all files / src/ async-event-dispatcher.ts

100% Statements 28/28
100% Branches 8/8
100% Functions 10/10
100% Lines 27/27
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122                                         12×                   10×                                                                                         21× 10×   21×                                          
import {GenericEvent} from './generic-event';
import {EventCallable, Observer} from './interfaces';
 
/**
 * The AsyncEventDispatcher is the central point of RxStack's event listener system.
 */
export class AsyncEventDispatcher {
 
  /**
   * Holds all events and its listeners
   *
   * @type {Map<any, any>}
   */
  private stack: Map<string, Observer[]> = new Map();
 
  /**
   * Adds an event listener that listens on the specified events.
   *
   * @param {string} eventName
   * @param {EventCallable} callable
   * @param {number} priority
   */
  addListener(eventName: string, callable: EventCallable, priority = 0): void {
    this.getNamedStack(eventName).push({name: eventName, callable: callable, priority: priority});
  }
 
  /**
   * Gets the listeners of a specific event sorted by descending priority.
   *
   * @param {string} eventName
   * @returns {EventCallable[]}
   */
  getListeners(eventName: string): EventCallable[] {
    const listeners = this.getNamedStack(eventName);
    return listeners
      .sort((a: Observer , b: Observer) => a.priority - b.priority)
      .map((item: Observer) => item.callable)
    ;
  }
 
  /**
   * Checks whether an event has any registered listeners.
   *
   * @param {string} eventName
   * @returns {boolean}
   */
  hasListeners(eventName: string): boolean {
    return this.stack.has(eventName);
  }
 
  /**
   *  Removes event listeners from the specified event.
   *
   * @param {string} eventName
   */
  removeListeners(eventName: string): void {
    this.stack.delete(eventName);
  }
 
  /**
   * Removes all event listeners
   */
  reset(): void {
    this.stack.clear();
  }
 
  /**
   * Dispatches an event to all registered listeners.
   *
   * @param {string} eventName
   * @param {GenericEvent} event
   * @returns {Promise<GenericEvent>}
   */
  async dispatch(eventName: string, event?: GenericEvent): Promise<GenericEvent> {
    if (!event)
      event = new GenericEvent();
    console.log('dddddd');
    const listeners = this.getListeners(eventName);
    if (listeners.length > 0)
      await this.doDispatch(listeners, event);
 
    return event;
  }
 
  /**
   * Gets a stack of a particular event
   *
   * @param {string} name
   * @returns {Observer[]}
   */
  private getNamedStack(name: string): Observer[] {
    if (!this.stack.has(name))
      this.stack.set(name, []);
 
    return this.stack.get(name);
  }
 
  /**
   * Triggers the listeners of an event.
   *
   * @param {EventCallable[]} listeners
   * @param {GenericEvent} event
   * @returns {Promise<GenericEvent>}
   */
  private async doDispatch(listeners: EventCallable[], event: GenericEvent): Promise<GenericEvent> {
    return listeners.reduce((currrent: Promise<GenericEvent>, next: EventCallable): Promise<GenericEvent> => {
      return currrent.then(async (): Promise<GenericEvent> => {
        if (event.isPropagationStopped())
          return event;
        return next.call(this, event);
      });
 
    }, Promise.resolve(event));
  }
}
 
/**
 * Exports single instance of AsyncEventDispatcher
 *
 * @type {AsyncEventDispatcher}
 */
export const asyncEventDispatcher = new AsyncEventDispatcher();