UNPKG

@novo-learning/novo-sdk

Version:

SDK for the Novolanguage Speech Analysis API

88 lines (77 loc) 2.48 kB
export interface Event<T> { name: string; props: T; } export type EventCallbackFn<T> = (data: T) => void; export type ChanneledEventBus<T = EventBus> = EventBus & { parent: T }; /** * The EventBus allows for simple event dispatching and listening * between different instances in the library. * * Each EventBus can create a new 'channel()' which allows it to * broadcast and subscribe its own events. * * By default events will 'bubble up' when they're broadcasted, meaning * all parent EventBus instances will receive the event. */ export class EventBus { /** * Internal list of callback listeners */ // eslint-disable-next-line @typescript-eslint/no-explicit-any private readonly listeners: { [key: string]: EventCallbackFn<any>[] } = {}; constructor(readonly parent?: EventBus, readonly identifier?: string) {} /** * Creates a new EventBus 'channel' with the current EventBus * set as its parent */ channel(identifier?: string): ChanneledEventBus<this> { return new EventBus(this, identifier) as ChanneledEventBus<this>; } /** * Shortcut to root EventBus */ root(): EventBus { let eb = this.parent; if (eb === undefined) { return this; } while (eb.parent) { eb = eb.parent; } return eb; } /** * Add a new listener for the given event */ addEventListener<T = never>(event: string, callbackFn: EventCallbackFn<T>): void { this.listeners[event] = (this.listeners[event] || []).concat(callbackFn); } /** * Remove the given callback */ removeEventListener<T = never>(event: string, callbackFn?: EventCallbackFn<T>): void { if (!callbackFn) { this.listeners[event] = []; } else { const index = (this.listeners[event] || []).findIndex((fn) => fn === callbackFn); if (index > -1) { this.listeners[event].splice(index, 1); } } } /** * Dispatch a new event with the given name and set of data and invoke * all listener callbacks. * * Enable 'broadcast' to dispatch an event which bubbles up to all parent eventbusses. * Note that this is enabled by default. */ dispatch<T = never>(event: string, data?: T, broadcast?: boolean): void { (this.listeners[event] || []).forEach((callbackFn) => callbackFn(data)); if (broadcast !== false && this.parent) { // Call parent with same arguments this.parent.dispatch.apply(this.parent, [event, data, broadcast]); } } }