diff --git a/src/compile/nodes/EventHandler.ts b/src/compile/nodes/EventHandler.ts index ab91eba23f..fe29c6d1fd 100644 --- a/src/compile/nodes/EventHandler.ts +++ b/src/compile/nodes/EventHandler.ts @@ -2,6 +2,7 @@ import Node from './shared/Node'; import Expression from './shared/Expression'; import Component from '../Component'; import deindent from '../../utils/deindent'; +import Block from '../render-dom/Block'; export default class EventHandler extends Node { name: string; @@ -52,8 +53,9 @@ export default class EventHandler extends Node { } } - render() { - if (this.expression) return this.expression.render(); + // TODO move this? it is specific to render-dom + render(block: Block) { + if (this.expression) return this.expression.render(block); this.component.template_references.add(this.handler_name); return `ctx.${this.handler_name}`; diff --git a/src/compile/nodes/shared/Expression.ts b/src/compile/nodes/shared/Expression.ts index 44e3ab7168..e45b282bfe 100644 --- a/src/compile/nodes/shared/Expression.ts +++ b/src/compile/nodes/shared/Expression.ts @@ -11,6 +11,7 @@ import sanitize from '../../../utils/sanitize'; import TemplateScope from './TemplateScope'; import getObject from '../../../utils/getObject'; import { nodes_match } from '../../../utils/nodes_match'; +import Block from '../../render-dom/Block'; const binaryOperators: Record = { '**': 15, @@ -86,13 +87,6 @@ export default class Expression { Object.defineProperties(this, { component: { value: component - }, - - // TODO remove this, is just for debugging - snippet: { - get: () => { - throw new Error(`cannot access expression.snippet, use expression.render() instead`) - } } }); @@ -181,7 +175,7 @@ export default class Expression { } // TODO move this into a render-dom wrapper? - render() { + render(block: Block) { if (this.rendered) return this.rendered; const { @@ -407,6 +401,13 @@ export default class Expression { } }); + if (declarations.length > 0) { + block.maintainContext = true; + declarations.forEach(declaration => { + block.builders.init.addBlock(declaration); + }); + } + return this.rendered = `[✂${this.node.start}-${this.node.end}✂]`; } } diff --git a/src/compile/render-dom/wrappers/AwaitBlock.ts b/src/compile/render-dom/wrappers/AwaitBlock.ts index c37bb4b1cf..ca1fdcc64e 100644 --- a/src/compile/render-dom/wrappers/AwaitBlock.ts +++ b/src/compile/render-dom/wrappers/AwaitBlock.ts @@ -125,7 +125,7 @@ export default class AwaitBlockWrapper extends Wrapper { const anchor = this.getOrCreateAnchor(block, parentNode, parentNodes); const updateMountNode = this.getUpdateMountNode(anchor); - const snippet = this.node.expression.render(); + const snippet = this.node.expression.render(block); const info = block.getUniqueName(`info`); const promise = block.getUniqueName(`promise`); diff --git a/src/compile/render-dom/wrappers/Document.ts b/src/compile/render-dom/wrappers/Document.ts index 51a7a81bcd..a87a486f6c 100644 --- a/src/compile/render-dom/wrappers/Document.ts +++ b/src/compile/render-dom/wrappers/Document.ts @@ -8,7 +8,7 @@ export default class DocumentWrapper extends Wrapper { render(block: Block, parentNode: string, parentNodes: string) { this.node.handlers.forEach(handler => { - const snippet = handler.render(); + const snippet = handler.render(block); block.builders.init.addBlock(deindent` document.addEventListener("${handler.name}", ${snippet}); diff --git a/src/compile/render-dom/wrappers/EachBlock.ts b/src/compile/render-dom/wrappers/EachBlock.ts index 2b3bd44a01..4f56a4c6c9 100644 --- a/src/compile/render-dom/wrappers/EachBlock.ts +++ b/src/compile/render-dom/wrappers/EachBlock.ts @@ -180,7 +180,7 @@ export default class EachBlockWrapper extends Wrapper { if (this.hasBinding) this.contextProps.push(`child_ctx.${this.vars.each_block_value} = list;`); if (this.hasBinding || this.node.index) this.contextProps.push(`child_ctx.${this.indexName} = i;`); - const snippet = this.node.expression.render(); + const snippet = this.node.expression.render(block); block.builders.init.addLine(`var ${this.vars.each_block_value} = ${snippet};`); diff --git a/src/compile/render-dom/wrappers/Element/Binding.ts b/src/compile/render-dom/wrappers/Element/Binding.ts index 4a2df8af70..3877d6fa04 100644 --- a/src/compile/render-dom/wrappers/Element/Binding.ts +++ b/src/compile/render-dom/wrappers/Element/Binding.ts @@ -65,7 +65,7 @@ export default class BindingWrapper { // view to model this.handler = getEventHandler(this, parent.renderer, block, this.object, contextless_snippet); - this.snippet = this.node.expression.render(); + this.snippet = this.node.expression.render(block); const type = parent.node.getStaticAttributeValue('type'); diff --git a/src/compile/render-dom/wrappers/Element/index.ts b/src/compile/render-dom/wrappers/Element/index.ts index e08c77dac4..abfef21bcc 100644 --- a/src/compile/render-dom/wrappers/Element/index.ts +++ b/src/compile/render-dom/wrappers/Element/index.ts @@ -534,7 +534,7 @@ export default class ElementWrapper extends Wrapper { : null; if (attr.isSpread) { - const snippet = attr.expression.render(); + const snippet = attr.expression.render(block); initialProps.push(snippet); @@ -584,7 +584,7 @@ export default class ElementWrapper extends Wrapper { if (intro === outro) { const name = block.getUniqueName(`${this.var}_transition`); const snippet = intro.expression - ? intro.expression.render() + ? intro.expression.render(block) : '{}'; block.addVariable(name); @@ -616,7 +616,7 @@ export default class ElementWrapper extends Wrapper { if (intro) { block.addVariable(introName); const snippet = intro.expression - ? intro.expression.render() + ? intro.expression.render(block) : '{}'; const fn = component.qualify(intro.name); // TODO add built-in transitions? @@ -639,7 +639,7 @@ export default class ElementWrapper extends Wrapper { if (outro) { block.addVariable(outroName); const snippet = outro.expression - ? outro.expression.render() + ? outro.expression.render(block) : '{}'; const fn = component.qualify(outro.name); @@ -680,7 +680,7 @@ export default class ElementWrapper extends Wrapper { ${stop_animation}(); `); - const params = this.node.animation.expression ? this.node.animation.expression.render() : '{}'; + const params = this.node.animation.expression ? this.node.animation.expression.render(block) : '{}'; const name = component.qualify(this.node.animation.name); @@ -699,7 +699,7 @@ export default class ElementWrapper extends Wrapper { const { expression, name } = classDir; let snippet, dependencies; if (expression) { - snippet = expression.render(); + snippet = expression.render(block); dependencies = expression.dependencies; } else { snippet = `${quotePropIfNecessary(name)}`; diff --git a/src/compile/render-dom/wrappers/IfBlock.ts b/src/compile/render-dom/wrappers/IfBlock.ts index 0b49412058..9ed1acddf3 100644 --- a/src/compile/render-dom/wrappers/IfBlock.ts +++ b/src/compile/render-dom/wrappers/IfBlock.ts @@ -32,7 +32,7 @@ class IfBlockBranch extends Wrapper { ) { super(renderer, block, parent, node); - this.condition = (node).expression && (node).expression.render(); + this.condition = (node).expression && (node).expression.render(block); this.block = block.child({ comment: createDebuggingComment(node, parent.renderer.component), diff --git a/src/compile/render-dom/wrappers/InlineComponent/index.ts b/src/compile/render-dom/wrappers/InlineComponent/index.ts index a5427ef073..f156ded8d5 100644 --- a/src/compile/render-dom/wrappers/InlineComponent/index.ts +++ b/src/compile/render-dom/wrappers/InlineComponent/index.ts @@ -150,7 +150,7 @@ export default class InlineComponentWrapper extends Wrapper { : null; if (attr.isSpread) { - const value = attr.expression.render(); + const value = attr.expression.render(block); initialProps.push(value); changes.push(condition ? `${condition} && ${value}` : value); @@ -238,7 +238,7 @@ export default class InlineComponentWrapper extends Wrapper { const updating = block.getUniqueName(`updating_${binding.name}`); block.addVariable(updating); - const snippet = binding.expression.render(); + const snippet = binding.expression.render(block); statements.push(deindent` if (${snippet} !== void 0) { @@ -305,13 +305,7 @@ export default class InlineComponentWrapper extends Wrapper { const munged_handlers = this.node.handlers.map(handler => { // TODO return declarations from handler.render()? - const snippet = handler.render(); - - if (handler.expression) { - handler.expression.declarations.forEach(declaration => { - block.builders.init.addBlock(declaration); - }); - } + const snippet = handler.render(block); return `${name}.$on("${handler.name}", ${snippet});`; }); @@ -320,7 +314,7 @@ export default class InlineComponentWrapper extends Wrapper { const switch_value = block.getUniqueName('switch_value'); const switch_props = block.getUniqueName('switch_props'); - const snippet = this.node.expression.render(); + const snippet = this.node.expression.render(block); block.builders.init.addBlock(deindent` var ${switch_value} = ${snippet}; diff --git a/src/compile/render-dom/wrappers/Title.ts b/src/compile/render-dom/wrappers/Title.ts index aa6268653e..733e4c845d 100644 --- a/src/compile/render-dom/wrappers/Title.ts +++ b/src/compile/render-dom/wrappers/Title.ts @@ -33,7 +33,7 @@ export default class TitleWrapper extends Wrapper { if (this.node.children.length === 1) { // single {tag} — may be a non-string const { expression } = this.node.children[0]; - value = expression.render(); + value = expression.render(block); addToSet(allDependencies, expression.dynamic_dependencies); } else { // '{foo} {bar}' — treat as string concatenation @@ -44,7 +44,7 @@ export default class TitleWrapper extends Wrapper { if (chunk.type === 'Text') { return stringify(chunk.data); } else { - const snippet = chunk.expression.render(); + const snippet = chunk.expression.render(block); chunk.expression.dynamic_dependencies.forEach(d => { allDependencies.add(d); diff --git a/src/compile/render-dom/wrappers/shared/Tag.ts b/src/compile/render-dom/wrappers/shared/Tag.ts index 8f00e1d9a9..510c2cf756 100644 --- a/src/compile/render-dom/wrappers/shared/Tag.ts +++ b/src/compile/render-dom/wrappers/shared/Tag.ts @@ -19,7 +19,7 @@ export default class Tag extends Wrapper { update: ((value: string) => string) ) { const dependencies = this.node.expression.dynamic_dependencies; - const snippet = this.node.expression.render(); + const snippet = this.node.expression.render(block); const value = this.node.shouldCache && block.getUniqueName(`${this.var}_value`); const content = this.node.shouldCache ? value : snippet; diff --git a/src/compile/render-dom/wrappers/shared/addActions.ts b/src/compile/render-dom/wrappers/shared/addActions.ts index 2749eb7820..48c2287f87 100644 --- a/src/compile/render-dom/wrappers/shared/addActions.ts +++ b/src/compile/render-dom/wrappers/shared/addActions.ts @@ -12,13 +12,10 @@ export default function addActions( actions.forEach(action => { const { expression } = action; let snippet, dependencies; + if (expression) { - snippet = expression.render(); + snippet = expression.render(block); dependencies = expression.dynamic_dependencies; - - expression.declarations.forEach(declaration => { - block.builders.init.addBlock(declaration); - }); } const name = block.getUniqueName( diff --git a/src/compile/render-dom/wrappers/shared/addEventHandlers.ts b/src/compile/render-dom/wrappers/shared/addEventHandlers.ts index e8183cdffc..140d4e35f2 100644 --- a/src/compile/render-dom/wrappers/shared/addEventHandlers.ts +++ b/src/compile/render-dom/wrappers/shared/addEventHandlers.ts @@ -7,7 +7,7 @@ export default function addEventHandlers( handlers: EventHandler[] ) { handlers.forEach(handler => { - let snippet = handler.render(); + let snippet = handler.render(block); if (handler.modifiers.has('preventDefault')) snippet = `@preventDefault(${snippet})`; if (handler.modifiers.has('stopPropagation')) snippet = `@stopPropagation(${snippet})`; @@ -26,11 +26,5 @@ export default function addEventHandlers( `@addListener(${target}, "${handler.name}", ${snippet})` ); } - - if (handler.expression) { - handler.expression.declarations.forEach(declaration => { - block.builders.init.addBlock(declaration); - }); - } }); } \ No newline at end of file diff --git a/test/runtime/samples/each-block-function/_config.js b/test/runtime/samples/each-block-function/_config.js new file mode 100644 index 0000000000..fd4095690e --- /dev/null +++ b/test/runtime/samples/each-block-function/_config.js @@ -0,0 +1,15 @@ +export default { + html: ` +

1, 2, 3

+

2, 4, 6

+

3, 6, 9

+ `, + + test({ assert, component, target }) { + component.numbers = [4, 5]; + assert.htmlEqual( target.innerHTML, ` +

16, 20

+

20, 25

+ ` ); + } +}; diff --git a/test/runtime/samples/each-block-function/main.html b/test/runtime/samples/each-block-function/main.html new file mode 100644 index 0000000000..29e4f9f71e --- /dev/null +++ b/test/runtime/samples/each-block-function/main.html @@ -0,0 +1,7 @@ +{#each numbers as i} +

{numbers.map(j => i * j).join(', ')}

+{/each} + +