UNPKG

7.7 kBJavaScriptView Raw
1'use strict';
2
3var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
4
5function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
6
7var DEFAULT_VALUES = {
8 emitDelay: 10,
9 strictMode: false
10};
11
12/**
13 * @typedef {object} EventEmitterListenerFunc
14 * @property {boolean} once
15 * @property {function} fn
16 */
17
18/**
19 * @class EventEmitter
20 *
21 * @private
22 * @property {Object.<string, EventEmitterListenerFunc[]>} _listeners
23 * @property {string[]} events
24 */
25
26var EventEmitter = function () {
27
28 /**
29 * @constructor
30 * @param {{}} [opts]
31 * @param {number} [opts.emitDelay = 10] - Number in ms. Specifies whether emit will be sync or async. By default - 10ms. If 0 - fires sync
32 * @param {boolean} [opts.strictMode = false] - is true, Emitter throws error on emit error with no listeners
33 */
34
35 function EventEmitter() {
36 var opts = arguments.length <= 0 || arguments[0] === undefined ? DEFAULT_VALUES : arguments[0];
37
38 _classCallCheck(this, EventEmitter);
39
40 var emitDelay = void 0,
41 strictMode = void 0;
42
43 if (opts.hasOwnProperty('emitDelay')) {
44 emitDelay = opts.emitDelay;
45 } else {
46 emitDelay = DEFAULT_VALUES.emitDelay;
47 }
48 this._emitDelay = emitDelay;
49
50 if (opts.hasOwnProperty('strictMode')) {
51 strictMode = opts.strictMode;
52 } else {
53 strictMode = DEFAULT_VALUES.strictMode;
54 }
55 this._strictMode = strictMode;
56
57 this._listeners = {};
58 this.events = [];
59 }
60
61 /**
62 * @protected
63 * @param {string} type
64 * @param {function} listener
65 * @param {boolean} [once = false]
66 */
67
68
69 _createClass(EventEmitter, [{
70 key: '_addListenner',
71 value: function _addListenner(type, listener, once) {
72 if (typeof listener !== 'function') {
73 throw TypeError('listener must be a function');
74 }
75
76 if (this.events.indexOf(type) === -1) {
77 this._listeners[type] = [{
78 once: once,
79 fn: listener
80 }];
81 this.events.push(type);
82 } else {
83 this._listeners[type].push({
84 once: once,
85 fn: listener
86 });
87 }
88 }
89
90 /**
91 * Subscribes on event type specified function
92 * @param {string} type
93 * @param {function} listener
94 */
95
96 }, {
97 key: 'on',
98 value: function on(type, listener) {
99 this._addListenner(type, listener, false);
100 }
101
102 /**
103 * Subscribes on event type specified function to fire only once
104 * @param {string} type
105 * @param {function} listener
106 */
107
108 }, {
109 key: 'once',
110 value: function once(type, listener) {
111 this._addListenner(type, listener, true);
112 }
113
114 /**
115 * Removes event with specified type. If specified listenerFunc - deletes only one listener of specified type
116 * @param {string} eventType
117 * @param {function} [listenerFunc]
118 */
119
120 }, {
121 key: 'off',
122 value: function off(eventType, listenerFunc) {
123 var _this = this;
124
125 var typeIndex = this.events.indexOf(eventType);
126 var hasType = eventType && typeIndex !== -1;
127
128 if (hasType) {
129 if (!listenerFunc) {
130 delete this._listeners[eventType];
131 this.events.splice(typeIndex, 1);
132 } else {
133 (function () {
134 var removedEvents = [];
135 var typeListeners = _this._listeners[eventType];
136
137 typeListeners.forEach(
138 /**
139 * @param {EventEmitterListenerFunc} fn
140 * @param {number} idx
141 */
142 function (fn, idx) {
143 if (fn.fn === listenerFunc) {
144 removedEvents.unshift(idx);
145 }
146 });
147
148 removedEvents.forEach(function (idx) {
149 typeListeners.splice(idx, 1);
150 });
151
152 if (!typeListeners.length) {
153 _this.events.splice(typeIndex, 1);
154 delete _this._listeners[eventType];
155 }
156 })();
157 }
158 }
159 }
160
161 /**
162 * Applies arguments to specified event type
163 * @param {string} eventType
164 * @param {*[]} eventArguments
165 * @protected
166 */
167
168 }, {
169 key: '_applyEvents',
170 value: function _applyEvents(eventType, eventArguments) {
171 var typeListeners = this._listeners[eventType];
172
173 if (!typeListeners || !typeListeners.length) {
174 if (this._strictMode) {
175 throw 'No listeners specified for event: ' + eventType;
176 } else {
177 return;
178 }
179 }
180
181 var removableListeners = [];
182 typeListeners.forEach(function (eeListener, idx) {
183 eeListener.fn.apply(null, eventArguments);
184 if (eeListener.once) {
185 removableListeners.unshift(idx);
186 }
187 });
188
189 removableListeners.forEach(function (idx) {
190 typeListeners.splice(idx, 1);
191 });
192 }
193
194 /**
195 * Emits event with specified type and params.
196 * @param {string} type
197 * @param eventArgs
198 */
199
200 }, {
201 key: 'emit',
202 value: function emit(type) {
203 var _this2 = this;
204
205 for (var _len = arguments.length, eventArgs = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
206 eventArgs[_key - 1] = arguments[_key];
207 }
208
209 if (this._emitDelay) {
210 setTimeout(function () {
211 _this2._applyEvents.call(_this2, type, eventArgs);
212 }, this._emitDelay);
213 } else {
214 this._applyEvents(type, eventArgs);
215 }
216 }
217
218 /**
219 * Emits event with specified type and params synchronously.
220 * @param {string} type
221 * @param eventArgs
222 */
223
224 }, {
225 key: 'emitSync',
226 value: function emitSync(type) {
227 for (var _len2 = arguments.length, eventArgs = Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
228 eventArgs[_key2 - 1] = arguments[_key2];
229 }
230
231 this._applyEvents(type, eventArgs);
232 }
233
234 /**
235 * Destroys EventEmitter
236 */
237
238 }, {
239 key: 'destroy',
240 value: function destroy() {
241 this._listeners = {};
242 this.events = [];
243 }
244 }]);
245
246 return EventEmitter;
247}();
248
249module.exports = EventEmitter;