Code coverage report for bookshelf/lib/base/events.js

Statements: 48.48% (32 / 66)      Branches: 21.43% (3 / 14)      Functions: 37.5% (3 / 8)      Lines: 50% (30 / 60)      Ignored: none     

All files » bookshelf/lib/base/ » events.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154          1 1 1 1                   1     1     1               1                                   1                               1   200010                   200010 200010                                           1 2         2 2 2 4         2 2               6   2 2 2 2     2     1               1                   1
// Events
// ---------------
 
'use strict';
 
var Promise = require('./promise');
var inherits = require('inherits');
var EventEmitter = require('events').EventEmitter;
var _ = require('lodash');
 
/**
 * @class Events
 * @class
 *
 * Bookshelf includes events based on those provided by
 * [Backbone](http://backbonejs.org/).
 *
 */
function Events() {
  EventEmitter.apply(this, arguments);
}
inherits(Events, EventEmitter);
 
// Regular expression used to split event strings.
var eventSplitter = /\s+/;
 
/**
 * @method Events#on
 * @description
 * Register an event listener.
 * @see {@link http://backbonejs.org/#Events-on Backbone.js `Events#on`}
 */
Events.prototype.on = function (name, handler) {
  // Handle space separated event names.
  if (eventSplitter.test(name)) {
    var names = name.split(eventSplitter);
    for (var i = 0, l = names.length; i < l; i++) {
      this.on(names[i], handler);
    }
    return this;
  }
  return EventEmitter.prototype.on.apply(this, arguments);
};
 
/**
 * @method Events#off
 * @description
 * Deregister an event listener.
 * @see {@link http://backbonejs.org/#Events-off Backbone.js `Events#off`}
 */
Events.prototype.off = function (event, listener) {
  if (arguments.length === 0) {
    return this.removeAllListeners();
  }
  if (arguments.length === 1) {
    return this.removeAllListeners(event);
  }
  return this.removeListener(event, listener);
};
 
/**
 * @method Events#off
 * @description
 * Deregister an event listener.
 * @see {@link http://backbonejs.org/#Events-off Backbone.js `Events#off`}
 */
Events.prototype.trigger = function (name) {
  // Handle space separated event names.
  Iif (eventSplitter.test(name)) {
    var len = arguments.length;
    var rest = new Array(len - 1);
    for (i = 1; i < len; i++) rest[i - 1] = arguments[i];
    var names = name.split(eventSplitter);
    for (var i = 0, l = names.length; i < l; i++) {
      EventEmitter.prototype.emit.apply(this, [names[i]].concat(rest));
    }
    return this;
  }
  EventEmitter.prototype.emit.apply(this, arguments);
  return this;
};
 
/**
 * @method Events#triggerThen
 * @description
 * A promise version of {@link Events#trigger}, returning a promise which
 * resolves with all return values from triggered event handlers. If any of the
 * event handlers throw an `Error` or return a rejected promise, the promise
 * will be rejected. Used internally on the {@link Model#creating "creating"},
 * {@link Model#updating "updating"}, {@link Model#saving "saving"}, and {@link
 * Model@destroying "destroying"} events, and can be helpful when needing async
 * event handlers (for validations, etc).
 *
 * @param {string} name
 *   The event name, or a whitespace-separated list of event names, to be
 *   triggered.
 * @param {...mixed} args
 *   Arguments to be passed to any registered event handlers.
 * @returns Promise<mixed[]>
 *   A promise resolving the the resolved return values of any triggered handlers.
 */
Events.prototype.triggerThen = function (name) {
  var i,
      l,
      rest,
      listeners = [];
  // Handle space separated event names.
  Eif (eventSplitter.test(name)) {
    var names = name.split(eventSplitter);
    for (i = 0, l = names.length; i < l; i++) {
      listeners = listeners.concat(this.listeners(names[i]));
    }
  } else {
    listeners = this.listeners(name);
  }
  var len = arguments.length;
  switch (len) {
    case 1:
      rest = [];break;
    case 2:
      rest = [arguments[1]];break;
    case 3:
      rest = [arguments[1], arguments[2]];break;
    default:
      rest = new Array(len - 1);for (i = 1; i < len; i++) rest[i - 1] = arguments[i];
  }
  var events = this;
  return Promise['try'](function () {
    var pending = [];
    for (i = 0, l = listeners.length; i < l; i++) {
      pending[i] = listeners[i].apply(events, rest);
    }
    return Promise.all(pending);
  });
};
Events.prototype.emitThen = Events.prototype.triggerThen;
 
/**
 * @method Events#once
 * @description
 * Register a one-off event handler.
 * @see {@link http://backbonejs.org/#Events-once Backbone.js `Events#once`}
 */
Events.prototype.once = function (name, callback, context) {
  var self = this;
  var once = _.once(function () {
    self.off(name, once);
    return callback.apply(this, arguments);
  });
  once._callback = callback;
  return this.on(name, once, context);
};
 
module.exports = Events;