Keep track of preventDefault/stopBubbling flags on JS side
This commit is contained in:
parent
3249dce498
commit
3cd4726c76
|
|
@ -10,6 +10,9 @@ const sharedTemplateElemForParsing = document.createElement('template');
|
||||||
const sharedSvgElemForParsing = document.createElementNS('http://www.w3.org/2000/svg', 'g');
|
const sharedSvgElemForParsing = document.createElementNS('http://www.w3.org/2000/svg', 'g');
|
||||||
const preventDefaultEvents: { [eventType: string]: boolean } = { submit: true };
|
const preventDefaultEvents: { [eventType: string]: boolean } = { submit: true };
|
||||||
const rootComponentsPendingFirstRender: { [componentId: number]: LogicalElement } = {};
|
const rootComponentsPendingFirstRender: { [componentId: number]: LogicalElement } = {};
|
||||||
|
const internalAttributeNamePrefix = '__internal_';
|
||||||
|
const eventPreventDefaultAttributeNamePrefix = 'preventDefault_';
|
||||||
|
const eventStopBubblingAttributeNamePrefix = 'stopBubbling_';
|
||||||
|
|
||||||
export class BrowserRenderer {
|
export class BrowserRenderer {
|
||||||
private eventDelegator: EventDelegator;
|
private eventDelegator: EventDelegator;
|
||||||
|
|
@ -310,8 +313,30 @@ export class BrowserRenderer {
|
||||||
return this.tryApplyValueProperty(batch, element, attributeFrame);
|
return this.tryApplyValueProperty(batch, element, attributeFrame);
|
||||||
case 'checked':
|
case 'checked':
|
||||||
return this.tryApplyCheckedProperty(batch, element, attributeFrame);
|
return this.tryApplyCheckedProperty(batch, element, attributeFrame);
|
||||||
default:
|
default: {
|
||||||
|
if (attributeName.startsWith(internalAttributeNamePrefix)) {
|
||||||
|
this.applyInternalAttribute(batch, element, attributeName.substring(internalAttributeNamePrefix.length), attributeFrame);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private applyInternalAttribute(batch: RenderBatch, element: Element, internalAttributeName: string, attributeFrame: RenderTreeFrame | null) {
|
||||||
|
const attributeValue = attributeFrame ? batch.frameReader.attributeValue(attributeFrame) : null;
|
||||||
|
|
||||||
|
if (internalAttributeName.startsWith(eventStopBubblingAttributeNamePrefix)) {
|
||||||
|
// Stop bubbling
|
||||||
|
const eventName = internalAttributeName.substring(eventStopBubblingAttributeNamePrefix.length);
|
||||||
|
this.eventDelegator.setStopBubbling(element, eventName, attributeValue !== null);
|
||||||
|
} else if (internalAttributeName.startsWith(eventPreventDefaultAttributeNamePrefix)) {
|
||||||
|
// Prevent default
|
||||||
|
const eventName = internalAttributeName.substring(eventPreventDefaultAttributeNamePrefix.length);
|
||||||
|
this.eventDelegator.setPreventDefault(element, eventName, attributeValue !== null);
|
||||||
|
} else {
|
||||||
|
// The prefix makes this attribute name reserved, so any other usage is disallowed
|
||||||
|
throw new Error(`Unsupported internal attribute '${internalAttributeName}'`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,16 @@ export class EventDelegator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public setStopBubbling(element: Element, eventName: string, value: boolean) {
|
||||||
|
const infoForElement = this.getEventHandlerInfosForElement(element, true)!;
|
||||||
|
infoForElement.stopBubbling(eventName, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public setPreventDefault(element: Element, eventName: string, value: boolean) {
|
||||||
|
const infoForElement = this.getEventHandlerInfosForElement(element, true)!;
|
||||||
|
infoForElement.preventDefault(eventName, value);
|
||||||
|
}
|
||||||
|
|
||||||
private onGlobalEvent(evt: Event) {
|
private onGlobalEvent(evt: Event) {
|
||||||
if (!(evt.target instanceof Element)) {
|
if (!(evt.target instanceof Element)) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -188,6 +198,8 @@ class EventHandlerInfosForElement {
|
||||||
// that name at any one time.
|
// that name at any one time.
|
||||||
// So to keep things simple, only track one EventHandlerInfo per (element, eventName)
|
// So to keep things simple, only track one EventHandlerInfo per (element, eventName)
|
||||||
private handlers: { [eventName: string]: EventHandlerInfo } = {};
|
private handlers: { [eventName: string]: EventHandlerInfo } = {};
|
||||||
|
private preventDefaultFlags: { [eventName: string]: boolean } | null = null;
|
||||||
|
private stopBubblingFlags: { [eventName: string]: boolean } | null = null;
|
||||||
|
|
||||||
public getHandler(eventName: string): EventHandlerInfo | null {
|
public getHandler(eventName: string): EventHandlerInfo | null {
|
||||||
return this.handlers.hasOwnProperty(eventName) ? this.handlers[eventName] : null;
|
return this.handlers.hasOwnProperty(eventName) ? this.handlers[eventName] : null;
|
||||||
|
|
@ -201,8 +213,28 @@ class EventHandlerInfosForElement {
|
||||||
delete this.handlers[eventName];
|
delete this.handlers[eventName];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public preventDefault(eventName: string, setValue: boolean | null): boolean {
|
||||||
|
if (setValue !== null) {
|
||||||
|
this.preventDefaultFlags = this.preventDefaultFlags || {};
|
||||||
|
this.preventDefaultFlags[eventName] = setValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.preventDefaultFlags ? this.preventDefaultFlags[eventName] : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public stopBubbling(eventName: string, setValue: boolean | null): boolean {
|
||||||
|
if (setValue !== null) {
|
||||||
|
this.stopBubblingFlags = this.stopBubblingFlags || {};
|
||||||
|
this.stopBubblingFlags[eventName] = setValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.stopBubblingFlags ? this.stopBubblingFlags[eventName] : false;
|
||||||
|
}
|
||||||
|
|
||||||
public isEmpty(): boolean {
|
public isEmpty(): boolean {
|
||||||
return Object.getOwnPropertyNames(this.handlers).length === 0;
|
return Object.getOwnPropertyNames(this.handlers).length === 0
|
||||||
|
&& (!this.preventDefaultFlags || Object.getOwnPropertyNames(this.preventDefaultFlags).length === 0)
|
||||||
|
&& (!this.stopBubblingFlags || Object.getOwnPropertyNames(this.stopBubblingFlags).length === 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue