Source: mixin/events.js

/*! events.js */

/** This mixin provides
 * [on()]{@linkcode KagoDB#on},
 * [once()]{@linkcode KagoDB#once},
 * [off()]{@linkcode KagoDB#off} and
 * [emit()]{@linkcode KagoDB#emit} methods to fire and receive events.
 *
 * @class events
 * @mixin
 * @example
 * var collection = new KagoDB();
 *
 * collection.on('hello', function(data) {
 *   console.log('Hello,', data);
 * });
 *
 * collection.emit('hello', 'world!'); // => 'hello, world!'
 */

module.exports = function() {
  var mixin = {};
  mixin.on = on;
  mixin.off = off;
  mixin.once = once;
  mixin.emit = emit;
  return mixin;
};

/**
 * This adds a listener to the end of the listeners array for the specified event.
 *
 * @method KagoDB.prototype.on
 * @param {String} event - event name
 * @param {Function} listener - listner function
 * @returns this class itself for method chaining
 * @see http://nodejs.org/api/events.html#events_emitter_on_event_listener
 */

function on(event, listener) {
  var ev = this._events || (this._events = {});
  var array = ev[event] || (ev[event] = []);
  array.push(listener);
  return this;
}

/**
 * This removes listeners.
 *
 * @method KagoDB.prototype.off
 * @param {String} [event] - event name
 * @param {Function} [listener] - listner function
 * @returns this class itself for method chaining
 */

function off(event, listener) {
  var ev = this._events;
  var array;
  if (!ev) {
    // no events registered
    return this;
  } else if (!event) {
    // remove all events
    delete this._events;
    return this;
  }

  array = ev[event];
  if (!array) {
    // no listener registered on this event
    return this;
  } else if (!listener) {
    // remove all listeners on this event
    delete ev[event];
    return this;
  }

  // remove the specified listener on this event
  ev[event] = array.filter(function(test) {
    return listener != test;
  });
  return this;
}

/**
 * This adds a one time listener for the event.
 * This listener is invoked only the next time the event is fired, after which it is removed.
 *
 * @method KagoDB.prototype.once
 * @param {String} event - event name
 * @param {Function} listener - listner function
 * @returns this class itself for method chaining
 * @see http://nodejs.org/api/events.html#events_emitter_once_event_listener
 */

function once(event, listener) {
  var self = this;
  var wrap = function() {
    if (wrap.done) return;
    self.off(event, listener);
    listener.apply(this, arguments);
    wrap.done = true;
  };
  this.on(event, wrap);
  return this;
}

/**
 * This fires an event with the supplied arguments. It executes each of the listeners in order.
 *
 * @method KagoDB.prototype.emit
 * @param {String} event - event name
 * @param args... - multiple arguments allowed.
 * @returns this class itself for method chaining
 * @see http://nodejs.org/api/events.html#events_emitter_emit_event_arg1_arg2
 */

function emit(event) {
  var self = this;
  var ev = this._events;
  var array, args;
  if (!ev) {
    // no events registered
    return;
  }

  array = ev[event];
  if (!array) {
    // no listener registered on this event
    return;
  }

  args = Array.prototype.slice.call(arguments);
  args.shift();
  array.forEach(function(listener) {
    listener.apply(self, args);
  });
  return this;
}