mostly working list diffing algorithm

pull/568/head
Rich-Harris 8 years ago
parent 08f7321d69
commit 24c4a7c9f0

@ -110,8 +110,6 @@ export default function visitEachBlock ( generator, block, state, node ) {
} }
function keyed ( generator, block, state, node, snippet, { each_block, create_each_block, each_block_value, iterations, i, params, anchor, mountOrIntro } ) { function keyed ( generator, block, state, node, snippet, { each_block, create_each_block, each_block_value, iterations, i, params, anchor, mountOrIntro } ) {
const fragment = block.getUniqueName( 'fragment' );
const value = block.getUniqueName( 'value' );
const key = block.getUniqueName( 'key' ); const key = block.getUniqueName( 'key' );
const lookup = block.getUniqueName( `${each_block}_lookup` ); const lookup = block.getUniqueName( `${each_block}_lookup` );
const keys = block.getUniqueName( `${each_block}_keys` ); const keys = block.getUniqueName( `${each_block}_keys` );
@ -135,66 +133,72 @@ function keyed ( generator, block, state, node, snippet, { each_block, create_ea
} }
` ); ` );
const consequent = node._block.hasUpdateMethod ? const dynamic = node._block.hasUpdateMethod;
deindent`
${_iterations}[${i}] = ${lookup}[ ${key} ] = ${lookup}[ ${key} ];
${lookup}[ ${key} ].update( changed, ${params}, ${each_block_value}, ${each_block_value}[${i}], ${i} );
` :
`${_iterations}[${i}] = ${lookup}[ ${key} ] = ${lookup}[ ${key} ];`;
const parentNode = state.parentNode || `${anchor}.parentNode`; const parentNode = state.parentNode || `${anchor}.parentNode`;
const hasIntros = node._block.hasIntroMethod; let destroy;
if ( node._block.hasOutroMethod ) {
const destroy = node._block.hasOutroMethod ? const outro = block.getUniqueName( `${each_block}_outro` );
deindent` block.builders.create.addBlock( deindent`
function outro ( key ) { function ${outro} ( key ) {
${lookup}[ key ].outro( function () { ${lookup}[ key ].outro( function () {
${lookup}[ key ].destroy( true ); ${lookup}[ key ].destroy( true );
${lookup}[ key ] = null; ${lookup}[ key ] = null;
}); });
} }
` );
for ( var ${i} = 0; ${i} < ${iterations}.length; ${i} += 1 ) { destroy = `${outro}( ${key} );`;
${key} = ${iterations}[${i}].key; } else {
if ( !${keys}[ ${key} ] ) outro( ${key} ); destroy = `${iteration}.destroy( true );`;
}
` :
deindent`
for ( var ${i} = 0; ${i} < ${iterations}.length; ${i} += 1 ) {
var ${iteration} = ${iterations}[${i}];
if ( !${keys}[ ${iteration}.key ] ) ${iteration}.destroy( true );
} }
`;
block.builders.update.addBlock( deindent` block.builders.update.addBlock( deindent`
var ${each_block_value} = ${snippet}; var ${each_block_value} = ${snippet};
var ${_iterations} = []; var ${_iterations} = Array( ${each_block_value}.length );
var ${keys} = Object.create( null ); var ${keys} = Object.create( null );
var ${fragment} = document.createDocumentFragment(); var index_by_key = Object.create( null );
var key_by_index = Array( ${each_block_value}.length );
// create new iterations as necessary var new_iterations = [];
for ( var ${i} = 0; ${i} < ${each_block_value}.length; ${i} += 1 ) {
var ${value} = ${each_block_value}[${i}]; for ( ${i} = 0; ${i} < ${each_block_value}.length; ${i} += 1 ) {
var ${key} = ${value}.${node.key}; var ${key} = ${each_block_value}[${i}].${node.key};
${keys}[ ${key} ] = true; index_by_key[${key}] = ${i};
key_by_index[${i}] = ${key};
if ( ${lookup}[ ${key} ] ) { if ( ${lookup}[ ${key} ] ) {
${consequent} // TODO this is an empty branch for non-dynamic blocks
${hasIntros && `${_iterations}[${i}].mount( ${fragment}, null );`} ${dynamic && `${lookup}[ ${key} ].update( changed, ${params}, ${each_block_value}, ${each_block_value}[${i}], ${i} );`}
} else { } else {
${_iterations}[${i}] = ${lookup}[ ${key} ] = ${create_each_block}( ${params}, ${each_block_value}, ${each_block_value}[${i}], ${i}, ${block.component}, ${key} ); ${lookup}[ ${key} ] = ${create_each_block}( ${params}, ${each_block_value}, ${each_block_value}[${i}], ${i}, ${block.component}, ${key} );
${hasIntros && `${_iterations}[${i}].intro( ${fragment}, null );`} new_iterations.push( ${lookup}[ ${key} ] );
} }
${!hasIntros && `${_iterations}[${i}].mount( ${fragment}, null );`} ${_iterations}[${i}] = ${lookup}[ ${key} ];
} }
// remove old iterations // TODO group consecutive runs into fragments?
${destroy} ${i} = new_iterations.length;
while ( ${i}-- ) {
${iteration} = new_iterations[${i}];
var index = index_by_key[${iteration}.key];
var next_sibling_key = key_by_index[index + 1];
${iteration}.${mountOrIntro}( ${parentNode}, next_sibling_key === undefined ? ${anchor} : ${lookup}[next_sibling_key].first );
}
${parentNode}.insertBefore( ${fragment}, ${anchor} ); for ( ${i} = 0; ${i} < ${iterations}.length; ${i} += 1 ) {
var ${iteration} = ${iterations}[${i}];
var index = index_by_key[${iteration}.key];
if ( index === undefined ) {
${destroy}
} else {
var next_sibling_key = key_by_index[index + 1];
${iteration}.mount( ${parentNode}, next_sibling_key === undefined ? ${anchor} : ${lookup}[next_sibling_key].first );
}
}
${iterations} = ${_iterations}; ${iterations} = ${_iterations};
` ); ` );

Loading…
Cancel
Save