#1609 fix lifecycle hooks in children of recycled keyed vnode
This commit is contained in:
parent
2688db881a
commit
dc42b60687
7 changed files with 121 additions and 71 deletions
|
|
@ -54,7 +54,7 @@ Let's create an HTML file to follow along:
|
||||||
|
|
||||||
```markup
|
```markup
|
||||||
<body>
|
<body>
|
||||||
<script src="http://unpkg.com/mithril/mithril.js"></script>
|
<script src="//unpkg.com/mithril/mithril.js"></script>
|
||||||
<script>
|
<script>
|
||||||
var root = document.body
|
var root = document.body
|
||||||
|
|
||||||
|
|
@ -231,7 +231,7 @@ var count = 0
|
||||||
var increment = function() {
|
var increment = function() {
|
||||||
m.request({
|
m.request({
|
||||||
method: "PUT",
|
method: "PUT",
|
||||||
url: "http://rem-rest-api.herokuapp.com/api/tutorial/1",
|
url: "//rem-rest-api.herokuapp.com/api/tutorial/1",
|
||||||
data: {count: count + 1},
|
data: {count: count + 1},
|
||||||
withCredentials: true,
|
withCredentials: true,
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,21 @@
|
||||||
# Change log
|
# Change log
|
||||||
|
|
||||||
|
- [v1.0.1](#v101)
|
||||||
- [Migrating from v0.2.x](#migrating-from-v02x)
|
- [Migrating from v0.2.x](#migrating-from-v02x)
|
||||||
- [Older docs](http://mithril.js.org/archive/v0.2.5/change-log.html)
|
- [Older docs](http://mithril.js.org/archive/v0.2.5/index.html)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### v1.0.1
|
||||||
|
|
||||||
|
#### News
|
||||||
|
|
||||||
|
- performance improvements in IE [#1598](https://github.com/lhorie/mithril.js/pull/1598)
|
||||||
|
|
||||||
|
#### Bug fixes
|
||||||
|
|
||||||
|
- prevent infinite loop in non-existent default route - [#1579](https://github.com/lhorie/mithril.js/issues/1579)
|
||||||
|
- call correct lifecycle methods on children of recycled keyed vnodes - [#1609](https://github.com/lhorie/mithril.js/issues/1609)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,10 +17,10 @@ Special thanks to:
|
||||||
- Leon Sorokin, for writing a DOM instrumentation tool that helped improve performance in Mithril 1.0
|
- Leon Sorokin, for writing a DOM instrumentation tool that helped improve performance in Mithril 1.0
|
||||||
- Jordan Walke, whose work on React was prior art to the implementation of keys in Mithril
|
- Jordan Walke, whose work on React was prior art to the implementation of keys in Mithril
|
||||||
- Pierre-Yves Gérardy, who consistently makes high quality contributions
|
- Pierre-Yves Gérardy, who consistently makes high quality contributions
|
||||||
|
- Gyandeep Singh, who contributed significant IE performance improvements
|
||||||
|
|
||||||
Other people who also deserve recognition:
|
Other people who also deserve recognition:
|
||||||
|
|
||||||
- Arthur Clemens - creator of [Polythene](https://github.com/ArthurClemens/Polythene) and the [HTML-to-Mithril converter](http://arthurclemens.github.io/mithril-template-converter/index.html)
|
- Arthur Clemens - creator of [Polythene](https://github.com/ArthurClemens/Polythene) and the [HTML-to-Mithril converter](http://arthurclemens.github.io/mithril-template-converter/index.html)
|
||||||
- Stephan Hoyer - creator of [mithril-node-render](https://github.com/StephanHoyer/mithril-node-render), [mithril-query](https://github.com/StephanHoyer/mithril-query) and [mithril-source-hint](https://github.com/StephanHoyer/mithril-source-hint)
|
- Stephan Hoyer - creator of [mithril-node-render](https://github.com/StephanHoyer/mithril-node-render), [mithril-query](https://github.com/StephanHoyer/mithril-query) and [mithril-source-hint](https://github.com/StephanHoyer/mithril-source-hint)
|
||||||
- the countless people who have reported and fixed bugs, participated in discussions, and helped promote Mithril
|
- the countless people who have reported and fixed bugs, participated in discussions, and helped promote Mithril
|
||||||
|
|
||||||
|
|
|
||||||
68
mithril.js
68
mithril.js
|
|
@ -355,30 +355,32 @@ var coreRenderer = function($window) {
|
||||||
for (var i = start; i < end; i++) {
|
for (var i = start; i < end; i++) {
|
||||||
var vnode = vnodes[i]
|
var vnode = vnodes[i]
|
||||||
if (vnode != null) {
|
if (vnode != null) {
|
||||||
insertNode(parent, createNode(vnode, hooks, ns), nextSibling)
|
createNode(parent, vnode, hooks, ns, nextSibling)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function createNode(vnode, hooks, ns) {
|
function createNode(parent, vnode, hooks, ns, nextSibling) {
|
||||||
var tag = vnode.tag
|
var tag = vnode.tag
|
||||||
if (vnode.attrs != null) initLifecycle(vnode.attrs, vnode, hooks)
|
if (vnode.attrs != null) initLifecycle(vnode.attrs, vnode, hooks)
|
||||||
if (typeof tag === "string") {
|
if (typeof tag === "string") {
|
||||||
switch (tag) {
|
switch (tag) {
|
||||||
case "#": return createText(vnode)
|
case "#": return createText(parent, vnode, nextSibling)
|
||||||
case "<": return createHTML(vnode)
|
case "<": return createHTML(parent, vnode, nextSibling)
|
||||||
case "[": return createFragment(vnode, hooks, ns)
|
case "[": return createFragment(parent, vnode, hooks, ns, nextSibling)
|
||||||
default: return createElement(vnode, hooks, ns)
|
default: return createElement(parent, vnode, hooks, ns, nextSibling)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else return createComponent(vnode, hooks, ns)
|
else return createComponent(parent, vnode, hooks, ns, nextSibling)
|
||||||
}
|
}
|
||||||
function createText(vnode) {
|
function createText(parent, vnode, nextSibling) {
|
||||||
return vnode.dom = $doc.createTextNode(vnode.children)
|
vnode.dom = $doc.createTextNode(vnode.children)
|
||||||
|
insertNode(parent, vnode.dom, nextSibling)
|
||||||
|
return vnode.dom
|
||||||
}
|
}
|
||||||
function createHTML(vnode) {
|
function createHTML(parent, vnode, nextSibling) {
|
||||||
var match1 = vnode.children.match(/^\s*?<(\w+)/im) || []
|
var match1 = vnode.children.match(/^\s*?<(\w+)/im) || []
|
||||||
var parent = {caption: "table", thead: "table", tbody: "table", tfoot: "table", tr: "tbody", th: "tr", td: "tr", colgroup: "table", col: "colgroup"}[match1[1]] || "div"
|
var parent1 = {caption: "table", thead: "table", tbody: "table", tfoot: "table", tr: "tbody", th: "tr", td: "tr", colgroup: "table", col: "colgroup"}[match1[1]] || "div"
|
||||||
var temp = $doc.createElement(parent)
|
var temp = $doc.createElement(parent1)
|
||||||
temp.innerHTML = vnode.children
|
temp.innerHTML = vnode.children
|
||||||
vnode.dom = temp.firstChild
|
vnode.dom = temp.firstChild
|
||||||
vnode.domSize = temp.childNodes.length
|
vnode.domSize = temp.childNodes.length
|
||||||
|
|
@ -387,9 +389,10 @@ var coreRenderer = function($window) {
|
||||||
while (child = temp.firstChild) {
|
while (child = temp.firstChild) {
|
||||||
fragment.appendChild(child)
|
fragment.appendChild(child)
|
||||||
}
|
}
|
||||||
|
insertNode(parent, fragment, nextSibling)
|
||||||
return fragment
|
return fragment
|
||||||
}
|
}
|
||||||
function createFragment(vnode, hooks, ns) {
|
function createFragment(parent, vnode, hooks, ns, nextSibling) {
|
||||||
var fragment = $doc.createDocumentFragment()
|
var fragment = $doc.createDocumentFragment()
|
||||||
if (vnode.children != null) {
|
if (vnode.children != null) {
|
||||||
var children = vnode.children
|
var children = vnode.children
|
||||||
|
|
@ -397,9 +400,10 @@ var coreRenderer = function($window) {
|
||||||
}
|
}
|
||||||
vnode.dom = fragment.firstChild
|
vnode.dom = fragment.firstChild
|
||||||
vnode.domSize = fragment.childNodes.length
|
vnode.domSize = fragment.childNodes.length
|
||||||
|
insertNode(parent, fragment, nextSibling)
|
||||||
return fragment
|
return fragment
|
||||||
}
|
}
|
||||||
function createElement(vnode, hooks, ns) {
|
function createElement(parent, vnode, hooks, ns, nextSibling) {
|
||||||
var tag = vnode.tag
|
var tag = vnode.tag
|
||||||
switch (vnode.tag) {
|
switch (vnode.tag) {
|
||||||
case "svg": ns = "http://www.w3.org/2000/svg"; break
|
case "svg": ns = "http://www.w3.org/2000/svg"; break
|
||||||
|
|
@ -414,6 +418,7 @@ var coreRenderer = function($window) {
|
||||||
if (attrs2 != null) {
|
if (attrs2 != null) {
|
||||||
setAttrs(vnode, attrs2, ns)
|
setAttrs(vnode, attrs2, ns)
|
||||||
}
|
}
|
||||||
|
insertNode(parent, element, nextSibling)
|
||||||
if (vnode.attrs != null && vnode.attrs.contenteditable != null) {
|
if (vnode.attrs != null && vnode.attrs.contenteditable != null) {
|
||||||
setContentEditable(vnode)
|
setContentEditable(vnode)
|
||||||
}
|
}
|
||||||
|
|
@ -430,7 +435,7 @@ var coreRenderer = function($window) {
|
||||||
}
|
}
|
||||||
return element
|
return element
|
||||||
}
|
}
|
||||||
function createComponent(vnode, hooks, ns) {
|
function createComponent(parent, vnode, hooks, ns, nextSibling) {
|
||||||
vnode.state = Object.create(vnode.tag)
|
vnode.state = Object.create(vnode.tag)
|
||||||
var view = vnode.tag.view
|
var view = vnode.tag.view
|
||||||
if (view.reentrantLock != null) return $emptyFragment
|
if (view.reentrantLock != null) return $emptyFragment
|
||||||
|
|
@ -440,9 +445,10 @@ var coreRenderer = function($window) {
|
||||||
view.reentrantLock = null
|
view.reentrantLock = null
|
||||||
if (vnode.instance != null) {
|
if (vnode.instance != null) {
|
||||||
if (vnode.instance === vnode) throw Error("A view cannot return the vnode it received as arguments")
|
if (vnode.instance === vnode) throw Error("A view cannot return the vnode it received as arguments")
|
||||||
var element = createNode(vnode.instance, hooks, ns)
|
var element = createNode(parent, vnode.instance, hooks, ns, nextSibling)
|
||||||
vnode.dom = vnode.instance.dom
|
vnode.dom = vnode.instance.dom
|
||||||
vnode.domSize = vnode.dom != null ? vnode.instance.domSize : 0
|
vnode.domSize = vnode.dom != null ? vnode.instance.domSize : 0
|
||||||
|
insertNode(parent, element, nextSibling)
|
||||||
return element
|
return element
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
@ -451,7 +457,7 @@ var coreRenderer = function($window) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//update
|
//update
|
||||||
function updateNodes(parent, old, vnodes, hooks, nextSibling, ns) {
|
function updateNodes(parent, old, vnodes, recycling, hooks, nextSibling, ns) {
|
||||||
if (old === vnodes || old == null && vnodes == null) return
|
if (old === vnodes || old == null && vnodes == null) return
|
||||||
else if (old == null) createNodes(parent, vnodes, 0, vnodes.length, hooks, nextSibling, undefined)
|
else if (old == null) createNodes(parent, vnodes, 0, vnodes.length, hooks, nextSibling, undefined)
|
||||||
else if (vnodes == null) removeNodes(old, 0, old.length, vnodes)
|
else if (vnodes == null) removeNodes(old, 0, old.length, vnodes)
|
||||||
|
|
@ -467,15 +473,16 @@ var coreRenderer = function($window) {
|
||||||
if (isUnkeyed) {
|
if (isUnkeyed) {
|
||||||
for (var i = 0; i < old.length; i++) {
|
for (var i = 0; i < old.length; i++) {
|
||||||
if (old[i] === vnodes[i]) continue
|
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 (old[i] == null && vnodes[i] != null) createNode(parent, vnodes[i], hooks, ns, getNextSibling(old, i + 1, nextSibling))
|
||||||
else if (vnodes[i] == null) removeNodes(old, i, i + 1, vnodes)
|
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 updateNode(parent, old[i], vnodes[i], hooks, getNextSibling(old, i + 1, nextSibling), false, ns)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var recycling = isRecyclable(old, vnodes)
|
recycling = recycling || isRecyclable(old, vnodes)
|
||||||
if (recycling) old = old.concat(old.pool)
|
if (recycling) old = old.concat(old.pool)
|
||||||
|
|
||||||
var oldStart = 0, start = 0, oldEnd = old.length - 1, end = vnodes.length - 1, map
|
var oldStart = 0, start = 0, oldEnd = old.length - 1, end = vnodes.length - 1, map
|
||||||
while (oldEnd >= oldStart && end >= start) {
|
while (oldEnd >= oldStart && end >= start) {
|
||||||
var o = old[oldStart], v = vnodes[start]
|
var o = old[oldStart], v = vnodes[start]
|
||||||
|
|
@ -523,8 +530,7 @@ var coreRenderer = function($window) {
|
||||||
if (movable.dom != null) nextSibling = movable.dom
|
if (movable.dom != null) nextSibling = movable.dom
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
var dom = createNode(v, hooks, undefined)
|
var dom = createNode(parent, v, hooks, undefined, nextSibling)
|
||||||
insertNode(parent, dom, nextSibling)
|
|
||||||
nextSibling = dom
|
nextSibling = dom
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -549,15 +555,15 @@ var coreRenderer = function($window) {
|
||||||
switch (oldTag) {
|
switch (oldTag) {
|
||||||
case "#": updateText(old, vnode); break
|
case "#": updateText(old, vnode); break
|
||||||
case "<": updateHTML(parent, old, vnode, nextSibling); break
|
case "<": updateHTML(parent, old, vnode, nextSibling); break
|
||||||
case "[": updateFragment(parent, old, vnode, hooks, nextSibling, ns); break
|
case "[": updateFragment(parent, old, vnode, recycling, hooks, nextSibling, ns); break
|
||||||
default: updateElement(old, vnode, hooks, ns)
|
default: updateElement(old, vnode, recycling, hooks, ns)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else updateComponent(parent, old, vnode, hooks, nextSibling, recycling, ns)
|
else updateComponent(parent, old, vnode, hooks, nextSibling, recycling, ns)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
removeNode(old, null)
|
removeNode(old, null)
|
||||||
insertNode(parent, createNode(vnode, hooks, ns), nextSibling)
|
createNode(parent, vnode, hooks, ns, nextSibling)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function updateText(old, vnode) {
|
function updateText(old, vnode) {
|
||||||
|
|
@ -569,12 +575,12 @@ var coreRenderer = function($window) {
|
||||||
function updateHTML(parent, old, vnode, nextSibling) {
|
function updateHTML(parent, old, vnode, nextSibling) {
|
||||||
if (old.children !== vnode.children) {
|
if (old.children !== vnode.children) {
|
||||||
toFragment(old)
|
toFragment(old)
|
||||||
insertNode(parent, createHTML(vnode), nextSibling)
|
createHTML(parent, vnode, nextSibling)
|
||||||
}
|
}
|
||||||
else vnode.dom = old.dom, vnode.domSize = old.domSize
|
else vnode.dom = old.dom, vnode.domSize = old.domSize
|
||||||
}
|
}
|
||||||
function updateFragment(parent, old, vnode, hooks, nextSibling, ns) {
|
function updateFragment(parent, old, vnode, recycling, hooks, nextSibling, ns) {
|
||||||
updateNodes(parent, old.children, vnode.children, hooks, nextSibling, ns)
|
updateNodes(parent, old.children, vnode.children, recycling, hooks, nextSibling, ns)
|
||||||
var domSize = 0, children = vnode.children
|
var domSize = 0, children = vnode.children
|
||||||
vnode.dom = null
|
vnode.dom = null
|
||||||
if (children != null) {
|
if (children != null) {
|
||||||
|
|
@ -588,7 +594,7 @@ var coreRenderer = function($window) {
|
||||||
if (domSize !== 1) vnode.domSize = domSize
|
if (domSize !== 1) vnode.domSize = domSize
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function updateElement(old, vnode, hooks, ns) {
|
function updateElement(old, vnode, recycling, hooks, ns) {
|
||||||
var element = vnode.dom = old.dom
|
var element = vnode.dom = old.dom
|
||||||
switch (vnode.tag) {
|
switch (vnode.tag) {
|
||||||
case "svg": ns = "http://www.w3.org/2000/svg"; break
|
case "svg": ns = "http://www.w3.org/2000/svg"; break
|
||||||
|
|
@ -611,14 +617,14 @@ var coreRenderer = function($window) {
|
||||||
else {
|
else {
|
||||||
if (old.text != null) old.children = [Vnode("#", undefined, undefined, old.text, undefined, old.dom.firstChild)]
|
if (old.text != null) old.children = [Vnode("#", undefined, undefined, old.text, undefined, old.dom.firstChild)]
|
||||||
if (vnode.text != null) vnode.children = [Vnode("#", undefined, undefined, vnode.text, undefined, undefined)]
|
if (vnode.text != null) vnode.children = [Vnode("#", undefined, undefined, vnode.text, undefined, undefined)]
|
||||||
updateNodes(element, old.children, vnode.children, hooks, null, ns)
|
updateNodes(element, old.children, vnode.children, recycling, hooks, null, ns)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function updateComponent(parent, old, vnode, hooks, nextSibling, recycling, ns) {
|
function updateComponent(parent, old, vnode, hooks, nextSibling, recycling, ns) {
|
||||||
vnode.instance = Vnode.normalize(vnode.tag.view.call(vnode.state, vnode))
|
vnode.instance = Vnode.normalize(vnode.tag.view.call(vnode.state, vnode))
|
||||||
updateLifecycle(vnode.tag, vnode, hooks, recycling)
|
updateLifecycle(vnode.tag, vnode, hooks, recycling)
|
||||||
if (vnode.instance != null) {
|
if (vnode.instance != null) {
|
||||||
if (old.instance == null) insertNode(parent, createNode(vnode.instance, hooks, ns), nextSibling)
|
if (old.instance == null) createNode(parent, vnode.instance, hooks, ns, nextSibling)
|
||||||
else updateNode(parent, old.instance, vnode.instance, hooks, nextSibling, recycling, ns)
|
else updateNode(parent, old.instance, vnode.instance, hooks, nextSibling, recycling, ns)
|
||||||
vnode.dom = vnode.instance.dom
|
vnode.dom = vnode.instance.dom
|
||||||
vnode.domSize = vnode.instance.domSize
|
vnode.domSize = vnode.instance.domSize
|
||||||
|
|
@ -886,7 +892,7 @@ var coreRenderer = function($window) {
|
||||||
// First time0 rendering into a node clears it out
|
// First time0 rendering into a node clears it out
|
||||||
if (dom.vnodes == null) dom.textContent = ""
|
if (dom.vnodes == null) dom.textContent = ""
|
||||||
if (!Array.isArray(vnodes)) vnodes = [vnodes]
|
if (!Array.isArray(vnodes)) vnodes = [vnodes]
|
||||||
updateNodes(dom, dom.vnodes, Vnode.normalizeChildren(vnodes), hooks, null, undefined)
|
updateNodes(dom, dom.vnodes, Vnode.normalizeChildren(vnodes), false, hooks, null, undefined)
|
||||||
dom.vnodes = vnodes
|
dom.vnodes = vnodes
|
||||||
for (var i = 0; i < hooks.length; i++) hooks[i]()
|
for (var i = 0; i < hooks.length; i++) hooks[i]()
|
||||||
if ($doc.activeElement !== active) active.focus()
|
if ($doc.activeElement !== active) active.focus()
|
||||||
|
|
|
||||||
|
|
@ -123,7 +123,7 @@ module.exports = function($window) {
|
||||||
}
|
}
|
||||||
|
|
||||||
//update
|
//update
|
||||||
function updateNodes(parent, old, vnodes, hooks, nextSibling, ns) {
|
function updateNodes(parent, old, vnodes, recycling, hooks, nextSibling, ns) {
|
||||||
if (old === vnodes || old == null && vnodes == null) return
|
if (old === vnodes || old == null && vnodes == null) return
|
||||||
else if (old == null) createNodes(parent, vnodes, 0, vnodes.length, hooks, nextSibling, undefined)
|
else if (old == null) createNodes(parent, vnodes, 0, vnodes.length, hooks, nextSibling, undefined)
|
||||||
else if (vnodes == null) removeNodes(old, 0, old.length, vnodes)
|
else if (vnodes == null) removeNodes(old, 0, old.length, vnodes)
|
||||||
|
|
@ -146,9 +146,9 @@ module.exports = function($window) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var recycling = isRecyclable(old, vnodes)
|
recycling = recycling || isRecyclable(old, vnodes)
|
||||||
if (recycling) old = old.concat(old.pool)
|
if (recycling) old = old.concat(old.pool)
|
||||||
|
|
||||||
var oldStart = 0, start = 0, oldEnd = old.length - 1, end = vnodes.length - 1, map
|
var oldStart = 0, start = 0, oldEnd = old.length - 1, end = vnodes.length - 1, map
|
||||||
while (oldEnd >= oldStart && end >= start) {
|
while (oldEnd >= oldStart && end >= start) {
|
||||||
var o = old[oldStart], v = vnodes[start]
|
var o = old[oldStart], v = vnodes[start]
|
||||||
|
|
@ -221,8 +221,8 @@ module.exports = function($window) {
|
||||||
switch (oldTag) {
|
switch (oldTag) {
|
||||||
case "#": updateText(old, vnode); break
|
case "#": updateText(old, vnode); break
|
||||||
case "<": updateHTML(parent, old, vnode, nextSibling); break
|
case "<": updateHTML(parent, old, vnode, nextSibling); break
|
||||||
case "[": updateFragment(parent, old, vnode, hooks, nextSibling, ns); break
|
case "[": updateFragment(parent, old, vnode, recycling, hooks, nextSibling, ns); break
|
||||||
default: updateElement(old, vnode, hooks, ns)
|
default: updateElement(old, vnode, recycling, hooks, ns)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else updateComponent(parent, old, vnode, hooks, nextSibling, recycling, ns)
|
else updateComponent(parent, old, vnode, hooks, nextSibling, recycling, ns)
|
||||||
|
|
@ -245,8 +245,8 @@ module.exports = function($window) {
|
||||||
}
|
}
|
||||||
else vnode.dom = old.dom, vnode.domSize = old.domSize
|
else vnode.dom = old.dom, vnode.domSize = old.domSize
|
||||||
}
|
}
|
||||||
function updateFragment(parent, old, vnode, hooks, nextSibling, ns) {
|
function updateFragment(parent, old, vnode, recycling, hooks, nextSibling, ns) {
|
||||||
updateNodes(parent, old.children, vnode.children, hooks, nextSibling, ns)
|
updateNodes(parent, old.children, vnode.children, recycling, hooks, nextSibling, ns)
|
||||||
var domSize = 0, children = vnode.children
|
var domSize = 0, children = vnode.children
|
||||||
vnode.dom = null
|
vnode.dom = null
|
||||||
if (children != null) {
|
if (children != null) {
|
||||||
|
|
@ -260,7 +260,7 @@ module.exports = function($window) {
|
||||||
if (domSize !== 1) vnode.domSize = domSize
|
if (domSize !== 1) vnode.domSize = domSize
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function updateElement(old, vnode, hooks, ns) {
|
function updateElement(old, vnode, recycling, hooks, ns) {
|
||||||
var element = vnode.dom = old.dom
|
var element = vnode.dom = old.dom
|
||||||
switch (vnode.tag) {
|
switch (vnode.tag) {
|
||||||
case "svg": ns = "http://www.w3.org/2000/svg"; break
|
case "svg": ns = "http://www.w3.org/2000/svg"; break
|
||||||
|
|
@ -283,7 +283,7 @@ module.exports = function($window) {
|
||||||
else {
|
else {
|
||||||
if (old.text != null) old.children = [Vnode("#", undefined, undefined, old.text, undefined, old.dom.firstChild)]
|
if (old.text != null) old.children = [Vnode("#", undefined, undefined, old.text, undefined, old.dom.firstChild)]
|
||||||
if (vnode.text != null) vnode.children = [Vnode("#", undefined, undefined, vnode.text, undefined, undefined)]
|
if (vnode.text != null) vnode.children = [Vnode("#", undefined, undefined, vnode.text, undefined, undefined)]
|
||||||
updateNodes(element, old.children, vnode.children, hooks, null, ns)
|
updateNodes(element, old.children, vnode.children, recycling, hooks, null, ns)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function updateComponent(parent, old, vnode, hooks, nextSibling, recycling, ns) {
|
function updateComponent(parent, old, vnode, hooks, nextSibling, recycling, ns) {
|
||||||
|
|
@ -568,7 +568,7 @@ module.exports = function($window) {
|
||||||
if (dom.vnodes == null) dom.textContent = ""
|
if (dom.vnodes == null) dom.textContent = ""
|
||||||
|
|
||||||
if (!Array.isArray(vnodes)) vnodes = [vnodes]
|
if (!Array.isArray(vnodes)) vnodes = [vnodes]
|
||||||
updateNodes(dom, dom.vnodes, Vnode.normalizeChildren(vnodes), hooks, null, undefined)
|
updateNodes(dom, dom.vnodes, Vnode.normalizeChildren(vnodes), false, hooks, null, undefined)
|
||||||
dom.vnodes = vnodes
|
dom.vnodes = vnodes
|
||||||
for (var i = 0; i < hooks.length; i++) hooks[i]()
|
for (var i = 0; i < hooks.length; i++) hooks[i]()
|
||||||
if ($doc.activeElement !== active) active.focus()
|
if ($doc.activeElement !== active) active.focus()
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ o.spec("render", function() {
|
||||||
|
|
||||||
o(root.childNodes.length).equals(0)
|
o(root.childNodes.length).equals(0)
|
||||||
})
|
})
|
||||||
|
|
||||||
o("throws on invalid root node", function() {
|
o("throws on invalid root node", function() {
|
||||||
var threw = false
|
var threw = false
|
||||||
try {
|
try {
|
||||||
|
|
@ -31,7 +31,7 @@ o.spec("render", function() {
|
||||||
}
|
}
|
||||||
o(threw).equals(true)
|
o(threw).equals(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
o("does not enter infinite loop when oninit triggers render and view throws", function(done) {
|
o("does not enter infinite loop when oninit triggers render and view throws", function(done) {
|
||||||
var A = {
|
var A = {
|
||||||
oninit: init,
|
oninit: init,
|
||||||
|
|
@ -44,15 +44,45 @@ o.spec("render", function() {
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
var threwInner = false
|
var threwInner = false
|
||||||
try {run()} catch (e) {threwInner = true}
|
try {run()} catch (e) {threwInner = true}
|
||||||
|
|
||||||
o(threwInner).equals(false)
|
o(threwInner).equals(false)
|
||||||
done()
|
done()
|
||||||
}, 0)
|
}, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
var threwOuter = false
|
var threwOuter = false
|
||||||
try {run()} catch (e) {threwOuter = true}
|
try {run()} catch (e) {threwOuter = true}
|
||||||
|
|
||||||
o(threwOuter).equals(true)
|
o(threwOuter).equals(true)
|
||||||
})
|
})
|
||||||
|
o("lifecycle methods work in children of recycled", function() {
|
||||||
|
var createA = o.spy()
|
||||||
|
var updateA = o.spy()
|
||||||
|
var removeA = o.spy()
|
||||||
|
var createB = o.spy()
|
||||||
|
var updateB = o.spy()
|
||||||
|
var removeB = o.spy()
|
||||||
|
var a = function() {
|
||||||
|
return {tag: "div", key: 1, children: [
|
||||||
|
{tag: "div", key: 11, attrs: {oncreate: createA, onupdate: updateA, onremove: removeA}},
|
||||||
|
{tag: "div", key: 12}
|
||||||
|
]}
|
||||||
|
}
|
||||||
|
var b = function() {
|
||||||
|
return {tag: "div", key: 2, children: [
|
||||||
|
{tag: "div", key: 21, attrs: {oncreate: createB, onupdate: updateB, onremove: removeB}},
|
||||||
|
{tag: "div", key: 22}
|
||||||
|
]}
|
||||||
|
}
|
||||||
|
render(root, a())
|
||||||
|
render(root, b())
|
||||||
|
render(root, a())
|
||||||
|
|
||||||
|
o(createA.callCount).equals(2)
|
||||||
|
o(updateA.callCount).equals(0)
|
||||||
|
o(removeA.callCount).equals(1)
|
||||||
|
o(createB.callCount).equals(1)
|
||||||
|
o(updateB.callCount).equals(0)
|
||||||
|
o(removeB.callCount).equals(1)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -11,11 +11,11 @@ o.spec("api", function() {
|
||||||
if (typeof global !== "undefined") global.window = mock
|
if (typeof global !== "undefined") global.window = mock
|
||||||
m = require("../mithril")
|
m = require("../mithril")
|
||||||
})
|
})
|
||||||
|
|
||||||
o.spec("m", function() {
|
o.spec("m", function() {
|
||||||
o("works", function() {
|
o("works", function() {
|
||||||
var vnode = m("div")
|
var vnode = m("div")
|
||||||
|
|
||||||
o(vnode.tag).equals("div")
|
o(vnode.tag).equals("div")
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -29,7 +29,7 @@ o.spec("api", function() {
|
||||||
o.spec("m.trust", function() {
|
o.spec("m.trust", function() {
|
||||||
o("works", function() {
|
o("works", function() {
|
||||||
var vnode = m.trust("<br>")
|
var vnode = m.trust("<br>")
|
||||||
|
|
||||||
o(vnode.tag).equals("<")
|
o(vnode.tag).equals("<")
|
||||||
o(vnode.children).equals("<br>")
|
o(vnode.children).equals("<br>")
|
||||||
})
|
})
|
||||||
|
|
@ -37,7 +37,7 @@ o.spec("api", function() {
|
||||||
o.spec("m.fragment", function() {
|
o.spec("m.fragment", function() {
|
||||||
o("works", function() {
|
o("works", function() {
|
||||||
var vnode = m.fragment({key: 123}, [m("div")])
|
var vnode = m.fragment({key: 123}, [m("div")])
|
||||||
|
|
||||||
o(vnode.tag).equals("[")
|
o(vnode.tag).equals("[")
|
||||||
o(vnode.key).equals(123)
|
o(vnode.key).equals(123)
|
||||||
o(vnode.children.length).equals(1)
|
o(vnode.children.length).equals(1)
|
||||||
|
|
@ -48,23 +48,23 @@ o.spec("api", function() {
|
||||||
o("works", function() {
|
o("works", function() {
|
||||||
var spy = o.spy()
|
var spy = o.spy()
|
||||||
var handler = m.withAttr("value", spy)
|
var handler = m.withAttr("value", spy)
|
||||||
|
|
||||||
handler({currentTarget: {value: 10}})
|
handler({currentTarget: {value: 10}})
|
||||||
|
|
||||||
o(spy.args[0]).equals(10)
|
o(spy.args[0]).equals(10)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
o.spec("m.parseQueryString", function() {
|
o.spec("m.parseQueryString", function() {
|
||||||
o("works", function() {
|
o("works", function() {
|
||||||
var query = m.parseQueryString("?a=1&b=2")
|
var query = m.parseQueryString("?a=1&b=2")
|
||||||
|
|
||||||
o(query).deepEquals({a: "1", b: "2"})
|
o(query).deepEquals({a: "1", b: "2"})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
o.spec("m.buildQueryString", function() {
|
o.spec("m.buildQueryString", function() {
|
||||||
o("works", function() {
|
o("works", function() {
|
||||||
var query = m.buildQueryString({a: 1, b: 2})
|
var query = m.buildQueryString({a: 1, b: 2})
|
||||||
|
|
||||||
o(query).equals("a=1&b=2")
|
o(query).equals("a=1&b=2")
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -72,7 +72,7 @@ o.spec("api", function() {
|
||||||
o("works", function() {
|
o("works", function() {
|
||||||
var root = window.document.createElement("div")
|
var root = window.document.createElement("div")
|
||||||
m.render(root, m("div"))
|
m.render(root, m("div"))
|
||||||
|
|
||||||
o(root.childNodes.length).equals(1)
|
o(root.childNodes.length).equals(1)
|
||||||
o(root.firstChild.nodeName).equals("DIV")
|
o(root.firstChild.nodeName).equals("DIV")
|
||||||
})
|
})
|
||||||
|
|
@ -81,7 +81,7 @@ o.spec("api", function() {
|
||||||
o("works", function() {
|
o("works", function() {
|
||||||
var root = window.document.createElement("div")
|
var root = window.document.createElement("div")
|
||||||
m.mount(root, {view: function() {return m("div")}})
|
m.mount(root, {view: function() {return m("div")}})
|
||||||
|
|
||||||
o(root.childNodes.length).equals(1)
|
o(root.childNodes.length).equals(1)
|
||||||
o(root.firstChild.nodeName).equals("DIV")
|
o(root.firstChild.nodeName).equals("DIV")
|
||||||
})
|
})
|
||||||
|
|
@ -92,11 +92,11 @@ o.spec("api", function() {
|
||||||
m.route(root, "/a", {
|
m.route(root, "/a", {
|
||||||
"/a": {view: function() {return m("div")}}
|
"/a": {view: function() {return m("div")}}
|
||||||
})
|
})
|
||||||
|
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
o(root.childNodes.length).equals(1)
|
o(root.childNodes.length).equals(1)
|
||||||
o(root.firstChild.nodeName).equals("DIV")
|
o(root.firstChild.nodeName).equals("DIV")
|
||||||
|
|
||||||
done()
|
done()
|
||||||
}, FRAME_BUDGET)
|
}, FRAME_BUDGET)
|
||||||
})
|
})
|
||||||
|
|
@ -106,11 +106,11 @@ o.spec("api", function() {
|
||||||
m.route(root, "/a", {
|
m.route(root, "/a", {
|
||||||
"/a": {view: function() {return m("div")}}
|
"/a": {view: function() {return m("div")}}
|
||||||
})
|
})
|
||||||
|
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
o(root.childNodes.length).equals(1)
|
o(root.childNodes.length).equals(1)
|
||||||
o(root.firstChild.nodeName).equals("DIV")
|
o(root.firstChild.nodeName).equals("DIV")
|
||||||
|
|
||||||
done()
|
done()
|
||||||
}, FRAME_BUDGET)
|
}, FRAME_BUDGET)
|
||||||
})
|
})
|
||||||
|
|
@ -119,10 +119,10 @@ o.spec("api", function() {
|
||||||
m.route(root, "/a", {
|
m.route(root, "/a", {
|
||||||
"/a": {view: function() {return m("div")}}
|
"/a": {view: function() {return m("div")}}
|
||||||
})
|
})
|
||||||
|
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
o(m.route.get()).equals("/a")
|
o(m.route.get()).equals("/a")
|
||||||
|
|
||||||
done()
|
done()
|
||||||
}, FRAME_BUDGET)
|
}, FRAME_BUDGET)
|
||||||
})
|
})
|
||||||
|
|
@ -132,12 +132,12 @@ o.spec("api", function() {
|
||||||
m.route(root, "/a", {
|
m.route(root, "/a", {
|
||||||
"/:id": {view: function() {return m("div")}}
|
"/:id": {view: function() {return m("div")}}
|
||||||
})
|
})
|
||||||
|
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
m.route.set("/b")
|
m.route.set("/b")
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
o(m.route.get()).equals("/b")
|
o(m.route.get()).equals("/b")
|
||||||
|
|
||||||
done()
|
done()
|
||||||
}, FRAME_BUDGET)
|
}, FRAME_BUDGET)
|
||||||
}, FRAME_BUDGET)
|
}, FRAME_BUDGET)
|
||||||
|
|
@ -150,9 +150,9 @@ o.spec("api", function() {
|
||||||
m.mount(root, {view: function() {count++}})
|
m.mount(root, {view: function() {count++}})
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
m.redraw()
|
m.redraw()
|
||||||
|
|
||||||
o(count).equals(2)
|
o(count).equals(2)
|
||||||
|
|
||||||
done()
|
done()
|
||||||
}, FRAME_BUDGET)
|
}, FRAME_BUDGET)
|
||||||
})
|
})
|
||||||
|
|
@ -167,4 +167,4 @@ o.spec("api", function() {
|
||||||
o(typeof m.jsonp).equals("function") // TODO improve
|
o(typeof m.jsonp).equals("function") // TODO improve
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue