export class EventDescriptor { constructor(private eventDispatcher: EventDispatcher, public eventName: T, public callback: Function, public condition?: Function) { } off() { this.eventDispatcher.offEvent(this); } } export class ParentEvent { constructor(public eventName: T = null, public data?: any) { } } export class EventDispatcher { protected events: Array>; constructor() { this.events = []; } on(eventName: T, callback1?: Function, callback2?: Function) { const condition = callback2 ? callback1 : null; const callback = callback2 ? callback2 : callback1; let descriptor; this.events.push(descriptor = new EventDescriptor(this, eventName, callback, condition)); return descriptor; } once(eventName: T, callback1?: Function, callback2?: Function) { const condition = callback2 ? callback1 : null; const callback = callback2 ? callback2 : callback1; let savedEvent, descriptor; this.events.push(descriptor = new EventDescriptor(this, eventName, savedEvent = (event: ParentEvent) => { this.off(eventName, savedEvent); callback(event); }, condition)); return descriptor; } offEvent(eventDescriptor: EventDescriptor): EventDispatcher { this.events.splice(this.events.indexOf(eventDescriptor), 1); return this; } off(eventName?: T, callback?: Function) { if (!eventName && !callback) this.events.splice(0, this.events.length); this.events.filter(event => (event.eventName === eventName && !callback) || (event.eventName === null && callback && event.callback === callback) || (event.eventName === eventName && callback && event.callback === callback) ).forEach(event => this.events.splice(this.events.indexOf(event), 1)); return this; } fire(eventName: T | Array, data: ParentEvent = new ParentEvent()) { if (eventName instanceof Array) { eventName.forEach(event => this.fire(event, data)); } else { data.eventName = eventName; this.events.slice().forEach(event => event.eventName === eventName && (!event.condition || (event.condition && event.condition(data, event, this))) && event.callback(data, event, this)); } return this; } }