UNPKG

ampersand-events

Version:

Module that can be mixed into any object to provide eventing. Heavily based on Backbone Events.

124 lines (110 loc) 4.74 kB
/*$AMPERSAND_VERSION*/ var runOnce = require('lodash/once'); var keys = require('lodash/keys'); var isEmpty = require('lodash/isEmpty'); var assign = require('lodash/assign'); var forEach = require('lodash/forEach'); var slice = Array.prototype.slice; var utils = require('./libs/utils'); var Events = { // Bind an event to a `callback` function. Passing `"all"` will bind // the callback to all events fired. on: function (name, callback, context) { if (!utils.eventsApi(this, 'on', name, [callback, context]) || !callback) return this; this._events || (this._events = {}); var events = this._events[name] || (this._events[name] = []); events.push({callback: callback, context: context, ctx: context || this}); return this; }, // Bind an event to only be triggered a single time. After the first time // the callback is invoked, it will be removed. once: function (name, callback, context) { if (!utils.eventsApi(this, 'once', name, [callback, context]) || !callback) return this; var self = this; var once = runOnce(function () { self.off(name, once); callback.apply(this, arguments); }); once._callback = callback; return this.on(name, once, context); }, // Remove one or many callbacks. If `context` is null, removes all // callbacks with that function. If `callback` is null, removes all // callbacks for the event. If `name` is null, removes all bound // callbacks for all events. off: function (name, callback, context) { var retain, ev, events, names, i, l, j, k; if (!this._events || !utils.eventsApi(this, 'off', name, [callback, context])) return this; if (!name && !callback && !context) { this._events = void 0; return this; } names = name ? [name] : keys(this._events); for (i = 0, l = names.length; i < l; i++) { name = names[i]; if (events = this._events[name]) { this._events[name] = retain = []; if (callback || context) { for (j = 0, k = events.length; j < k; j++) { ev = events[j]; if ((callback && callback !== ev.callback && callback !== ev.callback._callback) || (context && context !== ev.context)) { retain.push(ev); } } } if (!retain.length) delete this._events[name]; } } return this; }, // Trigger one or many events, firing all bound callbacks. Callbacks are // passed the same arguments as `trigger` is, apart from the event name // (unless you're listening on `"all"`, which will cause your callback to // receive the true name of the event as the first argument). trigger: function (name) { if (!this._events) return this; var args = slice.call(arguments, 1); if (!utils.eventsApi(this, 'trigger', name, args)) return this; var events = this._events[name]; var allEvents = this._events.all; if (events) utils.triggerEvents(events, args); if (allEvents) utils.triggerEvents(allEvents, arguments); return this; }, // Tell this object to stop listening to either specific events ... or // to every object it's currently listening to. stopListening: function (obj, name, callback) { var listeningTo = this._listeningTo; if (!listeningTo) return this; var remove = !name && !callback; if (!callback && typeof name === 'object') callback = this; if (obj) (listeningTo = {})[obj._listenId] = obj; var self = this; forEach(listeningTo, function (item, id) { item.off(name, callback, self); if (remove || isEmpty(item._events)) delete self._listeningTo[id]; }); return this; }, // extend an object with event capabilities if passed // or just return a new one. createEmitter: function (obj) { return assign(obj || {}, Events); }, listenTo: utils.createListenMethod('on'), listenToOnce: utils.createListenMethod('once'), listenToAndRun: function (obj, name, callback) { this.listenTo.apply(this, arguments); if (!callback && typeof name === 'object') callback = this; callback.apply(this); return this; } }; // setup aliases Events.bind = Events.on; Events.unbind = Events.off; Events.removeListener = Events.off; Events.removeAllListeners = Events.off; Events.emit = Events.trigger; module.exports = Events;