You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

89 lines
2.0 KiB
JavaScript

// https://dom.spec.whatwg.org/#interface-eventtarget
const wm = new WeakMap();
function dispatch(event, listener) {
if (typeof listener === 'function')
listener.call(event.target, event);
else
listener.handleEvent(event);
return event._stopImmediatePropagationFlag;
}
function invokeListeners({currentTarget, target}) {
const map = wm.get(currentTarget);
if (map && map.has(this.type)) {
const listeners = map.get(this.type);
if (currentTarget === target) {
this.eventPhase = this.AT_TARGET;
} else {
this.eventPhase = this.BUBBLING_PHASE;
}
this.currentTarget = currentTarget;
this.target = target;
for (const [listener, options] of listeners) {
if (options && options.once)
listeners.delete(listener);
if (dispatch(this, listener))
break;
}
delete this.currentTarget;
delete this.target;
return this.cancelBubble;
}
}
/**
* @implements globalThis.EventTarget
*/
class DOMEventTarget {
constructor() {
wm.set(this, new Map);
}
/**
* @protected
*/
_getParent() {
return null;
}
addEventListener(type, listener, options) {
const map = wm.get(this);
if (!map.has(type))
map.set(type, new Map);
map.get(type).set(listener, options);
}
removeEventListener(type, listener) {
const map = wm.get(this);
if (map.has(type)) {
const listeners = map.get(type);
if (listeners.delete(listener) && !listeners.size)
map.delete(type);
}
}
dispatchEvent(event) {
let node = this;
event.eventPhase = event.CAPTURING_PHASE;
// intentionally simplified, specs imply way more code: https://dom.spec.whatwg.org/#event-path
while (node) {
if (node.dispatchEvent)
event._path.push({currentTarget: node, target: this});
node = event.bubbles && node._getParent && node._getParent();
}
event._path.some(invokeListeners, event);
event._path = [];
event.eventPhase = event.NONE;
return !event.defaultPrevented;
}
}
export {DOMEventTarget as EventTarget};