Signals/Signals.js


/**
 * Dispatch and watch custom events.
 *
 * @module Signals
 *
 * @author       FeniXEngine Contributors
 * @copyright    2018 FeniXEngine
 * @license      {@link https://gitlab.com/FeniXEngineMV/fenix-tools/blob/master/LICENSE|MIT License}
 *
 * @example
 *
 * import {Signals} from 'fenix-tools'
 *
 * const dispatcher = Signals()
 *
 */
/**
 * Signals will return a {@link module:Signals~dispatcher|dispatcher} client to
 * use for adding and watching custom events.
 *
 * @function
 * @example
 * import {Dispatcher} from 'fenix-tools'
 *
 * const dispatcher = Signals()
 * // Emit the signal event
 * dispatcher.emit('my-event', eventData)
 *
 * // Do something when the signal event is emitted
 * dispatcher.on('my-event', (eventData) => {
 *   // Perform actions with eventData
 * })
 *
 * // Remove the signal event
 * dispatcher.remove('my-event')
 *
 * @return {dispatcher}
 */
export default function Signals () {
  /** An array that stores all custom events created by the dispatcher
   * @protected
   * @type {array}
   * @memberof module:Signals
   */
  const _events = []
  /**
   * Dispatcher interface is returned when creating a Signal client via
   * {@link module:Signals~Signals|Signals()}
   * @name dispatcher
   * @inner
   * @memberof module:Signals
   * @property {function} on - Adds a custom signal event.
   * @property {function} emit - Emits a custom signal event by calling the events handler.
   * @property {function} remove - Removes a custom signal event.
   */
  const dispatcher = {
    /**
     * Adds a custom signal event to the array.
     * (see: {@link module:Signals~dispatcher|dispatcher})
     *
     * @function
     * @memberof module:Signals
     * @instance dispatcher.on
     *
     * @param {string} name - The name you'd like to call this signal
     * @param {callback} handler  - A function which is called when signal is emitted.
     * @param {context} context - The context in which to run the callback function
     * @example
     * dispatcher.on('my-event', (args) => {
     *   // Perform some actions when event is called
     * })
     */
    on (name, handler, context) {
      const signal = { name, handler, context }
      _events.push(signal)
    },

    /**
     * Removes a signal form the events
     * (see: {@link module:Signals~dispatcher|dispatcher})
     *
     * @function
     * @memberof module:Signals
     * @instance dispatcher.remove
     *
     * @param {*} name - The name of the signal event
     * @example
     * dispatcher.remove('my-event')
     */
    remove (name) {
      const index = _events[name]
      _events.splice(0, index)
    },

    /**
     * Emits a signal, calling the events handler when doing so.
     * (see: {@link module:Signals~dispatcher|dispatcher})
     *
     * @function
     * @memberof module:Signals
     * @instance dispatcher.emit
     *
     * @param {*} name - The name of the signal event
     * @param {*} args - Arguments to pass through to the signal events handler.
     * @example
     * dispatcher.emit('my-event', someData)
     */
    emit (name, ...args) {
      _events.filter(event => event.name === name)
        .forEach(event => event.handler.call(event.context, ...args))
    }
  }
  return dispatcher
}