|
|
|
@ -9,9 +9,9 @@ function getBranches ( generator, block, state, node ) {
|
|
|
|
|
const branches = [{
|
|
|
|
|
condition: block.contextualise( node.expression ).snippet,
|
|
|
|
|
block: node._block.name,
|
|
|
|
|
dynamic: node._block.dependencies.size > 0,
|
|
|
|
|
hasIntroTransitions: node._block.hasIntroTransitions,
|
|
|
|
|
hasOutroTransitions: node._block.hasOutroTransitions
|
|
|
|
|
hasUpdateMethod: node._block.hasUpdateMethod,
|
|
|
|
|
hasIntroMethod: node._block.hasIntroMethod,
|
|
|
|
|
hasOutroMethod: node._block.hasOutroMethod
|
|
|
|
|
}];
|
|
|
|
|
|
|
|
|
|
visitChildren( generator, block, state, node );
|
|
|
|
@ -24,9 +24,9 @@ function getBranches ( generator, block, state, node ) {
|
|
|
|
|
branches.push({
|
|
|
|
|
condition: null,
|
|
|
|
|
block: node.else ? node.else._block.name : null,
|
|
|
|
|
dynamic: node.else ? node.else._block.dependencies.size > 0 : false,
|
|
|
|
|
hasIntroTransitions: node.else ? node.else._block.hasIntroTransitions : false,
|
|
|
|
|
hasOutroTransitions: node.else ? node.else._block.hasOutroTransitions : false
|
|
|
|
|
hasUpdateMethod: node.else ? node.else._block.hasUpdateMethod : false,
|
|
|
|
|
hasIntroMethod: node.else ? node.else._block.hasIntroMethod : false,
|
|
|
|
|
hasOutroMethod: node.else ? node.else._block.hasOutroMethod : false
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if ( node.else ) {
|
|
|
|
@ -57,10 +57,15 @@ export default function visitIfBlock ( generator, block, state, node ) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const branches = getBranches( generator, block, state, node, generator.getUniqueName( `create_if_block` ) );
|
|
|
|
|
const dynamic = branches.some( branch => branch.dynamic );
|
|
|
|
|
const dynamic = branches[0].hasUpdateMethod; // can use [0] as proxy for all, since they necessarily have the same value
|
|
|
|
|
const hasOutros = branches[0].hasOutroMethod;
|
|
|
|
|
|
|
|
|
|
if ( node.else ) {
|
|
|
|
|
if ( hasOutros ) {
|
|
|
|
|
compoundWithOutros( generator, block, state, node, branches, dynamic, vars );
|
|
|
|
|
} else {
|
|
|
|
|
compound( generator, block, state, node, branches, dynamic, vars );
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
simple( generator, block, state, node, branches[0], dynamic, vars );
|
|
|
|
|
}
|
|
|
|
@ -76,7 +81,7 @@ function simple ( generator, block, state, node, branch, dynamic, { name, anchor
|
|
|
|
|
` );
|
|
|
|
|
|
|
|
|
|
const isToplevel = !state.parentNode;
|
|
|
|
|
const mountOrIntro = branch.hasIntroTransitions ? 'intro' : 'mount';
|
|
|
|
|
const mountOrIntro = branch.hasIntroMethod ? 'intro' : 'mount';
|
|
|
|
|
|
|
|
|
|
if ( isToplevel ) {
|
|
|
|
|
block.builders.mount.addLine( `if ( ${name} ) ${name}.${mountOrIntro}( ${block.target}, null );` );
|
|
|
|
@ -87,7 +92,7 @@ function simple ( generator, block, state, node, branch, dynamic, { name, anchor
|
|
|
|
|
const parentNode = state.parentNode || `${anchor}.parentNode`;
|
|
|
|
|
|
|
|
|
|
const enter = dynamic ?
|
|
|
|
|
( branch.hasIntroTransitions ?
|
|
|
|
|
( branch.hasIntroMethod ?
|
|
|
|
|
deindent`
|
|
|
|
|
if ( ${name} ) {
|
|
|
|
|
${name}.update( changed, ${params} );
|
|
|
|
@ -105,7 +110,7 @@ function simple ( generator, block, state, node, branch, dynamic, { name, anchor
|
|
|
|
|
${name}.mount( ${parentNode}, ${anchor} );
|
|
|
|
|
}
|
|
|
|
|
` ) :
|
|
|
|
|
( branch.hasIntroTransitions ?
|
|
|
|
|
( branch.hasIntroMethod ?
|
|
|
|
|
deindent`
|
|
|
|
|
if ( !${name} ) ${name} = ${branch.block}( ${params}, ${block.component} );
|
|
|
|
|
${name}.intro( ${parentNode}, ${anchor} );
|
|
|
|
@ -119,7 +124,7 @@ function simple ( generator, block, state, node, branch, dynamic, { name, anchor
|
|
|
|
|
|
|
|
|
|
// no `update()` here — we don't want to update outroing nodes,
|
|
|
|
|
// as that will typically result in glitching
|
|
|
|
|
const exit = branch.hasOutroTransitions ?
|
|
|
|
|
const exit = branch.hasOutroMethod ?
|
|
|
|
|
deindent`
|
|
|
|
|
${name}.outro( function () {
|
|
|
|
|
${name}.destroy( true );
|
|
|
|
@ -141,50 +146,128 @@ function simple ( generator, block, state, node, branch, dynamic, { name, anchor
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function compound ( generator, block, state, node, branches, dynamic, { name, anchor, params } ) {
|
|
|
|
|
const getBlock = block.getUniqueName( `get_block` );
|
|
|
|
|
const get_block = block.getUniqueName( `get_block` );
|
|
|
|
|
const current_block = block.getUniqueName( `current_block` );
|
|
|
|
|
|
|
|
|
|
block.builders.create.addBlock( deindent`
|
|
|
|
|
function ${getBlock} ( ${params} ) {
|
|
|
|
|
function ${get_block} ( ${params} ) {
|
|
|
|
|
${branches.map( ({ condition, block }) => {
|
|
|
|
|
return `${condition ? `if ( ${condition} ) ` : ''}return ${block};`;
|
|
|
|
|
} ).join( '\n' )}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var ${current_block} = ${getBlock}( ${params} );
|
|
|
|
|
var ${current_block} = ${get_block}( ${params} );
|
|
|
|
|
var ${name} = ${current_block} && ${current_block}( ${params}, ${block.component} );
|
|
|
|
|
` );
|
|
|
|
|
|
|
|
|
|
const isToplevel = !state.parentNode;
|
|
|
|
|
const mountOrIntro = branches[0].hasIntroMethod ? 'intro' : 'mount';
|
|
|
|
|
|
|
|
|
|
if ( isToplevel ) {
|
|
|
|
|
block.builders.mount.addLine( `if ( ${name} ) ${name}.mount( ${block.target}, null );` );
|
|
|
|
|
block.builders.mount.addLine( `if ( ${name} ) ${name}.${mountOrIntro}( ${block.target}, null );` );
|
|
|
|
|
} else {
|
|
|
|
|
block.builders.create.addLine( `if ( ${name} ) ${name}.mount( ${state.parentNode}, null );` );
|
|
|
|
|
block.builders.create.addLine( `if ( ${name} ) ${name}.${mountOrIntro}( ${state.parentNode}, null );` );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const parentNode = state.parentNode || `${anchor}.parentNode`;
|
|
|
|
|
|
|
|
|
|
if ( block.hasOutroTransitions ) {
|
|
|
|
|
throw new Error( 'TODO compound if-blocks with outro transitions are not yet supported' );
|
|
|
|
|
}
|
|
|
|
|
const changeBlock = deindent`
|
|
|
|
|
if ( ${name} ) ${name}.destroy( true );
|
|
|
|
|
${name} = ${current_block} && ${current_block}( ${params}, ${block.component} );
|
|
|
|
|
if ( ${name} ) ${name}.${mountOrIntro}( ${parentNode}, ${anchor} );
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
if ( dynamic ) {
|
|
|
|
|
block.builders.update.addBlock( deindent`
|
|
|
|
|
if ( ${current_block} === ( ${current_block} = ${getBlock}( ${params} ) ) && ${name} ) {
|
|
|
|
|
if ( ${current_block} === ( ${current_block} = ${get_block}( ${params} ) ) && ${name} ) {
|
|
|
|
|
${name}.update( changed, ${params} );
|
|
|
|
|
} else {
|
|
|
|
|
if ( ${name} ) ${name}.destroy( true );
|
|
|
|
|
${name} = ${current_block} && ${current_block}( ${params}, ${block.component} );
|
|
|
|
|
if ( ${name} ) ${name}.mount( ${parentNode}, ${anchor} );
|
|
|
|
|
${changeBlock}
|
|
|
|
|
}
|
|
|
|
|
` );
|
|
|
|
|
} else {
|
|
|
|
|
block.builders.update.addBlock( deindent`
|
|
|
|
|
if ( ${current_block} !== ( ${current_block} = ${getBlock}( ${params} ) ) ) {
|
|
|
|
|
if ( ${name} ) ${name}.destroy( true );
|
|
|
|
|
${name} = ${current_block} && ${current_block}( ${params}, ${block.component} );
|
|
|
|
|
if ( ${name} ) ${name}.mount( ${parentNode}, ${anchor} );
|
|
|
|
|
if ( ${current_block} !== ( ${current_block} = ${get_block}( ${params} ) ) ) {
|
|
|
|
|
${changeBlock}
|
|
|
|
|
}
|
|
|
|
|
` );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// if any of the siblings have outros, we need to keep references to the blocks
|
|
|
|
|
// (TODO does this only apply to bidi transitions?)
|
|
|
|
|
function compoundWithOutros ( generator, block, state, node, branches, dynamic, { name, anchor, params } ) {
|
|
|
|
|
const get_block = block.getUniqueName( `get_block` );
|
|
|
|
|
const current_block_index = block.getUniqueName( `current_block_index` );
|
|
|
|
|
const previous_block_index = block.getUniqueName( `previous_block_index` );
|
|
|
|
|
const if_block_creators = block.getUniqueName( `if_block_creators` );
|
|
|
|
|
const if_blocks = block.getUniqueName( `if_blocks` );
|
|
|
|
|
|
|
|
|
|
block.addVariable( current_block_index );
|
|
|
|
|
|
|
|
|
|
block.builders.create.addBlock( deindent`
|
|
|
|
|
var ${if_block_creators} = [
|
|
|
|
|
${branches.map( branch => branch.block ).join( ',\n' )}
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
var ${if_blocks} = [];
|
|
|
|
|
|
|
|
|
|
function ${get_block} ( ${params} ) {
|
|
|
|
|
${branches.map( ({ condition, block }, i ) => {
|
|
|
|
|
return `${condition ? `if ( ${condition} ) ` : ''}return ${block ? i : -1};`;
|
|
|
|
|
} ).join( '\n' )}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( ~( ${current_block_index} = ${get_block}( ${params} ) ) ) {
|
|
|
|
|
${if_blocks}[ ${current_block_index} ] = ${if_block_creators}[ ${current_block_index} ]( ${params}, ${block.component} );
|
|
|
|
|
}
|
|
|
|
|
` );
|
|
|
|
|
|
|
|
|
|
const isToplevel = !state.parentNode;
|
|
|
|
|
const mountOrIntro = branches[0].hasIntroMethod ? 'intro' : 'mount';
|
|
|
|
|
const initialTarget = isToplevel ? block.target : state.parentNode;
|
|
|
|
|
|
|
|
|
|
( isToplevel ? block.builders.mount : block.builders.create ).addBlock(
|
|
|
|
|
`if ( ~${current_block_index} ) ${if_blocks}[ ${current_block_index} ].${mountOrIntro}( ${initialTarget}, null );`
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const parentNode = state.parentNode || `${anchor}.parentNode`;
|
|
|
|
|
|
|
|
|
|
const changeBlock = deindent`
|
|
|
|
|
var ${name} = ${if_blocks}[ ${previous_block_index} ];
|
|
|
|
|
if ( ${name} ) {
|
|
|
|
|
${name}.outro( function () {
|
|
|
|
|
${if_blocks}[ ${previous_block_index} ].destroy( true );
|
|
|
|
|
${if_blocks}[ ${previous_block_index} ] = null;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( ~${current_block_index} ) {
|
|
|
|
|
${name} = ${if_blocks}[ ${current_block_index} ];
|
|
|
|
|
if ( !${name} ) {
|
|
|
|
|
${name} = ${if_blocks}[ ${current_block_index} ] = ${if_block_creators}[ ${current_block_index} ]( ${params}, ${block.component} );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
${name}.${mountOrIntro}( ${parentNode}, ${anchor} );
|
|
|
|
|
}
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
if ( dynamic ) {
|
|
|
|
|
block.builders.update.addBlock( deindent`
|
|
|
|
|
var ${previous_block_index} = ${current_block_index};
|
|
|
|
|
${current_block_index} = ${get_block}( state );
|
|
|
|
|
if ( ${current_block_index} === ${previous_block_index} ) {
|
|
|
|
|
if ( ~${current_block_index} ) ${if_blocks}[ ${current_block_index} ].update( changed, ${params} );
|
|
|
|
|
} else {
|
|
|
|
|
${changeBlock}
|
|
|
|
|
}
|
|
|
|
|
` );
|
|
|
|
|
} else {
|
|
|
|
|
block.builders.update.addBlock( deindent`
|
|
|
|
|
var ${previous_block_index} = ${current_block_index};
|
|
|
|
|
${current_block_index} = ${get_block}( state );
|
|
|
|
|
if ( ${current_block_index} !== ${previous_block_index} ) {
|
|
|
|
|
${changeBlock}
|
|
|
|
|
}
|
|
|
|
|
` );
|
|
|
|
|
}
|
|
|
|
|