-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathampersand-events.js
123 lines (110 loc) · 4.63 KB
/
ampersand-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
/*$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;