API Docs for: 0.0.1
Show:

File: lib/events.js

/*
* niViz -- snow profiles visualization
* Copyright (C) 2015 WSL/SLF - Fluelastrasse 11 - 7260 Davos Dorf - Switzerland.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

(function (niviz) {
  'use strict';

  var util   = niviz.util;
  var assert = util.assert;

  /** @module niviz */

  /**
   * Any object can mix-in or inherit from the
   * EventEmitter prototype.
   *
   * @example
   *   var inherits = niviz.util.inherits;
   *   var EventEmitter = niviz.EventEmitter;
   *
   *   function MyEventEmitter() {
   *     EventEmitter.call(this);
   *   }
   *
   *   inherits(MyEventEmitter, EventEmitter);
   *
   * @class EventEmitter
   * @constructor
   */
  function EventEmitter() {
    /**
     * @property events
     * @type Object
     * @private
     */
    this.events = {};
  }

  /**
   * Registers a new handler for an event.
   *
   * @method on
   * @chainable
   *
   * @param {String} type The event type.
   * @param {Function} listener The listener.
   */
  EventEmitter.prototype.on = function (type, listener) {
    assert(typeof type === 'string');
    assert(typeof listener === 'function');

    (this.events[type] = this.events[type] || []).push(listener);
    return this;
  };

  /**
   * Registers a new handler for an event
   * that will be executed at most once.
   *
   * @method once
   * @chainable
   *
   * @param {String} type The event type.
   * @param {Function} listener The listener.
   */
  EventEmitter.prototype.once = function (type, listener) {
    assert(typeof type === 'string');
    assert(typeof listener === 'function');

    var self = this;

    function proxy() {
      self.off(type, proxy);
      return listener.apply(this, arguments);
    }

    proxy.listener = listener;

    return this.on(type, proxy);
  };

  /**
   * Removes a given event listener. If no listener
   * is given, removes all listeners for the given
   * type; if no type is given, removes all listeners.
   *
   * @method off
   * @chainable
   *
   * @param {String} [type] The event type.
   * @param {Function} [listener] The listener.
   */
  EventEmitter.prototype.off = function (type, listener) {
    switch (arguments.length) {

    case 0:
      this.events = {};
      break;

    case 1:
      assert(typeof type === 'string');

      delete this.events[type];
      break;

    default:
      assert(typeof type === 'string');
      assert(typeof listener === 'function');

      var i, ii, cb;

      if ((cb = this.events[type])) {
        for (i = 0, ii = cb.length; i < ii; ++i) {
          if (cb[i] === listener || cb[i].listener === listener) {
            cb.splice(i, 1);
          }
        }
      }
    }

    return this;
  };

  /**
   * Fires event type, executing all registered
   * handlers synchronously.
   *
   * @method emit
   * @returns {Boolean} True if there were listeners;
   *   false otherwise;
   */
  EventEmitter.prototype.emit = function (type) {
    assert(typeof type === 'string');

    var listeners = this.listeners(type);

    if (type === 'error' && !listeners.length) {
      var error = arguments[1];

      if (error instanceof Error) throw error;
      throw new Error('uncaught "error" event');
    }

    if (!listeners.length) return false;

    var args = Array.prototype.slice.call(arguments, 1);
    var i, ii;

    // Make a defensive copy in case events
    // register other events!
    listeners = listeners.slice();

    for (i = 0, ii = listeners.length; i < ii; ++i)
      listeners[i].apply(this, args);

    return true;
  };

  /**
   * Returns all listeners for the given event type.
   *
   * @method listeners
   * @returns {Array<Function>} All listeners for type.
   */
  EventEmitter.prototype.listeners = function (type) {
    return this.events[type] || [];
  };

  /**
   * Registers a callback function to be called
   * by the `end` or `error` events, like a Node
   * callback would be called.
   *
   * @method nodeback
   * @chainable
   * @private
   *
   * @param {Function} callback The callback to register.
   */
  EventEmitter.prototype.nodeback = function (callback) {
    return this
      .once('end', function (result) {
        callback.apply(this, [null, result]);
      })

      .once('error', function (error) {
        callback.apply(this, [error]);
      });
  };

  // --- Module Exports ---
  niviz.EventEmitter = EventEmitter;

}(niviz));