From d82d337569f1adf5a94238e0fe1bd27797395379 Mon Sep 17 00:00:00 2001 From: Barney Carroll Date: Thu, 24 Nov 2016 09:21:27 +0000 Subject: [PATCH 1/3] Replace x instanceof Array with Array.isArray(x) --- README.md | 2 +- mithril.js | 18 ++++++++---------- mithril.min.js | 18 +++++++++--------- ospec/ospec.js | 4 ++-- querystring/build.js | 2 +- render/hyperscript.js | 6 +++--- render/render.js | 6 +++--- render/tests/test-fragment.js | 4 ++-- render/vnode.js | 2 +- request/request.js | 4 ++-- 10 files changed, 32 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index f748cef7..71c22280 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,6 @@ There are over 4000 assertions in the test suite, and tests cover even difficult ## Modularity -Despite the huge improvements in performance and modularity, the new codebase is smaller than v0.2.x, currently clocking at 7.40 KB min+gzip +Despite the huge improvements in performance and modularity, the new codebase is smaller than v0.2.x, currently clocking at 7.41 KB min+gzip In addition, Mithril is now completely modular: you can import only the modules that you need and easily integrate 3rd party modules if you wish to use a different library for routing, ajax, and even rendering diff --git a/mithril.js b/mithril.js index 7fdbec3a..520055e5 100644 --- a/mithril.js +++ b/mithril.js @@ -4,7 +4,7 @@ function Vnode(tag, key, attrs0, children, text, dom) { return {tag: tag, key: key, attrs: attrs0, children: children, text: text, dom: dom, domSize: undefined, state: {}, events: undefined, instance: undefined, skip: false} } Vnode.normalize = function(node) { - if (node instanceof Array) return Vnode("[", undefined, undefined, Vnode.normalizeChildren(node), undefined, undefined) + if (Array.isArray(node)) return Vnode("[", undefined, undefined, Vnode.normalizeChildren(node), undefined, undefined) if (node != null && typeof node !== "object") return Vnode("#", undefined, undefined, node, undefined, undefined) return node } @@ -52,19 +52,19 @@ function hyperscript(selector) { break } } - if (children instanceof Array && children.length == 1 && children[0] != null && children[0].tag === "#") text = children[0].children + if (Array.isArray(children) && children.length == 1 && children[0] != null && children[0].tag === "#") text = children[0].children else childList = children return Vnode(tag || "div", attrs.key, hasAttrs ? attrs : undefined, childList, text, undefined) } } var attrs, children, childrenIndex - if (arguments[1] == null || typeof arguments[1] === "object" && arguments[1].tag === undefined && !(arguments[1] instanceof Array)) { + if (arguments[1] == null || typeof arguments[1] === "object" && arguments[1].tag === undefined && !Array.isArray(arguments[1])) { attrs = arguments[1] childrenIndex = 2 } else childrenIndex = 1 if (arguments.length === childrenIndex + 1) { - children = arguments[childrenIndex] instanceof Array ? arguments[childrenIndex] : [arguments[childrenIndex]] + children = Array.isArray(arguments[childrenIndex]) ? arguments[childrenIndex] : [arguments[childrenIndex]] } else { children = [] @@ -187,7 +187,7 @@ var buildQueryString = function(object) { } return args.join("&") function destructure(key0, value) { - if (value instanceof Array) { + if (Array.isArray(value)) { for (var i = 0; i < value.length; i++) { destructure(key0 + "[" + i + "]", value[i]) } @@ -219,7 +219,6 @@ var _8 = function($window, Promise) { } return promise0 } - function request(args, extra) { return finalize(new Promise(function(resolve, reject) { if (typeof args === "string") { @@ -316,7 +315,7 @@ var _8 = function($window, Promise) { function extract(xhr) {return xhr.responseText} function cast(type0, data) { if (typeof type0 === "function") { - if (data instanceof Array) { + if (Array.isArray(data)) { for (var i = 0; i < data.length; i++) { data[i] = new type0(data[i]) } @@ -467,7 +466,6 @@ var _13 = function($window) { else { var recycling = isRecyclable(old, vnodes) if (recycling) old = old.concat(old.pool) - var oldStart = 0, start = 0, oldEnd = old.length - 1, end = vnodes.length - 1, map while (oldEnd >= oldStart && end >= start) { var o = old[oldStart], v = vnodes[start] @@ -739,7 +737,7 @@ var _13 = function($window) { if (vnode.instance != null) onremove(vnode.instance) else { var children = vnode.children - if (children instanceof Array) { + if (Array.isArray(children)) { for (var i = 0; i < children.length; i++) { var child = children[i] if (child != null) onremove(child) @@ -880,7 +878,7 @@ var _13 = function($window) { var active = $doc.activeElement // First time rendering into a node clears it out if (dom.vnodes == null) dom.textContent = "" - if (!(vnodes instanceof Array)) vnodes = [vnodes] + if (!Array.isArray(vnodes)) vnodes = [vnodes] updateNodes(dom, dom.vnodes, Vnode.normalizeChildren(vnodes), hooks, null, undefined) dom.vnodes = vnodes for (var i = 0; i < hooks.length; i++) hooks[i]() diff --git a/mithril.min.js b/mithril.min.js index 41590c4a..5a8f0d69 100644 --- a/mithril.min.js +++ b/mithril.min.js @@ -1,13 +1,13 @@ new function(){function m(a,b,k,e,l,h){return{tag:a,key:b,attrs:k,children:e,text:l,dom:h,domSize:void 0,state:{},events:void 0,instance:void 0,skip:!1}}function t(a){if(null==a||"string"!==typeof a&&null==a.view)throw Error("The selector must be either a string or a component.");if("string"===typeof a&&void 0===H[a]){for(var b,k,e=[],l={};b=O.exec(a);){var h=b[1],v=b[2];""===h&&""!==v?k=v:"#"===h?l.id=v:"."===h?e.push(v):"["===b[3][0]&&((h=b[6])&&(h=h.replace(/\\(["'])/g,"$1").replace(/\\\\/g,"\\")), -"class"===b[4]?e.push(h):l[b[4]]=h||!0)}0a.indexOf("?")?"?":"&";a+=e+f}return a}function v(a){try{return""!== -a?JSON.parse(a):null}catch(w){throw Error(a);}}function p(a){return a.responseText}function r(a,b){if("function"===typeof a)if(b instanceof Array)for(var e=0;ea.indexOf("?")?"?":"&";a+=e+f}return a}function v(a){try{return""!== +a?JSON.parse(a):null}catch(w){throw Error(a);}}function p(a){return a.responseText}function r(a,b){if("function"===typeof a)if(Array.isArray(b))for(var e=0;en.status||304===n.status)b(r(f.type,a));else{var h=Error(n.responseText),k;for(k in a)h[k]=a[k];e(h)}}catch(G){e(G)}}; u&&null!=f.data?n.send(f.data):n.send()}))},jsonp:function(f){return e(new b(function(b,e){var n=f.callbackName||"_mithril_"+Math.round(1E16*Math.random())+"_"+m++,k=a.document.createElement("script");a[n]=function(e){k.parentNode.removeChild(k);b(r(f.type,e));delete a[n]};k.onerror=function(){k.parentNode.removeChild(k);e(Error("JSONP request failed"));delete a[n]};null==f.data&&(f.data={});f.url=l(f.url,f.data);f.data[f.callbackKey||"callback"]=n;k.src=h(f.url,f.data);a.document.documentElement.appendChild(k)}))}, @@ -25,11 +25,11 @@ d.attrs&&null!=d.attrs.contenteditable?y(d):null!=g.text&&null!=d.text&&""!==d.t b,u,q,w),d.dom=d.instance.dom,d.domSize=d.instance.domSize):null!=g.instance?(f(g.instance,null),d.dom=void 0,d.domSize=0):(d.dom=g.dom,d.domSize=g.domSize)}else f(g,null),r(a,k(d,b,w),u)}function v(a){var c=a.domSize;if(null!=c||null==a.dom){var d=z.createDocumentFragment();if(0" try {return JSON.stringify(value)} catch (e) {return String(value)} } diff --git a/querystring/build.js b/querystring/build.js index 3bea081f..55474392 100644 --- a/querystring/build.js +++ b/querystring/build.js @@ -10,7 +10,7 @@ module.exports = function(object) { return args.join("&") function destructure(key, value) { - if (value instanceof Array) { + if (Array.isArray(value)) { for (var i = 0; i < value.length; i++) { destructure(key + "[" + i + "]", value[i]) } diff --git a/render/hyperscript.js b/render/hyperscript.js index 28ce0d35..a2cf7332 100644 --- a/render/hyperscript.js +++ b/render/hyperscript.js @@ -41,20 +41,20 @@ function hyperscript(selector) { break } } - if (children instanceof Array && children.length == 1 && children[0] != null && children[0].tag === "#") text = children[0].children + if (Array.isArray(children) && children.length == 1 && children[0] != null && children[0].tag === "#") text = children[0].children else childList = children return Vnode(tag || "div", attrs.key, hasAttrs ? attrs : undefined, childList, text, undefined) } } var attrs, children, childrenIndex - if (arguments[1] == null || typeof arguments[1] === "object" && arguments[1].tag === undefined && !(arguments[1] instanceof Array)) { + if (arguments[1] == null || typeof arguments[1] === "object" && arguments[1].tag === undefined && !Array.isArray(arguments[1])) { attrs = arguments[1] childrenIndex = 2 } else childrenIndex = 1 if (arguments.length === childrenIndex + 1) { - children = arguments[childrenIndex] instanceof Array ? arguments[childrenIndex] : [arguments[childrenIndex]] + children = Array.isArray(arguments[childrenIndex]) ? arguments[childrenIndex] : [arguments[childrenIndex]] } else { children = [] diff --git a/render/render.js b/render/render.js index 909477a2..a851c91f 100644 --- a/render/render.js +++ b/render/render.js @@ -135,7 +135,7 @@ module.exports = function($window) { else { var recycling = isRecyclable(old, vnodes) if (recycling) old = old.concat(old.pool) - + var oldStart = 0, start = 0, oldEnd = old.length - 1, end = vnodes.length - 1, map while (oldEnd >= oldStart && end >= start) { var o = old[oldStart], v = vnodes[start] @@ -410,7 +410,7 @@ module.exports = function($window) { if (vnode.instance != null) onremove(vnode.instance) else { var children = vnode.children - if (children instanceof Array) { + if (Array.isArray(children)) { for (var i = 0; i < children.length; i++) { var child = children[i] if (child != null) onremove(child) @@ -559,7 +559,7 @@ module.exports = function($window) { // First time rendering into a node clears it out if (dom.vnodes == null) dom.textContent = "" - if (!(vnodes instanceof Array)) vnodes = [vnodes] + if (!Array.isArray(vnodes)) vnodes = [vnodes] updateNodes(dom, dom.vnodes, Vnode.normalizeChildren(vnodes), hooks, null, undefined) dom.vnodes = vnodes for (var i = 0; i < hooks.length; i++) hooks[i]() diff --git a/render/tests/test-fragment.js b/render/tests/test-fragment.js index f0403bbc..b10fc850 100644 --- a/render/tests/test-fragment.js +++ b/render/tests/test-fragment.js @@ -11,7 +11,7 @@ o.spec("fragment", function() { o(frag.tag).equals("[") - o(frag.children instanceof Array).equals(true) + o(Array.isArray(frag.children)).equals(true) o(frag.children.length).equals(1) o(frag.children[0]).equals(child) @@ -24,7 +24,7 @@ o.spec("fragment", function() { var frag = fragment(attrs, []) o(frag.tag).equals("[") - o(frag.children instanceof Array).equals(true) + o(Array.isArray(frag.children)).equals(true) o(frag.children.length).equals(0) o(frag.attrs).equals(attrs) diff --git a/render/vnode.js b/render/vnode.js index 0c52d53d..99877e4e 100644 --- a/render/vnode.js +++ b/render/vnode.js @@ -2,7 +2,7 @@ function Vnode(tag, key, attrs, children, text, dom) { return {tag: tag, key: key, attrs: attrs, children: children, text: text, dom: dom, domSize: undefined, state: {}, events: undefined, instance: undefined, skip: false} } Vnode.normalize = function(node) { - if (node instanceof Array) return Vnode("[", undefined, undefined, Vnode.normalizeChildren(node), undefined, undefined) + if (Array.isArray(node)) return Vnode("[", undefined, undefined, Vnode.normalizeChildren(node), undefined, undefined) if (node != null && typeof node !== "object") return Vnode("#", undefined, undefined, node, undefined, undefined) return node } diff --git a/request/request.js b/request/request.js index a005f240..91ea17a3 100644 --- a/request/request.js +++ b/request/request.js @@ -23,7 +23,7 @@ module.exports = function($window, Promise) { } return promise } - + function request(args, extra) { return finalize(new Promise(function(resolve, reject) { if (typeof args === "string") { @@ -136,7 +136,7 @@ module.exports = function($window, Promise) { function cast(type, data) { if (typeof type === "function") { - if (data instanceof Array) { + if (Array.isArray(data)) { for (var i = 0; i < data.length; i++) { data[i] = new type(data[i]) } From a53515404317fb36239b1b1c195bae1ab55ff0be Mon Sep 17 00:00:00 2001 From: Barney Carroll Date: Fri, 16 Dec 2016 10:58:25 +0000 Subject: [PATCH 2/3] Bundle merge aa72f87 --- README.md | 2 +- mithril.min.js | 80 +++++++++++++++++++++++++------------------------- 2 files changed, 41 insertions(+), 41 deletions(-) diff --git a/README.md b/README.md index 11a87ed7..4f1d161b 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,6 @@ There are over 4000 assertions in the test suite, and tests cover even difficult ## Modularity -Despite the huge improvements in performance and modularity, the new codebase is smaller than v0.2.x, currently clocking at 7.47 KB min+gzip +Despite the huge improvements in performance and modularity, the new codebase is smaller than v0.2.x, currently clocking at 7.48 KB min+gzip In addition, Mithril is now completely modular: you can import only the modules that you need and easily integrate 3rd party modules if you wish to use a different library for routing, ajax, and even rendering diff --git a/mithril.min.js b/mithril.min.js index 69e76332..02a8ce63 100644 --- a/mithril.min.js +++ b/mithril.min.js @@ -1,41 +1,41 @@ new function(){function w(a,c,h,d,g,m){return{tag:a,key:c,attrs:h,children:d,text:g,dom:m,domSize:void 0,state:{},events:void 0,instance:void 0,skip:!1}}function z(a){if(null==a||"string"!==typeof a&&null==a.view)throw Error("The selector must be either a string or a component.");if("string"===typeof a&&void 0===K[a]){for(var c,h,d=[],g={};c=P.exec(a);){var m=c[1],l=c[2];""===m&&""!==l?h=l:"#"===m?g.id=l:"."===m?d.push(l):"["===c[3][0]&&((m=c[6])&&(m=m.replace(/\\(["'])/g,"$1").replace(/\\\\/g,"\\")), -"class"===c[4]?d.push(m):g[c[4]]=m||!0)}0a.indexOf("?")?"?":"&";a+=d+b}return a}function l(a){try{return""!==a?JSON.parse(a):null}catch(D){throw Error(a);}}function n(a){return a.responseText}function p(a, -c){if("function"===typeof a)if(c instanceof Array)for(var b=0;bk.status||304===k.status)c(p(b.type,a));else{var g=Error(k.responseText),h;for(h in a)g[h]=a[h];d(g)}}catch(F){d(F)}};h&&null!=b.data?k.send(b.data):k.send()});return!0===b.background?t:r(t)},jsonp:function(b,l){var n=h();b=d(b,l);var t=new c(function(c, -d){var h=b.callbackName||"_mithril_"+Math.round(1E16*Math.random())+"_"+k++,l=a.document.createElement("script");a[h]=function(d){l.parentNode.removeChild(l);c(p(b.type,d));delete a[h]};l.onerror=function(){l.parentNode.removeChild(l);d(Error("JSONP request failed"));delete a[h]};null==b.data&&(b.data={});b.url=g(b.url,b.data);b.data[b.callbackKey||"callback"]=h;l.src=m(b.url,b.data);a.document.documentElement.appendChild(l)});return!0===b.background?t:n(t)},setCompletionCallback:function(a){r=a}}}(window, -H),O=function(a){function c(e,f,a,b,c,d,g){for(;a=k&&t>=A;){var x=f[k],u=a[A];if(x!==u||q)if(null==x)k++;else if(null==u)A++;else if(x.key===u.key)k++,A++,m(e,x,u,b,n(f,k,d),q,g),q&&x.tag===u.tag&&p(e,l(x),d);else if(x=f[y],x!==u||q)if(null==x)y--;else if(null==u)A++;else if(x.key===u.key)m(e,x,u,b,n(f,y+1,d),q,g),(q||A=k&&t>=A;){x=f[y];u=a[t];if(x!==u||q)if(null==x)y--;else{if(null!= -u)if(x.key===u.key)m(e,x,u,b,n(f,y+1,d),q,g),q&&x.tag===u.tag&&p(e,l(x),d),null!=x.dom&&(d=x.dom),y--;else{if(!D){D=f;var x=y,C={},w;for(w=0;wa.indexOf("?")?"?":"&";a+=d+b}return a}function l(a){try{return""!==a?JSON.parse(a):null}catch(D){throw Error(a);}}function n(a){return a.responseText}function p(a,c){if("function"===typeof a)if(Array.isArray(c))for(var b= +0;bk.status||304===k.status)c(p(b.type,a));else{var g=Error(k.responseText),h;for(h in a)g[h]=a[h];d(g)}}catch(F){d(F)}};h&&null!=b.data?k.send(b.data):k.send()});return!0===b.background?t:r(t)},jsonp:function(b,l){var n=h();b=d(b,l);var t=new c(function(c,d){var h=b.callbackName||"_mithril_"+Math.round(1E16* +Math.random())+"_"+k++,l=a.document.createElement("script");a[h]=function(d){l.parentNode.removeChild(l);c(p(b.type,d));delete a[h]};l.onerror=function(){l.parentNode.removeChild(l);d(Error("JSONP request failed"));delete a[h]};null==b.data&&(b.data={});b.url=g(b.url,b.data);b.data[b.callbackKey||"callback"]=h;l.src=m(b.url,b.data);a.document.documentElement.appendChild(l)});return!0===b.background?t:n(t)},setCompletionCallback:function(a){r=a}}}(window,H),O=function(a){function c(e,f,a,b,c,d,g){for(;a< +b;a++){var q=f[a];null!=q&&p(e,h(q,c,g),d)}}function h(e,f,a){var q=e.tag;null!=e.attrs&&L(e.attrs,e,f);if("string"===typeof q)switch(q){case "#":return e.dom=B.createTextNode(e.children);case "<":return d(e);case "[":var b=B.createDocumentFragment();null!=e.children&&(q=e.children,c(b,q,0,q.length,f,null,a));e.dom=b.firstChild;e.domSize=b.childNodes.length;return b;default:var g=e.tag;switch(e.tag){case "svg":a="http://www.w3.org/2000/svg";break;case "math":a="http://www.w3.org/1998/Math/MathML"}var p= +(q=e.attrs)&&q.is,g=a?p?B.createElementNS(a,g,{is:p}):B.createElementNS(a,g):p?B.createElement(g,{is:p}):B.createElement(g);e.dom=g;if(null!=q)for(b in p=a,q)t(e,b,null,q[b],p);null!=e.attrs&&null!=e.attrs.contenteditable?k(e):(null!=e.text&&(""!==e.text?g.textContent=e.text:e.children=[w("#",void 0,void 0,e.text,void 0,void 0)]),null!=e.children&&(b=e.children,c(g,b,0,b.length,f,null,a),f=e.attrs,"select"===e.tag&&null!=f&&("value"in f&&t(e,"value",null,f.value,void 0),"selectedIndex"in f&&t(e,"selectedIndex", +null,f.selectedIndex,void 0))));return g}else{e.state||(e.state={});R(e.state,e.tag);b=e.tag.view;if(null!=b.reentrantLock)e=E;else if(b.reentrantLock=!0,L(e.tag,e,f),e.instance=w.normalize(b.call(e.state,e)),b.reentrantLock=null,null!=e.instance){if(e.instance===e)throw Error("A view cannot return the vnode it received as arguments");f=h(e.instance,f,a);e.dom=e.instance.dom;e.domSize=null!=e.dom?e.instance.domSize:0;e=f}else e.domSize=0,e=E;return e}}function d(e){var f={caption:"table",thead:"table", +tbody:"table",tfoot:"table",tr:"tbody",th:"tr",td:"tr",colgroup:"table",col:"colgroup"}[(e.children.match(/^\s*?<(\w+)/im)||[])[1]]||"div",f=B.createElement(f);f.innerHTML=e.children;e.dom=f.firstChild;e.domSize=f.childNodes.length;e=B.createDocumentFragment();for(var a;a=f.firstChild;)e.appendChild(a);return e}function g(e,f,a,b,d,g){if(f!==a&&(null!=f||null!=a))if(null==f)c(e,a,0,a.length,b,d,void 0);else if(null==a)r(f,0,f.length,a);else{for(var q=!1,k=0;k=k&&t>=A;){var x=f[k],u=a[A];if(x!==u||q)if(null==x)k++;else if(null==u)A++;else if(x.key===u.key)k++,A++,m(e,x,u,b,n(f,k,d),q,g),q&&x.tag===u.tag&&p(e,l(x),d);else if(x=f[y],x!==u||q)if(null==x)y--;else if(null==u)A++;else if(x.key===u.key)m(e,x,u,b,n(f,y+1,d),q,g),(q||A=k&&t>=A;){x=f[y];u=a[t];if(x!==u||q)if(null==x)y--;else{if(null!=u)if(x.key===u.key)m(e,x,u,b,n(f,y+1,d),q,g),q&&x.tag===u.tag&&p(e,l(x), +d),null!=x.dom&&(d=x.dom),y--;else{if(!D){D=f;var x=y,C={},w;for(w=0;w Date: Fri, 30 Dec 2016 19:31:51 +0000 Subject: [PATCH 3/3] Test for onbeforeremove delayed resolution --- render/tests/test-onbeforeremove.js | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/render/tests/test-onbeforeremove.js b/render/tests/test-onbeforeremove.js index 82a859d0..c9af4894 100644 --- a/render/tests/test-onbeforeremove.js +++ b/render/tests/test-onbeforeremove.js @@ -158,14 +158,14 @@ o.spec("onbeforeremove", function() { render(root, vnodes) render(root, updated) - + o(root.childNodes.length).equals(2) o(root.firstChild.firstChild.nodeValue).equals("1") - + callAsync(function() { o(root.childNodes.length).equals(1) o(root.firstChild.firstChild.nodeValue).equals("2") - + done() }) }) @@ -184,4 +184,25 @@ o.spec("onbeforeremove", function() { done() }) }) + o("awaits promise resolution before removing the node", function(done) { + var view = o.spy() + var onremove = o.spy() + var onbeforeremove = function(){return new Promise(function(resolve){callAsync(resolve)})} + var component = { + onbeforeremove: onbeforeremove, + onremove: onremove, + view: view, + } + render(root, [{tag: component}]) + render(root, []) + + callAsync(function(){ + o(onremove.callCount).equals(0) + + callAsync(function() { + o(onremove.callCount).equals(1) + done() + }) + }) + }) })