Merge branch 'next' of https://github.com/lhorie/mithril.js into perf-update

This commit is contained in:
Isiah Meadows 2017-03-03 18:28:07 -05:00
commit c0061a8eb9
7 changed files with 337 additions and 204 deletions

View file

@ -177,3 +177,30 @@ m("div", [
]
])
```
#### Avoid passing model data directly to components if the model uses `key` as a data property
The `key` property may appear in your data model in a way that conflicts with Mithril's key logic. For example, a component may represent an entity whose `key` property is expected to change over time. This can lead to components receiving the wrong data, re-initialise, or change positions unexpectedly. If your data model uses the `key` property, make sure to wrap the data such that Mithril doesn't misinterpret it as a rendering instruction:
```javascript
// Data model
var users = [
{id: 1, name: "John", key: 'a'},
{id: 2, name: "Mary", key: 'b'},
]
// Later on...
users[0].key = 'c'
// AVOID
users.map(function(user){
// The component for John will be destroyed and recreated
return m(UserComponent, user)
})
// PREFER
users.map(function(user){
// Key is specifically extracted: data model is given its own property
return m(UserComponent, {key: user.id, model: user})
})
```

22
mithril.d.ts vendored
View file

@ -238,6 +238,18 @@ declare namespace Mithril {
/** A special value that can be returned to stream callbacks to halt execution of downstreams. */
HALT: any;
}
interface StreamScan {
/** Creates a new stream with the results of calling the function on every incoming stream with and accumulator and the incoming value. */
<T,U>(fn: (acc: U, value: T) => U, acc: U, stream: Stream<T>): Stream<U>;
}
interface StreamScanMerge {
/** Takes an array of pairs of streams and scan functions and merges all those streams using the given functions into a single stream. */
<T,U>(pairs: [Stream<T>, (acc: U, value: T) => U][], acc: U): Stream<U>;
/** Takes an array of pairs of streams and scan functions and merges all those streams using the given functions into a single stream. */
<U>(pairs: [Stream<any>, (acc: U, value: any) => U][], acc: U): Stream<U>;
}
}
declare module 'mithril' {
@ -284,3 +296,13 @@ declare module 'mithril/stream' {
const s: Mithril.StreamFactory;
export = s;
}
declare module 'mithril/stream/scan' {
const s: Mithril.StreamScan;
export = s;
}
declare module 'mithril/stream/scanMerge' {
const sm: Mithril.StreamScanMerge;
export = sm;
}

View file

@ -368,8 +368,8 @@ var coreRenderer = function($window) {
}
function createNode(parent, vnode, hooks, ns, nextSibling) {
var tag = vnode.tag
if (vnode.attrs != null) initLifecycle(vnode.attrs, vnode, hooks)
if (typeof tag === "string") {
if (vnode.attrs != null) initLifecycle(vnode.attrs, vnode, hooks)
switch (tag) {
case "#": return createText(parent, vnode, nextSibling)
case "<": return createHTML(parent, vnode, nextSibling)
@ -442,7 +442,7 @@ var coreRenderer = function($window) {
}
return element
}
function createComponent(parent, vnode, hooks, ns, nextSibling) {
function initComponent(vnode, hooks) {
var sentinel
if (typeof vnode.tag === "function") {
vnode.state = null
@ -457,9 +457,13 @@ var coreRenderer = function($window) {
if (sentinel.$$reentrantLock$$ != null) return $emptyFragment
sentinel.$$reentrantLock$$ = true
}
if (vnode.attrs != null) initLifecycle(vnode.attrs, vnode, hooks)
initLifecycle(vnode.state, vnode, hooks)
vnode.instance = Vnode.normalize(vnode.state.view(vnode))
sentinel.$$reentrantLock$$ = null
}
function createComponent(parent, vnode, hooks, ns, nextSibling) {
initComponent(vnode, hooks)
if (vnode.instance != null) {
if (vnode.instance === vnode) throw Error("A view cannot return the vnode it received as arguments")
var element = createNode(parent, vnode.instance, hooks, ns, nextSibling)
@ -570,11 +574,12 @@ var coreRenderer = function($window) {
if (oldTag === tag) {
vnode.state = old.state
vnode.events = old.events
if (shouldUpdate(vnode, old)) return
if (vnode.attrs != null) {
updateLifecycle(vnode.attrs, vnode, hooks, recycling)
}
if (!recycling && shouldNotUpdate(vnode, old)) return
if (typeof oldTag === "string") {
if (vnode.attrs != null) {
if (recycling) initLifecycle(vnode.attrs, vnode, hooks)
else updateLifecycle(vnode.attrs, vnode, hooks)
}
switch (oldTag) {
case "#": updateText(old, vnode); break
case "<": updateHTML(parent, old, vnode, nextSibling); break
@ -644,8 +649,13 @@ var coreRenderer = function($window) {
}
}
function updateComponent(parent, old, vnode, hooks, nextSibling, recycling, ns) {
vnode.instance = Vnode.normalize(vnode.state.view(vnode))
updateLifecycle(vnode.state, vnode, hooks, recycling)
if (recycling) {
initComponent(vnode, hooks)
} else {
vnode.instance = Vnode.normalize(vnode.state.view(vnode))
if (vnode.attrs != null) updateLifecycle(vnode.attrs, vnode, hooks)
updateLifecycle(vnode.state, vnode, hooks)
}
if (vnode.instance != null) {
if (old.instance == null) createNode(parent, vnode.instance, hooks, ns, nextSibling)
else updateNode(parent, old.instance, vnode.instance, hooks, nextSibling, recycling, ns)
@ -897,11 +907,10 @@ var coreRenderer = function($window) {
if (typeof source.oninit === "function") source.oninit.call(vnode.state, vnode)
if (typeof source.oncreate === "function") hooks.push(source.oncreate.bind(vnode.state, vnode))
}
function updateLifecycle(source, vnode, hooks, recycling) {
if (recycling) initLifecycle(source, vnode, hooks)
else if (typeof source.onupdate === "function") hooks.push(source.onupdate.bind(vnode.state, vnode))
function updateLifecycle(source, vnode, hooks) {
if (typeof source.onupdate === "function") hooks.push(source.onupdate.bind(vnode.state, vnode))
}
function shouldUpdate(vnode, old) {
function shouldNotUpdate(vnode, old) {
var forceVnodeUpdate, forceComponentUpdate
if (vnode.attrs != null && typeof vnode.attrs.onbeforeupdate === "function") forceVnodeUpdate = vnode.attrs.onbeforeupdate.call(vnode.state, vnode, old)
if (typeof vnode.tag !== "string" && typeof vnode.state.onbeforeupdate === "function") forceComponentUpdate = vnode.state.onbeforeupdate(vnode, old)

86
mithril.min.js vendored
View file

@ -1,43 +1,43 @@
new function(){function w(a,d,h,f,g,l){return{tag:a,key:d,attrs:h,children:f,text:g,dom:l,domSize:void 0,state:{},events:void 0,instance:void 0,skip:!1}}function A(a){if(null==a||"string"!==typeof a&&"function"!==typeof a&&"function"!==typeof a.view)throw Error("The selector must be either a string or a component.");if("string"===typeof a&&void 0===H[a]){for(var d,h,f=[],g={};d=O.exec(a);){var l=d[1],k=d[2];""===l&&""!==k?h=k:"#"===l?g.id=k:"."===l?f.push(k):"["===d[3][0]&&((l=d[6])&&(l=l.replace(/\\(["'])/g,
"$1").replace(/\\\\/g,"\\")),"class"===d[4]?f.push(l):g[d[4]]=l||!0)}0<f.length&&(g.className=f.join(" "));H[a]=function(a,d){var l=!1,c,f,p=a.className||a["class"],q;for(q in g)a[q]=g[q];void 0!==p&&(void 0!==a["class"]&&(a["class"]=void 0,a.className=p),void 0!==g.className&&(a.className=g.className+" "+p));for(q in a)if("key"!==q){l=!0;break}Array.isArray(d)&&1==d.length&&null!=d[0]&&"#"===d[0].tag?f=d[0].children:c=d;return w(h||"div",a.key,l?a:void 0,c,f,void 0)}}var q;null==arguments[1]||"object"===
typeof arguments[1]&&void 0===arguments[1].tag&&!Array.isArray(arguments[1])?(q=arguments[1],f=2):f=1;if(arguments.length===f+1)d=Array.isArray(arguments[f])?arguments[f]:[arguments[f]];else for(d=[];f<arguments.length;f++)d.push(arguments[f]);return"string"===typeof a?H[a](q||{},w.normalizeChildren(d)):w(a,q&&q.key,q||{},w.normalizeChildren(d),void 0,void 0)}function P(a){var d=0,h=null,f="function"===typeof requestAnimationFrame?requestAnimationFrame:setTimeout;return function(){var g=Date.now();
0===d||16<=g-d?(d=g,a()):null===h&&(h=f(function(){h=null;a();d=Date.now()},16-(g-d)))}}w.normalize=function(a){return Array.isArray(a)?w("[",void 0,void 0,w.normalizeChildren(a),void 0,void 0):null!=a&&"object"!==typeof a?w("#",void 0,void 0,!1===a?"":a,void 0,void 0):a};w.normalizeChildren=function(a){for(var d=0;d<a.length;d++)a[d]=w.normalize(a[d]);return a};var O=/(?:(^|#|\.)([^#\.\[\]]+))|(\[(.+?)(?:\s*=\s*("|'|)((?:\\["'\]]|.)*?)\5)?\])/g,H={};A.trust=function(a){null==a&&(a="");return w("<",
void 0,void 0,a,void 0,void 0)};A.fragment=function(a,d){return w("[",a.key,a,w.normalizeChildren(d),void 0,void 0)};var v=function(a){function d(a,c){return function z(d){var k;try{if(!c||null==d||"object"!==typeof d&&"function"!==typeof d||"function"!==typeof(k=d.then))r(function(){c||0!==a.length||console.error("Possible unhandled promise rejection:",d);for(var f=0;f<a.length;f++)a[f](d);g.length=0;l.length=0;p.state=c;p.retry=function(){z(d)}});else{if(d===f)throw new TypeError("Promise can't be resolved w/ itself");
h(k.bind(d))}}catch(Q){q(Q)}}}function h(a){function c(c){return function(a){0<d++||c(a)}}var d=0,f=c(q);try{a(c(k),f)}catch(D){f(D)}}if(!(this instanceof v))throw Error("Promise must be called with `new`");if("function"!==typeof a)throw new TypeError("executor must be a function");var f=this,g=[],l=[],k=d(g,!0),q=d(l,!1),p=f._instance={resolvers:g,rejectors:l},r="function"===typeof setImmediate?setImmediate:setTimeout;h(a)};v.prototype.then=function(a,d){function h(a,d,h,k){d.push(function(c){if("function"!==
typeof a)h(c);else try{g(a(c))}catch(t){l&&l(t)}});"function"===typeof f.retry&&k===f.state&&f.retry()}var f=this._instance,g,l,k=new v(function(a,d){g=a;l=d});h(a,f.resolvers,g,!0);h(d,f.rejectors,l,!1);return k};v.prototype["catch"]=function(a){return this.then(null,a)};v.resolve=function(a){return a instanceof v?a:new v(function(d){d(a)})};v.reject=function(a){return new v(function(d,h){h(a)})};v.all=function(a){return new v(function(d,h){var f=a.length,g=0,l=[];if(0===a.length)d([]);else for(var k=
0;k<a.length;k++)(function(k){function p(a){g++;l[k]=a;g===f&&d(l)}null==a[k]||"object"!==typeof a[k]&&"function"!==typeof a[k]||"function"!==typeof a[k].then?p(a[k]):a[k].then(p,h)})(k)})};v.race=function(a){return new v(function(d,h){for(var f=0;f<a.length;f++)a[f].then(d,h)})};"undefined"!==typeof window?("undefined"===typeof window.Promise&&(window.Promise=v),v=window.Promise):"undefined"!==typeof global&&("undefined"===typeof global.Promise&&(global.Promise=v),v=global.Promise);var F=function(a){function d(a,
f){if(Array.isArray(f))for(var g=0;g<f.length;g++)d(a+"["+g+"]",f[g]);else if("[object Object]"===Object.prototype.toString.call(f))for(g in f)d(a+"["+g+"]",f[g]);else h.push(encodeURIComponent(a)+(null!=f&&""!==f?"="+encodeURIComponent(f):""))}if("[object Object]"!==Object.prototype.toString.call(a))return"";var h=[],f;for(f in a)d(f,a[f]);return h.join("&")},R=/^file:\/\//i,K=function(a,d){function h(){function c(){0===--a&&"function"===typeof u&&u()}var a=0;return function D(d){var f=d.then;d.then=
function(){a++;var g=f.apply(d,arguments);g.then(c,function(d){c();if(0===a)throw d;});return D(g)};return d}}function f(c,a){if("string"===typeof c){var d=c;c=a||{};null==c.url&&(c.url=d)}return c}function g(c,a){if(null==a)return c;for(var d=c.match(/:[^\/]+/gi)||[],f=0;f<d.length;f++){var g=d[f].slice(1);null!=a[g]&&(c=c.replace(d[f],a[g]))}return c}function l(c,a){var d=F(a);if(""!==d){var f=0>c.indexOf("?")?"?":"&";c+=f+d}return c}function k(c){try{return""!==c?JSON.parse(c):null}catch(t){throw Error(c);
}}function q(c){return c.responseText}function p(c,a){if("function"===typeof c)if(Array.isArray(a))for(var d=0;d<a.length;d++)a[d]=new c(a[d]);else return new c(a);return a}var r=0,u;return{request:function(c,u){var r=h();c=f(c,u);var t=new d(function(d,f){null==c.method&&(c.method="GET");c.method=c.method.toUpperCase();var h="GET"===c.method||"TRACE"===c.method?!1:"boolean"===typeof c.useBody?c.useBody:!0;"function"!==typeof c.serialize&&(c.serialize="undefined"!==typeof FormData&&c.data instanceof
FormData?function(b){return b}:JSON.stringify);"function"!==typeof c.deserialize&&(c.deserialize=k);"function"!==typeof c.extract&&(c.extract=q);c.url=g(c.url,c.data);h?c.data=c.serialize(c.data):c.url=l(c.url,c.data);var n=new a.XMLHttpRequest,u=!1,r=n.abort;n.abort=function(){u=!0;r.call(n)};n.open(c.method,c.url,"boolean"===typeof c.async?c.async:!0,"string"===typeof c.user?c.user:void 0,"string"===typeof c.password?c.password:void 0);c.serialize===JSON.stringify&&h&&n.setRequestHeader("Content-Type",
"application/json; charset=utf-8");c.deserialize===k&&n.setRequestHeader("Accept","application/json, text/*");c.withCredentials&&(n.withCredentials=c.withCredentials);for(var m in c.headers)({}).hasOwnProperty.call(c.headers,m)&&n.setRequestHeader(m,c.headers[m]);"function"===typeof c.config&&(n=c.config(n,c)||n);n.onreadystatechange=function(){if(!u&&4===n.readyState)try{var b=c.extract!==q?c.extract(n,c):c.deserialize(c.extract(n,c));if(200<=n.status&&300>n.status||304===n.status||R.test(c.url))d(p(c.type,
b));else{var m=Error(n.responseText),a;for(a in b)m[a]=b[a];f(m)}}catch(C){f(C)}};h&&null!=c.data?n.send(c.data):n.send()});return!0===c.background?t:r(t)},jsonp:function(c,k){var q=h();c=f(c,k);var u=new d(function(d,f){var h=c.callbackName||"_mithril_"+Math.round(1E16*Math.random())+"_"+r++,k=a.document.createElement("script");a[h]=function(f){k.parentNode.removeChild(k);d(p(c.type,f));delete a[h]};k.onerror=function(){k.parentNode.removeChild(k);f(Error("JSONP request failed"));delete a[h]};null==
c.data&&(c.data={});c.url=g(c.url,c.data);c.data[c.callbackKey||"callback"]=h;k.src=l(c.url,c.data);a.document.documentElement.appendChild(k)});return!0===c.background?u:q(u)},setCompletionCallback:function(a){u=a}}}(window,v),N=function(a){function d(a,b,c,d,f,g,k){for(;c<d;c++){var m=b[c];null!=m&&h(a,m,f,k,g)}}function h(a,b,c,x,g){var m=b.tag;null!=b.attrs&&v(b.attrs,b,c);if("string"===typeof m)switch(m){case "#":return b.dom=n.createTextNode(b.children),p(a,b.dom,g),b.dom;case "<":return f(a,
b,g);case "[":var e=n.createDocumentFragment();null!=b.children&&(m=b.children,d(e,m,0,m.length,c,null,x));b.dom=e.firstChild;b.domSize=e.childNodes.length;p(a,e,g);return e;default:var k=b.tag;switch(b.tag){case "svg":x="http://www.w3.org/2000/svg";break;case "math":x="http://www.w3.org/1998/Math/MathML"}var l=(m=b.attrs)&&m.is,k=x?l?n.createElementNS(x,k,{is:l}):n.createElementNS(x,k):l?n.createElement(k,{is:l}):n.createElement(k);b.dom=k;if(null!=m)for(e in l=x,m)z(b,e,null,m[e],l);p(a,k,g);null!=
b.attrs&&null!=b.attrs.contenteditable?r(b):(null!=b.text&&(""!==b.text?k.textContent=b.text:b.children=[w("#",void 0,void 0,b.text,void 0,void 0)]),null!=b.children&&(a=b.children,d(k,a,0,a.length,c,null,x),a=b.attrs,"select"===b.tag&&null!=a&&("value"in a&&z(b,"value",null,a.value,void 0),"selectedIndex"in a&&z(b,"selectedIndex",null,a.selectedIndex,void 0))));return k}else{a:{if("function"===typeof b.tag){b.state=null;e=b.tag;if(null!=e.$$reentrantLock$$){b=I;break a}e.$$reentrantLock$$=!0;b.state=
null!=b.tag.prototype&&"function"===typeof b.tag.prototype.view?new b.tag(b):b.tag(b)}else{b.state=Object.create(b.tag);e=b.state.view;if(null!=e.$$reentrantLock$$){b=I;break a}e.$$reentrantLock$$=!0}v(b.state,b,c);b.instance=w.normalize(b.state.view(b));e.$$reentrantLock$$=null;if(null!=b.instance){if(b.instance===b)throw Error("A view cannot return the vnode it received as arguments");c=h(a,b.instance,c,x,g);b.dom=b.instance.dom;b.domSize=null!=b.dom?b.instance.domSize:0;p(a,c,g);b=c}else b.domSize=
0,b=I}return b}}function f(a,b,c){var m={caption:"table",thead:"table",tbody:"table",tfoot:"table",tr:"tbody",th:"tr",td:"tr",colgroup:"table",col:"colgroup"}[(b.children.match(/^\s*?<(\w+)/im)||[])[1]]||"div",m=n.createElement(m);m.innerHTML=b.children;b.dom=m.firstChild;b.domSize=m.childNodes.length;b=n.createDocumentFragment();for(var e;e=m.firstChild;)b.appendChild(e);p(a,b,c);return b}function g(a,b,c,f,g,B,n){if(b!==c&&(null!=b||null!=c))if(null==b)d(a,c,0,c.length,g,B,void 0);else if(null==
c)u(b,0,b.length,c);else{if(b.length===c.length){for(var m=!1,e=0;e<c.length;e++)if(null!=c[e]&&null!=b[e]){m=null==c[e].key&&null==b[e].key;break}if(m){for(e=0;e<b.length;e++)b[e]!==c[e]&&(null==b[e]&&null!=c[e]?h(a,c[e],g,n,q(b,e+1,B)):null==c[e]?u(b,e,e+1,c):l(a,b[e],c[e],g,q(b,e+1,B),f,n));return}}if(!f)a:{if(null!=b.pool&&Math.abs(b.pool.length-c.length)<=Math.abs(b.length-c.length)&&(f=c[0]&&c[0].children&&c[0].children.length||0,Math.abs((b.pool[0]&&b.pool[0].children&&b.pool[0].children.length||
0)-f)<=Math.abs((b[0]&&b[0].children&&b[0].children.length||0)-f))){f=!0;break a}f=!1}if(f){var x=b.pool;b=b.concat(b.pool)}for(var e=m=0,r=b.length-1,t=c.length-1,E;r>=m&&t>=e;){var y=b[m],z=c[e];if(y!==z||f)if(null==y)m++;else if(null==z)e++;else if(y.key===z.key){var C=null!=x&&m>=b.length-x.length||null==x&&f;m++;e++;l(a,y,z,g,q(b,m,B),C,n);f&&y.tag===z.tag&&p(a,k(y),B)}else if(y=b[r],y!==z||f)if(null==y)r--;else if(null==z)e++;else if(y.key===z.key)C=null!=x&&r>=b.length-x.length||null==x&&f,
l(a,y,z,g,q(b,r+1,B),C,n),(f||e<t)&&p(a,k(y),q(b,m,B)),r--,e++;else break;else r--,e++;else m++,e++}for(;r>=m&&t>=e;){y=b[r];z=c[t];if(y!==z||f)if(null==y)r--;else{if(null!=z)if(y.key===z.key)C=null!=x&&r>=b.length-x.length||null==x&&f,l(a,y,z,g,q(b,r+1,B),C,n),f&&y.tag===z.tag&&p(a,k(y),B),null!=y.dom&&(B=y.dom),r--;else{if(!E){E=b;var y=r,C={},v;for(v=0;v<y;v++){var w=E[v];null!=w&&(w=w.key,null!=w&&(C[w]=v))}E=C}null!=z&&(y=E[z.key],null!=y?(C=b[y],l(a,C,z,g,q(b,r+1,B),f,n),p(a,k(C),B),b[y].skip=
!0,null!=C.dom&&(B=C.dom)):B=h(a,z,g,void 0,B))}t--}else r--,t--;if(t<e)break}d(a,c,e,t+1,g,B,n);u(b,m,r+1,c)}}function l(a,b,e,d,p,n,q){var m=b.tag;if(m===e.tag){e.state=b.state;e.events=b.events;var x;var u;null!=e.attrs&&"function"===typeof e.attrs.onbeforeupdate&&(x=e.attrs.onbeforeupdate.call(e.state,e,b));"string"!==typeof e.tag&&"function"===typeof e.state.onbeforeupdate&&(u=e.state.onbeforeupdate(e,b));void 0===x&&void 0===u||x||u?x=!1:(e.dom=b.dom,e.domSize=b.domSize,e.instance=b.instance,
x=!0);if(!x)if(null!=e.attrs&&A(e.attrs,e,d,n),"string"===typeof m)switch(m){case "#":b.children.toString()!==e.children.toString()&&(b.dom.nodeValue=e.children);e.dom=b.dom;break;case "<":b.children!==e.children?(k(b),f(a,e,p)):(e.dom=b.dom,e.domSize=b.domSize);break;case "[":g(a,b.children,e.children,n,d,p,q);b=0;d=e.children;e.dom=null;if(null!=d){for(n=0;n<d.length;n++){var t=d[n];null!=t&&null!=t.dom&&(null==e.dom&&(e.dom=t.dom),b+=t.domSize||1)}1!==b&&(e.domSize=b)}break;default:a=q;p=e.dom=
b.dom;switch(e.tag){case "svg":a="http://www.w3.org/2000/svg";break;case "math":a="http://www.w3.org/1998/Math/MathML"}"textarea"===e.tag&&(null==e.attrs&&(e.attrs={}),null!=e.text&&(e.attrs.value=e.text,e.text=void 0));q=b.attrs;m=e.attrs;x=a;if(null!=m)for(t in m)z(e,t,q&&q[t],m[t],x);if(null!=q)for(t in q)null!=m&&t in m||("className"===t&&(t="class"),"o"!==t[0]||"n"!==t[1]||D(t)?"key"!==t&&e.dom.removeAttribute(t):M(e,t,void 0));null!=e.attrs&&null!=e.attrs.contenteditable?r(e):null!=b.text&&
null!=e.text&&""!==e.text?b.text.toString()!==e.text.toString()&&(b.dom.firstChild.nodeValue=e.text):(null!=b.text&&(b.children=[w("#",void 0,void 0,b.text,void 0,b.dom.firstChild)]),null!=e.text&&(e.children=[w("#",void 0,void 0,e.text,void 0,void 0)]),g(p,b.children,e.children,n,d,null,a))}else e.instance=w.normalize(e.state.view(e)),A(e.state,e,d,n),null!=e.instance?(null==b.instance?h(a,e.instance,d,q,p):l(a,b.instance,e.instance,d,p,n,q),e.dom=e.instance.dom,e.domSize=e.instance.domSize):null!=
b.instance?(c(b.instance,null),e.dom=void 0,e.domSize=0):(e.dom=b.dom,e.domSize=b.domSize)}else c(b,null),h(a,e,d,q,p)}function k(a){var b=a.domSize;if(null!=b||null==a.dom){var c=n.createDocumentFragment();if(0<b){for(a=a.dom;--b;)c.appendChild(a.nextSibling);c.insertBefore(a,c.firstChild)}return c}return a.dom}function q(a,b,c){for(;b<a.length;b++)if(null!=a[b]&&null!=a[b].dom)return a[b].dom;return c}function p(a,b,c){c&&c.parentNode?a.insertBefore(b,c):a.appendChild(b)}function r(a){var b=a.children;
if(null!=b&&1===b.length&&"<"===b[0].tag)b=b[0].children,a.dom.innerHTML!==b&&(a.dom.innerHTML=b);else if(null!=a.text||null!=b&&0!==b.length)throw Error("Child node of a contenteditable must be trusted");}function u(a,b,e,d){for(;b<e;b++){var m=a[b];null!=m&&(m.skip?m.skip=!1:c(m,d))}}function c(a,b){function c(){if(++m===d&&(t(a),a.dom)){var c=a.domSize||1;if(1<c)for(var e=a.dom;--c;){var f=e.nextSibling,g=f.parentNode;null!=g&&g.removeChild(f)}c=a.dom;e=c.parentNode;null!=e&&e.removeChild(c);if(c=
null!=b&&null==a.domSize)c=a.attrs,c=!(null!=c&&(c.oncreate||c.onupdate||c.onbeforeremove||c.onremove));c&&"string"===typeof a.tag&&(b.pool?b.pool.push(a):b.pool=[a])}}var d=1,m=0;if(a.attrs&&a.attrs.onbeforeremove){var f=a.attrs.onbeforeremove.call(a.state,a);null!=f&&"function"===typeof f.then&&(d++,f.then(c,c))}"string"!==typeof a.tag&&a.state.onbeforeremove&&(f=a.state.onbeforeremove(a),null!=f&&"function"===typeof f.then&&(d++,f.then(c,c)));c()}function t(a){a.attrs&&a.attrs.onremove&&a.attrs.onremove.call(a.state,
a);if("string"!==typeof a.tag&&a.state.onremove)a.state.onremove(a);if(null!=a.instance)t(a.instance);else if(a=a.children,Array.isArray(a))for(var b=0;b<a.length;b++){var c=a[b];null!=c&&t(c)}}function z(a,b,c,d,f){var e=a.dom;if("key"!==b&&"is"!==b&&(c!==d||"value"===b||"checked"===b||"selectedIndex"===b||"selected"===b&&a.dom===n.activeElement||"object"===typeof d)&&"undefined"!==typeof d&&!D(b)){var g=b.indexOf(":");if(-1<g&&"xlink"===b.substr(0,g))e.setAttributeNS("http://www.w3.org/1999/xlink",
b.slice(g+1),d);else if("o"===b[0]&&"n"===b[1]&&"function"===typeof d)M(a,b,d);else if("style"===b)if(a=c,a===d&&(e.style.cssText="",a=null),null==d)e.style.cssText="";else if("string"===typeof d)e.style.cssText=d;else{"string"===typeof a&&(e.style.cssText="");for(var m in d)e.style[m]=d[m];if(null!=a&&"string"!==typeof a)for(m in a)m in d||(e.style[m]="")}else b in e&&"href"!==b&&"list"!==b&&"form"!==b&&"width"!==b&&"height"!==b&&void 0===f&&!(a.attrs.is||-1<a.tag.indexOf("-"))?"input"===a.tag&&
"value"===b&&a.dom.value==d&&a.dom===n.activeElement||"select"===a.tag&&"value"===b&&a.dom.value==d&&a.dom===n.activeElement||"option"===a.tag&&"value"===b&&a.dom.value==d||("input"===a.tag&&"type"===b?e.setAttribute(b,d):e[b]=d):"boolean"===typeof d?d?e.setAttribute(b,""):e.removeAttribute(b):e.setAttribute("className"===b?"class":b,d)}}function D(a){return"oninit"===a||"oncreate"===a||"onupdate"===a||"onremove"===a||"onbeforeremove"===a||"onbeforeupdate"===a}function M(a,b,c){var d=a.dom,e="function"!==
typeof J?c:function(a){var b=c.call(d,a);J.call(d,a);return b};if(b in d)d[b]="function"===typeof c?e:null;else{var f=b.slice(2);void 0===a.events&&(a.events={});a.events[b]!==e&&(null!=a.events[b]&&d.removeEventListener(f,a.events[b],!1),"function"===typeof c&&(a.events[b]=e,d.addEventListener(f,a.events[b],!1)))}}function v(a,b,c){"function"===typeof a.oninit&&a.oninit.call(b.state,b);"function"===typeof a.oncreate&&c.push(a.oncreate.bind(b.state,b))}function A(a,b,c,d){d?v(a,b,c):"function"===
typeof a.onupdate&&c.push(a.onupdate.bind(b.state,b))}var n=a.document,I=n.createDocumentFragment(),J;return{render:function(a,b){if(!a)throw Error("Ensure the DOM element being passed to m.route/m.mount/m.render is not undefined.");var c=[],d=n.activeElement;null==a.vnodes&&(a.textContent="");Array.isArray(b)||(b=[b]);g(a,a.vnodes,w.normalizeChildren(b),!1,c,null,void 0);a.vnodes=b;for(var f=0;f<c.length;f++)c[f]();n.activeElement!==d&&d.focus()},setEventCallback:function(a){return J=a}}},G=function(a){function d(a){a=
f.indexOf(a);-1<a&&f.splice(a,2)}function h(){for(var a=1;a<f.length;a+=2)f[a]()}a=N(a);a.setEventCallback(function(a){!1!==a.redraw&&h()});var f=[];return{subscribe:function(a,h){d(a);f.push(a,P(h))},unsubscribe:d,redraw:h,render:a.render}}(window);K.setCompletionCallback(G.redraw);A.mount=function(a){return function(d,h){if(null===h)a.render(d,[]),a.unsubscribe(d);else{if(null==h.view&&"function"!==typeof h)throw Error("m.mount(element, component) expects a component, not a vnode");a.subscribe(d,
function(){a.render(d,w(h))});a.redraw()}}}(G);var S=v,L=function(a){if(""===a||null==a)return{};"?"===a.charAt(0)&&(a=a.slice(1));a=a.split("&");for(var d={},h={},f=0;f<a.length;f++){var g=a[f].split("="),l=decodeURIComponent(g[0]),g=2===g.length?decodeURIComponent(g[1]):"";"true"===g?g=!0:"false"===g&&(g=!1);var k=l.split(/\]\[?|\[/),q=d;-1<l.indexOf("[")&&k.pop();for(var p=0;p<k.length;p++){var l=k[p],r=k[p+1],r=""==r||!isNaN(parseInt(r,10)),u=p===k.length-1;""===l&&(l=k.slice(0,p).join(),null==
h[l]&&(h[l]=0),l=h[l]++);null==q[l]&&(q[l]=u?g:r?[]:{});q=q[l]}}return d},T=function(a){function d(d){var f=a.location[d].replace(/(?:%[a-f89][a-f0-9])+/gim,decodeURIComponent);"pathname"===d&&"/"!==f[0]&&(f="/"+f);return f}function h(a){return function(){null==k&&(k=l(function(){k=null;a()}))}}function f(a,d,f){var c=a.indexOf("?"),g=a.indexOf("#"),k=-1<c?c:-1<g?g:a.length;if(-1<c){var c=L(a.slice(c+1,-1<g?g:a.length)),h;for(h in c)d[h]=c[h]}if(-1<g)for(h in d=L(a.slice(g+1)),d)f[h]=d[h];return a.slice(0,
k)}var g="function"===typeof a.history.pushState,l="function"===typeof setImmediate?setImmediate:setTimeout,k,q={prefix:"#!",getPath:function(){switch(q.prefix.charAt(0)){case "#":return d("hash").slice(q.prefix.length);case "?":return d("search").slice(q.prefix.length)+d("hash");default:return d("pathname").slice(q.prefix.length)+d("search")+d("hash")}},setPath:function(d,h,k){var c={},l={};d=f(d,c,l);if(null!=h){for(var p in h)c[p]=h[p];d=d.replace(/:([^\/]+)/g,function(a,d){delete c[d];return h[d]})}(p=
F(c))&&(d+="?"+p);(l=F(l))&&(d+="#"+l);g?(l=k?k.state:null,p=k?k.title:null,a.onpopstate(),k&&k.replace?a.history.replaceState(l,p,q.prefix+d):a.history.pushState(l,p,q.prefix+d)):a.location.href=q.prefix+d},defineRoutes:function(d,k,l){function c(){var c=q.getPath(),g={},h=f(c,g,g),p=a.history.state;if(null!=p)for(var r in p)g[r]=p[r];for(var u in d)if(p=new RegExp("^"+u.replace(/:[^\/]+?\.{3}/g,"(.*?)").replace(/:[^\/]+/g,"([^\\/]+)")+"/?$"),p.test(h)){h.replace(p,function(){for(var a=u.match(/:[^\/]+/g)||
[],f=[].slice.call(arguments,1,-2),h=0;h<a.length;h++)g[a[h].replace(/:|\./g,"")]=decodeURIComponent(f[h]);k(d[u],g,c,u)});return}l(c,g)}g?a.onpopstate=h(c):"#"===q.prefix.charAt(0)&&(a.onhashchange=c);c()}};return q};A.route=function(a,d){var h=T(a),f=function(a){return a},g,l,k,q,p,r=function(a,c,r){if(null==a)throw Error("Ensure the DOM element that was passed to `m.route` is not undefined");var t=function(){null!=g&&d.render(a,g(w(l,k.key,k)))},u=function(a){if(a!==c)h.setPath(c,null,{replace:!0});
else throw Error("Could not resolve default route "+c);};h.defineRoutes(r,function(a,c,d){var h=p=function(a,n){h===p&&(l=null==n||"function"!==typeof n.view&&"function"!==typeof n?"div":n,k=c,q=d,p=null,g=(a.render||f).bind(a),t())};a.view||"function"===typeof a?h({},a):a.onmatch?S.resolve(a.onmatch(c,d)).then(function(c){h(a,c)},u):h(a,"div")},u);d.subscribe(a,t)};r.set=function(a,c,d){null!=p&&(d={replace:!0});p=null;h.setPath(a,c,d)};r.get=function(){return q};r.prefix=function(a){h.prefix=a};
r.link=function(a){a.dom.setAttribute("href",h.prefix+a.attrs.href);a.dom.onclick=function(a){a.ctrlKey||a.metaKey||a.shiftKey||2===a.which||(a.preventDefault(),a.redraw=!1,a=this.getAttribute("href"),0===a.indexOf(h.prefix)&&(a=a.slice(h.prefix.length)),r.set(a,void 0,void 0))}};r.param=function(a){return"undefined"!==typeof k&&"undefined"!==typeof a?k[a]:k};return r}(window,G);A.withAttr=function(a,d,h){return function(f){d.call(h||this,a in f.currentTarget?f.currentTarget[a]:f.currentTarget.getAttribute(a))}};
var U=N(window);A.render=U.render;A.redraw=G.redraw;A.request=K.request;A.jsonp=K.jsonp;A.parseQueryString=L;A.buildQueryString=F;A.version="1.0.1";A.vnode=w;"undefined"!==typeof module?module.exports=A:window.m=A};
new function(){function x(b,d,l,e,g,k){return{tag:b,key:d,attrs:l,children:e,text:g,dom:k,domSize:void 0,state:{},events:void 0,instance:void 0,skip:!1}}function B(b){if(null==b||"string"!==typeof b&&"function"!==typeof b&&"function"!==typeof b.view)throw Error("The selector must be either a string or a component.");if("string"===typeof b&&void 0===I[b]){for(var d,l,e=[],g={};d=O.exec(b);){var k=d[1],h=d[2];""===k&&""!==h?l=h:"#"===k?g.id=h:"."===k?e.push(h):"["===d[3][0]&&((k=d[6])&&(k=k.replace(/\\(["'])/g,
"$1").replace(/\\\\/g,"\\")),"class"===d[4]?e.push(k):g[d[4]]=k||!0)}0<e.length&&(g.className=e.join(" "));I[b]=function(b,d){var e=!1,a,k,n=b.className||b["class"],y;for(y in g)b[y]=g[y];void 0!==n&&(void 0!==b["class"]&&(b["class"]=void 0,b.className=n),void 0!==g.className&&(b.className=g.className+" "+n));for(y in b)if("key"!==y){e=!0;break}Array.isArray(d)&&1==d.length&&null!=d[0]&&"#"===d[0].tag?k=d[0].children:a=d;return x(l||"div",b.key,e?b:void 0,a,k,void 0)}}var r;null==arguments[1]||"object"===
typeof arguments[1]&&void 0===arguments[1].tag&&!Array.isArray(arguments[1])?(r=arguments[1],e=2):e=1;if(arguments.length===e+1)d=Array.isArray(arguments[e])?arguments[e]:[arguments[e]];else for(d=[];e<arguments.length;e++)d.push(arguments[e]);return"string"===typeof b?I[b](r||{},x.normalizeChildren(d)):x(b,r&&r.key,r||{},x.normalizeChildren(d),void 0,void 0)}function P(b){var d=0,l=null,e="function"===typeof requestAnimationFrame?requestAnimationFrame:setTimeout;return function(){var g=Date.now();
0===d||16<=g-d?(d=g,b()):null===l&&(l=e(function(){l=null;b();d=Date.now()},16-(g-d)))}}x.normalize=function(b){return Array.isArray(b)?x("[",void 0,void 0,x.normalizeChildren(b),void 0,void 0):null!=b&&"object"!==typeof b?x("#",void 0,void 0,!1===b?"":b,void 0,void 0):b};x.normalizeChildren=function(b){for(var d=0;d<b.length;d++)b[d]=x.normalize(b[d]);return b};var O=/(?:(^|#|\.)([^#\.\[\]]+))|(\[(.+?)(?:\s*=\s*("|'|)((?:\\["'\]]|.)*?)\5)?\])/g,I={};B.trust=function(b){null==b&&(b="");return x("<",
void 0,void 0,b,void 0,void 0)};B.fragment=function(b,d){return x("[",b.key,b,x.normalizeChildren(d),void 0,void 0)};var A=function(b){function d(b,a){return function t(d){var h;try{if(!a||null==d||"object"!==typeof d&&"function"!==typeof d||"function"!==typeof(h=d.then))m(function(){a||0!==b.length||console.error("Possible unhandled promise rejection:",d);for(var e=0;e<b.length;e++)b[e](d);g.length=0;k.length=0;n.state=a;n.retry=function(){t(d)}});else{if(d===e)throw new TypeError("Promise can't be resolved w/ itself");
l(h.bind(d))}}catch(Q){r(Q)}}}function l(b){function a(a){return function(b){0<d++||a(b)}}var d=0,e=a(r);try{b(a(h),e)}catch(y){e(y)}}if(!(this instanceof A))throw Error("Promise must be called with `new`");if("function"!==typeof b)throw new TypeError("executor must be a function");var e=this,g=[],k=[],h=d(g,!0),r=d(k,!1),n=e._instance={resolvers:g,rejectors:k},m="function"===typeof setImmediate?setImmediate:setTimeout;l(b)};A.prototype.then=function(b,d){function l(b,d,l,h){d.push(function(a){if("function"!==
typeof b)l(a);else try{g(b(a))}catch(w){k&&k(w)}});"function"===typeof e.retry&&h===e.state&&e.retry()}var e=this._instance,g,k,h=new A(function(b,d){g=b;k=d});l(b,e.resolvers,g,!0);l(d,e.rejectors,k,!1);return h};A.prototype["catch"]=function(b){return this.then(null,b)};A.resolve=function(b){return b instanceof A?b:new A(function(d){d(b)})};A.reject=function(b){return new A(function(d,l){l(b)})};A.all=function(b){return new A(function(d,l){var e=b.length,g=0,k=[];if(0===b.length)d([]);else for(var h=
0;h<b.length;h++)(function(h){function n(b){g++;k[h]=b;g===e&&d(k)}null==b[h]||"object"!==typeof b[h]&&"function"!==typeof b[h]||"function"!==typeof b[h].then?n(b[h]):b[h].then(n,l)})(h)})};A.race=function(b){return new A(function(d,l){for(var e=0;e<b.length;e++)b[e].then(d,l)})};"undefined"!==typeof window?("undefined"===typeof window.Promise&&(window.Promise=A),A=window.Promise):"undefined"!==typeof global&&("undefined"===typeof global.Promise&&(global.Promise=A),A=global.Promise);var F=function(b){function d(b,
e){if(Array.isArray(e))for(var g=0;g<e.length;g++)d(b+"["+g+"]",e[g]);else if("[object Object]"===Object.prototype.toString.call(e))for(g in e)d(b+"["+g+"]",e[g]);else l.push(encodeURIComponent(b)+(null!=e&&""!==e?"="+encodeURIComponent(e):""))}if("[object Object]"!==Object.prototype.toString.call(b))return"";var l=[],e;for(e in b)d(e,b[e]);return l.join("&")},R=/^file:\/\//i,L=function(b,d){function l(){function a(){0===--b&&"function"===typeof v&&v()}var b=0;return function y(d){var e=d.then;d.then=
function(){b++;var g=e.apply(d,arguments);g.then(a,function(d){a();if(0===b)throw d;});return y(g)};return d}}function e(a,b){if("string"===typeof a){var d=a;a=b||{};null==a.url&&(a.url=d)}return a}function g(a,b){if(null==b)return a;for(var d=a.match(/:[^\/]+/gi)||[],e=0;e<d.length;e++){var g=d[e].slice(1);null!=b[g]&&(a=a.replace(d[e],b[g]))}return a}function k(a,b){var d=F(b);if(""!==d){var e=0>a.indexOf("?")?"?":"&";a+=e+d}return a}function h(a){try{return""!==a?JSON.parse(a):null}catch(w){throw Error(a);
}}function r(a){return a.responseText}function n(a,b){if("function"===typeof a)if(Array.isArray(b))for(var d=0;d<b.length;d++)b[d]=new a(b[d]);else return new a(b);return b}var m=0,v;return{request:function(a,m){var v=l();a=e(a,m);var y=new d(function(d,e){null==a.method&&(a.method="GET");a.method=a.method.toUpperCase();var l="GET"===a.method||"TRACE"===a.method?!1:"boolean"===typeof a.useBody?a.useBody:!0;"function"!==typeof a.serialize&&(a.serialize="undefined"!==typeof FormData&&a.data instanceof
FormData?function(f){return f}:JSON.stringify);"function"!==typeof a.deserialize&&(a.deserialize=h);"function"!==typeof a.extract&&(a.extract=r);a.url=g(a.url,a.data);l?a.data=a.serialize(a.data):a.url=k(a.url,a.data);var m=new b.XMLHttpRequest,v=!1,y=m.abort;m.abort=function(){v=!0;y.call(m)};m.open(a.method,a.url,"boolean"===typeof a.async?a.async:!0,"string"===typeof a.user?a.user:void 0,"string"===typeof a.password?a.password:void 0);a.serialize===JSON.stringify&&l&&m.setRequestHeader("Content-Type",
"application/json; charset=utf-8");a.deserialize===h&&m.setRequestHeader("Accept","application/json, text/*");a.withCredentials&&(m.withCredentials=a.withCredentials);for(var w in a.headers)({}).hasOwnProperty.call(a.headers,w)&&m.setRequestHeader(w,a.headers[w]);"function"===typeof a.config&&(m=a.config(m,a)||m);m.onreadystatechange=function(){if(!v&&4===m.readyState)try{var f=a.extract!==r?a.extract(m,a):a.deserialize(a.extract(m,a));if(200<=m.status&&300>m.status||304===m.status||R.test(a.url))d(n(a.type,
f));else{var c=Error(m.responseText),q;for(q in f)c[q]=f[q];e(c)}}catch(p){e(p)}};l&&null!=a.data?m.send(a.data):m.send()});return!0===a.background?y:v(y)},jsonp:function(a,h){var v=l();a=e(a,h);var r=new d(function(d,e){var l=a.callbackName||"_mithril_"+Math.round(1E16*Math.random())+"_"+m++,h=b.document.createElement("script");b[l]=function(e){h.parentNode.removeChild(h);d(n(a.type,e));delete b[l]};h.onerror=function(){h.parentNode.removeChild(h);e(Error("JSONP request failed"));delete b[l]};null==
a.data&&(a.data={});a.url=g(a.url,a.data);a.data[a.callbackKey||"callback"]=l;h.src=k(a.url,a.data);b.document.documentElement.appendChild(h)});return!0===a.background?r:v(r)},setCompletionCallback:function(b){v=b}}}(window,A),N=function(b){function d(f,c,q,b,a,d,e){for(;q<b;q++){var p=c[q];null!=p&&l(f,p,a,e,d)}}function l(f,c,q,b,a){var p=c.tag;if("string"===typeof p)switch(null!=c.attrs&&B(c.attrs,c,q),p){case "#":return c.dom=C.createTextNode(c.children),m(f,c.dom,a),c.dom;case "<":return e(f,
c,a);case "[":var h=C.createDocumentFragment();null!=c.children&&(p=c.children,d(h,p,0,p.length,q,null,b));c.dom=h.firstChild;c.domSize=h.childNodes.length;m(f,h,a);return h;default:var n=c.tag;switch(c.tag){case "svg":b="http://www.w3.org/2000/svg";break;case "math":b="http://www.w3.org/1998/Math/MathML"}var k=(p=c.attrs)&&p.is,n=b?k?C.createElementNS(b,n,{is:k}):C.createElementNS(b,n):k?C.createElement(n,{is:k}):C.createElement(n);c.dom=n;if(null!=p)for(h in k=b,p)y(c,h,null,p[h],k);m(f,n,a);null!=
c.attrs&&null!=c.attrs.contenteditable?v(c):(null!=c.text&&(""!==c.text?n.textContent=c.text:c.children=[x("#",void 0,void 0,c.text,void 0,void 0)]),null!=c.children&&(f=c.children,d(n,f,0,f.length,q,null,b),f=c.attrs,"select"===c.tag&&null!=f&&("value"in f&&y(c,"value",null,f.value,void 0),"selectedIndex"in f&&y(c,"selectedIndex",null,f.selectedIndex,void 0))));return n}else{g(c,q);if(null!=c.instance){if(c.instance===c)throw Error("A view cannot return the vnode it received as arguments");q=l(f,
c.instance,q,b,a);c.dom=c.instance.dom;c.domSize=null!=c.dom?c.instance.domSize:0;m(f,q,a);c=q}else c.domSize=0,c=K;return c}}function e(f,c,b){var q={caption:"table",thead:"table",tbody:"table",tfoot:"table",tr:"tbody",th:"tr",td:"tr",colgroup:"table",col:"colgroup"}[(c.children.match(/^\s*?<(\w+)/im)||[])[1]]||"div",q=C.createElement(q);q.innerHTML=c.children;c.dom=q.firstChild;c.domSize=q.childNodes.length;c=C.createDocumentFragment();for(var a;a=q.firstChild;)c.appendChild(a);m(f,c,b);return c}
function g(f,c){var b;if("function"===typeof f.tag){f.state=null;b=f.tag;if(null!=b.$$reentrantLock$$)return K;b.$$reentrantLock$$=!0;f.state=null!=f.tag.prototype&&"function"===typeof f.tag.prototype.view?new f.tag(f):f.tag(f)}else{f.state=Object.create(f.tag);b=f.state.view;if(null!=b.$$reentrantLock$$)return K;b.$$reentrantLock$$=!0}null!=f.attrs&&B(f.attrs,f,c);B(f.state,f,c);f.instance=x.normalize(f.state.view(f));b.$$reentrantLock$$=null}function k(f,c,b,e,g,k,v){if(c!==b&&(null!=c||null!=b))if(null==
c)d(f,b,0,b.length,g,k,void 0);else if(null==b)a(c,0,c.length,b);else{if(c.length===b.length){for(var q=!1,p=0;p<b.length;p++)if(null!=b[p]&&null!=c[p]){q=null==b[p].key&&null==c[p].key;break}if(q){for(p=0;p<c.length;p++)c[p]!==b[p]&&(null==c[p]&&null!=b[p]?l(f,b[p],g,v,n(c,p+1,k)):null==b[p]?a(c,p,p+1,b):h(f,c[p],b[p],g,n(c,p+1,k),e,v));return}}if(!e)a:{if(null!=c.pool&&Math.abs(c.pool.length-b.length)<=Math.abs(c.length-b.length)&&(e=b[0]&&b[0].children&&b[0].children.length||0,Math.abs((c.pool[0]&&
c.pool[0].children&&c.pool[0].children.length||0)-e)<=Math.abs((c[0]&&c[0].children&&c[0].children.length||0)-e))){e=!0;break a}e=!1}if(e){var D=c.pool;c=c.concat(c.pool)}for(var p=q=0,w=c.length-1,y=b.length-1,G;w>=q&&y>=p;){var z=c[q],t=b[p];if(z!==t||e)if(null==z)q++;else if(null==t)p++;else if(z.key===t.key){var u=null!=D&&q>=c.length-D.length||null==D&&e;q++;p++;h(f,z,t,g,n(c,q,k),u,v);e&&z.tag===t.tag&&m(f,r(z),k)}else if(z=c[w],z!==t||e)if(null==z)w--;else if(null==t)p++;else if(z.key===t.key)u=
null!=D&&w>=c.length-D.length||null==D&&e,h(f,z,t,g,n(c,w+1,k),u,v),(e||p<y)&&m(f,r(z),n(c,q,k)),w--,p++;else break;else w--,p++;else q++,p++}for(;w>=q&&y>=p;){z=c[w];t=b[y];if(z!==t||e)if(null==z)w--;else{if(null!=t)if(z.key===t.key)u=null!=D&&w>=c.length-D.length||null==D&&e,h(f,z,t,g,n(c,w+1,k),u,v),e&&z.tag===t.tag&&m(f,r(z),k),null!=z.dom&&(k=z.dom),w--;else{if(!G){G=c;var z=w,u={},x;for(x=0;x<z;x++){var E=G[x];null!=E&&(E=E.key,null!=E&&(u[E]=x))}G=u}null!=t&&(z=G[t.key],null!=z?(u=c[z],h(f,
u,t,g,n(c,w+1,k),e,v),m(f,r(u),k),c[z].skip=!0,null!=u.dom&&(k=u.dom)):k=l(f,t,g,void 0,k))}y--}else w--,y--;if(y<p)break}d(f,b,p,y+1,g,k,v);a(c,q,w+1,b)}}function h(b,c,a,d,n,m,t){var f=c.tag;if(f===a.tag){a.state=c.state;a.events=c.events;var p;if(p=!m){var q,D;null!=a.attrs&&"function"===typeof a.attrs.onbeforeupdate&&(q=a.attrs.onbeforeupdate.call(a.state,a,c));"string"!==typeof a.tag&&"function"===typeof a.state.onbeforeupdate&&(D=a.state.onbeforeupdate(a,c));void 0===q&&void 0===D||q||D?p=!1:
(a.dom=c.dom,a.domSize=c.domSize,a.instance=c.instance,p=!0)}if(!p)if("string"===typeof f)switch(null!=a.attrs&&(m?B(a.attrs,a,d):J(a.attrs,a,d)),f){case "#":c.children.toString()!==a.children.toString()&&(c.dom.nodeValue=a.children);a.dom=c.dom;break;case "<":c.children!==a.children?(r(c),e(b,a,n)):(a.dom=c.dom,a.domSize=c.domSize);break;case "[":k(b,c.children,a.children,m,d,n,t);c=0;d=a.children;a.dom=null;if(null!=d){for(m=0;m<d.length;m++){var u=d[m];null!=u&&null!=u.dom&&(null==a.dom&&(a.dom=
u.dom),c+=u.domSize||1)}1!==c&&(a.domSize=c)}break;default:b=t;n=a.dom=c.dom;switch(a.tag){case "svg":b="http://www.w3.org/2000/svg";break;case "math":b="http://www.w3.org/1998/Math/MathML"}"textarea"===a.tag&&(null==a.attrs&&(a.attrs={}),null!=a.text&&(a.attrs.value=a.text,a.text=void 0));t=c.attrs;f=a.attrs;p=b;if(null!=f)for(u in f)y(a,u,t&&t[u],f[u],p);if(null!=t)for(u in t)null!=f&&u in f||("className"===u&&(u="class"),"o"!==u[0]||"n"!==u[1]||E(u)?"key"!==u&&a.dom.removeAttribute(u):A(a,u,void 0));
null!=a.attrs&&null!=a.attrs.contenteditable?v(a):null!=c.text&&null!=a.text&&""!==a.text?c.text.toString()!==a.text.toString()&&(c.dom.firstChild.nodeValue=a.text):(null!=c.text&&(c.children=[x("#",void 0,void 0,c.text,void 0,c.dom.firstChild)]),null!=a.text&&(a.children=[x("#",void 0,void 0,a.text,void 0,void 0)]),k(n,c.children,a.children,m,d,null,b))}else m?g(a,d):(a.instance=x.normalize(a.state.view(a)),null!=a.attrs&&J(a.attrs,a,d),J(a.state,a,d)),null!=a.instance?(null==c.instance?l(b,a.instance,
d,t,n):h(b,c.instance,a.instance,d,n,m,t),a.dom=a.instance.dom,a.domSize=a.instance.domSize):null!=c.instance?(w(c.instance,null),a.dom=void 0,a.domSize=0):(a.dom=c.dom,a.domSize=c.domSize)}else w(c,null),l(b,a,d,t,n)}function r(a){var c=a.domSize;if(null!=c||null==a.dom){var b=C.createDocumentFragment();if(0<c){for(a=a.dom;--c;)b.appendChild(a.nextSibling);b.insertBefore(a,b.firstChild)}return b}return a.dom}function n(a,c,b){for(;c<a.length;c++)if(null!=a[c]&&null!=a[c].dom)return a[c].dom;return b}
function m(a,c,b){b&&b.parentNode?a.insertBefore(c,b):a.appendChild(c)}function v(a){var c=a.children;if(null!=c&&1===c.length&&"<"===c[0].tag)c=c[0].children,a.dom.innerHTML!==c&&(a.dom.innerHTML=c);else if(null!=a.text||null!=c&&0!==c.length)throw Error("Child node of a contenteditable must be trusted");}function a(a,c,b,d){for(;c<b;c++){var f=a[c];null!=f&&(f.skip?f.skip=!1:w(f,d))}}function w(a,b){function c(){if(++d===f&&(t(a),a.dom)){var c=a.domSize||1;if(1<c)for(var e=a.dom;--c;){var p=e.nextSibling,
g=p.parentNode;null!=g&&g.removeChild(p)}c=a.dom;e=c.parentNode;null!=e&&e.removeChild(c);if(c=null!=b&&null==a.domSize)c=a.attrs,c=!(null!=c&&(c.oncreate||c.onupdate||c.onbeforeremove||c.onremove));c&&"string"===typeof a.tag&&(b.pool?b.pool.push(a):b.pool=[a])}}var f=1,d=0;if(a.attrs&&a.attrs.onbeforeremove){var e=a.attrs.onbeforeremove.call(a.state,a);null!=e&&"function"===typeof e.then&&(f++,e.then(c,c))}"string"!==typeof a.tag&&a.state.onbeforeremove&&(e=a.state.onbeforeremove(a),null!=e&&"function"===
typeof e.then&&(f++,e.then(c,c)));c()}function t(a){a.attrs&&a.attrs.onremove&&a.attrs.onremove.call(a.state,a);if("string"!==typeof a.tag&&a.state.onremove)a.state.onremove(a);if(null!=a.instance)t(a.instance);else if(a=a.children,Array.isArray(a))for(var c=0;c<a.length;c++){var b=a[c];null!=b&&t(b)}}function y(a,c,b,d,e){var f=a.dom;if("key"!==c&&"is"!==c&&(b!==d||"value"===c||"checked"===c||"selectedIndex"===c||"selected"===c&&a.dom===C.activeElement||"object"===typeof d)&&"undefined"!==typeof d&&
!E(c)){var g=c.indexOf(":");if(-1<g&&"xlink"===c.substr(0,g))f.setAttributeNS("http://www.w3.org/1999/xlink",c.slice(g+1),d);else if("o"===c[0]&&"n"===c[1]&&"function"===typeof d)A(a,c,d);else if("style"===c)if(a=b,a===d&&(f.style.cssText="",a=null),null==d)f.style.cssText="";else if("string"===typeof d)f.style.cssText=d;else{"string"===typeof a&&(f.style.cssText="");for(var n in d)f.style[n]=d[n];if(null!=a&&"string"!==typeof a)for(n in a)n in d||(f.style[n]="")}else c in f&&"href"!==c&&"list"!==
c&&"form"!==c&&"width"!==c&&"height"!==c&&void 0===e&&!(a.attrs.is||-1<a.tag.indexOf("-"))?"input"===a.tag&&"value"===c&&a.dom.value==d&&a.dom===C.activeElement||"select"===a.tag&&"value"===c&&a.dom.value==d&&a.dom===C.activeElement||"option"===a.tag&&"value"===c&&a.dom.value==d||("input"===a.tag&&"type"===c?f.setAttribute(c,d):f[c]=d):"boolean"===typeof d?d?f.setAttribute(c,""):f.removeAttribute(c):f.setAttribute("className"===c?"class":c,d)}}function E(a){return"oninit"===a||"oncreate"===a||"onupdate"===
a||"onremove"===a||"onbeforeremove"===a||"onbeforeupdate"===a}function A(a,c,b){var d=a.dom,e="function"!==typeof F?b:function(a){var c=b.call(d,a);F.call(d,a);return c};if(c in d)d[c]="function"===typeof b?e:null;else{var f=c.slice(2);void 0===a.events&&(a.events={});a.events[c]!==e&&(null!=a.events[c]&&d.removeEventListener(f,a.events[c],!1),"function"===typeof b&&(a.events[c]=e,d.addEventListener(f,a.events[c],!1)))}}function B(a,c,b){"function"===typeof a.oninit&&a.oninit.call(c.state,c);"function"===
typeof a.oncreate&&b.push(a.oncreate.bind(c.state,c))}function J(a,b,d){"function"===typeof a.onupdate&&d.push(a.onupdate.bind(b.state,b))}var C=b.document,K=C.createDocumentFragment(),F;return{render:function(a,b){if(!a)throw Error("Ensure the DOM element being passed to m.route/m.mount/m.render is not undefined.");var c=[],d=C.activeElement;null==a.vnodes&&(a.textContent="");Array.isArray(b)||(b=[b]);k(a,a.vnodes,x.normalizeChildren(b),!1,c,null,void 0);a.vnodes=b;for(var e=0;e<c.length;e++)c[e]();
C.activeElement!==d&&d.focus()},setEventCallback:function(a){return F=a}}},H=function(b){function d(b){b=e.indexOf(b);-1<b&&e.splice(b,2)}function l(){for(var b=1;b<e.length;b+=2)e[b]()}b=N(b);b.setEventCallback(function(b){!1!==b.redraw&&l()});var e=[];return{subscribe:function(b,k){d(b);e.push(b,P(k))},unsubscribe:d,redraw:l,render:b.render}}(window);L.setCompletionCallback(H.redraw);B.mount=function(b){return function(d,l){if(null===l)b.render(d,[]),b.unsubscribe(d);else{if(null==l.view&&"function"!==
typeof l)throw Error("m.mount(element, component) expects a component, not a vnode");b.subscribe(d,function(){b.render(d,x(l))});b.redraw()}}}(H);var S=A,M=function(b){if(""===b||null==b)return{};"?"===b.charAt(0)&&(b=b.slice(1));b=b.split("&");for(var d={},l={},e=0;e<b.length;e++){var g=b[e].split("="),k=decodeURIComponent(g[0]),g=2===g.length?decodeURIComponent(g[1]):"";"true"===g?g=!0:"false"===g&&(g=!1);var h=k.split(/\]\[?|\[/),r=d;-1<k.indexOf("[")&&h.pop();for(var n=0;n<h.length;n++){var k=
h[n],m=h[n+1],m=""==m||!isNaN(parseInt(m,10)),v=n===h.length-1;""===k&&(k=h.slice(0,n).join(),null==l[k]&&(l[k]=0),k=l[k]++);null==r[k]&&(r[k]=v?g:m?[]:{});r=r[k]}}return d},T=function(b){function d(d){var e=b.location[d].replace(/(?:%[a-f89][a-f0-9])+/gim,decodeURIComponent);"pathname"===d&&"/"!==e[0]&&(e="/"+e);return e}function l(b){return function(){null==h&&(h=k(function(){h=null;b()}))}}function e(b,d,e){var a=b.indexOf("?"),g=b.indexOf("#"),k=-1<a?a:-1<g?g:b.length;if(-1<a){var a=M(b.slice(a+
1,-1<g?g:b.length)),h;for(h in a)d[h]=a[h]}if(-1<g)for(h in d=M(b.slice(g+1)),d)e[h]=d[h];return b.slice(0,k)}var g="function"===typeof b.history.pushState,k="function"===typeof setImmediate?setImmediate:setTimeout,h,r={prefix:"#!",getPath:function(){switch(r.prefix.charAt(0)){case "#":return d("hash").slice(r.prefix.length);case "?":return d("search").slice(r.prefix.length)+d("hash");default:return d("pathname").slice(r.prefix.length)+d("search")+d("hash")}},setPath:function(d,h,k){var a={},l={};
d=e(d,a,l);if(null!=h){for(var m in h)a[m]=h[m];d=d.replace(/:([^\/]+)/g,function(b,d){delete a[d];return h[d]})}(m=F(a))&&(d+="?"+m);(l=F(l))&&(d+="#"+l);g?(l=k?k.state:null,m=k?k.title:null,b.onpopstate(),k&&k.replace?b.history.replaceState(l,m,r.prefix+d):b.history.pushState(l,m,r.prefix+d)):b.location.href=r.prefix+d},defineRoutes:function(d,k,h){function a(){var a=r.getPath(),g={},l=e(a,g,g),m=b.history.state;if(null!=m)for(var n in m)g[n]=m[n];for(var v in d)if(m=new RegExp("^"+v.replace(/:[^\/]+?\.{3}/g,
"(.*?)").replace(/:[^\/]+/g,"([^\\/]+)")+"/?$"),m.test(l)){l.replace(m,function(){for(var b=v.match(/:[^\/]+/g)||[],e=[].slice.call(arguments,1,-2),h=0;h<b.length;h++)g[b[h].replace(/:|\./g,"")]=decodeURIComponent(e[h]);k(d[v],g,a,v)});return}h(a,g)}g?b.onpopstate=l(a):"#"===r.prefix.charAt(0)&&(b.onhashchange=a);a()}};return r};B.route=function(b,d){var l=T(b),e=function(b){return b},g,k,h,r,n,m=function(b,a,m){if(null==b)throw Error("Ensure the DOM element that was passed to `m.route` is not undefined");
var v=function(){null!=g&&d.render(b,g(x(k,h.key,h)))},w=function(b){if(b!==a)l.setPath(a,null,{replace:!0});else throw Error("Could not resolve default route "+a);};l.defineRoutes(m,function(a,b,d){var l=n=function(a,m){l===n&&(k=null==m||"function"!==typeof m.view&&"function"!==typeof m?"div":m,h=b,r=d,n=null,g=(a.render||e).bind(a),v())};a.view||"function"===typeof a?l({},a):a.onmatch?S.resolve(a.onmatch(b,d)).then(function(b){l(a,b)},w):l(a,"div")},w);d.subscribe(b,v)};m.set=function(b,a,d){null!=
n&&(d={replace:!0});n=null;l.setPath(b,a,d)};m.get=function(){return r};m.prefix=function(b){l.prefix=b};m.link=function(b){b.dom.setAttribute("href",l.prefix+b.attrs.href);b.dom.onclick=function(a){a.ctrlKey||a.metaKey||a.shiftKey||2===a.which||(a.preventDefault(),a.redraw=!1,a=this.getAttribute("href"),0===a.indexOf(l.prefix)&&(a=a.slice(l.prefix.length)),m.set(a,void 0,void 0))}};m.param=function(b){return"undefined"!==typeof h&&"undefined"!==typeof b?h[b]:h};return m}(window,H);B.withAttr=function(b,
d,l){return function(e){d.call(l||this,b in e.currentTarget?e.currentTarget[b]:e.currentTarget.getAttribute(b))}};var U=N(window);B.render=U.render;B.redraw=H.redraw;B.request=L.request;B.jsonp=L.jsonp;B.parseQueryString=M;B.buildQueryString=F;B.version="1.0.1";B.vnode=x;"undefined"!==typeof module?module.exports=B:window.m=B};

View file

@ -20,8 +20,8 @@ module.exports = function($window) {
}
function createNode(parent, vnode, hooks, ns, nextSibling) {
var tag = vnode.tag
if (vnode.attrs != null) initLifecycle(vnode.attrs, vnode, hooks)
if (typeof tag === "string") {
if (vnode.attrs != null) initLifecycle(vnode.attrs, vnode, hooks)
switch (tag) {
case "#": return createText(parent, vnode, nextSibling)
case "<": return createHTML(parent, vnode, nextSibling)
@ -100,7 +100,7 @@ module.exports = function($window) {
}
return element
}
function createComponent(parent, vnode, hooks, ns, nextSibling) {
function initComponent(vnode, hooks) {
var sentinel
if (typeof vnode.tag === "function") {
vnode.state = null
@ -116,10 +116,13 @@ module.exports = function($window) {
sentinel.$$reentrantLock$$ = true
}
if (vnode.attrs != null) initLifecycle(vnode.attrs, vnode, hooks)
initLifecycle(vnode.state, vnode, hooks)
vnode.instance = Vnode.normalize(vnode.state.view(vnode))
sentinel.$$reentrantLock$$ = null
}
function createComponent(parent, vnode, hooks, ns, nextSibling) {
initComponent(vnode, hooks)
if (vnode.instance != null) {
if (vnode.instance === vnode) throw Error("A view cannot return the vnode it received as arguments")
var element = createNode(parent, vnode.instance, hooks, ns, nextSibling)
@ -232,11 +235,12 @@ module.exports = function($window) {
if (oldTag === tag) {
vnode.state = old.state
vnode.events = old.events
if (shouldUpdate(vnode, old)) return
if (vnode.attrs != null) {
updateLifecycle(vnode.attrs, vnode, hooks, recycling)
}
if (!recycling && shouldNotUpdate(vnode, old)) return
if (typeof oldTag === "string") {
if (vnode.attrs != null) {
if (recycling) initLifecycle(vnode.attrs, vnode, hooks)
else updateLifecycle(vnode.attrs, vnode, hooks)
}
switch (oldTag) {
case "#": updateText(old, vnode); break
case "<": updateHTML(parent, old, vnode, nextSibling); break
@ -306,8 +310,13 @@ module.exports = function($window) {
}
}
function updateComponent(parent, old, vnode, hooks, nextSibling, recycling, ns) {
vnode.instance = Vnode.normalize(vnode.state.view(vnode))
updateLifecycle(vnode.state, vnode, hooks, recycling)
if (recycling) {
initComponent(vnode, hooks)
} else {
vnode.instance = Vnode.normalize(vnode.state.view(vnode))
if (vnode.attrs != null) updateLifecycle(vnode.attrs, vnode, hooks)
updateLifecycle(vnode.state, vnode, hooks)
}
if (vnode.instance != null) {
if (old.instance == null) createNode(parent, vnode.instance, hooks, ns, nextSibling)
else updateNode(parent, old.instance, vnode.instance, hooks, nextSibling, recycling, ns)
@ -566,11 +575,10 @@ module.exports = function($window) {
if (typeof source.oninit === "function") source.oninit.call(vnode.state, vnode)
if (typeof source.oncreate === "function") hooks.push(source.oncreate.bind(vnode.state, vnode))
}
function updateLifecycle(source, vnode, hooks, recycling) {
if (recycling) initLifecycle(source, vnode, hooks)
else if (typeof source.onupdate === "function") hooks.push(source.onupdate.bind(vnode.state, vnode))
function updateLifecycle(source, vnode, hooks) {
if (typeof source.onupdate === "function") hooks.push(source.onupdate.bind(vnode.state, vnode))
}
function shouldUpdate(vnode, old) {
function shouldNotUpdate(vnode, old) {
var forceVnodeUpdate, forceComponentUpdate
if (vnode.attrs != null && typeof vnode.attrs.onbeforeupdate === "function") forceVnodeUpdate = vnode.attrs.onbeforeupdate.call(vnode.state, vnode, old)
if (typeof vnode.tag !== "string" && typeof vnode.state.onbeforeupdate === "function") forceComponentUpdate = vnode.state.onbeforeupdate(vnode, old)

View file

@ -656,6 +656,149 @@ o.spec("component", function() {
o(vnode.dom).notEquals(updated.dom)
})
o("lifecycle timing megatest (for a single component)", function() {
var methods = {
view: o.spy(function() {
return ""
})
}
var attrs = {}
var hooks = [
"oninit", "oncreate", "onbeforeupdate",
"onupdate", "onbeforeremove", "onremove"
]
hooks.forEach(function(hook) {
// the `attrs` hooks are called before the component ones
attrs[hook] = o.spy(function() {
o(attrs[hook].callCount).equals(methods[hook].callCount + 1)
})
methods[hook] = o.spy(function() {
o(attrs[hook].callCount).equals(methods[hook].callCount)
})
})
var component = createComponent(methods)
o(methods.view.callCount).equals(0)
o(methods.oninit.callCount).equals(0)
o(methods.oncreate.callCount).equals(0)
o(methods.onbeforeupdate.callCount).equals(0)
o(methods.onupdate.callCount).equals(0)
o(methods.onbeforeremove.callCount).equals(0)
o(methods.onremove.callCount).equals(0)
hooks.forEach(function(hook) {
o(attrs[hook].callCount).equals(methods[hook].callCount)(hook)
})
render(root, [{tag: component, attrs: attrs}])
o(methods.view.callCount).equals(1)
o(methods.oninit.callCount).equals(1)
o(methods.oncreate.callCount).equals(1)
o(methods.onbeforeupdate.callCount).equals(0)
o(methods.onupdate.callCount).equals(0)
o(methods.onbeforeremove.callCount).equals(0)
o(methods.onremove.callCount).equals(0)
hooks.forEach(function(hook) {
o(attrs[hook].callCount).equals(methods[hook].callCount)(hook)
})
render(root, [{tag: component, attrs: attrs}])
o(methods.view.callCount).equals(2)
o(methods.oninit.callCount).equals(1)
o(methods.oncreate.callCount).equals(1)
o(methods.onbeforeupdate.callCount).equals(1)
o(methods.onupdate.callCount).equals(1)
o(methods.onbeforeremove.callCount).equals(0)
o(methods.onremove.callCount).equals(0)
hooks.forEach(function(hook) {
o(attrs[hook].callCount).equals(methods[hook].callCount)(hook)
})
render(root, [])
o(methods.view.callCount).equals(2)
o(methods.oninit.callCount).equals(1)
o(methods.oncreate.callCount).equals(1)
o(methods.onbeforeupdate.callCount).equals(1)
o(methods.onupdate.callCount).equals(1)
o(methods.onbeforeremove.callCount).equals(1)
o(methods.onremove.callCount).equals(1)
hooks.forEach(function(hook) {
o(attrs[hook].callCount).equals(methods[hook].callCount)(hook)
})
})
o("hook state and arguments validation", function(){
var methods = {
view: o.spy(function(vnode) {
o(this).equals(vnode.state)
return ""
})
}
var attrs = {}
var hooks = [
"oninit", "oncreate", "onbeforeupdate",
"onupdate", "onbeforeremove", "onremove"
]
hooks.forEach(function(hook) {
attrs[hook] = o.spy(function(vnode){
o(this).equals(vnode.state)(hook)
})
methods[hook] = o.spy(function(vnode){
o(this).equals(vnode.state)
})
})
var component = createComponent(methods)
render(root, [{tag: component, attrs: attrs}])
render(root, [{tag: component, attrs: attrs}])
render(root, [])
hooks.forEach(function(hook) {
o(attrs[hook].this).equals(methods.view.this)(hook)
o(methods[hook].this).equals(methods.view.this)(hook)
})
o(methods.view.args.length).equals(1)
o(methods.oninit.args.length).equals(1)
o(methods.oncreate.args.length).equals(1)
o(methods.onbeforeupdate.args.length).equals(2)
o(methods.onupdate.args.length).equals(1)
o(methods.onbeforeremove.args.length).equals(1)
o(methods.onremove.args.length).equals(1)
hooks.forEach(function(hook) {
o(methods[hook].args.length).equals(attrs[hook].args.length)(hook)
})
})
o("recycled components get a fresh state", function() {
var step = 0
var firstState
var view = o.spy(function(vnode) {
if (step === 0) {
firstState = vnode.state
} else {
o(vnode.state).notEquals(firstState)
}
return {tag: 'div'}
})
var component = createComponent({view: view})
render(root, [{tag: 'div', children: [{tag: component, key: 1}]}])
var child = root.firstChild.firstChild
render(root, [])
step = 1
render(root, [{tag: 'div', children: [{tag: component, key: 1}]}])
o(child).equals(root.firstChild.firstChild)
o(view.callCount).equals(2)
})
})
o.spec("state", function() {
o("initializes state", function() {
@ -675,7 +818,7 @@ o.spec("component", function() {
o(vnode.state.data).equals(data)
}
})
o('state "copy" is shallow', function() {
o('state proxies to the component object/prototype', function() {
var called = 0
var body = {a: 1}
var data = [body]
@ -698,11 +841,10 @@ o.spec("component", function() {
})
})
o.spec("Tests specific to certain component kinds", function() {
o.spec("POJO state", function() {
o("copies state", function() {
o.spec("state", function() {
o("POJO", function() {
var called = 0
var data = {a: 1}
var data = {}
var component = {
data: data,
oninit: init,
@ -721,142 +863,52 @@ o.spec("component", function() {
o(vnode.state.x).equals(1)
}
})
})
o("Constructible", function() {
var oninit = o.spy()
var component = o.spy(function(vnode){
o(vnode.state).equals(null)
o(oninit.callCount).equals(0)
})
var view = o.spy(function(){
o(this instanceof component).equals(true)
return ""
})
component.prototype.view = view
component.prototype.oninit = oninit
o("Classes can be used as components", function() {
function MyComponent(vnode){
o(vnode.state).equals(null)
}
var proto = MyComponent.prototype
var context
var context
render(root, [{tag: component, attrs: {oninit: oninit}}])
render(root, [{tag: component, attrs: {oninit: oninit}}])
render(root, [])
proto.oninit = o.spy(function(vnode) {
o(this).equals(vnode.state)
context = this
o(component.callCount).equals(1)
o(oninit.callCount).equals(2)
o(view.callCount).equals(2)
})
proto.oncreate = o.spy()
proto.onbeforeupdate = o.spy()
proto.onupdate = o.spy()
proto.onbeforeremove = o.spy()
proto.onremove = o.spy()
proto.view = o.spy(function() {
return ""
o("Closure", function() {
var state
var oninit = o.spy()
var view = o.spy(function() {
o(this).equals(state)
return ""
})
var component = o.spy(function(vnode) {
o(vnode.state).equals(null)
o(oninit.callCount).equals(0)
return state = {
view: view
}
})
render(root, [{tag: component, attrs: {oninit: oninit}}])
render(root, [{tag: component, attrs: {oninit: oninit}}])
render(root, [])
o(component.callCount).equals(1)
o(oninit.callCount).equals(1)
o(view.callCount).equals(2)
})
render(root, [{tag: MyComponent}])
o(context instanceof MyComponent).equals(true)
o(proto.view.callCount).equals(1)
o(proto.oncreate.callCount).equals(1)
o(proto.onbeforeupdate.callCount).equals(0)
o(proto.onupdate.callCount).equals(0)
o(proto.onbeforeremove.callCount).equals(0)
o(proto.onremove.callCount).equals(0)
render(root, [{tag: MyComponent}])
o(proto.view.callCount).equals(2)
o(proto.oncreate.callCount).equals(1)
o(proto.onbeforeupdate.callCount).equals(1)
o(proto.onupdate.callCount).equals(1)
o(proto.onbeforeremove.callCount).equals(0)
o(proto.onremove.callCount).equals(0)
render(root, [])
o(proto.view.callCount).equals(2)
o(proto.oncreate.callCount).equals(1)
o(proto.onbeforeupdate.callCount).equals(1)
o(proto.onupdate.callCount).equals(1)
o(proto.onbeforeremove.callCount).equals(1)
o(proto.onremove.callCount).equals(1)
o(proto.oninit.this).equals(context)
o(proto.view.this).equals(context)
o(proto.oncreate.this).equals(context)
o(proto.onbeforeupdate.this).equals(context)
o(proto.onupdate.this).equals(context)
o(proto.onbeforeremove.this).equals(context)
o(proto.onremove.this).equals(context)
o(proto.oninit.args.length).equals(1)
o(proto.view.args.length).equals(1)
o(proto.oncreate.args.length).equals(1)
o(proto.onbeforeupdate.args.length).equals(2)
o(proto.onupdate.args.length).equals(1)
o(proto.onbeforeremove.args.length).equals(1)
o(proto.onremove.args.length).equals(1)
})
o("Closure functions can be used as components", function() {
var state, context
function component(vnode) {
o(vnode.state).equals(null)
return state = {
oninit: o.spy(function(vnode) {
o(this).equals(vnode.state)
context = this
}),
oncreate: o.spy(),
onbeforeupdate: o.spy(),
onupdate: o.spy(),
onbeforeremove: o.spy(),
onremove: o.spy(),
view: o.spy(function() {
return ""
})
}
}
render(root, [{tag: component}])
o(state).equals(context)
o(state.oninit.callCount).equals(1)
o(state.view.callCount).equals(1)
o(state.oncreate.callCount).equals(1)
o(state.onbeforeupdate.callCount).equals(0)
o(state.onupdate.callCount).equals(0)
o(state.onbeforeremove.callCount).equals(0)
o(state.onremove.callCount).equals(0)
render(root, [{tag: component}])
o(state.oninit.callCount).equals(1)
o(state.view.callCount).equals(2)
o(state.oncreate.callCount).equals(1)
o(state.onbeforeupdate.callCount).equals(1)
o(state.onupdate.callCount).equals(1)
o(state.onbeforeremove.callCount).equals(0)
o(state.onremove.callCount).equals(0)
render(root, [])
o(state.oninit.callCount).equals(1)
o(state.view.callCount).equals(2)
o(state.oncreate.callCount).equals(1)
o(state.onbeforeupdate.callCount).equals(1)
o(state.onupdate.callCount).equals(1)
o(state.onbeforeremove.callCount).equals(1)
o(state.onremove.callCount).equals(1)
o(state.oninit.this).equals(state)
o(state.view.this).equals(state)
o(state.oncreate.this).equals(state)
o(state.onbeforeupdate.this).equals(state)
o(state.onupdate.this).equals(state)
o(state.onbeforeremove.this).equals(state)
o(state.onremove.this).equals(state)
o(state.oninit.args.length).equals(1)
o(state.view.args.length).equals(1)
o(state.oncreate.args.length).equals(1)
o(state.onbeforeupdate.args.length).equals(2)
o(state.onupdate.args.length).equals(1)
o(state.onbeforeremove.args.length).equals(1)
o(state.onremove.args.length).equals(1)
})
})
})

View file

@ -120,6 +120,21 @@ o.spec("onbeforeupdate", function() {
o(count).equals(1)
})
o("doesn't fire on recycled nodes", function() {
var onbeforeupdate = o.spy()
var vnodes = [{tag: "div", key: 1}]
var temp = []
var updated = [{tag: "div", key: 1, attrs: {onbeforeupdate: onbeforeupdate}}]
render(root, vnodes)
render(root, temp)
render(root, updated)
o(vnodes[0].dom).equals(updated[0].dom)
o(updated[0].dom.nodeName).equals("DIV")
o(onbeforeupdate.callCount).equals(0)
})
components.forEach(function(cmp){
o.spec(cmp.kind, function(){
var createComponent = cmp.create