UNPKG

@ima/core

Version:

IMA.js framework for isomorphic javascript application

175 lines (174 loc) 6.04 kB
import { Dispatcher } from './Dispatcher'; import { GenericError } from '../error/GenericError'; /** * An empty immutable map of event listener to scopes, used for a mismatch in * the {@link _eventListeners} map. */ const EMPTY_MAP = Object.freeze(new Map()); /** * An empty immutable set of event listener scopes, used for a mismatch in the * {@link _eventListeners} map. */ const EMPTY_SET = Object.freeze(new Set()); /** * Default implementation of the {@link Dispatcher} interface. */ export class DispatcherImpl extends Dispatcher { _eventListeners; _eventListenersAll; static $dependencies = []; /** * Initializes the dispatcher. */ constructor(){ super(); /** * Map of event names to a map of event listeners to a set of scopes to * which the event listener should be bound when being executed due to * the event. */ this._eventListeners = new Map(); this._eventListenersAll = new Map(); } /** * @inheritDoc */ clear() { this._eventListeners.clear(); return this; } /** * @inheritDoc */ listen(event, listener, scope) { if ($Debug) { if (typeof listener !== 'function') { throw new GenericError(`The listener must be a function, ${listener} provided.`); } } if (!this._eventListeners.has(event)) { this._createNewEvent(event); } const listeners = this._getListenersOf(event); if (!listeners.has(listener)) { this._createNewListener(event, listener); } this._getScopesOf(event, listener).add(scope); return this; } /** * @inheritDoc */ listenAll(listener, scope) { if ($Debug) { if (typeof listener !== 'function') { throw new GenericError(`The listener must be a function, ${listener} provided.`); } } if (!this._eventListenersAll.has(listener)) { const scopes = new Set(); this._eventListenersAll.set(listener, scopes); } this._eventListenersAll.get(listener).add(scope); return this; } /** * @inheritDoc */ unlisten(event, listener, scope) { const scopes = this._getScopesOf(event, listener); if ($Debug) { if (!scopes.has(scope)) { console.warn('ima.core.event.DispatcherImpl.unlisten(): the provided ' + `listener '${listener}' is not registered for the ` + `specified event '${event}' and scope '${scope}'. Check ` + `your workflow.`, { event: event, listener: listener, scope: scope }); } } scopes.delete(scope); if (!scopes.size) { const listeners = this._getListenersOf(event); listeners.delete(listener); if (!listeners.size) { this._eventListeners.delete(event); } } return this; } unlistenAll(listener, scope) { const scopes = this._eventListenersAll.get(listener) ?? EMPTY_SET; if ($Debug) { if (!scopes.has(scope)) { console.warn('ima.core.event.DispatcherImpl.unlistenAll(): the provided ' + `listener '${listener}' is not registered for` + `scope '${scope}'. Check ` + `your workflow.`, { listener: listener, scope: scope }); } } scopes.delete(scope); if (!scopes.size) { this._eventListenersAll.delete(listener); } return this; } /** * @inheritDoc */ fire(event, data) { const listeners = this._getListenersOf(event); for (const [listener, scopes] of this._eventListenersAll.entries()){ for (const scope of scopes){ listener.bind(scope)(event, data); } } for (const [listener, scopes] of listeners){ for (const scope of scopes){ listener.bind(scope)(data); } } return this; } /** * Create new Map storage of listeners for the specified event. * * @param event The name of the event. */ _createNewEvent(event) { const listeners = new Map(); this._eventListeners.set(event, listeners); } /** * Create new Set storage of scopes for the specified event and listener. * * @param event The name of the event. * @param listener The event listener. */ _createNewListener(event, listener) { const scopes = new Set(); const listeners = this._eventListeners.get(event); if (listeners) { listeners.set(listener, scopes); } } /** * Retrieves the scopes in which the specified event listener should be * executed for the specified event. * * @param event The name of the event. * @param listener The event listener. * @return The scopes in which the specified listeners * should be executed in case of the specified event. The returned * set is an unmodifiable empty set if no listeners are registered * for the event. */ _getScopesOf(event, listener) { const listenersToScopes = this._getListenersOf(event); if (listenersToScopes.has(listener)) { return listenersToScopes.get(listener); } return EMPTY_SET; } /** * Retrieves the map of event listeners to scopes they are bound to. * * @param event The name of the event. * @return A map of event listeners to the * scopes in which they should be executed. The returned map is an * unmodifiable empty map if no listeners are registered for the * event. */ _getListenersOf(event) { if (this._eventListeners.has(event)) { return this._eventListeners.get(event); } return EMPTY_MAP; } } //# sourceMappingURL=DispatcherImpl.js.map