69 lines
2.1 KiB
JavaScript
69 lines
2.1 KiB
JavaScript
const listenerRegistry = new WeakMap();
|
|
const {addEventListener, removeEventListener} = EventTarget.prototype;
|
|
|
|
// Register event listeners to a key object
|
|
// listeners: array of listener definitions;
|
|
// - each definition must be a flat array of event target and the arguments
|
|
// used to call addEventListener() on the target
|
|
export function registerListeners(keyObj, listeners) {
|
|
let registered = listenerRegistry.get(keyObj);
|
|
if (!registered) {
|
|
registered = [];
|
|
listenerRegistry.set(keyObj, registered);
|
|
}
|
|
listeners.forEach((listener) => {
|
|
addEventListener.call(...listener);
|
|
registered.push(listener);
|
|
});
|
|
}
|
|
|
|
export function unregisterListeners(keyObj) {
|
|
let listeners = listenerRegistry.get(keyObj);
|
|
if (!listeners) {
|
|
return;
|
|
}
|
|
listeners.forEach((listener) => {
|
|
removeEventListener.call(...listener);
|
|
});
|
|
listenerRegistry.delete(keyObj);
|
|
}
|
|
|
|
// Event.composedPath() polyfill for Edge
|
|
// based on https://gist.github.com/kleinfreund/e9787d73776c0e3750dcfcdc89f100ec
|
|
if (!Event.prototype.composedPath) {
|
|
const getComposedPath = (node, path = []) => {
|
|
path.push(node);
|
|
|
|
let parent;
|
|
if (node.parentNode) {
|
|
parent = node.parentNode;
|
|
} else if (node.host) { // ShadowRoot
|
|
parent = node.host;
|
|
} else if (node.defaultView) { // Document
|
|
parent = node.defaultView;
|
|
}
|
|
return parent ? getComposedPath(parent, path) : path;
|
|
};
|
|
|
|
Event.prototype.composedPath = function () {
|
|
return getComposedPath(this.target);
|
|
};
|
|
}
|
|
|
|
function findFromPath(path, criteria, currentTarget, index = 0) {
|
|
const el = path[index];
|
|
if (criteria(el)) {
|
|
return el;
|
|
} else if (el === currentTarget || !el.parentElement) {
|
|
// stop when reaching currentTarget or <html>
|
|
return;
|
|
}
|
|
return findFromPath(path, criteria, currentTarget, index + 1);
|
|
}
|
|
|
|
// Search for the actual target of a delegated event
|
|
export function findElementInEventPath(ev, selector) {
|
|
const criteria = typeof selector === 'function' ? selector : el => el.matches(selector);
|
|
return findFromPath(ev.composedPath(), criteria, ev.currentTarget);
|
|
}
|