diff --git a/README.md b/README.md index 3aba4247..11a87ed7 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # Mithril.js - A framework for building brilliant applications -[Installation](docs/installation.md) | [API](docs/api.md) | [Examples](docs/examples.md) | [Migration Guide](docs/v1.x-migration.md) +[Installation](docs/installation.md) | [API](docs/api.md) | [Examples](docs/examples.md) | [Changelog/Migration Guide](docs/change-log.md) -Note: This branch is the upcoming version 1.0. It's a rewrite from the ground up and it's not backwards compatible with [Mithril 0.2.x](http://mithril.js.org). You can find preliminary [documentation here](docs) and [migration guide here](docs/v1.x-migration.md) +Note: This branch is the upcoming version 1.0. It's a rewrite from the ground up and it's not backwards compatible with [Mithril 0.2.x](http://mithril.js.org). You can find preliminary [documentation here](docs) and [migration guide here](docs/change-log.md) This rewrite aims to fix longstanding API design issues, significantly improve performance, and clean up the codebase. @@ -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.46 KB min+gzip +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 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/api/router.js b/api/router.js index c5306174..26acf219 100644 --- a/api/router.js +++ b/api/router.js @@ -15,7 +15,7 @@ module.exports = function($window, redrawService) { current.component = component current.path = path current.resolve = null - redrawService.render(root, current.render(Vnode(component, undefined, params))) + redrawService.render(root, current.render.call(resolver, Vnode(component, undefined, params))) } var run = routeService.defineRoutes(routes, function(component, params, path, route, isAction) { if (component.view) render({}, component, params, path) @@ -27,7 +27,7 @@ module.exports = function($window, redrawService) { render(component, resolved, params, path) } component.onmatch(function(resolved) { - if (current.path !== path && current.resolve != null) current.resolve(resolved) + if (current.resolve != null) current.resolve(resolved) }, params, path) } } diff --git a/api/tests/test-router.js b/api/tests/test-router.js index 302c1e27..30914607 100644 --- a/api/tests/test-router.js +++ b/api/tests/test-router.js @@ -238,25 +238,28 @@ o.spec("route", function() { } } + var resolver = { + onmatch: function(resolve, args, requestedPath) { + matchCount++ + + o(args.id).equals("abc") + o(requestedPath).equals("/abc") + o(this).equals(resolver) + resolve(Component) + }, + render: function(vnode) { + renderCount++ + + o(vnode.attrs.id).equals("abc") + o(this).equals(resolver) + + return vnode + }, + } + $window.location.href = prefix + "/abc" route(root, "/abc", { - "/:id" : { - onmatch: function(resolve, args, requestedPath) { - matchCount++ - - o(args.id).equals("abc") - o(requestedPath).equals("/abc") - - resolve(Component) - }, - render: function(vnode) { - renderCount++ - - o(vnode.attrs.id).equals("abc") - - return vnode - }, - }, + "/:id" : resolver }) o(matchCount).equals(1) @@ -514,21 +517,24 @@ o.spec("route", function() { o("m.route.set(m.route.get()) re-runs the resolution logic (#1180)", function(done){ var onmatch = o.spy(function(resolve) {resolve()}) + var render = o.spy(function(){return m("div")}) $window.location.href = prefix + "/" route(root, '/', { "/":{ onmatch: onmatch, - render: function(){return m("div")} + render: render } }) o(onmatch.callCount).equals(1) + o(render.callCount).equals(1) route.set(route.get()) setTimeout(function() { o(onmatch.callCount).equals(2) + o(render.callCount).equals(2) done() }, FRAME_BUDGET) diff --git a/mithril.js b/mithril.js index 1493aa46..8785809d 100644 --- a/mithril.js +++ b/mithril.js @@ -837,15 +837,16 @@ var coreRenderer = function($window) { //event function updateEvent(vnode, key2, value) { var element = vnode.dom - var callback = function(e) { + var callback = typeof onevent !== "function" ? value : function(e) { var result = value.call(element, e) - if (typeof onevent === "function") onevent.call(element, e) + onevent.call(element, e) return result } if (key2 in element) element[key2] = typeof value === "function" ? callback : null else { var eventName = key2.slice(2) if (vnode.events === undefined) vnode.events = {} + if (vnode.events[key2] === callback) return if (vnode.events[key2] != null) element.removeEventListener(eventName, vnode.events[key2], false) if (typeof value === "function") { vnode.events[key2] = callback @@ -1101,7 +1102,7 @@ var _20 = function($window, redrawService0) { current.component = component current.path = path current.resolve = null - redrawService0.render(root, current.render(Vnode(component, undefined, params))) + redrawService0.render(root, current.render.call(resolver, Vnode(component, undefined, params))) } var run1 = routeService.defineRoutes(routes, function(component, params, path, route, isAction) { if (component.view) render1({}, component, params, path) @@ -1113,7 +1114,7 @@ var _20 = function($window, redrawService0) { render1(component, resolved, params, path) } component.onmatch(function(resolved) { - if (current.path !== path && current.resolve != null) current.resolve(resolved) + if (current.resolve != null) current.resolve(resolved) }, params, path) } } diff --git a/mithril.min.js b/mithril.min.js index a218474f..e7b9b7d0 100644 --- a/mithril.min.js +++ b/mithril.min.js @@ -1,41 +1,41 @@ -new function(){function t(a,c,g,f,d,k){return{tag:a,key:c,attrs:g,children:f,text:d,dom:k,domSize:void 0,state:{},events:void 0,instance:void 0,skip:!1}}function A(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===I[a]){for(var c,g,f=[],d={};c=N.exec(a);){var k=c[1],m=c[2];""===k&&""!==m?g=m:"#"===k?d.id=m:"."===k?f.push(m):"["===c[3][0]&&((k=c[6])&&(k=k.replace(/\\(["'])/g,"$1").replace(/\\\\/g,"\\")), -"class"===c[4]?f.push(k):d[c[4]]=k||!0)}0b.indexOf("?")?"?":"&";b+=d+c}return b}function m(b){try{return""!==b?JSON.parse(b):null}catch(C){throw Error(b);}}function z(b){return b.responseText}function n(b,a){if("function"=== -typeof b)if(a instanceof Array)for(var c=0;cg.status||304===g.status)c(n(b.type,a));else{var d=Error(g.responseText),h;for(h in a)d[h]=a[h];f(d)}}catch(G){f(G)}};h&&null!=b.data?g.send(b.data):g.send()});return!0===b.background?r:v(r)},jsonp:function(b,h){var m=g();b=f(b,h);var r=new c(function(c,f){var g=b.callbackName|| -"_mithril_"+Math.round(1E16*Math.random())+"_"+t++,h=a.document.createElement("script");a[g]=function(d){h.parentNode.removeChild(h);c(n(b.type,d));delete a[g]};h.onerror=function(){h.parentNode.removeChild(h);f(Error("JSONP request failed"));delete a[g]};null==b.data&&(b.data={});b.url=d(b.url,b.data);b.data[b.callbackKey||"callback"]=g;h.src=k(b.url,b.data);a.document.documentElement.appendChild(h)});return!0===b.background?r:m(r)},setCompletionCallback:function(a){h=a}}}(window,"undefined"!==typeof Promise? -Promise:u),M=function(a){function c(e,l,a,b,c,d,f){for(;a=w&&v>=y;){var x=l[w],q=a[y];if(x!==q||p)if(null==x)w++;else if(null==q)y++;else if(x.key===q.key)w++,y++,k(e,x,q,b,z(l,w,d),p,f),p&&x.tag===q.tag&&n(e,m(x),d);else if(x=l[r],x!==q||p)if(null==x)r--;else if(null==q)y++;else if(x.key===q.key)k(e,x,q,b,z(l,r+1,d),p,f),(p||y=w&&v>=y;){x=l[r];q=a[v];if(x!==q||p)if(null==x)r--;else{if(null!= -q)if(x.key===q.key)k(e,x,q,b,z(l,r+1,d),p,f),p&&x.tag===q.tag&&n(e,m(x),d),null!=x.dom&&(d=x.dom),r--;else{if(!t){t=l;var x=r,C={},u;for(u=0;ub.indexOf("?")?"?":"&";b+=d+c}return b}function n(b){try{return""!==b?JSON.parse(b):null}catch(B){throw Error(b);}}function r(b){return b.responseText}function p(b,a){if("function"=== +typeof b)if(a instanceof Array)for(var c=0;cg.status||304===g.status)c(p(b.type,a));else{var d=Error(g.responseText),h;for(h in a)d[h]=a[h];f(d)}}catch(F){f(F)}};h&&null!=b.data?g.send(b.data):g.send()});return!0===b.background?t:v(t)},jsonp:function(b,h){var n=g();b=f(b,h);var t=new c(function(c,f){var g=b.callbackName|| +"_mithril_"+Math.round(1E16*Math.random())+"_"+m++,h=a.document.createElement("script");a[g]=function(d){h.parentNode.removeChild(h);c(p(b.type,d));delete a[g]};h.onerror=function(){h.parentNode.removeChild(h);f(Error("JSONP request failed"));delete a[g]};null==b.data&&(b.data={});b.url=d(b.url,b.data);b.data[b.callbackKey||"callback"]=g;h.src=k(b.url,b.data);a.document.documentElement.appendChild(h)});return!0===b.background?t:n(t)},setCompletionCallback:function(a){h=a}}}(window,"undefined"!==typeof Promise? +Promise:u),M=function(a){function c(e,l,a,b,c,d,f){for(;a=w&&v>=y;){var x=l[w],m=a[y];if(x!==m||q)if(null==x)w++;else if(null==m)y++;else if(x.key===m.key)w++,y++,k(e,x,m,b,r(l,w,d),q,f),q&&x.tag===m.tag&&p(e,n(x),d);else if(x=l[t],x!==m||q)if(null==x)t--;else if(null==m)y++;else if(x.key===m.key)k(e,x,m,b,r(l,t+1,d),q,f),(q||y=w&&v>=y;){x=l[t];m=a[v];if(x!==m||q)if(null==x)t--;else{if(null!= +m)if(x.key===m.key)k(e,x,m,b,r(l,t+1,d),q,f),q&&x.tag===m.tag&&p(e,n(x),d),null!=x.dom&&(d=x.dom),t--;else{if(!G){G=l;var x=t,B={},u;for(u=0;u