Skip to content

Commit 1102ff6

Browse files
authored
support once modifier on component events, fail on others (#2987)
* support once modifier on component events, fail on others. fixes #2654 * appease the gods of typescript
1 parent 9754f2a commit 1102ff6

File tree

8 files changed

+67
-1
lines changed

8 files changed

+67
-1
lines changed

src/compiler/compile/nodes/InlineComponent.ts

+11
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,17 @@ export default class InlineComponent extends Node {
100100
this.scope = scope;
101101
}
102102

103+
this.handlers.forEach(handler => {
104+
handler.modifiers.forEach(modifier => {
105+
if (modifier !== 'once') {
106+
component.error(handler, {
107+
code: 'invalid-event-modifier',
108+
message: `Event modifiers other than 'once' can only be used on DOM elements`
109+
});
110+
}
111+
});
112+
});
113+
103114
this.children = map_children(component, this, this.scope, info.children);
104115
}
105116
}

src/compiler/compile/render-dom/wrappers/InlineComponent/index.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,9 @@ export default class InlineComponentWrapper extends Wrapper {
363363
});
364364

365365
const munged_handlers = this.node.handlers.map(handler => {
366-
const snippet = handler.render(block);
366+
let snippet = handler.render(block);
367+
if (handler.modifiers.has('once')) snippet = `@once(${snippet})`;
368+
367369
return `${name}.$on("${handler.name}", ${snippet});`;
368370
});
369371

src/runtime/internal/utils.ts

+9
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,15 @@ export function exclude_internal_props(props) {
8181
return result;
8282
}
8383

84+
export function once(fn) {
85+
let ran = false;
86+
return function(this: any, ...args) {
87+
if (ran) return;
88+
ran = true;
89+
fn.call(this, ...args);
90+
}
91+
}
92+
8493
const is_client = typeof window !== 'undefined';
8594

8695
export let now: () => number = is_client
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<button on:click><slot></slot></button>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
export default {
2+
html: `
3+
<button>0</button>
4+
`,
5+
6+
async test({ assert, component, target, window }) {
7+
const button = target.querySelector('button');
8+
const event = new window.MouseEvent('click');
9+
10+
await button.dispatchEvent(event);
11+
assert.equal(component.count, 1);
12+
13+
await button.dispatchEvent(event);
14+
assert.equal(component.count, 1);
15+
}
16+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<script>
2+
import Button from './Button.svelte';
3+
export let count = 0;
4+
</script>
5+
6+
<Button on:click|once="{() => count += 1}">{count}</Button>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
[{
2+
"message": "Event modifiers other than 'once' can only be used on DOM elements",
3+
"code": "invalid-event-modifier",
4+
"start": {
5+
"line": 6,
6+
"column": 8,
7+
"character": 93
8+
},
9+
"end": {
10+
"line": 6,
11+
"column": 40,
12+
"character": 125
13+
},
14+
"pos": 93
15+
}]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<script>
2+
import Button from './Button.svelte';
3+
const doThat = () => {};
4+
</script>
5+
6+
<Button on:click|preventDefault={doThat}></Button>

0 commit comments

Comments
 (0)