UNPKG

3.76 kBJavaScriptView Raw
1'use strict';
2
3/**
4 * Module exports.
5 */
6
7exports.EventEmitter = EventEmitter;
8
9/**
10 * Object#toString reference.
11 */
12var objToString = Object.prototype.toString;
13
14/**
15 * Check if a value is an array.
16 *
17 * @api private
18 * @param {*} val The value to test.
19 * @return {boolean} true if the value is an array, otherwise false.
20 */
21function isArray (val) {
22 return objToString.call(val) === '[object Array]';
23}
24
25/**
26 * Event emitter constructor.
27 *
28 * @api public
29 */
30function EventEmitter () {}
31
32/**
33 * Add a listener.
34 *
35 * @api public
36 * @param {string} name Event name.
37 * @param {Function} fn Event handler.
38 * @return {EventEmitter} Emitter instance.
39 */
40EventEmitter.prototype.on = function (name, fn) {
41 if (!this.$events) {
42 this.$events = {};
43 }
44
45 if (!this.$events[name]) {
46 this.$events[name] = fn;
47 } else if (isArray(this.$events[name])) {
48 this.$events[name].push(fn);
49 } else {
50 this.$events[name] = [this.$events[name], fn];
51 }
52
53 return this;
54};
55
56EventEmitter.prototype.addListener = EventEmitter.prototype.on;
57
58/**
59 * Adds a volatile listener.
60 *
61 * @api public
62 * @param {string} name Event name.
63 * @param {Function} fn Event handler.
64 * @return {EventEmitter} Emitter instance.
65 */
66EventEmitter.prototype.once = function (name, fn) {
67 var self = this;
68
69 function on () {
70 self.removeListener(name, on);
71 fn.apply(this, arguments);
72 }
73
74 on.listener = fn;
75 this.on(name, on);
76
77 return this;
78};
79
80/**
81 * Remove a listener.
82 *
83 * @api public
84 * @param {string} name Event name.
85 * @param {Function} fn Event handler.
86 * @return {EventEmitter} Emitter instance.
87 */
88EventEmitter.prototype.removeListener = function (name, fn) {
89 if (this.$events && this.$events[name]) {
90 var list = this.$events[name];
91
92 if (isArray(list)) {
93 var pos = -1;
94
95 for (var i = 0, l = list.length; i < l; i++) {
96 if (list[i] === fn || (list[i].listener && list[i].listener === fn)) {
97 pos = i;
98 break;
99 }
100 }
101
102 if (pos < 0) {
103 return this;
104 }
105
106 list.splice(pos, 1);
107
108 if (!list.length) {
109 delete this.$events[name];
110 }
111 } else if (list === fn || (list.listener && list.listener === fn)) {
112 delete this.$events[name];
113 }
114 }
115
116 return this;
117};
118
119/**
120 * Remove all listeners for an event.
121 *
122 * @api public
123 * @param {string} name Event name.
124 * @return {EventEmitter} Emitter instance.
125 */
126EventEmitter.prototype.removeAllListeners = function (name) {
127 if (name === undefined) {
128 this.$events = {};
129 return this;
130 }
131
132 if (this.$events && this.$events[name]) {
133 this.$events[name] = null;
134 }
135
136 return this;
137};
138
139/**
140 * Get all listeners for a given event.
141 *
142 * @api public
143 * @param {string} name Event name.
144 * @return {EventEmitter} Emitter instance.
145 */
146EventEmitter.prototype.listeners = function (name) {
147 if (!this.$events) {
148 this.$events = {};
149 }
150
151 if (!this.$events[name]) {
152 this.$events[name] = [];
153 }
154
155 if (!isArray(this.$events[name])) {
156 this.$events[name] = [this.$events[name]];
157 }
158
159 return this.$events[name];
160};
161
162/**
163 * Emit an event.
164 *
165 * @api public
166 * @param {string} name Event name.
167 * @return {boolean} true if at least one handler was invoked, else false.
168 */
169EventEmitter.prototype.emit = function (name) {
170 if (!this.$events) {
171 return false;
172 }
173
174 var handler = this.$events[name];
175
176 if (!handler) {
177 return false;
178 }
179
180 var args = Array.prototype.slice.call(arguments, 1);
181
182 if (typeof handler === 'function') {
183 handler.apply(this, args);
184 } else if (isArray(handler)) {
185 var listeners = handler.slice();
186
187 for (var i = 0, l = listeners.length; i < l; i++) {
188 listeners[i].apply(this, args);
189 }
190 } else {
191 return false;
192 }
193
194 return true;
195};