refactor IfBlock slightly

pull/1193/head
Rich Harris 8 years ago
parent c6bba03f1d
commit da155878a8

@ -101,7 +101,7 @@ export default class IfBlock extends Node {
? block.getUniqueName(`${name}_anchor`)
: (this.next && this.next.var) || 'null';
const branches = getBranches(this.generator, block, parentNode, parentNodes, this);
const branches = this.getBranches(block, parentNode, parentNodes, this);
const hasElse = isElseBranch(branches[branches.length - 1]);
const if_name = hasElse ? '' : `if (${name}) `;
@ -113,21 +113,12 @@ export default class IfBlock extends Node {
if (this.else) {
if (hasOutros) {
compoundWithOutros(
this.generator,
block,
parentNode,
parentNodes,
this,
branches,
dynamic,
vars
);
this.buildCompoundWithOutros(block, parentNode, parentNodes, branches, dynamic, vars);
} else {
compound(this.generator, block, parentNode, parentNodes, this, branches, dynamic, vars);
this.buildCompound(block, parentNode, parentNodes, branches, dynamic, vars);
}
} else {
simple(this.generator, block, parentNode, parentNodes, this, branches[0], dynamic, vars);
this.buildSimple(block, parentNode, parentNodes, branches[0], dynamic, vars);
}
block.builders.create.addLine(`${if_name}${name}.c();`);
@ -147,173 +138,20 @@ export default class IfBlock extends Node {
);
}
}
}
// TODO move all this into the class
function getBranches(
generator: DomGenerator,
block: Block,
parentNode: string,
parentNodes: string,
node: Node
) {
block.contextualise(node.expression); // TODO remove
const branches = [
{
condition: node.metadata.snippet,
block: node.block.name,
hasUpdateMethod: node.block.hasUpdateMethod,
hasIntroMethod: node.block.hasIntroMethod,
hasOutroMethod: node.block.hasOutroMethod,
},
];
visitChildren(generator, block, node);
if (isElseIf(node.else)) {
branches.push(
...getBranches(generator, block, parentNode, parentNodes, node.else.children[0])
);
} else {
branches.push({
condition: null,
block: node.else ? node.else.block.name : null,
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) {
visitChildren(generator, block, node.else);
}
}
return branches;
}
function visitChildren(
generator: DomGenerator,
block: Block,
node: Node
) {
node.children.forEach((child: Node) => {
child.build(node.block, null, 'nodes');
});
}
function simple(
generator: DomGenerator,
buildCompound(
block: Block,
parentNode: string,
parentNodes: string,
node: Node,
branch,
dynamic,
{ name, anchor, if_name }
) {
block.builders.init.addBlock(deindent`
var ${name} = (${branch.condition}) && ${branch.block}(#component, state);
`);
const mountOrIntro = branch.hasIntroMethod ? 'i' : 'm';
const initialMountNode = parentNode || '#target';
const anchorNode = parentNode ? 'null' : 'anchor';
block.builders.mount.addLine(
`if (${name}) ${name}.${mountOrIntro}(${initialMountNode}, ${anchorNode});`
);
const updateMountNode = node.getUpdateMountNode(anchor);
const enter = dynamic
? branch.hasIntroMethod
? deindent`
if (${name}) {
${name}.p(changed, state);
} else {
${name} = ${branch.block}(#component, state);
if (${name}) ${name}.c();
}
${name}.i(${updateMountNode}, ${anchor});
`
: deindent`
if (${name}) {
${name}.p(changed, state);
} else {
${name} = ${branch.block}(#component, state);
${name}.c();
${name}.m(${updateMountNode}, ${anchor});
}
`
: branch.hasIntroMethod
? deindent`
if (!${name}) {
${name} = ${branch.block}(#component, state);
${name}.c();
}
${name}.i(${updateMountNode}, ${anchor});
`
: deindent`
if (!${name}) {
${name} = ${branch.block}(#component, state);
${name}.c();
${name}.m(${updateMountNode}, ${anchor});
}
`;
// no `p()` here — we don't want to update outroing nodes,
// as that will typically result in glitching
const exit = branch.hasOutroMethod
? deindent`
${name}.o(function() {
${name}.u();
${name}.d();
${name} = null;
});
`
: deindent`
${name}.u();
${name}.d();
${name} = null;
`;
block.builders.update.addBlock(deindent`
if (${branch.condition}) {
${enter}
} else if (${name}) {
${exit}
}
`);
block.builders.unmount.addLine(`${if_name}${name}.u();`);
block.builders.destroy.addLine(`${if_name}${name}.d();`);
}
function compound(
generator: DomGenerator,
block: Block,
parentNode: string,
parentNodes: string,
node: Node,
branches,
dynamic,
{ name, anchor, hasElse, if_name }
) {
const select_block_type = generator.getUniqueName(`select_block_type`);
const select_block_type = this.generator.getUniqueName(`select_block_type`);
const current_block_type = block.getUniqueName(`current_block_type`);
const current_block_type_and = hasElse ? '' : `${current_block_type} && `;
generator.blocks.push(deindent`
this.generator.blocks.push(deindent`
function ${select_block_type}(state) {
${branches
.map(({ condition, block }) => `${condition ? `if (${condition}) ` : ''}return ${block};`)
@ -334,7 +172,7 @@ function compound(
`${if_name}${name}.${mountOrIntro}(${initialMountNode}, ${anchorNode});`
);
const updateMountNode = node.getUpdateMountNode(anchor);
const updateMountNode = this.getUpdateMountNode(anchor);
const changeBlock = deindent`
${hasElse
@ -375,12 +213,10 @@ function compound(
// 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: DomGenerator,
buildCompoundWithOutros(
block: Block,
parentNode: string,
parentNodes: string,
node: Node,
branches,
dynamic,
{ name, anchor, hasElse }
@ -433,7 +269,7 @@ function compoundWithOutros(
`${if_current_block_type_index}${if_blocks}[${current_block_type_index}].${mountOrIntro}(${initialMountNode}, ${anchorNode});`
);
const updateMountNode = node.getUpdateMountNode(anchor);
const updateMountNode = this.getUpdateMountNode(anchor);
const destroyOldBlock = deindent`
${name}.o(function() {
@ -497,3 +333,139 @@ function compoundWithOutros(
}
`);
}
buildSimple(
block: Block,
parentNode: string,
parentNodes: string,
branch,
dynamic,
{ name, anchor, if_name }
) {
block.builders.init.addBlock(deindent`
var ${name} = (${branch.condition}) && ${branch.block}(#component, state);
`);
const mountOrIntro = branch.hasIntroMethod ? 'i' : 'm';
const initialMountNode = parentNode || '#target';
const anchorNode = parentNode ? 'null' : 'anchor';
block.builders.mount.addLine(
`if (${name}) ${name}.${mountOrIntro}(${initialMountNode}, ${anchorNode});`
);
const updateMountNode = this.getUpdateMountNode(anchor);
const enter = dynamic
? branch.hasIntroMethod
? deindent`
if (${name}) {
${name}.p(changed, state);
} else {
${name} = ${branch.block}(#component, state);
if (${name}) ${name}.c();
}
${name}.i(${updateMountNode}, ${anchor});
`
: deindent`
if (${name}) {
${name}.p(changed, state);
} else {
${name} = ${branch.block}(#component, state);
${name}.c();
${name}.m(${updateMountNode}, ${anchor});
}
`
: branch.hasIntroMethod
? deindent`
if (!${name}) {
${name} = ${branch.block}(#component, state);
${name}.c();
}
${name}.i(${updateMountNode}, ${anchor});
`
: deindent`
if (!${name}) {
${name} = ${branch.block}(#component, state);
${name}.c();
${name}.m(${updateMountNode}, ${anchor});
}
`;
// no `p()` here — we don't want to update outroing nodes,
// as that will typically result in glitching
const exit = branch.hasOutroMethod
? deindent`
${name}.o(function() {
${name}.u();
${name}.d();
${name} = null;
});
`
: deindent`
${name}.u();
${name}.d();
${name} = null;
`;
block.builders.update.addBlock(deindent`
if (${branch.condition}) {
${enter}
} else if (${name}) {
${exit}
}
`);
block.builders.unmount.addLine(`${if_name}${name}.u();`);
block.builders.destroy.addLine(`${if_name}${name}.d();`);
}
getBranches(
block: Block,
parentNode: string,
parentNodes: string,
node: Node
) {
block.contextualise(node.expression); // TODO remove
const branches = [
{
condition: node.metadata.snippet,
block: node.block.name,
hasUpdateMethod: node.block.hasUpdateMethod,
hasIntroMethod: node.block.hasIntroMethod,
hasOutroMethod: node.block.hasOutroMethod,
},
];
this.visitChildren(block, node);
if (isElseIf(node.else)) {
branches.push(
...this.getBranches(block, parentNode, parentNodes, node.else.children[0])
);
} else {
branches.push({
condition: null,
block: node.else ? node.else.block.name : null,
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) {
this.visitChildren(block, node.else);
}
}
return branches;
}
visitChildren(block: Block, node: Node) {
node.children.forEach((child: Node) => {
child.build(node.block, null, 'nodes');
});
}
}
Loading…
Cancel
Save