diff --git a/examples/hero/build.js b/examples/hero/build.js index 828787b..dd39375 100644 --- a/examples/hero/build.js +++ b/examples/hero/build.js @@ -62,7 +62,7 @@ var view = function view(data) { window.addEventListener('DOMContentLoaded', function () { var container = document.getElementById('container'); - vnode = patch(snabbdom.emptyNodeAt(container), view(data)); + vnode = patch(container, view(data)); render(); }); @@ -340,8 +340,6 @@ function emptyNodeAt(elm) { var emptyNode = VNode('', {}, [], undefined, undefined); -var frag = document.createDocumentFragment(); - var insertedVnodeQueue; function sameVnode(vnode1, vnode2) { @@ -365,26 +363,24 @@ function createRmCb(parentElm, childElm, listeners) { }; } +var hooks = ['create', 'update', 'remove', 'destroy', 'pre', 'post']; + function init(modules) { - var createCbs = []; - var updateCbs = []; - var removeCbs = []; - var destroyCbs = []; - var preCbs = []; - var postCbs = []; - - modules.forEach(function (module) { - if (module.create) createCbs.push(module.create); - if (module.update) updateCbs.push(module.update); - if (module.remove) removeCbs.push(module.remove); - if (module.destroy) destroyCbs.push(module.destroy); - if (module.pre) preCbs.push(module.pre); - if (module.post) postCbs.push(module.post); + var cbs = {}; + hooks.forEach(function (hook) { + cbs[hook] = []; + modules.forEach(function (module) { + if (module[hook] !== undefined) cbs[hook].push(module[hook]); + }); }); function createElm(vnode) { - var i, - elm, + var i; + if (!isUndef(i = vnode.data) && !isUndef(i = i.hook) && !isUndef(i = i.init)) { + i(vnode); + } + if (!isUndef(i = vnode.data) && !isUndef(i = i.vnode)) vnode = i; + var elm, children = vnode.children, sel = vnode.sel; if (!isUndef(sel)) { @@ -404,7 +400,7 @@ function init(modules) { } else if (is.primitive(vnode.text)) { elm.appendChild(document.createTextNode(vnode.text)); } - for (i = 0; i < createCbs.length; ++i) createCbs[i](emptyNode, vnode); + for (i = 0; i < cbs.create.length; ++i) cbs.create[i](emptyNode, vnode); i = vnode.data.hook; // Reuse variable if (!isUndef(i)) { if (i.create) i.create(vnode); @@ -430,8 +426,10 @@ function init(modules) { } function invokeDestroyHook(vnode) { - var i, j; - for (i = 0; i < destroyCbs.length; ++i) destroyCbs[i](vnode); + var i = vnode.data.hook, + j; + if (!isUndef(i) && !isUndef(j = i.destroy)) j(vnode); + for (i = 0; i < cbs.destroy.length; ++i) cbs.destroy[i](vnode); if (!isUndef(vnode.children)) { for (j = 0; j < vnode.children.length; ++j) { invokeDestroyHook(vnode.children[j]); @@ -446,9 +444,9 @@ function init(modules) { rm, ch = vnodes[startIdx]; if (!isUndef(ch)) { - listeners = removeCbs.length + 1; + listeners = cbs.remove.length + 1; rm = createRmCb(parentElm, ch.elm, listeners); - for (i = 0; i < removeCbs.length; ++i) removeCbs[i](ch, rm); + for (i = 0; i < cbs.remove.length; ++i) cbs.remove[i](ch, rm); invokeDestroyHook(ch); if (ch.data.hook && ch.data.hook.remove) { ch.data.hook.remove(ch, rm); @@ -515,16 +513,24 @@ function init(modules) { } function patchVnode(oldVnode, vnode) { - var i, - elm = vnode.elm = oldVnode.elm, + var i; + if (!isUndef(i = vnode.data) && !isUndef(i = i.hook) && !isUndef(i = i.patch)) { + i = i(oldVnode, vnode); + } + if (!isUndef(i = oldVnode.data) && !isUndef(i = i.vnode)) oldVnode = i; + if (!isUndef(i = vnode.data) && !isUndef(i = i.vnode)) vnode = i; + var elm = vnode.elm = oldVnode.elm, oldCh = oldVnode.children, ch = vnode.children; + if (oldVnode === vnode) return; if (!isUndef(vnode.data)) { - for (i = 0; i < updateCbs.length; ++i) updateCbs[i](oldVnode, vnode); + for (i = 0; i < cbs.update.length; ++i) cbs.update[i](oldVnode, vnode); + i = vnode.data.hook; + if (!isUndef(i) && !isUndef(i = i.update)) i(vnode); } if (isUndef(vnode.text)) { if (!isUndef(oldCh) && !isUndef(ch)) { - updateChildren(elm, oldCh, ch); + if (oldCh !== ch) updateChildren(elm, oldCh, ch); } else if (!isUndef(ch)) { addVnodes(elm, undefined, ch, 0, ch.length - 1); } else if (!isUndef(oldCh)) { @@ -539,18 +545,21 @@ function init(modules) { return function (oldVnode, vnode) { var i; insertedVnodeQueue = []; - for (i = 0; i < preCbs.length; ++i) preCbs[i](); + if (oldVnode instanceof Element) { + oldVnode = emptyNodeAt(oldVnode); + } + for (i = 0; i < cbs.pre.length; ++i) cbs.pre[i](); patchVnode(oldVnode, vnode); for (i = 0; i < insertedVnodeQueue.length; ++i) { insertedVnodeQueue[i].data.hook.insert(insertedVnodeQueue[i]); } insertedVnodeQueue = undefined; - for (i = 0; i < postCbs.length; ++i) postCbs[i](); + for (i = 0; i < cbs.post.length; ++i) cbs.post[i](); return vnode; }; } -module.exports = { init: init, emptyNodeAt: emptyNodeAt }; +module.exports = { init: init }; },{"./is":3,"./vnode":9}],9:[function(require,module,exports){ "use strict"; diff --git a/examples/hero/script.js b/examples/hero/script.js index 2732fc8..61579c3 100644 --- a/examples/hero/script.js +++ b/examples/hero/script.js @@ -112,6 +112,6 @@ const view = (data) => window.addEventListener('DOMContentLoaded', () => { var container = document.getElementById('container'); - vnode = patch(snabbdom.emptyNodeAt(container), view(data)); + vnode = patch(container, view(data)); render(); }); diff --git a/examples/reorder-animation/build.js b/examples/reorder-animation/build.js index a143f13..891ea19 100644 --- a/examples/reorder-animation/build.js +++ b/examples/reorder-animation/build.js @@ -69,7 +69,7 @@ function view(data) { window.addEventListener('DOMContentLoaded', function () { var container = document.getElementById('container'); - vnode = patch(snabbdom.emptyNodeAt(container), view(data)); + vnode = patch(container, view(data)); render(); }); @@ -284,8 +284,6 @@ function emptyNodeAt(elm) { var emptyNode = VNode('', {}, [], undefined, undefined); -var frag = document.createDocumentFragment(); - var insertedVnodeQueue; function sameVnode(vnode1, vnode2) { @@ -309,26 +307,24 @@ function createRmCb(parentElm, childElm, listeners) { }; } +var hooks = ['create', 'update', 'remove', 'destroy', 'pre', 'post']; + function init(modules) { - var createCbs = []; - var updateCbs = []; - var removeCbs = []; - var destroyCbs = []; - var preCbs = []; - var postCbs = []; - - modules.forEach(function (module) { - if (module.create) createCbs.push(module.create); - if (module.update) updateCbs.push(module.update); - if (module.remove) removeCbs.push(module.remove); - if (module.destroy) destroyCbs.push(module.destroy); - if (module.pre) preCbs.push(module.pre); - if (module.post) postCbs.push(module.post); + var cbs = {}; + hooks.forEach(function (hook) { + cbs[hook] = []; + modules.forEach(function (module) { + if (module[hook] !== undefined) cbs[hook].push(module[hook]); + }); }); function createElm(vnode) { - var i, - elm, + var i; + if (!isUndef(i = vnode.data) && !isUndef(i = i.hook) && !isUndef(i = i.init)) { + i(vnode); + } + if (!isUndef(i = vnode.data) && !isUndef(i = i.vnode)) vnode = i; + var elm, children = vnode.children, sel = vnode.sel; if (!isUndef(sel)) { @@ -348,7 +344,7 @@ function init(modules) { } else if (is.primitive(vnode.text)) { elm.appendChild(document.createTextNode(vnode.text)); } - for (i = 0; i < createCbs.length; ++i) createCbs[i](emptyNode, vnode); + for (i = 0; i < cbs.create.length; ++i) cbs.create[i](emptyNode, vnode); i = vnode.data.hook; // Reuse variable if (!isUndef(i)) { if (i.create) i.create(vnode); @@ -374,8 +370,10 @@ function init(modules) { } function invokeDestroyHook(vnode) { - var i, j; - for (i = 0; i < destroyCbs.length; ++i) destroyCbs[i](vnode); + var i = vnode.data.hook, + j; + if (!isUndef(i) && !isUndef(j = i.destroy)) j(vnode); + for (i = 0; i < cbs.destroy.length; ++i) cbs.destroy[i](vnode); if (!isUndef(vnode.children)) { for (j = 0; j < vnode.children.length; ++j) { invokeDestroyHook(vnode.children[j]); @@ -390,9 +388,9 @@ function init(modules) { rm, ch = vnodes[startIdx]; if (!isUndef(ch)) { - listeners = removeCbs.length + 1; + listeners = cbs.remove.length + 1; rm = createRmCb(parentElm, ch.elm, listeners); - for (i = 0; i < removeCbs.length; ++i) removeCbs[i](ch, rm); + for (i = 0; i < cbs.remove.length; ++i) cbs.remove[i](ch, rm); invokeDestroyHook(ch); if (ch.data.hook && ch.data.hook.remove) { ch.data.hook.remove(ch, rm); @@ -459,16 +457,24 @@ function init(modules) { } function patchVnode(oldVnode, vnode) { - var i, - elm = vnode.elm = oldVnode.elm, + var i; + if (!isUndef(i = vnode.data) && !isUndef(i = i.hook) && !isUndef(i = i.patch)) { + i = i(oldVnode, vnode); + } + if (!isUndef(i = oldVnode.data) && !isUndef(i = i.vnode)) oldVnode = i; + if (!isUndef(i = vnode.data) && !isUndef(i = i.vnode)) vnode = i; + var elm = vnode.elm = oldVnode.elm, oldCh = oldVnode.children, ch = vnode.children; + if (oldVnode === vnode) return; if (!isUndef(vnode.data)) { - for (i = 0; i < updateCbs.length; ++i) updateCbs[i](oldVnode, vnode); + for (i = 0; i < cbs.update.length; ++i) cbs.update[i](oldVnode, vnode); + i = vnode.data.hook; + if (!isUndef(i) && !isUndef(i = i.update)) i(vnode); } if (isUndef(vnode.text)) { if (!isUndef(oldCh) && !isUndef(ch)) { - updateChildren(elm, oldCh, ch); + if (oldCh !== ch) updateChildren(elm, oldCh, ch); } else if (!isUndef(ch)) { addVnodes(elm, undefined, ch, 0, ch.length - 1); } else if (!isUndef(oldCh)) { @@ -483,18 +489,21 @@ function init(modules) { return function (oldVnode, vnode) { var i; insertedVnodeQueue = []; - for (i = 0; i < preCbs.length; ++i) preCbs[i](); + if (oldVnode instanceof Element) { + oldVnode = emptyNodeAt(oldVnode); + } + for (i = 0; i < cbs.pre.length; ++i) cbs.pre[i](); patchVnode(oldVnode, vnode); for (i = 0; i < insertedVnodeQueue.length; ++i) { insertedVnodeQueue[i].data.hook.insert(insertedVnodeQueue[i]); } insertedVnodeQueue = undefined; - for (i = 0; i < postCbs.length; ++i) postCbs[i](); + for (i = 0; i < cbs.post.length; ++i) cbs.post[i](); return vnode; }; } -module.exports = { init: init, emptyNodeAt: emptyNodeAt }; +module.exports = { init: init }; },{"./is":3,"./vnode":9}],9:[function(require,module,exports){ "use strict"; diff --git a/examples/reorder-animation/script.js b/examples/reorder-animation/script.js index db061ac..a935b5f 100644 --- a/examples/reorder-animation/script.js +++ b/examples/reorder-animation/script.js @@ -107,6 +107,6 @@ function view(data) { window.addEventListener('DOMContentLoaded', () => { var container = document.getElementById('container'); - vnode = patch(snabbdom.emptyNodeAt(container), view(data)); + vnode = patch(container, view(data)); render(); }); diff --git a/snabbdom.js b/snabbdom.js index 3462c9b..e03a27b 100644 --- a/snabbdom.js +++ b/snabbdom.js @@ -204,6 +204,9 @@ function init(modules) { return function(oldVnode, vnode) { var i; insertedVnodeQueue = []; + if (oldVnode instanceof Element) { + oldVnode = emptyNodeAt(oldVnode); + } for (i = 0; i < cbs.pre.length; ++i) cbs.pre[i](); patchVnode(oldVnode, vnode); for (i = 0; i < insertedVnodeQueue.length; ++i) { @@ -215,4 +218,4 @@ function init(modules) { }; } -module.exports = {init: init, emptyNodeAt: emptyNodeAt}; +module.exports = {init: init}; diff --git a/test/core.js b/test/core.js index c26da93..c9a865f 100644 --- a/test/core.js +++ b/test/core.js @@ -29,7 +29,7 @@ describe('snabbdom', function() { var elm, vnode0; beforeEach(function() { elm = document.createElement('div'); - vnode0 = snabbdom.emptyNodeAt(elm); + vnode0 = elm; }); describe('hyperscript', function() { it('can create vnode with proper tag', function() { @@ -54,9 +54,6 @@ describe('snabbdom', function() { var vnode = h('a', {}, 'I am a string'); assert.equal(vnode.text, 'I am a string'); }); - it('can create empty vnode at element', function() { - assert.equal(vnode0.elm, elm); - }); }); describe('created element', function() { it('has tag', function() { @@ -314,7 +311,7 @@ describe('snabbdom', function() { })); var shufArr = shuffle(arr.slice(0)); var elm = document.createElement('div'); - patch(snabbdom.emptyNodeAt(elm), vnode1); + patch(elm, vnode1); for (i = 0; i < elms; ++i) { assert.equal(elm.children[i].innerHTML, i.toString()); opacities[i] = Math.random().toFixed(5).toString(); diff --git a/test/style.js b/test/style.js index c6a3c2c..e3af482 100644 --- a/test/style.js +++ b/test/style.js @@ -10,7 +10,7 @@ describe('style', function() { var elm, vnode0; beforeEach(function() { elm = document.createElement('div'); - vnode0 = snabbdom.emptyNodeAt(elm); + vnode0 = elm; }); it('is being styled', function() { patch(vnode0, h('div', {style: {fontSize: '12px'}})); diff --git a/test/thunk.js b/test/thunk.js index 1d3962a..ade371d 100644 --- a/test/thunk.js +++ b/test/thunk.js @@ -10,7 +10,7 @@ describe('thunk', function() { var elm, vnode0; beforeEach(function() { elm = document.createElement('div'); - vnode0 = snabbdom.emptyNodeAt(elm); + vnode0 = elm; }); it('returns vnode with data and render function', function() { function numberInSpan(n) {