/** * Handles named events. */ export default class NamedEventHandler { constructor () { this._eventListener = new Map() this._stateListener = new Map() } /** * @private * Returns all listeners that listen to a specified name. * * @param {String} name The query event name. */ _getListener (name) { let listeners = this._eventListener.get(name) if (listeners === undefined) { listeners = { once: new Set(), on: new Set() } this._eventListener.set(name, listeners) } return listeners } /** * Adds a named event listener. The listener is removed after it has been * called once. * * @param {String} name The event name to listen to. * @param {Function} f The function that is executed when the event is fired. */ once (name, f) { let listeners = this._getListener(name) listeners.once.add(f) } /** * Adds a named event listener. * * @param {String} name The event name to listen to. * @param {Function} f The function that is executed when the event is fired. */ on (name, f) { let listeners = this._getListener(name) listeners.on.add(f) } /** * @private * Init the saved state for an event name. */ _initStateListener (name) { let state = this._stateListener.get(name) if (state === undefined) { state = {} state.promise = new Promise(function (resolve) { state.resolve = resolve }) this._stateListener.set(name, state) } return state } /** * Returns a Promise that is resolved when the event name is called. * The Promise is immediately resolved when the event name was called in the * past. */ when (name) { return this._initStateListener(name).promise } /** * Remove an event listener that was registered with either * {@link EventHandler#on} or {@link EventHandler#once}. */ off (name, f) { if (name == null || f == null) { throw new Error('You must specify event name and function!') } const listener = this._eventListener.get(name) if (listener !== undefined) { listener.on.delete(f) listener.once.delete(f) } } /** * Emit a named event. All registered event listeners that listen to the * specified name will receive the event. * * @param {String} name The event name. * @param {Array} args The arguments that are applied to the event listener. */ emit (name, ...args) { this._initStateListener(name).resolve() const listener = this._eventListener.get(name) if (listener !== undefined) { listener.on.forEach(f => f.apply(null, args)) listener.once.forEach(f => f.apply(null, args)) listener.once = new Set() } else if (name === 'error') { console.error(args[0]) } } destroy () { this._eventListener = null } }