diff --git a/README.md b/README.md index c5df4082..4638fa31 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ mithril.js [![NPM Version](https://img.shields.io/npm/v/mithril.svg)](https://ww ## What is Mithril? -A modern client-side Javascript framework for building Single Page Applications. It's small (8.18 KB gzipped), fast and provides routing and XHR utilities out of the box. +A modern client-side Javascript framework for building Single Page Applications. It's small (8.22 KB gzipped), fast and provides routing and XHR utilities out of the box. Mithril is used by companies like Vimeo and Nike, and open source platforms like Lichess 👍. diff --git a/mithril.js b/mithril.js index 3b0d05be..9a3c9cba 100644 --- a/mithril.js +++ b/mithril.js @@ -963,7 +963,7 @@ var coreRenderer = function($window) { var hooks = [] var active = $doc.activeElement var namespace = dom.namespaceURI - // First time0 rendering into a node clears it out + // First time rendering0 into a node clears it out if (dom.vnodes == null) dom.textContent = "" if (!Array.isArray(vnodes)) vnodes = [vnodes] updateNodes(dom, dom.vnodes, Vnode.normalizeChildren(vnodes), false, hooks, null, namespace === "http://www.w3.org/1999/xhtml" ? undefined : namespace) @@ -975,44 +975,44 @@ var coreRenderer = function($window) { } function throttle(callback) { //60fps translates to 16.6ms, round it down since setTimeout requires int - var time = 16 + var delay = 16 var last = 0, pending = null var timeout = typeof requestAnimationFrame === "function" ? requestAnimationFrame : setTimeout return function() { - var now = Date.now() - if (last === 0 || now - last >= time) { - last = now - callback() - } - else if (pending === null) { + var elapsed = Date.now() - last + if (pending === null) { pending = timeout(function() { pending = null callback() last = Date.now() - }, time - (now - last)) + }, delay - elapsed) } } } -var _11 = function($window) { +var _11 = function($window, throttleMock) { var renderService = coreRenderer($window) renderService.setEventCallback(function(e) { if (e.redraw === false) e.redraw = undefined else redraw() }) var callbacks = [] + var rendering = false function subscribe(key1, callback) { unsubscribe(key1) - callbacks.push(key1, throttle(callback)) + callbacks.push(key1, callback) } function unsubscribe(key1) { var index = callbacks.indexOf(key1) if (index > -1) callbacks.splice(index, 2) } - function redraw() { - for (var i = 1; i < callbacks.length; i += 2) { - callbacks[i]() - } + function sync() { + if (rendering) throw new Error("Nested m.redraw.sync() call") + rendering = true + for (var i = 1; i < callbacks.length; i+=2) try {callbacks[i]()} catch (e) {/*noop*/} + rendering = false } + var redraw = (throttleMock || throttle)(sync) + redraw.sync = sync return {subscribe: subscribe, unsubscribe: unsubscribe, redraw: redraw, render: renderService.render} } var redrawService = _11(window) @@ -1031,7 +1031,7 @@ var _16 = function(redrawService0) { redrawService0.render(root, Vnode(component)) } redrawService0.subscribe(root, run0) - redrawService0.redraw() + run0() } } m.mount = _16(redrawService) @@ -1168,9 +1168,14 @@ var _20 = function($window, redrawService0) { var render1, component, attrs3, currentPath, lastUpdate var route = function(root, defaultRoute, routes) { if (root == null) throw new Error("Ensure the DOM element that was passed to `m.route` is not undefined") - var run1 = function() { + function run1() { if (render1 != null) redrawService0.render(root, render1(Vnode(component, attrs3.key, attrs3))) } + var redraw2 = function() { + run1() + redraw2 = redrawService0.redraw + } + redrawService0.subscribe(root, run1) var bail = function(path) { if (path !== defaultRoute) routeService.setPath(defaultRoute, null, {replace: true}) else throw new Error("Could not resolve default route " + defaultRoute) @@ -1181,7 +1186,7 @@ var _20 = function($window, redrawService0) { component = comp != null && (typeof comp.view === "function" || typeof comp === "function")? comp : "div" attrs3 = params, currentPath = path, lastUpdate = null render1 = (routeResolver.render || identity).bind(routeResolver) - run1() + redraw2() } if (payload.view || typeof payload === "function") update({}, payload) else { @@ -1193,7 +1198,6 @@ var _20 = function($window, redrawService0) { else update(payload, "div") } }, bail) - redrawService0.subscribe(root, run1) } route.set = function(path, data, options) { if (lastUpdate != null) { diff --git a/mithril.min.js b/mithril.min.js index d957be37..18a2e091 100644 --- a/mithril.min.js +++ b/mithril.min.js @@ -1,44 +1,44 @@ -(function(){function z(b,d,e,f,g,l){return{tag:b,key:d,attrs:e,children:f,text:g,dom:l,domSize:void 0,state:void 0,_state:void 0,events:void 0,instance:void 0,skip:!1}}function A(b){var d,e=arguments[1],f=2;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&&!(d=M[b])){var g="div";for(var l=[],k={};d=P.exec(b);){var r=d[1],p=d[2];""===r&&""!==p?g=p:"#"===r?k.id=p:"."===r?l.push(p): -"["===d[3][0]&&((r=d[6])&&(r=r.replace(/\\(["'])/g,"$1").replace(/\\\\/g,"\\")),"class"===d[4]?l.push(r):k[d[4]]=""===r?r:r||!0)}0a.indexOf("?")?"?":"&";a+=e+d}return a}function k(a){try{return""!==a?JSON.parse(a):null}catch(x){throw Error(a); -}}function r(a){return a.responseText}function p(a,b){if("function"===typeof a)if(Array.isArray(b))for(var d=0;dm.status||304===m.status||S.test(a.url))d(p(a.type, -b));else{var h=Error(m.responseText),c;for(c in b)h[c]=b[c];e(h)}}catch(q){e(q)}};f&&null!=a.data?m.send(a.data):m.send()});return!0===a.background?x:n(x)},jsonp:function(a,k){var n=e();a=f(a,k);var r=new d(function(d,e){var f=a.callbackName||"_mithril_"+Math.round(1E16*Math.random())+"_"+m++,k=b.document.createElement("script");b[f]=function(e){k.parentNode.removeChild(k);d(p(a.type,e));delete b[f]};k.onerror=function(){k.parentNode.removeChild(k);e(Error("JSONP request failed"));delete b[f]};null== -a.data&&(a.data={});a.url=g(a.url,a.data);a.data[a.callbackKey||"callback"]=f;k.src=l(a.url,a.data);b.document.documentElement.appendChild(k)});return!0===a.background?r:n(r)},setCompletionCallback:function(a){n=a}}}(window,y),O=function(b){function d(h,c,q,a,b,d,g){for(;q=n&&E>=B;){var t=c[n];u=q[B];if(t!==u||b)if(null==t)n++;else if(null==u)B++;else if(t.key===u.key){var w=null!=x&&n>=c.length-x.length||null==x&&b;n++;B++;k(h,t,u,g,p(c,n,f),w,l);b&&t.tag===u.tag&&m(h,r(t),f)}else if(t=c[v],t!==u||b)if(null==t)v--;else if(null==u)B++;else if(t.key===u.key)w=null!=x&&v>=c.length-x.length||null==x&&b, -k(h,t,u,g,p(c,v+1,f),w,l),(b||B=n&&E>=B;){t=c[v];u=q[E];if(t!==u||b)if(null==t)v--;else{if(null!=u)if(t.key===u.key)w=null!=x&&v>=c.length-x.length||null==x&&b,k(h,t,u,g,p(c,v+1,f),w,l),b&&t.tag===u.tag&&m(h,r(t),f),null!=t.dom&&(f=t.dom),v--;else{if(!H){H=c;w=v;t={};var C;for(C=0;Ca.indexOf("?")?"?":"&";a+=e+d}return a}function h(a){try{return""!==a?JSON.parse(a):null}catch(y){throw Error(a);}}function r(a){return a.responseText} +function f(a,b){if("function"===typeof a)if(Array.isArray(b))for(var d=0;dm.status||304===m.status||S.test(a.url))d(f(a.type,b));else{var k=Error(m.responseText),c; +for(c in b)k[c]=b[c];e(k)}}catch(q){e(q)}};l&&null!=a.data?m.send(a.data):m.send()});return!0===a.background?y:n(y)},jsonp:function(a,h){var r=e();a=l(a,h);var n=new d(function(d,e){var h=a.callbackName||"_mithril_"+Math.round(1E16*Math.random())+"_"+m++,l=b.document.createElement("script");b[h]=function(e){l.parentNode.removeChild(l);d(f(a.type,e));delete b[h]};l.onerror=function(){l.parentNode.removeChild(l);e(Error("JSONP request failed"));delete b[h]};null==a.data&&(a.data={});a.url=p(a.url,a.data); +a.data[a.callbackKey||"callback"]=h;l.src=g(a.url,a.data);b.document.documentElement.appendChild(l)});return!0===a.background?n:r(n)},setCompletionCallback:function(a){n=a}}}(window,w),P=function(b){function d(k,c,q,a,b,d,f){for(;q=n&&E>=B;){var t=c[n];u=q[B];if(t!==u||b)if(null==t)n++;else if(null==u)B++;else if(t.key===u.key){var x=null!=y&&n>=c.length-y.length||null==y&&b;n++;B++;h(k,t,u,l,f(c,n,g),x,p);b&&t.tag===u.tag&&m(k,r(t),g)}else if(t=c[v],t!==u||b)if(null==t)v--;else if(null==u)B++;else if(t.key===u.key)x=null!=y&&v>=c.length-y.length||null==y&&b,h(k,t,u,l,f(c,v+1,g),x,p),(b||B=n&&E>=B;){t=c[v];u=q[E];if(t!==u||b)if(null==t)v--;else{if(null!=u)if(t.key===u.key)x=null!=y&&v>=c.length-y.length||null==y&&b,h(k,t,u,l,f(c,v+1,g),x,p),b&&t.tag===u.tag&&m(k,r(t),g),null!=t.dom&&(g=t.dom),v--;else{if(!F){F=c;x=v;t={};var C;for(C=0;C