All files / core/util EventEmitter.ts

61.29% Statements 19/31
33.33% Branches 5/15
71.43% Functions 5/7
64.29% Lines 18/28
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                                12x           12x 84x                   84x 84x                                       12x                     12x 62x 62x 62x   62x 62x 62x       12x                           12x 62x   62x         12x  
/**
 * Copyright 2017 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
 
import { assert } from '@firebase/util';
 
/**
 * Base class to be used if you want to emit events. Call the constructor with
 * the set of allowed event names.
 */
export abstract class EventEmitter {
  private listeners_: {
    [eventType: string]: Array<{
      callback(...args: any[]): void;
      context: any;
    }>;
  } = {};
 
  /**
   * @param {!Array.<string>} allowedEvents_
   */
  constructor(private allowedEvents_: Array<string>) {
    assert(
      Array.isArray(allowedEvents_) && allowedEvents_.length > 0,
      'Requires a non-empty array'
    );
  }
 
  /**
   * To be overridden by derived classes in order to fire an initial event when
   * somebody subscribes for data.
   *
   * @param {!string} eventType
   * @return {Array.<*>} Array of parameters to trigger initial event with.
   */
  abstract getInitialEvent(eventType: string): any[];
 
  /**
   * To be called by derived classes to trigger events.
   * @param {!string} eventType
   * @param {...*} var_args
   */
  protected trigger(eventType: string, ...var_args: any[]) {
    if (Array.isArray(this.listeners_[eventType])) {
      // Clone the list, since callbacks could add/remove listeners.
      const listeners = [...this.listeners_[eventType]];
 
      for (let i = 0; i < listeners.length; i++) {
        listeners[i].callback.apply(listeners[i].context, var_args);
      }
    }
  }
 
  on(eventType: string, callback: (a: any) => void, context: any) {
    this.validateEventType_(eventType);
    this.listeners_[eventType] = this.listeners_[eventType] || [];
    this.listeners_[eventType].push({ callback, context });
 
    const eventData = this.getInitialEvent(eventType);
    Eif (eventData) {
      callback.apply(context, eventData);
    }
  }
 
  off(eventType: string, callback: (a: any) => void, context: any) {
    this.validateEventType_(eventType);
    const listeners = this.listeners_[eventType] || [];
    for (let i = 0; i < listeners.length; i++) {
      if (
        listeners[i].callback === callback &&
        (!context || context === listeners[i].context)
      ) {
        listeners.splice(i, 1);
        return;
      }
    }
  }
 
  private validateEventType_(eventType: string) {
    assert(
      this.allowedEvents_.find(function(et) {
        return et === eventType;
      }),
      'Unknown event: ' + eventType
    );
  }
}