fix bugs about recycling in components, and styles when reusing style object

This commit is contained in:
Leo Horie 2016-06-02 21:42:18 -04:00
parent 86673f8d16
commit f9ef480b34
5 changed files with 157 additions and 11 deletions

View file

@ -1,4 +1,100 @@
"use strict"
if (typeof Promise === "undefined") {
var Promise = function(executor) {
if (!(this instanceof Promise)) throw new Error("Promise must be called with `new`")
if (typeof executor !== "function") throw new TypeError("executor must be a function")
var self = this, resolvers = [], rejectors = [], resolveCurrent = handler(resolvers, true), rejectCurrent = handler(rejectors, false)
var instance = self._instance = {resolvers: resolvers, rejectors: rejectors}
var callAsync = typeof setImmediate === "function" ? setImmediate : setTimeout
function handler(list, shouldAbsorb) {
return function execute(value) {
var then
try {
if (shouldAbsorb && value != null && (typeof value === "object" || typeof value === "function") && typeof (then = value.then) === "function") {
if (value === self) throw new TypeError("Promise can't be resolved w/ itself")
executeOnce(then.bind(value))
}
else {
callAsync(function() {
if (!shouldAbsorb && list.length === 0) console.error("Possible unhandled promise rejection:", value)
for (var i = 0; i < list.length; i++) list[i](value)
resolvers.length = 0, rejectors.length = 0
instance.state = shouldAbsorb
instance.retry = function() {execute(value)}
}, 0)
}
}
catch (e) {
rejectCurrent(e)
}
}
}
function executeOnce(then) {
var runs = 0
function run(fn) {
return function(value) {
if (runs++ > 0) return
fn(value)
}
}
var onerror = run(rejectCurrent)
try {then(run(resolveCurrent), onerror)} catch (e) {onerror(e)}
}
executeOnce(executor)
}
Promise.prototype.then = function(onFulfilled, onRejection) {
var self = this, instance = self._instance
function handle(callback, list, next, state) {
list.push(function(value) {
if (typeof callback !== "function") next(value)
else try {resolveNext(callback(value))} catch (e) {if (rejectNext) rejectNext(e)}
})
if (typeof instance.retry === "function" && state === instance.state) instance.retry()
}
var resolveNext, rejectNext
var promise = new Promise(function(resolve, reject) {resolveNext = resolve, rejectNext = reject})
handle(onFulfilled, instance.resolvers, resolveNext, true), handle(onRejection, instance.rejectors, rejectNext, false)
return promise
}
Promise.prototype.catch = function(onRejection) {
return this.then(null, onRejection)
}
Promise.resolve = function(value) {
if (value instanceof Promise) return value
return new Promise(function(resolve, reject) {resolve(value)})
}
Promise.reject = function(value) {
return new Promise(function(resolve, reject) {reject(value)})
}
Promise.all = function(list) {
return new Promise(function(resolve, reject) {
var total = list.length, count = 0, values = []
if (list.length === 0) resolve([])
else for (var i = 0; i < list.length; i++) {
new function(i) {
function consume(value) {
count++
values[i] = value
if (count === total) resolve(values)
}
if (list[i] != null && (typeof list[i] === "object" || typeof list[i] === "function") && typeof list[i].then === "function") {
list[i].then(consume, reject)
}
else consume(list[i])
}(i)
}
})
}
Promise.race = function(list) {
return new Promise(function(resolve, reject) {
for (var i = 0; i < list.length; i++) {
list[i].then(resolve, reject)
}
})
}
}
function Node(tag, key, attrs, children, text, dom) {
return {tag: tag, key: key, attrs: attrs, children: children, text: text, dom: dom, domSize: undefined, state: {}, events: undefined}
}
@ -13,7 +109,7 @@ Node.normalizeChildren = function normalizeChildren(children) {
}
return children
}
var selectorParser = /(?:(^|#|\.)([^#\.\[\]]+))|(\[.+?\])/g, attrParser = /\[(.+?)(?:\s*=\s*("|'|)(.*?)\2)?\]/
var selectorParser = /(?:(^|#|\.)([^#\.\[\]]+))|(\[(.+?)(?:\s*=\s*("|'|)((?:\\["'\]]|.)*?)\5)?\])/g
var selectorCache = {}
function hyperscript(selector) {
if (typeof selector === "string") {
@ -25,8 +121,9 @@ function hyperscript(selector) {
else if (type === "#") attributes.id = value
else if (type === ".") classes.push(value)
else if (match[3][0] === "[") {
var pair = attrParser.exec(match[3])
attributes[pair[1]] = pair[3] || true
var attrValue = match[6]
if (attrValue) attrValue = attrValue.replace(/\\(["'])/g, "$1").replace(/\\\\/g, "\\")
attributes[match[4]] = attrValue || true
}
}
if (classes.length > 0) attributes.className = classes.join(" ")
@ -601,10 +698,10 @@ var buildQueryString = function(object) {
else args.push(encodeURIComponent(key) + (value != null && value !== "" ? "=" + encodeURIComponent(value) : ""))
}
}
var requestService = function($window, Promise) {
var requestService = function($window, Promise1) {
var callbackCount = 0
function xhr(args) {
return new Promise(function(resolve, reject) {
return new Promise1(function(resolve, reject) {
var useBody = args.useBody != null ? args.useBody : args.method !== "GET" && args.method !== "TRACE"
if (typeof args.serialize !== "function") args.serialize = JSON.stringify
@ -656,7 +753,7 @@ var requestService = function($window, Promise) {
})
}
function jsonp(args) {
return new Promise(function(resolve, reject) {
return new Promise1(function(resolve, reject) {
var callbackName = args.callbackName || "_mithril_" + Math.round(Math.random() * 1e16) + "_" + callbackCount++
var script = $window.document.createElement("script")
$window[callbackName] = function(data) {