Skip to content

Commit

Permalink
Mechanism for bubbling all events. Closes sveltejs#2837
Browse files Browse the repository at this point in the history
  • Loading branch information
Timothy Johnson committed Mar 25, 2020
1 parent aa3dcc0 commit e269da2
Show file tree
Hide file tree
Showing 85 changed files with 239 additions and 36 deletions.
3 changes: 0 additions & 3 deletions src/compiler/compile/nodes/EventHandler.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import Node from './shared/Node';
import Expression from './shared/Expression';
import Component from '../Component';
import { sanitize } from '../../utils/names';
import { Identifier } from 'estree';

export default class EventHandler extends Node {
Expand Down Expand Up @@ -42,8 +41,6 @@ export default class EventHandler extends Node {
}
}
}
} else {
this.handler_name = component.get_unique_name(`${sanitize(this.name)}_handler`);
}
}

Expand Down
64 changes: 49 additions & 15 deletions src/compiler/compile/render_dom/Block.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export default class Block {
claim: Array<Node | Node[]>;
hydrate: Array<Node | Node[]>;
mount: Array<Node | Node[]>;
bubble: Array<Node | Node[]>;
measure: Array<Node | Node[]>;
fix: Array<Node | Node[]>;
animate: Array<Node | Node[]>;
Expand Down Expand Up @@ -100,6 +101,7 @@ export default class Block {
claim: [],
hydrate: [],
mount: [],
bubble: [],
measure: [],
fix: [],
animate: [],
Expand Down Expand Up @@ -292,9 +294,39 @@ export default class Block {
}`;
}

if (this.chunks.bubble.length === 0) {
properties.bubble = noop;
} else {
const mounted: Identifier = {
type: 'Identifier',
name: '#mounted'
};
this.add_variable(mounted, x`false`);
const bubble_fns: Identifier = {
type: 'Identifier',
name: '#bubble_fns'
};
this.add_variable(bubble_fns, x`[]`);

properties.bubble = x`function #bubble(type, callback) {
const local_dispose = [];
const fn = () => {
${this.chunks.bubble}
#dispose.push(...local_dispose);
}
if (${mounted}) fn()
else ${bubble_fns}.push(fn);
return () => @run_all(local_dispose);
}`;
this.chunks.mount.push(b`
${mounted} = true;
@run_all(${bubble_fns});
`);
}

if (this.chunks.mount.length === 0) {
properties.mount = noop;
} else if (this.event_listeners.length === 0) {
} else if (this.event_listeners.length === 0 && this.chunks.bubble.length === 0) {
properties.mount = x`function #mount(#target, anchor) {
${this.chunks.mount}
}`;
Expand Down Expand Up @@ -378,6 +410,7 @@ export default class Block {
l: ${properties.claim},
h: ${properties.hydrate},
m: ${properties.mount},
b: ${properties.bubble},
p: ${properties.update},
r: ${properties.measure},
f: ${properties.fix},
Expand Down Expand Up @@ -428,6 +461,7 @@ export default class Block {
this.chunks.hydrate.length > 0 ||
this.chunks.claim.length > 0 ||
this.chunks.mount.length > 0 ||
this.chunks.bubble.length > 0 ||
this.chunks.update.length > 0 ||
this.chunks.destroy.length > 0 ||
this.has_animation;
Expand All @@ -451,15 +485,26 @@ export default class Block {
}

render_listeners(chunk: string = '') {
if (this.event_listeners.length > 0) {
if (this.chunks.bubble.length > 0 || this.event_listeners.length > 0) {
const dispose: Identifier = {
type: 'Identifier',
name: `#dispose${chunk}`
};

this.add_variable(dispose);

if (this.event_listeners.length === 1) {
if (this.chunks.bubble.length > 0 || this.event_listeners.length > 1) {
this.chunks.mount.push(b`
if (#remount) @run_all(${dispose});
${dispose} = [
${this.event_listeners.length > 0 ? this.event_listeners : ''}
];
`);

this.chunks.destroy.push(
b`@run_all(${dispose});`
);
} else {
this.chunks.mount.push(
b`
if (#remount) ${dispose}();
Expand All @@ -470,18 +515,7 @@ export default class Block {
this.chunks.destroy.push(
b`${dispose}();`
);
} else {
this.chunks.mount.push(b`
if (#remount) @run_all(${dispose});
${dispose} = [
${this.event_listeners}
];
`);

this.chunks.destroy.push(
b`@run_all(${dispose});`
);
}
}
}
}
}
21 changes: 10 additions & 11 deletions src/compiler/compile/render_dom/wrappers/Element/EventHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,10 @@ export default class EventHandlerWrapper {
constructor(node: EventHandler, parent: Wrapper) {
this.node = node;
this.parent = parent;

if (!node.expression) {
this.parent.renderer.add_to_context(node.handler_name.name);

this.parent.renderer.component.partly_hoisted.push(b`
function ${node.handler_name.name}(event) {
@bubble($$self, event);
}
`);
}
}

get_snippet(block) {
const snippet = this.node.expression ? this.node.expression.manipulate(block) : block.renderer.reference(this.node.handler_name);
const snippet = this.node.expression.manipulate(block);

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

render(block: Block, target: string | Expression) {
if (!this.node.expression) {
if (this.node.name === "*")
block.chunks.bubble.push(b`local_dispose.push(@listen(${target}, type, callback))`);
else
block.chunks.bubble.push(b`if (type === "${this.node.name}") local_dispose.push(@listen(${target}, "${this.node.name}", callback));`);

return;
}

let snippet = this.get_snippet(block);

if (this.node.modifiers.has('preventDefault')) snippet = x`@prevent_default(${snippet})`;
Expand Down
25 changes: 18 additions & 7 deletions src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -391,13 +391,24 @@ export default class InlineComponentWrapper extends Wrapper {
return b`@binding_callbacks.push(() => @bind(${this.var}, '${binding.name}', ${id}));`;
});

const munged_handlers = this.node.handlers.map(handler => {
const event_handler = new EventHandler(handler, this);
let snippet = event_handler.get_snippet(block);
if (handler.modifiers.has('once')) snippet = x`@once(${snippet})`;

return b`${name}.$on("${handler.name}", ${snippet});`;
});
const munged_handlers = this.node.handlers
.filter(handler => {
if (handler.expression) return true;

if (handler.name === "*")
block.chunks.bubble.push(b`local_dispose.push(${name}.$on(type, callback))`);
else
block.chunks.bubble.push(b`if (type === "${handler.name}") local_dispose.push(${name}.$on("${handler.name}", callback));`);

return false;
})
.map(handler => {
const event_handler = new EventHandler(handler, this);
let snippet = event_handler.get_snippet(block);
if (handler.modifiers.has('once')) snippet = x`@once(${snippet})`;

return b`${name}.$on("${handler.name}", ${snippet});`;
});

if (this.node.name === 'svelte:component') {
const switch_value = block.get_unique_name('switch_value');
Expand Down
3 changes: 3 additions & 0 deletions src/runtime/internal/Component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ interface Fragment {
/* claim */ l: (nodes: any) => void;
/* hydrate */ h: () => void;
/* mount */ m: (target: HTMLElement, anchor: any) => void;
/* bubble */ b: (type: string, callback: Function) => Function;
/* update */ p: (ctx: any, dirty: any) => void;
/* measure */ r: () => void;
/* fix */ f: () => void;
Expand Down Expand Up @@ -215,10 +216,12 @@ export class SvelteComponent {
}

$on(type, callback) {
const dispose = this.$$.fragment && this.$$.fragment.b(type, callback) || noop;
const callbacks = (this.$$.callbacks[type] || (this.$$.callbacks[type] = []));
callbacks.push(callback);

return () => {
dispose();
const index = callbacks.indexOf(callback);
if (index !== -1) callbacks.splice(index, 1);
};
Expand Down
1 change: 1 addition & 0 deletions test/js/samples/action-custom-event-handler/expected.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ function create_fragment(ctx) {
if (remount) dispose();
dispose = action_destroyer(foo_action = foo.call(null, button, /*foo_function*/ ctx[1]));
},
b: noop,
p(ctx, [dirty]) {
if (foo_action && is_function(foo_action.update) && dirty & /*bar*/ 1) foo_action.update.call(null, /*foo_function*/ ctx[1]);
},
Expand Down
1 change: 1 addition & 0 deletions test/js/samples/action/expected.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ function create_fragment(ctx) {
if (remount) dispose();
dispose = action_destroyer(link_action = link.call(null, a));
},
b: noop,
p: noop,
i: noop,
o: noop,
Expand Down
1 change: 1 addition & 0 deletions test/js/samples/bind-online/expected.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ function create_fragment(ctx) {
listen(window, "offline", /*onlinestatuschanged*/ ctx[1])
];
},
b: noop,
p: noop,
i: noop,
o: noop,
Expand Down
1 change: 1 addition & 0 deletions test/js/samples/bind-open/expected.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ function create_fragment(ctx) {
if (remount) dispose();
dispose = listen(details, "toggle", /*details_toggle_handler*/ ctx[1]);
},
b: noop,
p(ctx, [dirty]) {
if (dirty & /*open*/ 1) {
details.open = /*open*/ ctx[0];
Expand Down
1 change: 1 addition & 0 deletions test/js/samples/bind-width-height/expected.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ function create_fragment(ctx) {
insert(target, div, anchor);
div_resize_listener = add_resize_listener(div, /*div_elementresize_handler*/ ctx[2].bind(div));
},
b: noop,
p: noop,
i: noop,
o: noop,
Expand Down
1 change: 1 addition & 0 deletions test/js/samples/bindings-readonly-order/expected.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ function create_fragment(ctx) {
listen(input1, "change", /*input1_change_handler*/ ctx[2])
];
},
b: noop,
p: noop,
i: noop,
o: noop,
Expand Down
1 change: 1 addition & 0 deletions test/js/samples/capture-inject-dev-only/expected.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ function create_fragment(ctx) {
if (remount) dispose();
dispose = listen(input, "input", /*input_input_handler*/ ctx[1]);
},
b: noop,
p(ctx, [dirty]) {
if (dirty & /*foo*/ 1) set_data(t0, /*foo*/ ctx[0]);

Expand Down
1 change: 1 addition & 0 deletions test/js/samples/capture-inject-state/expected.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ function create_fragment(ctx) {
append_dev(p, t9);
append_dev(p, t10);
},
b: noop,
p: function update(ctx, [dirty]) {
if (dirty & /*prop*/ 1) set_data_dev(t0, /*prop*/ ctx[0]);
if (dirty & /*realName*/ 2) set_data_dev(t2, /*realName*/ ctx[1]);
Expand Down
1 change: 1 addition & 0 deletions test/js/samples/collapses-text-around-comments/expected.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ function create_fragment(ctx) {
insert(target, p, anchor);
append(p, t);
},
b: noop,
p(ctx, [dirty]) {
if (dirty & /*foo*/ 1) set_data(t, /*foo*/ ctx[0]);
},
Expand Down
1 change: 1 addition & 0 deletions test/js/samples/component-static-array/expected.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ function create_fragment(ctx) {
mount_component(nested, target, anchor);
current = true;
},
b: noop,
p: noop,
i(local) {
if (current) return;
Expand Down
1 change: 1 addition & 0 deletions test/js/samples/component-static-immutable/expected.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ function create_fragment(ctx) {
mount_component(nested, target, anchor);
current = true;
},
b: noop,
p: noop,
i(local) {
if (current) return;
Expand Down
1 change: 1 addition & 0 deletions test/js/samples/component-static-immutable2/expected.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ function create_fragment(ctx) {
mount_component(nested, target, anchor);
current = true;
},
b: noop,
p: noop,
i(local) {
if (current) return;
Expand Down
2 changes: 2 additions & 0 deletions test/js/samples/component-static-var/expected.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
insert,
listen,
mount_component,
noop,
safe_not_equal,
set_input_value,
space,
Expand Down Expand Up @@ -47,6 +48,7 @@ function create_fragment(ctx) {
if (remount) dispose();
dispose = listen(input, "input", /*input_input_handler*/ ctx[1]);
},
b: noop,
p(ctx, [dirty]) {
const bar_changes = {};
if (dirty & /*z*/ 1) bar_changes.x = /*z*/ ctx[0];
Expand Down
1 change: 1 addition & 0 deletions test/js/samples/component-static/expected.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ function create_fragment(ctx) {
mount_component(nested, target, anchor);
current = true;
},
b: noop,
p: noop,
i(local) {
if (current) return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ function create_fragment(ctx) {
insert(target, h1, anchor);
append(h1, t);
},
b: noop,
p(ctx, [dirty]) {
if (dirty & /*$foo*/ 1) set_data(t, /*$foo*/ ctx[0]);
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ function create_fragment(ctx) {
if (remount) dispose();
dispose = listen(button, "click", /*click_handler*/ ctx[2]);
},
b: noop,
p(ctx, [dirty]) {
if (dirty & /*$foo*/ 2) set_data(t0, /*$foo*/ ctx[1]);
},
Expand Down
1 change: 1 addition & 0 deletions test/js/samples/css-media-query/expected.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ function create_fragment(ctx) {
m(target, anchor) {
insert(target, div, anchor);
},
b: noop,
p: noop,
i: noop,
o: noop,
Expand Down
1 change: 1 addition & 0 deletions test/js/samples/css-shadow-dom-keyframes/expected.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ function create_fragment(ctx) {
m(target, anchor) {
insert(target, div, anchor);
},
b: noop,
p: noop,
i: noop,
o: noop,
Expand Down
1 change: 1 addition & 0 deletions test/js/samples/data-attribute/expected.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ function create_fragment(ctx) {
insert(target, t, anchor);
insert(target, div1, anchor);
},
b: noop,
p(ctx, [dirty]) {
if (dirty & /*bar*/ 1) {
attr(div1, "data-foo", /*bar*/ ctx[0]);
Expand Down
1 change: 1 addition & 0 deletions test/js/samples/debug-empty/expected.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ function create_fragment(ctx) {
append_dev(h1, t2);
insert_dev(target, t3, anchor);
},
b: noop,
p: function update(ctx, [dirty]) {
if (dirty & /*name*/ 1) set_data_dev(t1, /*name*/ ctx[0]);
debugger;
Expand Down
Loading

0 comments on commit e269da2

Please sign in to comment.