mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
[IMP] blockdom: t-on supports synthetic and native event handler
Synthetic handler is a sort of event delegation that allows placing only one listener on the document to improve performance. It is an opt-in option. Native listener places the listener on the node itself.
This commit is contained in:
committed by
Aaron Bohy
parent
3eb63452e7
commit
2ae0149adb
@@ -396,12 +396,12 @@ function updateCtx(ctx: BlockCtx, tree: IntermediateTree) {
|
||||
});
|
||||
break;
|
||||
case "handler": {
|
||||
const setupHandler = createEventHandler(info.event!);
|
||||
const { setup, update } = createEventHandler(info.event!);
|
||||
ctx.locations.push({
|
||||
idx: info.idx,
|
||||
refIdx: info.refIdx!,
|
||||
setData: setupHandler,
|
||||
updateData: setupHandler,
|
||||
setData: setup,
|
||||
updateData: update,
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
export function filterOutModifiersFromData(dataList: any[]): { modifiers: string[], data: any[]} {
|
||||
dataList = dataList.slice();
|
||||
const modifiers = [];
|
||||
let elm;
|
||||
while ((elm = dataList[0]) && typeof elm === "string") {
|
||||
modifiers.push(dataList.shift());
|
||||
}
|
||||
return { modifiers, data: dataList };
|
||||
}
|
||||
|
||||
export const config = {
|
||||
// whether or not blockdom should normalize DOM whenever a block is created.
|
||||
// Normalizing dom mean removing empty text nodes (or containing only spaces)
|
||||
@@ -10,6 +20,7 @@ export const config = {
|
||||
if (typeof data === "function") {
|
||||
data(ev);
|
||||
} else if (Array.isArray(data)) {
|
||||
data = filterOutModifiersFromData(data).data;
|
||||
data[0](data[1], ev);
|
||||
}
|
||||
},
|
||||
|
||||
+53
-13
@@ -1,21 +1,61 @@
|
||||
import { config } from "./config";
|
||||
|
||||
export function createEventHandler(event: string) {
|
||||
setupSyntheticEvent(event);
|
||||
const key = `__event__${event}`;
|
||||
return function setupHandler(this: HTMLElement, data: any) {
|
||||
(this as any)[key] = data;
|
||||
};
|
||||
type EventHandlerSetter = (this: HTMLElement, data: any) => void;
|
||||
|
||||
interface EventHandlerCreator {
|
||||
setup: EventHandlerSetter;
|
||||
update: EventHandlerSetter;
|
||||
}
|
||||
|
||||
function nativeToSyntheticEvent(event: Event, name: string) {
|
||||
const eventKey = `__event__${name}`;
|
||||
export function createEventHandler(rawEvent: string): EventHandlerCreator {
|
||||
const eventName = rawEvent.split(".")[0];
|
||||
if (rawEvent.includes(".synthetic")) {
|
||||
return createSyntheticHandler(eventName);
|
||||
} else {
|
||||
return createElementHandler(eventName);
|
||||
}
|
||||
}
|
||||
|
||||
// Native listener
|
||||
function createElementHandler(evName: string): EventHandlerCreator {
|
||||
let eventKey = `__event__${evName}`;
|
||||
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);
|
||||
}
|
||||
|
||||
function setup(this: HTMLElement, data: any) {
|
||||
(this as any)[eventKey] = data;
|
||||
this.addEventListener(evName, listener);
|
||||
}
|
||||
|
||||
function update(this: HTMLElement, data: any) {
|
||||
(this as any)[eventKey] = data;
|
||||
}
|
||||
|
||||
return { setup, update };
|
||||
}
|
||||
|
||||
// Synthetic handler: a form of event delegation that allows placing only one
|
||||
// listener per event type.
|
||||
function createSyntheticHandler(evName: string): EventHandlerCreator {
|
||||
let eventKey = `__event__synthetic_${evName}`;
|
||||
setupSyntheticEvent(evName, eventKey);
|
||||
function setup(this: HTMLElement, data: any) {
|
||||
(this as any)[eventKey] = data;
|
||||
}
|
||||
return { setup, update: setup };
|
||||
}
|
||||
|
||||
function nativeToSyntheticEvent(eventKey: string, event: Event) {
|
||||
let dom = event.target;
|
||||
while (dom !== null) {
|
||||
const data = (dom as any)[eventKey];
|
||||
if (data) {
|
||||
config.mainEventHandler(data, event);
|
||||
return;
|
||||
}
|
||||
dom = (dom as any).parentNode;
|
||||
}
|
||||
@@ -23,10 +63,10 @@ function nativeToSyntheticEvent(event: Event, name: string) {
|
||||
|
||||
const CONFIGURED_SYNTHETIC_EVENTS: { [event: string]: boolean } = {};
|
||||
|
||||
function setupSyntheticEvent(name: string) {
|
||||
if (CONFIGURED_SYNTHETIC_EVENTS[name]) {
|
||||
function setupSyntheticEvent(evName: string, eventKey: string) {
|
||||
if (CONFIGURED_SYNTHETIC_EVENTS[eventKey]) {
|
||||
return;
|
||||
}
|
||||
document.addEventListener(name, (event) => nativeToSyntheticEvent(event, name));
|
||||
CONFIGURED_SYNTHETIC_EVENTS[name] = true;
|
||||
document.addEventListener(evName, (event) => nativeToSyntheticEvent(eventKey, event));
|
||||
CONFIGURED_SYNTHETIC_EVENTS[eventKey] = true;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import { filterOutModifiersFromData } from "../blockdom/config";
|
||||
|
||||
export function mainEventHandler(data: any, ev: Event) {
|
||||
if (typeof data === "function") {
|
||||
data(ev);
|
||||
} else {
|
||||
data = filterOutModifiersFromData(data).data;
|
||||
const ctx = data[0];
|
||||
const method = data[1];
|
||||
const args = data[2] || [];
|
||||
|
||||
Reference in New Issue
Block a user