svelte/src/generators/dom/visitors/IfBlock.js

149 lines
4.6 KiB

import deindent from '../../../utils/deindent.js';
import visit from '../visit.js';
function isElseIf ( node ) {
return node && node.children.length === 1 && node.children[0].type === 'IfBlock';
}
function getBranches ( generator, block, state, node ) {
const branches = [{
condition: block.contextualise( node.expression ).snippet,
block: node._block.name,
dynamic: node._block.dependencies.size > 0
}];
visitChildren( generator, block, state, node );
if ( isElseIf( node.else ) ) {
branches.push(
...getBranches( generator, block, state, node.else.children[0] )
);
} else {
branches.push({
condition: null,
block: node.else ? node.else._block.name : null,
dynamic: node.else ? node.else._block.dependencies.size > 0 : false
});
if ( node.else ) {
visitChildren( generator, block, state, node.else );
}
}
return branches;
}
function visitChildren ( generator, block, state, node ) {
node.children.forEach( child => {
visit( generator, node._block, node._state, child );
});
}
export default function visitIfBlock ( generator, block, state, node ) {
const name = generator.getUniqueName( `if_block` );
const anchor = generator.getUniqueName( `${name}_anchor` );
const params = block.params.join( ', ' );
const vars = { name, anchor, params };
block.createAnchor( anchor, state.parentNode );
const branches = getBranches( generator, block, state, node, generator.getUniqueName( `create_if_block` ) );
const dynamic = branches.some( branch => branch.dynamic );
if ( node.else ) {
compound( generator, block, state, node, branches, dynamic, vars );
} else {
simple( generator, block, state, node, branches[0], dynamic, vars );
}
block.builders.destroy.addLine(
`if ( ${name} ) ${name}.destroy( ${state.parentNode ? 'false' : 'detach'} );`
);
}
function simple ( generator, block, state, node, branch, dynamic, { name, anchor, params } ) {
block.builders.create.addBlock( deindent`
var ${name} = ${branch.condition} && ${branch.block}( ${params}, ${block.component} );
` );
const isToplevel = !state.parentNode;
if ( isToplevel ) {
block.builders.mount.addLine( `if ( ${name} ) ${name}.mount( ${block.target}, ${anchor} );` );
} else {
block.builders.create.addLine( `if ( ${name} ) ${name}.mount( ${state.parentNode}, null );` );
}
if ( dynamic ) {
block.builders.update.addBlock( deindent`
if ( ${branch.condition} ) {
if ( ${name} ) {
${name}.update( changed, ${params} );
} else {
${name} = ${branch.block}( ${params}, ${block.component} );
${name}.mount( ${anchor}.parentNode, ${anchor} );
}
} else if ( ${name} ) {
${name}.destroy( true );
${name} = null;
}
` );
} else {
block.builders.update.addBlock( deindent`
if ( ${branch.condition} ) {
if ( !${name} ) {
${name} = ${branch.block}( ${params}, ${block.component} );
${name}.mount( ${anchor}.parentNode, ${anchor} );
}
} else if ( ${name} ) {
${name}.destroy( true );
${name} = null;
}
` );
}
}
function compound ( generator, block, state, node, branches, dynamic, { name, anchor, params } ) {
const getBlock = block.getUniqueName( `get_block` );
const current_block = block.getUniqueName( `current_block` );
block.builders.create.addBlock( deindent`
function ${getBlock} ( ${params} ) {
${branches.map( ({ condition, block }) => {
return `${condition ? `if ( ${condition} ) ` : ''}return ${block};`;
} ).join( '\n' )}
}
var ${current_block} = ${getBlock}( ${params} );
var ${name} = ${current_block} && ${current_block}( ${params}, ${block.component} );
` );
const isToplevel = !state.parentNode;
if ( isToplevel ) {
block.builders.mount.addLine( `if ( ${name} ) ${name}.mount( ${block.target}, ${anchor} );` );
} else {
block.builders.create.addLine( `if ( ${name} ) ${name}.mount( ${state.parentNode}, null );` );
}
if ( dynamic ) {
block.builders.update.addBlock( deindent`
if ( ${current_block} === ( ${current_block} = ${getBlock}( ${params} ) ) && ${name} ) {
${name}.update( changed, ${params} );
} else {
if ( ${name} ) ${name}.destroy( true );
${name} = ${current_block} && ${current_block}( ${params}, ${block.component} );
if ( ${name} ) ${name}.mount( ${anchor}.parentNode, ${anchor} );
}
` );
} 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( ${anchor}.parentNode, ${anchor} );
}
` );
}
}