Skip to content

Commit 58ee0e6

Browse files
committed
[FIX] smarter synthetic events
This commit fixes 2 behaviors regarding synthetic events: - "non-bubbling" events (such as 'mouseenter', 'focus', etc.) are not allowed anymore as synthetic events, since this would not work either way; - instead of an internal global variable to keep track of what events have already been registered with synthetic event handlers, special keys are now assigned on the document object. This has been done to avoid duplicate listeners when multiple instances of Owl are spawned.
1 parent fb7d25b commit 58ee0e6

File tree

2 files changed

+35
-6
lines changed

2 files changed

+35
-6
lines changed

src/runtime/blockdom/events.ts

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,11 @@ function createElementHandler(evName: string, capture: boolean = false): EventHa
5555
// listener per event type.
5656
let nextSyntheticEventId = 1;
5757
function createSyntheticHandler(evName: string, capture: boolean = false): EventHandlerCreator {
58+
if (NON_BUBBLING_EVENT_NAMES.has(evName)) {
59+
throw new Error(
60+
`cannot set synthetic event handler for "${evName}" events: these events do not bubble by default`
61+
);
62+
}
5863
let eventKey = `__event__synthetic_${evName}`;
5964
if (capture) {
6065
eventKey = `${eventKey}_capture`;
@@ -88,14 +93,27 @@ function nativeToSyntheticEvent(eventKey: string, event: Event) {
8893
}
8994
}
9095

91-
const CONFIGURED_SYNTHETIC_EVENTS: { [event: string]: boolean } = {};
96+
const NON_BUBBLING_EVENT_NAMES = new Set([
97+
"blur",
98+
"error",
99+
"focus",
100+
"hashchange",
101+
"load",
102+
"mouseenter",
103+
"mouseleave",
104+
"pointercancel",
105+
"pointerenter",
106+
"pointerleave",
107+
"unload",
108+
]);
92109

93110
function setupSyntheticEvent(evName: string, eventKey: string, capture: boolean = false) {
94-
if (CONFIGURED_SYNTHETIC_EVENTS[eventKey]) {
111+
const root = document as any;
112+
if (root[eventKey]) {
95113
return;
96114
}
97-
document.addEventListener(evName, (event) => nativeToSyntheticEvent(eventKey, event), {
98-
capture,
99-
});
100-
CONFIGURED_SYNTHETIC_EVENTS[eventKey] = true;
115+
const syntheticHandler = nativeToSyntheticEvent.bind(root, eventKey);
116+
const options = { capture };
117+
root[eventKey] = [evName, syntheticHandler, options];
118+
root.addEventListener(evName, syntheticHandler, options);
101119
}

tests/compiler/event_handling.test.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -575,5 +575,16 @@ describe("t-on", () => {
575575
button.click();
576576
expect(steps).toEqual(["btnClicked", "divClicked"]);
577577
});
578+
579+
test("non-bubbling events cannot be synthesized", () => {
580+
const template = `<div t-on-mouseenter.synthetic="onMouseEnter"></div>`;
581+
582+
const owner = {
583+
onMouseEnter() {},
584+
};
585+
const node = mountToFixture(template, owner);
586+
const div = <HTMLElement>node;
587+
div.dispatchEvent(new MouseEvent("mouseenter"));
588+
});
578589
});
579590
});

0 commit comments

Comments
 (0)