ractive
Version:
Next-generation DOM manipulation
289 lines (230 loc) • 7.89 kB
JavaScript
define([ 'ractive' ], function ( Ractive ) {
'use strict';
return function () {
var fixture = document.getElementById( 'qunit-fixture' );
module( 'ractive.merge()' );
test( 'Merging an array of strings only creates the necessary fragments', function ( t ) {
var entered, exited, foo, bar, baz, ractive;
entered = 0;
exited = 0;
ractive = new Ractive({
el: fixture,
template: '<ul>{{#items}}<li id="{{.}}" intro-outro="log">{{.}}</li>{{/items}}</ul>',
data: {
items: [ 'foo', 'bar', 'baz' ]
},
transitions: {
log: function ( t ) {
if ( t.isIntro ) {
entered += 1;
} else {
exited += 1;
}
t.complete();
}
}
});
foo = ractive.nodes.foo;
bar = ractive.nodes.bar;
baz = ractive.nodes.baz;
t.htmlEqual( fixture.innerHTML, '<ul><li id="foo">foo</li><li id="bar">bar</li><li id="baz">baz</li></ul>' );
t.equal( entered, 3 );
entered = 0; // reset
ractive.merge( 'items', [ 'foo', 'bip', 'bar', 'baz' ] );
t.htmlEqual( fixture.innerHTML, '<ul><li id="foo">foo</li><li id="bip">bip</li><li id="bar">bar</li><li id="baz">baz</li></ul>' );
t.equal( entered, 1 );
t.ok( foo === ractive.nodes.foo );
t.ok( bar === ractive.nodes.bar );
t.ok( baz === ractive.nodes.baz );
});
test( 'Merging an array of strings only removes the necessary fragments', function ( t ) {
var entered, exited, foo, bar, baz, ractive;
entered = 0;
exited = 0;
ractive = new Ractive({
el: fixture,
template: '<ul>{{#items}}<li id="{{.}}" intro-outro="log">{{.}}</li>{{/items}}</ul>',
data: {
items: [ 'foo', 'bar', 'baz' ]
},
transitions: {
log: function ( t ) {
if ( t.isIntro ) {
entered += 1;
} else {
exited += 1;
}
t.complete();
}
}
});
foo = ractive.nodes.foo;
bar = ractive.nodes.bar;
baz = ractive.nodes.baz;
t.htmlEqual( fixture.innerHTML, '<ul><li id="foo">foo</li><li id="bar">bar</li><li id="baz">baz</li></ul>' );
t.equal( entered, 3 );
ractive.merge( 'items', [ 'foo', 'baz' ] );
t.htmlEqual( fixture.innerHTML, '<ul><li id="foo">foo</li><li id="baz">baz</li></ul>' );
t.equal( exited, 1 );
t.ok( foo === ractive.nodes.foo );
t.ok( isOrphan( bar ) );
t.ok( baz === ractive.nodes.baz );
});
test( 'Merging an array of same-looking objects only adds/removes the necessary fragments if `compare` is `true`', function ( t ) {
var entered, exited, foo, bar, baz, ractive;
entered = 0;
exited = 0;
ractive = new Ractive({
el: fixture,
template: '<ul>{{#items}}<li id="{{name}}" intro-outro="log">{{name}}</li>{{/items}}</ul>',
data: {
items: [{ name: 'foo' }, { name: 'bar' }, { name: 'baz' }]
},
transitions: {
log: function ( t ) {
if ( t.isIntro ) {
entered += 1;
} else {
exited += 1;
}
t.complete();
}
}
});
foo = ractive.nodes.foo;
bar = ractive.nodes.bar;
baz = ractive.nodes.baz;
t.htmlEqual( fixture.innerHTML, '<ul><li id="foo">foo</li><li id="bar">bar</li><li id="baz">baz</li></ul>' );
t.equal( entered, 3 );
entered = 0;
ractive.merge( 'items', [{ name: 'foo' }, { name: 'baz' }, { name: 'bip' }], { compare: true });
t.htmlEqual( fixture.innerHTML, '<ul><li id="foo">foo</li><li id="baz">baz</li><li id="bip">bip</li></ul>' );
t.equal( entered, 1 );
t.equal( exited, 1 );
t.ok( foo === ractive.nodes.foo );
t.ok( isOrphan( bar ) );
t.ok( baz === ractive.nodes.baz );
});
test( 'Merging an array of same-looking objects only adds/removes the necessary fragments if `compare` is a string id field', function ( t ) {
var entered, exited, foo, bar, baz, ractive;
entered = 0;
exited = 0;
ractive = new Ractive({
el: fixture,
template: '<ul>{{#items}}<li id="{{name}}" intro-outro="log">{{name}}</li>{{/items}}</ul>',
data: {
items: [{ name: 'foo' }, { name: 'bar' }, { name: 'baz' }]
},
transitions: {
log: function ( t ) {
if ( t.isIntro ) {
entered += 1;
} else {
exited += 1;
}
t.complete();
}
}
});
foo = ractive.nodes.foo;
bar = ractive.nodes.bar;
baz = ractive.nodes.baz;
t.htmlEqual( fixture.innerHTML, '<ul><li id="foo">foo</li><li id="bar">bar</li><li id="baz">baz</li></ul>' );
t.equal( entered, 3 );
entered = 0;
ractive.merge( 'items', [{ name: 'foo' }, { name: 'baz' }, { name: 'bip' }], { compare: 'name' });
t.htmlEqual( fixture.innerHTML, '<ul><li id="foo">foo</li><li id="baz">baz</li><li id="bip">bip</li></ul>' );
t.equal( entered, 1 );
t.equal( exited, 1 );
t.ok( foo === ractive.nodes.foo );
t.ok( isOrphan( bar ) );
t.ok( baz === ractive.nodes.baz );
});
test( 'Merging an array of same-looking objects only adds/removes the necessary fragments if `compare` is a comparison function', function ( t ) {
var entered, exited, foo, bar, baz, ractive;
entered = 0;
exited = 0;
ractive = new Ractive({
el: fixture,
template: '<ul>{{#items}}<li id="{{name}}" intro-outro="log">{{name}}</li>{{/items}}</ul>',
data: {
items: [{ name: 'foo' }, { name: 'bar' }, { name: 'baz' }]
},
transitions: {
log: function ( t ) {
if ( t.isIntro ) {
entered += 1;
} else {
exited += 1;
}
t.complete();
}
}
});
foo = ractive.nodes.foo;
bar = ractive.nodes.bar;
baz = ractive.nodes.baz;
t.htmlEqual( fixture.innerHTML, '<ul><li id="foo">foo</li><li id="bar">bar</li><li id="baz">baz</li></ul>' );
t.equal( entered, 3 );
entered = 0;
ractive.merge( 'items', [{ name: 'foo' }, { name: 'baz' }, { name: 'bip' }], { compare: function ( item ) { return item.name; }});
t.htmlEqual( fixture.innerHTML, '<ul><li id="foo">foo</li><li id="baz">baz</li><li id="bip">bip</li></ul>' );
t.equal( entered, 1 );
t.equal( exited, 1 );
t.ok( foo === ractive.nodes.foo );
t.ok( isOrphan( bar ) );
t.ok( baz === ractive.nodes.baz );
});
test( 'If identity comparison fails, the resulting shape of the DOM is still correct', function ( t ) {
var entered, exited, foo, bar, baz, ractive;
entered = 0;
exited = 0;
ractive = new Ractive({
el: fixture,
template: '<ul>{{#items}}<li id="{{name}}" intro-outro="log">{{name}}</li>{{/items}}</ul>',
data: {
items: [{ name: 'foo' }, { name: 'bar' }, { name: 'baz' }]
},
transitions: {
log: function ( t ) {
if ( t.isIntro ) {
entered += 1;
} else {
exited += 1;
}
t.complete();
}
}
});
foo = ractive.nodes.foo;
bar = ractive.nodes.bar;
baz = ractive.nodes.baz;
t.htmlEqual( fixture.innerHTML, '<ul><li id="foo">foo</li><li id="bar">bar</li><li id="baz">baz</li></ul>' );
t.equal( entered, 3 );
entered = 0;
ractive.merge( 'items', [{ name: 'foo' }, { name: 'baz' }, { name: 'bip' }] );
t.htmlEqual( fixture.innerHTML, '<ul><li id="foo">foo</li><li id="baz">baz</li><li id="bip">bip</li></ul>' );
t.equal( entered, 3 );
t.equal( exited, 3 );
t.ok( foo !== ractive.nodes.foo );
t.ok( isOrphan( bar ) );
t.ok( baz !== ractive.nodes.baz );
});
test( 'Merging will trigger upstream updates regardless of whether items are being added/removed', function ( t ) {
var ractive = new Ractive({
el: fixture,
template: '{{items}} {{JSON.stringify(items)}}',
data: {
items: [ 'a', 'b', 'c' ]
}
});
ractive.merge( 'items', [ 'b', 'a', 'c' ]);
t.htmlEqual( fixture.innerHTML, 'b,a,c ["b","a","c"]' );
});
};
function isOrphan ( node ) {
// IE8... when you detach a node from its parent it thinks the document
// is its parent
return !node.parentNode || node.parentNode instanceof HTMLDocument;
}
});