Merge remote-tracking branch 'origin/rewrite' into rewrite
This commit is contained in:
commit
0e914eff80
16 changed files with 555 additions and 239 deletions
14
.npmignore
14
.npmignore
|
|
@ -1,20 +1,8 @@
|
|||
# Configuration files
|
||||
# Development-specific files
|
||||
.deploy.env
|
||||
.editorconfig
|
||||
.eslintrc.js
|
||||
.gitattributes
|
||||
.gitignore
|
||||
.travis.yml
|
||||
|
||||
# Tests
|
||||
test-utils/
|
||||
tests/
|
||||
|
||||
# Documentation
|
||||
docs/
|
||||
examples/
|
||||
CONTRIBUTING.md
|
||||
|
||||
# Browser stub (use index.js w/ a bundler or mithril.js w/o one instead)
|
||||
module/
|
||||
browser.js
|
||||
|
|
|
|||
|
|
@ -34,6 +34,6 @@ There are over 4000 assertions in the test suite, and tests cover even difficult
|
|||
|
||||
## Modularity
|
||||
|
||||
Despite the huge improvements in performance and modularity, the new codebase is smaller than v0.2.x, currently clocking at <!-- size -->7.47 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.55 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
|
||||
|
|
|
|||
|
|
@ -8,14 +8,9 @@ module.exports = function($window, redrawService) {
|
|||
var routeService = coreRouter($window)
|
||||
|
||||
var identity = function(v) {return v}
|
||||
var render, component, attrs, currentPath, updatePending = false
|
||||
var render, component, attrs, currentPath, lastUpdate
|
||||
var route = function(root, defaultRoute, routes) {
|
||||
if (root == null) throw new Error("Ensure the DOM element that was passed to `m.route` is not undefined")
|
||||
var update = function(routeResolver, comp, params, path) {
|
||||
component = comp != null && typeof comp.view === "function" ? comp : "div", attrs = params, currentPath = path, updatePending = false
|
||||
render = (routeResolver.render || identity).bind(routeResolver)
|
||||
run()
|
||||
}
|
||||
var run = function() {
|
||||
if (render != null) redrawService.render(root, render(Vnode(component, attrs.key, attrs)))
|
||||
}
|
||||
|
|
@ -23,22 +18,27 @@ module.exports = function($window, redrawService) {
|
|||
routeService.setPath(defaultRoute)
|
||||
}
|
||||
routeService.defineRoutes(routes, function(payload, params, path) {
|
||||
if (payload.view) update({}, payload, params, path)
|
||||
var update = lastUpdate = function(routeResolver, comp) {
|
||||
if (update !== lastUpdate) return
|
||||
component = comp != null && typeof comp.view === "function" ? comp : "div", attrs = params, currentPath = path, lastUpdate = null
|
||||
render = (routeResolver.render || identity).bind(routeResolver)
|
||||
run()
|
||||
}
|
||||
if (payload.view) update({}, payload)
|
||||
else {
|
||||
if (payload.onmatch) {
|
||||
updatePending = true
|
||||
Promise.resolve(payload.onmatch(params, path)).then(function(resolved) {
|
||||
if (updatePending) update(payload, resolved, params, path)
|
||||
update(payload, resolved)
|
||||
}, bail)
|
||||
}
|
||||
else update(payload, "div", params, path)
|
||||
else update(payload, "div")
|
||||
}
|
||||
}, bail)
|
||||
redrawService.subscribe(root, run)
|
||||
}
|
||||
route.set = function(path, data, options) {
|
||||
if (updatePending) options = {replace: true}
|
||||
updatePending = false
|
||||
if (lastUpdate != null) options = {replace: true}
|
||||
lastUpdate = null
|
||||
routeService.setPath(path, data, options)
|
||||
}
|
||||
route.get = function() {return currentPath}
|
||||
|
|
|
|||
|
|
@ -932,6 +932,63 @@ o.spec("route", function() {
|
|||
})
|
||||
})
|
||||
|
||||
o("when two async routes are racing, the last one set cancels the finalization of the first", function(done) {
|
||||
var renderA = o.spy()
|
||||
var renderB = o.spy()
|
||||
var onmatchA = o.spy(function(){
|
||||
return new Promise(function(fulfill) {
|
||||
setTimeout(function(){
|
||||
fulfill()
|
||||
}, 10)
|
||||
})
|
||||
})
|
||||
|
||||
$window.location.href = prefix + "/a"
|
||||
route(root, "/a", {
|
||||
"/a": {
|
||||
onmatch: onmatchA,
|
||||
render: renderA
|
||||
},
|
||||
"/b": {
|
||||
onmatch: function(){
|
||||
var p = new Promise(function(fulfill) {
|
||||
o(onmatchA.callCount).equals(1)
|
||||
o(renderA.callCount).equals(0)
|
||||
o(renderB.callCount).equals(0)
|
||||
|
||||
setTimeout(function(){
|
||||
o(onmatchA.callCount).equals(1)
|
||||
o(renderA.callCount).equals(0)
|
||||
o(renderB.callCount).equals(0)
|
||||
|
||||
fulfill()
|
||||
|
||||
p.then(function(){
|
||||
o(onmatchA.callCount).equals(1)
|
||||
o(renderA.callCount).equals(0)
|
||||
o(renderB.callCount).equals(1)
|
||||
|
||||
done()
|
||||
})
|
||||
}, 20)
|
||||
})
|
||||
return p
|
||||
},
|
||||
render: renderB
|
||||
}
|
||||
})
|
||||
|
||||
callAsync(function() {
|
||||
o(onmatchA.callCount).equals(1)
|
||||
o(renderA.callCount).equals(0)
|
||||
o(renderB.callCount).equals(0)
|
||||
route.set("/b")
|
||||
o(onmatchA.callCount).equals(1)
|
||||
o(renderA.callCount).equals(0)
|
||||
o(renderB.callCount).equals(0)
|
||||
})
|
||||
})
|
||||
|
||||
o("m.route.set(m.route.get()) re-runs the resolution logic (#1180)", function(done){
|
||||
var onmatch = o.spy()
|
||||
var render = o.spy(function() {return m("div")})
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
- [Signature](#signature)
|
||||
- [How it works](#how-it-works)
|
||||
- [Performance considerations](#performance-considerations)
|
||||
- [Differences from m.render](#differences-from-m-render)
|
||||
- [Differences from m.render](#differences-from-mrender)
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -73,4 +73,4 @@ A component rendered via `m.mount` automatically auto-redraws in response to vie
|
|||
|
||||
`m.mount()` is suitable for application developers integrating Mithril widgets into existing codebases where routing is handled by another library or framework, while still enjoying Mithril's auto-redrawing facilities.
|
||||
|
||||
`m.render()` is suitable for library authors who wish to manually control rendering (e.g. when hooking to a third party router, or using third party data-layer libraries like Redux).
|
||||
`m.render()` is suitable for library authors who wish to manually control rendering (e.g. when hooking to a third party router, or using third party data-layer libraries like Redux).
|
||||
|
|
|
|||
118
docs/route.md
118
docs/route.md
|
|
@ -14,6 +14,9 @@
|
|||
- [Typical usage](#typical-usage)
|
||||
- [Navigating to different routes](#navigating-to-different-routes)
|
||||
- [Routing parameters](#routing-parameters)
|
||||
- [Key parameter](#key-parameter)
|
||||
- [Variadic routes](#variadic-routes)
|
||||
- [History state](#history-state)
|
||||
- [Changing router prefix](#changing-router-prefix)
|
||||
- [Advanced component resolution](#advanced-component-resolution)
|
||||
- [Wrapping a layout component](#wrapping-a-layout-component)
|
||||
|
|
@ -39,6 +42,8 @@ m.route(document.body, "/home", {
|
|||
})
|
||||
```
|
||||
|
||||
You can only have one `m.route` call per application.
|
||||
|
||||
---
|
||||
|
||||
### Signature
|
||||
|
|
@ -68,6 +73,8 @@ Argument | Type | Required | Description
|
|||
`path` | `String` | Yes | The path to route to, without a prefix. The path may include slots for routing parameters
|
||||
`data` | `Object` | No | Routing parameters. If `path` has routing parameter slots, the properties of this object are interpolated into the path string
|
||||
`options.replace` | `Boolean` | No | Whether to create a new history entry or to replace the current one. Defaults to false
|
||||
`options.state` | `Object` | No | The `state` object to pass to the underlying `history.pushState` / `history.replaceState` call. This state object becomes available in the `history.state` property, and is merged into the [routing parameters](#routing-parameters) object. Note that this option only works when using the pushState API, but is ignored if the router falls back to hashchange mode (i.e. if the pushState API is not available)
|
||||
`options.title` | `String` | No | The `title` string to pass to the underlying `history.pushState` / `history.replaceState` call.
|
||||
**returns** | | | Returns `undefined`
|
||||
|
||||
##### route.get
|
||||
|
|
@ -252,6 +259,28 @@ It's possible to have multiple arguments in a route, for example `/edit/:project
|
|||
|
||||
In addition to routing parameters, the `attrs` object also includes a `path` property that contains the current route path, and a `route` property that contains the matched routed.
|
||||
|
||||
#### Key parameter
|
||||
|
||||
When a user navigates from a parameterized route to the same route with a different parameter (e.g. going from `/page/1` to `/page/2` given a route `/page/:id`, the component would not be recreated from scratch since both routes resolve to the same component, and thus result in a virtual dom in-place diff. This has the side-effect of triggering the `onupdate` hook, rather than `oninit`/`oncreate`. However, it's relatively common for a developer to want to synchronize the recreation of the component to the route change event.
|
||||
|
||||
To achieve that, it's possible to combine route parameterization with the virtual dom [key reconciliation](keys.md) feature:
|
||||
|
||||
```javascript
|
||||
m.route(document.body, "/edit/1", {
|
||||
"/edit/:key": Edit,
|
||||
})
|
||||
```
|
||||
|
||||
This means that the [vnode](vnodes.md) that is created for the root component of the route has a route parameter object `key`. Route parameters become `attrs` in the vnode. Thus, when jumping from one page to another, the `key` changes and causes the component to be recreated from scratch (since the key tells the virtual dom engine that old and new components are different entities).
|
||||
|
||||
You can take that idea further to create components that recreate themselves when reloaded:
|
||||
|
||||
`m.route.set(m.route.get(), {key: Date.now()})`
|
||||
|
||||
Or even use the [`history state`](#history-state) feature to achieve reloadable components without polluting the URL:
|
||||
|
||||
`m.route.set(m.route.get(), null, {state: {key: Date.now()}})`
|
||||
|
||||
#### Variadic routes
|
||||
|
||||
It's also possible to have variadic routes, i.e. a route with an argument that contains URL pathnames that contain slashes:
|
||||
|
|
@ -262,6 +291,44 @@ m.route(document.body, "/edit/pictures/image.jpg", {
|
|||
})
|
||||
```
|
||||
|
||||
#### History state
|
||||
|
||||
It's possible to take full advantage of the underlying `history.pushState` API to improve user's navigation experience. For example, an application could "remember" the state of a large form when the user leaves a page by navigating away, such that if the user pressed the back button in the browser, they'd have the form filled rather than a blank form.
|
||||
|
||||
For example, you could create a form like this:
|
||||
|
||||
```javascript
|
||||
var state = {
|
||||
term: "",
|
||||
search: function() {
|
||||
// save the state for this route
|
||||
// this is equivalent to `history.replaceState({term: state.term}, null, location.href)`
|
||||
m.route.set(m.route.get(), null, {replace: true, state: {term: state.term}})
|
||||
|
||||
// navigate away
|
||||
location.href = "https://google.com/?q=" + state.term
|
||||
}
|
||||
}
|
||||
|
||||
var Form = {
|
||||
oninit: function(vnode) {
|
||||
state.term = vnode.attrs.term || "" // populated from the `history.state` property if the user presses the back button
|
||||
},
|
||||
view: function() {
|
||||
return m("form", [
|
||||
m("input[placeholder='Search']", {oninput: m.withAttr("value", function(v) {state.term = v}), value: state.term}),
|
||||
m("button", {onclick: state.search}, "Search")
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
m.route(document.body, "/", {
|
||||
"/": Form,
|
||||
})
|
||||
```
|
||||
|
||||
This way, if the user searches and presses the back button to return to the application, the input will still be populated with the search term. This technique can improve the user experience of large forms and other apps where non-persisted state is laborious for a user to produce.
|
||||
|
||||
---
|
||||
|
||||
### Changing router prefix
|
||||
|
|
@ -323,31 +390,76 @@ In the example above, the layout merely consists of a `<div class="layout">` tha
|
|||
One way to wrap the layout is to define an anonymous component in the routes map:
|
||||
|
||||
```javascript
|
||||
// example 1
|
||||
m.route(document.body, "/", {
|
||||
"/": {
|
||||
view: function() {
|
||||
return m(Layout, m(Home))
|
||||
},
|
||||
},
|
||||
"/form": {
|
||||
view: function() {
|
||||
return m(Layout, m(Form))
|
||||
},
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
However, note that because the top level component is an anonymous component, jumping from route to route will tear down the anonymous component and recreate the DOM from scratch. If the Layout component had [lifecycle methods](lifecycle-methods.md) defined, the `oninit` and `oncreate` hooks would fire on every route change. Depending on the application, this may or may not be desirable.
|
||||
However, note that because the top level component is an anonymous component, jumping from the `/` route to the `/form` route (or vice-versa) will tear down the anonymous component and recreate the DOM from scratch. If the Layout component had [lifecycle methods](lifecycle-methods.md) defined, the `oninit` and `oncreate` hooks would fire on every route change. Depending on the application, this may or may not be desirable.
|
||||
|
||||
If you would prefer to have the Layout component be diffed and maintained intact rather than recreated from scratch, you should instead use a RouteResolver as the root object:
|
||||
|
||||
```javascript
|
||||
// example 2
|
||||
m.route(document.body, "/", {
|
||||
"/": {
|
||||
render: function() {
|
||||
return m(Layout, m(Home))
|
||||
},
|
||||
},
|
||||
"/form": {
|
||||
render: function() {
|
||||
return m(Layout, m(Form))
|
||||
},
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
Note that in this case, if the Layout component the `oninit` and `oncreate` lifecycle methods would only fire on the Layout component on the first route change (assuming all routes use the same layout).
|
||||
|
||||
To clarify the difference between the two examples, example 1 is equivalent to this code:
|
||||
|
||||
```javascript
|
||||
// functionally equivalent to example 1
|
||||
var Anon1 = {
|
||||
view: function() {
|
||||
return m(Layout, m(Home))
|
||||
},
|
||||
}
|
||||
var Anon2 = {
|
||||
view: function() {
|
||||
return m(Layout, m(Form))
|
||||
},
|
||||
}
|
||||
|
||||
m.route(document.body, "/", {
|
||||
"/": {
|
||||
render: function() {
|
||||
return m(Anon1)
|
||||
}
|
||||
},
|
||||
"/form": {
|
||||
render: function() {
|
||||
return m(Anon2)
|
||||
}
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
Since `Anon1` and `Anon2` are different components, their subtrees (including `Layout`) are recreated from scratch. This is also what happens when components are used directly without a RouteResolver.
|
||||
|
||||
In example 2, since `Layout` is the top-level component in both routes, the DOM for the `Layout` component is diffed (i.e. left intact if it has no changes), and only the change from `Home` to `Form` triggers a recreation of that subsection of the DOM.
|
||||
|
||||
---
|
||||
|
||||
#### Authentication
|
||||
|
|
@ -407,7 +519,7 @@ m.route(document.body, "/user/list", {
|
|||
"/user/list": {
|
||||
oninit: state.loadUsers,
|
||||
view: function() {
|
||||
return state.users.length > 0 ? state.users.map(function() {
|
||||
return state.users.length > 0 ? state.users.map(function(user) {
|
||||
return m("div", user.id)
|
||||
}) : "loading"
|
||||
}
|
||||
|
|
@ -433,7 +545,7 @@ m.route(document.body, "/user/list", {
|
|||
"/user/list": {
|
||||
onmatch: state.loadUsers,
|
||||
render: function() {
|
||||
return state.users.length > 0 ? state.users.map(function() {
|
||||
return state.users.length > 0 ? state.users.map(function(user) {
|
||||
return m("div", user.id)
|
||||
}) : "loading"
|
||||
}
|
||||
|
|
|
|||
1
index.js
1
index.js
|
|
@ -16,5 +16,6 @@ m.jsonp = requestService.jsonp
|
|||
m.parseQueryString = require("./querystring/parse")
|
||||
m.buildQueryString = require("./querystring/build")
|
||||
m.version = "bleeding-edge"
|
||||
m.vnode = require("./render/vnode")
|
||||
|
||||
module.exports = m
|
||||
|
|
|
|||
179
mithril.js
179
mithril.js
|
|
@ -453,83 +453,84 @@ var coreRenderer = function($window) {
|
|||
else if (old == null) createNodes(parent, vnodes, 0, vnodes.length, hooks, nextSibling, undefined)
|
||||
else if (vnodes == null) removeNodes(old, 0, old.length, vnodes)
|
||||
else {
|
||||
var isUnkeyed = false
|
||||
for (var i = 0; i < vnodes.length; i++) {
|
||||
if (vnodes[i] != null) {
|
||||
isUnkeyed = vnodes[i].key == null
|
||||
break
|
||||
if (old.length === vnodes.length) {
|
||||
var isUnkeyed = false
|
||||
for (var i = 0; i < vnodes.length; i++) {
|
||||
if (vnodes[i] != null && old[i] != null) {
|
||||
isUnkeyed = vnodes[i].key == null && old[i].key == null
|
||||
break
|
||||
}
|
||||
}
|
||||
if (isUnkeyed) {
|
||||
for (var i = 0; i < old.length; i++) {
|
||||
if (old[i] === vnodes[i]) continue
|
||||
else if (old[i] == null && vnodes[i] != null) insertNode(parent, createNode(vnodes[i], hooks, ns), getNextSibling(old, i + 1, nextSibling))
|
||||
else if (vnodes[i] == null) removeNodes(old, i, i + 1, vnodes)
|
||||
else updateNode(parent, old[i], vnodes[i], hooks, getNextSibling(old, i + 1, nextSibling), false, ns)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
if (old.length === vnodes.length && isUnkeyed) {
|
||||
for (var i = 0; i < old.length; i++) {
|
||||
if (old[i] === vnodes[i]) continue
|
||||
else if (old[i] == null) insertNode(parent, createNode(vnodes[i], hooks, ns), getNextSibling(old, i + 1, nextSibling))
|
||||
else if (vnodes[i] == null) removeNodes(old, i, i + 1, vnodes)
|
||||
else updateNode(parent, old[i], vnodes[i], hooks, getNextSibling(old, i + 1, nextSibling), false, ns)
|
||||
var recycling = isRecyclable(old, vnodes)
|
||||
if (recycling) old = old.concat(old.pool)
|
||||
var oldStart = 0, start = 0, oldEnd = old.length - 1, end = vnodes.length - 1, map
|
||||
while (oldEnd >= oldStart && end >= start) {
|
||||
var o = old[oldStart], v = vnodes[start]
|
||||
if (o === v && !recycling) oldStart++, start++
|
||||
else if (o == null) oldStart++
|
||||
else if (v == null) start++
|
||||
else if (o.key === v.key) {
|
||||
oldStart++, start++
|
||||
updateNode(parent, o, v, hooks, getNextSibling(old, oldStart, nextSibling), recycling, ns)
|
||||
if (recycling && o.tag === v.tag) insertNode(parent, toFragment(o), nextSibling)
|
||||
}
|
||||
}
|
||||
else {
|
||||
var recycling = isRecyclable(old, vnodes)
|
||||
if (recycling) old = old.concat(old.pool)
|
||||
var oldStart = 0, start = 0, oldEnd = old.length - 1, end = vnodes.length - 1, map
|
||||
while (oldEnd >= oldStart && end >= start) {
|
||||
var o = old[oldStart], v = vnodes[start]
|
||||
if (o === v && !recycling) oldStart++, start++
|
||||
else if (o == null) oldStart++
|
||||
else {
|
||||
var o = old[oldEnd]
|
||||
if (o === v && !recycling) oldEnd--, start++
|
||||
else if (o == null) oldEnd--
|
||||
else if (v == null) start++
|
||||
else if (o.key === v.key) {
|
||||
oldStart++, start++
|
||||
updateNode(parent, o, v, hooks, getNextSibling(old, oldStart, nextSibling), recycling, ns)
|
||||
if (recycling && o.tag === v.tag) insertNode(parent, toFragment(o), nextSibling)
|
||||
}
|
||||
else {
|
||||
var o = old[oldEnd]
|
||||
if (o === v && !recycling) oldEnd--, start++
|
||||
else if (o == null) oldEnd--
|
||||
else if (v == null) start++
|
||||
else if (o.key === v.key) {
|
||||
updateNode(parent, o, v, hooks, getNextSibling(old, oldEnd + 1, nextSibling), recycling, ns)
|
||||
if (recycling || start < end) insertNode(parent, toFragment(o), getNextSibling(old, oldStart, nextSibling))
|
||||
oldEnd--, start++
|
||||
}
|
||||
else break
|
||||
}
|
||||
}
|
||||
while (oldEnd >= oldStart && end >= start) {
|
||||
var o = old[oldEnd], v = vnodes[end]
|
||||
if (o === v && !recycling) oldEnd--, end--
|
||||
else if (o == null) oldEnd--
|
||||
else if (v == null) end--
|
||||
else if (o.key === v.key) {
|
||||
updateNode(parent, o, v, hooks, getNextSibling(old, oldEnd + 1, nextSibling), recycling, ns)
|
||||
if (recycling && o.tag === v.tag) insertNode(parent, toFragment(o), nextSibling)
|
||||
if (o.dom != null) nextSibling = o.dom
|
||||
oldEnd--, end--
|
||||
if (recycling || start < end) insertNode(parent, toFragment(o), getNextSibling(old, oldStart, nextSibling))
|
||||
oldEnd--, start++
|
||||
}
|
||||
else {
|
||||
if (!map) map = getKeyMap(old, oldEnd)
|
||||
if (v != null) {
|
||||
var oldIndex = map[v.key]
|
||||
if (oldIndex != null) {
|
||||
var movable = old[oldIndex]
|
||||
updateNode(parent, movable, v, hooks, getNextSibling(old, oldEnd + 1, nextSibling), recycling, ns)
|
||||
insertNode(parent, toFragment(movable), nextSibling)
|
||||
old[oldIndex].skip = true
|
||||
if (movable.dom != null) nextSibling = movable.dom
|
||||
}
|
||||
else {
|
||||
var dom = createNode(v, hooks, undefined)
|
||||
insertNode(parent, dom, nextSibling)
|
||||
nextSibling = dom
|
||||
}
|
||||
}
|
||||
end--
|
||||
}
|
||||
if (end < start) break
|
||||
else break
|
||||
}
|
||||
createNodes(parent, vnodes, start, end + 1, hooks, nextSibling, ns)
|
||||
removeNodes(old, oldStart, oldEnd + 1, vnodes)
|
||||
}
|
||||
while (oldEnd >= oldStart && end >= start) {
|
||||
var o = old[oldEnd], v = vnodes[end]
|
||||
if (o === v && !recycling) oldEnd--, end--
|
||||
else if (o == null) oldEnd--
|
||||
else if (v == null) end--
|
||||
else if (o.key === v.key) {
|
||||
updateNode(parent, o, v, hooks, getNextSibling(old, oldEnd + 1, nextSibling), recycling, ns)
|
||||
if (recycling && o.tag === v.tag) insertNode(parent, toFragment(o), nextSibling)
|
||||
if (o.dom != null) nextSibling = o.dom
|
||||
oldEnd--, end--
|
||||
}
|
||||
else {
|
||||
if (!map) map = getKeyMap(old, oldEnd)
|
||||
if (v != null) {
|
||||
var oldIndex = map[v.key]
|
||||
if (oldIndex != null) {
|
||||
var movable = old[oldIndex]
|
||||
updateNode(parent, movable, v, hooks, getNextSibling(old, oldEnd + 1, nextSibling), recycling, ns)
|
||||
insertNode(parent, toFragment(movable), nextSibling)
|
||||
old[oldIndex].skip = true
|
||||
if (movable.dom != null) nextSibling = movable.dom
|
||||
}
|
||||
else {
|
||||
var dom = createNode(v, hooks, undefined)
|
||||
insertNode(parent, dom, nextSibling)
|
||||
nextSibling = dom
|
||||
}
|
||||
}
|
||||
end--
|
||||
}
|
||||
if (end < start) break
|
||||
}
|
||||
createNodes(parent, vnodes, start, end + 1, hooks, nextSibling, ns)
|
||||
removeNodes(old, oldStart, oldEnd + 1, vnodes)
|
||||
}
|
||||
}
|
||||
function updateNode(parent, old, vnode, hooks, nextSibling, recycling, ns) {
|
||||
|
|
@ -758,14 +759,14 @@ var coreRenderer = function($window) {
|
|||
}
|
||||
function setAttr(vnode, key2, old, value, ns) {
|
||||
var element = vnode.dom
|
||||
if (key2 === "key" || (old === value && !isFormAttribute(vnode, key2)) && typeof value !== "object" || typeof value === "undefined" || isLifecycleMethod(key2)) return
|
||||
if (key2 === "key" || key2 === "is" || (old === value && !isFormAttribute(vnode, key2)) && typeof value !== "object" || typeof value === "undefined" || isLifecycleMethod(key2)) return
|
||||
var nsLastIndex = key2.indexOf(":")
|
||||
if (nsLastIndex > -1 && key2.substr(0, nsLastIndex) === "xlink") {
|
||||
element.setAttributeNS("http://www.w3.org/1999/xlink", key2.slice(nsLastIndex + 1), value)
|
||||
}
|
||||
else if (key2[0] === "o" && key2[1] === "n" && typeof value === "function") updateEvent(vnode, key2, value)
|
||||
else if (key2 === "style") updateStyle(element, old, value)
|
||||
else if (key2 in element && !isAttribute(key2) && ns === undefined) {
|
||||
else if (key2 in element && !isAttribute(key2) && ns === undefined && !isCustomElement(vnode)) {
|
||||
//setting input[value] to same value by typing on focused element moves cursor to end in Chrome
|
||||
if (vnode.tag === "input" && key2 === "value" && vnode.dom.value === value && vnode.dom === $doc.activeElement) return
|
||||
//setting select[value] to same value while having select open blinks select dropdown in Chrome
|
||||
|
|
@ -814,6 +815,9 @@ var coreRenderer = function($window) {
|
|||
function isAttribute(attr) {
|
||||
return attr === "href" || attr === "list" || attr === "form" || attr === "width" || attr === "height"// || attr === "type"
|
||||
}
|
||||
function isCustomElement(vnode){
|
||||
return vnode.attrs.is || vnode.tag.indexOf("-") > -1
|
||||
}
|
||||
function hasIntegrationMethods(source) {
|
||||
return source != null && (source.oncreate || source.onupdate || source.onbeforeremove || source.onremove)
|
||||
}
|
||||
|
|
@ -1042,9 +1046,11 @@ var coreRouter = function($window) {
|
|||
var hash = buildQueryString(hashData)
|
||||
if (hash) path += "#" + hash
|
||||
if (supportsPushState) {
|
||||
if (options && options.replace) $window.history.replaceState(null, null, router.prefix + path)
|
||||
else $window.history.pushState(null, null, router.prefix + path)
|
||||
var state = options ? options.state : null
|
||||
var title = options ? options.title : null
|
||||
$window.onpopstate()
|
||||
if (options && options.replace) $window.history.replaceState(state, title, router.prefix + path)
|
||||
else $window.history.pushState(state, title, router.prefix + path)
|
||||
}
|
||||
else $window.location.href = router.prefix + path
|
||||
}
|
||||
|
|
@ -1054,6 +1060,10 @@ var coreRouter = function($window) {
|
|||
var params = {}
|
||||
var pathname = parsePath(path, params, params)
|
||||
|
||||
var state = $window.history.state
|
||||
if (state != null) {
|
||||
for (var k in state) params[k] = state[k]
|
||||
}
|
||||
for (var route0 in routes) {
|
||||
var matcher = new RegExp("^" + route0.replace(/:[^\/]+?\.{3}/g, "(.*?)").replace(/:[^\/]+/g, "([^\\/]+)") + "\/?$")
|
||||
if (matcher.test(pathname)) {
|
||||
|
|
@ -1081,14 +1091,9 @@ var coreRouter = function($window) {
|
|||
var _20 = function($window, redrawService0) {
|
||||
var routeService = coreRouter($window)
|
||||
var identity = function(v) {return v}
|
||||
var render1, component, attrs3, currentPath, updatePending = false
|
||||
var render1, component, attrs3, currentPath, lastUpdate
|
||||
var route = function(root, defaultRoute, routes) {
|
||||
if (root == null) throw new Error("Ensure the DOM element that was passed to `m.route` is not undefined")
|
||||
var update = function(routeResolver, comp, params, path) {
|
||||
component = comp != null && typeof comp.view === "function" ? comp : "div", attrs3 = params, currentPath = path, updatePending = false
|
||||
render1 = (routeResolver.render || identity).bind(routeResolver)
|
||||
run1()
|
||||
}
|
||||
var run1 = function() {
|
||||
if (render1 != null) redrawService0.render(root, render1(Vnode(component, attrs3.key, attrs3)))
|
||||
}
|
||||
|
|
@ -1096,22 +1101,27 @@ var _20 = function($window, redrawService0) {
|
|||
routeService.setPath(defaultRoute)
|
||||
}
|
||||
routeService.defineRoutes(routes, function(payload, params, path) {
|
||||
if (payload.view) update({}, payload, params, path)
|
||||
var update = lastUpdate = function(routeResolver, comp) {
|
||||
if (update !== lastUpdate) return
|
||||
component = comp != null && typeof comp.view === "function" ? comp : "div", attrs3 = params, currentPath = path, lastUpdate = null
|
||||
render1 = (routeResolver.render || identity).bind(routeResolver)
|
||||
run1()
|
||||
}
|
||||
if (payload.view) update({}, payload)
|
||||
else {
|
||||
if (payload.onmatch) {
|
||||
updatePending = true
|
||||
Promise.resolve(payload.onmatch(params, path)).then(function(resolved) {
|
||||
if (updatePending) update(payload, resolved, params, path)
|
||||
update(payload, resolved)
|
||||
}, bail)
|
||||
}
|
||||
else update(payload, "div", params, path)
|
||||
else update(payload, "div")
|
||||
}
|
||||
}, bail)
|
||||
redrawService0.subscribe(root, run1)
|
||||
}
|
||||
route.set = function(path, data, options) {
|
||||
if (updatePending) options = {replace: true}
|
||||
updatePending = false
|
||||
if (lastUpdate != null) options = {replace: true}
|
||||
lastUpdate = null
|
||||
routeService.setPath(path, data, options)
|
||||
}
|
||||
route.get = function() {return currentPath}
|
||||
|
|
@ -1143,6 +1153,7 @@ m.jsonp = requestService.jsonp
|
|||
m.parseQueryString = parseQueryString
|
||||
m.buildQueryString = buildQueryString
|
||||
m.version = "1.0.0-rc.6"
|
||||
m.vnode = Vnode
|
||||
if (typeof module !== "undefined") module["exports"] = m
|
||||
else window.m = m
|
||||
}
|
||||
80
mithril.min.js
vendored
80
mithril.min.js
vendored
|
|
@ -1,41 +1,41 @@
|
|||
new function(){function w(a,c,h,d,g,m){return{tag:a,key:c,attrs:h,children:d,text:g,dom:m,domSize:void 0,state:{},events:void 0,instance:void 0,skip:!1}}function z(a){if(null==a||"string"!==typeof a&&null==a.view)throw Error("The selector must be either a string or a component.");if("string"===typeof a&&void 0===K[a]){for(var c,h,d=[],g={};c=P.exec(a);){var m=c[1],l=c[2];""===m&&""!==l?h=l:"#"===m?g.id=l:"."===m?d.push(l):"["===c[3][0]&&((m=c[6])&&(m=m.replace(/\\(["'])/g,"$1").replace(/\\\\/g,"\\")),
|
||||
"class"===c[4]?d.push(m):g[c[4]]=m||!0)}0<d.length&&(g.className=d.join(" "));K[a]=function(a,c){var m=!1,b,p,d=a.className||a["class"],t;for(t in g)a[t]=g[t];void 0!==d&&(void 0!==a["class"]&&(a["class"]=void 0,a.className=d),void 0!==g.className&&(a.className=g.className+" "+d));for(t in a)if("key"!==t){m=!0;break}c instanceof Array&&1==c.length&&null!=c[0]&&"#"===c[0].tag?p=c[0].children:b=c;return w(h||"div",a.key,m?a:void 0,b,p,void 0)}}var n;null!=arguments[1]&&("object"!==typeof arguments[1]||
|
||||
void 0!==arguments[1].tag||arguments[1]instanceof Array)?d=1:(n=arguments[1],d=2);if(arguments.length===d+1)c=arguments[d]instanceof Array?arguments[d]:[arguments[d]];else for(c=[];d<arguments.length;d++)c.push(arguments[d]);return"string"===typeof a?K[a](n||{},w.normalizeChildren(c)):w(a,n&&n.key,n||{},w.normalizeChildren(c),void 0,void 0)}function Q(a){var c=0,h=null,d="function"===typeof requestAnimationFrame?requestAnimationFrame:setTimeout;return function(){var g=Date.now();0===c||16<=g-c?(c=
|
||||
g,a()):null===h&&(h=d(function(){h=null;a();c=Date.now()},16-(g-c)))}}w.normalize=function(a){return a instanceof Array?w("[",void 0,void 0,w.normalizeChildren(a),void 0,void 0):null!=a&&"object"!==typeof a?w("#",void 0,void 0,a,void 0,void 0):a};w.normalizeChildren=function(a){for(var c=0;c<a.length;c++)a[c]=w.normalize(a[c]);return a};var P=/(?:(^|#|\.)([^#\.\[\]]+))|(\[(.+?)(?:\s*=\s*("|'|)((?:\\["'\]]|.)*?)\5)?\])/g,K={};z.trust=function(a){null==a&&(a="");return w("<",void 0,void 0,a,void 0,
|
||||
void 0)};z.fragment=function(a,c){return w("[",a.key,a,w.normalizeChildren(c),void 0,void 0)};var v=function(a){function c(a,b){return function C(c){var l;try{if(!b||null==c||"object"!==typeof c&&"function"!==typeof c||"function"!==typeof(l=c.then))k(function(){b||0!==a.length||console.error("Possible unhandled promise rejection:",c);for(var d=0;d<a.length;d++)a[d](c);g.length=0;m.length=0;p.state=b;p.retry=function(){C(c)}});else{if(c===d)throw new TypeError("Promise can't be resolved w/ itself");
|
||||
h(l.bind(c))}}catch(G){n(G)}}}function h(a){function b(b){return function(a){0<c++||b(a)}}var c=0,d=b(n);try{a(b(l),d)}catch(t){d(t)}}if(!(this instanceof v))throw Error("Promise must be called with `new`");if("function"!==typeof a)throw new TypeError("executor must be a function");var d=this,g=[],m=[],l=c(g,!0),n=c(m,!1),p=d._instance={resolvers:g,rejectors:m},k="function"===typeof setImmediate?setImmediate:setTimeout;h(a)};v.prototype.then=function(a,c){function h(a,c,h,l){c.push(function(b){if("function"!==
|
||||
typeof a)h(b);else try{g(a(b))}catch(D){m&&m(D)}});"function"===typeof d.retry&&l===d.state&&d.retry()}var d=this._instance,g,m,l=new v(function(a,c){g=a;m=c});h(a,d.resolvers,g,!0);h(c,d.rejectors,m,!1);return l};v.prototype["catch"]=function(a){return this.then(null,a)};v.resolve=function(a){return a instanceof v?a:new v(function(c){c(a)})};v.reject=function(a){return new v(function(c,h){h(a)})};v.all=function(a){return new v(function(c,h){var d=a.length,g=0,m=[];if(0===a.length)c([]);else for(var l=
|
||||
0;l<a.length;l++)(function(l){function p(a){g++;m[l]=a;g===d&&c(m)}null==a[l]||"object"!==typeof a[l]&&"function"!==typeof a[l]||"function"!==typeof a[l].then?p(a[l]):a[l].then(p,h)})(l)})};v.race=function(a){return new v(function(c,h){for(var d=0;d<a.length;d++)a[d].then(c,h)})};"undefined"===typeof E&&("undefined"!==typeof window?window.Promise=v:"undefined"!==typeof global&&(global.Promise=v));var H="undefined"!==typeof E?E:v,I=function(a){function c(a,d){if(d instanceof Array)for(var g=0;g<d.length;g++)c(a+
|
||||
"["+g+"]",d[g]);else if("[object Object]"===Object.prototype.toString.call(d))for(g in d)c(a+"["+g+"]",d[g]);else h.push(encodeURIComponent(a)+(null!=d&&""!==d?"="+encodeURIComponent(d):""))}if("[object Object]"!==Object.prototype.toString.call(a))return"";var h=[],d;for(d in a)c(d,a[d]);return h.join("&")},M=function(a,c){function h(){function b(){0===--a&&"function"===typeof r&&r()}var a=0;return function t(c){var d=c.then;c.then=function(){a++;var g=d.apply(c,arguments);g.then(b,function(c){b();
|
||||
if(0===a)throw c;});return t(g)};return c}}function d(b,a){if("string"===typeof b){var c=b;b=a||{};null==b.url&&(b.url=c)}return b}function g(b,a){if(null==a)return b;for(var c=b.match(/:[^\/]+/gi)||[],d=0;d<c.length;d++){var g=c[d].slice(1);null!=a[g]&&(b=b.replace(c[d],a[g]),delete a[g])}return b}function m(a,c){var b=I(c);if(""!==b){var d=0>a.indexOf("?")?"?":"&";a+=d+b}return a}function l(a){try{return""!==a?JSON.parse(a):null}catch(D){throw Error(a);}}function n(a){return a.responseText}function p(a,
|
||||
c){if("function"===typeof a)if(c instanceof Array)for(var b=0;b<c.length;b++)c[b]=new a(c[b]);else return new a(c);return c}var k=0,r;return{request:function(b,k){var r=h();b=d(b,k);var t=new c(function(c,d){null==b.method&&(b.method="GET");b.method=b.method.toUpperCase();var h="boolean"===typeof b.useBody?b.useBody:"GET"!==b.method&&"TRACE"!==b.method;"function"!==typeof b.serialize&&(b.serialize="undefined"!==typeof FormData&&b.data instanceof FormData?function(a){return a}:JSON.stringify);"function"!==
|
||||
new function(){function u(a,c,h,d,g,m){return{tag:a,key:c,attrs:h,children:d,text:g,dom:m,domSize:void 0,state:{},events:void 0,instance:void 0,skip:!1}}function z(a){if(null==a||"string"!==typeof a&&null==a.view)throw Error("The selector must be either a string or a component.");if("string"===typeof a&&void 0===J[a]){for(var c,h,d=[],g={};c=P.exec(a);){var m=c[1],l=c[2];""===m&&""!==l?h=l:"#"===m?g.id=l:"."===m?d.push(l):"["===c[3][0]&&((m=c[6])&&(m=m.replace(/\\(["'])/g,"$1").replace(/\\\\/g,"\\")),
|
||||
"class"===c[4]?d.push(m):g[c[4]]=m||!0)}0<d.length&&(g.className=d.join(" "));J[a]=function(a,c){var m=!1,b,p,d=a.className||a["class"],w;for(w in g)a[w]=g[w];void 0!==d&&(void 0!==a["class"]&&(a["class"]=void 0,a.className=d),void 0!==g.className&&(a.className=g.className+" "+d));for(w in a)if("key"!==w){m=!0;break}c instanceof Array&&1==c.length&&null!=c[0]&&"#"===c[0].tag?p=c[0].children:b=c;return u(h||"div",a.key,m?a:void 0,b,p,void 0)}}var n;null!=arguments[1]&&("object"!==typeof arguments[1]||
|
||||
void 0!==arguments[1].tag||arguments[1]instanceof Array)?d=1:(n=arguments[1],d=2);if(arguments.length===d+1)c=arguments[d]instanceof Array?arguments[d]:[arguments[d]];else for(c=[];d<arguments.length;d++)c.push(arguments[d]);return"string"===typeof a?J[a](n||{},u.normalizeChildren(c)):u(a,n&&n.key,n||{},u.normalizeChildren(c),void 0,void 0)}function Q(a){var c=0,h=null,d="function"===typeof requestAnimationFrame?requestAnimationFrame:setTimeout;return function(){var g=Date.now();0===c||16<=g-c?(c=
|
||||
g,a()):null===h&&(h=d(function(){h=null;a();c=Date.now()},16-(g-c)))}}u.normalize=function(a){return a instanceof Array?u("[",void 0,void 0,u.normalizeChildren(a),void 0,void 0):null!=a&&"object"!==typeof a?u("#",void 0,void 0,a,void 0,void 0):a};u.normalizeChildren=function(a){for(var c=0;c<a.length;c++)a[c]=u.normalize(a[c]);return a};var P=/(?:(^|#|\.)([^#\.\[\]]+))|(\[(.+?)(?:\s*=\s*("|'|)((?:\\["'\]]|.)*?)\5)?\])/g,J={};z.trust=function(a){null==a&&(a="");return u("<",void 0,void 0,a,void 0,
|
||||
void 0)};z.fragment=function(a,c){return u("[",a.key,a,u.normalizeChildren(c),void 0,void 0)};var A=function(a){function c(a,b){return function q(c){var l;try{if(!b||null==c||"object"!==typeof c&&"function"!==typeof c||"function"!==typeof(l=c.then))k(function(){b||0!==a.length||console.error("Possible unhandled promise rejection:",c);for(var d=0;d<a.length;d++)a[d](c);g.length=0;m.length=0;p.state=b;p.retry=function(){q(c)}});else{if(c===d)throw new TypeError("Promise can't be resolved w/ itself");
|
||||
h(l.bind(c))}}catch(R){n(R)}}}function h(a){function b(b){return function(a){0<c++||b(a)}}var c=0,d=b(n);try{a(b(l),d)}catch(w){d(w)}}if(!(this instanceof A))throw Error("Promise must be called with `new`");if("function"!==typeof a)throw new TypeError("executor must be a function");var d=this,g=[],m=[],l=c(g,!0),n=c(m,!1),p=d._instance={resolvers:g,rejectors:m},k="function"===typeof setImmediate?setImmediate:setTimeout;h(a)};A.prototype.then=function(a,c){function h(a,c,h,l){c.push(function(b){if("function"!==
|
||||
typeof a)h(b);else try{g(a(b))}catch(C){m&&m(C)}});"function"===typeof d.retry&&l===d.state&&d.retry()}var d=this._instance,g,m,l=new A(function(a,c){g=a;m=c});h(a,d.resolvers,g,!0);h(c,d.rejectors,m,!1);return l};A.prototype["catch"]=function(a){return this.then(null,a)};A.resolve=function(a){return a instanceof A?a:new A(function(c){c(a)})};A.reject=function(a){return new A(function(c,h){h(a)})};A.all=function(a){return new A(function(c,h){var d=a.length,g=0,m=[];if(0===a.length)c([]);else for(var l=
|
||||
0;l<a.length;l++)(function(l){function p(a){g++;m[l]=a;g===d&&c(m)}null==a[l]||"object"!==typeof a[l]&&"function"!==typeof a[l]||"function"!==typeof a[l].then?p(a[l]):a[l].then(p,h)})(l)})};A.race=function(a){return new A(function(c,h){for(var d=0;d<a.length;d++)a[d].then(c,h)})};"undefined"===typeof D&&("undefined"!==typeof window?window.Promise=A:"undefined"!==typeof global&&(global.Promise=A));var G="undefined"!==typeof D?D:A,H=function(a){function c(a,d){if(d instanceof Array)for(var g=0;g<d.length;g++)c(a+
|
||||
"["+g+"]",d[g]);else if("[object Object]"===Object.prototype.toString.call(d))for(g in d)c(a+"["+g+"]",d[g]);else h.push(encodeURIComponent(a)+(null!=d&&""!==d?"="+encodeURIComponent(d):""))}if("[object Object]"!==Object.prototype.toString.call(a))return"";var h=[],d;for(d in a)c(d,a[d]);return h.join("&")},K=function(a,c){function h(){function b(){0===--a&&"function"===typeof t&&t()}var a=0;return function w(c){var d=c.then;c.then=function(){a++;var g=d.apply(c,arguments);g.then(b,function(c){b();
|
||||
if(0===a)throw c;});return w(g)};return c}}function d(b,a){if("string"===typeof b){var c=b;b=a||{};null==b.url&&(b.url=c)}return b}function g(b,a){if(null==a)return b;for(var c=b.match(/:[^\/]+/gi)||[],d=0;d<c.length;d++){var g=c[d].slice(1);null!=a[g]&&(b=b.replace(c[d],a[g]),delete a[g])}return b}function m(a,c){var b=H(c);if(""!==b){var d=0>a.indexOf("?")?"?":"&";a+=d+b}return a}function l(a){try{return""!==a?JSON.parse(a):null}catch(C){throw Error(a);}}function n(a){return a.responseText}function p(a,
|
||||
c){if("function"===typeof a)if(c instanceof Array)for(var b=0;b<c.length;b++)c[b]=new a(c[b]);else return new a(c);return c}var k=0,t;return{request:function(b,k){var t=h();b=d(b,k);var w=new c(function(c,d){null==b.method&&(b.method="GET");b.method=b.method.toUpperCase();var h="boolean"===typeof b.useBody?b.useBody:"GET"!==b.method&&"TRACE"!==b.method;"function"!==typeof b.serialize&&(b.serialize="undefined"!==typeof FormData&&b.data instanceof FormData?function(a){return a}:JSON.stringify);"function"!==
|
||||
typeof b.deserialize&&(b.deserialize=l);"function"!==typeof b.extract&&(b.extract=n);b.url=g(b.url,b.data);h?b.data=b.serialize(b.data):b.url=m(b.url,b.data);var k=new a.XMLHttpRequest;k.open(b.method,b.url,"boolean"===typeof b.async?b.async:!0,"string"===typeof b.user?b.user:void 0,"string"===typeof b.password?b.password:void 0);b.serialize===JSON.stringify&&h&&k.setRequestHeader("Content-Type","application/json; charset=utf-8");b.deserialize===l&&k.setRequestHeader("Accept","application/json, text/*");
|
||||
b.withCredentials&&(k.withCredentials=b.withCredentials);"function"===typeof b.config&&(k=b.config(k,b)||k);k.onreadystatechange=function(){if(4===k.readyState)try{var a=b.extract!==n?b.extract(k,b):b.deserialize(b.extract(k,b));if(200<=k.status&&300>k.status||304===k.status)c(p(b.type,a));else{var g=Error(k.responseText),h;for(h in a)g[h]=a[h];d(g)}}catch(F){d(F)}};h&&null!=b.data?k.send(b.data):k.send()});return!0===b.background?t:r(t)},jsonp:function(b,l){var n=h();b=d(b,l);var t=new c(function(c,
|
||||
d){var h=b.callbackName||"_mithril_"+Math.round(1E16*Math.random())+"_"+k++,l=a.document.createElement("script");a[h]=function(d){l.parentNode.removeChild(l);c(p(b.type,d));delete a[h]};l.onerror=function(){l.parentNode.removeChild(l);d(Error("JSONP request failed"));delete a[h]};null==b.data&&(b.data={});b.url=g(b.url,b.data);b.data[b.callbackKey||"callback"]=h;l.src=m(b.url,b.data);a.document.documentElement.appendChild(l)});return!0===b.background?t:n(t)},setCompletionCallback:function(a){r=a}}}(window,
|
||||
H),O=function(a){function c(e,f,a,b,c,d,g){for(;a<b;a++){var q=f[a];null!=q&&p(e,h(q,c,g),d)}}function h(e,f,a){var q=e.tag;null!=e.attrs&&L(e.attrs,e,f);if("string"===typeof q)switch(q){case "#":return e.dom=B.createTextNode(e.children);case "<":return d(e);case "[":var b=B.createDocumentFragment();null!=e.children&&(q=e.children,c(b,q,0,q.length,f,null,a));e.dom=b.firstChild;e.domSize=b.childNodes.length;return b;default:var g=e.tag;switch(e.tag){case "svg":a="http://www.w3.org/2000/svg";break;
|
||||
case "math":a="http://www.w3.org/1998/Math/MathML"}var p=(q=e.attrs)&&q.is,g=a?p?B.createElementNS(a,g,{is:p}):B.createElementNS(a,g):p?B.createElement(g,{is:p}):B.createElement(g);e.dom=g;if(null!=q)for(b in p=a,q)t(e,b,null,q[b],p);null!=e.attrs&&null!=e.attrs.contenteditable?k(e):(null!=e.text&&(""!==e.text?g.textContent=e.text:e.children=[w("#",void 0,void 0,e.text,void 0,void 0)]),null!=e.children&&(b=e.children,c(g,b,0,b.length,f,null,a),f=e.attrs,"select"===e.tag&&null!=f&&("value"in f&&t(e,
|
||||
"value",null,f.value,void 0),"selectedIndex"in f&&t(e,"selectedIndex",null,f.selectedIndex,void 0))));return g}else{e.state||(e.state={});R(e.state,e.tag);b=e.tag.view;if(null!=b.reentrantLock)e=E;else if(b.reentrantLock=!0,L(e.tag,e,f),e.instance=w.normalize(b.call(e.state,e)),b.reentrantLock=null,null!=e.instance){if(e.instance===e)throw Error("A view cannot return the vnode it received as arguments");f=h(e.instance,f,a);e.dom=e.instance.dom;e.domSize=null!=e.dom?e.instance.domSize:0;e=f}else e.domSize=
|
||||
0,e=E;return e}}function d(e){var f={caption:"table",thead:"table",tbody:"table",tfoot:"table",tr:"tbody",th:"tr",td:"tr",colgroup:"table",col:"colgroup"}[(e.children.match(/^\s*?<(\w+)/im)||[])[1]]||"div",f=B.createElement(f);f.innerHTML=e.children;e.dom=f.firstChild;e.domSize=f.childNodes.length;e=B.createDocumentFragment();for(var a;a=f.firstChild;)e.appendChild(a);return e}function g(e,f,a,b,d,g){if(f!==a&&(null!=f||null!=a))if(null==f)c(e,a,0,a.length,b,d,void 0);else if(null==a)r(f,0,f.length,
|
||||
a);else{for(var q=!1,k=0;k<a.length;k++)if(null!=a[k]){q=null==a[k].key;break}if(f.length===a.length&&q)for(k=0;k<f.length;k++)f[k]!==a[k]&&(null==f[k]?p(e,h(a[k],b,g),n(f,k+1,d)):null==a[k]?r(f,k,k+1,a):m(e,f[k],a[k],b,n(f,k+1,d),!1,g));else{a:{if(null!=f.pool&&Math.abs(f.pool.length-a.length)<=Math.abs(f.length-a.length)&&(q=a[0]&&a[0].children&&a[0].children.length||0,Math.abs((f.pool[0]&&f.pool[0].children&&f.pool[0].children.length||0)-q)<=Math.abs((f[0]&&f[0].children&&f[0].children.length||
|
||||
0)-q))){q=!0;break a}q=!1}q&&(f=f.concat(f.pool));for(var A=k=0,y=f.length-1,t=a.length-1,D;y>=k&&t>=A;){var x=f[k],u=a[A];if(x!==u||q)if(null==x)k++;else if(null==u)A++;else if(x.key===u.key)k++,A++,m(e,x,u,b,n(f,k,d),q,g),q&&x.tag===u.tag&&p(e,l(x),d);else if(x=f[y],x!==u||q)if(null==x)y--;else if(null==u)A++;else if(x.key===u.key)m(e,x,u,b,n(f,y+1,d),q,g),(q||A<t)&&p(e,l(x),n(f,k,d)),y--,A++;else break;else y--,A++;else k++,A++}for(;y>=k&&t>=A;){x=f[y];u=a[t];if(x!==u||q)if(null==x)y--;else{if(null!=
|
||||
u)if(x.key===u.key)m(e,x,u,b,n(f,y+1,d),q,g),q&&x.tag===u.tag&&p(e,l(x),d),null!=x.dom&&(d=x.dom),y--;else{if(!D){D=f;var x=y,C={},w;for(w=0;w<x;w++){var v=D[w];null!=v&&(v=v.key,null!=v&&(C[v]=w))}D=C}null!=u&&(x=D[u.key],null!=x?(C=f[x],m(e,C,u,b,n(f,y+1,d),q,g),p(e,l(C),d),f[x].skip=!0,null!=C.dom&&(d=C.dom)):(u=h(u,b,void 0),p(e,u,d),d=u))}t--}else y--,t--;if(t<A)break}c(e,a,A,t+1,b,d,g);r(f,k,y+1,a)}}}function m(a,f,b,c,u,y,n){var e=f.tag;if(e===b.tag){b.state=f.state;b.events=f.events;var q;
|
||||
var A;null!=b.attrs&&"function"===typeof b.attrs.onbeforeupdate&&(q=b.attrs.onbeforeupdate.call(b.state,b,f));"string"!==typeof b.tag&&"function"===typeof b.tag.onbeforeupdate&&(A=b.tag.onbeforeupdate.call(b.state,b,f));void 0===q&&void 0===A||q||A?q=!1:(b.dom=f.dom,b.domSize=f.domSize,b.instance=f.instance,q=!0);if(!q)if(null!=b.attrs&&z(b.attrs,b,c,y),"string"===typeof e)switch(e){case "#":f.children.toString()!==b.children.toString()&&(f.dom.nodeValue=b.children);b.dom=f.dom;break;case "<":f.children!==
|
||||
b.children?(l(f),p(a,d(b),u)):(b.dom=f.dom,b.domSize=f.domSize);break;case "[":g(a,f.children,b.children,c,u,n);f=0;c=b.children;b.dom=null;if(null!=c){for(var r=0;r<c.length;r++)a=c[r],null!=a&&null!=a.dom&&(null==b.dom&&(b.dom=a.dom),f+=a.domSize||1);1!==f&&(b.domSize=f)}break;default:a=n;u=b.dom=f.dom;switch(b.tag){case "svg":a="http://www.w3.org/2000/svg";break;case "math":a="http://www.w3.org/1998/Math/MathML"}"textarea"===b.tag&&(null==b.attrs&&(b.attrs={}),null!=b.text&&(b.attrs.value=b.text,
|
||||
b.text=void 0));y=f.attrs;n=b.attrs;e=a;if(null!=n)for(r in n)t(b,r,y&&y[r],n[r],e);if(null!=y)for(r in y)null!=n&&r in n||("className"===r&&(r="class"),"o"!==r[0]||"n"!==r[1]||v(r)?"key"!==r&&b.dom.removeAttribute(r):G(b,r,void 0));null!=b.attrs&&null!=b.attrs.contenteditable?k(b):null!=f.text&&null!=b.text&&""!==b.text?f.text.toString()!==b.text.toString()&&(f.dom.firstChild.nodeValue=b.text):(null!=f.text&&(f.children=[w("#",void 0,void 0,f.text,void 0,f.dom.firstChild)]),null!=b.text&&(b.children=
|
||||
[w("#",void 0,void 0,b.text,void 0,void 0)]),g(u,f.children,b.children,c,null,a))}else b.instance=w.normalize(b.tag.view.call(b.state,b)),z(b.tag,b,c,y),null!=b.instance?(null==f.instance?p(a,h(b.instance,c,n),u):m(a,f.instance,b.instance,c,u,y,n),b.dom=b.instance.dom,b.domSize=b.instance.domSize):null!=f.instance?(D(f.instance,null),b.dom=void 0,b.domSize=0):(b.dom=f.dom,b.domSize=f.domSize)}else D(f,null),p(a,h(b,c,n),u)}function l(b){var a=b.domSize;if(null!=a||null==b.dom){var e=B.createDocumentFragment();
|
||||
if(0<a){for(b=b.dom;--a;)e.appendChild(b.nextSibling);e.insertBefore(b,e.firstChild)}return e}return b.dom}function n(b,a,c){for(;a<b.length;a++)if(null!=b[a]&&null!=b[a].dom)return b[a].dom;return c}function p(b,a,c){c&&c.parentNode?b.insertBefore(a,c):b.appendChild(a)}function k(b){var a=b.children;if(null!=a&&1===a.length&&"<"===a[0].tag)a=a[0].children,b.dom.innerHTML!==a&&(b.dom.innerHTML=a);else if(null!=b.text||null!=a&&0!==a.length)throw Error("Child node of a contenteditable must be trusted");
|
||||
}function r(b,a,c,d){for(;a<c;a++){var e=b[a];null!=e&&(e.skip?e.skip=!1:D(e,d))}}function b(b){var a=!1;return function(){a||(a=!0,b())}}function D(a,f){function e(){if(++d===c&&(C(a),a.dom)){var b=a.domSize||1;if(1<b)for(var e=a.dom;--b;){var g=e.nextSibling,k=g.parentNode;null!=k&&k.removeChild(g)}b=a.dom;e=b.parentNode;null!=e&&e.removeChild(b);if(b=null!=f&&null==a.domSize)b=a.attrs,b=!(null!=b&&(b.oncreate||b.onupdate||b.onbeforeremove||b.onremove));b&&"string"===typeof a.tag&&(f.pool?f.pool.push(a):
|
||||
f.pool=[a])}}var c=1,d=0;a.attrs&&a.attrs.onbeforeremove&&(c++,a.attrs.onbeforeremove.call(a.state,a,b(e)));"string"!==typeof a.tag&&a.tag.onbeforeremove&&(c++,a.tag.onbeforeremove.call(a.state,a,b(e)));e()}function C(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)C(b.instance);else if(b=b.children,b instanceof Array)for(var a=0;a<b.length;a++){var e=b[a];null!=e&&C(e)}}function t(b,a,c,d,g){var e=
|
||||
b.dom;if("key"!==a&&(c!==d||"value"===a||"checked"===a||"selectedIndex"===a||"selected"===a&&b.dom===B.activeElement||"object"===typeof d)&&"undefined"!==typeof d&&!v(a)){var f=a.indexOf(":");if(-1<f&&"xlink"===a.substr(0,f))e.setAttributeNS("http://www.w3.org/1999/xlink",a.slice(f+1),d);else if("o"===a[0]&&"n"===a[1]&&"function"===typeof d)G(b,a,d);else if("style"===a)if(b=c,b===d&&(e.style.cssText="",b=null),null==d)e.style.cssText="";else if("string"===typeof d)e.style.cssText=d;else{"string"===
|
||||
typeof b&&(e.style.cssText="");for(var k in d)e.style[k]=d[k];if(null!=b&&"string"!==typeof b)for(k in b)k in d||(e.style[k]="")}else a in e&&"href"!==a&&"list"!==a&&"form"!==a&&"width"!==a&&"height"!==a&&void 0===g?"input"===b.tag&&"value"===a&&b.dom.value===d&&b.dom===B.activeElement||"select"===b.tag&&"value"===a&&b.dom.value===d&&b.dom===B.activeElement||"option"===b.tag&&"value"===a&&b.dom.value===d||(e[a]=d):"boolean"===typeof d?d?e.setAttribute(a,""):e.removeAttribute(a):e.setAttribute("className"===
|
||||
a?"class":a,d)}}function v(b){return"oninit"===b||"oncreate"===b||"onupdate"===b||"onremove"===b||"onbeforeremove"===b||"onbeforeupdate"===b}function G(b,a,c){var d=b.dom,e="function"!==typeof F?c:function(b){var a=c.call(d,b);F.call(d,b);return a};if(a in d)d[a]="function"===typeof c?e:null;else{var f=a.slice(2);void 0===b.events&&(b.events={});b.events[a]!==e&&(null!=b.events[a]&&d.removeEventListener(f,b.events[a],!1),"function"===typeof c&&(b.events[a]=e,d.addEventListener(f,b.events[a],!1)))}}
|
||||
function L(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 z(b,a,c,d){d?L(b,a,c):"function"===typeof b.onupdate&&c.push(b.onupdate.bind(a.state,a))}function R(b,a){Object.keys(a).forEach(function(c){b[c]=a[c]})}var B=a.document,E=B.createDocumentFragment(),F;return{render:function(b,a){if(!b)throw Error("Ensure the DOM element being passed to m.route/m.mount/m.render is not undefined.");var c=[],d=B.activeElement;
|
||||
null==b.vnodes&&(b.textContent="");a instanceof Array||(a=[a]);g(b,b.vnodes,w.normalizeChildren(a),c,null,void 0);b.vnodes=a;for(var e=0;e<c.length;e++)c[e]();B.activeElement!==d&&d.focus()},setEventCallback:function(b){return F=b}}},J=function(a){function c(a){a=d.indexOf(a);-1<a&&d.splice(a,2)}function h(){for(var a=1;a<d.length;a+=2)d[a]()}a=O(a);a.setEventCallback(function(a){!1!==a.redraw&&h()});var d=[];return{subscribe:function(a,h){c(a);d.push(a,Q(h))},unsubscribe:c,redraw:h,render:a.render}}(window);
|
||||
M.setCompletionCallback(J.redraw);z.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,w(h))});a.redraw()}}}(J);var E=H,N=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("="),m=decodeURIComponent(g[0]),g=2===g.length?decodeURIComponent(g[1]):
|
||||
"";"true"===g?g=!0:"false"===g&&(g=!1);var l=m.split(/\]\[?|\[/),n=c;-1<m.indexOf("[")&&l.pop();for(var p=0;p<l.length;p++){var m=l[p],k=l[p+1],k=""==k||!isNaN(parseInt(k,10)),r=p===l.length-1;""===m&&(m=l.slice(0,p).join(),null==h[m]&&(h[m]=0),m=h[m]++);null==n[m]&&(n[m]=r?g:k?[]:{});n=n[m]}}return c},S=function(a){function c(c){var d=a.location[c].replace(/(?:%[a-f89][a-f0-9])+/gim,decodeURIComponent);"pathname"===c&&"/"!==d[0]&&(d="/"+d);return d}function h(a){return function(){null==l&&(l=m(function(){l=
|
||||
null;a()}))}}function d(a,c,d){var b=a.indexOf("?"),g=a.indexOf("#"),k=-1<b?b:-1<g?g:a.length;if(-1<b){var b=N(a.slice(b+1,-1<g?g:a.length)),h;for(h in b)c[h]=b[h]}if(-1<g)for(h in c=N(a.slice(g+1)),c)d[h]=c[h];return a.slice(0,k)}var g="function"===typeof a.history.pushState,m="function"===typeof setImmediate?setImmediate:setTimeout,l,n={prefix:"#!",getPath:function(){switch(n.prefix.charAt(0)){case "#":return c("hash").slice(n.prefix.length);case "?":return c("search").slice(n.prefix.length)+c("hash");
|
||||
default:return c("pathname").slice(n.prefix.length)+c("search")+c("hash")}},setPath:function(c,k,h){var b={},l={};c=d(c,b,l);if(null!=k){for(var m in k)b[m]=k[m];c=c.replace(/:([^\/]+)/g,function(a,c){delete b[c];return k[c]})}(m=I(b))&&(c+="?"+m);(l=I(l))&&(c+="#"+l);g?(h&&h.replace?a.history.replaceState(null,null,n.prefix+c):a.history.pushState(null,null,n.prefix+c),a.onpopstate()):a.location.href=n.prefix+c},defineRoutes:function(c,k,l){function b(){var a=n.getPath(),b={},g=d(a,b,b),h;for(h in c){var m=
|
||||
new RegExp("^"+h.replace(/:[^\/]+?\.{3}/g,"(.*?)").replace(/:[^\/]+/g,"([^\\/]+)")+"/?$");if(m.test(g)){g.replace(m,function(){for(var d=h.match(/:[^\/]+/g)||[],g=[].slice.call(arguments,1,-2),l=0;l<d.length;l++)b[d[l].replace(/:|\./g,"")]=decodeURIComponent(g[l]);k(c[h],b,a,h)});return}}l(a,b)}g?a.onpopstate=h(b):"#"===n.prefix.charAt(0)&&(a.onhashchange=b);b()}};return n};z.route=function(a,c){var h=S(a),d=function(a){return a},g,m,l,n,p=!1,k=function(a,b,k){if(null==a)throw Error("Ensure the DOM element that was passed to `m.route` is not undefined");
|
||||
var r=function(a,b,c,h){m=null!=b&&"function"===typeof b.view?b:"div";l=c;n=h;p=!1;g=(a.render||d).bind(a);t()},t=function(){null!=g&&c.render(a,g(w(m,l.key,l)))},v=function(){h.setPath(b)};h.defineRoutes(k,function(a,b,c){a.view?r({},a,b,c):a.onmatch?(p=!0,E.resolve(a.onmatch(b,c)).then(function(d){p&&r(a,d,b,c)},v)):r(a,"div",b,c)},v);c.subscribe(a,t)};k.set=function(a,b,c){p&&(c={replace:!0});p=!1;h.setPath(a,b,c)};k.get=function(){return n};k.prefix=function(a){h.prefix=a};k.link=function(a){a.dom.setAttribute("href",
|
||||
h.prefix+a.attrs.href);a.dom.onclick=function(a){a.ctrlKey||a.metaKey||a.shiftKey||2===a.which||(a.preventDefault(),a.redraw=!1,a=this.getAttribute("href"),0===a.indexOf(h.prefix)&&(a=a.slice(h.prefix.length)),k.set(a,void 0,void 0))}};return k}(window,J);z.withAttr=function(a,c,h){return function(d){return c.call(h||this,a in d.currentTarget?d.currentTarget[a]:d.currentTarget.getAttribute(a))}};H=O(window);z.render=H.render;z.redraw=J.redraw;z.request=M.request;z.jsonp=M.jsonp;z.parseQueryString=
|
||||
N;z.buildQueryString=I;z.version="1.0.0-rc.6";"undefined"!==typeof module?module.exports=z:window.m=z};
|
||||
b.withCredentials&&(k.withCredentials=b.withCredentials);"function"===typeof b.config&&(k=b.config(k,b)||k);k.onreadystatechange=function(){if(4===k.readyState)try{var a=b.extract!==n?b.extract(k,b):b.deserialize(b.extract(k,b));if(200<=k.status&&300>k.status||304===k.status)c(p(b.type,a));else{var g=Error(k.responseText),h;for(h in a)g[h]=a[h];d(g)}}catch(E){d(E)}};h&&null!=b.data?k.send(b.data):k.send()});return!0===b.background?w:t(w)},jsonp:function(b,l){var n=h();b=d(b,l);var t=new c(function(c,
|
||||
d){var h=b.callbackName||"_mithril_"+Math.round(1E16*Math.random())+"_"+k++,l=a.document.createElement("script");a[h]=function(d){l.parentNode.removeChild(l);c(p(b.type,d));delete a[h]};l.onerror=function(){l.parentNode.removeChild(l);d(Error("JSONP request failed"));delete a[h]};null==b.data&&(b.data={});b.url=g(b.url,b.data);b.data[b.callbackKey||"callback"]=h;l.src=m(b.url,b.data);a.document.documentElement.appendChild(l)});return!0===b.background?t:n(t)},setCompletionCallback:function(a){t=a}}}(window,
|
||||
G),O=function(a){function c(e,f,a,b,c,d,g){for(;a<b;a++){var r=f[a];null!=r&&p(e,h(r,c,g),d)}}function h(e,f,a){var r=e.tag;null!=e.attrs&&z(e.attrs,e,f);if("string"===typeof r)switch(r){case "#":return e.dom=y.createTextNode(e.children);case "<":return d(e);case "[":var b=y.createDocumentFragment();null!=e.children&&(r=e.children,c(b,r,0,r.length,f,null,a));e.dom=b.firstChild;e.domSize=b.childNodes.length;return b;default:var g=e.tag;switch(e.tag){case "svg":a="http://www.w3.org/2000/svg";break;
|
||||
case "math":a="http://www.w3.org/1998/Math/MathML"}var p=(r=e.attrs)&&r.is,g=a?p?y.createElementNS(a,g,{is:p}):y.createElementNS(a,g):p?y.createElement(g,{is:p}):y.createElement(g);e.dom=g;if(null!=r)for(b in p=a,r)w(e,b,null,r[b],p);null!=e.attrs&&null!=e.attrs.contenteditable?k(e):(null!=e.text&&(""!==e.text?g.textContent=e.text:e.children=[u("#",void 0,void 0,e.text,void 0,void 0)]),null!=e.children&&(b=e.children,c(g,b,0,b.length,f,null,a),f=e.attrs,"select"===e.tag&&null!=f&&("value"in f&&w(e,
|
||||
"value",null,f.value,void 0),"selectedIndex"in f&&w(e,"selectedIndex",null,f.selectedIndex,void 0))));return g}else{e.state||(e.state={});S(e.state,e.tag);b=e.tag.view;if(null!=b.reentrantLock)e=D;else if(b.reentrantLock=!0,z(e.tag,e,f),e.instance=u.normalize(b.call(e.state,e)),b.reentrantLock=null,null!=e.instance){if(e.instance===e)throw Error("A view cannot return the vnode it received as arguments");f=h(e.instance,f,a);e.dom=e.instance.dom;e.domSize=null!=e.dom?e.instance.domSize:0;e=f}else e.domSize=
|
||||
0,e=D;return e}}function d(e){var f={caption:"table",thead:"table",tbody:"table",tfoot:"table",tr:"tbody",th:"tr",td:"tr",colgroup:"table",col:"colgroup"}[(e.children.match(/^\s*?<(\w+)/im)||[])[1]]||"div",f=y.createElement(f);f.innerHTML=e.children;e.dom=f.firstChild;e.domSize=f.childNodes.length;e=y.createDocumentFragment();for(var a;a=f.firstChild;)e.appendChild(a);return e}function g(e,f,a,b,d,g){if(f!==a&&(null!=f||null!=a))if(null==f)c(e,a,0,a.length,b,d,void 0);else if(null==a)t(f,0,f.length,
|
||||
a);else{if(f.length===a.length){for(var r=!1,k=0;k<a.length;k++)if(null!=a[k]&&null!=f[k]){r=null==a[k].key&&null==f[k].key;break}if(r){for(k=0;k<f.length;k++)f[k]!==a[k]&&(null==f[k]&&null!=a[k]?p(e,h(a[k],b,g),n(f,k+1,d)):null==a[k]?t(f,k,k+1,a):m(e,f[k],a[k],b,n(f,k+1,d),!1,g));return}}a:{if(null!=f.pool&&Math.abs(f.pool.length-a.length)<=Math.abs(f.length-a.length)&&(r=a[0]&&a[0].children&&a[0].children.length||0,Math.abs((f.pool[0]&&f.pool[0].children&&f.pool[0].children.length||0)-r)<=Math.abs((f[0]&&
|
||||
f[0].children&&f[0].children.length||0)-r))){r=!0;break a}r=!1}r&&(f=f.concat(f.pool));for(var B=k=0,x=f.length-1,w=a.length-1,C;x>=k&&w>=B;){var v=f[k],q=a[B];if(v!==q||r)if(null==v)k++;else if(null==q)B++;else if(v.key===q.key)k++,B++,m(e,v,q,b,n(f,k,d),r,g),r&&v.tag===q.tag&&p(e,l(v),d);else if(v=f[x],v!==q||r)if(null==v)x--;else if(null==q)B++;else if(v.key===q.key)m(e,v,q,b,n(f,x+1,d),r,g),(r||B<w)&&p(e,l(v),n(f,k,d)),x--,B++;else break;else x--,B++;else k++,B++}for(;x>=k&&w>=B;){v=f[x];q=a[w];
|
||||
if(v!==q||r)if(null==v)x--;else{if(null!=q)if(v.key===q.key)m(e,v,q,b,n(f,x+1,d),r,g),r&&v.tag===q.tag&&p(e,l(v),d),null!=v.dom&&(d=v.dom),x--;else{if(!C){C=f;var v=x,y={},F;for(F=0;F<v;F++){var u=C[F];null!=u&&(u=u.key,null!=u&&(y[u]=F))}C=y}null!=q&&(v=C[q.key],null!=v?(y=f[v],m(e,y,q,b,n(f,x+1,d),r,g),p(e,l(y),d),f[v].skip=!0,null!=y.dom&&(d=y.dom)):(q=h(q,b,void 0),p(e,q,d),d=q))}w--}else x--,w--;if(w<B)break}c(e,a,B,w+1,b,d,g);t(f,k,x+1,a)}}function m(a,f,b,c,q,x,n){var e=f.tag;if(e===b.tag){b.state=
|
||||
f.state;b.events=f.events;var r;var B;null!=b.attrs&&"function"===typeof b.attrs.onbeforeupdate&&(r=b.attrs.onbeforeupdate.call(b.state,b,f));"string"!==typeof b.tag&&"function"===typeof b.tag.onbeforeupdate&&(B=b.tag.onbeforeupdate.call(b.state,b,f));void 0===r&&void 0===B||r||B?r=!1:(b.dom=f.dom,b.domSize=f.domSize,b.instance=f.instance,r=!0);if(!r)if(null!=b.attrs&&N(b.attrs,b,c,x),"string"===typeof e)switch(e){case "#":f.children.toString()!==b.children.toString()&&(f.dom.nodeValue=b.children);
|
||||
b.dom=f.dom;break;case "<":f.children!==b.children?(l(f),p(a,d(b),q)):(b.dom=f.dom,b.domSize=f.domSize);break;case "[":g(a,f.children,b.children,c,q,n);f=0;c=b.children;b.dom=null;if(null!=c){for(var t=0;t<c.length;t++)a=c[t],null!=a&&null!=a.dom&&(null==b.dom&&(b.dom=a.dom),f+=a.domSize||1);1!==f&&(b.domSize=f)}break;default:a=n;q=b.dom=f.dom;switch(b.tag){case "svg":a="http://www.w3.org/2000/svg";break;case "math":a="http://www.w3.org/1998/Math/MathML"}"textarea"===b.tag&&(null==b.attrs&&(b.attrs=
|
||||
{}),null!=b.text&&(b.attrs.value=b.text,b.text=void 0));x=f.attrs;n=b.attrs;e=a;if(null!=n)for(t in n)w(b,t,x&&x[t],n[t],e);if(null!=x)for(t in x)null!=n&&t in n||("className"===t&&(t="class"),"o"!==t[0]||"n"!==t[1]||M(t)?"key"!==t&&b.dom.removeAttribute(t):A(b,t,void 0));null!=b.attrs&&null!=b.attrs.contenteditable?k(b):null!=f.text&&null!=b.text&&""!==b.text?f.text.toString()!==b.text.toString()&&(f.dom.firstChild.nodeValue=b.text):(null!=f.text&&(f.children=[u("#",void 0,void 0,f.text,void 0,f.dom.firstChild)]),
|
||||
null!=b.text&&(b.children=[u("#",void 0,void 0,b.text,void 0,void 0)]),g(q,f.children,b.children,c,null,a))}else b.instance=u.normalize(b.tag.view.call(b.state,b)),N(b.tag,b,c,x),null!=b.instance?(null==f.instance?p(a,h(b.instance,c,n),q):m(a,f.instance,b.instance,c,q,x,n),b.dom=b.instance.dom,b.domSize=b.instance.domSize):null!=f.instance?(C(f.instance,null),b.dom=void 0,b.domSize=0):(b.dom=f.dom,b.domSize=f.domSize)}else C(f,null),p(a,h(b,c,n),q)}function l(b){var a=b.domSize;if(null!=a||null==
|
||||
b.dom){var e=y.createDocumentFragment();if(0<a){for(b=b.dom;--a;)e.appendChild(b.nextSibling);e.insertBefore(b,e.firstChild)}return e}return b.dom}function n(b,a,c){for(;a<b.length;a++)if(null!=b[a]&&null!=b[a].dom)return b[a].dom;return c}function p(b,a,c){c&&c.parentNode?b.insertBefore(a,c):b.appendChild(a)}function k(b){var a=b.children;if(null!=a&&1===a.length&&"<"===a[0].tag)a=a[0].children,b.dom.innerHTML!==a&&(b.dom.innerHTML=a);else if(null!=b.text||null!=a&&0!==a.length)throw Error("Child node of a contenteditable must be trusted");
|
||||
}function t(b,a,c,d){for(;a<c;a++){var e=b[a];null!=e&&(e.skip?e.skip=!1:C(e,d))}}function b(b){var a=!1;return function(){a||(a=!0,b())}}function C(a,f){function e(){if(++d===c&&(q(a),a.dom)){var b=a.domSize||1;if(1<b)for(var e=a.dom;--b;){var g=e.nextSibling,k=g.parentNode;null!=k&&k.removeChild(g)}b=a.dom;e=b.parentNode;null!=e&&e.removeChild(b);if(b=null!=f&&null==a.domSize)b=a.attrs,b=!(null!=b&&(b.oncreate||b.onupdate||b.onbeforeremove||b.onremove));b&&"string"===typeof a.tag&&(f.pool?f.pool.push(a):
|
||||
f.pool=[a])}}var c=1,d=0;a.attrs&&a.attrs.onbeforeremove&&(c++,a.attrs.onbeforeremove.call(a.state,a,b(e)));"string"!==typeof a.tag&&a.tag.onbeforeremove&&(c++,a.tag.onbeforeremove.call(a.state,a,b(e)));e()}function q(a){a.attrs&&a.attrs.onremove&&a.attrs.onremove.call(a.state,a);"string"!==typeof a.tag&&a.tag.onremove&&a.tag.onremove.call(a.state,a);if(null!=a.instance)q(a.instance);else if(a=a.children,a instanceof Array)for(var b=0;b<a.length;b++){var e=a[b];null!=e&&q(e)}}function w(a,b,c,d,g){var e=
|
||||
a.dom;if("key"!==b&&"is"!==b&&(c!==d||"value"===b||"checked"===b||"selectedIndex"===b||"selected"===b&&a.dom===y.activeElement||"object"===typeof d)&&"undefined"!==typeof d&&!M(b)){var f=b.indexOf(":");if(-1<f&&"xlink"===b.substr(0,f))e.setAttributeNS("http://www.w3.org/1999/xlink",b.slice(f+1),d);else if("o"===b[0]&&"n"===b[1]&&"function"===typeof d)A(a,b,d);else if("style"===b)if(a=c,a===d&&(e.style.cssText="",a=null),null==d)e.style.cssText="";else if("string"===typeof d)e.style.cssText=d;else{"string"===
|
||||
typeof a&&(e.style.cssText="");for(var k in d)e.style[k]=d[k];if(null!=a&&"string"!==typeof a)for(k in a)k in d||(e.style[k]="")}else b in e&&"href"!==b&&"list"!==b&&"form"!==b&&"width"!==b&&"height"!==b&&void 0===g&&!(a.attrs.is||-1<a.tag.indexOf("-"))?"input"===a.tag&&"value"===b&&a.dom.value===d&&a.dom===y.activeElement||"select"===a.tag&&"value"===b&&a.dom.value===d&&a.dom===y.activeElement||"option"===a.tag&&"value"===b&&a.dom.value===d||(e[b]=d):"boolean"===typeof d?d?e.setAttribute(b,""):e.removeAttribute(b):
|
||||
e.setAttribute("className"===b?"class":b,d)}}function M(a){return"oninit"===a||"oncreate"===a||"onupdate"===a||"onremove"===a||"onbeforeremove"===a||"onbeforeupdate"===a}function A(a,b,c){var d=a.dom,e="function"!==typeof E?c:function(a){var b=c.call(d,a);E.call(d,a);return b};if(b in d)d[b]="function"===typeof c?e:null;else{var f=b.slice(2);void 0===a.events&&(a.events={});a.events[b]!==e&&(null!=a.events[b]&&d.removeEventListener(f,a.events[b],!1),"function"===typeof c&&(a.events[b]=e,d.addEventListener(f,
|
||||
a.events[b],!1)))}}function z(a,b,c){"function"===typeof a.oninit&&a.oninit.call(b.state,b);"function"===typeof a.oncreate&&c.push(a.oncreate.bind(b.state,b))}function N(a,b,c,d){d?z(a,b,c):"function"===typeof a.onupdate&&c.push(a.onupdate.bind(b.state,b))}function S(a,b){Object.keys(b).forEach(function(c){a[c]=b[c]})}var y=a.document,D=y.createDocumentFragment(),E;return{render:function(a,b){if(!a)throw Error("Ensure the DOM element being passed to m.route/m.mount/m.render is not undefined.");var c=
|
||||
[],d=y.activeElement;null==a.vnodes&&(a.textContent="");b instanceof Array||(b=[b]);g(a,a.vnodes,u.normalizeChildren(b),c,null,void 0);a.vnodes=b;for(var e=0;e<c.length;e++)c[e]();y.activeElement!==d&&d.focus()},setEventCallback:function(a){return E=a}}},I=function(a){function c(a){a=d.indexOf(a);-1<a&&d.splice(a,2)}function h(){for(var a=1;a<d.length;a+=2)d[a]()}a=O(a);a.setEventCallback(function(a){!1!==a.redraw&&h()});var d=[];return{subscribe:function(a,h){c(a);d.push(a,Q(h))},unsubscribe:c,redraw:h,
|
||||
render:a.render}}(window);K.setCompletionCallback(I.redraw);z.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,u(h))});a.redraw()}}}(I);var D=G,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("="),m=decodeURIComponent(g[0]),g=2===g.length?
|
||||
decodeURIComponent(g[1]):"";"true"===g?g=!0:"false"===g&&(g=!1);var l=m.split(/\]\[?|\[/),n=c;-1<m.indexOf("[")&&l.pop();for(var p=0;p<l.length;p++){var m=l[p],k=l[p+1],k=""==k||!isNaN(parseInt(k,10)),t=p===l.length-1;""===m&&(m=l.slice(0,p).join(),null==h[m]&&(h[m]=0),m=h[m]++);null==n[m]&&(n[m]=t?g:k?[]:{});n=n[m]}}return c},T=function(a){function c(c){var d=a.location[c].replace(/(?:%[a-f89][a-f0-9])+/gim,decodeURIComponent);"pathname"===c&&"/"!==d[0]&&(d="/"+d);return d}function h(a){return function(){null==
|
||||
l&&(l=m(function(){l=null;a()}))}}function d(a,c,d){var b=a.indexOf("?"),g=a.indexOf("#"),k=-1<b?b:-1<g?g:a.length;if(-1<b){var b=L(a.slice(b+1,-1<g?g:a.length)),h;for(h in b)c[h]=b[h]}if(-1<g)for(h in c=L(a.slice(g+1)),c)d[h]=c[h];return a.slice(0,k)}var g="function"===typeof a.history.pushState,m="function"===typeof setImmediate?setImmediate:setTimeout,l,n={prefix:"#!",getPath:function(){switch(n.prefix.charAt(0)){case "#":return c("hash").slice(n.prefix.length);case "?":return c("search").slice(n.prefix.length)+
|
||||
c("hash");default:return c("pathname").slice(n.prefix.length)+c("search")+c("hash")}},setPath:function(c,k,h){var b={},l={};c=d(c,b,l);if(null!=k){for(var q in k)b[q]=k[q];c=c.replace(/:([^\/]+)/g,function(a,c){delete b[c];return k[c]})}(q=H(b))&&(c+="?"+q);(l=H(l))&&(c+="#"+l);g?(l=h?h.state:null,q=h?h.title:null,a.onpopstate(),h&&h.replace?a.history.replaceState(l,q,n.prefix+c):a.history.pushState(l,q,n.prefix+c)):a.location.href=n.prefix+c},defineRoutes:function(c,k,l){function b(){var b=n.getPath(),
|
||||
g={},h=d(b,g,g),m=a.history.state;if(null!=m)for(var t in m)g[t]=m[t];for(var p in c)if(m=new RegExp("^"+p.replace(/:[^\/]+?\.{3}/g,"(.*?)").replace(/:[^\/]+/g,"([^\\/]+)")+"/?$"),m.test(h)){h.replace(m,function(){for(var a=p.match(/:[^\/]+/g)||[],d=[].slice.call(arguments,1,-2),h=0;h<a.length;h++)g[a[h].replace(/:|\./g,"")]=decodeURIComponent(d[h]);k(c[p],g,b,p)});return}l(b,g)}g?a.onpopstate=h(b):"#"===n.prefix.charAt(0)&&(a.onhashchange=b);b()}};return n};z.route=function(a,c){var h=T(a),d=function(a){return a},
|
||||
g,m,l,n,p,k=function(a,b,k){if(null==a)throw Error("Ensure the DOM element that was passed to `m.route` is not undefined");var q=function(){null!=g&&c.render(a,g(u(m,l.key,l)))},t=function(){h.setPath(b)};h.defineRoutes(k,function(a,b,c){var h=p=function(a,k){h===p&&(m=null!=k&&"function"===typeof k.view?k:"div",l=b,n=c,p=null,g=(a.render||d).bind(a),q())};a.view?h({},a):a.onmatch?D.resolve(a.onmatch(b,c)).then(function(b){h(a,b)},t):h(a,"div")},t);c.subscribe(a,q)};k.set=function(a,b,c){null!=p&&
|
||||
(c={replace:!0});p=null;h.setPath(a,b,c)};k.get=function(){return n};k.prefix=function(a){h.prefix=a};k.link=function(a){a.dom.setAttribute("href",h.prefix+a.attrs.href);a.dom.onclick=function(a){a.ctrlKey||a.metaKey||a.shiftKey||2===a.which||(a.preventDefault(),a.redraw=!1,a=this.getAttribute("href"),0===a.indexOf(h.prefix)&&(a=a.slice(h.prefix.length)),k.set(a,void 0,void 0))}};return k}(window,I);z.withAttr=function(a,c,h){return function(d){return c.call(h||this,a in d.currentTarget?d.currentTarget[a]:
|
||||
d.currentTarget.getAttribute(a))}};G=O(window);z.render=G.render;z.redraw=I.redraw;z.request=K.request;z.jsonp=K.jsonp;z.parseQueryString=L;z.buildQueryString=H;z.version="1.0.0-rc.6";z.vnode=u;"undefined"!==typeof module?module.exports=z:window.m=z};
|
||||
146
render/render.js
146
render/render.js
|
|
@ -124,84 +124,85 @@ module.exports = function($window) {
|
|||
else if (old == null) createNodes(parent, vnodes, 0, vnodes.length, hooks, nextSibling, undefined)
|
||||
else if (vnodes == null) removeNodes(old, 0, old.length, vnodes)
|
||||
else {
|
||||
var isUnkeyed = false
|
||||
for (var i = 0; i < vnodes.length; i++) {
|
||||
if (vnodes[i] != null) {
|
||||
isUnkeyed = vnodes[i].key == null
|
||||
break
|
||||
if (old.length === vnodes.length) {
|
||||
var isUnkeyed = false
|
||||
for (var i = 0; i < vnodes.length; i++) {
|
||||
if (vnodes[i] != null && old[i] != null) {
|
||||
isUnkeyed = vnodes[i].key == null && old[i].key == null
|
||||
break
|
||||
}
|
||||
}
|
||||
if (isUnkeyed) {
|
||||
for (var i = 0; i < old.length; i++) {
|
||||
if (old[i] === vnodes[i]) continue
|
||||
else if (old[i] == null && vnodes[i] != null) insertNode(parent, createNode(vnodes[i], hooks, ns), getNextSibling(old, i + 1, nextSibling))
|
||||
else if (vnodes[i] == null) removeNodes(old, i, i + 1, vnodes)
|
||||
else updateNode(parent, old[i], vnodes[i], hooks, getNextSibling(old, i + 1, nextSibling), false, ns)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
if (old.length === vnodes.length && isUnkeyed) {
|
||||
for (var i = 0; i < old.length; i++) {
|
||||
if (old[i] === vnodes[i]) continue
|
||||
else if (old[i] == null) insertNode(parent, createNode(vnodes[i], hooks, ns), getNextSibling(old, i + 1, nextSibling))
|
||||
else if (vnodes[i] == null) removeNodes(old, i, i + 1, vnodes)
|
||||
else updateNode(parent, old[i], vnodes[i], hooks, getNextSibling(old, i + 1, nextSibling), false, ns)
|
||||
}
|
||||
}
|
||||
else {
|
||||
var recycling = isRecyclable(old, vnodes)
|
||||
if (recycling) old = old.concat(old.pool)
|
||||
var recycling = isRecyclable(old, vnodes)
|
||||
if (recycling) old = old.concat(old.pool)
|
||||
|
||||
var oldStart = 0, start = 0, oldEnd = old.length - 1, end = vnodes.length - 1, map
|
||||
while (oldEnd >= oldStart && end >= start) {
|
||||
var o = old[oldStart], v = vnodes[start]
|
||||
if (o === v && !recycling) oldStart++, start++
|
||||
else if (o == null) oldStart++
|
||||
var oldStart = 0, start = 0, oldEnd = old.length - 1, end = vnodes.length - 1, map
|
||||
while (oldEnd >= oldStart && end >= start) {
|
||||
var o = old[oldStart], v = vnodes[start]
|
||||
if (o === v && !recycling) oldStart++, start++
|
||||
else if (o == null) oldStart++
|
||||
else if (v == null) start++
|
||||
else if (o.key === v.key) {
|
||||
oldStart++, start++
|
||||
updateNode(parent, o, v, hooks, getNextSibling(old, oldStart, nextSibling), recycling, ns)
|
||||
if (recycling && o.tag === v.tag) insertNode(parent, toFragment(o), nextSibling)
|
||||
}
|
||||
else {
|
||||
var o = old[oldEnd]
|
||||
if (o === v && !recycling) oldEnd--, start++
|
||||
else if (o == null) oldEnd--
|
||||
else if (v == null) start++
|
||||
else if (o.key === v.key) {
|
||||
oldStart++, start++
|
||||
updateNode(parent, o, v, hooks, getNextSibling(old, oldStart, nextSibling), recycling, ns)
|
||||
if (recycling && o.tag === v.tag) insertNode(parent, toFragment(o), nextSibling)
|
||||
}
|
||||
else {
|
||||
var o = old[oldEnd]
|
||||
if (o === v && !recycling) oldEnd--, start++
|
||||
else if (o == null) oldEnd--
|
||||
else if (v == null) start++
|
||||
else if (o.key === v.key) {
|
||||
updateNode(parent, o, v, hooks, getNextSibling(old, oldEnd + 1, nextSibling), recycling, ns)
|
||||
if (recycling || start < end) insertNode(parent, toFragment(o), getNextSibling(old, oldStart, nextSibling))
|
||||
oldEnd--, start++
|
||||
}
|
||||
else break
|
||||
}
|
||||
}
|
||||
while (oldEnd >= oldStart && end >= start) {
|
||||
var o = old[oldEnd], v = vnodes[end]
|
||||
if (o === v && !recycling) oldEnd--, end--
|
||||
else if (o == null) oldEnd--
|
||||
else if (v == null) end--
|
||||
else if (o.key === v.key) {
|
||||
updateNode(parent, o, v, hooks, getNextSibling(old, oldEnd + 1, nextSibling), recycling, ns)
|
||||
if (recycling && o.tag === v.tag) insertNode(parent, toFragment(o), nextSibling)
|
||||
if (o.dom != null) nextSibling = o.dom
|
||||
oldEnd--, end--
|
||||
if (recycling || start < end) insertNode(parent, toFragment(o), getNextSibling(old, oldStart, nextSibling))
|
||||
oldEnd--, start++
|
||||
}
|
||||
else {
|
||||
if (!map) map = getKeyMap(old, oldEnd)
|
||||
if (v != null) {
|
||||
var oldIndex = map[v.key]
|
||||
if (oldIndex != null) {
|
||||
var movable = old[oldIndex]
|
||||
updateNode(parent, movable, v, hooks, getNextSibling(old, oldEnd + 1, nextSibling), recycling, ns)
|
||||
insertNode(parent, toFragment(movable), nextSibling)
|
||||
old[oldIndex].skip = true
|
||||
if (movable.dom != null) nextSibling = movable.dom
|
||||
}
|
||||
else {
|
||||
var dom = createNode(v, hooks, undefined)
|
||||
insertNode(parent, dom, nextSibling)
|
||||
nextSibling = dom
|
||||
}
|
||||
}
|
||||
end--
|
||||
}
|
||||
if (end < start) break
|
||||
else break
|
||||
}
|
||||
createNodes(parent, vnodes, start, end + 1, hooks, nextSibling, ns)
|
||||
removeNodes(old, oldStart, oldEnd + 1, vnodes)
|
||||
}
|
||||
while (oldEnd >= oldStart && end >= start) {
|
||||
var o = old[oldEnd], v = vnodes[end]
|
||||
if (o === v && !recycling) oldEnd--, end--
|
||||
else if (o == null) oldEnd--
|
||||
else if (v == null) end--
|
||||
else if (o.key === v.key) {
|
||||
updateNode(parent, o, v, hooks, getNextSibling(old, oldEnd + 1, nextSibling), recycling, ns)
|
||||
if (recycling && o.tag === v.tag) insertNode(parent, toFragment(o), nextSibling)
|
||||
if (o.dom != null) nextSibling = o.dom
|
||||
oldEnd--, end--
|
||||
}
|
||||
else {
|
||||
if (!map) map = getKeyMap(old, oldEnd)
|
||||
if (v != null) {
|
||||
var oldIndex = map[v.key]
|
||||
if (oldIndex != null) {
|
||||
var movable = old[oldIndex]
|
||||
updateNode(parent, movable, v, hooks, getNextSibling(old, oldEnd + 1, nextSibling), recycling, ns)
|
||||
insertNode(parent, toFragment(movable), nextSibling)
|
||||
old[oldIndex].skip = true
|
||||
if (movable.dom != null) nextSibling = movable.dom
|
||||
}
|
||||
else {
|
||||
var dom = createNode(v, hooks, undefined)
|
||||
insertNode(parent, dom, nextSibling)
|
||||
nextSibling = dom
|
||||
}
|
||||
}
|
||||
end--
|
||||
}
|
||||
if (end < start) break
|
||||
}
|
||||
createNodes(parent, vnodes, start, end + 1, hooks, nextSibling, ns)
|
||||
removeNodes(old, oldStart, oldEnd + 1, vnodes)
|
||||
}
|
||||
}
|
||||
function updateNode(parent, old, vnode, hooks, nextSibling, recycling, ns) {
|
||||
|
|
@ -434,14 +435,14 @@ module.exports = function($window) {
|
|||
}
|
||||
function setAttr(vnode, key, old, value, ns) {
|
||||
var element = vnode.dom
|
||||
if (key === "key" || (old === value && !isFormAttribute(vnode, key)) && typeof value !== "object" || typeof value === "undefined" || isLifecycleMethod(key)) return
|
||||
if (key === "key" || key === "is" || (old === value && !isFormAttribute(vnode, key)) && typeof value !== "object" || typeof value === "undefined" || isLifecycleMethod(key)) return
|
||||
var nsLastIndex = key.indexOf(":")
|
||||
if (nsLastIndex > -1 && key.substr(0, nsLastIndex) === "xlink") {
|
||||
element.setAttributeNS("http://www.w3.org/1999/xlink", key.slice(nsLastIndex + 1), value)
|
||||
}
|
||||
else if (key[0] === "o" && key[1] === "n" && typeof value === "function") updateEvent(vnode, key, value)
|
||||
else if (key === "style") updateStyle(element, old, value)
|
||||
else if (key in element && !isAttribute(key) && ns === undefined) {
|
||||
else if (key in element && !isAttribute(key) && ns === undefined && !isCustomElement(vnode)) {
|
||||
//setting input[value] to same value by typing on focused element moves cursor to end in Chrome
|
||||
if (vnode.tag === "input" && key === "value" && vnode.dom.value === value && vnode.dom === $doc.activeElement) return
|
||||
//setting select[value] to same value while having select open blinks select dropdown in Chrome
|
||||
|
|
@ -490,6 +491,9 @@ module.exports = function($window) {
|
|||
function isAttribute(attr) {
|
||||
return attr === "href" || attr === "list" || attr === "form" || attr === "width" || attr === "height"// || attr === "type"
|
||||
}
|
||||
function isCustomElement(vnode){
|
||||
return vnode.attrs.is || vnode.tag.indexOf("-") > -1
|
||||
}
|
||||
function hasIntegrationMethods(source) {
|
||||
return source != null && (source.oncreate || source.onupdate || source.onbeforeremove || source.onremove)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,43 @@ o.spec("attributes", function() {
|
|||
root = $window.document.body
|
||||
render = vdom($window).render
|
||||
})
|
||||
o.spec("customElements", function(){
|
||||
|
||||
o("when vnode is customElement, custom setAttribute called", function(){
|
||||
|
||||
var normal = [
|
||||
{ tag: "input", attrs: { value: 'hello' } },
|
||||
{ tag: "input", attrs: { value: 'hello' } },
|
||||
{ tag: "input", attrs: { value: 'hello' } }
|
||||
]
|
||||
|
||||
var custom = [
|
||||
{ tag: "custom-element", attrs: { custom: 'x' } },
|
||||
{ tag: "input", attrs: { is: 'something-special', custom: 'x' } },
|
||||
{ tag: "custom-element", attrs: { is: 'something-special', custom: 'x' } }
|
||||
]
|
||||
|
||||
var view = normal.concat(custom)
|
||||
|
||||
var f = $window.document.createElement
|
||||
var spy
|
||||
|
||||
$window.document.createElement = function(tag, is){
|
||||
var el = f(tag, is)
|
||||
if(!spy){
|
||||
spy = o.spy(el.setAttribute)
|
||||
}
|
||||
el.setAttribute = spy
|
||||
|
||||
return el
|
||||
}
|
||||
|
||||
render(root, view)
|
||||
|
||||
o(spy.callCount).equals( custom.length )
|
||||
})
|
||||
|
||||
})
|
||||
o.spec("input readonly", function() {
|
||||
o("when input readonly is true, attribute is present", function() {
|
||||
var a = {tag: "input", attrs: {readonly: true}}
|
||||
|
|
|
|||
|
|
@ -104,6 +104,15 @@ o.spec("updateNodes", function() {
|
|||
o(updated[0].dom.nodeValue).equals("a")
|
||||
o(updated[0].dom).equals(root.childNodes[0])
|
||||
})
|
||||
o("handles undefined to null noop", function() {
|
||||
var vnodes = [null, {tag: "div"}]
|
||||
var updated = [undefined, {tag: "div"}]
|
||||
|
||||
render(root, vnodes)
|
||||
render(root, updated)
|
||||
|
||||
o(root.childNodes.length).equals(1)
|
||||
})
|
||||
o("reverses els w/ even count", function() {
|
||||
var vnodes = [{tag: "a", key: 1}, {tag: "b", key: 2}, {tag: "i", key: 3}, {tag: "s", key: 4}]
|
||||
var updated = [{tag: "s", key: 4}, {tag: "i", key: 3}, {tag: "b", key: 2}, {tag: "a", key: 1}]
|
||||
|
|
@ -871,7 +880,7 @@ o.spec("updateNodes", function() {
|
|||
o(onupdate.callCount).equals(0)
|
||||
})
|
||||
o("cached, keyed nodes skip diff", function () {
|
||||
var onupdate = o.spy();
|
||||
var onupdate = o.spy()
|
||||
var cached = {tag:"a", key:"a", attrs:{onupdate: onupdate}}
|
||||
|
||||
render(root, cached)
|
||||
|
|
@ -917,4 +926,14 @@ o.spec("updateNodes", function() {
|
|||
o(update.callCount).equals(2)
|
||||
o(remove.callCount).equals(0)
|
||||
})
|
||||
o("component is recreated if key changes to undefined", function () {
|
||||
var vnode = {tag: "b", key: 1}
|
||||
var updated = {tag: "b"}
|
||||
|
||||
render(root, vnode)
|
||||
var dom = vnode.dom
|
||||
render(root, updated)
|
||||
|
||||
o(vnode.dom).notEquals(updated.dom)
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -67,9 +67,11 @@ module.exports = function($window) {
|
|||
if (hash) path += "#" + hash
|
||||
|
||||
if (supportsPushState) {
|
||||
if (options && options.replace) $window.history.replaceState(null, null, router.prefix + path)
|
||||
else $window.history.pushState(null, null, router.prefix + path)
|
||||
var state = options ? options.state : null
|
||||
var title = options ? options.title : null
|
||||
$window.onpopstate()
|
||||
if (options && options.replace) $window.history.replaceState(state, title, router.prefix + path)
|
||||
else $window.history.pushState(state, title, router.prefix + path)
|
||||
}
|
||||
else $window.location.href = router.prefix + path
|
||||
}
|
||||
|
|
@ -79,6 +81,10 @@ module.exports = function($window) {
|
|||
var params = {}
|
||||
var pathname = parsePath(path, params, params)
|
||||
|
||||
var state = $window.history.state
|
||||
if (state != null) {
|
||||
for (var k in state) params[k] = state[k]
|
||||
}
|
||||
for (var route in routes) {
|
||||
var matcher = new RegExp("^" + route.replace(/:[^\/]+?\.{3}/g, "(.*?)").replace(/:[^\/]+/g, "([^\\/]+)") + "\/?$")
|
||||
|
||||
|
|
|
|||
|
|
@ -150,6 +150,18 @@ o.spec("Router.setPath", function() {
|
|||
|
||||
o($window.location.href).equals(env.protocol + "//" + (env.hostname === "/" ? "" : env.hostname) + slash + (prefix ? prefix + "/" : "") + "test")
|
||||
|
||||
done()
|
||||
})
|
||||
})
|
||||
o("state works", function(done) {
|
||||
$window.location.href = prefix + "/test"
|
||||
router.defineRoutes({"/test": {data: 1}, "/other": {data: 2}}, onRouteChange, onFail)
|
||||
|
||||
callAsync(function() {
|
||||
router.setPath("/other", null, {state: {a: 1}})
|
||||
|
||||
o($window.history.state).deepEquals({a: 1})
|
||||
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ module.exports = function(options) {
|
|||
var search = ""
|
||||
var hash = ""
|
||||
|
||||
var past = [], future = []
|
||||
var past = [{url: getURL(), isNew: true, state: null, title: null}], future = []
|
||||
|
||||
function getURL() {
|
||||
if (protocol === "file:") return protocol + "//" + pathname + search + hash
|
||||
|
|
@ -42,7 +42,7 @@ module.exports = function(options) {
|
|||
if (typeof $window.onhashchange === "function") $window.onhashchange({type: "hashchange"})
|
||||
}
|
||||
function popstate() {
|
||||
if (typeof $window.onpopstate === "function") $window.onpopstate({type: "popstate"})
|
||||
if (typeof $window.onpopstate === "function") $window.onpopstate({type: "popstate", state: $window.history.state})
|
||||
}
|
||||
function unload() {
|
||||
if (typeof $window.onunload === "function") $window.onunload({type: "unload"})
|
||||
|
|
@ -135,20 +135,22 @@ module.exports = function(options) {
|
|||
},
|
||||
}
|
||||
$window.history = {
|
||||
pushState: function(data, title, url) {
|
||||
past.push({url: getURL(), isNew: false})
|
||||
pushState: function(state, title, url) {
|
||||
past.push({url: getURL(), isNew: false, state: state, title: title})
|
||||
future = []
|
||||
setURL(url)
|
||||
},
|
||||
replaceState: function(data, title, url) {
|
||||
future = []
|
||||
replaceState: function(state, title, url) {
|
||||
var entry = past[past.length - 1]
|
||||
entry.state = state
|
||||
entry.title = title
|
||||
setURL(url)
|
||||
},
|
||||
back: function() {
|
||||
var entry = past.pop()
|
||||
if (entry != null) {
|
||||
if (past.length > 1) {
|
||||
var entry = past.pop()
|
||||
if (entry.isNew) unload()
|
||||
future.push({url: getURL(), isNew: false})
|
||||
future.push({url: getURL(), isNew: false, state: entry.state, title: entry.title})
|
||||
setURL(entry.url)
|
||||
if (!entry.isNew) popstate()
|
||||
}
|
||||
|
|
@ -157,11 +159,14 @@ module.exports = function(options) {
|
|||
var entry = future.pop()
|
||||
if (entry != null) {
|
||||
if (entry.isNew) unload()
|
||||
past.push({url: getURL(), isNew: false})
|
||||
past.push({url: getURL(), isNew: false, state: entry.state, title: entry.title})
|
||||
setURL(entry.url)
|
||||
if (!entry.isNew) popstate()
|
||||
}
|
||||
},
|
||||
get state() {
|
||||
return past.length === 0 ? null : past[past.length - 1].state
|
||||
},
|
||||
}
|
||||
$window.onpopstate = null,
|
||||
$window.onhashchange = null,
|
||||
|
|
|
|||
|
|
@ -417,6 +417,71 @@ o.spec("pushStateMock", function() {
|
|||
$window.history.pushState(null, null, "b")
|
||||
$window.history.back()
|
||||
})
|
||||
o("replaceState does not break forward history", function() {
|
||||
$window.onpopstate = o.spy()
|
||||
|
||||
$window.history.pushState(null, null, "b")
|
||||
$window.history.back()
|
||||
|
||||
o($window.onpopstate.callCount).equals(1)
|
||||
o($window.location.href).equals("http://localhost/")
|
||||
|
||||
$window.history.replaceState(null, null, "a")
|
||||
|
||||
o($window.location.href).equals("http://localhost/a")
|
||||
|
||||
$window.history.forward()
|
||||
|
||||
o($window.onpopstate.callCount).equals(2)
|
||||
o($window.location.href).equals("http://localhost/b")
|
||||
})
|
||||
o("pushstate retains state", function() {
|
||||
$window.onpopstate = o.spy()
|
||||
|
||||
$window.history.pushState({a: 1}, null, "#a")
|
||||
$window.history.pushState({b: 2}, null, "#b")
|
||||
|
||||
o($window.onpopstate.callCount).equals(0)
|
||||
|
||||
$window.history.back()
|
||||
|
||||
o($window.onpopstate.callCount).equals(1)
|
||||
o($window.onpopstate.args[0].type).equals("popstate")
|
||||
o($window.onpopstate.args[0].state).deepEquals({a: 1})
|
||||
|
||||
$window.history.back()
|
||||
|
||||
o($window.onpopstate.callCount).equals(2)
|
||||
o($window.onpopstate.args[0].type).equals("popstate")
|
||||
o($window.onpopstate.args[0].state).equals(null)
|
||||
|
||||
$window.history.forward()
|
||||
|
||||
o($window.onpopstate.callCount).equals(3)
|
||||
o($window.onpopstate.args[0].type).equals("popstate")
|
||||
o($window.onpopstate.args[0].state).deepEquals({a: 1})
|
||||
|
||||
$window.history.forward()
|
||||
|
||||
o($window.onpopstate.callCount).equals(4)
|
||||
o($window.onpopstate.args[0].type).equals("popstate")
|
||||
o($window.onpopstate.args[0].state).deepEquals({b: 2})
|
||||
})
|
||||
o("replacestate replaces state", function() {
|
||||
$window.onpopstate = o.spy(pop)
|
||||
|
||||
$window.history.replaceState({a: 1}, null, "a")
|
||||
|
||||
o($window.history.state).deepEquals({a: 1})
|
||||
|
||||
$window.history.pushState(null, null, "a")
|
||||
$window.history.back()
|
||||
|
||||
function pop(e) {
|
||||
o(e.state).deepEquals({a: 1})
|
||||
o($window.history.state).deepEquals({a: 1})
|
||||
}
|
||||
})
|
||||
})
|
||||
o.spec("onhashchance", function() {
|
||||
o("onhashchange triggers on location.href change", function() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue