Merge pull request #1244 from pygy/robust-onbeforeremove

Robust onbeforeremove
This commit is contained in:
Leo Horie 2016-08-17 23:54:36 -04:00 committed by GitHub
commit 3761226c2c
3 changed files with 78 additions and 30 deletions

View file

@ -203,7 +203,7 @@ module.exports = function($window) {
else updateComponent(parent, old, vnode, hooks, nextSibling, recycling, ns) else updateComponent(parent, old, vnode, hooks, nextSibling, recycling, ns)
} }
else { else {
removeNode(parent, old, null, false) removeNode(parent, old, null)
insertNode(parent, createNode(vnode, hooks, undefined), nextSibling) insertNode(parent, createNode(vnode, hooks, undefined), nextSibling)
} }
} }
@ -265,7 +265,7 @@ module.exports = function($window) {
vnode.domSize = vnode.instance.domSize vnode.domSize = vnode.instance.domSize
} }
else if (old.instance != null) { else if (old.instance != null) {
removeNode(parent, old.instance, null, false) removeNode(parent, old.instance, null)
vnode.dom = undefined vnode.dom = undefined
vnode.domSize = 0 vnode.domSize = 0
} }
@ -327,27 +327,32 @@ module.exports = function($window) {
var vnode = vnodes[i] var vnode = vnodes[i]
if (vnode != null) { if (vnode != null) {
if (vnode.skip) vnode.skip = false if (vnode.skip) vnode.skip = false
else removeNode(parent, vnode, context, false) else removeNode(parent, vnode, context)
} }
} }
} }
function removeNode(parent, vnode, context, deferred) { function once(f) {
if (deferred === false) { var called = false
var expected = 0, called = 0 return function() {
var callback = function() { if (!called) {
if (++called === expected) removeNode(parent, vnode, context, true) called = true
f()
} }
}
}
function removeNode(parent, vnode, context) {
var expected = 1, called = 0
if (vnode.attrs && vnode.attrs.onbeforeremove) { if (vnode.attrs && vnode.attrs.onbeforeremove) {
expected++ expected++
vnode.attrs.onbeforeremove.call(vnode.state, vnode, callback) vnode.attrs.onbeforeremove.call(vnode.state, vnode, once(continuation))
} }
if (typeof vnode.tag !== "string" && vnode.tag.onbeforeremove) { if (typeof vnode.tag !== "string" && vnode.tag.onbeforeremove) {
expected++ expected++
vnode.tag.onbeforeremove.call(vnode.state, vnode, callback) vnode.tag.onbeforeremove.call(vnode.state, vnode, once(continuation))
} }
if (expected > 0) return continuation()
} function continuation() {
if (++called === expected) {
onremove(vnode) onremove(vnode)
if (vnode.dom) { if (vnode.dom) {
var count = vnode.domSize || 1 var count = vnode.domSize || 1
@ -364,6 +369,8 @@ module.exports = function($window) {
} }
} }
} }
}
}
function onremove(vnode) { function onremove(vnode) {
if (vnode.attrs && vnode.attrs.onremove) vnode.attrs.onremove.call(vnode.state, vnode) if (vnode.attrs && vnode.attrs.onremove) vnode.attrs.onremove.call(vnode.state, vnode)
if (typeof vnode.tag !== "string" && vnode.tag.onremove) vnode.tag.onremove.call(vnode.state, vnode) if (typeof vnode.tag !== "string" && vnode.tag.onremove) vnode.tag.onremove.call(vnode.state, vnode)

View file

@ -188,4 +188,34 @@ o.spec("onbeforeremove", function() {
o(root.childNodes.length).equals(1) o(root.childNodes.length).equals(1)
o(root.firstChild.firstChild.nodeValue).equals("2") o(root.firstChild.firstChild.nodeValue).equals("2")
}) })
o("finalizes the remove phase only once when `done()` is called synchronously from both attrs- and tag.onbeforeremove", function() {
var onremove = o.spy()
var component = {
view: function(){return {tag:'br'}},
onbeforeremove: function(vnode, done){done()},
onremove: onremove
}
render(root, [{tag: component, attrs: component}])
render(root, [])
o(onremove.callCount).equals(2) // once for `tag`, once for `attrs`
})
o("doesn't finalize prematurely if `done` is called twice in the `tag` hook", function(done) {
var async = false
var component = {
view: function(){return {tag:'br'}},
onbeforeremove: function(vnode, doneRemoving){
doneRemoving()
doneRemoving()
},
onremove: function(){
o(async).equals(true)("onremove should be called asynchronously")
done()
}
}
render(root, [{tag:component, attrs: {onbeforeremove: function(vnode, doneRemoving){
callAsync(doneRemoving)
}}}])
render(root, [])
async = true
})
}) })

View file

@ -145,4 +145,15 @@ o.spec("onremove", function() {
o(vnode.dom).notEquals(updated.dom) o(vnode.dom).notEquals(updated.dom)
}) })
o("The remove phase is finalized only once when `done()` is called synchronously from both attrs- and tag.onbeforeremove", function () {
var onremove = o.spy()
var component = {
view: function(){return m('br')},
onbeforeremove: function(vnode, done){done()},
onremove: onremove
}
render(root, [{tag: component, attrs: component}])
render(root, [])
o(onremove.callCount).equals(2)
})
}) })