import { Subject } from 'rxjs/Subject'; import { Subscription } from 'rxjs/Subscription'; declare type SubscriptionArray = Subscription[]; export { Subscription } from 'rxjs/Subscription'; export interface Handler { (...args: any[]): void; } export class EventEmitter { private subjects: Map>; private subscriptions: Map>; constructor() { this.subjects = new Map>(); this.subscriptions = new Map>(); } public dispose() { this.subjects.forEach((subject: Subject) => { subject.unsubscribe(); }); this.subjects.clear(); } public addListener(name: string, handler: Handler) { return this.on(name, handler); } public emit(fnName: string, ...data: any[]) { let subject = this.getSubject(fnName); subject.next(data); } public listen(name: string, handler: Handler): Subscription { let subscription = this.getSubject(name).subscribe(handler); this.registerSubscription(name, handler, subscription); return subscription; } public off(name: string, handler: Handler) { let subs = this.getSubscriptions(name, handler); subs.forEach(sub => sub.unsubscribe()); } public on(name: string, handler: Handler) { let subscription = this.getSubject(name).subscribe(val => { if (Array.isArray(val)) { handler(...val); } else { handler(val); } }); this.registerSubscription(name, handler, subscription); } public once(name: string, handler: Handler) { let onceHandler = (value: any) => { this.off(name, onceHandler); handler(value); }; return this.on(name, onceHandler); } public removeListener(name: string, handler: Handler) { return this.off(name, handler); } private registerSubscription(name: string, handler: Handler, sub: Subscription) { let handlerMap = this.subscriptions.get(name); if (!handlerMap) { handlerMap = new Map(); this.subscriptions.set(name, handlerMap); } let subArr = handlerMap.get(handler); if (!subArr) { subArr = []; handlerMap.set(handler, subArr); } subArr.push(sub); } private getSubscriptions(name: string, handler: Handler): SubscriptionArray { let handlerMap = this.subscriptions.get(name); if (!handlerMap) { return []; } return handlerMap.get(handler) || []; } private getSubject(fnName: string): Subject { let subject = this.subjects.get(fnName); if (!subject) { subject = new Subject(); this.subjects.set(fnName, subject); } return subject; } }