privly/privly-applications

View on GitHub
shared/javascripts/event_emitter.js

Summary

Maintainability
A
0 mins
Test Coverage
/**
 * @fileOverview This file implements an event emitter.
 * Developers can use Privly.EventEmitter.inherit(MyClass)
 * to bring event emitter feature to his/her own class.
 *
 * Event emitter is used in `new` adapter and `seamless`
 * adapter. See shared/javascripts/viewAdapters/new.js and
 * shared/javascripts/viewAdapters/seamless.js for examples.
 */

// If Privly namespace is not initialized, initialize it
/*global Promise */
var Privly;
if (Privly === undefined) {
  Privly = {};
}

(function () {
  // If this file is already loaded, don't do it again
  if (Privly.EventEmitter !== undefined) {
    return;
  }

  Privly.EventEmitter = function () {};

  /**
   * Add an event listener.
   * 
   * @param  {String}   ev Event name
   * @param  {Function} listener
   */
  Privly.EventEmitter.prototype.on = function (ev, listener) {
    if (this.__listeners === undefined) {
      this.__listeners = {};
    }
    if (!this.__listeners.hasOwnProperty(ev)) {
      this.__listeners[ev] = [];
    }
    if (this.__listeners[ev].indexOf(listener) === -1) {
      this.__listeners[ev].push(listener);
    }
  };

  /**
   * Remove an event listener.
   * 
   * @param  {String} ev Event name
   * @param  {Function} listener
   */
  Privly.EventEmitter.prototype.off = function (ev, listener) {
    if (this.__listeners === undefined) {
      this.__listeners = {};
    }
    // delete all event listeners
    if (listener === undefined) {
      delete this.__listeners[ev];
      return;
    }
    if (!this.__listeners.hasOwnProperty(ev)) {
      return;
    }
    var idx = this.__listeners[ev].indexOf(listener);
    if (idx > -1) {
      this.__listeners[ev].splice(idx, 1);
    }
  };

  /**
   * Trigger an event.
   * If an event listener returns non-undefiend values,
   * the rest of the listeners will not be called and
   * this value will be returned.
   * 
   * @param  {String} ev Event name
   * @return {Any}
   */
  Privly.EventEmitter.prototype.emit = function (ev) {
    var i, ret;
    if (this.__listeners === undefined) {
      this.__listeners = {};
    }
    if (!this.__listeners.hasOwnProperty(ev)) {
      return;
    }
    for (i = 0; i < this.__listeners[ev].length; ++i) {
      ret = this.__listeners[ev][i].apply(this, Array.prototype.slice.call(arguments, 1));
      if (ret !== undefined) {
        return ret;
      }
    }
  };

  /**
   * Trigger an event and returns a resolved Promise
   * if none of the event listeners returns a Promise.
   *
   * Requires Promise loaded.
   * 
   * @param  {String} ev Event name
   * @return {Promise<Any>}
   */
  Privly.EventEmitter.prototype.emitAsync = function () {
    var retValue = this.emit.apply(this, arguments);
    if (typeof retValue === 'object' && retValue !== null && retValue.then !== undefined) {
      // event listeners returns a Promise: use the Promise as a return value
      return retValue;
    } else {
      // non return values from event listeners,
      // or event listeners returns a non-Promise value: returns a resolved Promise
      return Promise.resolve(retValue);
    }
  };

  /**
   * Helper function to add event emitter feature
   * to an object or a class.
   * 
   * @param  {Object|Function} obj
   */
  Privly.EventEmitter.inherit = function (obj) {
    var prop, dest;
    if (typeof obj === 'function') {
      dest = obj.prototype;
    } else {
      dest = obj;
    }
    for (prop in Privly.EventEmitter.prototype) {
      if (Privly.EventEmitter.prototype.hasOwnProperty(prop)) {
        dest[prop] = Privly.EventEmitter.prototype[prop];
      }
    }
  };

}());