@irrelon/emitter 5.0.0 → 5.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/Emitter.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  The MIT License (MIT)
3
3
 
4
4
  Copyright (c) 2014 Irrelon Software Limited
5
- http://www.irrelon.com
5
+ https://www.irrelon.com
6
6
 
7
7
  Permission is hereby granted, free of charge, to any person obtaining a copy
8
8
  of this software and associated documentation files (the "Software"), to deal
@@ -25,12 +25,13 @@
25
25
  Source: https://github.com/irrelon/emitter
26
26
 
27
27
  Changelog:
28
+ Version 5.0.2:
29
+ Removed some unnecessary code, updated to be in step with version
30
+ that is being used in the new version of Isogenic Game Engine.
31
+ Version 5.0.1:
32
+ Further TypeScript updates.
28
33
  Version 5.0.0:
29
- Added typescript types, switched from mocha to jest for test
30
- running.
31
- Breaking change. When using makeEmitter, prototypeMode is now
32
- false by default. Simply pass makeEmitter(SomeClass.prototype)
33
- instead of makeEmitter(SomeClass) to modify a prototype.
34
+ Added TypeScript and prettier, removed babel etc
34
35
  Version 4.0.1:
35
36
  Updated library to use new ES6 functionality making Overload()
36
37
  less useful so it can be removed as a dependency.
@@ -83,83 +84,62 @@
83
84
  Version 1.0.0:
84
85
  First commit
85
86
  */
86
- export interface InternalEventListenersType {
87
- [eventName: string|symbol]: InternalEventListenersByIdType
87
+ export enum EventReturnFlag {
88
+ none,
89
+ cancel
88
90
  }
89
91
 
90
- export interface InternalEventListenersByIdType {
91
- [idName: string|symbol]: Array<EventListenerType>
92
- }
93
-
94
- export type EventListenerType = (...rest: any[]) => any;
95
-
96
- export interface InternalEventEmittersType {
97
- [eventName: string|symbol]: Array<EventEmitterType>
98
- }
99
-
100
- export interface EventEmitterType {
101
- id: string|symbol
102
- args: any
92
+ export type EventListenerCallback = (...args: any[]) => any | Promise<any>;
93
+ export interface EventStaticEmitterObject {
94
+ id: string;
95
+ args: any[];
103
96
  }
104
97
 
105
98
  /**
106
- * @class Emitter
107
- * @constructor
99
+ * Creates a new class with the capability to emit events.
108
100
  */
109
101
  export class Emitter {
110
- private _emitting: boolean;
111
- private _noEmitDefer: boolean;
112
- private _listeners: InternalEventListenersType
113
- private _emitters: InternalEventEmittersType
114
- private _eventRemovalQueue: Array<(...rest: any[]) => any>;
115
- private _deferTimeout: any;
116
-
117
- constructor (obj?: any) {
118
- this._noEmitDefer = false;
119
- this._emitting = false;
120
- this._listeners = {};
121
- this._emitters = {};
122
- this._eventRemovalQueue = [];
123
-
124
- if (obj !== undefined) {
125
- return makeEmitter(obj);
126
- }
127
- }
102
+ _eventsEmitting: boolean = false;
103
+ _eventRemovalQueue: any[] = [];
104
+ _eventListeners?: Record<string, Record<string, EventListenerCallback[]>>;
105
+ _eventStaticEmitters: Record<string, EventStaticEmitterObject[]> = {};
106
+ _eventsAllowDefer: boolean = false;
107
+ _eventsDeferTimeouts: Record<any, number> = {};
128
108
 
129
109
  /**
130
110
  * Attach an event listener to the passed event only if the passed
131
- * id matches the document id for the event being fired.
132
- * @memberOf Emitter
133
- * @method on
134
- * @param {String} event The name of the event to listen for.
135
- * @param {*} id The document id to match against.
136
- * @param {Function} listener The method to call when the event is fired.
111
+ * id matches the id for the event being fired.
112
+ * @param {string} eventName The name of the event to listen for.
113
+ * @param {string} id The id to match against.
114
+ * @param {function} listener The method to call when the event is fired.
137
115
  * @returns {Emitter} The emitter instance.
138
116
  */
139
- _on (event: string|symbol, id: string|symbol, listener: (...rest: any[]) => any) {
140
- const generateEmitterTimeout = (emitter: EventEmitterType) => {
117
+ _on (eventName: string, id: string, listener: EventListenerCallback) {
118
+ const generateTimeout = (emitter: EventStaticEmitterObject) => {
141
119
  setTimeout(() => {
142
- listener.apply(this, emitter.args);
120
+ listener(...emitter.args);
143
121
  }, 1);
144
122
  };
145
123
 
146
- this._listeners = this._listeners || {};
147
- this._listeners[event] = this._listeners[event] || {};
148
- this._listeners[event][id] = this._listeners[event][id] || [];
149
- this._listeners[event][id].push(listener);
124
+ this._eventListeners = this._eventListeners || {};
125
+ this._eventListeners[eventName] = this._eventListeners[eventName] || {};
126
+ this._eventListeners[eventName][id] = this._eventListeners[eventName][id] || [];
127
+ this._eventListeners[eventName][id].push(listener);
150
128
 
151
129
  // Check for any static emitters, and fire the event if any exist
152
- if (!this._emitters || !this._emitters[event] || !this._emitters[event].length) return this;
130
+ if (!this._eventStaticEmitters || !this._eventStaticEmitters[eventName] || !this._eventStaticEmitters[eventName].length) return this;
153
131
 
154
132
  // Emit events for each emitter
155
- this._emitters[event].forEach((emitter: EventEmitterType) => {
133
+ for (let i = 0; i < this._eventStaticEmitters[eventName].length; i++) {
134
+ const emitter = this._eventStaticEmitters[eventName][i];
135
+
156
136
  if (id === "*" || emitter.id === id) {
157
137
  // Call the listener out of process so that any code that expects a listener
158
138
  // to be called at some point in the future rather than immediately on registration
159
139
  // will not fail
160
- generateEmitterTimeout(emitter);
140
+ generateTimeout(emitter);
161
141
  }
162
- });
142
+ }
163
143
 
164
144
  return this;
165
145
  }
@@ -167,213 +147,248 @@ export class Emitter {
167
147
  /**
168
148
  * Attach an event listener to the passed event only if the passed
169
149
  * id matches the document id for the event being fired.
170
- * @memberOf Emitter
171
- * @method once
172
- * @param {String} event The name of the event to listen for.
173
- * @param {*} id The document id to match against.
150
+ * @param {String} eventName The name of the event to listen for.
151
+ * @param {*} id The id to match against.
174
152
  * @param {Function} listener The method to call when the event is fired.
175
153
  * @returns {Emitter} The emitter instance.
176
154
  */
177
- _once (event:string|symbol, id:string|symbol, listener: EventListenerType) {
155
+ _once (eventName: string, id: string, listener: EventListenerCallback) {
178
156
  let fired = false;
179
157
 
180
- const internalCallback = (...rest: any[]) => {
158
+ const internalCallback = (...args: any[]) => {
181
159
  if (fired) return;
182
160
 
183
161
  fired = true;
184
- this.off(event, id, internalCallback);
185
- listener(...rest);
162
+ this.off(eventName, id, internalCallback);
163
+ listener(...args);
186
164
  };
187
165
 
188
- return this.on(event, id, internalCallback);
166
+ return this.on(eventName, id, internalCallback);
189
167
  }
190
168
 
191
169
  /**
192
170
  * Cancels an event listener based on an event name, id and listener function.
193
- * @memberOf Emitter
194
- * @method off
195
- * @param {String} event The event to cancel listener for.
171
+ * @param {String} eventName The event to cancel listener for.
196
172
  * @param {String} id The ID of the event to cancel listening for.
197
173
  * @param {Function} listener The event listener function used in the on()
198
174
  * or once() call to cancel.
199
175
  * @returns {Emitter} The emitter instance.
200
176
  */
201
- _off (event: string|symbol, id: string|symbol, listener?: EventListenerType) {
202
- if (this._emitting) {
177
+ _off (eventName: string, id: string, listener?: EventListenerCallback): this {
178
+ // If the event name doesn't have any listeners, exit early
179
+ if (!this._eventListeners || !this._eventListeners[eventName] || !this._eventListeners[eventName][id]) return this;
180
+
181
+ // If we are emitting events at the moment, don't remove this listener
182
+ // until the process has completed, so we queue for removal instead
183
+ if (this._eventsEmitting) {
203
184
  this._eventRemovalQueue = this._eventRemovalQueue || [];
204
185
  this._eventRemovalQueue.push(() => {
205
- this.off(event, id, listener);
186
+ this.off(eventName, id, listener);
206
187
  });
207
188
 
208
189
  return this;
209
190
  }
210
191
 
211
- if (!this._listeners || !this._listeners[event] || !this._listeners[event][id]) return this;
212
-
213
- if (id && !listener) {
192
+ // Check if we have no specific listener... in this case
193
+ // we want to remove all listeners for an id
194
+ if (!listener) {
214
195
  if (id === "*") {
215
- delete this._listeners[event];
196
+ // The id is "all" and no listener was provided so delete all
197
+ // event listeners for this event name
198
+ delete this._eventListeners[eventName];
216
199
  return this;
217
200
  }
218
201
 
219
- // No listener provided, delete all listeners
220
- delete this._listeners[event][id];
202
+ // No listener provided, delete all listeners for this id
203
+ delete this._eventListeners[eventName][id];
221
204
  return this;
222
205
  }
223
206
 
224
- if (!listener) return this;
225
-
226
- const arr = this._listeners[event][id] || [];
207
+ const arr = this._eventListeners[eventName][id] || [];
227
208
  const index = arr.indexOf(listener);
228
209
 
229
210
  if (index > -1) {
230
211
  arr.splice(index, 1);
231
212
  }
213
+
214
+ return this;
232
215
  }
233
216
 
234
217
  /**
235
218
  * Attach an event listener to the passed event only if the passed
236
219
  * id matches the document id for the event being fired.
237
- * @memberOf Emitter
238
- * @method on
239
- * @param {String} event The name of the event to listen for.
240
- * @param {*} id The document id to match against.
220
+ * @param {String} eventName The name of the event to listen for.
221
+ * @param {*} id The id to match against.
241
222
  * @param {Function} listener The method to call when the event is fired.
242
223
  * @returns {Emitter} The emitter instance.
243
224
  */
244
- on (event: string|symbol, id: string|symbol, listener: EventListenerType): any;
245
- on (event: string|symbol, listener: (...rest: any[]) => any): any;
246
- on (event: string|symbol, ...rest: any[]) {
225
+ on (eventName: string, id: string, listener: EventListenerCallback): this;
226
+ on (eventName: string, listener: EventListenerCallback): this;
227
+ on (eventName: string, ...rest: any[]): this {
247
228
  const restTypes = rest.map((arg) => typeof arg);
248
229
 
249
230
  if (restTypes[0] === "function") {
250
- return this._on.call(this, event, "*", rest[0]);
231
+ return this._on(eventName, "*", rest[0]);
251
232
  }
252
233
 
253
- return this._on.call(this, event, rest[0], rest[1]);
234
+ return this._on(eventName, rest[0], rest[1]);
254
235
  }
255
236
 
256
237
  /**
257
238
  * Attach an event listener to the passed event only if the passed
258
239
  * id matches the document id for the event being fired.
259
- * @memberOf Emitter
260
- * @method once
261
- * @param {String} event The name of the event to listen for.
262
- * @param {*} id The document id to match against.
263
- * @param {Function} listener The method to call when the event is fired.
240
+ * @param {String} eventName The name of the event to listen for.
241
+ * @param id The id to match against.
242
+ * @param listener
264
243
  * @returns {Emitter} The emitter instance.
265
244
  */
266
- once (event: string, id: string|symbol, listener: EventListenerType): any;
267
- once (event: string, listener: (...rest: any[]) => any): any;
268
- once (event: string, ...rest: any[]) {
245
+ once (eventName: string, id: string, listener: EventListenerCallback): this;
246
+ once (eventName: string, listener: EventListenerCallback): this;
247
+ once (eventName: string, ...rest: any[]): this {
269
248
  const restTypes = rest.map((arg) => typeof arg);
270
249
 
271
250
  if (restTypes[0] === "function") {
272
- return this._once.call(this, event, "*", rest[0]);
251
+ return this._once(eventName, "*", rest[0]);
273
252
  }
274
253
 
275
- return this._once.call(this, event, rest[0], rest[1]);
254
+ return this._once(eventName, rest[0], rest[1]);
276
255
  }
277
256
 
278
257
  /**
279
- * Attach an event listener to the passed event only if the passed
280
- * id matches the document id for the event being fired.
281
- * @memberOf Emitter
282
- * @method once
283
- * @param {String} event The name of the event to listen for.
284
- * @param {*} id The document id to match against.
258
+ * Overwrites any previous event listeners so that if the event fires, only
259
+ * the listener you pass will be called. If you pass an id along with the
260
+ * listener, only listeners for the id will be overwritten. This is similar
261
+ * to calling `.off(eventName)` then `on(eventName, listener)` since
262
+ * `off(eventName)` will cancel any previous event listeners for the passed
263
+ * event name.
264
+ * @param {String} eventName The name of the event to listen for.
265
+ * @param {*} id The id to match against.
285
266
  * @param {Function} listener The method to call when the event is fired.
286
267
  * @returns {Emitter} The emitter instance.
287
268
  */
288
- one (event: string, id: string|symbol, listener: EventListenerType): any;
289
- one (event: string, listener: (...rest: any[]) => any): any;
290
- one (event: string, ...rest: any[]) {
269
+ overwrite (eventName: string, id: string, listener: EventListenerCallback): this;
270
+ overwrite (eventName: string, listener: EventListenerCallback): this;
271
+ overwrite (eventName: string, ...rest: any[]) {
291
272
  const restTypes = rest.map((arg) => typeof arg);
292
273
 
293
274
  if (restTypes[0] === "function") {
294
- this.off(event);
295
- return this._on.call(this, event, "*", rest[0]);
275
+ this.off(eventName);
276
+ return this._on(eventName, "*", rest[0]);
296
277
  }
297
278
 
298
- this.off(event, rest[0]);
299
- return this._on.call(this, event, rest[0], rest[1]);
279
+ this.off(eventName, rest[0]);
280
+ return this._on(eventName, rest[0], rest[1]);
300
281
  }
301
282
 
302
283
  /**
303
284
  * Cancels an event listener based on an event name, id and listener function.
304
- * @memberOf Emitter
305
- * @method off
306
- * @param event The event to cancel listener for.
307
- * @param id The ID of the event to cancel listening for.
308
- * @param listener The event listener function used in the on()
285
+ * @param {String} eventName The event to cancel listener for.
286
+ * @param {String} id The ID of the event to cancel listening for.
287
+ * @param {Function} listener The event listener function used in the on()
309
288
  * or once() call to cancel.
310
289
  * @returns {Emitter} The emitter instance.
311
290
  */
312
- off (event: string|symbol, id: string|symbol, listener?: EventListenerType): any;
313
- off (event: string|symbol, listener: (...rest: any[]) => any): any;
314
- off (event: string|symbol): any;
315
- off (event: string|symbol, ...rest: any[]) {
291
+ off (eventName: string, id: string, listener?: EventListenerCallback): this;
292
+ off (eventName: string, listener?: EventListenerCallback): this;
293
+ off (eventName: string): this;
294
+ off (eventName: string, ...rest: any[]) {
316
295
  if (rest.length === 0) {
317
- // Only event was provided
318
- return this._off.call(this, event, "*");
296
+ // Only event was provided, use * as the id to mean "any without"
297
+ // a specific id
298
+ return this._off(eventName, "*");
319
299
  }
320
300
 
321
301
  const restTypes = rest.map((arg) => typeof arg);
322
302
 
323
303
  if (restTypes[0] === "function") {
324
- return this._off.call(this, event, "*", rest[0]);
304
+ // The first arg after the event name was a function (listener)
305
+ // so remove listening for events for this specific listener
306
+ return this._off(eventName, "*", rest[0]);
325
307
  }
326
308
 
327
- return this._off.call(this, event, rest[0], rest[1]);
309
+ // Both id and listener were provided, remove for the specific id
310
+ return this._off(eventName, rest[0], rest[1]);
328
311
  }
329
312
 
330
313
  /**
331
- * Handles emitting events, is an internal method not called directly.
332
- * @param {String} event The name of the event to emit.
333
- * @param {*} data The data to emit with the event.
334
- * @returns {Emitter} The emitter instance.
335
- * @private
314
+ * Emit an event by name.
315
+ * @param {Object} eventName The name of the event to emit.
316
+ * @param {...any} data The arguments to send to any listening methods.
317
+ * If you are sending multiple arguments, separate them with a comma so
318
+ * that they are received by the function as separate arguments.
319
+ * @return {number}
320
+ * @example #Emit an Event
321
+ * // Emit the event named "hello"
322
+ * myEntity.emit('hello');
323
+ * @example #Emit an Event With Data Object
324
+ * // Emit the event named "hello"
325
+ * myEntity.emit('hello', {moo: true});
326
+ * @example #Emit an Event With Multiple Data Values
327
+ * // Emit the event named "hello"
328
+ * myEntity.emit('hello', {moo: true}, 'someString');
329
+ * @example #Listen for Event Data
330
+ * // Set a listener to listen for the data (multiple values emitted
331
+ * // from an event are passed as function arguments)
332
+ * myEntity.on('hello', function (arg1, arg2) {
333
+ * console.log(arg1, arg2);
334
+ * }
335
+ *
336
+ * // Emit the event named "hello"
337
+ * myEntity.emit('hello', 'data1', 'data2');
338
+ *
339
+ * // The console output is:
340
+ * // data1, data2
336
341
  */
337
- emit (event: string|symbol, ...data: any[]) {
342
+ async emit (eventName: string, ...data: any[]): Promise<EventReturnFlag> {
343
+ if (!this._eventListeners) {
344
+ return EventReturnFlag.none;
345
+ }
346
+
338
347
  const id = "*";
339
- this._listeners = this._listeners || {};
340
- this._emitting = true;
341
348
 
342
- if (this._listeners[event] && this._listeners[event][id]) {
349
+ let returnFlag: EventReturnFlag = EventReturnFlag.none;
350
+ this._eventsEmitting = true;
351
+
352
+ if (this._eventListeners[eventName] && this._eventListeners[eventName][id]) {
343
353
  // Handle global emit
344
- const arr = this._listeners[event][id];
345
- const arrCount = arr.length;
354
+ const arr = this._eventListeners[eventName][id];
346
355
 
347
- for (let arrIndex = 0; arrIndex < arrCount; arrIndex++) {
348
- // Check we have a function to execute
349
- const tmpFunc = arr[arrIndex];
356
+ const promiseArr = arr.map((tmpFunc) => {
357
+ if (typeof tmpFunc !== "function") return;
358
+ return tmpFunc(...data);
359
+ });
350
360
 
351
- if (typeof tmpFunc === "function") {
352
- tmpFunc.call(this, ...data);
353
- }
361
+ const result = (await Promise.all(promiseArr)).find((tmpResult) => tmpResult !== EventReturnFlag.none);
362
+
363
+ if (result) {
364
+ returnFlag = EventReturnFlag.cancel;
354
365
  }
355
366
  }
356
367
 
357
- this._emitting = false;
368
+ this._eventsEmitting = false;
358
369
  this._processRemovalQueue();
359
370
 
360
- return this;
371
+ return returnFlag;
361
372
  }
362
373
 
363
- emitId (event: string|symbol, id: string|symbol, ...data: any[]) {
364
- this._listeners = this._listeners || {};
365
- this._emitting = true;
374
+ emitId (eventName: string, id: string, ...data: any[]): EventReturnFlag {
375
+ if (!this._eventListeners) {
376
+ return EventReturnFlag.none;
377
+ }
378
+
379
+ this._eventListeners = this._eventListeners || {};
380
+ this._eventsEmitting = true;
366
381
 
367
- if (!this._listeners || !this._listeners[event]) {
368
- this._emitting = false;
382
+ if (!this._eventListeners[eventName]) {
383
+ this._eventsEmitting = false;
369
384
  this._processRemovalQueue();
370
385
 
371
- return this;
386
+ return EventReturnFlag.none;
372
387
  }
373
388
 
374
389
  // Handle id emit
375
- if (this._listeners[event][id]) {
376
- const arr = this._listeners[event][id];
390
+ if (this._eventListeners[eventName][id]) {
391
+ const arr = this._eventListeners[eventName][id];
377
392
  const arrCount = arr.length;
378
393
 
379
394
  for (let arrIndex = 0; arrIndex < arrCount; arrIndex++) {
@@ -387,8 +402,8 @@ export class Emitter {
387
402
  }
388
403
 
389
404
  // Handle global emit
390
- if (this._listeners[event]["*"]) {
391
- const arr = this._listeners[event]["*"];
405
+ if (this._eventListeners[eventName]["*"]) {
406
+ const arr = this._eventListeners[eventName]["*"];
392
407
  const arrCount = arr.length;
393
408
 
394
409
  for (let arrIndex = 0; arrIndex < arrCount; arrIndex++) {
@@ -401,86 +416,144 @@ export class Emitter {
401
416
  }
402
417
  }
403
418
 
404
- this._emitting = false;
419
+ this._eventsEmitting = false;
405
420
  this._processRemovalQueue();
406
421
 
407
- return this;
422
+ return EventReturnFlag.none;
408
423
  }
409
424
 
410
425
  /**
411
- * Creates a static event emitter that is emitted whenever an
412
- * event listener is created with the same name.
413
- * @param {String} event The name of the event to emit.
414
- * @param {*} data The data to emit with the event.
426
+ * Creates a persistent emitter record that will fire a listener if
427
+ * one is added for this event after the emitStatic() call has been
428
+ * made.
429
+ * @param {String} eventName The name of the event to emit.
430
+ * @param {...any} data Optional arguments to emit with the event.
415
431
  * @returns {Emitter} The emitter instance.
432
+ * @private
416
433
  */
417
- emitStatic (event: string|symbol, ...data: any[]) {
418
- this._emitters = this._emitters || {};
419
- this._emitters[event] = this._emitters[event] || [];
420
- this._emitters[event].push({
434
+ emitStatic (eventName: string, ...data: any[]) {
435
+ const id = "*";
436
+ this._eventListeners = this._eventListeners || {};
437
+ this._eventsEmitting = true;
438
+
439
+ if (this._eventListeners[eventName] && this._eventListeners[eventName][id]) {
440
+ // Handle global emit
441
+ const arr = this._eventListeners[eventName][id];
442
+ const arrCount = arr.length;
443
+
444
+ for (let arrIndex = 0; arrIndex < arrCount; arrIndex++) {
445
+ // Check we have a function to execute
446
+ const tmpFunc = arr[arrIndex];
447
+
448
+ if (typeof tmpFunc === "function") {
449
+ tmpFunc.call(this, ...data);
450
+ }
451
+ }
452
+ }
453
+
454
+ this._eventsEmitting = false;
455
+
456
+ this._eventStaticEmitters = this._eventStaticEmitters || {};
457
+ this._eventStaticEmitters[eventName] = this._eventStaticEmitters[eventName] || [];
458
+ this._eventStaticEmitters[eventName].push({
421
459
  "id": "*",
422
460
  "args": data
423
461
  });
424
462
 
425
- this.emit(event, ...data);
426
-
427
463
  this._processRemovalQueue();
428
464
 
429
465
  return this;
430
466
  }
431
467
 
432
468
  /**
433
- * Creates a static event emitter that is emitted whenever an
434
- * event listener is created with the same name and id.
435
- * @param {String} event The name of the event to emit.
469
+ * Creates a persistent emitter record that will fire a listener if
470
+ * one is added for this event after the emitStatic() call has been
471
+ * made.
472
+ * @param {String} eventName The name of the event to emit.
436
473
  * @param {String} id The id of the event to emit.
437
- * @param {*} data The data to emit with the event.
474
+ * @param {...any} data Optional arguments to emit with the event.
438
475
  * @returns {Emitter} The emitter instance.
476
+ * @private
439
477
  */
440
- emitStaticId (event: string|symbol, id: string|symbol, ...data: any[]) {
441
- if (!id) throw new Error("Missing id from emitStaticId call!");
478
+ emitStaticId (eventName: string, id: string, ...data: any[]) {
479
+ if (!id) throw new Error("Missing id from emitId call!");
480
+
481
+ this._eventListeners = this._eventListeners || {};
482
+ this._eventsEmitting = true;
483
+
484
+ if (this._eventListeners[eventName]) {
485
+ // Handle id emit
486
+ if (this._eventListeners[eventName][id]) {
487
+ const arr = this._eventListeners[eventName][id];
488
+ const arrCount = arr.length;
442
489
 
443
- this._emitters = this._emitters || {};
444
- this._emitters[event] = this._emitters[event] || [];
445
- this._emitters[event].push({
490
+ for (let arrIndex = 0; arrIndex < arrCount; arrIndex++) {
491
+ // Check we have a function to execute
492
+ const tmpFunc = arr[arrIndex];
493
+
494
+ if (typeof tmpFunc === "function") {
495
+ tmpFunc.call(this, ...data);
496
+ }
497
+ }
498
+ }
499
+
500
+ // Handle global emit
501
+ if (this._eventListeners[eventName]["*"]) {
502
+ const arr = this._eventListeners[eventName]["*"];
503
+ const arrCount = arr.length;
504
+
505
+ for (let arrIndex = 0; arrIndex < arrCount; arrIndex++) {
506
+ // Check we have a function to execute
507
+ const tmpFunc = arr[arrIndex];
508
+
509
+ if (typeof tmpFunc === "function") {
510
+ tmpFunc.call(this, ...data);
511
+ }
512
+ }
513
+ }
514
+ }
515
+
516
+ this._eventsEmitting = false;
517
+
518
+ this._eventStaticEmitters = this._eventStaticEmitters || {};
519
+ this._eventStaticEmitters[eventName] = this._eventStaticEmitters[eventName] || [];
520
+ this._eventStaticEmitters[eventName].push({
446
521
  id,
447
522
  "args": data
448
523
  });
449
524
 
450
- this.emitId(event, id, ...data);
525
+ this._processRemovalQueue();
451
526
 
452
527
  return this;
453
528
  }
454
529
 
455
530
  /**
456
531
  * Handles removing emitters, is an internal method not called directly.
457
- * @param {String} event The event to remove static emitter for.
532
+ * @param {String} eventName The event to remove static emitter for.
458
533
  * @returns {Emitter} The emitter instance.
459
534
  * @private
460
535
  */
461
- cancelStatic (event: string|symbol) {
462
- this._emitters = this._emitters || {};
463
- this._emitters[event] = [];
536
+ cancelStatic (eventName: string) {
537
+ this._eventStaticEmitters = this._eventStaticEmitters || {};
538
+ this._eventStaticEmitters[eventName] = [];
464
539
 
465
540
  return this;
466
541
  }
467
542
 
468
543
  /**
469
544
  * Checks if an event has any event listeners or not.
470
- * @memberOf Emitter
471
- * @method willEmit
472
- * @param {String} event The name of the event to check for.
545
+ * @param {String} eventName The name of the event to check for.
473
546
  * @returns {boolean} True if one or more event listeners are registered for
474
547
  * the event. False if none are found.
475
548
  */
476
- willEmit (event: string|symbol) {
549
+ willEmit (eventName: string) {
477
550
  const id = "*";
478
551
 
479
- if (!this._listeners || !this._listeners[event]) {
552
+ if (!this._eventListeners || !this._eventListeners[eventName]) {
480
553
  return false;
481
554
  }
482
555
 
483
- const arr = this._listeners[event][id];
556
+ const arr = this._eventListeners[eventName][id];
484
557
  const arrCount = arr.length;
485
558
 
486
559
  for (let arrIndex = 0; arrIndex < arrCount; arrIndex++) {
@@ -497,21 +570,19 @@ export class Emitter {
497
570
 
498
571
  /**
499
572
  * Checks if an event has any event listeners or not based on the passed id.
500
- * @memberOf Emitter
501
- * @method willEmitId
502
- * @param {String} event The name of the event to check for.
573
+ * @param {String} eventName The name of the event to check for.
503
574
  * @param {String} id The event ID to check for.
504
575
  * @returns {boolean} True if one or more event listeners are registered for
505
576
  * the event. False if none are found.
506
577
  */
507
- willEmitId (event: string|symbol, id: string|symbol) {
508
- if (!this._listeners || !this._listeners[event]) {
578
+ willEmitId (eventName: string, id: string) {
579
+ if (!this._eventListeners || !this._eventListeners[eventName]) {
509
580
  return false;
510
581
  }
511
582
 
512
583
  // Handle id emit
513
- if (this._listeners[event][id]) {
514
- const arr = this._listeners[event][id];
584
+ if (this._eventListeners[eventName][id]) {
585
+ const arr = this._eventListeners[eventName][id];
515
586
  const arrCount = arr.length;
516
587
 
517
588
  for (let arrIndex = 0; arrIndex < arrCount; arrIndex++) {
@@ -525,8 +596,8 @@ export class Emitter {
525
596
  }
526
597
 
527
598
  // Handle global emit
528
- if (this._listeners[event]["*"]) {
529
- const arr = this._listeners[event]["*"];
599
+ if (this._eventListeners[eventName]["*"]) {
600
+ const arr = this._eventListeners[eventName]["*"];
530
601
  const arrCount = arr.length;
531
602
 
532
603
  for (let arrIndex = 0; arrIndex < arrCount; arrIndex++) {
@@ -546,32 +617,29 @@ export class Emitter {
546
617
  * Queues an event to be fired. This has automatic de-bouncing so that any
547
618
  * events of the same type that occur within 100 milliseconds of a previous
548
619
  * one will all be wrapped into a single emit rather than emitting tons of
549
- * events for the same eventName. Only the data from the last de-bounced event
550
- * will be emitted.
551
- * @memberOf Emitter
552
- * @method deferEmit
620
+ * events for lots of chained inserts etc. Only the data from the last
621
+ * de-bounced event will be emitted.
553
622
  * @param {String} eventName The name of the event to emit.
554
- * @param {*=} data Optional data to emit with the event.
623
+ * @param {...any} data Optional arguments to emit with the event.
555
624
  * @returns {Emitter} The emitter instance.
556
625
  */
557
- deferEmit (eventName: string|symbol, ...data: any[]) {
558
- if (this._noEmitDefer) {
559
- this.emit(eventName, ...data);
560
- return this;
561
- }
626
+ deferEmit (eventName: string, ...data: any[]) {
627
+ if (!this._eventsAllowDefer) {
628
+ // Check for an existing timeout
629
+ this._eventsDeferTimeouts = this._eventsDeferTimeouts || {};
562
630
 
563
- // Check for an existing timeout
564
- this._deferTimeout = this._deferTimeout || {};
631
+ if (this._eventsDeferTimeouts[eventName]) {
632
+ clearTimeout(this._eventsDeferTimeouts[eventName]);
633
+ }
565
634
 
566
- if (this._deferTimeout[eventName]) {
567
- clearTimeout(this._deferTimeout[eventName]);
635
+ // Set a timeout
636
+ this._eventsDeferTimeouts[eventName] = setTimeout(() => {
637
+ this.emit.call(this, eventName, ...data);
638
+ }, 1) as unknown as number;
639
+ } else {
640
+ this.emit.call(this, eventName, ...data);
568
641
  }
569
642
 
570
- // Set a timeout
571
- this._deferTimeout[eventName] = setTimeout(() => {
572
- this.emit(eventName, ...data);
573
- }, 100);
574
-
575
643
  return this;
576
644
  }
577
645
 
@@ -583,7 +651,6 @@ export class Emitter {
583
651
  * the emitter is running through them. This method is called after the
584
652
  * event emitter is finished processing.
585
653
  * @private
586
- * @returns {undefined}
587
654
  */
588
655
  _processRemovalQueue () {
589
656
  if (!this._eventRemovalQueue || !this._eventRemovalQueue.length) {
@@ -600,26 +667,10 @@ export class Emitter {
600
667
  }
601
668
  }
602
669
 
603
- /**
604
- * Makes the passed class or object into an emitter by modifying either the
605
- * prototype or the actual object to include event emitter methods.
606
- * @param obj The object / function / class to add event methods to.
607
- * If none is provided a new object will be created. This allows you to use
608
- * new Emitter() to generate an event emitter that is not tied to any other
609
- * object or class.
610
- * @param prototypeMode Defaults to true. Set to true to add emitter
611
- * methods to the the passed object"s prototype property e.g. obj.prototype.on
612
- * = emitter.on. Set to false to add emitter methods the object directly e.g.
613
- * obj.on = emitter.on.
614
- * @returns {Object} The newly augmented object.
615
- */
616
- type MakeEmitter = {
617
- (obj: Record<string, unknown>|boolean|undefined, prototypeMode: boolean): any,
618
- (obj: boolean): any,
619
- (obj: undefined): any
620
- }
621
-
622
- export const makeEmitter: MakeEmitter = (obj: Record<string, unknown>|boolean|undefined, prototypeMode = false) => {
670
+ export function makeEmitter(obj: new (...args: any[]) => any, prototypeMode: boolean): Emitter;
671
+ export function makeEmitter(obj: boolean): Emitter;
672
+ export function makeEmitter(obj: Record<string, unknown>, prototypeMode: boolean): Emitter;
673
+ export function makeEmitter (obj: any, prototypeMode?: any) {
623
674
  let operateOnObject;
624
675
 
625
676
  if (obj === undefined && prototypeMode === undefined) {
@@ -633,27 +684,26 @@ export const makeEmitter: MakeEmitter = (obj: Record<string, unknown>|boolean|un
633
684
  }
634
685
 
635
686
  if (prototypeMode === undefined) {
636
- prototypeMode = false;
687
+ prototypeMode = true;
637
688
  }
638
689
 
639
690
  if (typeof obj !== "object" && typeof obj !== "function") {
640
- throw new Error("Cannot operate on passed value, it is not an object, function or class!");
691
+ throw new Error("Cannot operate on a non-object / non-function passed as first argument!");
641
692
  }
642
693
 
643
694
  if (prototypeMode) {
644
695
  if (obj.prototype === undefined) {
645
- throw new Error("Cannot modify prototype of passed object, it has no prototype property!");
696
+ throw new Error("Cannot modify prototype of passed object, it has no prototype property! Was it instantiated with the new operator correctly?");
646
697
  }
647
698
 
648
- operateOnObject = obj.prototype as Record<string, unknown>;
699
+ operateOnObject = obj.prototype;
649
700
  } else {
650
701
  operateOnObject = obj;
651
702
  }
652
703
 
653
- // Convert the object to have eventing capability
704
+ // Convert the object prototype to have eventing capability
654
705
  operateOnObject.on = Emitter.prototype.on;
655
706
  operateOnObject.off = Emitter.prototype.off;
656
- operateOnObject.one = Emitter.prototype.one;
657
707
  operateOnObject.once = Emitter.prototype.once;
658
708
  operateOnObject.emit = Emitter.prototype.emit;
659
709
  operateOnObject.emitId = Emitter.prototype.emitId;
@@ -664,9 +714,6 @@ export const makeEmitter: MakeEmitter = (obj: Record<string, unknown>|boolean|un
664
714
  operateOnObject.willEmit = Emitter.prototype.willEmit;
665
715
  operateOnObject.willEmitId = Emitter.prototype.willEmitId;
666
716
  operateOnObject._processRemovalQueue = Emitter.prototype._processRemovalQueue;
667
- operateOnObject._on = Emitter.prototype._on;
668
- operateOnObject._off = Emitter.prototype._off;
669
- operateOnObject._once = Emitter.prototype._once;
670
717
 
671
718
  return obj;
672
- };
719
+ }