fix tests

This commit is contained in:
Leo Horie 2016-12-06 00:09:09 -05:00
parent adabc37fd7
commit 3134202d24
8 changed files with 145 additions and 119 deletions

View file

@ -34,6 +34,6 @@ There are over 4000 assertions in the test suite, and tests cover even difficult
## Modularity ## Modularity
Despite the huge improvements in performance and modularity, the new codebase is smaller than v0.2.x, currently clocking at <!-- size -->7.42 KB<!-- /size --> min+gzip Despite the huge improvements in performance and modularity, the new codebase is smaller than v0.2.x, currently clocking at <!-- size -->7.44 KB<!-- /size --> 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 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

View file

@ -7,25 +7,29 @@ module.exports = function($window, redrawService) {
var routeService = coreRouter($window) var routeService = coreRouter($window)
var identity = function(v) {return v} var identity = function(v) {return v}
var resolver, component, attrs, currentPath, waiting var resolver, component, attrs, currentPath, resolve
var route = function(root, defaultRoute, routes) { 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") if (root == null) throw new Error("Ensure the DOM element that was passed to `m.route` is not undefined")
var update = function(routeResolver, comp, params, path) { var update = function(routeResolver, comp, params, path) {
resolver = routeResolver, component = comp, attrs = params, currentPath = path, waiting = null resolver = routeResolver, component = comp, attrs = params, currentPath = path, resolve = null
resolver.render = routeResolver.render || identity resolver.render = routeResolver.render || identity
render() render()
} }
var render = function() { var render = function() {
if (resolver != null) redrawService.render(root, resolver.render(Vnode(component, attrs.key, attrs))) if (resolver != null) redrawService.render(root, resolver.render(Vnode(component || "div", attrs.key, attrs)))
} }
routeService.defineRoutes(routes, function(payload, params, path) { routeService.defineRoutes(routes, function(payload, params, path) {
if (payload.view) update({}, payload, params, path) if (payload.view) update({}, payload, params, path)
else { else {
if (payload.onmatch) { if (payload.onmatch) {
if (waiting != null) update(payload, component, params, path) if (resolve != null) update(payload, component, params, path)
else { else {
waiting = Promise.resolve(payload.onmatch(params, path)) resolve = function(resolved) {
.then(function(comp) {update(payload, comp != null ? comp : component, params, path)}) update(payload, resolved, params, path)
}
Promise.resolve(payload.onmatch(params, path)).then(function(resolved) {
if (resolve != null) resolve(resolved)
})
} }
} }
else update(payload, "div", params, path) else update(payload, "div", params, path)

View file

@ -8,6 +8,7 @@ var m = require("../../render/hyperscript")
var coreRenderer = require("../../render/render") var coreRenderer = require("../../render/render")
var apiRedraw = require("../../api/redraw") var apiRedraw = require("../../api/redraw")
var apiRouter = require("../../api/router") var apiRouter = require("../../api/router")
var Promise = require("../../promise/promise")
o.spec("route", function() { o.spec("route", function() {
void [{protocol: "http:", hostname: "localhost"}, {protocol: "file:", hostname: "/"}].forEach(function(env) { void [{protocol: "http:", hostname: "localhost"}, {protocol: "file:", hostname: "/"}].forEach(function(env) {
@ -229,7 +230,7 @@ o.spec("route", function() {
o($window.location.href).equals(env.protocol + "//" + (env.hostname === "/" ? "" : env.hostname) + slash + (prefix ? prefix + "/" : "") + "test") o($window.location.href).equals(env.protocol + "//" + (env.hostname === "/" ? "" : env.hostname) + slash + (prefix ? prefix + "/" : "") + "test")
}) })
o("accepts RouteResolver", function() { o("accepts RouteResolver", function(done) {
var matchCount = 0 var matchCount = 0
var renderCount = 0 var renderCount = 0
var Component = { var Component = {
@ -239,13 +240,13 @@ o.spec("route", function() {
} }
var resolver = { var resolver = {
onmatch: function(resolve, args, requestedPath) { onmatch: function(args, requestedPath) {
matchCount++ matchCount++
o(args.id).equals("abc") o(args.id).equals("abc")
o(requestedPath).equals("/abc") o(requestedPath).equals("/abc")
o(this).equals(resolver) o(this).equals(resolver)
resolve(Component) return Component
}, },
render: function(vnode) { render: function(vnode) {
renderCount++ renderCount++
@ -262,12 +263,15 @@ o.spec("route", function() {
"/:id" : resolver "/:id" : resolver
}) })
o(matchCount).equals(1) setTimeout(function() {
o(renderCount).equals(1) o(matchCount).equals(1)
o(root.firstChild.nodeName).equals("DIV") o(renderCount).equals(1)
o(root.firstChild.nodeName).equals("DIV")
done()
}, 20)
}) })
o("accepts RouteResolver without `render` method as payload", function() { o("accepts RouteResolver without `render` method as payload", function(done) {
var matchCount = 0 var matchCount = 0
var Component = { var Component = {
view: function() { view: function() {
@ -278,20 +282,22 @@ o.spec("route", function() {
$window.location.href = prefix + "/abc" $window.location.href = prefix + "/abc"
route(root, "/abc", { route(root, "/abc", {
"/:id" : { "/:id" : {
onmatch: function(resolve, args, requestedPath) { onmatch: function(args, requestedPath) {
matchCount++ matchCount++
o(args.id).equals("abc") o(args.id).equals("abc")
o(requestedPath).equals("/abc") o(requestedPath).equals("/abc")
resolve(Component) return Component
}, },
}, },
}) })
o(matchCount).equals(1) setTimeout(function() {
o(matchCount).equals(1)
o(root.firstChild.nodeName).equals("DIV") o(root.firstChild.nodeName).equals("DIV")
done()
}, 20)
}) })
o("changing `vnode.key` in `render` resets the component", function(done, timeout){ o("changing `vnode.key` in `render` resets the component", function(done, timeout){
@ -378,7 +384,7 @@ o.spec("route", function() {
}, FRAME_BUDGET) }, FRAME_BUDGET)
}) })
o("calls onmatch and view correct number of times", function() { o("calls onmatch and view correct number of times", function(done) {
var matchCount = 0 var matchCount = 0
var renderCount = 0 var renderCount = 0
var Component = { var Component = {
@ -390,9 +396,9 @@ o.spec("route", function() {
$window.location.href = prefix + "/" $window.location.href = prefix + "/"
route(root, "/", { route(root, "/", {
"/" : { "/" : {
onmatch: function(resolve) { onmatch: function() {
matchCount++ matchCount++
resolve(Component) return Component
}, },
render: function(vnode) { render: function(vnode) {
renderCount++ renderCount++
@ -401,13 +407,52 @@ o.spec("route", function() {
}, },
}) })
o(matchCount).equals(1) setTimeout(function() {
o(renderCount).equals(1) o(matchCount).equals(1)
o(renderCount).equals(1)
redrawService.redraw() redrawService.redraw()
o(matchCount).equals(1) o(matchCount).equals(1)
o(renderCount).equals(2) o(renderCount).equals(2)
done()
}, 20)
})
o("calls onmatch and view correct number of times when not onmatch returns undefined", function(done) {
var matchCount = 0
var renderCount = 0
var Component = {
view: function() {
return m("div")
}
}
$window.location.href = prefix + "/"
route(root, "/", {
"/" : {
onmatch: function() {
matchCount++
},
render: function(vnode) {
renderCount++
return {tag: Component}
},
},
})
setTimeout(function() {
o(matchCount).equals(1)
o(renderCount).equals(1)
redrawService.redraw()
o(matchCount).equals(1)
o(renderCount).equals(2)
done()
}, 20)
}) })
o("onmatch can redirect to another route", function(done) { o("onmatch can redirect to another route", function(done) {
@ -458,38 +503,11 @@ o.spec("route", function() {
}, FRAME_BUDGET) }, FRAME_BUDGET)
}) })
o("onmatch resolution callback resolves at most once", function(done) {
var resolveCount = 0
var resolvedComponent
var A = {view: function() {}}
var B = {view: function() {}}
var C = {view: function() {}}
$window.location.href = prefix + "/"
route(root, "/", {
"/": {
onmatch: function(resolve) {
resolve(A)
resolve(B)
callAsync(function() {resolve(C)})
},
render: function(vnode) {
resolveCount++
resolvedComponent = vnode.tag
}
},
})
setTimeout(function() {
o(resolveCount).equals(1)
o(resolvedComponent).equals(A)
done()
}, FRAME_BUDGET)
})
o("the previous view redraws while onmatch resolution is pending (#1268)", function(done) { o("the previous view redraws while onmatch resolution is pending (#1268)", function(done) {
var view = o.spy() var view = o.spy()
var onmatch = o.spy() var onmatch = o.spy(function() {
return new Promise(function() {})
})
$window.location.href = prefix + "/a" $window.location.href = prefix + "/a"
route(root, "/", { route(root, "/", {
@ -516,7 +534,7 @@ o.spec("route", function() {
}) })
o("m.route.set(m.route.get()) re-runs the resolution logic (#1180)", function(done){ o("m.route.set(m.route.get()) re-runs the resolution logic (#1180)", function(done){
var onmatch = o.spy(function(resolve) {resolve()}) var onmatch = o.spy()
var render = o.spy(function(){return m("div")}) var render = o.spy(function(){return m("div")})
$window.location.href = prefix + "/" $window.location.href = prefix + "/"
@ -527,16 +545,18 @@ o.spec("route", function() {
} }
}) })
o(onmatch.callCount).equals(1)
o(render.callCount).equals(1)
route.set(route.get())
setTimeout(function() { setTimeout(function() {
o(onmatch.callCount).equals(2) o(onmatch.callCount).equals(1)
o(render.callCount).equals(2) o(render.callCount).equals(1)
done() route.set(route.get())
setTimeout(function() {
o(onmatch.callCount).equals(2)
o(render.callCount).equals(2)
done()
}, FRAME_BUDGET)
}, FRAME_BUDGET) }, FRAME_BUDGET)
}) })
@ -544,8 +564,12 @@ o.spec("route", function() {
$window.location.href = prefix + "/" $window.location.href = prefix + "/"
route(root, "/", { route(root, "/", {
"/": {view: function(){}}, "/": {view: function() {}},
"/2": {onmatch: function(){}} "/2": {
onmatch: function() {
return new Promise(function() {})
}
}
}) })
@ -596,8 +620,10 @@ o.spec("route", function() {
$window.location.href = prefix + "/a" $window.location.href = prefix + "/a"
route(root, "/a", { route(root, "/a", {
"/a": { "/a": {
onmatch: function(resolve) { onmatch: function() {
setTimeout(resolve, 20) return new Promise(function(resolve) {
setTimeout(resolve, 20)
})
}, },
render: function(vnode) {resolved = "a"} render: function(vnode) {resolved = "a"}
}, },

View file

@ -107,18 +107,17 @@ A RouterResolver is an object that contains an `onmatch` method and/or a `render
##### routeResolver.onmatch ##### routeResolver.onmatch
The `onmatch` hook is called when the router needs to find a component to render. It is called once when a router path changes, but not on subsequent redraws. It can be used to run logic before a component initializes (for example authentication logic) The `onmatch` hook is called when the router needs to find a component to render. It is called once per router path changes, but not on subsequent redraws while on the same path. It can be used to run logic before a component initializes (for example authentication logic or analytics tracking)
This method also allows you to asynchronously define what component will be rendered, making it suitable for code splitting and asynchronous module loading. This method also allows you to asynchronously define what component will be rendered, making it suitable for code splitting and asynchronous module loading. To render a component asynchronously return a promise that resolves to a component.
`routeResolver.onmatch(resolve, args, requestedPath)` `routeResolver.onmatch(args, requestedPath)`
Argument | Type | Description Argument | Type | Description
--------------- | ------------------------ | --- --------------- | ------------------------------ | ---
`resolve` | `Component -> undefined` | Call this function with a component as the first argument to use it as the route's component `args` | `Object` | The [routing parameters](#routing-parameters)
`args` | `Object` | The [routing parameters](#routing-parameters) `requestedPath` | `String` | The router path requested by the last routing action, including interpolated routing parameter values, but without the prefix. When `onmatch` is called, the resolution for this path is not complete and `m.route.get()` still returns the previous path.
`requestedPath` | `String` | The router path requested by the last routing action, including interpolated routing parameter values, but without the prefix. When `onmatch` is called, the resolution for this path is not complete and `m.route.get()` still returns the previous path. **returns** | `Promise<Component>|undefined` | Returns a promise that resolves to a component, or undefined
**returns** | | Returns `undefined`
##### routeResolver.render ##### routeResolver.render
@ -286,8 +285,8 @@ Instead of mapping a component to a route, you can specify a RouteResolver objec
```javascript ```javascript
m.route(document.body, "/", { m.route(document.body, "/", {
"/": { "/": {
onmatch: function(resolve, args, requestedPath) { onmatch: function(args, requestedPath) {
resolve(Home) return Home
}, },
render: function(vnode) { render: function(vnode) {
return vnode // equivalent to m(Home) return vnode // equivalent to m(Home)
@ -366,10 +365,12 @@ var Login = {
m.route(document.body, "/secret", { m.route(document.body, "/secret", {
"/secret": { "/secret": {
onmatch: function(resolve) { onmatch: function() {
if (isLoggedIn) resolve(Home) if (!isLoggedIn) m.route.set("/login")
else m.route.set("/login")
}, },
render: function() {
return m(Home)
}
}, },
"/login": Login "/login": Login
}) })
@ -401,21 +402,20 @@ module.export = {
```javascript ```javascript
// index.js // index.js
function load(file, done) { function load(file) {
m.request({ return m.request({
method: "GET", method: "GET",
url: file, url: file,
extract: function(xhr) { extract: function(xhr) {
return new Function("var module = {};" + xhr.responseText + ";return module.exports;") return new Function("var module = {};" + xhr.responseText + ";return module.exports;")
} }
}) })
.run(done)
} }
m.route(document.body, "/", { m.route(document.body, "/", {
"/": { "/": {
onmatch: function(resolve) { onmatch: function() {
load("Home.js", resolve) return load("Home.js")
}, },
}, },
}) })
@ -428,9 +428,11 @@ Fortunately, there are a number of tools that facilitate the task of bundling mo
```javascript ```javascript
m.route(document.body, "/", { m.route(document.body, "/", {
"/": { "/": {
onmatch: function(resolve) { onmatch: function() {
// using Webpack async code splitting // using Webpack async code splitting
require(['./Home.js'], resolve) return new Promise(function(resolve) {
require(['./Home.js'], resolve)
})
}, },
}, },
}) })

View file

@ -995,12 +995,12 @@ var coreRouter = function($window) {
return data return data
} }
var asyncId var asyncId
function debounceAsync(f) { function debounceAsync(callback0) {
return function() { return function() {
if (asyncId != null) return if (asyncId != null) return
asyncId = callAsync0(function() { asyncId = callAsync0(function() {
asyncId = null asyncId = null
f() callback0()
}) })
} }
} }
@ -1044,7 +1044,7 @@ var coreRouter = function($window) {
if (supportsPushState) { if (supportsPushState) {
if (options && options.replace) $window.history.replaceState(null, null, prefix1 + path) if (options && options.replace) $window.history.replaceState(null, null, prefix1 + path)
else $window.history.pushState(null, null, prefix1 + path) else $window.history.pushState(null, null, prefix1 + path)
$window.onpopstate(true) $window.onpopstate()
} }
else $window.location.href = prefix1 + path else $window.location.href = prefix1 + path
} }
@ -1090,7 +1090,6 @@ var coreRouter = function($window) {
} }
var _20 = function($window, redrawService0) { var _20 = function($window, redrawService0) {
var routeService = coreRouter($window) var routeService = coreRouter($window)
var identity = function(v) {return v} var identity = function(v) {return v}
var resolver, component, attrs3, currentPath, resolve var resolver, component, attrs3, currentPath, resolve
var route = function(root, defaultRoute, routes) { var route = function(root, defaultRoute, routes) {
@ -1101,7 +1100,7 @@ var _20 = function($window, redrawService0) {
render1() render1()
} }
var render1 = function() { var render1 = function() {
if (resolver != null) redrawService0.render(root, resolver.render(Vnode(component, attrs3.key, attrs3))) if (resolver != null) redrawService0.render(root, resolver.render(Vnode(component || "div", attrs3.key, attrs3)))
} }
routeService.defineRoutes(routes, function(payload, params, path) { routeService.defineRoutes(routes, function(payload, params, path) {
if (payload.view) update({}, payload, params, path) if (payload.view) update({}, payload, params, path)
@ -1112,9 +1111,9 @@ var _20 = function($window, redrawService0) {
resolve = function(resolved) { resolve = function(resolved) {
update(payload, resolved, params, path) update(payload, resolved, params, path)
} }
payload.onmatch(function(resolved) { Promise.resolve(payload.onmatch(params, path)).then(function(resolved) {
if (resolve != null) resolve(resolved) if (resolve != null) resolve(resolved)
}, params, path) })
} }
} }
else update(payload, "div", params, path) else update(payload, "div", params, path)
@ -1131,9 +1130,9 @@ var _20 = function($window, redrawService0) {
return route return route
} }
m.route = _20(window, redrawService) m.route = _20(window, redrawService)
m.withAttr = function(attrName, callback0, context) { m.withAttr = function(attrName, callback1, context) {
return function(e) { return function(e) {
return callback0.call(context || this, attrName in e.currentTarget ? e.currentTarget[attrName] : e.currentTarget.getAttribute(attrName)) return callback1.call(context || this, attrName in e.currentTarget ? e.currentTarget[attrName] : e.currentTarget.getAttribute(attrName))
} }
} }
var _27 = coreRenderer(window) var _27 = coreRenderer(window)

8
mithril.min.js vendored
View file

@ -34,8 +34,8 @@ null==a.vnodes&&(a.textContent="");b instanceof Array||(b=[b]);g(a,a.vnodes,r.no
K.setCompletionCallback(H.redraw);y.mount=function(a){return function(c,h){if(null===h)a.render(c,[]),a.unsubscribe(c);else{if(null==h.view)throw Error("m.mount(element, component) expects a component, not a vnode");a.subscribe(c,function(){a.render(c,r(h))});a.redraw()}}}(H);var L=function(a){if(""===a||null==a)return{};"?"===a.charAt(0)&&(a=a.slice(1));a=a.split("&");for(var c={},h={},d=0;d<a.length;d++){var g=a[d].split("="),l=decodeURIComponent(g[0]),g=2===g.length?decodeURIComponent(g[1]):""; K.setCompletionCallback(H.redraw);y.mount=function(a){return function(c,h){if(null===h)a.render(c,[]),a.unsubscribe(c);else{if(null==h.view)throw Error("m.mount(element, component) expects a component, not a vnode");a.subscribe(c,function(){a.render(c,r(h))});a.redraw()}}}(H);var L=function(a){if(""===a||null==a)return{};"?"===a.charAt(0)&&(a=a.slice(1));a=a.split("&");for(var c={},h={},d=0;d<a.length;d++){var g=a[d].split("="),l=decodeURIComponent(g[0]),g=2===g.length?decodeURIComponent(g[1]):"";
"true"===g?g=!0:"false"===g&&(g=!1);var m=l.split(/\]\[?|\[/),r=c;-1<l.indexOf("[")&&m.pop();for(var n=0;n<m.length;n++){var l=m[n],t=m[n+1],t=""==t||!isNaN(parseInt(t,10)),k=n===m.length-1;""===l&&(l=m.slice(0,n).join(),null==h[l]&&(h[l]=0),l=h[l]++);null==r[l]&&(r[l]=k?g:t?[]:{});r=r[l]}}return c},R=function(a){function c(c){var b=a.location[c].replace(/(?:%[a-f89][a-f0-9])+/gim,decodeURIComponent);"pathname"===c&&"/"!==b[0]&&(b="/"+b);return b}function h(a){return function(){null==t&&(t=r(function(){t= "true"===g?g=!0:"false"===g&&(g=!1);var m=l.split(/\]\[?|\[/),r=c;-1<l.indexOf("[")&&m.pop();for(var n=0;n<m.length;n++){var l=m[n],t=m[n+1],t=""==t||!isNaN(parseInt(t,10)),k=n===m.length-1;""===l&&(l=m.slice(0,n).join(),null==h[l]&&(h[l]=0),l=h[l]++);null==r[l]&&(r[l]=k?g:t?[]:{});r=r[l]}}return c},R=function(a){function c(c){var b=a.location[c].replace(/(?:%[a-f89][a-f0-9])+/gim,decodeURIComponent);"pathname"===c&&"/"!==b[0]&&(b="/"+b);return b}function h(a){return function(){null==t&&(t=r(function(){t=
null;a()}))}}function d(a,b,c){var d=a.indexOf("?"),g=a.indexOf("#"),k=-1<d?d:-1<g?g:a.length;if(-1<d){var d=L(a.slice(d+1,-1<g?g:a.length)),h;for(h in d)b[h]=d[h]}if(-1<g)for(h in b=L(a.slice(g+1)),b)c[h]=b[h];return a.slice(0,k)}function g(){switch(n.charAt(0)){case "#":return c("hash").slice(n.length);case "?":return c("search").slice(n.length)+c("hash");default:return c("pathname").slice(n.length)+c("search")+c("hash")}}function l(c,b,g){var k={},h={};c=d(c,k,h);if(null!=b){for(var l in b)k[l]= null;a()}))}}function d(a,b,c){var d=a.indexOf("?"),g=a.indexOf("#"),k=-1<d?d:-1<g?g:a.length;if(-1<d){var d=L(a.slice(d+1,-1<g?g:a.length)),h;for(h in d)b[h]=d[h]}if(-1<g)for(h in b=L(a.slice(g+1)),b)c[h]=b[h];return a.slice(0,k)}function g(){switch(n.charAt(0)){case "#":return c("hash").slice(n.length);case "?":return c("search").slice(n.length)+c("hash");default:return c("pathname").slice(n.length)+c("search")+c("hash")}}function l(c,b,g){var k={},h={};c=d(c,k,h);if(null!=b){for(var l in b)k[l]=
b[l];c=c.replace(/:([^\/]+)/g,function(a,c){delete k[c];return b[c]})}(l=E(k))&&(c+="?"+l);(h=E(h))&&(c+="#"+h);m?(g&&g.replace?a.history.replaceState(null,null,n+c):a.history.pushState(null,null,n+c),a.onpopstate(!0)):a.location.href=n+c}var m="function"===typeof a.history.pushState,r="function"===typeof setImmediate?setImmediate:setTimeout,n="#!",t;return{setPrefix:function(a){n=a},getPath:g,setPath:l,defineRoutes:function(c,b,l){function k(){var a=g(),h={},k=d(a,h,h),m;for(m in c){var n=new RegExp("^"+ b[l];c=c.replace(/:([^\/]+)/g,function(a,c){delete k[c];return b[c]})}(l=E(k))&&(c+="?"+l);(h=E(h))&&(c+="#"+h);m?(g&&g.replace?a.history.replaceState(null,null,n+c):a.history.pushState(null,null,n+c),a.onpopstate()):a.location.href=n+c}var m="function"===typeof a.history.pushState,r="function"===typeof setImmediate?setImmediate:setTimeout,n="#!",t;return{setPrefix:function(a){n=a},getPath:g,setPath:l,defineRoutes:function(c,b,l){function k(){var a=g(),h={},k=d(a,h,h),m;for(m in c){var n=new RegExp("^"+
m.replace(/:[^\/]+?\.{3}/g,"(.*?)").replace(/:[^\/]+/g,"([^\\/]+)")+"/?$");if(n.test(k)){k.replace(n,function(){for(var d=m.match(/:[^\/]+/g)||[],g=[].slice.call(arguments,1,-2),k=0;k<d.length;k++)h[d[k].replace(/:|\./g,"")]=decodeURIComponent(g[k]);b(c[m],h,a,m)});return}}l(a,h)}m?a.onpopstate=h(k):"#"===n.charAt(0)&&(a.onhashchange=k);k()},link:function(a){a.dom.setAttribute("href",n+a.attrs.href);a.dom.onclick=function(a){a.ctrlKey||a.metaKey||a.shiftKey||2===a.which||(a.preventDefault(),a.redraw= m.replace(/:[^\/]+?\.{3}/g,"(.*?)").replace(/:[^\/]+/g,"([^\\/]+)")+"/?$");if(n.test(k)){k.replace(n,function(){for(var d=m.match(/:[^\/]+/g)||[],g=[].slice.call(arguments,1,-2),k=0;k<d.length;k++)h[d[k].replace(/:|\./g,"")]=decodeURIComponent(g[k]);b(c[m],h,a,m)});return}}l(a,h)}m?a.onpopstate=h(k):"#"===n.charAt(0)&&(a.onhashchange=k);k()},link:function(a){a.dom.setAttribute("href",n+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(n)&&(a=a.slice(n.length)),l(a,void 0,void 0))}}}};y.route=function(a,c){var h=R(a),d=function(a){return a},g,l,m,t,n,y=function(a,b,y){if(null==a)throw Error("Ensure the DOM element that was passed to `m.route` is not undefined");var k=function(a,b,c,h){g=a;l=b;m=c;t=h;n=null;g.render=a.render||d;u()},u=function(){null!=g&&c.render(a,g.render(r(l,m.key,m)))};h.defineRoutes(y,function(a,b,c){a.view?k({},a,b,c):a.onmatch?null!=n?k(a,l,b,c):(n=function(d){k(a, !1,a=this.getAttribute("href"),0===a.indexOf(n)&&(a=a.slice(n.length)),l(a,void 0,void 0))}}}};y.route=function(a,c){var h=R(a),d=function(a){return a},g,l,m,t,n,y=function(a,b,y){if(null==a)throw Error("Ensure the DOM element that was passed to `m.route` is not undefined");var k=function(a,b,c,h){g=a;l=b;m=c;t=h;n=null;g.render=a.render||d;u()},u=function(){null!=g&&c.render(a,g.render(r(l||"div",m.key,m)))};h.defineRoutes(y,function(a,b,c){a.view?k({},a,b,c):a.onmatch?null!=n?k(a,l,b,c):(n=function(d){k(a,
d,b,c)},a.onmatch(function(a){null!=n&&n(a)},b,c)):k(a,"div",b,c)},function(){h.setPath(b)});c.subscribe(a,u)};y.set=h.setPath;y.get=function(){return t};y.prefix=h.setPrefix;y.link=h.link;return y}(window,H);y.withAttr=function(a,c,h){return function(d){return c.call(h||this,a in d.currentTarget?d.currentTarget[a]:d.currentTarget.getAttribute(a))}};var S=O(window);y.render=S.render;y.redraw=H.redraw;y.request=K.request;y.jsonp=K.jsonp;y.parseQueryString=L;y.buildQueryString=E;y.version="1.0.0-rc.6"; d,b,c)},Promise.resolve(a.onmatch(b,c)).then(function(a){null!=n&&n(a)})):k(a,"div",b,c)},function(){h.setPath(b)});c.subscribe(a,u)};y.set=h.setPath;y.get=function(){return t};y.prefix=h.setPrefix;y.link=h.link;return y}(window,H);y.withAttr=function(a,c,h){return function(d){return c.call(h||this,a in d.currentTarget?d.currentTarget[a]:d.currentTarget.getAttribute(a))}};var S=O(window);y.render=S.render;y.redraw=H.redraw;y.request=K.request;y.jsonp=K.jsonp;y.parseQueryString=L;y.buildQueryString=
"undefined"!==typeof module?module.exports=y:window.m=y}; E;y.version="1.0.0-rc.6";"undefined"!==typeof module?module.exports=y:window.m=y};

View file

@ -1,6 +1,5 @@
"use strict" "use strict"
var Promise = require("../promise/promise")
var buildQueryString = require("../querystring/build") var buildQueryString = require("../querystring/build")
var parseQueryString = require("../querystring/parse") var parseQueryString = require("../querystring/parse")
@ -18,15 +17,13 @@ module.exports = function($window) {
} }
var asyncId var asyncId
function debounceAsync(f) { function debounceAsync(callback) {
return function() { return function() {
return new Promise(function(resolve, reject) { if (asyncId != null) return
if (asyncId != null) return reject() asyncId = callAsync(function() {
asyncId = callAsync(function() { asyncId = null
asyncId = null callback()
resolve(f()) })
})
});
} }
} }
@ -75,12 +72,9 @@ module.exports = function($window) {
if (supportsPushState) { if (supportsPushState) {
if (options && options.replace) $window.history.replaceState(null, null, prefix + path) if (options && options.replace) $window.history.replaceState(null, null, prefix + path)
else $window.history.pushState(null, null, prefix + path) else $window.history.pushState(null, null, prefix + path)
return $window.onpopstate() $window.onpopstate()
}
else {
$window.location.href = prefix + path
return Promise.resolve(prefix + path)
} }
else $window.location.href = prefix + path
} }
function defineRoutes(routes, resolve, reject) { function defineRoutes(routes, resolve, reject) {
@ -121,7 +115,7 @@ module.exports = function($window) {
e.redraw = false e.redraw = false
var href = this.getAttribute("href") var href = this.getAttribute("href")
if (href.indexOf(prefix) === 0) href = href.slice(prefix.length) if (href.indexOf(prefix) === 0) href = href.slice(prefix.length)
return setPath(href, undefined, undefined) setPath(href, undefined, undefined)
} }
} }

View file

@ -11,6 +11,7 @@
<script src="../../test-utils/pushStateMock.js"></script> <script src="../../test-utils/pushStateMock.js"></script>
<script src="../../test-utils/domMock.js"></script> <script src="../../test-utils/domMock.js"></script>
<script src="../../promise/promise.js"></script>
<script src="../../render/vnode.js"></script> <script src="../../render/vnode.js"></script>
<script src="../../render/render.js"></script> <script src="../../render/render.js"></script>
<script src="../../querystring/build.js"></script> <script src="../../querystring/build.js"></script>