From 73321465c126a44a515a2be89b098e270dade668 Mon Sep 17 00:00:00 2001 From: Maxim Matyunin Date: Sun, 4 Aug 2019 20:49:35 +0900 Subject: [PATCH 1/4] on:* --- src/compiler/compile/nodes/EventHandler.ts | 2 +- src/compiler/compile/render_dom/Block.ts | 15 +++++++++++++++ .../wrappers/shared/add_event_handlers.ts | 6 ++++++ src/runtime/internal/Component.ts | 10 ++++++++++ 4 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/compiler/compile/nodes/EventHandler.ts b/src/compiler/compile/nodes/EventHandler.ts index 0c65e463ba..0f9ff0dfd9 100644 --- a/src/compiler/compile/nodes/EventHandler.ts +++ b/src/compiler/compile/nodes/EventHandler.ts @@ -17,7 +17,7 @@ export default class EventHandler extends Node { constructor(component: Component, parent, template_scope, info) { super(component, parent, template_scope, info); - this.name = info.name; + this.name = info.name !== '*' ? info.name : 'any'; this.modifiers = new Set(info.modifiers); if (info.expression) { diff --git a/src/compiler/compile/render_dom/Block.ts b/src/compiler/compile/render_dom/Block.ts index 59beae1a39..a9a0eee8c7 100644 --- a/src/compiler/compile/render_dom/Block.ts +++ b/src/compiler/compile/render_dom/Block.ts @@ -45,6 +45,7 @@ export default class Block { }; event_listeners: string[] = []; + any_event_elements: string[] = []; maintain_context: boolean; has_animation: boolean; @@ -325,6 +326,20 @@ export default class Block { `); } + if (this.variables.size > 0) { + const listens = Array.from(this.variables.keys()) + .filter(key => this.any_event_elements.includes(key)) + .join(', '); + + if (listens.length > 0) { + properties.add_block(deindent` + ${method_name('bbl', 'bubble')}() { + return [listen, [${listens}]]; + }, + `); + } + } + if (this.has_intro_method || this.has_outro_method) { if (this.builders.intro.is_empty()) { properties.add_line(`i: @noop,`); diff --git a/src/compiler/compile/render_dom/wrappers/shared/add_event_handlers.ts b/src/compiler/compile/render_dom/wrappers/shared/add_event_handlers.ts index 6b7e62d212..9cc24836af 100644 --- a/src/compiler/compile/render_dom/wrappers/shared/add_event_handlers.ts +++ b/src/compiler/compile/render_dom/wrappers/shared/add_event_handlers.ts @@ -21,6 +21,12 @@ export default function add_event_handlers( block.event_listeners.push( `@listen(${target}, "${handler.name}", ${snippet}, ${opts_string})` ); + } else if (handler.name === 'any') { + block.any_event_elements.push(target); + // This isn't required but listen is treeshaken otherwise + block.event_listeners.push( + `@listen(${target}, "${handler.name}", ${snippet})` + ); } else { block.event_listeners.push( `@listen(${target}, "${handler.name}", ${snippet})` diff --git a/src/runtime/internal/Component.ts b/src/runtime/internal/Component.ts index 92e227e57c..79d89c2428 100644 --- a/src/runtime/internal/Component.ts +++ b/src/runtime/internal/Component.ts @@ -43,6 +43,16 @@ export function mount_component(component, target, anchor) { run_all(new_on_destroy); } component.$$.on_mount = []; + + if (fragment.bbl) { + Object.keys(component.$$.callbacks).forEach(type => { + if (!component.$$.ctx[`${type}_handler`]) { + const [listen, els] = fragment.bbl(); + + els.forEach(el => component.$$.callbacks[type].forEach(cb => listen(el, type, cb))); + } + }); + } }); after_update.forEach(add_render_callback); From 0b9928476f17c788a889c950ad6e733e5c933454 Mon Sep 17 00:00:00 2001 From: Maxim Matyunin Date: Sun, 4 Aug 2019 22:06:41 +0900 Subject: [PATCH 2/4] any -> $$any --- src/compiler/compile/nodes/EventHandler.ts | 14 ++++++++------ .../wrappers/shared/add_event_handlers.ts | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/compiler/compile/nodes/EventHandler.ts b/src/compiler/compile/nodes/EventHandler.ts index 0f9ff0dfd9..6cf867daa5 100644 --- a/src/compiler/compile/nodes/EventHandler.ts +++ b/src/compiler/compile/nodes/EventHandler.ts @@ -17,7 +17,7 @@ export default class EventHandler extends Node { constructor(component: Component, parent, template_scope, info) { super(component, parent, template_scope, info); - this.name = info.name !== '*' ? info.name : 'any'; + this.name = info.name !== '*' ? info.name : '$$any'; this.modifiers = new Set(info.modifiers); if (info.expression) { @@ -50,11 +50,13 @@ export default class EventHandler extends Node { referenced: true }); - component.partly_hoisted.push(deindent` - function ${name}(event) { - @bubble($$self, event); - } - `); + if (this.name !== '$$any') { + component.partly_hoisted.push(deindent` + function ${name}(event) { + @bubble($$self, event); + } + `); + } this.handler_name = name; } diff --git a/src/compiler/compile/render_dom/wrappers/shared/add_event_handlers.ts b/src/compiler/compile/render_dom/wrappers/shared/add_event_handlers.ts index 9cc24836af..cf46366ca2 100644 --- a/src/compiler/compile/render_dom/wrappers/shared/add_event_handlers.ts +++ b/src/compiler/compile/render_dom/wrappers/shared/add_event_handlers.ts @@ -21,7 +21,7 @@ export default function add_event_handlers( block.event_listeners.push( `@listen(${target}, "${handler.name}", ${snippet}, ${opts_string})` ); - } else if (handler.name === 'any') { + } else if (handler.name === '$$any') { block.any_event_elements.push(target); // This isn't required but listen is treeshaken otherwise block.event_listeners.push( From 3825b9e9a4ee49c327d4a346c2f78eaddb95ec48 Mon Sep 17 00:00:00 2001 From: Maxim Matyunin Date: Sun, 4 Aug 2019 22:15:10 +0900 Subject: [PATCH 3/4] fix for any event --- src/compiler/compile/nodes/EventHandler.ts | 12 ++++++------ .../render_dom/wrappers/shared/add_event_handlers.ts | 4 +--- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/compiler/compile/nodes/EventHandler.ts b/src/compiler/compile/nodes/EventHandler.ts index 6cf867daa5..144a3a97ca 100644 --- a/src/compiler/compile/nodes/EventHandler.ts +++ b/src/compiler/compile/nodes/EventHandler.ts @@ -44,13 +44,13 @@ export default class EventHandler extends Node { } else { const name = component.get_unique_name(`${sanitize(this.name)}_handler`); - component.add_var({ - name, - internal: true, - referenced: true - }); - if (this.name !== '$$any') { + component.add_var({ + name, + internal: true, + referenced: true + }); + component.partly_hoisted.push(deindent` function ${name}(event) { @bubble($$self, event); diff --git a/src/compiler/compile/render_dom/wrappers/shared/add_event_handlers.ts b/src/compiler/compile/render_dom/wrappers/shared/add_event_handlers.ts index cf46366ca2..862f02b674 100644 --- a/src/compiler/compile/render_dom/wrappers/shared/add_event_handlers.ts +++ b/src/compiler/compile/render_dom/wrappers/shared/add_event_handlers.ts @@ -24,9 +24,7 @@ export default function add_event_handlers( } else if (handler.name === '$$any') { block.any_event_elements.push(target); // This isn't required but listen is treeshaken otherwise - block.event_listeners.push( - `@listen(${target}, "${handler.name}", ${snippet})` - ); + block.event_listeners.push(`@listen`); } else { block.event_listeners.push( `@listen(${target}, "${handler.name}", ${snippet})` From 085a97c9f2336f835a25841a01e2497cb8672d18 Mon Sep 17 00:00:00 2001 From: Maxim Matyunin Date: Mon, 5 Aug 2019 12:31:59 +0900 Subject: [PATCH 4/4] push bubbles for if/each blocks --- src/compiler/compile/render_dom/Block.ts | 6 ++++- .../compile/render_dom/wrappers/EachBlock.ts | 4 ++++ .../compile/render_dom/wrappers/IfBlock.ts | 4 ++++ src/runtime/ambient.ts | 1 + src/runtime/internal/Component.ts | 24 +++++++++++-------- src/runtime/internal/scheduler.ts | 4 +++- 6 files changed, 31 insertions(+), 12 deletions(-) diff --git a/src/compiler/compile/render_dom/Block.ts b/src/compiler/compile/render_dom/Block.ts index a9a0eee8c7..763fa4e208 100644 --- a/src/compiler/compile/render_dom/Block.ts +++ b/src/compiler/compile/render_dom/Block.ts @@ -35,6 +35,7 @@ export default class Block { claim: CodeBuilder; hydrate: CodeBuilder; mount: CodeBuilder; + bubble: CodeBuilder; measure: CodeBuilder; fix: CodeBuilder; animate: CodeBuilder; @@ -84,6 +85,7 @@ export default class Block { claim: new CodeBuilder(), hydrate: new CodeBuilder(), mount: new CodeBuilder(), + bubble: new CodeBuilder(), measure: new CodeBuilder(), fix: new CodeBuilder(), animate: new CodeBuilder(), @@ -334,7 +336,9 @@ export default class Block { if (listens.length > 0) { properties.add_block(deindent` ${method_name('bbl', 'bubble')}() { - return [listen, [${listens}]]; + let bubbles = [${listens}]; + ${this.builders.bubble} + return bubbles; }, `); } diff --git a/src/compiler/compile/render_dom/wrappers/EachBlock.ts b/src/compiler/compile/render_dom/wrappers/EachBlock.ts index 42792efce7..28f30cbc58 100644 --- a/src/compiler/compile/render_dom/wrappers/EachBlock.ts +++ b/src/compiler/compile/render_dom/wrappers/EachBlock.ts @@ -218,6 +218,10 @@ export default class EachBlockWrapper extends Wrapper { `); } + block.builders.bubble.add_block(deindent` + for (#i = 0; #i < ${this.vars.data_length}; #i += 1) bubbles.push(...${this.vars.iterations}[#i].bbl()); + `); + if (needs_anchor) { block.add_element( update_anchor_node, diff --git a/src/compiler/compile/render_dom/wrappers/IfBlock.ts b/src/compiler/compile/render_dom/wrappers/IfBlock.ts index fe870df862..351d16e5c3 100644 --- a/src/compiler/compile/render_dom/wrappers/IfBlock.ts +++ b/src/compiler/compile/render_dom/wrappers/IfBlock.ts @@ -431,6 +431,10 @@ export default class IfBlockWrapper extends Wrapper { } `; + block.builders.bubble.add_line( + `if (${name}) bubbles.push(...${name}.bbl());` + ); + // no `p()` here — we don't want to update outroing nodes, // as that will typically result in glitching if (branch.block.has_outro_method) { diff --git a/src/runtime/ambient.ts b/src/runtime/ambient.ts index b094056c59..28e55686fe 100644 --- a/src/runtime/ambient.ts +++ b/src/runtime/ambient.ts @@ -13,6 +13,7 @@ declare module '*.svelte' { $set(props: Props): void; $on(event: string, callback: (event: CustomEvent) => void): () => void; $destroy(): void; + $bubble(): void; [accessor: string]: any; } diff --git a/src/runtime/internal/Component.ts b/src/runtime/internal/Component.ts index 79d89c2428..d61a04d72d 100644 --- a/src/runtime/internal/Component.ts +++ b/src/runtime/internal/Component.ts @@ -1,7 +1,7 @@ import { add_render_callback, flush, schedule_update, dirty_components } from './scheduler'; import { current_component, set_current_component } from './lifecycle'; import { blank_object, is_function, run, run_all, noop } from './utils'; -import { children } from './dom'; +import { children, listen } from './dom'; import { transition_in } from './transitions'; // eslint-disable-next-line @typescript-eslint/class-name-casing @@ -27,6 +27,18 @@ export function bind(component, name, callback) { callback(component.$$.ctx[name]); } +function attach_any_listeners($$) { + $$.bubble = () => Object.keys($$.callbacks).forEach(type => { + if ($$.ctx[`${type}_handler`]) return; + + $$.fragment.bbl().forEach(el => { + $$.callbacks[type].forEach(cb => listen(el, type, cb)); + }); + }); + + $$.bubble(); +} + export function mount_component(component, target, anchor) { const { fragment, on_mount, on_destroy, after_update } = component.$$; @@ -44,15 +56,7 @@ export function mount_component(component, target, anchor) { } component.$$.on_mount = []; - if (fragment.bbl) { - Object.keys(component.$$.callbacks).forEach(type => { - if (!component.$$.ctx[`${type}_handler`]) { - const [listen, els] = fragment.bbl(); - - els.forEach(el => component.$$.callbacks[type].forEach(cb => listen(el, type, cb))); - } - }); - } + if (fragment.bbl) attach_any_listeners(component.$$); }); after_update.forEach(add_render_callback); diff --git a/src/runtime/internal/scheduler.ts b/src/runtime/internal/scheduler.ts index e3d7181fcb..66ca63143c 100644 --- a/src/runtime/internal/scheduler.ts +++ b/src/runtime/internal/scheduler.ts @@ -76,6 +76,8 @@ function update($$) { $$.fragment.p($$.dirty, $$.ctx); $$.dirty = null; + $$.bubble && $$.bubble(); + $$.after_update.forEach(add_render_callback); } -} +} \ No newline at end of file