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 preventDefaultEvents: { [eventType: string]: boolean } = { submit: true };
|
||||
const rootComponentsPendingFirstRender: { [componentId: number]: LogicalElement } = {};
|
||||
const internalAttributeNamePrefix = '__internal_';
|
||||
const eventPreventDefaultAttributeNamePrefix = 'preventDefault_';
|
||||
const eventStopBubblingAttributeNamePrefix = 'stopBubbling_';
|
||||
|
||||
export class BrowserRenderer {
|
||||
private eventDelegator: EventDelegator;
|
||||
|
|
@ -310,8 +313,30 @@ export class BrowserRenderer {
|
|||
return this.tryApplyValueProperty(batch, element, attributeFrame);
|
||||
case 'checked':
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
if (!(evt.target instanceof Element)) {
|
||||
return;
|
||||
|
|
@ -188,6 +198,8 @@ class EventHandlerInfosForElement {
|
|||
// that name at any one time.
|
||||
// So to keep things simple, only track one EventHandlerInfo per (element, eventName)
|
||||
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 {
|
||||
return this.handlers.hasOwnProperty(eventName) ? this.handlers[eventName] : null;
|
||||
|
|
@ -201,8 +213,28 @@ class EventHandlerInfosForElement {
|
|||
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 {
|
||||
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