okiba-gang/okiba

View on GitHub
packages/event-emitter/index.js

Summary

Maintainability
A
0 mins
Test Coverage
/**
 * @module EventEmitter
 * @description Emits events that can be listened and unlistened to. Allows for a catch-all event which is always triggered.
 * @example
 * import EventEmitter from '@okiba/event-emitter'
 * const emitter = new EventEmitter
 * emitter.on('log', console.log)
 * emitter.emit('log', 'Silence is deprecated')
 * // Logs: 'Silence is deprecated'
 *
 * emitter.off('log', console.log)
 * emitter.emit('log', 'Will not run')
 * // ...Nothing happens
 */
class EventEmitter {
  constructor() {
    this.hs = {}
  }

  /**
   * Sets an event listener for an event type
   * @param  {String} name    Event type
   * @param  {Function} handler Callback to be fired when that event occours
   */
  on(name, handler) {
    (
      this.hs[name] || (this.hs[name] = new Map())
    ).set(handler, handler)
  }

  /**
   * Unsets an event listener for an event type
   * @param  {String} name    Event type
   * @param  {Function} handler Callback previously registered for that event type
   */
  off(name, handler) {
    if (!this.hs[name]) return
    this.hs[name].delete(handler)
  }

  /**
   * Triggers an event with optional data attached.
   * All listeners will be triggered in registration order.
   * Custom data will be passed to them as a parameter
   * @param  {String} name Event type
   * @param  {Object} [data] Custom data to be passed to the handlers
   */
  emit(name, data) {
    if (!this.hs) return

    if (this.hs[name]) {
      this.hs[name].forEach(handler => handler(data))
    }

    if (this.hs['*']) {
      this.hs['*'].forEach(handler => handler(data))
    }
  }

  /**
   * Checks if the given event has at least one registered callback
   * @param {String} type The event type
   */
  hasListeners(type) {
    return this.hs.hasOwnProperty(type) && this.hs[type].size > 0
  }

  /**
   * Removes all event listeners and deletes the handlers object
   */
  destroy() {
    Object.keys(this.hs)
      .forEach((name) =>
        this.hs[name].clear()
      )

    delete this.hs
  }
}

export default EventEmitter