Merge remote-tracking branch 'origin/rewrite' into rewrite

Conflicts:
	docs/route.md
This commit is contained in:
Leo Horie 2016-09-12 09:48:30 -04:00
commit 55f0dfa4dd
16 changed files with 546 additions and 392 deletions

View file

@ -2,38 +2,56 @@
var Vnode = require("../render/vnode")
var coreRouter = require("../router/router")
var autoredraw = require("../api/autoredraw")
module.exports = function($window, renderer, pubsub) {
module.exports = function($window, mount) {
var router = coreRouter($window)
var currentResolve, currentComponent, currentRender, currentArgs, currentPath
var RouteComponent = {view: function() {
return currentRender(Vnode(currentComponent, null, currentArgs, undefined, undefined, undefined))
}}
function defaultRender(vnode) {
return vnode
}
var route = function(root, defaultRoute, routes) {
var current = {path: null, component: "div", resolver: null}, currentResolutionIdentifier = null
var replay = router.defineRoutes(routes, function(payload, args, path, route) {
var resolutionIdentifier = currentResolutionIdentifier = {}
function resolve(component) {
if (resolutionIdentifier !== currentResolutionIdentifier) return
resolutionIdentifier = null
current.path = path, current.component = component
renderer.render(root, payload.render(Vnode(component, null, args, undefined, undefined, undefined)))
currentComponent = "div"
currentRender = defaultRender
currentArgs = null
mount(root, RouteComponent)
router.defineRoutes(routes, function(payload, args, path) {
var isResolver = typeof payload.view !== "function"
var render = defaultRender
var resolve = currentResolve = function (component) {
if (resolve !== currentResolve) return
currentResolve = null
currentComponent = component != null ? component : isResolver ? "div" : payload
currentRender = render
currentArgs = args
currentPath = path
root.redraw(true)
}
if (typeof payload.view !== "function") {
if (typeof payload.render !== "function") payload.render = function(vnode) {return vnode}
if (typeof payload.onmatch !== "function") payload.onmatch = function() {resolve(current.component)}
if (path !== current.path) payload.onmatch(Vnode(payload, null, args, undefined, undefined, undefined), resolve)
else resolve(current.component)
var onmatch = function() {
resolve()
}
else {
renderer.render(root, Vnode(payload, null, args, undefined, undefined, undefined))
if (isResolver) {
if (typeof payload.render === "function") render = payload.render.bind(payload)
if (typeof payload.onmatch === "function") onmatch = payload.onmatch
}
onmatch.call(payload, resolve, args, path)
}, function() {
router.setPath(defaultRoute, null, {replace: true})
})
autoredraw(root, renderer, pubsub, replay)
}
route.link = router.link
route.prefix = router.setPrefix
route.set = router.setPath
route.get = router.getPath
route.get = function() {return currentPath}
return route
}

View file

@ -22,6 +22,16 @@ o.spec("mount", function() {
render = coreRenderer($window).render
})
o("throws on invalid `root` DOM node", function() {
var threw = false
try {
mount(null, {view: function() {}})
} catch (e) {
threw = true
}
o(threw).equals(true)
})
o("renders into `root`", function() {
mount(root, {
view : function() {

View file

@ -8,13 +8,14 @@ var m = require("../../render/hyperscript")
var coreRenderer = require("../../render/render")
var apiPubSub = require("../../api/pubsub")
var apiRouter = require("../../api/router")
var apiMounter = require("../../api/mount")
o.spec("route", function() {
void [{protocol: "http:", hostname: "localhost"}, {protocol: "file:", hostname: "/"}].forEach(function(env) {
void ["#", "?", "", "#!", "?!", "/foo"].forEach(function(prefix) {
o.spec("using prefix `" + prefix + "` starting on " + env.protocol + "//" + env.hostname, function() {
var FRAME_BUDGET = Math.floor(1000 / 60)
var $window, root, redraw, route
var $window, root, redraw, mount, route
o.beforeEach(function() {
$window = browserMock(env)
@ -22,11 +23,22 @@ o.spec("route", function() {
root = $window.document.body
redraw = apiPubSub()
route = apiRouter($window, coreRenderer($window), redraw)
mount = apiMounter(coreRenderer($window), redraw)
route = apiRouter($window, mount)
route.prefix(prefix)
})
o("renders into `root`", function(done) {
o("throws on invalid `root` DOM node", function() {
var threw = false
try {
route(null, '/', {'/':{view: function() {}}})
} catch (e) {
threw = true
}
o(threw).equals(true)
})
o("renders into `root`", function() {
$window.location.href = prefix + "/"
route(root, "/", {
"/" : {
@ -36,11 +48,21 @@ o.spec("route", function() {
}
})
callAsync(function() {
o(root.firstChild.nodeName).equals("DIV")
done()
})
o(root.firstChild.nodeName).equals("DIV")
})
o("routed mount points can redraw synchronoulsy (#1275)", function() {
var view = o.spy()
$window.location.href = prefix + "/"
route(root, "/", {"/":{view:view}})
o(view.callCount).equals(1)
redraw.publish(true)
o(view.callCount).equals(2)
})
o("default route doesn't break back button", function(done) {
@ -55,11 +77,11 @@ o.spec("route", function() {
setTimeout(function() {
o(root.firstChild.nodeName).equals("DIV")
$window.history.back()
o($window.location.pathname).equals("/")
done()
}, FRAME_BUDGET)
})
@ -77,12 +99,12 @@ o.spec("route", function() {
function init(vnode) {
o(vnode.attrs.foo).equals(undefined)
done()
}
})
o("redraws when render function is executed", function(done) {
o("redraws when render function is executed", function() {
var onupdate = o.spy()
var oninit = o.spy()
@ -98,18 +120,11 @@ o.spec("route", function() {
}
})
callAsync(function() {
o(oninit.callCount).equals(1)
o(oninit.callCount).equals(1)
redraw.publish()
redraw.publish(true)
// Wrapped to give time for the rate-limited redraw to fire
setTimeout(function() {
o(onupdate.callCount).equals(1)
done()
}, FRAME_BUDGET)
})
o(onupdate.callCount).equals(1)
})
o("redraws on events", function(done) {
@ -133,23 +148,21 @@ o.spec("route", function() {
}
})
callAsync(function() {
root.firstChild.dispatchEvent(e)
root.firstChild.dispatchEvent(e)
o(oninit.callCount).equals(1)
o(oninit.callCount).equals(1)
o(onclick.callCount).equals(1)
o(onclick.this).equals(root.firstChild)
o(onclick.args[0].type).equals("click")
o(onclick.args[0].target).equals(root.firstChild)
o(onclick.callCount).equals(1)
o(onclick.this).equals(root.firstChild)
o(onclick.args[0].type).equals("click")
o(onclick.args[0].target).equals(root.firstChild)
// Wrapped to give time for the rate-limited redraw to fire
setTimeout(function() {
o(onupdate.callCount).equals(1)
// Wrapped to give time for the rate-limited redraw to fire
setTimeout(function() {
o(onupdate.callCount).equals(1)
done()
}, FRAME_BUDGET)
})
done()
}, FRAME_BUDGET * 2)
})
o("event handlers can skip redraw", function(done) {
@ -175,21 +188,19 @@ o.spec("route", function() {
}
})
callAsync(function() {
root.firstChild.dispatchEvent(e)
root.firstChild.dispatchEvent(e)
o(oninit.callCount).equals(1)
o(oninit.callCount).equals(1)
// Wrapped to ensure no redraw fired
setTimeout(function() {
o(onupdate.callCount).equals(0)
// Wrapped to ensure no redraw fired
setTimeout(function() {
o(onupdate.callCount).equals(0)
done()
}, FRAME_BUDGET)
})
done()
}, FRAME_BUDGET)
})
o("changes location on route.link", function(done) {
o("changes location on route.link", function() {
var e = $window.document.createEvent("MouseEvents")
e.initEvent("click", true, true)
@ -211,20 +222,16 @@ o.spec("route", function() {
}
})
callAsync(function() {
var slash = prefix[0] === "/" ? "" : "/"
var slash = prefix[0] === "/" ? "" : "/"
o($window.location.href).equals(env.protocol + "//" + (env.hostname === "/" ? "" : env.hostname) + slash + (prefix ? prefix + "/" : ""))
o($window.location.href).equals(env.protocol + "//" + (env.hostname === "/" ? "" : env.hostname) + slash + (prefix ? prefix + "/" : ""))
root.firstChild.dispatchEvent(e)
root.firstChild.dispatchEvent(e)
o($window.location.href).equals(env.protocol + "//" + (env.hostname === "/" ? "" : env.hostname) + slash + (prefix ? prefix + "/" : "") + "test")
done()
})
o($window.location.href).equals(env.protocol + "//" + (env.hostname === "/" ? "" : env.hostname) + slash + (prefix ? prefix + "/" : "") + "test")
})
o("accepts RouteResolver", function(done) {
o("accepts RouteResolver", function() {
var matchCount = 0
var renderCount = 0
var Component = {
@ -232,107 +239,93 @@ o.spec("route", function() {
return m("div")
}
}
$window.location.href = prefix + "/"
$window.location.href = prefix + "/abc"
route(root, "/abc", {
"/:id" : {
onmatch: function(vnode, resolve) {
onmatch: function(resolve, args, requestedPath) {
matchCount++
o(vnode.attrs.id).equals("abc")
o(route.get()).equals("/abc")
o(args.id).equals("abc")
o(requestedPath).equals("/abc")
resolve(Component)
},
render: function(vnode) {
renderCount++
o(vnode.attrs.id).equals("abc")
return vnode
},
},
})
setTimeout(function() {
o(matchCount).equals(1)
o(renderCount).equals(1)
o(root.firstChild.nodeName).equals("DIV")
done()
}, FRAME_BUDGET)
o(matchCount).equals(1)
o(renderCount).equals(1)
o(root.firstChild.nodeName).equals("DIV")
})
o("accepts RouteResolver without `render` method as payload", function(done) {
o("accepts RouteResolver without `render` method as payload", function() {
var matchCount = 0
var Component = {
view: function() {
return m("div")
}
}
$window.location.href = prefix + "/"
$window.location.href = prefix + "/abc"
route(root, "/abc", {
"/:id" : {
onmatch: function(vnode, resolve) {
onmatch: function(resolve, args, requestedPath) {
matchCount++
o(vnode.attrs.id).equals("abc")
o(route.get()).equals("/abc")
o(args.id).equals("abc")
o(requestedPath).equals("/abc")
resolve(Component)
},
},
})
setTimeout(function() {
o(matchCount).equals(1)
o(root.firstChild.nodeName).equals("DIV")
done()
}, FRAME_BUDGET)
o(matchCount).equals(1)
o(root.firstChild.nodeName).equals("DIV")
})
o("accepts RouteResolver without `onmatch` method as payload", function(done) {
o("accepts RouteResolver without `onmatch` method as payload", function() {
var renderCount = 0
var Component = {
view: function() {
return m("div")
}
}
$window.location.href = prefix + "/"
$window.location.href = prefix + "/abc"
route(root, "/abc", {
"/:id" : {
render: function(vnode) {
renderCount++
o(vnode.attrs.id).equals("abc")
return m(Component)
},
},
})
setTimeout(function() {
o(root.firstChild.nodeName).equals("DIV")
done()
}, FRAME_BUDGET)
o(root.firstChild.nodeName).equals("DIV")
})
o("RouteResolver `render` does not have component semantics", function(done, timeout) {
timeout(60)
o("RouteResolver `render` does not have component semantics", function(done) {
var renderCount = 0
var A = {
view: function() {
return m("div")
}
}
$window.location.href = prefix + "/"
$window.location.href = prefix + "/a"
route(root, "/a", {
"/a" : {
render: function(vnode) {
@ -345,22 +338,20 @@ o.spec("route", function() {
},
},
})
var dom = root.firstChild
o(root.firstChild.nodeName).equals("DIV")
route.set("/b")
setTimeout(function() {
var dom = root.firstChild
o(root.firstChild.nodeName).equals("DIV")
route.set("/b")
setTimeout(function() {
o(root.firstChild).equals(dom)
done()
}, FRAME_BUDGET)
o(root.firstChild).equals(dom)
done()
}, FRAME_BUDGET)
})
o("calls onmatch and view correct number of times", function(done) {
o("calls onmatch and view correct number of times", function() {
var matchCount = 0
var renderCount = 0
var Component = {
@ -368,11 +359,11 @@ o.spec("route", function() {
return m("div")
}
}
$window.location.href = prefix + "/"
route(root, "/", {
"/" : {
onmatch: function(vnode, resolve) {
onmatch: function(resolve) {
matchCount++
resolve(Component)
},
@ -383,69 +374,63 @@ o.spec("route", function() {
},
})
callAsync(function() {
o(matchCount).equals(1)
o(renderCount).equals(1)
redraw.publish()
o(matchCount).equals(1)
o(renderCount).equals(1)
setTimeout(function() {
o(matchCount).equals(1)
o(renderCount).equals(2)
done()
}, FRAME_BUDGET)
})
redraw.publish(true)
o(matchCount).equals(1)
o(renderCount).equals(2)
})
o("onmatch can redirect to another route", function(done) {
var redirected = false
var redirected = false
$window.location.href = prefix + "/"
route(root, "/a", {
"/a" : {
onmatch: function() {
route.set("/b")
}
},
"/b" : {
view: function(vnode){
redirected = true
}
}
})
$window.location.href = prefix + "/a"
route(root, "/a", {
"/a" : {
onmatch: function() {
route.set("/b")
}
},
"/b" : {
view: function(vnode){
redirected = true
}
}
})
setTimeout(function() {
o(redirected).equals(true)
setTimeout(function() {
o(redirected).equals(true)
done()
}, FRAME_BUDGET)
})
done()
}, FRAME_BUDGET)
})
o("onmatch can redirect to another route that has RouteResolver", function(done) {
var redirected = false
var redirected = false
$window.location.href = prefix + "/"
route(root, "/a", {
"/a" : {
onmatch: function() {
route.set("/b")
}
},
"/b" : {
render: function(vnode){
redirected = true
}
}
})
$window.location.href = prefix + "/a"
route(root, "/a", {
"/a" : {
onmatch: function() {
route.set("/b")
}
},
"/b" : {
render: function(vnode){
redirected = true
}
}
})
setTimeout(function() {
o(redirected).equals(true)
setTimeout(function() {
o(redirected).equals(true)
done()
}, FRAME_BUDGET)
})
done()
}, FRAME_BUDGET)
})
o("onmatch resolution callback resolves at most once", function(done) {
var resolveCount = 0
var resolvedComponent
@ -456,7 +441,7 @@ o.spec("route", function() {
$window.location.href = prefix + "/"
route(root, "/", {
"/": {
onmatch: function(vnode, resolve) {
onmatch: function(resolve) {
resolve(A)
resolve(B)
callAsync(function() {resolve(C)})
@ -474,15 +459,114 @@ o.spec("route", function() {
done()
}, FRAME_BUDGET)
})
o("calling route.set invalidates pending onmatch resolution", function(done, timeout) {
timeout(100)
var resolved
o("the previous view redraws while onmatch resolution is pending (#1268)", function(done) {
var view = o.spy()
var onmatch = o.spy()
$window.location.href = prefix + "/a"
route(root, "/", {
"/a": {view: view},
"/b": {onmatch: onmatch}
})
o(view.callCount).equals(1)
o(onmatch.callCount).equals(0)
route.set("/b")
setTimeout(function(){
o(view.callCount).equals(1)
o(onmatch.callCount).equals(1)
redraw.publish(true)
o(view.callCount).equals(2)
o(onmatch.callCount).equals(1)
done()
}, FRAME_BUDGET)
})
o("m.route.set(m.route.get()) re-runs the resolution logic (#1180)", function(done){
var onmatch = o.spy(function(resolve){resolve()})
$window.location.href = prefix + "/"
route(root, '/', {
"/":{
onmatch: onmatch,
render: function(){return m("div")}
}
})
o(onmatch.callCount).equals(1)
route.set(route.get())
setTimeout(function() {
o(onmatch.callCount).equals(2)
done()
}, FRAME_BUDGET)
})
o("m.route.get() returns the last fully resolved route (#1276)", function(done){
$window.location.href = prefix + "/"
route(root, "/", {
"/": {view: function(){}},
"/2": {onmatch: function(){}}
})
o(route.get()).equals("/")
route.set("/2")
setTimeout(function(){
o(route.get()).equals("/")
done()
}, FRAME_BUDGET)
})
o("routing with RouteResolver works more than once (#1286)", function(done, timeout){
timeout(FRAME_BUDGET * 3)
$window.location.href = prefix + "/a"
route(root, '/a', {
'/a': {
render: function() {
return m("a", "a")
}
},
'/b': {
render: function() {
return m("b", "b")
}
}
})
route.set('/b')
setTimeout(function(){
route.set('/a')
setTimeout(function(){
o(root.firstChild.nodeName).equals("A")
done()
}, FRAME_BUDGET)
}, FRAME_BUDGET)
})
o("calling route.set invalidates pending onmatch resolution", function(done, timeout) {
timeout(50)
var resolved
$window.location.href = prefix + "/a"
route(root, "/a", {
"/a": {
onmatch: function(vnode, resolve) {
onmatch: function(resolve) {
setTimeout(resolve, 20)
},
render: function(vnode) {resolved = "a"}
@ -491,15 +575,14 @@ o.spec("route", function() {
view: function() {resolved = "b"}
}
})
setTimeout(function() {
route.set("/b")
setTimeout(function() {
o(resolved).equals("b")
done()
}, 30)
}, FRAME_BUDGET)
route.set("/b")
setTimeout(function() {
o(resolved).equals("b")
done()
}, 30)
})
})
})

View file

@ -2,13 +2,13 @@
- [API](#api)
- [Static members](#static-members)
- [route.set](#route-set)
- [route.get](#route-get)
- [route.prefix](#route-prefix)
- [route.link](#route-link)
- [route.set](#routeset)
- [route.get](#routeget)
- [route.prefix](#routeprefix)
- [route.link](#routelink)
- [RouteResolver](#routeresolver)
- [routeResolver.onmatch](#routeresolver-onmatch)
- [routeResolver.render](#routeresolver-render)
- [routeResolver.onmatch](#routeresolveronmatch)
- [routeResolver.render](#routeresolverrender)
- [How it works](#how-it-works)
- [Typical usage](#typical-usage)
- [Navigating to different routes](#navigating-to-different-routes)
@ -52,13 +52,13 @@ Argument | Type | Required | Description
##### route.get
Returns the current routing path, without the prefix.
Returns the last fully resolved routing path, without the prefix. It may differ from the path displayed in the location bar while an asynchronous route is [pending resolution](#code-splitting).
`path = m.route.get()`
Argument | Type | Required | Description
----------------- | --------- | -------- | ---
**returns** | String | | Returns the current path
**returns** | String | | Returns the last fully resolved path
##### route.prefix
@ -94,14 +94,12 @@ This method also allows you to asynchronously define what component will be rend
`routeResolver.onmatch(vnode, resolve)`
Argument | Type | Description
------------------- | --------------------- | ---
`vnode` | `Vnode` | A [vnode](vnodes.md) whose attributes object contains routing parameters. If the routeResolver does not have a `resolve` method, the vnode's `tag` field defaults to a `div`
`vnode.attrs` | `Object` | The [routing parameters](#routing-parameters)
`vnode.attrs.path` | `String` | The current router path, including interpolated routing parameter values, but without the prefix. Same value as `m.route.get()`
`vnode.attrs.route` | `String` | The matched route
`resolve` | `Function(Component)` | Call this function with a component as the first argument to use it as the route's component
**returns** | | Returns `undefined`
Argument | Type | Description
--------------- | --------------------- | ---
`resolve` | `Function(Component)` | 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)
`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** | | Returns `undefined`
##### routeResolver.render
@ -113,8 +111,6 @@ Argument | Type | Description
------------------- | --------------- | -----------
`vnode` | `Object` | A [vnode](vnodes.md) whose attributes object contains routing parameters. If the routeResolver does not have a `resolve` method, the vnode's `tag` field defaults to a `div`
`vnode.attrs` | `Object` | A [vnode](vnodes.md) whose attributes object contains routing parameters. If the routeResolver does not have a `resolve` method, the vnode defaults to a `div`
`vnode.attrs.path` | `String` | The current router path, including interpolated routing parameter values, but without the prefix. Same value as `m.route.get()`
`vnode.attrs.route` | `String` | The matched route
**returns** | `Vnode` | Returns a vnode
---
@ -271,7 +267,7 @@ Instead of mapping a component to a route, you can specify a RouteResolver objec
```javascript
m.route(document.body, "/", {
"/": {
onmatch: function(vnode, resolve) {
onmatch: function(resolve, args, requestedPath) {
resolve(Home)
},
render: function(vnode) {
@ -351,7 +347,7 @@ var Login = {
m.route(document.body, "/secret", {
"/secret": {
onmatch: function(vnode, resolve) {
onmatch: function(resolve) {
if (isLoggedIn) resolve(Home)
else m.route.set("/login")
},
@ -399,7 +395,7 @@ function load(file, done) {
m.route(document.body, "/", {
"/": {
onmatch: function(vnode, resolve) {
onmatch: function(resolve) {
load("Home.js", resolve)
},
},
@ -413,7 +409,7 @@ Fortunately, there are a number of tools that facilitate the task of bundling mo
```javascript
m.route(document.body, "/", {
"/": {
onmatch: function(vnode, resolve) {
onmatch: function(resolve) {
// using Webpack async code splitting
require(['./Home.js'], resolve)
},

View file

@ -209,7 +209,7 @@ m.route(element, '/', {
## `m.route` mode
`m.route.mode` was replaced by `m.route.prefix(prefix)` where `prefix` can be `#`, `?`, `` (for "pathname" mode). The new API also supports hashbang (`#!`), which is the default, and it supports non-root pathnames and arbitrary mode variations such as querybang (`?!`)
`m.route.mode` was replaced by `m.route.prefix(prefix)` where `prefix` can be `#`, `?`, or an empty string (for "pathname" mode). The new API also supports hashbang (`#!`), which is the default, and it supports non-root pathnames and arbitrary mode variations such as querybang (`?!`)
## `m.route()` and anchor tags

View file

@ -10,8 +10,8 @@ var Stream = require("./stream")
requestService.setCompletionCallback(redrawService.publish)
m.route = require("./route")
m.mount = require("./mount")
m.route = require("./route")
m.withAttr = require("./util/withAttr")
m.prop = Stream
m.render = renderService.render

View file

@ -573,6 +573,7 @@ var renderService = function($window) {
Object.keys(source).forEach(function(k){target[k] = source[k]})
}
function render(dom, vnodes) {
if (!dom) throw new Error("Ensure the DOM element being passed to m.route/m.mount/m.render is not undefined.")
var hooks = []
var active = $doc.activeElement
// First time rendering into a node clears it out
@ -967,6 +968,56 @@ var parseQueryString = function(string) {
return data
}
requestService.setCompletionCallback(redrawService.publish)
var throttle = function(callback) {
//60fps translates to 16.6ms, round it down since setTimeout requires int
var time = 16
var last = 0, pending = null
var timeout = typeof requestAnimationFrame === "function" ? requestAnimationFrame : setTimeout
return function(synchronous) {
var now = Date.now()
if (synchronous === true || last === 0 || now - last >= time) {
last = now
callback()
}
else if (pending === null) {
pending = timeout(function() {
pending = null
callback()
last = Date.now()
}, time - (now - last))
}
}
}
var autoredraw = function(root, renderer, pubsub, callback) {
var run = throttle(callback)
if (renderer != null) {
renderer.setEventCallback(function(e) {
if (e.redraw !== false) pubsub.publish()
})
}
if (pubsub != null) {
if (root.redraw) pubsub.unsubscribe(root.redraw)
pubsub.subscribe(run)
}
return root.redraw = run
}
m.mount = function(renderer, pubsub) {
return function(root, component) {
if (component === null) {
renderer.render(root, [])
pubsub.unsubscribe(root.redraw)
delete root.redraw
return
}
var run = autoredraw(root, renderer, pubsub, function() {
renderer.render(
root,
Vnode(component, undefined, undefined, undefined, undefined, undefined)
)
})
run()
}
}(renderService, redrawService)
var coreRouter = function($window) {
var supportsPushState = typeof $window.history.pushState === "function"
var callAsync = typeof setImmediate === "function" ? setImmediate : setTimeout
@ -977,6 +1028,16 @@ var coreRouter = function($window) {
if (fragment === "pathname" && data[0] !== "/") data = "/" + data
return data
}
var asyncId
function debounceAsync(f) {
return function() {
if (asyncId != null) return
asyncId = callAsync(function() {
asyncId = null
f()
})
}
}
function parsePath(path, queryData, hashData) {
var queryIndex = path.indexOf("?")
var hashIndex = path.indexOf("#")
@ -1022,7 +1083,7 @@ var coreRouter = function($window) {
else $window.location.href = prefix + path
}
function defineRoutes(routes, resolve, reject) {
if (supportsPushState) $window.onpopstate = resolveRoute
if (supportsPushState) $window.onpopstate = debounceAsync(resolveRoute)
else if (prefix.charAt(0) === "#") $window.onhashchange = resolveRoute
resolveRoute()
@ -1031,23 +1092,21 @@ var coreRouter = function($window) {
var params = {}
var pathname = parsePath(path, params, params)
callAsync(function() {
for (var route in routes) {
var matcher = new RegExp("^" + route.replace(/:[^\/]+?\.{3}/g, "(.*?)").replace(/:[^\/]+/g, "([^\\/]+)") + "\/?$")
if (matcher.test(pathname)) {
pathname.replace(matcher, function() {
var keys = route.match(/:[^\/]+/g) || []
var values = [].slice.call(arguments, 1, -2)
for (var i = 0; i < keys.length; i++) {
params[keys[i].replace(/:|\./g, "")] = decodeURIComponent(values[i])
}
resolve(routes[route], params, path, route)
})
return
}
for (var route in routes) {
var matcher = new RegExp("^" + route.replace(/:[^\/]+?\.{3}/g, "(.*?)").replace(/:[^\/]+/g, "([^\\/]+)") + "\/?$")
if (matcher.test(pathname)) {
pathname.replace(matcher, function() {
var keys = route.match(/:[^\/]+/g) || []
var values = [].slice.call(arguments, 1, -2)
for (var i = 0; i < keys.length; i++) {
params[keys[i].replace(/:|\./g, "")] = decodeURIComponent(values[i])
}
resolve(routes[route], params, path, route)
})
return
}
reject(path, params)
})
}
reject(path, params)
}
return resolveRoute
}
@ -1061,89 +1120,52 @@ var coreRouter = function($window) {
}
return {setPrefix: setPrefix, getPath: getPath, setPath: setPath, defineRoutes: defineRoutes, link: link}
}
var throttle = function(callback) {
//60fps translates to 16.6ms, round it down since setTimeout requires int
var time = 16
var last = 0, pending = null
var timeout = typeof requestAnimationFrame === "function" ? requestAnimationFrame : setTimeout
return function(synchronous) {
var now = Date.now()
if (synchronous === true || last === 0 || now - last >= time) {
last = now
callback()
}
else if (pending === null) {
pending = timeout(function() {
pending = null
callback()
last = Date.now()
}, time - (now - last))
}
}
}
var autoredraw = function(root, renderer, pubsub, callback) {
var run = throttle(callback)
if (renderer != null) {
renderer.setEventCallback(function(e) {
if (e.redraw !== false) pubsub.publish()
})
}
if (pubsub != null) {
if (root.redraw) pubsub.unsubscribe(root.redraw)
pubsub.subscribe(run)
}
return root.redraw = run
}
m.route = function($window, renderer, pubsub) {
m.route = function($window, mount1) {
var router = coreRouter($window)
var globalId, currentComponent, currentRender, currentArgs, currentPath
var RouteComponent = {view: function() {
return currentRender(Vnode(currentComponent, null, currentArgs, undefined, undefined, undefined))
}}
function defaultRender(vnode) {
return vnode
}
var route = function(root, defaultRoute, routes) {
var current = {path: null, component: "div", resolver: null}, currentResolutionIdentifier = null
var replay = router.defineRoutes(routes, function(payload, args, path, route) {
var resolutionIdentifier = currentResolutionIdentifier = {}
function resolve(component) {
if (resolutionIdentifier !== currentResolutionIdentifier) return
resolutionIdentifier = null
current.path = path, current.component = component
renderer.render(root, payload.render(Vnode(component, null, args, undefined, undefined, undefined)))
currentComponent = "div"
currentRender = defaultRender
currentArgs = null
mount1(root, RouteComponent)
router.defineRoutes(routes, function(payload, args, path) {
var resolutionIdentifier = globalId = {}
var isResolver = typeof payload.view !== "function"
var render = defaultRender
function resolve (component) {
if (resolutionIdentifier !== globalId) return
globalId = null
currentComponent = component != null ? component : isResolver ? "div" : payload
currentRender = render
currentArgs = args
currentPath = path
root.redraw(true)
}
if (typeof payload.view !== "function") {
if (typeof payload.render !== "function") payload.render = function(vnode) {return vnode}
if (typeof payload.onmatch !== "function") payload.onmatch = function() {resolve(current.component)}
if (path !== current.path) payload.onmatch(Vnode(payload, null, args, undefined, undefined, undefined), resolve)
else resolve(current.component)
var onmatch = function() {
resolve()
}
else {
renderer.render(root, Vnode(payload, null, args, undefined, undefined, undefined))
if (isResolver) {
if (typeof payload.render === "function") render = payload.render.bind(payload)
if (typeof payload.onmatch === "function") onmatch = payload.onmatch
}
onmatch.call(payload, resolve, args, path)
}, function() {
router.setPath(defaultRoute, null, {replace: true})
})
autoredraw(root, renderer, pubsub, replay)
}
route.link = router.link
route.prefix = router.setPrefix
route.set = router.setPath
route.get = router.getPath
route.get = function() {return currentPath}
return route
}(window, renderService, redrawService)
m.mount = function(renderer, pubsub) {
return function(root, component) {
if (component === null) {
renderer.render(root, [])
pubsub.unsubscribe(root.redraw)
delete root.redraw
return
}
var run = autoredraw(root, renderer, pubsub, function() {
renderer.render(
root,
Vnode(component, undefined, undefined, undefined, undefined, undefined)
)
})
run()
}
}(renderService, redrawService)
}(window, m.mount)
m.withAttr = function(attrName, callback, context) {
return function(e) {
return callback.call(context || this, attrName in e.currentTarget ? e.currentTarget[attrName] : e.currentTarget.getAttribute(attrName))

83
mithril.min.js vendored
View file

@ -1,41 +1,42 @@
new function(){function u(d,e,p,g,k,m){return{tag:d,key:e,attrs:p,children:g,text:k,dom:m,domSize:void 0,state:{},events:void 0,instance:void 0,skip:!1}}function x(d){if(null==d||"string"!==typeof d&&null==d.view)throw Error("The selector must be either a string or a component.");if("string"===typeof d&&void 0===H[d]){for(var e,p,g=[],k={};e=P.exec(d);){var m=e[1],n=e[2];""===m&&""!==n?p=n:"#"===m?k.id=n:"."===m?g.push(n):"["===e[3][0]&&((m=e[6])&&(m=m.replace(/\\(["'])/g,"$1").replace(/\\\\/g,"\\")),
k[e[4]]=m||!0)}0<g.length&&(k.className=g.join(" "));H[d]=function(d,c){var e=!1,g,h,m=d.className||d["class"],n;for(n in k)d[n]=k[n];void 0!==m&&(void 0!==d["class"]&&(d["class"]=void 0,d.className=m),void 0!==k.className&&(d.className=k.className+" "+m));for(n in d)if("key"!==n){e=!0;break}c instanceof Array&&1==c.length&&null!=c[0]&&"#"===c[0].tag?h=c[0].children:g=c;return u(p||"div",d.key,e?d:void 0,g,h,void 0)}}var l;null!=arguments[1]&&("object"!==typeof arguments[1]||void 0!==arguments[1].tag||
arguments[1]instanceof Array)?g=1:(l=arguments[1],g=2);if(arguments.length===g+1)e=arguments[g]instanceof Array?arguments[g]:[arguments[g]];else for(e=[];g<arguments.length;g++)e.push(arguments[g]);return"string"===typeof d?H[d](l||{},u.normalizeChildren(e)):u(d,l&&l.key,l||{},u.normalizeChildren(e),void 0,void 0)}u.normalize=function(d){return d instanceof Array?u("[",void 0,void 0,u.normalizeChildren(d),void 0,void 0):null!=d&&"object"!==typeof d?u("#",void 0,void 0,d,void 0,void 0):d};u.normalizeChildren=
function(d){for(var e=0;e<d.length;e++)d[e]=u.normalize(d[e]);return d};var P=/(?:(^|#|\.)([^#\.\[\]]+))|(\[(.+?)(?:\s*=\s*("|'|)((?:\\["'\]]|.)*?)\5)?\])/g,H={};x.trust=function(d){return u("<",void 0,void 0,d,void 0,void 0)};x.fragment=function(d,e){return u("[",d.key,d,u.normalizeChildren(e),void 0,void 0)};var F=function(d){function e(b,a,f,c,d,e,q){for(;f<c;f++){var r=a[f];null!=r&&t(b,p(r,d,q),e)}}function p(b,a,f){var c=b.tag;null!=b.attrs&&J(b.attrs,b,a);if("string"===typeof c)switch(c){case "#":return b.dom=
y.createTextNode(b.children);case "<":return g(b);case "[":var d=y.createDocumentFragment();null!=b.children&&(c=b.children,e(d,c,0,c.length,a,null,f));b.dom=d.firstChild;b.domSize=d.childNodes.length;return d;default:var t=b.tag;switch(b.tag){case "svg":f="http://www.w3.org/2000/svg";break;case "math":f="http://www.w3.org/1998/Math/MathML"}var q=(c=b.attrs)&&c.is,t=f?q?y.createElementNS(f,t,{is:q}):y.createElementNS(f,t):q?y.createElement(t,{is:q}):y.createElement(t);b.dom=t;if(null!=c)for(d in q=
f,c)v(b,d,null,c[d],q);null!=b.text&&(""!==b.text?t.textContent=b.text:b.children=[u("#",void 0,void 0,b.text,void 0,void 0)]);null!=b.children&&(d=b.children,e(t,d,0,d.length,a,null,f),a=b.attrs,"select"===b.tag&&null!=a&&("value"in a&&v(b,"value",null,a.value,void 0),"selectedIndex"in a&&v(b,"selectedIndex",null,a.selectedIndex,void 0)));return t}else{b.state||(b.state={});K(b.state,b.tag);J(b.tag,b,a);b.instance=u.normalize(b.tag.view.call(b.state,b));if(null!=b.instance){if(b.instance===b)throw Error("A view cannot return the vnode it received as arguments");
a=p(b.instance,a,f);b.dom=b.instance.dom;b.domSize=null!=b.dom?b.instance.domSize:0;b=a}else b.domSize=0,b=D;return b}}function g(b){var a={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",a=y.createElement(a);a.innerHTML=b.children;b.dom=a.firstChild;b.domSize=a.childNodes.length;b=y.createDocumentFragment();for(var f;f=a.firstChild;)b.appendChild(f);return b}function k(b,a,f,d,
h,g){if(a!==f&&(null!=a||null!=f))if(null==a)e(b,f,0,f.length,d,h,void 0);else if(null==f)c(b,a,0,a.length,f);else{var q;a:{if(null!=a.pool&&Math.abs(a.pool.length-f.length)<=Math.abs(a.length-f.length)&&(q=f[0]&&f[0].children&&f[0].children.length||0,Math.abs((a.pool[0]&&a.pool[0].children&&a.pool[0].children.length||0)-q)<=Math.abs((a[0]&&a[0].children&&a[0].children.length||0)-q))){q=!0;break a}q=!1}q&&(a=a.concat(a.pool));if(a.length===f.length&&null!=f[0]&&null==f[0].key)for(var r=0;r<a.length;r++)a[r]===
f[r]||null==a[r]&&null==f[r]||(null==a[r]?t(b,p(f[r],d,g),l(a,r+1,h)):null==f[r]?c(b,a,r,r+1,f):m(b,a[r],f[r],d,l(a,r+1,h),q,g),q&&a[r].tag===f[r].tag&&t(b,n(a[r]),l(a,r+1,h)));else{for(var B=r=0,k=a.length-1,z=f.length-1,A;k>=r&&z>=B;){var v=a[r],w=f[B];if(v===w)r++,B++;else if(null!=v&&null!=w&&v.key===w.key)r++,B++,m(b,v,w,d,l(a,r,h),q,g),q&&v.tag===w.tag&&t(b,n(v),h);else if(v=a[k],v===w)k--,B++;else if(null!=v&&null!=w&&v.key===w.key)m(b,v,w,d,l(a,k+1,h),q,g),B<z&&t(b,n(v),l(a,r,h)),k--,B++;
else break}for(;k>=r&&z>=B;){v=a[k];w=f[z];if(v===w)k--;else if(null!=v&&null!=w&&v.key===w.key)m(b,v,w,d,l(a,k+1,h),q,g),q&&v.tag===w.tag&&t(b,n(v),h),null!=v.dom&&(h=v.dom),k--;else{if(!A){A=a;var v=k,u={},y;for(y=0;y<v;y++){var C=A[y];null!=C&&(C=C.key,null!=C&&(u[C]=y))}A=u}null!=w&&(v=A[w.key],null!=v?(u=a[v],m(b,u,w,d,l(a,k+1,h),q,g),t(b,n(u),h),a[v].skip=!0,null!=u.dom&&(h=u.dom)):(w=p(w,d,void 0),t(b,w,h),h=w))}z--;if(z<B)break}e(b,f,B,z+1,d,h,g);c(b,a,r,k+1,f)}}}function m(b,a,f,c,d,e,q){var r=
a.tag;if(r===f.tag){f.state=a.state;f.events=a.events;var h;var z;null!=f.attrs&&"function"===typeof f.attrs.onbeforeupdate&&(h=f.attrs.onbeforeupdate.call(f.state,f,a));"string"!==typeof f.tag&&"function"===typeof f.tag.onbeforeupdate&&(z=f.tag.onbeforeupdate.call(f.state,f,a));void 0===h&&void 0===z||h||z?h=!1:(f.dom=a.dom,f.domSize=a.domSize,f.instance=a.instance,h=!0);if(!h)if(null!=f.attrs&&x(f.attrs,f,c,e),"string"===typeof r)switch(r){case "#":a.children.toString()!==f.children.toString()&&
(a.dom.nodeValue=f.children);f.dom=a.dom;break;case "<":a.children!==f.children?(n(a),t(b,g(f),d)):(f.dom=a.dom,f.domSize=a.domSize);break;case "[":k(b,a.children,f.children,c,d,q);a=0;c=f.children;f.dom=null;if(null!=c){for(var l=0;l<c.length;l++)b=c[l],null!=b&&null!=b.dom&&(null==f.dom&&(f.dom=b.dom),a+=b.domSize||1);1!==a&&(f.domSize=a)}break;default:b=q;d=f.dom=a.dom;switch(f.tag){case "svg":b="http://www.w3.org/2000/svg";break;case "math":b="http://www.w3.org/1998/Math/MathML"}"textarea"===
f.tag&&(null==f.attrs&&(f.attrs={}),null!=f.text&&(f.attrs.value=f.text));e=a.attrs;q=f.attrs;r=b;if(null!=q)for(l in q)v(f,l,e&&e[l],q[l],r);if(null!=e)for(l in e)null!=q&&l in q||("o"!==l[0]||"n"!==l[1]||w(l)?"key"!==l&&f.dom.removeAttribute(l):C(f,l,void 0));null!=a.text&&null!=f.text&&""!==f.text?a.text.toString()!==f.text.toString()&&(a.dom.firstChild.nodeValue=f.text):(null!=a.text&&(a.children=[u("#",void 0,void 0,a.text,void 0,a.dom.firstChild)]),null!=f.text&&(f.children=[u("#",void 0,void 0,
f.text,void 0,void 0)]),k(d,a.children,f.children,c,null,b))}else f.instance=u.normalize(f.tag.view.call(f.state,f)),x(f.tag,f,c,e),null!=f.instance?(null==a.instance?t(b,p(f.instance,c,q),d):m(b,a.instance,f.instance,c,d,e,q),f.dom=f.instance.dom,f.domSize=f.instance.domSize):null!=a.instance?(A(b,a.instance,null),f.dom=void 0,f.domSize=0):(f.dom=a.dom,f.domSize=a.domSize)}else A(b,a,null),t(b,p(f,c,void 0),d)}function n(b){var a=b.domSize;if(null!=a||null==b.dom){var f=y.createDocumentFragment();
if(0<a){for(b=b.dom;--a;)f.appendChild(b.nextSibling);f.insertBefore(b,f.firstChild)}return f}return b.dom}function l(b,a,f){for(;a<b.length;a++)if(null!=b[a]&&null!=b[a].dom)return b[a].dom;return f}function t(b,a,f){f&&f.parentNode?b.insertBefore(a,f):b.appendChild(a)}function c(b,a,f,c,d){for(;f<c;f++){var e=a[f];null!=e&&(e.skip?e.skip=!1:A(b,e,d))}}function z(b){var a=!1;return function(){a||(a=!0,b())}}function A(b,a,f){function c(){if(++e===d&&(h(a),a.dom)){var q=a.domSize||1;if(1<q)for(var r=
a.dom;--q;)b.removeChild(r.nextSibling);null!=a.dom.parentNode&&b.removeChild(a.dom);if(q=null!=f&&null==a.domSize)q=a.attrs,q=!(null!=q&&(q.oncreate||q.onupdate||q.onbeforeremove||q.onremove));q&&"string"===typeof a.tag&&(f.pool?f.pool.push(a):f.pool=[a])}}var d=1,e=0;a.attrs&&a.attrs.onbeforeremove&&(d++,a.attrs.onbeforeremove.call(a.state,a,z(c)));"string"!==typeof a.tag&&a.tag.onbeforeremove&&(d++,a.tag.onbeforeremove.call(a.state,a,z(c)));c()}function h(b){b.attrs&&b.attrs.onremove&&b.attrs.onremove.call(b.state,
b);"string"!==typeof b.tag&&b.tag.onremove&&b.tag.onremove.call(b.state,b);if(null!=b.instance)h(b.instance);else if(b=b.children,b instanceof Array)for(var a=0;a<b.length;a++){var f=b[a];null!=f&&h(f)}}function v(b,a,f,c,d){var e=b.dom;if("key"!==a&&(f!==c||"value"===a||"checked"===a||"selectedIndex"===a||"selected"===a&&b.dom===y.activeElement||"object"===typeof c)&&"undefined"!==typeof c&&!w(a)){var q=a.indexOf(":");if(-1<q&&"xlink"===a.substr(0,q))e.setAttributeNS("http://www.w3.org/1999/xlink",
a.slice(q+1),c);else if("o"===a[0]&&"n"===a[1]&&"function"===typeof c)C(b,a,c);else if("style"===a)if(b=f,b===c&&(e.style.cssText="",b=null),null==c)e.style.cssText="";else if("string"===typeof c)e.style.cssText=c;else{"string"===typeof b&&(e.style.cssText="");for(var r in c)e.style[r]=c[r];if(null!=b&&"string"!==typeof b)for(r in b)r in c||(e.style[r]="")}else if(a in e&&"href"!==a&&"list"!==a&&"form"!==a&&void 0===d){if("input"!==b.tag||"value"!==a||b.dom.value!==c||b.dom!==y.activeElement)e[a]=
c}else"boolean"===typeof c?c?e.setAttribute(a,""):e.removeAttribute(a):e.setAttribute("className"===a?"class":a,c)}}function w(b){return"oninit"===b||"oncreate"===b||"onupdate"===b||"onremove"===b||"onbeforeremove"===b||"onbeforeupdate"===b}function C(b,a,c){var d=b.dom,e=function(a){var b=c.call(d,a);"function"===typeof I&&I.call(d,a);return b};if(a in d)d[a]=e;else{var h=a.slice(2);void 0===b.events&&(b.events={});null!=b.events[a]&&d.removeEventListener(h,b.events[a],!1);"function"===typeof c&&
(b.events[a]=e,d.addEventListener(h,b.events[a],!1))}}function J(b,a,c){"function"===typeof b.oninit&&b.oninit.call(a.state,a);"function"===typeof b.oncreate&&c.push(b.oncreate.bind(a.state,a))}function x(b,a,c,d){d?J(b,a,c):"function"===typeof b.onupdate&&c.push(b.onupdate.bind(a.state,a))}function K(b,a){Object.keys(a).forEach(function(c){b[c]=a[c]})}var y=d.document,D=y.createDocumentFragment(),I;return{render:function(b,a){var c=[],d=y.activeElement;null==b.vnodes&&(b.textContent="");a instanceof
Array||(a=[a]);k(b,b.vnodes,u.normalizeChildren(a),c,null,void 0);b.vnodes=a;for(var e=0;e<c.length;e++)c[e]();y.activeElement!==d&&d.focus()},setEventCallback:function(b){return I=b}}}(window),N=function(d){function e(){function a(){0<arguments.length&&arguments[0]!==E&&g(a,arguments[0],void 0);return a._state.value}p(a,arguments);0<arguments.length&&arguments[0]!==E&&g(a,arguments[0],void 0);return a}function p(a,b){a.constructor=e;a._state={id:H++,value:void 0,error:void 0,state:0,derive:void 0,
recover:void 0,deps:{},parents:[],errorStream:void 0,endStream:void 0};a.map=D;a.ap=K;a.of=e;a.valueOf=y;a.toJSON=G;a.toString=y;a.run=z;a["catch"]=A;Object.defineProperties(a,{error:{get:function(){if(!a._state.errorStream){var b=function(){0<arguments.length&&arguments[0]!==E&&g(a,void 0,arguments[0]);return a._state.error};p(b,[]);w(b,[a],F,F);a._state.errorStream=b}return a._state.errorStream}},end:{get:function(){if(!a._state.endStream){var b=e();b.map(function(c){!0===c&&(x(a),x(b));return c});
a._state.endStream=b}return a._state.endStream}}})}function g(a,b,c){k(a,b,c);for(var d in a._state.deps)n(a._state.deps[d],!1);a._state.changed=!1;for(var f in a._state.deps)a._state.deps[f]._state.changed=!1}function k(a,b,c){c=t(b,c);if(void 0!==c&&"function"===typeof a._state.recover){if(!l(a,m,!0))return}else m(a,b,c);a._state.changed=!0;2!==a._state.state&&(a._state.state=1)}function m(a,b,c){a._state.value=b;a._state.error=c}function n(a,c){var d=a._state.parents;0<d.length&&d.filter(I).length===
d.length&&(c||0<d.filter(b).length)&&(d=d.filter(f),0<d.length?k(a,void 0,d[0]._state.error):l(a,k,!1))}function l(a,b,d){try{var f=d?a._state.recover():a._state.derive();if(f===E)return!1;b(a,f,void 0)}catch(e){b(a,void 0,null!=e.__error?e.__error:e),null==e.__error&&c(a,e)}return!0}function t(a,b){null!=a&&a.constructor===e&&(b=void 0!==a._state.error?a._state.error:t(a._state.value,a._state.error));return b}function c(a,b){0===Object.keys(a._state.deps).length&&setTimeout(function(){0===Object.keys(a._state.deps).length&&
d(b)},0)}function z(a){var b=e(),c=this;return w(b,[c],function(){return v(b,a(c()))},void 0)}function A(a){var b=e(),c=this;return w(b,[c],function(){return c._state.value},function(){return v(b,a(c._state.error))})}function h(a,c){return w(e(),c,function(){var d=c.filter(f);if(0<d.length)throw{__error:d[0]._state.error};return a.apply(this,c.concat([c.filter(b)]))},void 0)}function v(a,b){if(null!=b&&b.constructor===e){var c=b,d=function(){k(a,c._state.value,c._state.error);for(var b in a._state.deps)n(a._state.deps[b],
!1)};c.map(d)["catch"](function(a){d();throw{__error:a};});if(0===c._state.state)return E;if(c._state.error)throw{__error:c._state.error};b=c._state.value}return b}function w(b,c,d,f){var e=b._state;e.derive=d;e.recover=f;e.parents=c.filter(a);u(b,e.parents);n(b,!0);return b}function u(a,b){for(var c=0;c<b.length;c++)b[c]._state.deps[a._state.id]=a,u(a,b[c]._state.parents)}function x(a){for(var b=0;b<a._state.parents.length;b++)delete a._state.parents[b]._state.deps[a._state.id];for(var c in a._state.deps){var b=
a._state.deps[c],d=b._state.parents.indexOf(a);-1<d&&b._state.parents.splice(d,1)}a._state.state=2;a._state.deps={}}function D(a){return h(function(b){return a(b())},[this])}function K(a){return h(function(a,b){return a()(b())},[this,a])}function y(){return this._state.value}function G(){return null!=this._state.value&&"function"===typeof this._state.value.toJSON?this._state.value.toJSON():this._state.value}function I(a){return 1===a._state.state}function b(a){return a._state.changed}function a(a){return 2!==
a._state.state}function f(a){return a._state.error}var H=0,F=function(){},E={};e.merge=function(a){return h(function(){return a.map(function(a){return a()})},a)};e.combine=h;e.reject=function(a){var b=e();b.error(a);return b};e.HALT=E;return e}(console.log.bind(console)),D=function(d){function e(d,g){if(g instanceof Array)for(var n=0;n<g.length;n++)e(d+"["+n+"]",g[n]);else if("[object Object]"===Object.prototype.toString.call(g))for(n in g)e(d+"["+n+"]",g[n]);else p.push(encodeURIComponent(d)+(null!=
g&&""!==g?"="+encodeURIComponent(g):""))}if("[object Object]"!==Object.prototype.toString.call(d))return"";var p=[],g;for(g in d)e(g,d[g]);return p.join("&")},L=function(d,e){function p(c,d){if(null==d)return c;for(var e=c.match(/:[^\/]+/gi)||[],h=0;h<e.length;h++){var g=e[h].slice(1);null!=d[g]&&(c=c.replace(e[h],d[g]),delete d[g])}return c}function g(c,d){var e=D(d);if(""!==e){var h=0>c.indexOf("?")?"?":"&";c+=h+e}return c}function k(c){try{return""!==c?JSON.parse(c):null}catch(d){throw Error(c);
}}function m(c){return c.responseText}function n(c,d){if("function"===typeof c)if(d instanceof Array)for(var e=0;e<d.length;e++)d[e]=new c(d[e]);else return new c(d);return d}var l=0,t;return{request:function(c){var l=e();void 0!==c.initialValue&&l(c.initialValue);var A="boolean"===typeof c.useBody?c.useBody:"GET"!==c.method&&"TRACE"!==c.method;"function"!==typeof c.serialize&&(c.serialize="undefined"!==typeof FormData&&c.data instanceof FormData?function(c){return c}:JSON.stringify);"function"!==
typeof c.deserialize&&(c.deserialize=k);"function"!==typeof c.extract&&(c.extract=m);c.url=p(c.url,c.data);A?c.data=c.serialize(c.data):c.url=g(c.url,c.data);var h=new d.XMLHttpRequest;h.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&&A&&h.setRequestHeader("Content-Type","application/json; charset=utf-8");c.deserialize===k&&h.setRequestHeader("Accept","application/json, text/*");
"function"===typeof c.config&&(h=c.config(h,c)||h);h.onreadystatechange=function(){if(4===h.readyState){try{var d=c.extract!==m?c.extract(h,c):c.deserialize(c.extract(h,c));if(200<=h.status&&300>h.status)l(n(c.type,d));else{var e=Error(h.responseText),g;for(g in d)e[g]=d[g];l.error(e)}}catch(k){l.error(k)}"function"===typeof t&&t()}};A?h.send(c.data):h.send();return l},jsonp:function(c){var k=e();void 0!==c.initialValue&&k(c.initialValue);var m=c.callbackName||"_mithril_"+Math.round(1E16*Math.random())+
"_"+l++,h=d.document.createElement("script");d[m]=function(e){h.parentNode.removeChild(h);k(n(c.type,e));"function"===typeof t&&t();delete d[m]};h.onerror=function(){h.parentNode.removeChild(h);k.error(Error("JSONP request failed"));"function"===typeof t&&t();delete d[m]};null==c.data&&(c.data={});c.url=p(c.url,c.data);c.data[c.callbackKey||"callback"]=m;h.src=g(c.url,c.data);d.document.documentElement.appendChild(h);return k},setCompletionCallback:function(c){t=c}}}(window,N),G=function(){var d=
[];return{subscribe:d.push.bind(d),unsubscribe:function(e){e=d.indexOf(e);-1<e&&d.splice(e,1)},publish:function(){for(var e=0;e<d.length;e++)d[e].apply(this,arguments)}}}(),M=function(d){if(""===d||null==d)return{};"?"===d.charAt(0)&&(d=d.slice(1));d=d.split("&");for(var e={},p={},g=0;g<d.length;g++){var k=d[g].split("="),m=decodeURIComponent(k[0]),k=2===k.length?decodeURIComponent(k[1]):"",n=Number(k);""!==k&&!isNaN(n)||"NaN"===k?k=n:"true"===k?k=!0:"false"===k?k=!1:(n=new Date(k),isNaN(n.getTime())||
(k=n));var n=m.split(/\]\[?|\[/),l=e;-1<m.indexOf("[")&&n.pop();for(var t=0;t<n.length;t++){var m=n[t],c=n[t+1],c=""==c||!isNaN(parseInt(c,10)),z=t===n.length-1;""===m&&(m=n.slice(0,t).join(),null==p[m]&&(p[m]=0),m=p[m]++);null==l[m]&&(l[m]=z?k:c?[]:{});l=l[m]}}return e};L.setCompletionCallback(G.publish);var Q=function(d){function e(e){var c=d.location[e].replace(/(?:%[a-f89][a-f0-9])+/gim,decodeURIComponent);"pathname"===e&&"/"!==c[0]&&(c="/"+c);return c}function p(d,c,e){var g=d.indexOf("?"),h=
d.indexOf("#"),k=-1<g?g:-1<h?h:d.length;if(-1<g){var g=M(d.slice(g+1,-1<h?h:d.length)),l;for(l in g)c[l]=g[l]}if(-1<h)for(l in c=M(d.slice(h+1)),c)e[l]=c[l];return d.slice(0,k)}function g(){switch(l.charAt(0)){case "#":return e("hash").slice(l.length);case "?":return e("search").slice(l.length)+e("hash");default:return e("pathname").slice(l.length)+e("search")+e("hash")}}function k(e,c,g){var k={},h={};e=p(e,k,h);if(null!=c){for(var n in c)k[n]=c[n];e=e.replace(/:([^\/]+)/g,function(d,e){delete k[e];
return c[e]})}(n=D(k))&&(e+="?"+n);(h=D(h))&&(e+="#"+h);m?(g&&g.replace?d.history.replaceState(null,null,l+e):d.history.pushState(null,null,l+e),d.onpopstate()):d.location.href=l+e}var m="function"===typeof d.history.pushState,n="function"===typeof setImmediate?setImmediate:setTimeout,l="#!";return{setPrefix:function(d){l=d},getPath:g,setPath:k,defineRoutes:function(e,c,k){function u(){var d=g(),l={},m=p(d,l,l);n(function(){for(var g in e){var n=new RegExp("^"+g.replace(/:[^\/]+?\.{3}/g,"(.*?)").replace(/:[^\/]+/g,
"([^\\/]+)")+"/?$");if(n.test(m)){m.replace(n,function(){for(var k=g.match(/:[^\/]+/g)||[],n=[].slice.call(arguments,1,-2),m=0;m<k.length;m++)l[k[m].replace(/:|\./g,"")]=decodeURIComponent(n[m]);c(e[g],l,d,g)});return}}k(d,l)})}m?d.onpopstate=u:"#"===l.charAt(0)&&(d.onhashchange=u);u();return u},link:function(d){d.dom.setAttribute("href",l+d.attrs.href);d.dom.onclick=function(c){c.preventDefault();c.redraw=!1;k(d.attrs.href,void 0,void 0)}}}},R=function(d){var e=0,p=null,g="function"===typeof requestAnimationFrame?
requestAnimationFrame:setTimeout;return function(k){var m=Date.now();!0===k||0===e||16<=m-e?(e=m,d()):null===p&&(p=g(function(){p=null;d();e=Date.now()},16-(m-e)))}},O=function(d,e,p,g){g=R(g);null!=e&&e.setEventCallback(function(d){!1!==d.redraw&&p.publish()});null!=p&&(d.redraw&&p.unsubscribe(d.redraw),p.subscribe(g));return d.redraw=g};x.route=function(d,e,p){var g=Q(d);d=function(d,m,n){var l=null,t="div",c=null;n=g.defineRoutes(n,function(g,m,h,n){function p(n){x===c&&(x=null,l=h,t=n,e.render(d,
g.render(u(n,null,m,void 0,void 0,void 0))))}var x=c={};if("function"!==typeof g.view)if("function"!==typeof g.render&&(g.render=function(c){return c}),"function"!==typeof g.onmatch&&(g.onmatch=function(){p(t)}),h!==l)g.onmatch(u(g,null,m,void 0,void 0,void 0),p);else p(t);else e.render(d,u(g,null,m,void 0,void 0,void 0))},function(){g.setPath(m,null,{replace:!0})});O(d,e,p,n)};d.link=g.link;d.prefix=g.setPrefix;d.set=g.setPath;d.get=g.getPath;return d}(window,F,G);x.mount=function(d,e){return function(p,
g){null===g?(d.render(p,[]),e.unsubscribe(p.redraw),delete p.redraw):O(p,d,e,function(){d.render(p,u(g,void 0,void 0,void 0,void 0,void 0))})()}}(F,G);x.withAttr=function(d,e,p){return function(g){return e.call(p||this,d in g.currentTarget?g.currentTarget[d]:g.currentTarget.getAttribute(d))}};x.prop=N;x.render=F.render;x.redraw=G.publish;x.request=L.request;x.jsonp=L.jsonp;x.parseQueryString=M;x.buildQueryString=D;x.version="1.0.0";"undefined"!==typeof module?module.exports=x:window.m=x};
new function(){function x(b,f,n,h,k,l){return{tag:b,key:f,attrs:n,children:h,text:k,dom:l,domSize:void 0,state:{},events:void 0,instance:void 0,skip:!1}}function y(b){if(null==b||"string"!==typeof b&&null==b.view)throw Error("The selector must be either a string or a component.");if("string"===typeof b&&void 0===F[b]){for(var f,n,h=[],k={};f=P.exec(b);){var l=f[1],m=f[2];""===l&&""!==m?n=m:"#"===l?k.id=m:"."===l?h.push(m):"["===f[3][0]&&((l=f[6])&&(l=l.replace(/\\(["'])/g,"$1").replace(/\\\\/g,"\\")),
k[f[4]]=l||!0)}0<h.length&&(k.className=h.join(" "));F[b]=function(b,d){var f=!1,l,h,m=b.className||b["class"],r;for(r in k)b[r]=k[r];void 0!==m&&(void 0!==b["class"]&&(b["class"]=void 0,b.className=m),void 0!==k.className&&(b.className=k.className+" "+m));for(r in b)if("key"!==r){f=!0;break}d instanceof Array&&1==d.length&&null!=d[0]&&"#"===d[0].tag?h=d[0].children:l=d;return x(n||"div",b.key,f?b:void 0,l,h,void 0)}}var w;null!=arguments[1]&&("object"!==typeof arguments[1]||void 0!==arguments[1].tag||
arguments[1]instanceof Array)?h=1:(w=arguments[1],h=2);if(arguments.length===h+1)f=arguments[h]instanceof Array?arguments[h]:[arguments[h]];else for(f=[];h<arguments.length;h++)f.push(arguments[h]);return"string"===typeof b?F[b](w||{},x.normalizeChildren(f)):x(b,w&&w.key,w||{},x.normalizeChildren(f),void 0,void 0)}x.normalize=function(b){return b instanceof Array?x("[",void 0,void 0,x.normalizeChildren(b),void 0,void 0):null!=b&&"object"!==typeof b?x("#",void 0,void 0,b,void 0,void 0):b};x.normalizeChildren=
function(b){for(var f=0;f<b.length;f++)b[f]=x.normalize(b[f]);return b};var P=/(?:(^|#|\.)([^#\.\[\]]+))|(\[(.+?)(?:\s*=\s*("|'|)((?:\\["'\]]|.)*?)\5)?\])/g,F={};y.trust=function(b){return x("<",void 0,void 0,b,void 0,void 0)};y.fragment=function(b,f){return x("[",b.key,b,x.normalizeChildren(f),void 0,void 0)};var N=function(b){function f(c,a,e,d,b,f,p){for(;e<d;e++){var v=a[e];null!=v&&q(c,n(v,b,p),f)}}function n(c,a,e){var d=c.tag;null!=c.attrs&&D(c.attrs,c,a);if("string"===typeof d)switch(d){case "#":return c.dom=
z.createTextNode(c.children);case "<":return h(c);case "[":var b=z.createDocumentFragment();null!=c.children&&(d=c.children,f(b,d,0,d.length,a,null,e));c.dom=b.firstChild;c.domSize=b.childNodes.length;return b;default:var g=c.tag;switch(c.tag){case "svg":e="http://www.w3.org/2000/svg";break;case "math":e="http://www.w3.org/1998/Math/MathML"}var p=(d=c.attrs)&&d.is,g=e?p?z.createElementNS(e,g,{is:p}):z.createElementNS(e,g):p?z.createElement(g,{is:p}):z.createElement(g);c.dom=g;if(null!=d)for(b in p=
e,d)u(c,b,null,d[b],p);null!=c.text&&(""!==c.text?g.textContent=c.text:c.children=[x("#",void 0,void 0,c.text,void 0,void 0)]);null!=c.children&&(b=c.children,f(g,b,0,b.length,a,null,e),a=c.attrs,"select"===c.tag&&null!=a&&("value"in a&&u(c,"value",null,a.value,void 0),"selectedIndex"in a&&u(c,"selectedIndex",null,a.selectedIndex,void 0)));return g}else{c.state||(c.state={});Q(c.state,c.tag);D(c.tag,c,a);c.instance=x.normalize(c.tag.view.call(c.state,c));if(null!=c.instance){if(c.instance===c)throw Error("A view cannot return the vnode it received as arguments");
a=n(c.instance,a,e);c.dom=c.instance.dom;c.domSize=null!=c.dom?c.instance.domSize:0;c=a}else c.domSize=0,c=J;return c}}function h(c){var a={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",a=z.createElement(a);a.innerHTML=c.children;c.dom=a.firstChild;c.domSize=a.childNodes.length;c=z.createDocumentFragment();for(var e;e=a.firstChild;)c.appendChild(e);return c}function k(c,a,e,b,
g,h){if(a!==e&&(null!=a||null!=e))if(null==a)f(c,e,0,e.length,b,g,void 0);else if(null==e)d(c,a,0,a.length,e);else{var p;a:{if(null!=a.pool&&Math.abs(a.pool.length-e.length)<=Math.abs(a.length-e.length)&&(p=e[0]&&e[0].children&&e[0].children.length||0,Math.abs((a.pool[0]&&a.pool[0].children&&a.pool[0].children.length||0)-p)<=Math.abs((a[0]&&a[0].children&&a[0].children.length||0)-p))){p=!0;break a}p=!1}p&&(a=a.concat(a.pool));if(a.length===e.length&&null!=e[0]&&null==e[0].key)for(var v=0;v<a.length;v++)a[v]===
e[v]||null==a[v]&&null==e[v]||(null==a[v]?q(c,n(e[v],b,h),w(a,v+1,g)):null==e[v]?d(c,a,v,v+1,e):l(c,a[v],e[v],b,w(a,v+1,g),p,h),p&&a[v].tag===e[v].tag&&q(c,m(a[v]),w(a,v+1,g)));else{for(var E=v=0,k=a.length-1,A=e.length-1,t;k>=v&&A>=E;){var r=a[v],u=e[E];if(r===u)v++,E++;else if(null!=r&&null!=u&&r.key===u.key)v++,E++,l(c,r,u,b,w(a,v,g),p,h),p&&r.tag===u.tag&&q(c,m(r),g);else if(r=a[k],r===u)k--,E++;else if(null!=r&&null!=u&&r.key===u.key)l(c,r,u,b,w(a,k+1,g),p,h),E<A&&q(c,m(r),w(a,v,g)),k--,E++;
else break}for(;k>=v&&A>=E;){r=a[k];u=e[A];if(r===u)k--;else if(null!=r&&null!=u&&r.key===u.key)l(c,r,u,b,w(a,k+1,g),p,h),p&&r.tag===u.tag&&q(c,m(r),g),null!=r.dom&&(g=r.dom),k--;else{if(!t){t=a;var r=k,C={},z;for(z=0;z<r;z++){var D=t[z];null!=D&&(D=D.key,null!=D&&(C[D]=z))}t=C}null!=u&&(r=t[u.key],null!=r?(C=a[r],l(c,C,u,b,w(a,k+1,g),p,h),q(c,m(C),g),a[r].skip=!0,null!=C.dom&&(g=C.dom)):(u=n(u,b,void 0),q(c,u,g),g=u))}A--;if(A<E)break}f(c,e,E,A+1,b,g,h);d(c,a,v,k+1,e)}}}function l(c,a,e,b,d,g,p){var v=
a.tag;if(v===e.tag){e.state=a.state;e.events=a.events;var f;var t;null!=e.attrs&&"function"===typeof e.attrs.onbeforeupdate&&(f=e.attrs.onbeforeupdate.call(e.state,e,a));"string"!==typeof e.tag&&"function"===typeof e.tag.onbeforeupdate&&(t=e.tag.onbeforeupdate.call(e.state,e,a));void 0===f&&void 0===t||f||t?f=!1:(e.dom=a.dom,e.domSize=a.domSize,e.instance=a.instance,f=!0);if(!f)if(null!=e.attrs&&y(e.attrs,e,b,g),"string"===typeof v)switch(v){case "#":a.children.toString()!==e.children.toString()&&
(a.dom.nodeValue=e.children);e.dom=a.dom;break;case "<":a.children!==e.children?(m(a),q(c,h(e),d)):(e.dom=a.dom,e.domSize=a.domSize);break;case "[":k(c,a.children,e.children,b,d,p);a=0;b=e.children;e.dom=null;if(null!=b){for(var B=0;B<b.length;B++)c=b[B],null!=c&&null!=c.dom&&(null==e.dom&&(e.dom=c.dom),a+=c.domSize||1);1!==a&&(e.domSize=a)}break;default:c=p;d=e.dom=a.dom;switch(e.tag){case "svg":c="http://www.w3.org/2000/svg";break;case "math":c="http://www.w3.org/1998/Math/MathML"}"textarea"===
e.tag&&(null==e.attrs&&(e.attrs={}),null!=e.text&&(e.attrs.value=e.text));g=a.attrs;p=e.attrs;v=c;if(null!=p)for(B in p)u(e,B,g&&g[B],p[B],v);if(null!=g)for(B in g)null!=p&&B in p||("o"!==B[0]||"n"!==B[1]||r(B)?"key"!==B&&e.dom.removeAttribute(B):C(e,B,void 0));null!=a.text&&null!=e.text&&""!==e.text?a.text.toString()!==e.text.toString()&&(a.dom.firstChild.nodeValue=e.text):(null!=a.text&&(a.children=[x("#",void 0,void 0,a.text,void 0,a.dom.firstChild)]),null!=e.text&&(e.children=[x("#",void 0,void 0,
e.text,void 0,void 0)]),k(d,a.children,e.children,b,null,c))}else e.instance=x.normalize(e.tag.view.call(e.state,e)),y(e.tag,e,b,g),null!=e.instance?(null==a.instance?q(c,n(e.instance,b,p),d):l(c,a.instance,e.instance,b,d,g,p),e.dom=e.instance.dom,e.domSize=e.instance.domSize):null!=a.instance?(A(c,a.instance,null),e.dom=void 0,e.domSize=0):(e.dom=a.dom,e.domSize=a.domSize)}else A(c,a,null),q(c,n(e,b,void 0),d)}function m(c){var a=c.domSize;if(null!=a||null==c.dom){var e=z.createDocumentFragment();
if(0<a){for(c=c.dom;--a;)e.appendChild(c.nextSibling);e.insertBefore(c,e.firstChild)}return e}return c.dom}function w(c,a,e){for(;a<c.length;a++)if(null!=c[a]&&null!=c[a].dom)return c[a].dom;return e}function q(c,a,e){e&&e.parentNode?c.insertBefore(a,e):c.appendChild(a)}function d(c,a,e,b,d){for(;e<b;e++){var g=a[e];null!=g&&(g.skip?g.skip=!1:A(c,g,d))}}function g(c){var a=!1;return function(){a||(a=!0,c())}}function A(c,a,e){function b(){if(++f===d&&(t(a),a.dom)){var p=a.domSize||1;if(1<p)for(var g=
a.dom;--p;)c.removeChild(g.nextSibling);null!=a.dom.parentNode&&c.removeChild(a.dom);if(p=null!=e&&null==a.domSize)p=a.attrs,p=!(null!=p&&(p.oncreate||p.onupdate||p.onbeforeremove||p.onremove));p&&"string"===typeof a.tag&&(e.pool?e.pool.push(a):e.pool=[a])}}var d=1,f=0;a.attrs&&a.attrs.onbeforeremove&&(d++,a.attrs.onbeforeremove.call(a.state,a,g(b)));"string"!==typeof a.tag&&a.tag.onbeforeremove&&(d++,a.tag.onbeforeremove.call(a.state,a,g(b)));b()}function t(c){c.attrs&&c.attrs.onremove&&c.attrs.onremove.call(c.state,
c);"string"!==typeof c.tag&&c.tag.onremove&&c.tag.onremove.call(c.state,c);if(null!=c.instance)t(c.instance);else if(c=c.children,c instanceof Array)for(var a=0;a<c.length;a++){var e=c[a];null!=e&&t(e)}}function u(c,a,e,b,d){var g=c.dom;if("key"!==a&&(e!==b||"value"===a||"checked"===a||"selectedIndex"===a||"selected"===a&&c.dom===z.activeElement||"object"===typeof b)&&"undefined"!==typeof b&&!r(a)){var p=a.indexOf(":");if(-1<p&&"xlink"===a.substr(0,p))g.setAttributeNS("http://www.w3.org/1999/xlink",
a.slice(p+1),b);else if("o"===a[0]&&"n"===a[1]&&"function"===typeof b)C(c,a,b);else if("style"===a)if(c=e,c===b&&(g.style.cssText="",c=null),null==b)g.style.cssText="";else if("string"===typeof b)g.style.cssText=b;else{"string"===typeof c&&(g.style.cssText="");for(var v in b)g.style[v]=b[v];if(null!=c&&"string"!==typeof c)for(v in c)v in b||(g.style[v]="")}else if(a in g&&"href"!==a&&"list"!==a&&"form"!==a&&void 0===d){if("input"!==c.tag||"value"!==a||c.dom.value!==b||c.dom!==z.activeElement)g[a]=
b}else"boolean"===typeof b?b?g.setAttribute(a,""):g.removeAttribute(a):g.setAttribute("className"===a?"class":a,b)}}function r(c){return"oninit"===c||"oncreate"===c||"onupdate"===c||"onremove"===c||"onbeforeremove"===c||"onbeforeupdate"===c}function C(c,a,b){var d=c.dom,g=function(a){var c=b.call(d,a);"function"===typeof I&&I.call(d,a);return c};if(a in d)d[a]=g;else{var f=a.slice(2);void 0===c.events&&(c.events={});null!=c.events[a]&&d.removeEventListener(f,c.events[a],!1);"function"===typeof b&&
(c.events[a]=g,d.addEventListener(f,c.events[a],!1))}}function D(c,a,b){"function"===typeof c.oninit&&c.oninit.call(a.state,a);"function"===typeof c.oncreate&&b.push(c.oncreate.bind(a.state,a))}function y(c,a,b,d){d?D(c,a,b):"function"===typeof c.onupdate&&b.push(c.onupdate.bind(a.state,a))}function Q(c,a){Object.keys(a).forEach(function(b){c[b]=a[b]})}var z=b.document,J=z.createDocumentFragment(),I;return{render:function(c,a){if(!c)throw Error("Ensure the DOM element being passed to m.route/m.mount/m.render is not undefined.");
var b=[],d=z.activeElement;null==c.vnodes&&(c.textContent="");a instanceof Array||(a=[a]);k(c,c.vnodes,x.normalizeChildren(a),b,null,void 0);c.vnodes=a;for(var g=0;g<b.length;g++)b[g]();z.activeElement!==d&&d.focus()},setEventCallback:function(c){return I=c}}}(window),O=function(b){function f(){function a(){0<arguments.length&&arguments[0]!==G&&h(a,arguments[0],void 0);return a._state.value}n(a,arguments);0<arguments.length&&arguments[0]!==G&&h(a,arguments[0],void 0);return a}function n(a,c){a.constructor=
f;a._state={id:H++,value:void 0,error:void 0,state:0,derive:void 0,recover:void 0,deps:{},parents:[],errorStream:void 0,endStream:void 0};a.map=x;a.ap=y;a.of=f;a.valueOf=z;a.toJSON=J;a.toString=z;a.run=g;a["catch"]=A;Object.defineProperties(a,{error:{get:function(){if(!a._state.errorStream){var c=function(){0<arguments.length&&arguments[0]!==G&&h(a,void 0,arguments[0]);return a._state.error};n(c,[]);r(c,[a],F,F);a._state.errorStream=c}return a._state.errorStream}},end:{get:function(){if(!a._state.endStream){var c=
f();c.map(function(b){!0===b&&(D(a),D(c));return b});a._state.endStream=c}return a._state.endStream}}})}function h(a,c,b){k(a,c,b);for(var d in a._state.deps)m(a._state.deps[d],!1);a._state.changed=!1;for(var e in a._state.deps)a._state.deps[e]._state.changed=!1}function k(a,c,b){b=q(c,b);if(void 0!==b&&"function"===typeof a._state.recover){if(!w(a,l,!0))return}else l(a,c,b);a._state.changed=!0;2!==a._state.state&&(a._state.state=1)}function l(a,c,b){a._state.value=c;a._state.error=b}function m(a,
b){var d=a._state.parents;0<d.length&&d.filter(I).length===d.length&&(b||0<d.filter(c).length)&&(d=d.filter(e),0<d.length?k(a,void 0,d[0]._state.error):w(a,k,!1))}function w(a,c,b){try{var e=b?a._state.recover():a._state.derive();if(e===G)return!1;c(a,e,void 0)}catch(g){c(a,void 0,null!=g.__error?g.__error:g),null==g.__error&&d(a,g)}return!0}function q(a,c){null!=a&&a.constructor===f&&(c=void 0!==a._state.error?a._state.error:q(a._state.value,a._state.error));return c}function d(a,c){0===Object.keys(a._state.deps).length&&
setTimeout(function(){0===Object.keys(a._state.deps).length&&b(c)},0)}function g(a){var c=f(),b=this;return r(c,[b],function(){return u(c,a(b()))},void 0)}function A(a){var c=f(),b=this;return r(c,[b],function(){return b._state.value},function(){return u(c,a(b._state.error))})}function t(a,b){return r(f(),b,function(){var d=b.filter(e);if(0<d.length)throw{__error:d[0]._state.error};return a.apply(this,b.concat([b.filter(c)]))},void 0)}function u(a,c){if(null!=c&&c.constructor===f){var b=c,d=function(){k(a,
b._state.value,b._state.error);for(var c in a._state.deps)m(a._state.deps[c],!1)};b.map(d)["catch"](function(a){d();throw{__error:a};});if(0===b._state.state)return G;if(b._state.error)throw{__error:b._state.error};c=b._state.value}return c}function r(c,b,d,e){var g=c._state;g.derive=d;g.recover=e;g.parents=b.filter(a);C(c,g.parents);m(c,!0);return c}function C(a,c){for(var b=0;b<c.length;b++)c[b]._state.deps[a._state.id]=a,C(a,c[b]._state.parents)}function D(a){for(var c=0;c<a._state.parents.length;c++)delete a._state.parents[c]._state.deps[a._state.id];
for(var b in a._state.deps){var c=a._state.deps[b],d=c._state.parents.indexOf(a);-1<d&&c._state.parents.splice(d,1)}a._state.state=2;a._state.deps={}}function x(a){return t(function(c){return a(c())},[this])}function y(a){return t(function(a,c){return a()(c())},[this,a])}function z(){return this._state.value}function J(){return null!=this._state.value&&"function"===typeof this._state.value.toJSON?this._state.value.toJSON():this._state.value}function I(a){return 1===a._state.state}function c(a){return a._state.changed}
function a(a){return 2!==a._state.state}function e(a){return a._state.error}var H=0,F=function(){},G={};f.merge=function(a){return t(function(){return a.map(function(a){return a()})},a)};f.combine=t;f.reject=function(a){var c=f();c.error(a);return c};f.HALT=G;return f}(console.log.bind(console)),H=function(b){function f(b,h){if(h instanceof Array)for(var m=0;m<h.length;m++)f(b+"["+m+"]",h[m]);else if("[object Object]"===Object.prototype.toString.call(h))for(m in h)f(b+"["+m+"]",h[m]);else n.push(encodeURIComponent(b)+
(null!=h&&""!==h?"="+encodeURIComponent(h):""))}if("[object Object]"!==Object.prototype.toString.call(b))return"";var n=[],h;for(h in b)f(h,b[h]);return n.join("&")},K=function(b,f){function n(b,g){if(null==g)return b;for(var f=b.match(/:[^\/]+/gi)||[],h=0;h<f.length;h++){var k=f[h].slice(1);null!=g[k]&&(b=b.replace(f[h],g[k]),delete g[k])}return b}function h(b,g){var f=H(g);if(""!==f){var h=0>b.indexOf("?")?"?":"&";b+=h+f}return b}function k(b){try{return""!==b?JSON.parse(b):null}catch(g){throw Error(b);
}}function l(b){return b.responseText}function m(b,g){if("function"===typeof b)if(g instanceof Array)for(var f=0;f<g.length;f++)g[f]=new b(g[f]);else return new b(g);return g}var w=0,q;return{request:function(d){var g=f();void 0!==d.initialValue&&g(d.initialValue);var A="boolean"===typeof d.useBody?d.useBody:"GET"!==d.method&&"TRACE"!==d.method;"function"!==typeof d.serialize&&(d.serialize="undefined"!==typeof FormData&&d.data instanceof FormData?function(b){return b}:JSON.stringify);"function"!==
typeof d.deserialize&&(d.deserialize=k);"function"!==typeof d.extract&&(d.extract=l);d.url=n(d.url,d.data);A?d.data=d.serialize(d.data):d.url=h(d.url,d.data);var t=new b.XMLHttpRequest;t.open(d.method,d.url,"boolean"===typeof d.async?d.async:!0,"string"===typeof d.user?d.user:void 0,"string"===typeof d.password?d.password:void 0);d.serialize===JSON.stringify&&A&&t.setRequestHeader("Content-Type","application/json; charset=utf-8");d.deserialize===k&&t.setRequestHeader("Accept","application/json, text/*");
"function"===typeof d.config&&(t=d.config(t,d)||t);t.onreadystatechange=function(){if(4===t.readyState){try{var b=d.extract!==l?d.extract(t,d):d.deserialize(d.extract(t,d));if(200<=t.status&&300>t.status)g(m(d.type,b));else{var f=Error(t.responseText),h;for(h in b)f[h]=b[h];g.error(f)}}catch(k){g.error(k)}"function"===typeof q&&q()}};A?t.send(d.data):t.send();return g},jsonp:function(d){var g=f();void 0!==d.initialValue&&g(d.initialValue);var k=d.callbackName||"_mithril_"+Math.round(1E16*Math.random())+
"_"+w++,t=b.document.createElement("script");b[k]=function(f){t.parentNode.removeChild(t);g(m(d.type,f));"function"===typeof q&&q();delete b[k]};t.onerror=function(){t.parentNode.removeChild(t);g.error(Error("JSONP request failed"));"function"===typeof q&&q();delete b[k]};null==d.data&&(d.data={});d.url=n(d.url,d.data);d.data[d.callbackKey||"callback"]=k;t.src=h(d.url,d.data);b.document.documentElement.appendChild(t);return g},setCompletionCallback:function(b){q=b}}}(window,O),L=function(){var b=
[];return{subscribe:b.push.bind(b),unsubscribe:function(f){f=b.indexOf(f);-1<f&&b.splice(f,1)},publish:function(){for(var f=0;f<b.length;f++)b[f].apply(this,arguments)}}}(),M=function(b){if(""===b||null==b)return{};"?"===b.charAt(0)&&(b=b.slice(1));b=b.split("&");for(var f={},n={},h=0;h<b.length;h++){var k=b[h].split("="),l=decodeURIComponent(k[0]),k=2===k.length?decodeURIComponent(k[1]):"",m=Number(k);""!==k&&!isNaN(m)||"NaN"===k?k=m:"true"===k?k=!0:"false"===k?k=!1:(m=new Date(k),isNaN(m.getTime())||
(k=m));var m=l.split(/\]\[?|\[/),w=f;-1<l.indexOf("[")&&m.pop();for(var q=0;q<m.length;q++){var l=m[q],d=m[q+1],d=""==d||!isNaN(parseInt(d,10)),g=q===m.length-1;""===l&&(l=m.slice(0,q).join(),null==n[l]&&(n[l]=0),l=n[l]++);null==w[l]&&(w[l]=g?k:d?[]:{});w=w[l]}}return f};K.setCompletionCallback(L.publish);var R=function(b){var f=0,n=null,h="function"===typeof requestAnimationFrame?requestAnimationFrame:setTimeout;return function(k){var l=Date.now();!0===k||0===f||16<=l-f?(f=l,b()):null===n&&(n=h(function(){n=
null;b();f=Date.now()},16-(l-f)))}},S=function(b,f,n,h){h=R(h);null!=f&&f.setEventCallback(function(b){!1!==b.redraw&&n.publish()});null!=n&&(b.redraw&&n.unsubscribe(b.redraw),n.subscribe(h));return b.redraw=h};y.mount=function(b,f){return function(n,h){null===h?(b.render(n,[]),f.unsubscribe(n.redraw),delete n.redraw):S(n,b,f,function(){b.render(n,x(h,void 0,void 0,void 0,void 0,void 0))})()}}(N,L);var T=function(b){function f(g){var d=b.location[g].replace(/(?:%[a-f89][a-f0-9])+/gim,decodeURIComponent);
"pathname"===g&&"/"!==d[0]&&(d="/"+d);return d}function n(b){return function(){null==d&&(d=w(function(){d=null;b()}))}}function h(b,d,f){var h=b.indexOf("?"),k=b.indexOf("#"),m=-1<h?h:-1<k?k:b.length;if(-1<h){var h=M(b.slice(h+1,-1<k?k:b.length)),l;for(l in h)d[l]=h[l]}if(-1<k)for(l in d=M(b.slice(k+1)),d)f[l]=d[l];return b.slice(0,m)}function k(){switch(q.charAt(0)){case "#":return f("hash").slice(q.length);case "?":return f("search").slice(q.length)+f("hash");default:return f("pathname").slice(q.length)+
f("search")+f("hash")}}function l(d,f,k){var l={},r={};d=h(d,l,r);if(null!=f){for(var n in f)l[n]=f[n];d=d.replace(/:([^\/]+)/g,function(b,d){delete l[d];return f[d]})}(n=H(l))&&(d+="?"+n);(r=H(r))&&(d+="#"+r);m?(k&&k.replace?b.history.replaceState(null,null,q+d):b.history.pushState(null,null,q+d),b.onpopstate()):b.location.href=q+d}var m="function"===typeof b.history.pushState,w="function"===typeof setImmediate?setImmediate:setTimeout,q="#!",d;return{setPrefix:function(b){q=b},getPath:k,setPath:l,
defineRoutes:function(d,f,l){function u(){var b=k(),m={},n=h(b,m,m),q;for(q in d){var u=new RegExp("^"+q.replace(/:[^\/]+?\.{3}/g,"(.*?)").replace(/:[^\/]+/g,"([^\\/]+)")+"/?$");if(u.test(n)){n.replace(u,function(){for(var h=q.match(/:[^\/]+/g)||[],k=[].slice.call(arguments,1,-2),l=0;l<h.length;l++)m[h[l].replace(/:|\./g,"")]=decodeURIComponent(k[l]);f(d[q],m,b,q)});return}}l(b,m)}m?b.onpopstate=n(u):"#"===q.charAt(0)&&(b.onhashchange=u);u();return u},link:function(b){b.dom.setAttribute("href",q+
b.attrs.href);b.dom.onclick=function(d){d.preventDefault();d.redraw=!1;l(b.attrs.href,void 0,void 0)}}}};y.route=function(b,f){function n(b){return b}var h=T(b),k,l,m,w,q,d={view:function(){return m(x(l,null,w,void 0,void 0,void 0))}},g=function(b,g,u){l="div";m=n;w=null;f(b,d);h.defineRoutes(u,function(d,f,g){function h(c){t===k&&(k=null,l=null!=c?c:u?"div":d,m=x,w=f,q=g,b.redraw(!0))}var t=k={},u="function"!==typeof d.view,x=n,y=function(){h()};u&&("function"===typeof d.render&&(x=d.render.bind(d)),
"function"===typeof d.onmatch&&(y=d.onmatch));y.call(d,h,f,g)},function(){h.setPath(g,null,{replace:!0})})};g.link=h.link;g.prefix=h.setPrefix;g.set=h.setPath;g.get=function(){return q};return g}(window,y.mount);y.withAttr=function(b,f,n){return function(h){return f.call(n||this,b in h.currentTarget?h.currentTarget[b]:h.currentTarget.getAttribute(b))}};y.prop=O;y.render=N.render;y.redraw=L.publish;y.request=K.request;y.jsonp=K.jsonp;y.parseQueryString=M;y.buildQueryString=H;y.version="1.0.0";"undefined"!==
typeof module?module.exports=y:window.m=y};

View file

@ -27,6 +27,11 @@ module.exports = new function init() {
if (fn) return fn.apply(this, arguments)
}
if (fn)
Object.defineProperties(spy, {
length: {value: fn.length},
name: {value: fn.name}
})
spy.args = []
spy.callCount = 0
return spy

View file

@ -60,6 +60,8 @@ o.spec("ospec", function() {
var output = spy.call(state, {children: children})
o(spy.length).equals(1)
o(spy.name).equals("view")
o(spy.callCount).equals(1)
o(spy.args.length).equals(1)
o(spy.args[0]).deepEquals({children: children})

View file

@ -516,6 +516,7 @@ module.exports = function($window) {
}
function render(dom, vnodes) {
if (!dom) throw new Error("Ensure the DOM element being passed to m.route/m.mount/m.render is not undefined.")
var hooks = []
var active = $doc.activeElement

View file

@ -21,4 +21,13 @@ o.spec("render", function() {
o(root.childNodes.length).equals(0)
})
o("throws on invalid root node", function(){
var threw = false
try {
render(null, [])
} catch (e) {
threw = true
}
o(threw).equals(true)
})
})

View file

@ -1,4 +1,3 @@
var renderService = require("./render")
var redrawService = require("./redraw")
var mount = require("./mount")
module.exports = require("./api/router")(window, renderService, redrawService)
module.exports = require("./api/router")(window, mount)

View file

@ -16,6 +16,18 @@ module.exports = function($window) {
return data
}
var asyncId
function debounceAsync(f) {
return function() {
if (asyncId != null) return
asyncId = callAsync(function() {
asyncId = null
f()
})
}
}
function parsePath(path, queryData, hashData) {
var queryIndex = path.indexOf("?")
var hashIndex = path.indexOf("#")
@ -67,7 +79,7 @@ module.exports = function($window) {
}
function defineRoutes(routes, resolve, reject) {
if (supportsPushState) $window.onpopstate = resolveRoute
if (supportsPushState) $window.onpopstate = debounceAsync(resolveRoute)
else if (prefix.charAt(0) === "#") $window.onhashchange = resolveRoute
resolveRoute()
@ -76,25 +88,23 @@ module.exports = function($window) {
var params = {}
var pathname = parsePath(path, params, params)
callAsync(function() {
for (var route in routes) {
var matcher = new RegExp("^" + route.replace(/:[^\/]+?\.{3}/g, "(.*?)").replace(/:[^\/]+/g, "([^\\/]+)") + "\/?$")
for (var route in routes) {
var matcher = new RegExp("^" + route.replace(/:[^\/]+?\.{3}/g, "(.*?)").replace(/:[^\/]+/g, "([^\\/]+)") + "\/?$")
if (matcher.test(pathname)) {
pathname.replace(matcher, function() {
var keys = route.match(/:[^\/]+/g) || []
var values = [].slice.call(arguments, 1, -2)
for (var i = 0; i < keys.length; i++) {
params[keys[i].replace(/:|\./g, "")] = decodeURIComponent(values[i])
}
resolve(routes[route], params, path, route)
})
return
}
if (matcher.test(pathname)) {
pathname.replace(matcher, function() {
var keys = route.match(/:[^\/]+/g) || []
var values = [].slice.call(arguments, 1, -2)
for (var i = 0; i < keys.length; i++) {
params[keys[i].replace(/:|\./g, "")] = decodeURIComponent(values[i])
}
resolve(routes[route], params, path, route)
})
return
}
}
reject(path, params)
})
reject(path, params)
}
return resolveRoute
}

View file

@ -285,18 +285,14 @@ o.spec("Router.defineRoutes", function() {
})
})
o("replays", function(done) {
o("replays", function() {
$window.location.href = prefix + "/test"
var replay = router.defineRoutes({"/test": {data: 1}}, onRouteChange, onFail)
replay()
callAsync(function() {
o(onRouteChange.callCount).equals(2)
o(onRouteChange.args).deepEquals([{data: 1}, {}, "/test", "/test"])
o(onFail.callCount).equals(0)
done()
})
o(onRouteChange.callCount).equals(2)
o(onRouteChange.args).deepEquals([{data: 1}, {}, "/test", "/test"])
o(onFail.callCount).equals(0)
})
})
})

View file

@ -164,9 +164,11 @@ o.spec("api", function() {
setTimeout(function() {
m.route.set("/b")
o(m.route.get()).equals("/b")
setTimeout(function() {
o(m.route.get()).equals("/b")
done()
done()
}, FRAME_BUDGET)
}, FRAME_BUDGET)
})
})