/** * Copyright (c) 2019 The xterm.js authors. All rights reserved. * @license MIT */ import { IDisposable } from 'common/Types'; interface IListener { (arg1: T, arg2: U): void; } export interface IEvent { (listener: (arg1: T, arg2: U) => any): IDisposable; } export interface IEventEmitter { fire(arg1: T, arg2: U): void; dispose(): void; } export interface IEventWithEmitter extends IEventEmitter, IEvent { } export class EventEmitter implements IEventEmitter { private readonly _listeners: IListener[] = []; private _event?: IEvent; private _disposed: boolean = false; public get event(): IEvent { if (!this._event) { this._event = (listener: (arg1: T, arg2: U) => any) => { this._listeners.push(listener); const disposable = { dispose: () => { if (!this._disposed) { for (let i = 0; i < this._listeners.length; i++) { if (this._listeners[i] === listener) { this._listeners.splice(i, 1); return; } } } } }; return disposable; }; } return this._event; } public fire(arg1: T, arg2: U): void { const queue: IListener[] = []; for (let i = 0; i < this._listeners.length; i++) { queue.push(this._listeners[i]); } for (let i = 0; i < queue.length; i++) { queue[i].call(undefined, arg1, arg2); } } public dispose(): void { if (this._listeners) { this._listeners.length = 0; } this._disposed = true; } } /** * Creates an object that implements both the {@link IEvent} and {@link IEmitter} interfaces. This * allows more concise instantiation. The idea is to internally use the combined * {@link IEventWithEmitter} interface and only expose {@link IEvent} externally. * * @example * ```ts * public readonly onFoo = initEvent(); * // ... * onFoo(e => handle(e)); * onFoo.fire('bar'); * ``` */ export function initEvent(): IEventWithEmitter { const emitter = new EventEmitter(); const event = emitter.event; Object.defineProperty(event, '_listeners', { value: (emitter as any)._listeners }); Object.defineProperty(event, 'fire', { value: emitter.fire.bind(emitter) }); Object.defineProperty(event, 'dispose', { value: emitter.dispose.bind(emitter) }); return event as any; } export function forwardEvent(from: IEvent, to: IEventEmitter): IDisposable { return from(e => to.fire(e)); }