Skip to content

Commit 0ee7cb2

Browse files
author
Timothy Johnson
committed
Mechanism for bubbling all events. Closes #2837
1 parent a1b0295 commit 0ee7cb2

File tree

85 files changed

+239
-36
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

85 files changed

+239
-36
lines changed

src/compiler/compile/nodes/EventHandler.ts

-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import Node from './shared/Node';
22
import Expression from './shared/Expression';
33
import Component from '../Component';
4-
import { sanitize } from '../../utils/names';
54
import { Identifier } from 'estree';
65

76
export default class EventHandler extends Node {
@@ -42,8 +41,6 @@ export default class EventHandler extends Node {
4241
}
4342
}
4443
}
45-
} else {
46-
this.handler_name = component.get_unique_name(`${sanitize(this.name)}_handler`);
4744
}
4845
}
4946

src/compiler/compile/render_dom/Block.ts

+49-15
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ export default class Block {
5252
claim: Array<Node | Node[]>;
5353
hydrate: Array<Node | Node[]>;
5454
mount: Array<Node | Node[]>;
55+
bubble: Array<Node | Node[]>;
5556
measure: Array<Node | Node[]>;
5657
fix: Array<Node | Node[]>;
5758
animate: Array<Node | Node[]>;
@@ -100,6 +101,7 @@ export default class Block {
100101
claim: [],
101102
hydrate: [],
102103
mount: [],
104+
bubble: [],
103105
measure: [],
104106
fix: [],
105107
animate: [],
@@ -292,9 +294,39 @@ export default class Block {
292294
}`;
293295
}
294296

297+
if (this.chunks.bubble.length === 0) {
298+
properties.bubble = noop;
299+
} else {
300+
const mounted: Identifier = {
301+
type: 'Identifier',
302+
name: '#mounted'
303+
};
304+
this.add_variable(mounted, x`false`);
305+
const bubble_fns: Identifier = {
306+
type: 'Identifier',
307+
name: '#bubble_fns'
308+
};
309+
this.add_variable(bubble_fns, x`[]`);
310+
311+
properties.bubble = x`function #bubble(type, callback) {
312+
const local_dispose = [];
313+
const fn = () => {
314+
${this.chunks.bubble}
315+
#dispose.push(...local_dispose);
316+
}
317+
if (${mounted}) fn()
318+
else ${bubble_fns}.push(fn);
319+
return () => @run_all(local_dispose);
320+
}`;
321+
this.chunks.mount.push(b`
322+
${mounted} = true;
323+
@run_all(${bubble_fns});
324+
`);
325+
}
326+
295327
if (this.chunks.mount.length === 0) {
296328
properties.mount = noop;
297-
} else if (this.event_listeners.length === 0) {
329+
} else if (this.event_listeners.length === 0 && this.chunks.bubble.length === 0) {
298330
properties.mount = x`function #mount(#target, #anchor) {
299331
${this.chunks.mount}
300332
}`;
@@ -378,6 +410,7 @@ export default class Block {
378410
l: ${properties.claim},
379411
h: ${properties.hydrate},
380412
m: ${properties.mount},
413+
b: ${properties.bubble},
381414
p: ${properties.update},
382415
r: ${properties.measure},
383416
f: ${properties.fix},
@@ -428,6 +461,7 @@ export default class Block {
428461
this.chunks.hydrate.length > 0 ||
429462
this.chunks.claim.length > 0 ||
430463
this.chunks.mount.length > 0 ||
464+
this.chunks.bubble.length > 0 ||
431465
this.chunks.update.length > 0 ||
432466
this.chunks.destroy.length > 0 ||
433467
this.has_animation;
@@ -451,15 +485,26 @@ export default class Block {
451485
}
452486

453487
render_listeners(chunk: string = '') {
454-
if (this.event_listeners.length > 0) {
488+
if (this.chunks.bubble.length > 0 || this.event_listeners.length > 0) {
455489
const dispose: Identifier = {
456490
type: 'Identifier',
457491
name: `#dispose${chunk}`
458492
};
459493

460494
this.add_variable(dispose);
461495

462-
if (this.event_listeners.length === 1) {
496+
if (this.chunks.bubble.length > 0 || this.event_listeners.length > 1) {
497+
this.chunks.mount.push(b`
498+
if (#remount) @run_all(${dispose});
499+
${dispose} = [
500+
${this.event_listeners.length > 0 ? this.event_listeners : ''}
501+
];
502+
`);
503+
504+
this.chunks.destroy.push(
505+
b`@run_all(${dispose});`
506+
);
507+
} else {
463508
this.chunks.mount.push(
464509
b`
465510
if (#remount) ${dispose}();
@@ -470,18 +515,7 @@ export default class Block {
470515
this.chunks.destroy.push(
471516
b`${dispose}();`
472517
);
473-
} else {
474-
this.chunks.mount.push(b`
475-
if (#remount) @run_all(${dispose});
476-
${dispose} = [
477-
${this.event_listeners}
478-
];
479-
`);
480-
481-
this.chunks.destroy.push(
482-
b`@run_all(${dispose});`
483-
);
484518
}
485519
}
486520
}
487-
}
521+
}

src/compiler/compile/render_dom/wrappers/Element/EventHandler.ts

+10-11
Original file line numberDiff line numberDiff line change
@@ -14,20 +14,10 @@ export default class EventHandlerWrapper {
1414
constructor(node: EventHandler, parent: Wrapper) {
1515
this.node = node;
1616
this.parent = parent;
17-
18-
if (!node.expression) {
19-
this.parent.renderer.add_to_context(node.handler_name.name);
20-
21-
this.parent.renderer.component.partly_hoisted.push(b`
22-
function ${node.handler_name.name}(event) {
23-
@bubble($$self, event);
24-
}
25-
`);
26-
}
2717
}
2818

2919
get_snippet(block) {
30-
const snippet = this.node.expression ? this.node.expression.manipulate(block) : block.renderer.reference(this.node.handler_name);
20+
const snippet = this.node.expression.manipulate(block);
3121

3222
if (this.node.reassigned) {
3323
block.maintain_context = true;
@@ -37,6 +27,15 @@ export default class EventHandlerWrapper {
3727
}
3828

3929
render(block: Block, target: string | Expression) {
30+
if (!this.node.expression) {
31+
if (this.node.name === "*")
32+
block.chunks.bubble.push(b`local_dispose.push(@listen(${target}, type, callback))`);
33+
else
34+
block.chunks.bubble.push(b`if (type === "${this.node.name}") local_dispose.push(@listen(${target}, "${this.node.name}", callback));`);
35+
36+
return;
37+
}
38+
4039
let snippet = this.get_snippet(block);
4140

4241
if (this.node.modifiers.has('preventDefault')) snippet = x`@prevent_default(${snippet})`;

src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts

+18-7
Original file line numberDiff line numberDiff line change
@@ -391,13 +391,24 @@ export default class InlineComponentWrapper extends Wrapper {
391391
return b`@binding_callbacks.push(() => @bind(${this.var}, '${binding.name}', ${id}));`;
392392
});
393393

394-
const munged_handlers = this.node.handlers.map(handler => {
395-
const event_handler = new EventHandler(handler, this);
396-
let snippet = event_handler.get_snippet(block);
397-
if (handler.modifiers.has('once')) snippet = x`@once(${snippet})`;
398-
399-
return b`${name}.$on("${handler.name}", ${snippet});`;
400-
});
394+
const munged_handlers = this.node.handlers
395+
.filter(handler => {
396+
if (handler.expression) return true;
397+
398+
if (handler.name === "*")
399+
block.chunks.bubble.push(b`local_dispose.push(${name}.$on(type, callback))`);
400+
else
401+
block.chunks.bubble.push(b`if (type === "${handler.name}") local_dispose.push(${name}.$on("${handler.name}", callback));`);
402+
403+
return false;
404+
})
405+
.map(handler => {
406+
const event_handler = new EventHandler(handler, this);
407+
let snippet = event_handler.get_snippet(block);
408+
if (handler.modifiers.has('once')) snippet = x`@once(${snippet})`;
409+
410+
return b`${name}.$on("${handler.name}", ${snippet});`;
411+
});
401412

402413
if (this.node.name === 'svelte:component') {
403414
const switch_value = block.get_unique_name('switch_value');

src/runtime/internal/Component.ts

+3
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ interface Fragment {
1111
/* claim */ l: (nodes: any) => void;
1212
/* hydrate */ h: () => void;
1313
/* mount */ m: (target: HTMLElement, anchor: any) => void;
14+
/* bubble */ b: (type: string, callback: Function) => Function;
1415
/* update */ p: (ctx: any, dirty: any) => void;
1516
/* measure */ r: () => void;
1617
/* fix */ f: () => void;
@@ -215,10 +216,12 @@ export class SvelteComponent {
215216
}
216217

217218
$on(type, callback) {
219+
const dispose = this.$$.fragment && this.$$.fragment.b(type, callback) || noop;
218220
const callbacks = (this.$$.callbacks[type] || (this.$$.callbacks[type] = []));
219221
callbacks.push(callback);
220222

221223
return () => {
224+
dispose();
222225
const index = callbacks.indexOf(callback);
223226
if (index !== -1) callbacks.splice(index, 1);
224227
};

test/js/samples/action-custom-event-handler/expected.js

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ function create_fragment(ctx) {
2626
if (remount) dispose();
2727
dispose = action_destroyer(foo_action = foo.call(null, button, /*foo_function*/ ctx[1]));
2828
},
29+
b: noop,
2930
p(ctx, [dirty]) {
3031
if (foo_action && is_function(foo_action.update) && dirty & /*bar*/ 1) foo_action.update.call(null, /*foo_function*/ ctx[1]);
3132
},

test/js/samples/action/expected.js

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ function create_fragment(ctx) {
2727
if (remount) dispose();
2828
dispose = action_destroyer(link_action = link.call(null, a));
2929
},
30+
b: noop,
3031
p: noop,
3132
i: noop,
3233
o: noop,

test/js/samples/bind-online/expected.js

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ function create_fragment(ctx) {
2323
listen(window, "offline", /*onlinestatuschanged*/ ctx[1])
2424
];
2525
},
26+
b: noop,
2627
p: noop,
2728
i: noop,
2829
o: noop,

test/js/samples/bind-open/expected.js

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ function create_fragment(ctx) {
2727
if (remount) dispose();
2828
dispose = listen(details, "toggle", /*details_toggle_handler*/ ctx[1]);
2929
},
30+
b: noop,
3031
p(ctx, [dirty]) {
3132
if (dirty & /*open*/ 1) {
3233
details.open = /*open*/ ctx[0];

test/js/samples/bind-width-height/expected.js

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ function create_fragment(ctx) {
2525
insert(target, div, anchor);
2626
div_resize_listener = add_resize_listener(div, /*div_elementresize_handler*/ ctx[2].bind(div));
2727
},
28+
b: noop,
2829
p: noop,
2930
i: noop,
3031
o: noop,

test/js/samples/bindings-readonly-order/expected.js

+1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ function create_fragment(ctx) {
3838
listen(input1, "change", /*input1_change_handler*/ ctx[2])
3939
];
4040
},
41+
b: noop,
4142
p: noop,
4243
i: noop,
4344
o: noop,

test/js/samples/capture-inject-dev-only/expected.js

+1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ function create_fragment(ctx) {
3838
if (remount) dispose();
3939
dispose = listen(input, "input", /*input_input_handler*/ ctx[1]);
4040
},
41+
b: noop,
4142
p(ctx, [dirty]) {
4243
if (dirty & /*foo*/ 1) set_data(t0, /*foo*/ ctx[0]);
4344

test/js/samples/capture-inject-state/expected.js

+1
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ function create_fragment(ctx) {
6767
append_dev(p, t9);
6868
append_dev(p, t10);
6969
},
70+
b: noop,
7071
p: function update(ctx, [dirty]) {
7172
if (dirty & /*prop*/ 1) set_data_dev(t0, /*prop*/ ctx[0]);
7273
if (dirty & /*realName*/ 2) set_data_dev(t2, /*realName*/ ctx[1]);

test/js/samples/collapses-text-around-comments/expected.js

+1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ function create_fragment(ctx) {
3434
insert(target, p, anchor);
3535
append(p, t);
3636
},
37+
b: noop,
3738
p(ctx, [dirty]) {
3839
if (dirty & /*foo*/ 1) set_data(t, /*foo*/ ctx[0]);
3940
},

test/js/samples/component-static-array/expected.js

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ function create_fragment(ctx) {
2323
mount_component(nested, target, anchor);
2424
current = true;
2525
},
26+
b: noop,
2627
p: noop,
2728
i(local) {
2829
if (current) return;

test/js/samples/component-static-immutable/expected.js

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ function create_fragment(ctx) {
2323
mount_component(nested, target, anchor);
2424
current = true;
2525
},
26+
b: noop,
2627
p: noop,
2728
i(local) {
2829
if (current) return;

test/js/samples/component-static-immutable2/expected.js

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ function create_fragment(ctx) {
2323
mount_component(nested, target, anchor);
2424
current = true;
2525
},
26+
b: noop,
2627
p: noop,
2728
i(local) {
2829
if (current) return;

test/js/samples/component-static-var/expected.js

+2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
insert,
1010
listen,
1111
mount_component,
12+
noop,
1213
safe_not_equal,
1314
set_input_value,
1415
space,
@@ -47,6 +48,7 @@ function create_fragment(ctx) {
4748
if (remount) dispose();
4849
dispose = listen(input, "input", /*input_input_handler*/ ctx[1]);
4950
},
51+
b: noop,
5052
p(ctx, [dirty]) {
5153
const bar_changes = {};
5254
if (dirty & /*z*/ 1) bar_changes.x = /*z*/ ctx[0];

test/js/samples/component-static/expected.js

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ function create_fragment(ctx) {
2323
mount_component(nested, target, anchor);
2424
current = true;
2525
},
26+
b: noop,
2627
p: noop,
2728
i(local) {
2829
if (current) return;

test/js/samples/component-store-access-invalidate/expected.js

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ function create_fragment(ctx) {
2828
insert(target, h1, anchor);
2929
append(h1, t);
3030
},
31+
b: noop,
3132
p(ctx, [dirty]) {
3233
if (dirty & /*$foo*/ 1) set_data(t, /*$foo*/ ctx[0]);
3334
},

test/js/samples/component-store-reassign-invalidate/expected.js

+1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ function create_fragment(ctx) {
4040
if (remount) dispose();
4141
dispose = listen(button, "click", /*click_handler*/ ctx[2]);
4242
},
43+
b: noop,
4344
p(ctx, [dirty]) {
4445
if (dirty & /*$foo*/ 2) set_data(t0, /*$foo*/ ctx[1]);
4546
},

test/js/samples/css-media-query/expected.js

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ function create_fragment(ctx) {
2929
m(target, anchor) {
3030
insert(target, div, anchor);
3131
},
32+
b: noop,
3233
p: noop,
3334
i: noop,
3435
o: noop,

test/js/samples/css-shadow-dom-keyframes/expected.js

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ function create_fragment(ctx) {
2121
m(target, anchor) {
2222
insert(target, div, anchor);
2323
},
24+
b: noop,
2425
p: noop,
2526
i: noop,
2627
o: noop,

test/js/samples/data-attribute/expected.js

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ function create_fragment(ctx) {
2929
insert(target, t, anchor);
3030
insert(target, div1, anchor);
3131
},
32+
b: noop,
3233
p(ctx, [dirty]) {
3334
if (dirty & /*bar*/ 1) {
3435
attr(div1, "data-foo", /*bar*/ ctx[0]);

test/js/samples/debug-empty/expected.js

+1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ function create_fragment(ctx) {
4545
append_dev(h1, t2);
4646
insert_dev(target, t3, anchor);
4747
},
48+
b: noop,
4849
p: function update(ctx, [dirty]) {
4950
if (dirty & /*name*/ 1) set_data_dev(t1, /*name*/ ctx[0]);
5051
debugger;

0 commit comments

Comments
 (0)