// EventDispatcher.js (extended with options)
class EventDispatcher {
addEventListener(type, listener, options = undefined) {
if (this._listeners === undefined) this._listeners = {};
const listeners = this._listeners;
if (listeners[type] === undefined) listeners[type] = [];
const arr = listeners[type];
// prevent duplicates (by function ref)
if (arr.some(rec => rec.fn === listener)) return;
arr.push({ fn: listener, once: !!(options && options.once) });
}
hasEventListener(type, listener) {
const listeners = this._listeners;
if (listeners === undefined) return false;
const arr = listeners[type];
if (!arr) return false;
return arr.some(rec => rec.fn === listener);
}
removeEventListener(type, listener) {
const listeners = this._listeners;
if (listeners === undefined) return;
const arr = listeners[type];
if (!arr) return;
const i = arr.findIndex(rec => rec.fn === listener);
if (i !== -1) arr.splice(i, 1);
}
dispatchEvent(event) {
const listeners = this._listeners;
if (listeners === undefined) return;
const arr = listeners[event.type];
if (arr !== undefined) {
event.target = this;
// copy because the original may be mutated during dispatch
const copy = arr.slice();
for (let i = 0, l = copy.length; i < l; i++) {
const rec = copy[i];
rec.fn.call(this, event);
if (rec.once) {
// remove from the original array (not the copy)
const idx = arr.indexOf(rec);
if (idx !== -1) arr.splice(idx, 1);
}
}
event.target = null;
}
}
}
export { EventDispatcher };
I have this suggestion to add options on EventDispatcher to handle once = true/false case as well in the future can be added other handy options as well