UNPKG

mana-common

Version:

Common utils for mana

185 lines (143 loc) 3.84 kB
let _Symbol$iterator; /* eslint-disable @typescript-eslint/ban-types */ /* eslint-disable @typescript-eslint/no-explicit-any */ import { Disposable } from './disposable'; export var Event; (function (Event) { Event.None = () => Disposable.NONE; function map(event, mapFunc) { return (listener, context) => event(i => listener.call(context, mapFunc(i)), undefined); } Event.map = map; })(Event || (Event = {})); _Symbol$iterator = Symbol.iterator; class CallbackList { constructor(mono = false) { this.mono = void 0; this._callbacks = void 0; this.mono = mono; } get callbacks() { if (!this._callbacks) { this._callbacks = []; } return this._callbacks; } get length() { return this.callbacks.length; } add(callback, context = undefined) { this.callbacks.push([callback, context]); } remove(callback, context = undefined) { if (this.isEmpty()) return; let foundCallbackWithDifferentContext = false; for (let i = 0; i < this.length; i += 1) { if (this.callbacks[i][0] === callback) { if (this.callbacks[i][1] === context) { // remove when callback & context match this.callbacks.splice(i, 1); return; } foundCallbackWithDifferentContext = true; } } if (foundCallbackWithDifferentContext) { throw new Error('You should remove it with the same context you add it'); } } [_Symbol$iterator]() { if (this.isEmpty()) { return [][Symbol.iterator](); } const callbacks = this.callbacks.slice(0); return callbacks.map(callback => (...args) => callback[0].apply(callback[1], args))[Symbol.iterator](); } invoke(...args) { const ret = []; for (const callback of this) { try { ret.push(callback(...args)); } catch (e) { console.error(e); } } return ret; } isEmpty() { return this.callbacks.length === 0; } dispose() { this._callbacks = undefined; } } export class Emitter { constructor(options = {}) { this.options = void 0; this._event = void 0; this._callbacks = void 0; this.disposed = false; this.options = options; } get callbacks() { if (!this._callbacks) { this._callbacks = new CallbackList(); } return this._callbacks; } /** * For the public to allow to subscribe * to events from this Emitter */ get event() { if (!this._event) { this._event = (listener, thisArgs) => { if (this.options.onFirstListenerAdd && this.callbacks.isEmpty()) { this.options.onFirstListenerAdd(this); } this.callbacks.add(listener, thisArgs); const result = { dispose: () => { result.dispose = Emitter.noop; if (!this.disposed) { this.callbacks.remove(listener, thisArgs); result.dispose = Emitter.noop; if (this.options.onLastListenerRemove && this.callbacks.isEmpty()) { this.options.onLastListenerRemove(this); } } } }; return result; }; } return this._event; } fire(event) { if (!this._callbacks) { return; } this.callbacks.invoke(event); } /** * Process each listener one by one. * Return `false` to stop iterating over the listeners, `true` to continue. */ async sequence(processor) { for (const listener of this.callbacks) { // eslint-disable-next-line no-await-in-loop const result = await processor(listener); if (!result) { break; } } } dispose() { if (this._callbacks) { this._callbacks.dispose(); this._callbacks = undefined; } this.disposed = true; } } Emitter.noop = () => {};