Merge branch 'master' of https://github.com/kay999/snabbdom into replace-root

pull/75/head
paldepind 9 years ago
commit ce14417216

2
.gitignore vendored

@ -28,3 +28,5 @@ node_modules
# Vim # Vim
*.swp *.swp
test/browserified.js

@ -8,8 +8,9 @@ var is = require('./is');
function isUndef(s) { return s === undefined; } function isUndef(s) { return s === undefined; }
function isDef(s) { return s !== undefined; } function isDef(s) { return s !== undefined; }
// deal with case sensivity better than that
function emptyNodeAt(elm) { function emptyNodeAt(elm) {
return VNode(elm.tagName, {}, [], undefined, elm); return VNode(elm.tagName.toLowerCase(), {}, [], undefined, elm);
} }
var emptyNode = VNode('', {}, [], undefined, undefined); var emptyNode = VNode('', {}, [], undefined, undefined);
@ -45,10 +46,13 @@ function init(modules) {
} }
function createElm(vnode, insertedVnodeQueue) { function createElm(vnode, insertedVnodeQueue) {
var i, data = vnode.data; var i, thunk, data = vnode.data;
if (isDef(data)) { if (isDef(data)) {
if (isDef(i = data.hook) && isDef(i = i.init)) i(vnode); if (isDef(i = data.hook) && isDef(i = i.init)) i(vnode);
if (isDef(i = data.vnode)) vnode = i; if (isDef(i = data.vnode)) {
thunk = vnode;
vnode = i;
}
} }
var elm, children = vnode.children, sel = vnode.sel; var elm, children = vnode.children, sel = vnode.sel;
if (isDef(sel)) { if (isDef(sel)) {
@ -78,6 +82,7 @@ function init(modules) {
} else { } else {
elm = vnode.elm = document.createTextNode(vnode.text); elm = vnode.elm = document.createTextNode(vnode.text);
} }
if (isDef(thunk)) thunk.elm = vnode.elm;
return vnode.elm; return vnode.elm;
} }
@ -88,15 +93,16 @@ function init(modules) {
} }
function invokeDestroyHook(vnode) { function invokeDestroyHook(vnode) {
var i = vnode.data, j; var i, j, data = vnode.data;
if (isDef(i)) { if (isDef(data)) {
if (isDef(i = i.hook) && isDef(i = i.destroy)) i(vnode); if (isDef(i = data.hook) && isDef(i = i.destroy)) i(vnode);
for (i = 0; i < cbs.destroy.length; ++i) cbs.destroy[i](vnode); for (i = 0; i < cbs.destroy.length; ++i) cbs.destroy[i](vnode);
if (isDef(i = vnode.children)) { if (isDef(i = vnode.children)) {
for (j = 0; j < vnode.children.length; ++j) { for (j = 0; j < vnode.children.length; ++j) {
invokeDestroyHook(vnode.children[j]); invokeDestroyHook(vnode.children[j]);
} }
} }
if (isDef(i = data.vnode)) invokeDestroyHook(i);
} }
} }
@ -183,9 +189,20 @@ function init(modules) {
i(oldVnode, vnode); i(oldVnode, vnode);
} }
if (isDef(i = oldVnode.data) && isDef(i = i.vnode)) oldVnode = i; if (isDef(i = oldVnode.data) && isDef(i = i.vnode)) oldVnode = i;
if (isDef(i = vnode.data) && isDef(i = i.vnode)) vnode = i; if (isDef(i = vnode.data) && isDef(i = i.vnode)) {
patchVnode(oldVnode, i, insertedVnodeQueue);
vnode.elm = i.elm;
return;
}
var elm = vnode.elm = oldVnode.elm, oldCh = oldVnode.children, ch = vnode.children; var elm = vnode.elm = oldVnode.elm, oldCh = oldVnode.children, ch = vnode.children;
if (oldVnode === vnode) return; if (oldVnode === vnode) return;
if (!sameVnode(oldVnode, vnode)) {
var parentElm = oldVnode.elm.parentElement;
elm = createElm(vnode, insertedVnodeQueue);
parentElm.insertBefore(elm, oldVnode.elm);
removeVnodes(parentElm, [oldVnode], 0, 0);
return;
}
if (isDef(vnode.data)) { if (isDef(vnode.data)) {
for (i = 0; i < cbs.update.length; ++i) cbs.update[i](oldVnode, vnode); for (i = 0; i < cbs.update.length; ++i) cbs.update[i](oldVnode, vnode);
i = vnode.data.hook; i = vnode.data.hook;
@ -210,21 +227,37 @@ function init(modules) {
} }
} }
var dummyParent = document.createElement('div');
return function(oldVnode, vnode) { return function(oldVnode, vnode) {
var i; var i, noParent;
var insertedVnodeQueue = []; var insertedVnodeQueue = [];
for (i = 0; i < cbs.pre.length; ++i) cbs.pre[i](); for (i = 0; i < cbs.pre.length; ++i) cbs.pre[i]();
if (oldVnode.nodeType === Node.ELEMENT_NODE) { if (oldVnode.nodeType === Node.ELEMENT_NODE) {
if (oldVnode.parentElement !== null) {
createElm(vnode, insertedVnodeQueue);
oldVnode.parentElement.replaceChild(vnode.elm, oldVnode);
} else {
oldVnode = emptyNodeAt(oldVnode); oldVnode = emptyNodeAt(oldVnode);
patchVnode(oldVnode, vnode, insertedVnodeQueue);
} }
} else {
var elm = oldVnode.elm;
var parent = elm.parentElement;
if (noParent = (parent === null)) {
dummyParent.appendChild(elm);
parent = dummyParent;
}
if (sameVnode(oldVnode, vnode)) {
patchVnode(oldVnode, vnode, insertedVnodeQueue); patchVnode(oldVnode, vnode, insertedVnodeQueue);
} else {
var next = elm.nextSibling;
createElm(vnode, insertedVnodeQueue);
if (next) parent.insertBefore(vnode.elm, next);
else parent.appendChild(vnode.elm);
removeVnodes(parent, [oldVnode], 0, 0);
} }
if (noParent) dummyParent.removeChild(vnode.elm);
for (i = 0; i < insertedVnodeQueue.length; ++i) { for (i = 0; i < insertedVnodeQueue.length; ++i) {
insertedVnodeQueue[i].data.hook.insert(insertedVnodeQueue[i]); insertedVnodeQueue[i].data.hook.insert(insertedVnodeQueue[i]);
} }

@ -12,12 +12,13 @@ describe('attachTo', function() {
vnode0 = elm; vnode0 = elm;
}); });
it('adds element to target', function() { it('adds element to target', function() {
patch(vnode0, h('div', [ var vnode1 = h('div', [
h('div#wrapper', [ h('div#wrapper', [
h('div', 'Some element'), h('div', 'Some element'),
attachTo(elm, h('div#attached', 'Test')), attachTo(elm, h('div#attached', 'Test')),
]), ]),
])); ]);
elm = patch(vnode0, vnode1).elm;
assert.equal(elm.children.length, 2); assert.equal(elm.children.length, 2);
}); });
it('updates element at target', function() { it('updates element at target', function() {
@ -33,9 +34,9 @@ describe('attachTo', function() {
attachTo(elm, h('div#attached', 'New text')), attachTo(elm, h('div#attached', 'New text')),
]), ]),
]); ]);
patch(vnode0, vnode1); elm = patch(vnode0, vnode1).elm;
assert.equal(elm.children[0].innerHTML, 'First text'); assert.equal(elm.children[0].innerHTML, 'First text');
patch(vnode1, vnode2); elm = patch(vnode1, vnode2).elm;
assert.equal(elm.children[0].innerHTML, 'New text'); assert.equal(elm.children[0].innerHTML, 'New text');
}); });
it('element can be inserted before modal', function() { it('element can be inserted before modal', function() {
@ -52,9 +53,9 @@ describe('attachTo', function() {
attachTo(elm, h('div#attached', 'Text')), attachTo(elm, h('div#attached', 'Text')),
]), ]),
]); ]);
patch(vnode0, vnode1); elm = patch(vnode0, vnode1).elm;
assert.equal(elm.children[0].innerHTML, 'Text'); assert.equal(elm.children[0].innerHTML, 'Text');
patch(vnode1, vnode2); elm = patch(vnode1, vnode2).elm;
assert.equal(elm.children[0].innerHTML, 'Text'); assert.equal(elm.children[0].innerHTML, 'Text');
}); });
it('removes element at target', function() { it('removes element at target', function() {
@ -69,16 +70,13 @@ describe('attachTo', function() {
h('div', 'Some element'), h('div', 'Some element'),
]), ]),
]); ]);
patch(vnode0, vnode1); elm = patch(vnode0, vnode1).elm;
assert.equal(elm.children[0].innerHTML, 'First text'); assert.equal(elm.children[0].innerHTML, 'First text');
patch(vnode1, vnode2); elm = patch(vnode1, vnode2).elm;
assert.equal(elm.children.length, 1); assert.equal(elm.children.length, 1);
}); });
it('remove hook recieves real element', function() { it('remove hook recieves real element', function() {
function rm(vnode, cb) { function rm(vnode, cb) {
console.log(vnode);
console.log(vnode.elm);
console.log(vnode.elm.parentElement);
assert.equal(vnode.elm.tagName, 'DIV'); assert.equal(vnode.elm.tagName, 'DIV');
assert.equal(vnode.elm.innerHTML, 'First text'); assert.equal(vnode.elm.innerHTML, 'First text');
cb(); cb();
@ -94,7 +92,7 @@ describe('attachTo', function() {
h('div', 'Some element'), h('div', 'Some element'),
]), ]),
]); ]);
patch(vnode0, vnode1); elm = patch(vnode0, vnode1).elm;
patch(vnode1, vnode2); elm = patch(vnode1, vnode2).elm;
}); });
}); });

@ -57,54 +57,54 @@ describe('snabbdom', function() {
}); });
describe('created element', function() { describe('created element', function() {
it('has tag', function() { it('has tag', function() {
patch(vnode0, h('div')); elm = patch(vnode0, h('div')).elm;
assert.equal(elm.tagName, 'DIV'); assert.equal(elm.tagName, 'DIV');
}); });
it('has different tag and id', function() { it('has different tag and id', function() {
var elm = document.createElement('div'); var elm = document.createElement('div');
vnode0.appendChild(elm); vnode0.appendChild(elm);
var vnode1 = h('span#id'); var vnode1 = h('span#id');
patch(elm, vnode1); elm = patch(elm, vnode1).elm;
assert.equal(vnode1.elm.tagName, 'SPAN'); assert.equal(elm.tagName, 'SPAN');
assert.equal(vnode1.elm.id, 'id'); assert.equal(elm.id, 'id');
}); });
it('has id', function() { it('has id', function() {
patch(vnode0, h('div', [h('div#unique')])); elm = patch(vnode0, h('div', [h('div#unique')])).elm;
assert.equal(elm.firstChild.id, 'unique'); assert.equal(elm.firstChild.id, 'unique');
}); });
it('has correct namespace', function() { it('has correct namespace', function() {
patch(vnode0, h('div', [h('div', {ns: 'http://www.w3.org/2000/svg'})])); elm = patch(vnode0, h('div', [h('div', {ns: 'http://www.w3.org/2000/svg'})])).elm;
assert.equal(elm.firstChild.namespaceURI, 'http://www.w3.org/2000/svg'); assert.equal(elm.firstChild.namespaceURI, 'http://www.w3.org/2000/svg');
}); });
it('is recieves classes in selector', function() { it('is recieves classes in selector', function() {
patch(vnode0, h('div', [h('i.am.a.class')])); elm = patch(vnode0, h('div', [h('i.am.a.class')])).elm;
assert(elm.firstChild.classList.contains('am')); assert(elm.firstChild.classList.contains('am'));
assert(elm.firstChild.classList.contains('a')); assert(elm.firstChild.classList.contains('a'));
assert(elm.firstChild.classList.contains('class')); assert(elm.firstChild.classList.contains('class'));
}); });
it('is recieves classes in class property', function() { it('is recieves classes in class property', function() {
patch(vnode0, h('i', {class: {am: true, a: true, class: true, not: false}})); elm = patch(vnode0, h('i', {class: {am: true, a: true, class: true, not: false}})).elm;
assert(elm.classList.contains('am')); assert(elm.classList.contains('am'));
assert(elm.classList.contains('a')); assert(elm.classList.contains('a'));
assert(elm.classList.contains('class')); assert(elm.classList.contains('class'));
assert(!elm.classList.contains('not')); assert(!elm.classList.contains('not'));
}); });
it('handles classes from both selector and property', function() { it('handles classes from both selector and property', function() {
patch(vnode0, h('div', [h('i.has', {class: {classes: true}})])); elm = patch(vnode0, h('div', [h('i.has', {class: {classes: true}})])).elm;
assert(elm.firstChild.classList.contains('has')); assert(elm.firstChild.classList.contains('has'));
assert(elm.firstChild.classList.contains('classes')); assert(elm.firstChild.classList.contains('classes'));
}); });
it('can create elements with text content', function() { it('can create elements with text content', function() {
patch(vnode0, h('div', ['I am a string'])); elm = patch(vnode0, h('div', ['I am a string'])).elm;
assert.equal(elm.innerHTML, 'I am a string'); assert.equal(elm.innerHTML, 'I am a string');
}); });
it('can create elements with span and text content', function() { it('can create elements with span and text content', function() {
patch(vnode0, h('a', [h('span'), 'I am a string'])); elm = patch(vnode0, h('a', [h('span'), 'I am a string'])).elm;
assert.equal(elm.childNodes[0].tagName, 'SPAN'); assert.equal(elm.childNodes[0].tagName, 'SPAN');
assert.equal(elm.childNodes[1].textContent, 'I am a string'); assert.equal(elm.childNodes[1].textContent, 'I am a string');
}); });
it('can create elements with props', function() { it('can create elements with props', function() {
patch(vnode0, h('a', {props: {src: 'http://localhost/'}})); elm = patch(vnode0, h('a', {props: {src: 'http://localhost/'}})).elm;
assert.equal(elm.src, 'http://localhost/'); assert.equal(elm.src, 'http://localhost/');
}); });
it('can create an element created inside an iframe', function(done) { it('can create an element created inside an iframe', function(done) {
@ -129,7 +129,7 @@ describe('snabbdom', function() {
var vnode1 = h('i', {class: {i: true, am: true, horse: true}}); var vnode1 = h('i', {class: {i: true, am: true, horse: true}});
var vnode2 = h('i', {class: {i: true, am: true, horse: false}}); var vnode2 = h('i', {class: {i: true, am: true, horse: false}});
patch(vnode0, vnode1); patch(vnode0, vnode1);
patch(vnode1, vnode2); elm = patch(vnode1, vnode2).elm;
assert(elm.classList.contains('i')); assert(elm.classList.contains('i'));
assert(elm.classList.contains('am')); assert(elm.classList.contains('am'));
assert(!elm.classList.contains('horse')); assert(!elm.classList.contains('horse'));
@ -138,7 +138,7 @@ describe('snabbdom', function() {
var vnode1 = h('i', {class: {i: true, am: true, horse: true}}); var vnode1 = h('i', {class: {i: true, am: true, horse: true}});
var vnode2 = h('i', {class: {i: true, am: true, horse: false}}); var vnode2 = h('i', {class: {i: true, am: true, horse: false}});
patch(vnode0, vnode1); patch(vnode0, vnode1);
patch(vnode1, vnode2); elm = patch(vnode1, vnode2).elm;
assert(elm.classList.contains('i')); assert(elm.classList.contains('i'));
assert(elm.classList.contains('am')); assert(elm.classList.contains('am'));
assert(!elm.classList.contains('horse')); assert(!elm.classList.contains('horse'));
@ -147,7 +147,7 @@ describe('snabbdom', function() {
var vnode1 = h('i', {class: {i: true, am: true, horse: true}}); var vnode1 = h('i', {class: {i: true, am: true, horse: true}});
var vnode2 = h('i', {class: {i: true, am: true}}); var vnode2 = h('i', {class: {i: true, am: true}});
patch(vnode0, vnode1); patch(vnode0, vnode1);
patch(vnode1, vnode2); elm = patch(vnode1, vnode2).elm;
assert(elm.classList.contains('i')); assert(elm.classList.contains('i'));
assert(elm.classList.contains('am')); assert(elm.classList.contains('am'));
assert(!elm.classList.contains('horse')); assert(!elm.classList.contains('horse'));
@ -156,7 +156,7 @@ describe('snabbdom', function() {
var vnode1 = h('a', {props: {src: 'http://other/'}}); var vnode1 = h('a', {props: {src: 'http://other/'}});
var vnode2 = h('a', {props: {src: 'http://localhost/'}}); var vnode2 = h('a', {props: {src: 'http://localhost/'}});
patch(vnode0, vnode1); patch(vnode0, vnode1);
patch(vnode1, vnode2); elm = patch(vnode1, vnode2).elm;
assert.equal(elm.src, 'http://localhost/'); assert.equal(elm.src, 'http://localhost/');
}); });
it('removes an elements props', function() { it('removes an elements props', function() {
@ -178,9 +178,9 @@ describe('snabbdom', function() {
it('appends elements', function() { it('appends elements', function() {
var vnode1 = h('span', [1].map(spanNum)); var vnode1 = h('span', [1].map(spanNum));
var vnode2 = h('span', [1, 2, 3].map(spanNum)); var vnode2 = h('span', [1, 2, 3].map(spanNum));
patch(vnode0, vnode1); elm = patch(vnode0, vnode1).elm;
assert.equal(elm.children.length, 1); assert.equal(elm.children.length, 1);
patch(vnode1, vnode2); elm = patch(vnode1, vnode2).elm;
assert.equal(elm.children.length, 3); assert.equal(elm.children.length, 3);
assert.equal(elm.children[1].innerHTML, '2'); assert.equal(elm.children[1].innerHTML, '2');
assert.equal(elm.children[2].innerHTML, '3'); assert.equal(elm.children[2].innerHTML, '3');
@ -188,42 +188,42 @@ describe('snabbdom', function() {
it('prepends elements', function() { it('prepends elements', function() {
var vnode1 = h('span', [4, 5].map(spanNum)); var vnode1 = h('span', [4, 5].map(spanNum));
var vnode2 = h('span', [1, 2, 3, 4, 5].map(spanNum)); var vnode2 = h('span', [1, 2, 3, 4, 5].map(spanNum));
patch(vnode0, vnode1); elm = patch(vnode0, vnode1).elm;
assert.equal(elm.children.length, 2); assert.equal(elm.children.length, 2);
patch(vnode1, vnode2); elm = patch(vnode1, vnode2).elm;
assert.deepEqual(map(inner, elm.children), ['1', '2', '3', '4', '5']); assert.deepEqual(map(inner, elm.children), ['1', '2', '3', '4', '5']);
}); });
it('add elements in the middle', function() { it('add elements in the middle', function() {
var vnode1 = h('span', [1, 2, 4, 5].map(spanNum)); var vnode1 = h('span', [1, 2, 4, 5].map(spanNum));
var vnode2 = h('span', [1, 2, 3, 4, 5].map(spanNum)); var vnode2 = h('span', [1, 2, 3, 4, 5].map(spanNum));
patch(vnode0, vnode1); elm = patch(vnode0, vnode1).elm;
assert.equal(elm.children.length, 4); assert.equal(elm.children.length, 4);
assert.equal(elm.children.length, 4); assert.equal(elm.children.length, 4);
patch(vnode1, vnode2); elm = patch(vnode1, vnode2).elm;
assert.deepEqual(map(inner, elm.children), ['1', '2', '3', '4', '5']); assert.deepEqual(map(inner, elm.children), ['1', '2', '3', '4', '5']);
}); });
it('add elements at begin and end', function() { it('add elements at begin and end', function() {
var vnode1 = h('span', [2, 3, 4].map(spanNum)); var vnode1 = h('span', [2, 3, 4].map(spanNum));
var vnode2 = h('span', [1, 2, 3, 4, 5].map(spanNum)); var vnode2 = h('span', [1, 2, 3, 4, 5].map(spanNum));
patch(vnode0, vnode1); elm = patch(vnode0, vnode1).elm;
assert.equal(elm.children.length, 3); assert.equal(elm.children.length, 3);
patch(vnode1, vnode2); elm = patch(vnode1, vnode2).elm;
assert.deepEqual(map(inner, elm.children), ['1', '2', '3', '4', '5']); assert.deepEqual(map(inner, elm.children), ['1', '2', '3', '4', '5']);
}); });
it('adds children to parent with no children', function() { it('adds children to parent with no children', function() {
var vnode1 = h('span', {key: 'span'}); var vnode1 = h('span', {key: 'span'});
var vnode2 = h('span', {key: 'span'}, [1, 2, 3].map(spanNum)); var vnode2 = h('span', {key: 'span'}, [1, 2, 3].map(spanNum));
patch(vnode0, vnode1); elm = patch(vnode0, vnode1).elm;
assert.equal(elm.children.length, 0); assert.equal(elm.children.length, 0);
patch(vnode1, vnode2); elm = patch(vnode1, vnode2).elm;
assert.deepEqual(map(inner, elm.children), ['1', '2', '3']); assert.deepEqual(map(inner, elm.children), ['1', '2', '3']);
}); });
it('removes all children from parent', function() { it('removes all children from parent', function() {
var vnode1 = h('span', {key: 'span'}, [1, 2, 3].map(spanNum)); var vnode1 = h('span', {key: 'span'}, [1, 2, 3].map(spanNum));
var vnode2 = h('span', {key: 'span'}); var vnode2 = h('span', {key: 'span'});
patch(vnode0, vnode1); elm = patch(vnode0, vnode1).elm;
assert.deepEqual(map(inner, elm.children), ['1', '2', '3']); assert.deepEqual(map(inner, elm.children), ['1', '2', '3']);
patch(vnode1, vnode2); elm = patch(vnode1, vnode2).elm;
assert.equal(elm.children.length, 0); assert.equal(elm.children.length, 0);
}); });
}); });
@ -231,17 +231,17 @@ describe('snabbdom', function() {
it('removes elements from the beginning', function() { it('removes elements from the beginning', function() {
var vnode1 = h('span', [1, 2, 3, 4, 5].map(spanNum)); var vnode1 = h('span', [1, 2, 3, 4, 5].map(spanNum));
var vnode2 = h('span', [3, 4, 5].map(spanNum)); var vnode2 = h('span', [3, 4, 5].map(spanNum));
patch(vnode0, vnode1); elm = patch(vnode0, vnode1).elm;
assert.equal(elm.children.length, 5); assert.equal(elm.children.length, 5);
patch(vnode1, vnode2); elm = patch(vnode1, vnode2).elm;
assert.deepEqual(map(inner, elm.children), ['3', '4', '5']); assert.deepEqual(map(inner, elm.children), ['3', '4', '5']);
}); });
it('removes elements from the end', function() { it('removes elements from the end', function() {
var vnode1 = h('span', [1, 2, 3, 4, 5].map(spanNum)); var vnode1 = h('span', [1, 2, 3, 4, 5].map(spanNum));
var vnode2 = h('span', [1, 2, 3].map(spanNum)); var vnode2 = h('span', [1, 2, 3].map(spanNum));
patch(vnode0, vnode1); elm = patch(vnode0, vnode1).elm;
assert.equal(elm.children.length, 5); assert.equal(elm.children.length, 5);
patch(vnode1, vnode2); elm = patch(vnode1, vnode2).elm;
assert.equal(elm.children.length, 3); assert.equal(elm.children.length, 3);
assert.equal(elm.children[0].innerHTML, '1'); assert.equal(elm.children[0].innerHTML, '1');
assert.equal(elm.children[1].innerHTML, '2'); assert.equal(elm.children[1].innerHTML, '2');
@ -250,9 +250,9 @@ describe('snabbdom', function() {
it('removes elements from the middle', function() { it('removes elements from the middle', function() {
var vnode1 = h('span', [1, 2, 3, 4, 5].map(spanNum)); var vnode1 = h('span', [1, 2, 3, 4, 5].map(spanNum));
var vnode2 = h('span', [1, 2, 4, 5].map(spanNum)); var vnode2 = h('span', [1, 2, 4, 5].map(spanNum));
patch(vnode0, vnode1); elm = patch(vnode0, vnode1).elm;
assert.equal(elm.children.length, 5); assert.equal(elm.children.length, 5);
patch(vnode1, vnode2); elm = patch(vnode1, vnode2).elm;
assert.equal(elm.children.length, 4); assert.equal(elm.children.length, 4);
assert.deepEqual(elm.children[0].innerHTML, '1'); assert.deepEqual(elm.children[0].innerHTML, '1');
assert.equal(elm.children[0].innerHTML, '1'); assert.equal(elm.children[0].innerHTML, '1');
@ -265,9 +265,9 @@ describe('snabbdom', function() {
it('moves element forward', function() { it('moves element forward', function() {
var vnode1 = h('span', [1, 2, 3, 4].map(spanNum)); var vnode1 = h('span', [1, 2, 3, 4].map(spanNum));
var vnode2 = h('span', [2, 3, 1, 4].map(spanNum)); var vnode2 = h('span', [2, 3, 1, 4].map(spanNum));
patch(vnode0, vnode1); elm = patch(vnode0, vnode1).elm;
assert.equal(elm.children.length, 4); assert.equal(elm.children.length, 4);
patch(vnode1, vnode2); elm = patch(vnode1, vnode2).elm;
assert.equal(elm.children.length, 4); assert.equal(elm.children.length, 4);
assert.equal(elm.children[0].innerHTML, '2'); assert.equal(elm.children[0].innerHTML, '2');
assert.equal(elm.children[1].innerHTML, '3'); assert.equal(elm.children[1].innerHTML, '3');
@ -277,9 +277,9 @@ describe('snabbdom', function() {
it('moves element to end', function() { it('moves element to end', function() {
var vnode1 = h('span', [1, 2, 3].map(spanNum)); var vnode1 = h('span', [1, 2, 3].map(spanNum));
var vnode2 = h('span', [2, 3, 1].map(spanNum)); var vnode2 = h('span', [2, 3, 1].map(spanNum));
patch(vnode0, vnode1); elm = patch(vnode0, vnode1).elm;
assert.equal(elm.children.length, 3); assert.equal(elm.children.length, 3);
patch(vnode1, vnode2); elm = patch(vnode1, vnode2).elm;
assert.equal(elm.children.length, 3); assert.equal(elm.children.length, 3);
assert.equal(elm.children[0].innerHTML, '2'); assert.equal(elm.children[0].innerHTML, '2');
assert.equal(elm.children[1].innerHTML, '3'); assert.equal(elm.children[1].innerHTML, '3');
@ -288,9 +288,9 @@ describe('snabbdom', function() {
it('moves element backwards', function() { it('moves element backwards', function() {
var vnode1 = h('span', [1, 2, 3, 4].map(spanNum)); var vnode1 = h('span', [1, 2, 3, 4].map(spanNum));
var vnode2 = h('span', [1, 4, 2, 3].map(spanNum)); var vnode2 = h('span', [1, 4, 2, 3].map(spanNum));
patch(vnode0, vnode1); elm = patch(vnode0, vnode1).elm;
assert.equal(elm.children.length, 4); assert.equal(elm.children.length, 4);
patch(vnode1, vnode2); elm = patch(vnode1, vnode2).elm;
assert.equal(elm.children.length, 4); assert.equal(elm.children.length, 4);
assert.equal(elm.children[0].innerHTML, '1'); assert.equal(elm.children[0].innerHTML, '1');
assert.equal(elm.children[1].innerHTML, '4'); assert.equal(elm.children[1].innerHTML, '4');
@ -300,9 +300,9 @@ describe('snabbdom', function() {
it('swaps first and last', function() { it('swaps first and last', function() {
var vnode1 = h('span', [1, 2, 3, 4].map(spanNum)); var vnode1 = h('span', [1, 2, 3, 4].map(spanNum));
var vnode2 = h('span', [4, 2, 3, 1].map(spanNum)); var vnode2 = h('span', [4, 2, 3, 1].map(spanNum));
patch(vnode0, vnode1); elm = patch(vnode0, vnode1).elm;
assert.equal(elm.children.length, 4); assert.equal(elm.children.length, 4);
patch(vnode1, vnode2); elm = patch(vnode1, vnode2).elm;
assert.equal(elm.children.length, 4); assert.equal(elm.children.length, 4);
assert.equal(elm.children[0].innerHTML, '4'); assert.equal(elm.children[0].innerHTML, '4');
assert.equal(elm.children[1].innerHTML, '2'); assert.equal(elm.children[1].innerHTML, '2');
@ -314,9 +314,9 @@ describe('snabbdom', function() {
it('move to left and replace', function() { it('move to left and replace', function() {
var vnode1 = h('span', [1, 2, 3, 4, 5].map(spanNum)); var vnode1 = h('span', [1, 2, 3, 4, 5].map(spanNum));
var vnode2 = h('span', [4, 1, 2, 3, 6].map(spanNum)); var vnode2 = h('span', [4, 1, 2, 3, 6].map(spanNum));
patch(vnode0, vnode1); elm = patch(vnode0, vnode1).elm;
assert.equal(elm.children.length, 5); assert.equal(elm.children.length, 5);
patch(vnode1, vnode2); elm = patch(vnode1, vnode2).elm;
assert.equal(elm.children.length, 5); assert.equal(elm.children.length, 5);
assert.equal(elm.children[0].innerHTML, '4'); assert.equal(elm.children[0].innerHTML, '4');
assert.equal(elm.children[1].innerHTML, '1'); assert.equal(elm.children[1].innerHTML, '1');
@ -327,17 +327,17 @@ describe('snabbdom', function() {
it('moves to left and leaves hole', function() { it('moves to left and leaves hole', function() {
var vnode1 = h('span', [1, 4, 5].map(spanNum)); var vnode1 = h('span', [1, 4, 5].map(spanNum));
var vnode2 = h('span', [4, 6].map(spanNum)); var vnode2 = h('span', [4, 6].map(spanNum));
patch(vnode0, vnode1); elm = patch(vnode0, vnode1).elm;
assert.equal(elm.children.length, 3); assert.equal(elm.children.length, 3);
patch(vnode1, vnode2); elm = patch(vnode1, vnode2).elm;
assert.deepEqual(map(inner, elm.children), ['4', '6']); assert.deepEqual(map(inner, elm.children), ['4', '6']);
}); });
it('handles moved and set to undefined element ending at the end', function() { it('handles moved and set to undefined element ending at the end', function() {
var vnode1 = h('span', [2, 4, 5].map(spanNum)); var vnode1 = h('span', [2, 4, 5].map(spanNum));
var vnode2 = h('span', [4, 5, 3].map(spanNum)); var vnode2 = h('span', [4, 5, 3].map(spanNum));
patch(vnode0, vnode1); elm = patch(vnode0, vnode1).elm;
assert.equal(elm.children.length, 3); assert.equal(elm.children.length, 3);
patch(vnode1, vnode2); elm = patch(vnode1, vnode2).elm;
assert.equal(elm.children.length, 3); assert.equal(elm.children.length, 3);
assert.equal(elm.children[0].innerHTML, '4'); assert.equal(elm.children[0].innerHTML, '4');
assert.equal(elm.children[1].innerHTML, '5'); assert.equal(elm.children[1].innerHTML, '5');
@ -346,10 +346,10 @@ describe('snabbdom', function() {
it('moves a key in non-keyed nodes with a size up', function() { it('moves a key in non-keyed nodes with a size up', function() {
var vnode1 = h('span', [1, 'a', 'b', 'c'].map(spanNum)); var vnode1 = h('span', [1, 'a', 'b', 'c'].map(spanNum));
var vnode2 = h('span', ['d', 'a', 'b', 'c', 1, 'e'].map(spanNum)); var vnode2 = h('span', ['d', 'a', 'b', 'c', 1, 'e'].map(spanNum));
patch(vnode0, vnode1); elm = patch(vnode0, vnode1).elm;
assert.equal(elm.childNodes.length, 4); assert.equal(elm.childNodes.length, 4);
assert.equal(elm.textContent, '1abc'); assert.equal(elm.textContent, '1abc');
patch(vnode1, vnode2); elm = patch(vnode1, vnode2).elm;
assert.equal(elm.childNodes.length, 6); assert.equal(elm.childNodes.length, 6);
assert.equal(elm.textContent, 'dabc1e'); assert.equal(elm.textContent, 'dabc1e');
}); });
@ -357,17 +357,17 @@ describe('snabbdom', function() {
it('reverses elements', function() { it('reverses elements', function() {
var vnode1 = h('span', [1, 2, 3, 4, 5, 6, 7, 8].map(spanNum)); var vnode1 = h('span', [1, 2, 3, 4, 5, 6, 7, 8].map(spanNum));
var vnode2 = h('span', [8, 7, 6, 5, 4, 3, 2, 1].map(spanNum)); var vnode2 = h('span', [8, 7, 6, 5, 4, 3, 2, 1].map(spanNum));
patch(vnode0, vnode1); elm = patch(vnode0, vnode1).elm;
assert.equal(elm.children.length, 8); assert.equal(elm.children.length, 8);
patch(vnode1, vnode2); elm = patch(vnode1, vnode2).elm;
assert.deepEqual(map(inner, elm.children), ['8', '7', '6', '5', '4', '3', '2', '1']); assert.deepEqual(map(inner, elm.children), ['8', '7', '6', '5', '4', '3', '2', '1']);
}); });
it('something', function() { it('something', function() {
var vnode1 = h('span', [0, 1, 2, 3, 4, 5].map(spanNum)); var vnode1 = h('span', [0, 1, 2, 3, 4, 5].map(spanNum));
var vnode2 = h('span', [4, 3, 2, 1, 5, 0].map(spanNum)); var vnode2 = h('span', [4, 3, 2, 1, 5, 0].map(spanNum));
patch(vnode0, vnode1); elm = patch(vnode0, vnode1).elm;
assert.equal(elm.children.length, 6); assert.equal(elm.children.length, 6);
patch(vnode1, vnode2); elm = patch(vnode1, vnode2).elm;
assert.deepEqual(map(inner, elm.children), ['4', '3', '2', '1', '5', '0']); assert.deepEqual(map(inner, elm.children), ['4', '3', '2', '1', '5', '0']);
}); });
it('handles random shuffles', function() { it('handles random shuffles', function() {
@ -382,7 +382,7 @@ describe('snabbdom', function() {
})); }));
var shufArr = shuffle(arr.slice(0)); var shufArr = shuffle(arr.slice(0));
var elm = document.createElement('div'); var elm = document.createElement('div');
patch(elm, vnode1); elm = patch(elm, vnode1).elm;
for (i = 0; i < elms; ++i) { for (i = 0; i < elms; ++i) {
assert.equal(elm.children[i].innerHTML, i.toString()); assert.equal(elm.children[i].innerHTML, i.toString());
opacities[i] = Math.random().toFixed(5).toString(); opacities[i] = Math.random().toFixed(5).toString();
@ -390,7 +390,7 @@ describe('snabbdom', function() {
var vnode2 = h('span', arr.map(function(n) { var vnode2 = h('span', arr.map(function(n) {
return spanNumWithOpacity(shufArr[n], opacities[n]); return spanNumWithOpacity(shufArr[n], opacities[n]);
})); }));
patch(vnode1, vnode2); elm = patch(vnode1, vnode2).elm;
for (i = 0; i < elms; ++i) { for (i = 0; i < elms; ++i) {
assert.equal(elm.children[i].innerHTML, shufArr[i].toString()); assert.equal(elm.children[i].innerHTML, shufArr[i].toString());
assert.equal(opacities[i].indexOf(elm.children[i].style.opacity), 0); assert.equal(opacities[i].indexOf(elm.children[i].style.opacity), 0);
@ -402,50 +402,50 @@ describe('snabbdom', function() {
it('appends elements', function() { it('appends elements', function() {
var vnode1 = h('div', [h('span', 'Hello')]); var vnode1 = h('div', [h('span', 'Hello')]);
var vnode2 = h('div', [h('span', 'Hello'), h('span', 'World')]); var vnode2 = h('div', [h('span', 'Hello'), h('span', 'World')]);
patch(vnode0, vnode1); elm = patch(vnode0, vnode1).elm;
assert.deepEqual(map(inner, elm.children), ['Hello']); assert.deepEqual(map(inner, elm.children), ['Hello']);
patch(vnode1, vnode2); elm = patch(vnode1, vnode2).elm;
assert.deepEqual(map(inner, elm.children), ['Hello', 'World']); assert.deepEqual(map(inner, elm.children), ['Hello', 'World']);
}); });
it('handles unmoved text nodes', function() { it('handles unmoved text nodes', function() {
var vnode1 = h('div', ['Text', h('span', 'Span')]); var vnode1 = h('div', ['Text', h('span', 'Span')]);
var vnode2 = h('div', ['Text', h('span', 'Span')]); var vnode2 = h('div', ['Text', h('span', 'Span')]);
patch(vnode0, vnode1); elm = patch(vnode0, vnode1).elm;
assert.equal(elm.childNodes[0].textContent, 'Text'); assert.equal(elm.childNodes[0].textContent, 'Text');
patch(vnode1, vnode2); elm = patch(vnode1, vnode2).elm;
assert.equal(elm.childNodes[0].textContent, 'Text'); assert.equal(elm.childNodes[0].textContent, 'Text');
}); });
it('handles changing text children', function() { it('handles changing text children', function() {
var vnode1 = h('div', ['Text', h('span', 'Span')]); var vnode1 = h('div', ['Text', h('span', 'Span')]);
var vnode2 = h('div', ['Text2', h('span', 'Span')]); var vnode2 = h('div', ['Text2', h('span', 'Span')]);
patch(vnode0, vnode1); elm = patch(vnode0, vnode1).elm;
assert.equal(elm.childNodes[0].textContent, 'Text'); assert.equal(elm.childNodes[0].textContent, 'Text');
patch(vnode1, vnode2); elm = patch(vnode1, vnode2).elm;
assert.equal(elm.childNodes[0].textContent, 'Text2'); assert.equal(elm.childNodes[0].textContent, 'Text2');
}); });
it('prepends element', function() { it('prepends element', function() {
var vnode1 = h('div', [h('span', 'World')]); var vnode1 = h('div', [h('span', 'World')]);
var vnode2 = h('div', [h('span', 'Hello'), h('span', 'World')]); var vnode2 = h('div', [h('span', 'Hello'), h('span', 'World')]);
patch(vnode0, vnode1); elm = patch(vnode0, vnode1).elm;
assert.deepEqual(map(inner, elm.children), ['World']); assert.deepEqual(map(inner, elm.children), ['World']);
patch(vnode1, vnode2); elm = patch(vnode1, vnode2).elm;
assert.deepEqual(map(inner, elm.children), ['Hello', 'World']); assert.deepEqual(map(inner, elm.children), ['Hello', 'World']);
}); });
it('prepends element of different tag type', function() { it('prepends element of different tag type', function() {
var vnode1 = h('div', [h('span', 'World')]); var vnode1 = h('div', [h('span', 'World')]);
var vnode2 = h('div', [h('div', 'Hello'), h('span', 'World')]); var vnode2 = h('div', [h('div', 'Hello'), h('span', 'World')]);
patch(vnode0, vnode1); elm = patch(vnode0, vnode1).elm;
assert.deepEqual(map(inner, elm.children), ['World']); assert.deepEqual(map(inner, elm.children), ['World']);
patch(vnode1, vnode2); elm = patch(vnode1, vnode2).elm;
assert.deepEqual(map(prop('tagName'), elm.children), ['DIV', 'SPAN']); assert.deepEqual(map(prop('tagName'), elm.children), ['DIV', 'SPAN']);
assert.deepEqual(map(inner, elm.children), ['Hello', 'World']); assert.deepEqual(map(inner, elm.children), ['Hello', 'World']);
}); });
it('removes elements', function() { it('removes elements', function() {
var vnode1 = h('div', [h('span', 'One'), h('span', 'Two'), h('span', 'Three')]); var vnode1 = h('div', [h('span', 'One'), h('span', 'Two'), h('span', 'Three')]);
var vnode2 = h('div', [h('span', 'One'), h('span', 'Three')]); var vnode2 = h('div', [h('span', 'One'), h('span', 'Three')]);
patch(vnode0, vnode1); elm = patch(vnode0, vnode1).elm;
assert.deepEqual(map(inner, elm.children), ['One', 'Two', 'Three']); assert.deepEqual(map(inner, elm.children), ['One', 'Two', 'Three']);
patch(vnode1, vnode2); elm = patch(vnode1, vnode2).elm;
assert.deepEqual(map(inner, elm.children), ['One', 'Three']); assert.deepEqual(map(inner, elm.children), ['One', 'Three']);
}); });
it('removes a single text node', function() { it('removes a single text node', function() {
@ -462,7 +462,6 @@ describe('snabbdom', function() {
patch(vnode0, vnode1); patch(vnode0, vnode1);
assert.equal(elm.textContent, 'One'); assert.equal(elm.textContent, 'One');
patch(vnode1, vnode2); patch(vnode1, vnode2);
console.log(elm.childNodes);
assert.deepEqual(map(prop('textContent'), elm.childNodes), ['Two', 'Three']); assert.deepEqual(map(prop('textContent'), elm.childNodes), ['Two', 'Three']);
}); });
it('removes a text node among other elements', function() { it('removes a text node among other elements', function() {
@ -478,9 +477,9 @@ describe('snabbdom', function() {
it('reorders elements', function() { it('reorders elements', function() {
var vnode1 = h('div', [h('span', 'One'), h('div', 'Two'), h('b', 'Three')]); var vnode1 = h('div', [h('span', 'One'), h('div', 'Two'), h('b', 'Three')]);
var vnode2 = h('div', [h('b', 'Three'), h('span', 'One'), h('div', 'Two')]); var vnode2 = h('div', [h('b', 'Three'), h('span', 'One'), h('div', 'Two')]);
patch(vnode0, vnode1); elm = patch(vnode0, vnode1).elm;
assert.deepEqual(map(inner, elm.children), ['One', 'Two', 'Three']); assert.deepEqual(map(inner, elm.children), ['One', 'Two', 'Three']);
patch(vnode1, vnode2); elm = patch(vnode1, vnode2).elm;
assert.deepEqual(map(prop('tagName'), elm.children), ['B', 'SPAN', 'DIV']); assert.deepEqual(map(prop('tagName'), elm.children), ['B', 'SPAN', 'DIV']);
assert.deepEqual(map(inner, elm.children), ['Three', 'One', 'Two']); assert.deepEqual(map(inner, elm.children), ['Three', 'One', 'Two']);
}); });
@ -634,6 +633,23 @@ describe('snabbdom', function() {
patch(vnode1, vnode2); patch(vnode1, vnode2);
assert.equal(1, result.length); assert.equal(1, result.length);
}); });
it('calls `init` and `prepatch` listeners on root', function() {
var count = 0;
function init(vnode) {
assert.strictEqual(vnode, vnode2);
count += 1;
}
function prepatch(oldVnode, vnode) {
assert.strictEqual(vnode, vnode1);
count += 1;
}
var vnode1 = h('div', {hook: {init: init, prepatch: prepatch}});
patch(vnode0, vnode1);
assert.equal(1, count);
var vnode2 = h('span', {hook: {init: init, prepatch: prepatch}});
patch(vnode1, vnode2);
assert.equal(2, count);
});
it('removes element when all remove listeners are done', function() { it('removes element when all remove listeners are done', function() {
var rm1, rm2, rm3; var rm1, rm2, rm3;
var patch = snabbdom.init([ var patch = snabbdom.init([
@ -641,9 +657,10 @@ describe('snabbdom', function() {
{remove: function(_, rm) { rm2 = rm; }}, {remove: function(_, rm) { rm2 = rm; }},
]); ]);
var vnode1 = h('div', [h('a', {hook: {remove: function(_, rm) { rm3 = rm; }}})]); var vnode1 = h('div', [h('a', {hook: {remove: function(_, rm) { rm3 = rm; }}})]);
patch(vnode0, vnode1); var vnode2 = h('div', []);
elm = patch(vnode0, vnode1).elm;
assert.equal(elm.children.length, 1); assert.equal(elm.children.length, 1);
patch(vnode1, vnode0); elm = patch(vnode1, vnode2).elm;
assert.equal(elm.children.length, 1); assert.equal(elm.children.length, 1);
rm1(); rm1();
assert.equal(elm.children.length, 1); assert.equal(elm.children.length, 1);
@ -700,8 +717,9 @@ describe('snabbdom', function() {
h('span', 'Child 2'), h('span', 'Child 2'),
]), ]),
]); ]);
var vnode2 = h('div');
patch(vnode0, vnode1); patch(vnode0, vnode1);
patch(vnode1, vnode0); patch(vnode1, vnode2);
assert.equal(created, 4); assert.equal(created, 4);
assert.equal(destroyed, 4); assert.equal(destroyed, 4);
}); });
@ -717,8 +735,9 @@ describe('snabbdom', function() {
'', '',
h('span', 'Third child'), h('span', 'Third child'),
]); ]);
var vnode2 = h('div');
patch(vnode0, vnode1); patch(vnode0, vnode1);
patch(vnode1, vnode0); patch(vnode1, vnode2);
assert.equal(created, 2); assert.equal(created, 2);
assert.equal(removed, 2); assert.equal(removed, 2);
}); });
@ -736,8 +755,9 @@ describe('snabbdom', function() {
h('span', ['Text 1', 'Text 2']), h('span', ['Text 1', 'Text 2']),
]), ]),
]); ]);
var vnode2 = h('div');
patch(vnode0, vnode1); patch(vnode0, vnode1);
patch(vnode1, vnode0); patch(vnode1, vnode2);
assert.equal(created, 4); assert.equal(created, 4);
assert.equal(destroyed, 4); assert.equal(destroyed, 4);
}); });

@ -18,7 +18,7 @@ describe('event listeners', function() {
var vnode = h('div', {on: {click: clicked}}, [ var vnode = h('div', {on: {click: clicked}}, [
h('a', 'Click my parent'), h('a', 'Click my parent'),
]); ]);
patch(vnode0, vnode); elm = patch(vnode0, vnode).elm;
elm.click(); elm.click();
assert.equal(1, result.length); assert.equal(1, result.length);
}); });
@ -31,9 +31,9 @@ describe('event listeners', function() {
var vnode2 = h('div', {on: {click: function(ev) { result.push(2); }}}, [ var vnode2 = h('div', {on: {click: function(ev) { result.push(2); }}}, [
h('a', 'Click my parent'), h('a', 'Click my parent'),
]); ]);
patch(vnode0, vnode1); elm = patch(vnode0, vnode1).elm;
elm.click(); elm.click();
patch(vnode1, vnode2); elm = patch(vnode1, vnode2).elm;
elm.click(); elm.click();
assert.deepEqual(result, [1, 2]); assert.deepEqual(result, [1, 2]);
}); });
@ -43,7 +43,7 @@ describe('event listeners', function() {
var vnode = h('div', {on: {click: [clicked, 1]}}, [ var vnode = h('div', {on: {click: [clicked, 1]}}, [
h('a', 'Click my parent'), h('a', 'Click my parent'),
]); ]);
patch(vnode0, vnode); elm = patch(vnode0, vnode).elm;
elm.click(); elm.click();
assert.deepEqual(result, [1]); assert.deepEqual(result, [1]);
}); });
@ -59,11 +59,11 @@ describe('event listeners', function() {
var vnode3 = h('div', {on: {click: [clicked, 3]}}, [ var vnode3 = h('div', {on: {click: [clicked, 3]}}, [
h('a', 'Click my parent'), h('a', 'Click my parent'),
]); ]);
patch(vnode0, vnode1); elm = patch(vnode0, vnode1).elm;
elm.click(); elm.click();
patch(vnode1, vnode2); elm = patch(vnode1, vnode2).elm;
elm.click(); elm.click();
patch(vnode2, vnode3); elm = patch(vnode2, vnode3).elm;
elm.click(); elm.click();
assert.deepEqual(result, [1, 2, 3]); assert.deepEqual(result, [1, 2, 3]);
}); });
@ -79,11 +79,11 @@ describe('event listeners', function() {
var vnode3 = h('div', {on: {click: [clicked, 2, 3]}}, [ var vnode3 = h('div', {on: {click: [clicked, 2, 3]}}, [
h('a', 'Click my parent'), h('a', 'Click my parent'),
]); ]);
patch(vnode0, vnode1); elm = patch(vnode0, vnode1).elm;
elm.click(); elm.click();
patch(vnode1, vnode2); elm = patch(vnode1, vnode2).elm;
elm.click(); elm.click();
patch(vnode2, vnode3); elm = patch(vnode2, vnode3).elm;
elm.click(); elm.click();
assert.deepEqual(result, [[1, 2, 3], [1, 2], [2, 3]]); assert.deepEqual(result, [[1, 2, 3], [1, 2], [2, 3]]);
}); });

@ -15,20 +15,20 @@ describe('style', function() {
vnode0 = elm; vnode0 = elm;
}); });
it('is being styled', function() { it('is being styled', function() {
patch(vnode0, h('div', {style: {fontSize: '12px'}})); elm = patch(vnode0, h('div', {style: {fontSize: '12px'}})).elm;
assert.equal(elm.style.fontSize, '12px'); assert.equal(elm.style.fontSize, '12px');
}); });
it('updates styles', function() { it('updates styles', function() {
var vnode1 = h('i', {style: {fontSize: '14px', display: 'inline'}}); var vnode1 = h('i', {style: {fontSize: '14px', display: 'inline'}});
var vnode2 = h('i', {style: {fontSize: '12px', display: 'block'}}); var vnode2 = h('i', {style: {fontSize: '12px', display: 'block'}});
var vnode3 = h('i', {style: {fontSize: '10px', display: 'block'}}); var vnode3 = h('i', {style: {fontSize: '10px', display: 'block'}});
patch(vnode0, vnode1); elm = patch(vnode0, vnode1).elm;
assert.equal(elm.style.fontSize, '14px'); assert.equal(elm.style.fontSize, '14px');
assert.equal(elm.style.display, 'inline'); assert.equal(elm.style.display, 'inline');
patch(vnode1, vnode2); elm = patch(vnode1, vnode2).elm;
assert.equal(elm.style.fontSize, '12px'); assert.equal(elm.style.fontSize, '12px');
assert.equal(elm.style.display, 'block'); assert.equal(elm.style.display, 'block');
patch(vnode2, vnode3); elm = patch(vnode2, vnode3).elm;
assert.equal(elm.style.fontSize, '10px'); assert.equal(elm.style.fontSize, '10px');
assert.equal(elm.style.display, 'block'); assert.equal(elm.style.display, 'block');
}); });
@ -36,7 +36,7 @@ describe('style', function() {
var vnode1 = h('i', {style: {fontSize: '14px'}}); var vnode1 = h('i', {style: {fontSize: '14px'}});
var vnode2 = h('i', {style: {fontSize: ''}}); var vnode2 = h('i', {style: {fontSize: ''}});
var vnode3 = h('i', {style: {fontSize: '10px'}}); var vnode3 = h('i', {style: {fontSize: '10px'}});
patch(vnode0, vnode1); elm = patch(vnode0, vnode1).elm;
assert.equal(elm.style.fontSize, '14px'); assert.equal(elm.style.fontSize, '14px');
patch(vnode1, vnode2); patch(vnode1, vnode2);
assert.equal(elm.style.fontSize, ''); assert.equal(elm.style.fontSize, '');
@ -60,12 +60,12 @@ describe('style', function() {
]); ]);
var vnode1 = h('i', {style: {fontSize: '14px', delayed: {fontSize: '16px'}}}); var vnode1 = h('i', {style: {fontSize: '14px', delayed: {fontSize: '16px'}}});
var vnode2 = h('i', {style: {fontSize: '18px', delayed: {fontSize: '20px'}}}); var vnode2 = h('i', {style: {fontSize: '18px', delayed: {fontSize: '20px'}}});
patch(vnode0, vnode1); elm = patch(vnode0, vnode1).elm;
assert.equal(elm.style.fontSize, '14px'); assert.equal(elm.style.fontSize, '14px');
fakeRaf.step(); fakeRaf.step();
fakeRaf.step(); fakeRaf.step();
assert.equal(elm.style.fontSize, '16px'); assert.equal(elm.style.fontSize, '16px');
patch(vnode1, vnode2); elm = patch(vnode1, vnode2).elm;
assert.equal(elm.style.fontSize, '18px'); assert.equal(elm.style.fontSize, '18px');
fakeRaf.step(); fakeRaf.step();
fakeRaf.step(); fakeRaf.step();

@ -9,8 +9,7 @@ var thunk = require('../thunk');
describe('thunk', function() { describe('thunk', function() {
var elm, vnode0; var elm, vnode0;
beforeEach(function() { beforeEach(function() {
elm = document.createElement('div'); elm = vnode0 = document.createElement('div');
vnode0 = elm;
}); });
it('returns vnode with data and render function', function() { it('returns vnode with data and render function', function() {
function numberInSpan(n) { function numberInSpan(n) {
@ -55,12 +54,132 @@ describe('thunk', function() {
var vnode3 = h('div', [ var vnode3 = h('div', [
thunk('num', numberInSpan, 2) thunk('num', numberInSpan, 2)
]); ]);
patch(vnode0, vnode1); elm = patch(vnode0, vnode1).elm;
assert.equal(elm.firstChild.tagName.toLowerCase(), 'span');
assert.equal(elm.firstChild.innerHTML, 'Number is 1'); assert.equal(elm.firstChild.innerHTML, 'Number is 1');
patch(vnode1, vnode2); elm = patch(vnode1, vnode2).elm;
assert.equal(elm.firstChild.tagName.toLowerCase(), 'span');
assert.equal(elm.firstChild.innerHTML, 'Number is 1'); assert.equal(elm.firstChild.innerHTML, 'Number is 1');
patch(vnode2, vnode3); elm = patch(vnode2, vnode3).elm;
assert.equal(elm.firstChild.tagName.toLowerCase(), 'span');
assert.equal(elm.firstChild.innerHTML, 'Number is 2'); assert.equal(elm.firstChild.innerHTML, 'Number is 2');
assert.equal(called, 2); assert.equal(called, 2);
}); });
it('renders correctly child thunk', function() {
function oddEven(n) {
var oddEvenSel = (n % 2) ? 'span.odd' : 'span.even';
return h(oddEvenSel, n);
}
function numberInSpan(n) {
return h('span.number', ['Number is ', thunk('oddeven', oddEven, n)]);
}
var vnode1 = thunk('num', numberInSpan, 1);
var vnode2 = thunk('num', numberInSpan, 2);
elm = patch(vnode0, vnode1).elm;
assert.equal(elm.tagName.toLowerCase(), 'span');
assert.equal(elm.className, 'number');
assert.equal(elm.childNodes[1].tagName.toLowerCase(), 'span');
assert.equal(elm.childNodes[1].className, 'odd');
elm = patch(vnode1, vnode2).elm;
assert.equal(elm.tagName.toLowerCase(), 'span');
assert.equal(elm.className, 'number');
assert.equal(elm.childNodes[1].tagName.toLowerCase(), 'span');
assert.equal(elm.childNodes[1].className, 'even');
});
/* NOT WORKING YET
it('renders correctly nested thunk', function() {
function oddEven(n) {
var oddEvenSel = (n % 2) ? 'span.odd' : 'span.even';
return h(oddEvenSel, n);
}
function nested(n) {
return thunk('oddeven', oddEven, n);
}
var vnode1 = thunk('num', nested, 1);
var vnode2 = thunk('num', nested, 2);
elm = patch(vnode0, vnode1).elm;
assert.equal(elm.tagName.toLowerCase(), 'span');
assert.equal(elm.className, 'odd');
elm = patch(vnode1, vnode2).elm;
assert.equal(elm.tagName.toLowerCase(), 'span');
assert.equal(elm.className, 'even');
});
*/
it('renders correctly when root', function() {
var called = 0;
function numberInSpan(n) {
called++;
return h('span', 'Number is ' + n);
}
var vnode1 = thunk('num', numberInSpan, 1);
var vnode2 = thunk('num', numberInSpan, 1);
var vnode3 = thunk('num', numberInSpan, 2);
elm = patch(vnode0, vnode1).elm;
assert.equal(elm.tagName.toLowerCase(), 'span');
assert.equal(elm.innerHTML, 'Number is 1');
elm = patch(vnode1, vnode2).elm;
assert.equal(elm.tagName.toLowerCase(), 'span');
assert.equal(elm.innerHTML, 'Number is 1');
elm = patch(vnode2, vnode3).elm;
assert.equal(elm.tagName.toLowerCase(), 'span');
assert.equal(elm.innerHTML, 'Number is 2');
assert.equal(called, 2);
});
it('can mutate its root tag', function() {
function oddEven(n) {
var oddEvenSel = (n % 2) ? 'div.odd' : 'p.even';
return h(oddEvenSel, n);
}
var vnode1 = h('div', [thunk('oddEven', oddEven, 1)]);
var vnode2 = h('div', [thunk('oddEven', oddEven, 4)]);
elm = patch(vnode0, vnode1).elm;
assert.equal(elm.firstChild.tagName.toLowerCase(), 'div');
assert.equal(elm.firstChild.className, 'odd');
elm = patch(vnode1, vnode2).elm;
assert.equal(elm.firstChild.tagName.toLowerCase(), 'p');
assert.equal(elm.firstChild.className, 'even');
});
it('can be replaced and removed', function() {
function numberInSpan(n) {
return h('span.numberInSpan', 'Number is ' + n);
}
function oddEven(n) {
var oddEvenClass = (n % 2) ? '.odd' : '.even';
return h('div' + oddEvenClass, 'Number is ' + n);
}
var vnode1 = h('div', [thunk('num', numberInSpan, 1)]);
var vnode2 = h('div', [thunk('oddEven', oddEven, 4)]);
elm = patch(vnode0, vnode1).elm;
assert.equal(elm.firstChild.tagName.toLowerCase(), 'span');
assert.equal(elm.firstChild.className, 'numberInSpan');
elm = patch(vnode1, vnode2).elm;
assert.equal(elm.firstChild.tagName.toLowerCase(), 'div');
assert.equal(elm.firstChild.className, 'even');
});
it('can be replaced and removed when root', function() {
function numberInSpan(n) {
return h('span.numberInSpan', 'Number is ' + n);
}
function oddEven(n) {
var oddEvenClass = (n % 2) ? '.odd' : '.even';
return h('div' + oddEvenClass, 'Number is ' + n);
}
var vnode1 = thunk('num', numberInSpan, 1);
var vnode2 = thunk('oddEven', oddEven, 4);
elm = patch(vnode0, vnode1).elm;
assert.equal(elm.tagName.toLowerCase(), 'span');
assert.equal(elm.className, 'numberInSpan');
elm = patch(vnode1, vnode2).elm;
assert.equal(elm.tagName.toLowerCase(), 'div');
assert.equal(elm.className, 'even');
});
}); });

@ -9,7 +9,7 @@ function prepatch(oldThunk, thunk) {
var i, old = oldThunk.data, cur = thunk.data; var i, old = oldThunk.data, cur = thunk.data;
var oldArgs = old.args, args = cur.args; var oldArgs = old.args, args = cur.args;
cur.vnode = old.vnode; cur.vnode = old.vnode;
if (oldArgs.length !== args.length) { if (old.fn !== cur.fn || oldArgs.length !== args.length) {
cur.vnode = cur.fn.apply(undefined, args); cur.vnode = cur.fn.apply(undefined, args);
return; return;
} }

Loading…
Cancel
Save