ractive
Version:
Next-generation DOM manipulation
104 lines (80 loc) • 2.44 kB
JavaScript
import runloop from 'global/runloop';
import circular from 'circular';
var Fragment;
circular.push( function () {
Fragment = circular.Fragment;
});
export default function Section$merge ( newIndices ) {
var section = this,
parentFragment,
firstChange,
i,
newLength,
reboundFragments,
fragmentOptions,
fragment,
nextNode;
parentFragment = this.parentFragment;
reboundFragments = [];
// first, rebind existing fragments
newIndices.forEach( function rebindIfNecessary ( newIndex, oldIndex ) {
var fragment, by, oldKeypath, newKeypath;
if ( newIndex === oldIndex ) {
reboundFragments[ newIndex ] = section.fragments[ oldIndex ];
return;
}
fragment = section.fragments[ oldIndex ];
if ( firstChange === undefined ) {
firstChange = oldIndex;
}
// does this fragment need to be torn down?
if ( newIndex === -1 ) {
section.fragmentsToUnrender.push( fragment );
fragment.unbind();
return;
}
// Otherwise, it needs to be rebound to a new index
by = newIndex - oldIndex;
oldKeypath = section.keypath + '.' + oldIndex;
newKeypath = section.keypath + '.' + newIndex;
fragment.rebind( section.template.i, newIndex, oldKeypath, newKeypath );
reboundFragments[ newIndex ] = fragment;
});
// If nothing changed with the existing fragments, then we start adding
// new fragments at the end...
if ( firstChange === undefined ) {
firstChange = this.length;
}
this.length = this.fragments.length = newLength = this.root.get( this.keypath ).length;
if ( newLength === firstChange ) {
// ...unless there are no new fragments to add
return;
}
runloop.addView( this );
// Prepare new fragment options
fragmentOptions = {
template: this.template.f,
root: this.root,
owner: this
};
if ( this.template.i ) {
fragmentOptions.indexRef = this.template.i;
}
// Add as many new fragments as we need to, or add back existing
// (detached) fragments
for ( i = firstChange; i < newLength; i += 1 ) {
// is this an existing fragment?
if ( fragment = reboundFragments[i] ) {
this.docFrag.appendChild( fragment.detach( false ) );
}
else {
// Fragment will be created when changes are applied
// by the runloop
this.fragmentsToCreate.push( i );
}
this.fragments[i] = fragment;
}
// reinsert fragment
nextNode = parentFragment.findNextNode( this );
this.parentFragment.getNode().insertBefore( this.docFrag, nextNode );
}