UNPKG

@haxiomic/event-signal

Version:

A single event emitter with priority support for TypeScript

98 lines (97 loc) 3.26 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.EventSignal = void 0; /** * Event emitter with a notion of explicit ordering via priority */ class EventSignal { constructor() { this.listeners = new Array(); } addListener(listener, priority = 0) { let eventObj = { priority, listener, remove: () => this.removeListener(listener), }; if (listener !== null) { this.listeners.push(eventObj); } return eventObj; } /** Alias for addListener */ on(listener, priority) { return this.addListener(listener, priority); } removeListener(listener) { // remove listener from array let i = 0; for (; i < this.listeners.length; i++) { if (this.listeners[i].listener === listener) { break; } } this.listeners.splice(i, 1); } once(listener, priority = 0) { const tempListener = (event) => { listener(event); this.removeListener(tempListener); }; return this.addListener(tempListener, priority); } /** * Dispatch an event by providing a payload * The underlying event object will be created and populated with the payload * * @param maxPriority If provided, only listeners with a priority equal or lower than this will be called */ dispatch(payload, maxPriority) { if (this.listeners.length === 0) return; return this.dispatchWithExistingEvent(payload, maxPriority); } /** * Dispatch an event with an existing event object * * This is useful if you want to forward an event from another source like a DOM event */ dispatchWithExistingEvent(payload, maxPriority = Infinity) { if (this.listeners.length === 0) return; let event = this.patchPayload(payload); // sort listeners by priority before dispatch (priority can change at runtime) this.sortPriorityDescending(); // enumerate listeners, highest priority first for (let i = 0; i < this.listeners.length; i++) { let item = this.listeners[i]; if (item.priority > maxPriority) continue; // skip this.listeners[i].listener(event); // stop propagation if event was prevented if (typeof event === 'object' && event.propagationStopped) { return; } } } hasListeners() { return this.listeners.length > 0; } sortPriorityDescending() { this.listeners.sort((a, b) => b.priority - a.priority); } patchPayload(payload) { // patch event object to support `propagationStopped` if (payload instanceof Event && payload.propagationStopped === undefined) { payload.propagationStopped = false; payload._stopPropagation = payload.stopPropagation; payload.stopPropagation = stopPropagationOverride; } return payload; } } exports.EventSignal = EventSignal; function stopPropagationOverride() { this.propagationStopped = true; this._stopPropagation(); }