Merge branch 'rewrite' into array-isArray
This commit is contained in:
commit
fbb454c6fd
45 changed files with 1132 additions and 449 deletions
177
render/render.js
177
render/render.js
|
|
@ -97,7 +97,9 @@ module.exports = function($window) {
|
|||
function createComponent(vnode, hooks, ns) {
|
||||
// For object literals since `Vnode()` always sets the `state` field.
|
||||
if (!vnode.state) vnode.state = {}
|
||||
assign(vnode.state, vnode.tag)
|
||||
var constructor = function() {}
|
||||
constructor.prototype = vnode.tag
|
||||
vnode.state = new constructor
|
||||
|
||||
var view = vnode.tag.view
|
||||
if (view.reentrantLock != null) return $emptyFragment
|
||||
|
|
@ -124,84 +126,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) {
|
||||
|
|
@ -367,24 +370,21 @@ module.exports = function($window) {
|
|||
}
|
||||
}
|
||||
}
|
||||
function once(f) {
|
||||
var called = false
|
||||
return function() {
|
||||
if (!called) {
|
||||
called = true
|
||||
f()
|
||||
}
|
||||
}
|
||||
}
|
||||
function removeNode(vnode, context) {
|
||||
var expected = 1, called = 0
|
||||
if (vnode.attrs && vnode.attrs.onbeforeremove) {
|
||||
expected++
|
||||
vnode.attrs.onbeforeremove.call(vnode.state, vnode, once(continuation))
|
||||
var result = vnode.attrs.onbeforeremove.call(vnode.state, vnode)
|
||||
if (result != null && typeof result.then === "function") {
|
||||
expected++
|
||||
result.then(continuation, continuation)
|
||||
}
|
||||
}
|
||||
if (typeof vnode.tag !== "string" && vnode.tag.onbeforeremove) {
|
||||
expected++
|
||||
vnode.tag.onbeforeremove.call(vnode.state, vnode, once(continuation))
|
||||
var result = vnode.tag.onbeforeremove.call(vnode.state, vnode)
|
||||
if (result != null && typeof result.then === "function") {
|
||||
expected++
|
||||
result.then(continuation, continuation)
|
||||
}
|
||||
}
|
||||
continuation()
|
||||
function continuation() {
|
||||
|
|
@ -434,14 +434,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 +490,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)
|
||||
}
|
||||
|
|
@ -555,10 +558,6 @@ module.exports = function($window) {
|
|||
return false
|
||||
}
|
||||
|
||||
function assign(target, source) {
|
||||
Object.keys(source).forEach(function(k){target[k] = source[k]})
|
||||
}
|
||||
|
||||
function render(dom, vnodes) {
|
||||
if (!dom) throw new Error("Ensure the DOM element being passed to m.route/m.mount/m.render is not undefined.")
|
||||
var hooks = []
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
<script src="../../render/fragment.js"></script>
|
||||
<script src="../../render/hyperscript.js"></script>
|
||||
<script src="../../render/render.js"></script>
|
||||
<script src="../../promise/promise.js"></script>
|
||||
<script src="test-hyperscript.js"></script>
|
||||
<script src="test-trust.js"></script>
|
||||
<script src="test-fragment.js"></script>
|
||||
|
|
|
|||
|
|
@ -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}}
|
||||
|
|
|
|||
|
|
@ -588,14 +588,12 @@ o.spec("component", function() {
|
|||
o("calls onbeforeremove", function() {
|
||||
var called = 0
|
||||
var component = {
|
||||
onbeforeremove: function(vnode, done) {
|
||||
onbeforeremove: function(vnode) {
|
||||
called++
|
||||
|
||||
o(vnode.dom).notEquals(undefined)
|
||||
o(vnode.dom).equals(root.firstChild)
|
||||
o(root.childNodes.length).equals(1)
|
||||
|
||||
done()
|
||||
},
|
||||
view: function() {
|
||||
return {tag: "div", attrs: {id: "a"}, text: "b"}
|
||||
|
|
@ -614,14 +612,12 @@ o.spec("component", function() {
|
|||
o("calls onbeforeremove when returning fragment", function() {
|
||||
var called = 0
|
||||
var component = {
|
||||
onbeforeremove: function(vnode, done) {
|
||||
onbeforeremove: function(vnode) {
|
||||
called++
|
||||
|
||||
o(vnode.dom).notEquals(undefined)
|
||||
o(vnode.dom).equals(root.firstChild)
|
||||
o(root.childNodes.length).equals(1)
|
||||
|
||||
done()
|
||||
},
|
||||
view: function() {
|
||||
return [{tag: "div", attrs: {id: "a"}, text: "b"}]
|
||||
|
|
@ -672,6 +668,10 @@ o.spec("component", function() {
|
|||
function init(vnode) {
|
||||
o(vnode.state.data).deepEquals(data)
|
||||
o(vnode.state.data).equals(data)
|
||||
|
||||
//inherits state via prototype
|
||||
component.x = 1
|
||||
o(vnode.state.x).equals(1)
|
||||
}
|
||||
})
|
||||
o("state copy is shallow", function() {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ var o = require("../../ospec/ospec")
|
|||
var callAsync = require("../../test-utils/callAsync")
|
||||
var domMock = require("../../test-utils/domMock")
|
||||
var vdom = require("../../render/render")
|
||||
var Promise = require("../../promise/promise")
|
||||
|
||||
o.spec("onbeforeremove", function() {
|
||||
var $window, root, render
|
||||
|
|
@ -43,17 +44,13 @@ o.spec("onbeforeremove", function() {
|
|||
render(root, [vnode])
|
||||
render(root, [])
|
||||
|
||||
function remove(node, complete) {
|
||||
function remove(node) {
|
||||
o(node).equals(vnode)
|
||||
o(this).equals(vnode.state)
|
||||
o(root.childNodes.length).equals(1)
|
||||
o(root.firstChild).equals(vnode.dom)
|
||||
|
||||
callAsync(function() {
|
||||
o(root.childNodes.length).equals(1)
|
||||
|
||||
complete()
|
||||
|
||||
o(root.childNodes.length).equals(0)
|
||||
|
||||
done()
|
||||
|
|
@ -66,16 +63,12 @@ o.spec("onbeforeremove", function() {
|
|||
render(root, [vnode])
|
||||
render(root, [])
|
||||
|
||||
function remove(node, complete) {
|
||||
function remove(node) {
|
||||
o(node).equals(vnode)
|
||||
o(root.childNodes.length).equals(1)
|
||||
o(root.firstChild).equals(vnode.dom)
|
||||
|
||||
callAsync(function() {
|
||||
o(root.childNodes.length).equals(1)
|
||||
|
||||
complete()
|
||||
|
||||
o(root.childNodes.length).equals(0)
|
||||
|
||||
done()
|
||||
|
|
@ -88,16 +81,12 @@ o.spec("onbeforeremove", function() {
|
|||
render(root, [vnode])
|
||||
render(root, [])
|
||||
|
||||
function remove(node, complete) {
|
||||
function remove(node) {
|
||||
o(node).equals(vnode)
|
||||
o(root.childNodes.length).equals(1)
|
||||
o(root.firstChild).equals(vnode.dom)
|
||||
|
||||
callAsync(function() {
|
||||
o(root.childNodes.length).equals(1)
|
||||
|
||||
complete()
|
||||
|
||||
o(root.childNodes.length).equals(0)
|
||||
|
||||
done()
|
||||
|
|
@ -110,16 +99,12 @@ o.spec("onbeforeremove", function() {
|
|||
render(root, [vnode])
|
||||
render(root, [])
|
||||
|
||||
function remove(node, complete) {
|
||||
function remove(node) {
|
||||
o(node).equals(vnode)
|
||||
o(root.childNodes.length).equals(1)
|
||||
o(root.firstChild).equals(vnode.dom)
|
||||
|
||||
callAsync(function() {
|
||||
o(root.childNodes.length).equals(1)
|
||||
|
||||
complete()
|
||||
|
||||
o(root.childNodes.length).equals(0)
|
||||
|
||||
done()
|
||||
|
|
@ -133,17 +118,12 @@ o.spec("onbeforeremove", function() {
|
|||
render(root, [vnode])
|
||||
render(root, [])
|
||||
|
||||
function remove(node, complete) {
|
||||
function remove(node) {
|
||||
o(node).equals(vnode)
|
||||
o(root.childNodes.length).equals(1)
|
||||
o(root.firstChild).equals(vnode.dom)
|
||||
|
||||
callAsync(function() {
|
||||
o(root.childNodes.length).equals(1)
|
||||
o(spy.callCount).equals(0)
|
||||
|
||||
complete()
|
||||
|
||||
o(root.childNodes.length).equals(0)
|
||||
o(spy.callCount).equals(1)
|
||||
|
||||
|
|
@ -161,7 +141,7 @@ o.spec("onbeforeremove", function() {
|
|||
o(vnode.dom.attributes["onbeforeremove"]).equals(undefined)
|
||||
})
|
||||
o("does not recycle when there's an onbeforeremove", function() {
|
||||
var remove = function(vnode, done) {done()}
|
||||
var remove = function(vnode) {}
|
||||
var vnode = {tag: "div", key: 1, attrs: {onbeforeremove: remove}}
|
||||
var updated = {tag: "div", key: 1, attrs: {onbeforeremove: remove}}
|
||||
|
||||
|
|
@ -171,26 +151,27 @@ o.spec("onbeforeremove", function() {
|
|||
|
||||
o(vnode.dom).notEquals(updated.dom)
|
||||
})
|
||||
o("does not leave elements out of order during removal", function() {
|
||||
var finish
|
||||
var remove = function(vnode, done) {finish = done}
|
||||
o("does not leave elements out of order during removal", function(done) {
|
||||
var remove = function(vnode) {return Promise.resolve()}
|
||||
var vnodes = [{tag: "div", key: 1, attrs: {onbeforeremove: remove}, text: "1"}, {tag: "div", key: 2, attrs: {onbeforeremove: remove}, text: "2"}]
|
||||
var updated = {tag: "div", key: 2, attrs: {onbeforeremove: remove}, text: "2"}
|
||||
|
||||
render(root, vnodes)
|
||||
render(root, updated)
|
||||
|
||||
|
||||
o(root.childNodes.length).equals(2)
|
||||
o(root.firstChild.firstChild.nodeValue).equals("1")
|
||||
|
||||
finish()
|
||||
|
||||
o(root.childNodes.length).equals(1)
|
||||
o(root.firstChild.firstChild.nodeValue).equals("2")
|
||||
|
||||
callAsync(function() {
|
||||
o(root.childNodes.length).equals(1)
|
||||
o(root.firstChild.firstChild.nodeValue).equals("2")
|
||||
|
||||
done()
|
||||
})
|
||||
})
|
||||
o("finalizes the remove phase only once when `done()` is called synchronously from both attrs- and tag.onbeforeremove", function() {
|
||||
o("finalizes the remove phase asynchronously when promise is returned synchronously from both attrs- and tag.onbeforeremove", function(done) {
|
||||
var onremove = o.spy()
|
||||
var onbeforeremove = function(vnode, done){done()}
|
||||
var onbeforeremove = function(){return Promise.resolve()}
|
||||
var component = {
|
||||
onbeforeremove: onbeforeremove,
|
||||
onremove: onremove,
|
||||
|
|
@ -198,30 +179,30 @@ o.spec("onbeforeremove", function() {
|
|||
}
|
||||
render(root, [{tag: component, attrs: {onbeforeremove: onbeforeremove, onremove: onremove}}])
|
||||
render(root, [])
|
||||
o(onremove.callCount).equals(2) // once for `tag`, once for `attrs`
|
||||
callAsync(function() {
|
||||
o(onremove.callCount).equals(2) // once for `tag`, once for `attrs`
|
||||
done()
|
||||
})
|
||||
})
|
||||
o("doesn't finalize prematurely if `done` is called twice in the `tag` hook", function(done) {
|
||||
var async = false
|
||||
o("awaits promise resolution before removing the node", function(done) {
|
||||
var view = o.spy()
|
||||
var onremove = o.spy()
|
||||
var onbeforeremove = function(){return new Promise(function(resolve){callAsync(resolve)})}
|
||||
var component = {
|
||||
view: function() {},
|
||||
onbeforeremove: function(vnode, doneRemoving){
|
||||
doneRemoving()
|
||||
doneRemoving()
|
||||
},
|
||||
onremove: function() {
|
||||
o(async).equals(true)
|
||||
done()
|
||||
},
|
||||
onbeforeremove: onbeforeremove,
|
||||
onremove: onremove,
|
||||
view: view,
|
||||
}
|
||||
render(root, [{
|
||||
tag:component,
|
||||
attrs: {
|
||||
onbeforeremove: function(vnode, doneRemoving){
|
||||
callAsync(doneRemoving)
|
||||
}
|
||||
}
|
||||
}])
|
||||
render(root, [{tag: component}])
|
||||
render(root, [])
|
||||
async = true
|
||||
|
||||
callAsync(function(){
|
||||
o(onremove.callCount).equals(0)
|
||||
|
||||
callAsync(function() {
|
||||
o(onremove.callCount).equals(1)
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
})
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue