@irrelon/emitter 4.0.1 → 5.0.2

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.js CHANGED
@@ -1,8 +1,17 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
1
10
  /*
2
11
  The MIT License (MIT)
3
12
 
4
13
  Copyright (c) 2014 Irrelon Software Limited
5
- http://www.irrelon.com
14
+ https://www.irrelon.com
6
15
 
7
16
  Permission is hereby granted, free of charge, to any person obtaining a copy
8
17
  of this software and associated documentation files (the "Software"), to deal
@@ -25,651 +34,547 @@
25
34
  Source: https://github.com/irrelon/emitter
26
35
 
27
36
  Changelog:
28
- Version 4.0.1:
29
- Updated library to use new ES6 functionality making Overload()
30
- less useful so it can be removed as a dependency.
31
- Version 4.0.0:
32
- Breaking change. Library now has named exports `Emitter` and
33
- `makeEmitter`. `Emitter` is an ES6 class that can be extended
34
- and `makeEmitter` is a function that takes an object or class
35
- and does what `Emitter(someObject)` used to do. This change is
36
- to support being able to extend `Emitter` as a base class.
37
- Version 3.1.0:
38
- Changed order of execution so that listeners that are listening
39
- against a specific ID get called before the general catch-all
40
- listeners. Renamed package to @irrelon/emitter.
41
- Version 2.0.11:
42
- Added cancelStatic method to allow cancelling a static event
43
- Version 2.0.7:
44
- Fixed UMD module support
45
- Version 2.0.6:
46
- Added UMD module support
47
- Version 2.0.5:
48
- Added bower version number
49
- Version 2.0.4:
50
- Allow instantiation as independent instance, updated unit tests
51
- Version 2.0.3:
52
- Documentation updates, published to bower
53
- Version 2.0.2:
54
- Documentation updates
55
- Version 2.0.1:
56
- Bug fix in this._emitters usage
57
- Version 2.0.0:
58
- Big update to bring in line with latest developments in other projects. Event emitter can
59
- now use deferEmit(), emitId(), emitStatic(), emitStaticId(), willEmit(), willEmitId().
60
- Version 1.1.9:
61
- Updated changelog correctly
62
- Version 1.1.8:
63
- Removed tons of dependencies wrongly included in main dependencies, have moved to devDependencies section of package.json
64
- Version 1.1.0:
65
- Added support for overloaded methods
66
- Added support for events with ids
67
- Version 1.0.2:
68
- Removed AMD support, added browserify support
69
- Added package.json
70
- Added once() method
71
- Added hasListener() method
72
- Published to NPM as irrelon-emitter
73
- Version 1.0.1:
74
- Added ability to extend any object with eventing capability
75
- Added AMD / Require.js support
76
- Added Node.js support
77
- Version 1.0.0:
78
- First commit
37
+ Version 5.0.2:
38
+ Removed some unnecessary code, updated to be in step with version
39
+ that is being used in the new version of Isogenic Game Engine.
40
+ Version 5.0.1:
41
+ Further TypeScript updates.
42
+ Version 5.0.0:
43
+ Added TypeScript and prettier, removed babel etc
44
+ Version 4.0.1:
45
+ Updated library to use new ES6 functionality making Overload()
46
+ less useful so it can be removed as a dependency.
47
+ Version 4.0.0:
48
+ Breaking change. Library now has named exports `Emitter` and
49
+ `makeEmitter`. `Emitter` is an ES6 class that can be extended
50
+ and `makeEmitter` is a function that takes an object or class
51
+ and does what `Emitter(someObject)` used to do. This change is
52
+ to support being able to extend `Emitter` as a base class.
53
+ Version 3.1.0:
54
+ Changed order of execution so that listeners that are listening
55
+ against a specific ID get called before the general catch-all
56
+ listeners. Renamed package to @irrelon/emitter.
57
+ Version 2.0.11:
58
+ Added cancelStatic method to allow cancelling a static event
59
+ Version 2.0.7:
60
+ Fixed UMD module support
61
+ Version 2.0.6:
62
+ Added UMD module support
63
+ Version 2.0.5:
64
+ Added bower version number
65
+ Version 2.0.4:
66
+ Allow instantiation as independent instance, updated unit tests
67
+ Version 2.0.3:
68
+ Documentation updates, published to bower
69
+ Version 2.0.2:
70
+ Documentation updates
71
+ Version 2.0.1:
72
+ Bug fix in this._emitters usage
73
+ Version 2.0.0:
74
+ Big update to bring in line with latest developments in other projects. Event emitter can
75
+ now use deferEmit(), emitId(), emitStatic(), emitStaticId(), willEmit(), willEmitId().
76
+ Version 1.1.9:
77
+ Updated changelog correctly
78
+ Version 1.1.8:
79
+ Removed tons of dependencies wrongly included in main dependencies, have moved to devDependencies section of package.json
80
+ Version 1.1.0:
81
+ Added support for overloaded methods
82
+ Added support for events with ids
83
+ Version 1.0.2:
84
+ Removed AMD support, added browserify support
85
+ Added package.json
86
+ Added once() method
87
+ Added hasListener() method
88
+ Published to NPM as irrelon-emitter
89
+ Version 1.0.1:
90
+ Added ability to extend any object with eventing capability
91
+ Added AMD / Require.js support
92
+ Added Node.js support
93
+ Version 1.0.0:
94
+ First commit
79
95
  */
80
- "use strict";
81
-
82
- const EventMainMethods = {
83
- /**
84
- * Attach an event listener to the passed event only if the passed
85
- * id matches the document id for the event being fired.
86
- * @memberOf Emitter
87
- * @method on
88
- * @param {String} event The name of the event to listen for.
89
- * @param {*} id The document id to match against.
90
- * @param {Function} listener The method to call when the event is fired.
91
- * @returns {Emitter} The emitter instance.
92
- */
93
- "_on" (event, id, listener) {
94
- const self = this;
95
-
96
- const generateTimeout = (emitter) => {
97
- setTimeout(() => {
98
- listener.apply(this, emitter.args);
99
- }, 1);
100
- };
101
-
102
- this._listeners = this._listeners || {};
103
- this._listeners[event] = this._listeners[event] || {};
104
- this._listeners[event][id] = this._listeners[event][id] || [];
105
- this._listeners[event][id].push(listener);
106
-
107
- // Check for any static emitters, and fire the event if any exist
108
- if (!this._emitters || !this._emitters[event] || !this._emitters[event].length) return this;
109
-
110
- // Emit events for each emitter
111
- for (let i = 0; i < this._emitters[event].length; i++) {
112
- const emitter = this._emitters[event];
113
-
114
- if (id === "*" || emitter.id === id) {
115
- // Call the listener out of process so that any code that expects a listener
116
- // to be called at some point in the future rather than immediately on registration
117
- // will not fail
118
- generateTimeout(emitter);
119
- }
120
- }
121
-
122
- return this;
123
- },
124
-
125
- /**
126
- * Attach an event listener to the passed event only if the passed
127
- * id matches the document id for the event being fired.
128
- * @memberOf Emitter
129
- * @method once
130
- * @param {String} event The name of the event to listen for.
131
- * @param {*} id The document id to match against.
132
- * @param {Function} listener The method to call when the event is fired.
133
- * @returns {Emitter} The emitter instance.
134
- */
135
- "_once" (event, id, listener) {
136
- let fired = false;
137
-
138
- const internalCallback = () => {
139
- if (fired) return;
140
-
141
- fired = true;
142
- this.off(event, id, internalCallback);
143
- listener.apply(this, arguments);
144
- };
145
-
146
- return this.on(event, id, internalCallback);
147
- },
148
-
149
- /**
150
- * Cancels an event listener based on an event name, id and listener function.
151
- * @memberOf Emitter
152
- * @method off
153
- * @param {String} event The event to cancel listener for.
154
- * @param {String} id The ID of the event to cancel listening for.
155
- * @param {Function} listener The event listener function used in the on()
156
- * or once() call to cancel.
157
- * @returns {Emitter} The emitter instance.
158
- */
159
- "_off" (event, id, listener) {
160
- if (this._emitting) {
161
- this._eventRemovalQueue = this._eventRemovalQueue || [];
162
- this._eventRemovalQueue.push(() => {
163
- this.off(event, id, listener);
164
- });
165
-
166
- return this;
167
- }
168
-
169
- if (!this._listeners || !this._listeners[event] || !this._listeners[event][id]) return this;
170
-
171
- if (id && !listener) {
172
- if (id === "*") {
173
- delete this._listeners[event];
174
- return this;
175
- }
176
-
177
- // No listener provided, delete all listeners
178
- delete this._listeners[event][id];
179
- return this;
180
- }
181
-
182
- const arr = this._listeners[event][id] || [],
183
- index = arr.indexOf(listener);
184
-
185
- if (index > -1) {
186
- arr.splice(index, 1);
187
- }
188
- }
189
- };
190
-
96
+ export var EventReturnFlag;
97
+ (function (EventReturnFlag) {
98
+ EventReturnFlag[EventReturnFlag["none"] = 0] = "none";
99
+ EventReturnFlag[EventReturnFlag["cancel"] = 1] = "cancel";
100
+ })(EventReturnFlag || (EventReturnFlag = {}));
191
101
  /**
192
- * @class Emitter
193
- * @constructor
102
+ * Creates a new class with the capability to emit events.
194
103
  */
195
- class Emitter {
196
- /**
197
- * Attach an event listener to the passed event only if the passed
198
- * id matches the document id for the event being fired.
199
- * @memberOf Emitter
200
- * @method on
201
- * @param {String} event The name of the event to listen for.
202
- * @param {*} id The document id to match against.
203
- * @param {Function} listener The method to call when the event is fired.
204
- * @returns {Emitter} The emitter instance.
205
- */
206
- on (event, ...rest) {
207
- const restTypes = rest.map((arg) => typeof arg);
208
-
209
- if (restTypes[0] === "function") {
210
- return EventMainMethods._on.call(this, event, "*", rest[0]);
211
- }
212
-
213
- return EventMainMethods._on.call(this, event, rest[0], rest[1]);
214
- }
215
-
216
- /**
217
- * Attach an event listener to the passed event only if the passed
218
- * id matches the document id for the event being fired.
219
- * @memberOf Emitter
220
- * @method once
221
- * @param {String} event The name of the event to listen for.
222
- * @param {*} id The document id to match against.
223
- * @param {Function} listener The method to call when the event is fired.
224
- * @returns {Emitter} The emitter instance.
225
- */
226
- once (event, ...rest) {
227
- const restTypes = rest.map((arg) => typeof arg);
228
-
229
- if (restTypes[0] === "function") {
230
- return EventMainMethods._once.call(this, event, "*", rest[0]);
231
- }
232
-
233
- return EventMainMethods._once.call(this, event, rest[0], rest[1]);
234
- }
235
-
236
- /**
237
- * Attach an event listener to the passed event only if the passed
238
- * id matches the document id for the event being fired.
239
- * @memberOf Emitter
240
- * @method once
241
- * @param {String} event The name of the event to listen for.
242
- * @param {*} id The document id to match against.
243
- * @param {Function} listener The method to call when the event is fired.
244
- * @returns {Emitter} The emitter instance.
245
- */
246
- one (event, ...rest) {
247
- const restTypes = rest.map((arg) => typeof arg);
248
-
249
- if (restTypes[0] === "function") {
250
- this.off(event);
251
- return EventMainMethods._on.call(this, event, "*", rest[0]);
252
- }
253
-
254
- this.off(event, rest[0]);
255
- return EventMainMethods._on.call(this, event, rest[0], rest[1]);
256
- }
257
-
258
- /**
259
- * Cancels an event listener based on an event name, id and listener function.
260
- * @memberOf Emitter
261
- * @method off
262
- * @param {String} event The event to cancel listener for.
263
- * @param {String} id The ID of the event to cancel listening for.
264
- * @param {Function} listener The event listener function used in the on()
265
- * or once() call to cancel.
266
- * @returns {Emitter} The emitter instance.
267
- */
268
- off (event, ...rest) {
269
- if (rest.length === 0) {
270
- // Only event was provided
271
- return EventMainMethods._off.call(this, event, "*");
272
- }
273
-
274
- const restTypes = rest.map((arg) => typeof arg);
275
-
276
- if (restTypes[0] === "function") {
277
- return EventMainMethods._off.call(this, event, "*", rest[0]);
278
- }
279
-
280
- return EventMainMethods._off.call(this, event, rest[0], rest[1]);
281
- }
282
-
283
- /**
284
- * Handles emitting events, is an internal method not called directly.
285
- * @param {String} event The name of the event to emit.
286
- * @param {*} data The data to emit with the event.
287
- * @returns {Emitter} The emitter instance.
288
- * @private
289
- */
290
- emit (event, ...data) {
291
- const id = "*";
292
- this._listeners = this._listeners || {};
293
- this._emitting = true;
294
-
295
- if (this._listeners[event] && this._listeners[event][id]) {
296
- // Handle global emit
297
- const arr = this._listeners[event][id];
298
- const arrCount = arr.length;
299
-
300
- for (let arrIndex = 0; arrIndex < arrCount; arrIndex++) {
301
- // Check we have a function to execute
302
- const tmpFunc = arr[arrIndex];
303
-
304
- if (typeof tmpFunc === "function") {
305
- tmpFunc.call(this, ...data);
306
- }
307
- }
308
- }
309
-
310
- this._emitting = false;
311
- this._processRemovalQueue();
312
-
313
- return this;
314
- }
315
-
316
- emitId (event, id, ...data) {
317
- this._listeners = this._listeners || {};
318
- this._emitting = true;
319
-
320
- if (!this._listeners[event]) {
321
- this._emitting = false;
322
- this._processRemovalQueue();
323
-
324
- return this;
325
- }
326
-
327
- // Handle id emit
328
- if (this._listeners[event][id]) {
329
- const arr = this._listeners[event][id];
330
- const arrCount = arr.length;
331
-
332
- for (let arrIndex = 0; arrIndex < arrCount; arrIndex++) {
333
- // Check we have a function to execute
334
- const tmpFunc = arr[arrIndex];
335
-
336
- if (typeof tmpFunc === "function") {
337
- tmpFunc.call(this, ...data);
338
- }
339
- }
340
- }
341
-
342
- // Handle global emit
343
- if (this._listeners[event]["*"]) {
344
- const arr = this._listeners[event]["*"];
345
- const arrCount = arr.length;
346
-
347
- for (let arrIndex = 0; arrIndex < arrCount; arrIndex++) {
348
- // Check we have a function to execute
349
- const tmpFunc = arr[arrIndex];
350
-
351
- if (typeof tmpFunc === "function") {
352
- tmpFunc.call(this, ...data);
353
- }
354
- }
355
- }
356
-
357
- this._emitting = false;
358
- this._processRemovalQueue();
359
-
360
- return this;
361
- }
362
-
363
- /**
364
- * Handles emitting events, is an internal method not called directly.
365
- * @param {String} event The name of the event to emit.
366
- * @param {*} data The data to emit with the event.
367
- * @returns {Emitter} The emitter instance.
368
- * @private
369
- */
370
- emitStatic (event, ...data) {
371
- const id = "*";
372
- this._listeners = this._listeners || {};
373
- this._emitting = true;
374
-
375
- if (this._listeners[event] && this._listeners[event][id]) {
376
- // Handle global emit
377
- const arr = this._listeners[event][id];
378
- const arrCount = arr.length;
379
-
380
- for (let arrIndex = 0; arrIndex < arrCount; arrIndex++) {
381
- // Check we have a function to execute
382
- const tmpFunc = arr[arrIndex];
383
-
384
- if (typeof tmpFunc === "function") {
385
- tmpFunc.call(this, ...data);
386
- }
387
- }
388
- }
389
-
390
- this._emitting = false;
391
-
392
- this._emitters = this._emitters || {};
393
- this._emitters[event] = this._emitters[event] || [];
394
- this._emitters[event].push({
395
- "id": "*",
396
- "args": data
397
- });
398
-
399
- this._processRemovalQueue();
400
-
401
- return this;
402
- }
403
-
404
- /**
405
- * Handles emitting events, is an internal method not called directly.
406
- * @param {String} event The name of the event to emit.
407
- * @param {String} id The id of the event to emit.
408
- * @param {*} data The data to emit with the event.
409
- * @returns {Emitter} The emitter instance.
410
- * @private
411
- */
412
- emitStaticId (event, id, ...data) {
413
- if (!id) throw new Error("Missing id from emitId call!");
414
-
415
- this._listeners = this._listeners || {};
416
- this._emitting = true;
417
-
418
- if (this._listeners[event]) {
419
- // Handle id emit
420
- if (this._listeners[event][id]) {
421
- const arr = this._listeners[event][id];
422
- const arrCount = arr.length;
423
-
424
- for (let arrIndex = 0; arrIndex < arrCount; arrIndex++) {
425
- // Check we have a function to execute
426
- const tmpFunc = arr[arrIndex];
427
-
428
- if (typeof tmpFunc === "function") {
429
- tmpFunc.call(this, ...data);
430
- }
431
- }
432
- }
433
-
434
- // Handle global emit
435
- if (this._listeners[event]["*"]) {
436
- const arr = this._listeners[event]["*"];
437
- const arrCount = arr.length;
438
-
439
- for (let arrIndex = 0; arrIndex < arrCount; arrIndex++) {
440
- // Check we have a function to execute
441
- const tmpFunc = arr[arrIndex];
442
-
443
- if (typeof tmpFunc === "function") {
444
- tmpFunc.call(this, ...data);
445
- }
446
- }
447
- }
448
- }
449
-
450
- this._emitting = false;
451
-
452
- this._emitters = this._emitters || {};
453
- this._emitters[event] = this._emitters[event] || [];
454
- this._emitters[event].push({
455
- id,
456
- "args": data
457
- });
458
-
459
- this._processRemovalQueue();
460
-
461
- return this;
462
- }
463
-
464
- /**
465
- * Handles removing emitters, is an internal method not called directly.
466
- * @param {String} event The event to remove static emitter for.
467
- * @returns {Emitter} The emitter instance.
468
- * @private
469
- */
470
- cancelStatic (event) {
471
- this._emitters = this._emitters || {};
472
- this._emitters[event] = [];
473
-
474
- return this;
475
- }
476
-
477
- /**
478
- * Checks if an event has any event listeners or not.
479
- * @memberOf Emitter
480
- * @method willEmit
481
- * @param {String} event The name of the event to check for.
482
- * @returns {boolean} True if one or more event listeners are registered for
483
- * the event. False if none are found.
484
- */
485
- willEmit (event) {
486
- const id = "*";
487
-
488
- if (!this._listeners || !this._listeners[event]) {
489
- return false;
490
- }
491
-
492
- const arr = this._listeners[event][id];
493
- const arrCount = arr.length;
494
-
495
- for (let arrIndex = 0; arrIndex < arrCount; arrIndex++) {
496
- // Check we have a function to execute
497
- const tmpFunc = arr[arrIndex];
498
-
499
- if (typeof tmpFunc === "function") {
500
- return true;
501
- }
502
- }
503
-
504
- return false;
505
- }
506
-
507
- /**
508
- * Checks if an event has any event listeners or not based on the passed id.
509
- * @memberOf Emitter
510
- * @method willEmitId
511
- * @param {String} event The name of the event to check for.
512
- * @param {String} id The event ID to check for.
513
- * @returns {boolean} True if one or more event listeners are registered for
514
- * the event. False if none are found.
515
- */
516
- willEmitId (event, id) {
517
- if (!this._listeners || !this._listeners[event]) {
518
- return false;
519
- }
520
-
521
- // Handle id emit
522
- if (this._listeners[event][id]) {
523
- const arr = this._listeners[event][id];
524
- const arrCount = arr.length;
525
-
526
- for (let arrIndex = 0; arrIndex < arrCount; arrIndex++) {
527
- // Check we have a function to execute
528
- const tmpFunc = arr[arrIndex];
529
-
530
- if (typeof tmpFunc === "function") {
531
- return true;
532
- }
533
- }
534
- }
535
-
536
- // Handle global emit
537
- if (this._listeners[event]["*"]) {
538
- const arr = this._listeners[event]["*"];
539
- const arrCount = arr.length;
540
-
541
- for (let arrIndex = 0; arrIndex < arrCount; arrIndex++) {
542
- // Check we have a function to execute
543
- const tmpFunc = arr[arrIndex];
544
-
545
- if (typeof tmpFunc === "function") {
546
- return true;
547
- }
548
- }
549
- }
550
-
551
- return false;
552
- }
553
-
554
- /**
555
- * Queues an event to be fired. This has automatic de-bouncing so that any
556
- * events of the same type that occur within 100 milliseconds of a previous
557
- * one will all be wrapped into a single emit rather than emitting tons of
558
- * events for lots of chained inserts etc. Only the data from the last
559
- * de-bounced event will be emitted.
560
- * @memberOf Emitter
561
- * @method deferEmit
562
- * @param {String} eventName The name of the event to emit.
563
- * @param {*=} data Optional data to emit with the event.
564
- * @returns {Emitter} The emitter instance.
565
- */
566
- deferEmit (eventName, ...data) {
567
- if (!this._noEmitDefer && (!this._db || (this._db && !this._db._noEmitDefer))) {
568
- // Check for an existing timeout
569
- this._deferTimeout = this._deferTimeout || {};
570
-
571
- if (this._deferTimeout[eventName]) {
572
- clearTimeout(this._deferTimeout[eventName]);
573
- }
574
-
575
- // Set a timeout
576
- this._deferTimeout[eventName] = setTimeout(() => {
577
- this.emit.call(this, eventName, ...data);
578
- }, 1);
579
- } else {
580
- this.emit.call(this, eventName, ...data);
581
- }
582
-
583
- return this;
584
- }
585
-
586
- /**
587
- * If events are cleared with the off() method while the event emitter is
588
- * actively processing any events then the off() calls get added to a
589
- * queue to be executed after the event emitter is finished. This stops
590
- * errors that might occur by potentially modifying the event queue while
591
- * the emitter is running through them. This method is called after the
592
- * event emitter is finished processing.
593
- * @private
594
- */
595
- _processRemovalQueue () {
596
- if (!this._eventRemovalQueue || !this._eventRemovalQueue.length) {
597
- return;
598
- }
599
-
600
- // Execute each removal call
601
- for (let i = 0; i < this._eventRemovalQueue.length; i++) {
602
- this._eventRemovalQueue[i]();
603
- }
604
-
605
- // Clear the removal queue
606
- this._eventRemovalQueue = [];
607
- }
104
+ export class Emitter {
105
+ constructor() {
106
+ this._eventsEmitting = false;
107
+ this._eventRemovalQueue = [];
108
+ this._eventStaticEmitters = {};
109
+ this._eventsAllowDefer = false;
110
+ this._eventsDeferTimeouts = {};
111
+ }
112
+ /**
113
+ * Attach an event listener to the passed event only if the passed
114
+ * id matches the id for the event being fired.
115
+ * @param {string} eventName The name of the event to listen for.
116
+ * @param {string} id The id to match against.
117
+ * @param {function} listener The method to call when the event is fired.
118
+ * @returns {Emitter} The emitter instance.
119
+ */
120
+ _on(eventName, id, listener) {
121
+ const generateTimeout = (emitter) => {
122
+ setTimeout(() => {
123
+ listener(...emitter.args);
124
+ }, 1);
125
+ };
126
+ this._eventListeners = this._eventListeners || {};
127
+ this._eventListeners[eventName] = this._eventListeners[eventName] || {};
128
+ this._eventListeners[eventName][id] = this._eventListeners[eventName][id] || [];
129
+ this._eventListeners[eventName][id].push(listener);
130
+ // Check for any static emitters, and fire the event if any exist
131
+ if (!this._eventStaticEmitters || !this._eventStaticEmitters[eventName] || !this._eventStaticEmitters[eventName].length)
132
+ return this;
133
+ // Emit events for each emitter
134
+ for (let i = 0; i < this._eventStaticEmitters[eventName].length; i++) {
135
+ const emitter = this._eventStaticEmitters[eventName][i];
136
+ if (id === "*" || emitter.id === id) {
137
+ // Call the listener out of process so that any code that expects a listener
138
+ // to be called at some point in the future rather than immediately on registration
139
+ // will not fail
140
+ generateTimeout(emitter);
141
+ }
142
+ }
143
+ return this;
144
+ }
145
+ /**
146
+ * Attach an event listener to the passed event only if the passed
147
+ * id matches the document id for the event being fired.
148
+ * @param {String} eventName The name of the event to listen for.
149
+ * @param {*} id The id to match against.
150
+ * @param {Function} listener The method to call when the event is fired.
151
+ * @returns {Emitter} The emitter instance.
152
+ */
153
+ _once(eventName, id, listener) {
154
+ let fired = false;
155
+ const internalCallback = (...args) => {
156
+ if (fired)
157
+ return;
158
+ fired = true;
159
+ this.off(eventName, id, internalCallback);
160
+ listener(...args);
161
+ };
162
+ return this.on(eventName, id, internalCallback);
163
+ }
164
+ /**
165
+ * Cancels an event listener based on an event name, id and listener function.
166
+ * @param {String} eventName The event to cancel listener for.
167
+ * @param {String} id The ID of the event to cancel listening for.
168
+ * @param {Function} listener The event listener function used in the on()
169
+ * or once() call to cancel.
170
+ * @returns {Emitter} The emitter instance.
171
+ */
172
+ _off(eventName, id, listener) {
173
+ // If the event name doesn't have any listeners, exit early
174
+ if (!this._eventListeners || !this._eventListeners[eventName] || !this._eventListeners[eventName][id])
175
+ return this;
176
+ // If we are emitting events at the moment, don't remove this listener
177
+ // until the process has completed, so we queue for removal instead
178
+ if (this._eventsEmitting) {
179
+ this._eventRemovalQueue = this._eventRemovalQueue || [];
180
+ this._eventRemovalQueue.push(() => {
181
+ this.off(eventName, id, listener);
182
+ });
183
+ return this;
184
+ }
185
+ // Check if we have no specific listener... in this case
186
+ // we want to remove all listeners for an id
187
+ if (!listener) {
188
+ if (id === "*") {
189
+ // The id is "all" and no listener was provided so delete all
190
+ // event listeners for this event name
191
+ delete this._eventListeners[eventName];
192
+ return this;
193
+ }
194
+ // No listener provided, delete all listeners for this id
195
+ delete this._eventListeners[eventName][id];
196
+ return this;
197
+ }
198
+ const arr = this._eventListeners[eventName][id] || [];
199
+ const index = arr.indexOf(listener);
200
+ if (index > -1) {
201
+ arr.splice(index, 1);
202
+ }
203
+ return this;
204
+ }
205
+ on(eventName, ...rest) {
206
+ const restTypes = rest.map((arg) => typeof arg);
207
+ if (restTypes[0] === "function") {
208
+ return this._on(eventName, "*", rest[0]);
209
+ }
210
+ return this._on(eventName, rest[0], rest[1]);
211
+ }
212
+ once(eventName, ...rest) {
213
+ const restTypes = rest.map((arg) => typeof arg);
214
+ if (restTypes[0] === "function") {
215
+ return this._once(eventName, "*", rest[0]);
216
+ }
217
+ return this._once(eventName, rest[0], rest[1]);
218
+ }
219
+ overwrite(eventName, ...rest) {
220
+ const restTypes = rest.map((arg) => typeof arg);
221
+ if (restTypes[0] === "function") {
222
+ this.off(eventName);
223
+ return this._on(eventName, "*", rest[0]);
224
+ }
225
+ this.off(eventName, rest[0]);
226
+ return this._on(eventName, rest[0], rest[1]);
227
+ }
228
+ off(eventName, ...rest) {
229
+ if (rest.length === 0) {
230
+ // Only event was provided, use * as the id to mean "any without"
231
+ // a specific id
232
+ return this._off(eventName, "*");
233
+ }
234
+ const restTypes = rest.map((arg) => typeof arg);
235
+ if (restTypes[0] === "function") {
236
+ // The first arg after the event name was a function (listener)
237
+ // so remove listening for events for this specific listener
238
+ return this._off(eventName, "*", rest[0]);
239
+ }
240
+ // Both id and listener were provided, remove for the specific id
241
+ return this._off(eventName, rest[0], rest[1]);
242
+ }
243
+ /**
244
+ * Emit an event by name.
245
+ * @param {Object} eventName The name of the event to emit.
246
+ * @param {...any} data The arguments to send to any listening methods.
247
+ * If you are sending multiple arguments, separate them with a comma so
248
+ * that they are received by the function as separate arguments.
249
+ * @return {number}
250
+ * @example #Emit an Event
251
+ * // Emit the event named "hello"
252
+ * myEntity.emit('hello');
253
+ * @example #Emit an Event With Data Object
254
+ * // Emit the event named "hello"
255
+ * myEntity.emit('hello', {moo: true});
256
+ * @example #Emit an Event With Multiple Data Values
257
+ * // Emit the event named "hello"
258
+ * myEntity.emit('hello', {moo: true}, 'someString');
259
+ * @example #Listen for Event Data
260
+ * // Set a listener to listen for the data (multiple values emitted
261
+ * // from an event are passed as function arguments)
262
+ * myEntity.on('hello', function (arg1, arg2) {
263
+ * console.log(arg1, arg2);
264
+ * }
265
+ *
266
+ * // Emit the event named "hello"
267
+ * myEntity.emit('hello', 'data1', 'data2');
268
+ *
269
+ * // The console output is:
270
+ * // data1, data2
271
+ */
272
+ emit(eventName, ...data) {
273
+ return __awaiter(this, void 0, void 0, function* () {
274
+ if (!this._eventListeners) {
275
+ return EventReturnFlag.none;
276
+ }
277
+ const id = "*";
278
+ let returnFlag = EventReturnFlag.none;
279
+ this._eventsEmitting = true;
280
+ if (this._eventListeners[eventName] && this._eventListeners[eventName][id]) {
281
+ // Handle global emit
282
+ const arr = this._eventListeners[eventName][id];
283
+ const promiseArr = arr.map((tmpFunc) => {
284
+ if (typeof tmpFunc !== "function")
285
+ return;
286
+ return tmpFunc(...data);
287
+ });
288
+ const result = (yield Promise.all(promiseArr)).find((tmpResult) => tmpResult !== EventReturnFlag.none);
289
+ if (result) {
290
+ returnFlag = EventReturnFlag.cancel;
291
+ }
292
+ }
293
+ this._eventsEmitting = false;
294
+ this._processRemovalQueue();
295
+ return returnFlag;
296
+ });
297
+ }
298
+ emitId(eventName, id, ...data) {
299
+ if (!this._eventListeners) {
300
+ return EventReturnFlag.none;
301
+ }
302
+ this._eventListeners = this._eventListeners || {};
303
+ this._eventsEmitting = true;
304
+ if (!this._eventListeners[eventName]) {
305
+ this._eventsEmitting = false;
306
+ this._processRemovalQueue();
307
+ return EventReturnFlag.none;
308
+ }
309
+ // Handle id emit
310
+ if (this._eventListeners[eventName][id]) {
311
+ const arr = this._eventListeners[eventName][id];
312
+ const arrCount = arr.length;
313
+ for (let arrIndex = 0; arrIndex < arrCount; arrIndex++) {
314
+ // Check we have a function to execute
315
+ const tmpFunc = arr[arrIndex];
316
+ if (typeof tmpFunc === "function") {
317
+ tmpFunc.call(this, ...data);
318
+ }
319
+ }
320
+ }
321
+ // Handle global emit
322
+ if (this._eventListeners[eventName]["*"]) {
323
+ const arr = this._eventListeners[eventName]["*"];
324
+ const arrCount = arr.length;
325
+ for (let arrIndex = 0; arrIndex < arrCount; arrIndex++) {
326
+ // Check we have a function to execute
327
+ const tmpFunc = arr[arrIndex];
328
+ if (typeof tmpFunc === "function") {
329
+ tmpFunc.call(this, ...data);
330
+ }
331
+ }
332
+ }
333
+ this._eventsEmitting = false;
334
+ this._processRemovalQueue();
335
+ return EventReturnFlag.none;
336
+ }
337
+ /**
338
+ * Creates a persistent emitter record that will fire a listener if
339
+ * one is added for this event after the emitStatic() call has been
340
+ * made.
341
+ * @param {String} eventName The name of the event to emit.
342
+ * @param {...any} data Optional arguments to emit with the event.
343
+ * @returns {Emitter} The emitter instance.
344
+ * @private
345
+ */
346
+ emitStatic(eventName, ...data) {
347
+ const id = "*";
348
+ this._eventListeners = this._eventListeners || {};
349
+ this._eventsEmitting = true;
350
+ if (this._eventListeners[eventName] && this._eventListeners[eventName][id]) {
351
+ // Handle global emit
352
+ const arr = this._eventListeners[eventName][id];
353
+ const arrCount = arr.length;
354
+ for (let arrIndex = 0; arrIndex < arrCount; arrIndex++) {
355
+ // Check we have a function to execute
356
+ const tmpFunc = arr[arrIndex];
357
+ if (typeof tmpFunc === "function") {
358
+ tmpFunc.call(this, ...data);
359
+ }
360
+ }
361
+ }
362
+ this._eventsEmitting = false;
363
+ this._eventStaticEmitters = this._eventStaticEmitters || {};
364
+ this._eventStaticEmitters[eventName] = this._eventStaticEmitters[eventName] || [];
365
+ this._eventStaticEmitters[eventName].push({
366
+ "id": "*",
367
+ "args": data
368
+ });
369
+ this._processRemovalQueue();
370
+ return this;
371
+ }
372
+ /**
373
+ * Creates a persistent emitter record that will fire a listener if
374
+ * one is added for this event after the emitStatic() call has been
375
+ * made.
376
+ * @param {String} eventName The name of the event to emit.
377
+ * @param {String} id The id of the event to emit.
378
+ * @param {...any} data Optional arguments to emit with the event.
379
+ * @returns {Emitter} The emitter instance.
380
+ * @private
381
+ */
382
+ emitStaticId(eventName, id, ...data) {
383
+ if (!id)
384
+ throw new Error("Missing id from emitId call!");
385
+ this._eventListeners = this._eventListeners || {};
386
+ this._eventsEmitting = true;
387
+ if (this._eventListeners[eventName]) {
388
+ // Handle id emit
389
+ if (this._eventListeners[eventName][id]) {
390
+ const arr = this._eventListeners[eventName][id];
391
+ const arrCount = arr.length;
392
+ for (let arrIndex = 0; arrIndex < arrCount; arrIndex++) {
393
+ // Check we have a function to execute
394
+ const tmpFunc = arr[arrIndex];
395
+ if (typeof tmpFunc === "function") {
396
+ tmpFunc.call(this, ...data);
397
+ }
398
+ }
399
+ }
400
+ // Handle global emit
401
+ if (this._eventListeners[eventName]["*"]) {
402
+ const arr = this._eventListeners[eventName]["*"];
403
+ const arrCount = arr.length;
404
+ for (let arrIndex = 0; arrIndex < arrCount; arrIndex++) {
405
+ // Check we have a function to execute
406
+ const tmpFunc = arr[arrIndex];
407
+ if (typeof tmpFunc === "function") {
408
+ tmpFunc.call(this, ...data);
409
+ }
410
+ }
411
+ }
412
+ }
413
+ this._eventsEmitting = false;
414
+ this._eventStaticEmitters = this._eventStaticEmitters || {};
415
+ this._eventStaticEmitters[eventName] = this._eventStaticEmitters[eventName] || [];
416
+ this._eventStaticEmitters[eventName].push({
417
+ id,
418
+ "args": data
419
+ });
420
+ this._processRemovalQueue();
421
+ return this;
422
+ }
423
+ /**
424
+ * Handles removing emitters, is an internal method not called directly.
425
+ * @param {String} eventName The event to remove static emitter for.
426
+ * @returns {Emitter} The emitter instance.
427
+ * @private
428
+ */
429
+ cancelStatic(eventName) {
430
+ this._eventStaticEmitters = this._eventStaticEmitters || {};
431
+ this._eventStaticEmitters[eventName] = [];
432
+ return this;
433
+ }
434
+ /**
435
+ * Checks if an event has any event listeners or not.
436
+ * @param {String} eventName The name of the event to check for.
437
+ * @returns {boolean} True if one or more event listeners are registered for
438
+ * the event. False if none are found.
439
+ */
440
+ willEmit(eventName) {
441
+ const id = "*";
442
+ if (!this._eventListeners || !this._eventListeners[eventName]) {
443
+ return false;
444
+ }
445
+ const arr = this._eventListeners[eventName][id];
446
+ const arrCount = arr.length;
447
+ for (let arrIndex = 0; arrIndex < arrCount; arrIndex++) {
448
+ // Check we have a function to execute
449
+ const tmpFunc = arr[arrIndex];
450
+ if (typeof tmpFunc === "function") {
451
+ return true;
452
+ }
453
+ }
454
+ return false;
455
+ }
456
+ /**
457
+ * Checks if an event has any event listeners or not based on the passed id.
458
+ * @param {String} eventName The name of the event to check for.
459
+ * @param {String} id The event ID to check for.
460
+ * @returns {boolean} True if one or more event listeners are registered for
461
+ * the event. False if none are found.
462
+ */
463
+ willEmitId(eventName, id) {
464
+ if (!this._eventListeners || !this._eventListeners[eventName]) {
465
+ return false;
466
+ }
467
+ // Handle id emit
468
+ if (this._eventListeners[eventName][id]) {
469
+ const arr = this._eventListeners[eventName][id];
470
+ const arrCount = arr.length;
471
+ for (let arrIndex = 0; arrIndex < arrCount; arrIndex++) {
472
+ // Check we have a function to execute
473
+ const tmpFunc = arr[arrIndex];
474
+ if (typeof tmpFunc === "function") {
475
+ return true;
476
+ }
477
+ }
478
+ }
479
+ // Handle global emit
480
+ if (this._eventListeners[eventName]["*"]) {
481
+ const arr = this._eventListeners[eventName]["*"];
482
+ const arrCount = arr.length;
483
+ for (let arrIndex = 0; arrIndex < arrCount; arrIndex++) {
484
+ // Check we have a function to execute
485
+ const tmpFunc = arr[arrIndex];
486
+ if (typeof tmpFunc === "function") {
487
+ return true;
488
+ }
489
+ }
490
+ }
491
+ return false;
492
+ }
493
+ /**
494
+ * Queues an event to be fired. This has automatic de-bouncing so that any
495
+ * events of the same type that occur within 100 milliseconds of a previous
496
+ * one will all be wrapped into a single emit rather than emitting tons of
497
+ * events for lots of chained inserts etc. Only the data from the last
498
+ * de-bounced event will be emitted.
499
+ * @param {String} eventName The name of the event to emit.
500
+ * @param {...any} data Optional arguments to emit with the event.
501
+ * @returns {Emitter} The emitter instance.
502
+ */
503
+ deferEmit(eventName, ...data) {
504
+ if (!this._eventsAllowDefer) {
505
+ // Check for an existing timeout
506
+ this._eventsDeferTimeouts = this._eventsDeferTimeouts || {};
507
+ if (this._eventsDeferTimeouts[eventName]) {
508
+ clearTimeout(this._eventsDeferTimeouts[eventName]);
509
+ }
510
+ // Set a timeout
511
+ this._eventsDeferTimeouts[eventName] = setTimeout(() => {
512
+ this.emit.call(this, eventName, ...data);
513
+ }, 1);
514
+ }
515
+ else {
516
+ this.emit.call(this, eventName, ...data);
517
+ }
518
+ return this;
519
+ }
520
+ /**
521
+ * If events are cleared with the off() method while the event emitter is
522
+ * actively processing any events then the off() calls get added to a
523
+ * queue to be executed after the event emitter is finished. This stops
524
+ * errors that might occur by potentially modifying the event queue while
525
+ * the emitter is running through them. This method is called after the
526
+ * event emitter is finished processing.
527
+ * @private
528
+ */
529
+ _processRemovalQueue() {
530
+ if (!this._eventRemovalQueue || !this._eventRemovalQueue.length) {
531
+ return;
532
+ }
533
+ // Execute each removal call
534
+ for (let i = 0; i < this._eventRemovalQueue.length; i++) {
535
+ this._eventRemovalQueue[i]();
536
+ }
537
+ // Clear the removal queue
538
+ this._eventRemovalQueue = [];
539
+ }
540
+ }
541
+ export function makeEmitter(obj, prototypeMode) {
542
+ let operateOnObject;
543
+ if (obj === undefined && prototypeMode === undefined) {
544
+ obj = {};
545
+ prototypeMode = false;
546
+ }
547
+ if (typeof obj === "boolean" && prototypeMode === undefined) {
548
+ prototypeMode = obj;
549
+ obj = {};
550
+ }
551
+ if (prototypeMode === undefined) {
552
+ prototypeMode = true;
553
+ }
554
+ if (typeof obj !== "object" && typeof obj !== "function") {
555
+ throw new Error("Cannot operate on a non-object / non-function passed as first argument!");
556
+ }
557
+ if (prototypeMode) {
558
+ if (obj.prototype === undefined) {
559
+ throw new Error("Cannot modify prototype of passed object, it has no prototype property! Was it instantiated with the new operator correctly?");
560
+ }
561
+ operateOnObject = obj.prototype;
562
+ }
563
+ else {
564
+ operateOnObject = obj;
565
+ }
566
+ // Convert the object prototype to have eventing capability
567
+ operateOnObject.on = Emitter.prototype.on;
568
+ operateOnObject.off = Emitter.prototype.off;
569
+ operateOnObject.once = Emitter.prototype.once;
570
+ operateOnObject.emit = Emitter.prototype.emit;
571
+ operateOnObject.emitId = Emitter.prototype.emitId;
572
+ operateOnObject.emitStatic = Emitter.prototype.emitStatic;
573
+ operateOnObject.emitStaticId = Emitter.prototype.emitStaticId;
574
+ operateOnObject.cancelStatic = Emitter.prototype.cancelStatic;
575
+ operateOnObject.deferEmit = Emitter.prototype.deferEmit;
576
+ operateOnObject.willEmit = Emitter.prototype.willEmit;
577
+ operateOnObject.willEmitId = Emitter.prototype.willEmitId;
578
+ operateOnObject._processRemovalQueue = Emitter.prototype._processRemovalQueue;
579
+ return obj;
608
580
  }
609
-
610
- /**
611
- * Makes the passed class or object into an emitter by modifying either the
612
- * prototype or the actual object to include event emitter methods.
613
- * @param {Object} [obj={}] The object / function / class to add event methods to.
614
- * If none is provided a new object will be created. This allows you to use
615
- * new Emitter() to generate an event emitter that is not tied to any other
616
- * object or class.
617
- * @param {Boolean} [prototypeMode=true] Defaults to true. Set to true to add emitter
618
- * methods to the the passed object"s prototype property e.g. obj.prototype.on
619
- * = emitter.on. Set to false to add emitter methods the object directly e.g.
620
- * obj.on = emitter.on.
621
- * @returns {Object} The newly augmented object.
622
- */
623
- const makeEmitter = function (obj, prototypeMode) {
624
- let operateOnObject;
625
-
626
- if (obj === undefined && prototypeMode === undefined) {
627
- obj = {};
628
- prototypeMode = false;
629
- }
630
-
631
- if (typeof obj === "boolean" && prototypeMode === undefined) {
632
- prototypeMode = obj;
633
- obj = {};
634
- }
635
-
636
- if (prototypeMode === undefined) {
637
- prototypeMode = true;
638
- }
639
-
640
- if (typeof obj !== "object" && typeof obj !== "function") {
641
- throw new Error("Cannot operate on a non-object / non-function passed as first argument!");
642
- }
643
-
644
- if (prototypeMode) {
645
- if (obj.prototype === undefined) {
646
- throw new Error("Cannot modify prototype of passed object, it has no prototype property! Was it instantiated with the new operator correctly?");
647
- }
648
-
649
- operateOnObject = obj.prototype;
650
- } else {
651
- operateOnObject = obj;
652
- }
653
-
654
- // Convert the object prototype to have eventing capability
655
- operateOnObject.on = Emitter.prototype.on;
656
- operateOnObject.off = Emitter.prototype.off;
657
- operateOnObject.one = Emitter.prototype.one;
658
- operateOnObject.once = Emitter.prototype.once;
659
- operateOnObject.emit = Emitter.prototype.emit;
660
- operateOnObject.emitId = Emitter.prototype.emitId;
661
- operateOnObject.emitStatic = Emitter.prototype.emitStatic;
662
- operateOnObject.emitStaticId = Emitter.prototype.emitStaticId;
663
- operateOnObject.cancelStatic = Emitter.prototype.cancelStatic;
664
- operateOnObject.deferEmit = Emitter.prototype.deferEmit;
665
- operateOnObject.willEmit = Emitter.prototype.willEmit;
666
- operateOnObject.willEmitId = Emitter.prototype.willEmitId;
667
- operateOnObject._processRemovalQueue = Emitter.prototype._processRemovalQueue;
668
-
669
- return obj;
670
- };
671
-
672
- module.exports = {
673
- Emitter,
674
- makeEmitter
675
- };