Source: EventHandling.js

/**
 * @module nyc/EventHandling
 */

import $ from 'jquery'

/**
 * @desc Class to provide event handling functionality
 * @public
 * @abstract
 * @class
 */
class EventHandling {
/**
 * @desc Create an instance of EventHandling
 * @public
 * @constructor
 */
  constructor() {
    /**
     * @private
     * @type {Object<string, Array<EventHandling.Handler>>}
     */
    this.evtHdlrs = {}
  }
  /**
   * @desc Connect a function to an event
   * @public
   * @method
   * @param {string} eventName The name of the event to which the handler will be connected
   * @param {function(Object)} evtHdlr The event handler function
   * @param {Object=} hdlrScope The scope in which to invoke the event handler
   */
  on(eventName, evtHdlr, hdlrScope) {
    this.addHdlr(eventName, evtHdlr, hdlrScope)
  }
  /**
   * @desc Connect a function to an event for a single invocation
   * @public
   * @method
   * @param {string} eventName The name of the event to which the handler will be connected
   * @param {function(Object)} evtHdlr The event handler function
   * @param {Object=} hdlrScope The scope in which to invoke the event handler
   */
  one(eventName, evtHdlr, hdlrScope) {
    this.addHdlr(eventName, evtHdlr, hdlrScope, true)
  }
  /**
   * @desc Trigger a named event with event data
   * @public
   * @method
   * @param {string} eventName The name of the event to trigger
   * @param {Object=} data The event data
   */
  trigger(eventName, data) {
    const handlers = this.evtHdlrs[eventName]
    const remove = []
    if (handlers) {
      handlers.forEach(hdlr => {
        if (hdlr.scope) {
          hdlr.handler.call(hdlr.scope, data)
        } else {
          hdlr.handler(data)
        }
        if (hdlr.remove) {
          remove.push(hdlr)
        }
      })
      remove.forEach(hdlr => {
        handlers.splice($.inArray(hdlr, handlers), 1)
      })
    }
  }
  /**
   * @desc Remove a previously connected event handler
   * @public
   * @method
   * @param {string} eventName The name of the event to which the handler will be connected
   * @param {function(Object)} evtHdlr The event handler function
   * @param {Object=} hdlrScope The scope in which to invoke the event handler
   */
  off(eventName, evtHdlr, hdlrScope) {
    const handlers = this.evtHdlrs[eventName]
    handlers.forEach((hdlr, index) => {
      if (hdlr.handler === evtHdlr && hdlr.scope === hdlrScope) {
        handlers.splice(index, 1)
        return false
      }
    })
  }
  /**
   * @private
   * @method
   * @param {string} eventName Name of the event
   * @param {function(Object)} evtHdlr Event handler
   * @param {Object} hdlrScope Scope of the handler
   * @param {boolean} one Single handler or not
   */
  addHdlr(eventName, evtHdlr, hdlrScope, one) {
    this.evtHdlrs[eventName] = this.evtHdlrs[eventName] || []
    this.evtHdlrs[eventName].push({handler: evtHdlr, scope: hdlrScope, remove: one})
  }
}

/**
 * @desc Object type to hold event handlers
 * @private
 * @typedef {Object}
 * @property {function(Object)} handler The event handler
 * @property {Object} scope The event handler scope
 * @property {boolean} [remove=false] Remove after one execution
 */
EventHandling.Handler

export default EventHandling