[IMP] qweb, blockdom, components: t-on with modifiers

supported modifiers: capture, prevent, stop, self.
This commit is contained in:
Lucas Perais (lpe)
2021-10-27 14:45:29 +02:00
committed by Aaron Bohy
parent 2ae0149adb
commit 4cceb239dd
11 changed files with 427 additions and 39 deletions
+2 -1
View File
@@ -16,12 +16,13 @@ export const config = {
// this is the main event handler. Every event handler registered with blockdom
// will go through this function, giving it the data registered in the block
// and the event
mainEventHandler: (data: any, ev: Event) => {
mainEventHandler: (data: any, ev: Event, currentTarget?: EventTarget | null): boolean => {
if (typeof data === "function") {
data(ev);
} else if (Array.isArray(data)) {
data = filterOutModifiersFromData(data).data;
data[0](data[1], ev);
}
return false;
},
};
+19 -10
View File
@@ -9,27 +9,32 @@ interface EventHandlerCreator {
export function createEventHandler(rawEvent: string): EventHandlerCreator {
const eventName = rawEvent.split(".")[0];
const capture = rawEvent.includes(".capture");
if (rawEvent.includes(".synthetic")) {
return createSyntheticHandler(eventName);
return createSyntheticHandler(eventName, capture);
} else {
return createElementHandler(eventName);
return createElementHandler(eventName, capture);
}
}
// Native listener
function createElementHandler(evName: string): EventHandlerCreator {
function createElementHandler(evName: string, capture: boolean = false): EventHandlerCreator {
let eventKey = `__event__${evName}`;
if (capture) {
eventKey = `${eventKey}_capture`;
}
function listener(ev: Event) {
const currentTarget = ev.currentTarget;
if (!currentTarget || !document.contains(currentTarget as HTMLElement)) return;
const data = (currentTarget as any)[eventKey];
if (!data) return;
config.mainEventHandler(data, ev);
config.mainEventHandler(data, ev, currentTarget);
}
function setup(this: HTMLElement, data: any) {
(this as any)[eventKey] = data;
this.addEventListener(evName, listener);
this.addEventListener(evName, listener, { capture });
}
function update(this: HTMLElement, data: any) {
@@ -41,9 +46,12 @@ function createElementHandler(evName: string): EventHandlerCreator {
// Synthetic handler: a form of event delegation that allows placing only one
// listener per event type.
function createSyntheticHandler(evName: string): EventHandlerCreator {
function createSyntheticHandler(evName: string, capture: boolean = false): EventHandlerCreator {
let eventKey = `__event__synthetic_${evName}`;
setupSyntheticEvent(evName, eventKey);
if (capture) {
eventKey = `${eventKey}_capture`;
}
setupSyntheticEvent(evName, eventKey, capture);
function setup(this: HTMLElement, data: any) {
(this as any)[eventKey] = data;
}
@@ -55,7 +63,8 @@ function nativeToSyntheticEvent(eventKey: string, event: Event) {
while (dom !== null) {
const data = (dom as any)[eventKey];
if (data) {
config.mainEventHandler(data, event);
const stopped = config.mainEventHandler(data, event, dom);
if (stopped) return;
}
dom = (dom as any).parentNode;
}
@@ -63,10 +72,10 @@ function nativeToSyntheticEvent(eventKey: string, event: Event) {
const CONFIGURED_SYNTHETIC_EVENTS: { [event: string]: boolean } = {};
function setupSyntheticEvent(evName: string, eventKey: string) {
function setupSyntheticEvent(evName: string, eventKey: string, capture: boolean = false) {
if (CONFIGURED_SYNTHETIC_EVENTS[eventKey]) {
return;
}
document.addEventListener(evName, (event) => nativeToSyntheticEvent(eventKey, event));
document.addEventListener(evName, (event) => nativeToSyntheticEvent(eventKey, event), { capture });
CONFIGURED_SYNTHETIC_EVENTS[eventKey] = true;
}