@lumjs/core 1.30.0 → 1.31.0
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/README.md +1 -1
- package/jsdoc.js +13 -0
- package/lib/enum.js +38 -9
- package/lib/events/event.js +85 -0
- package/lib/events/index.js +30 -0
- package/lib/events/listener.js +127 -0
- package/lib/events/registry.js +537 -0
- package/lib/index.js +23 -2
- package/lib/meta.js +15 -6
- package/lib/obj/copyprops.js +1 -1
- package/lib/obj/cp.js +1375 -0
- package/lib/obj/flip.js +2 -0
- package/lib/obj/index.js +2 -1
- package/lib/objectid.js +7 -0
- package/lib/types/basics.js +6 -14
- package/lib/types/dt.js +3 -3
- package/lib/types/index.js +0 -3
- package/lib/types/js.js +21 -2
- package/lib/types/typelist.js +6 -4
- package/lum.build.js +40 -0
- package/package.json +19 -13
- package/TODO.md +0 -76
- package/jsdoc.json +0 -33
|
@@ -0,0 +1,537 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const {S,F,isObj,def,isIterable} = require('../types');
|
|
4
|
+
const Listener = require('./listener');
|
|
5
|
+
|
|
6
|
+
const DEF_EXTENDS =
|
|
7
|
+
{
|
|
8
|
+
registry: 'events',
|
|
9
|
+
listen: 'on',
|
|
10
|
+
emit: 'emit',
|
|
11
|
+
remove: null,
|
|
12
|
+
once: null,
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const DEF_OPTIONS =
|
|
16
|
+
{
|
|
17
|
+
delimiter: /\s+/,
|
|
18
|
+
multiMatch: false,
|
|
19
|
+
wildcard: '*',
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* A class that handles events for target objects
|
|
24
|
+
*
|
|
25
|
+
* @prop {module:@lumjs/core/events~GetTargets} getTargets
|
|
26
|
+
* A constructor-assigned callback method that returns a set of targets.
|
|
27
|
+
* @prop {object} options - Registry-level options
|
|
28
|
+
* @prop {Set.<module:@lumjs/core/events.Listener>} allListeners
|
|
29
|
+
* All registered event listeners
|
|
30
|
+
* @prop {Map.<string,Set.<module:@lumjs/core/events.Listener>>} listenersFor
|
|
31
|
+
* Each key is a single event name, and the value is a Set of
|
|
32
|
+
* listener objects that handle that event.
|
|
33
|
+
*
|
|
34
|
+
* @alias module:@lumjs/core/events.Registry
|
|
35
|
+
*/
|
|
36
|
+
class LumEventRegistry
|
|
37
|
+
{
|
|
38
|
+
/**
|
|
39
|
+
* Create a new registry instance for one or more target objects
|
|
40
|
+
*
|
|
41
|
+
* @param {(object|module:@lumjs/core/events~GetTargets)} targets
|
|
42
|
+
*
|
|
43
|
+
* If this is a `function`, it will be called to dynamically get a
|
|
44
|
+
* list of target objects whenever an event is triggered.
|
|
45
|
+
*
|
|
46
|
+
* If this is an `object`, then any kind of `Iterable` may be used
|
|
47
|
+
* to represent multiple targets, while any non-Iterable object will
|
|
48
|
+
* be considered as single target.
|
|
49
|
+
*
|
|
50
|
+
* @param {object} [opts] Options (saved to `options` property).
|
|
51
|
+
*
|
|
52
|
+
* @param {(RegExp|string)} [opts.delimiter=/\s+/] Used to split event names
|
|
53
|
+
*
|
|
54
|
+
* @param {boolean} [opts.multiMatch=false]
|
|
55
|
+
* If a registered listener has multiple event names, and a call
|
|
56
|
+
* to `emit()` also has multiple event names, the value of this
|
|
57
|
+
* option will determine if the same listener will have its
|
|
58
|
+
* handler function called more than once.
|
|
59
|
+
*
|
|
60
|
+
* If this is `true`, the handler will be called once for every
|
|
61
|
+
* combination of target and event name.
|
|
62
|
+
*
|
|
63
|
+
* If this is `false` (default), then only the first matching event
|
|
64
|
+
* name will be called for each target.
|
|
65
|
+
*
|
|
66
|
+
* @param {(object|boolean)} [opts.extend]
|
|
67
|
+
* This option determines the rules for adding wrapper methods and
|
|
68
|
+
* other extension properties to the target objects.
|
|
69
|
+
*
|
|
70
|
+
* If this is `true` (default when `targets` is an `object`), then
|
|
71
|
+
* the target objects will be extended using the default property names.
|
|
72
|
+
*
|
|
73
|
+
* If this is set to `false` (default when `targets` is a `function`),
|
|
74
|
+
* it disables adding extension properties entirely.
|
|
75
|
+
*
|
|
76
|
+
* If it is an `object` then each nested property may be set to a string
|
|
77
|
+
* to override the default, or `null` to skip adding that property.
|
|
78
|
+
*
|
|
79
|
+
* @param {?string} [opts.extend.registry="events"] Registry property
|
|
80
|
+
* @param {?string} [opts.extend.emit="emit"] `emit()` proxy method
|
|
81
|
+
* @param {?string} [opts.extend.listen="on"] `listen()` proxy method
|
|
82
|
+
* @param {?string} [opts.extend.once=null] `once()` proxy method
|
|
83
|
+
* @param {?string} [opts.extend.remove=null] `remove()` proxy method
|
|
84
|
+
*
|
|
85
|
+
* @param {boolean} [opts.overwrite=false] Overwrite existing properties?
|
|
86
|
+
*
|
|
87
|
+
* If `true` then when adding wrapper methods, the properties from
|
|
88
|
+
* `opts.extend` will replace any existing ones in each target.
|
|
89
|
+
*
|
|
90
|
+
* @param {function} [opts.setupEvent] Initialize each Event object?
|
|
91
|
+
*
|
|
92
|
+
* If this is specified (either here or in individual listeners),
|
|
93
|
+
* it will be called and passed the Event object at the very end of
|
|
94
|
+
* its constructor.
|
|
95
|
+
*
|
|
96
|
+
* @param {string} [opts.wildcard='*'] Wildcard event name.
|
|
97
|
+
*
|
|
98
|
+
* - If you use this in `listen()` the handler will be used regardless
|
|
99
|
+
* as to what event name was triggered. You can always see which
|
|
100
|
+
* event name was actually triggered by using `event.name`.
|
|
101
|
+
* - If you use this in `remove()` it calls `removeAll()` to remove all
|
|
102
|
+
* registered listeners.
|
|
103
|
+
*/
|
|
104
|
+
constructor(targets, opts={})
|
|
105
|
+
{
|
|
106
|
+
let defExt; // Default opts.extend value
|
|
107
|
+
if (typeof targets === F)
|
|
108
|
+
{ // A dynamic getter method
|
|
109
|
+
this.getTargets = targets;
|
|
110
|
+
defExt = false;
|
|
111
|
+
}
|
|
112
|
+
else
|
|
113
|
+
{ // Simple getter for a static value
|
|
114
|
+
if (!isIterable(targets))
|
|
115
|
+
{
|
|
116
|
+
targets = [targets];
|
|
117
|
+
}
|
|
118
|
+
this.getTargets = () => targets;
|
|
119
|
+
defExt = true;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
this.options = Object.assign({}, DEF_OPTIONS, opts);
|
|
123
|
+
|
|
124
|
+
this.allListeners = new Set();
|
|
125
|
+
this.listenersFor = new Map();
|
|
126
|
+
|
|
127
|
+
const extOpts = opts.extend ?? defExt;
|
|
128
|
+
if (extOpts !== false)
|
|
129
|
+
{
|
|
130
|
+
const intNames = Object.keys(DEF_EXTENDS);
|
|
131
|
+
const extNames = Object.assign({}, DEF_EXTENDS, extOpts);
|
|
132
|
+
const targets = this.getTargets();
|
|
133
|
+
|
|
134
|
+
for (const iname of intNames)
|
|
135
|
+
{
|
|
136
|
+
if (typeof extNames[iname] === S && extNames[iname].trim() !== '')
|
|
137
|
+
{
|
|
138
|
+
const ename = extNames[iname];
|
|
139
|
+
const value = iname === 'registry'
|
|
140
|
+
? this // The registry instance itself
|
|
141
|
+
: (...args) => this[iname](...args) // A proxy method
|
|
142
|
+
for (const target of targets)
|
|
143
|
+
{
|
|
144
|
+
if (opts.overwrite || target[ename] === undefined)
|
|
145
|
+
{
|
|
146
|
+
def(target, ename, {value});
|
|
147
|
+
}
|
|
148
|
+
else
|
|
149
|
+
{
|
|
150
|
+
console.error("Won't overwrite existing property",
|
|
151
|
+
{target,iname,ename,registry: this});
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
} // constructor()
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Build a new Listener instance; used by `listen()` method.
|
|
161
|
+
*
|
|
162
|
+
* @param {(string|object)} eventNames
|
|
163
|
+
* What this does depends on the type, and the number of arguments passed.
|
|
164
|
+
*
|
|
165
|
+
* If this is an `object` **AND** is *the only argument* passed,
|
|
166
|
+
* it will be used as the `spec`, and the `spec.eventNames`
|
|
167
|
+
* and `spec.listener` properties will become mandatory.
|
|
168
|
+
*
|
|
169
|
+
* If it's a string or there is more than one argument, this
|
|
170
|
+
* will be used as the `spec.eventNames` property.
|
|
171
|
+
*
|
|
172
|
+
* @param {module:@lumjs/core/events~Handler} [handler]
|
|
173
|
+
* Used as the `spec.handler` property if specified.
|
|
174
|
+
*
|
|
175
|
+
* This is mandatory if `eventNames` argument is a `string`!
|
|
176
|
+
*
|
|
177
|
+
* @param {object} [spec] The listener specification rules
|
|
178
|
+
*
|
|
179
|
+
* @param {(string|Iterable)} [spec.eventNames] Event names to listen for
|
|
180
|
+
*
|
|
181
|
+
* See {@link module:@lumjs/core/events.Registry#getEventNames} for details.
|
|
182
|
+
*
|
|
183
|
+
* @param {module:@lumjs/core/events~Handler} [spec.handler] Event handler.
|
|
184
|
+
*
|
|
185
|
+
* @param {(function|object)} [spec.listener] An alias for `handler`
|
|
186
|
+
*
|
|
187
|
+
* @param {object} [spec.options] Options for the listener
|
|
188
|
+
*
|
|
189
|
+
* The option properties can be included directly in the `spec` itself
|
|
190
|
+
* for brevity, but a nested `options` object is supported to be more
|
|
191
|
+
* like the `DOM.addEventListener()` method. Either way works fine.
|
|
192
|
+
*
|
|
193
|
+
* If `spec.options` is used, the properties in it take precedence over
|
|
194
|
+
* those directly in the `spec` object. Note that you cannot use the
|
|
195
|
+
* names `listener`, `handler` or `eventNames` as option properties,
|
|
196
|
+
* and if found, they will be removed.
|
|
197
|
+
*
|
|
198
|
+
* You may also override the `setupEvent` registry option here.
|
|
199
|
+
*
|
|
200
|
+
* @param {boolean} [spec.options.once=false] Only use the listener once?
|
|
201
|
+
*
|
|
202
|
+
* If this is set to `true`, then the first time this listener is used in
|
|
203
|
+
* an {@link module:@lumjs/core/events.Registry#emit emit()} call, it will
|
|
204
|
+
* be removed from the registry at the end of the emit process (after all
|
|
205
|
+
* events for all targets have been triggered).
|
|
206
|
+
*
|
|
207
|
+
* @returns {module:@lumjs/core/events.Listener} A new `Listener` instance
|
|
208
|
+
*/
|
|
209
|
+
makeListener(...args)
|
|
210
|
+
{
|
|
211
|
+
let spec;
|
|
212
|
+
|
|
213
|
+
if (args.length === 0 || args.length > 3)
|
|
214
|
+
{
|
|
215
|
+
console.error({args, registry: this});
|
|
216
|
+
throw new RangeError("Invalid number of arguments");
|
|
217
|
+
}
|
|
218
|
+
else if (args.length === 1 && isObj(args[0]))
|
|
219
|
+
{ // listen(spec)
|
|
220
|
+
spec = Object.assign({}, args[0]);
|
|
221
|
+
}
|
|
222
|
+
else
|
|
223
|
+
{ // listen(eventNames, listener, [spec])
|
|
224
|
+
spec = Object.assign({}, args[2]);
|
|
225
|
+
spec.eventNames = args[0];
|
|
226
|
+
spec.handler = args[1];
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
return new Listener(this, spec);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Assign a new event listener.
|
|
234
|
+
*
|
|
235
|
+
* Calls `this.makeListener()` passing all arguments to it.
|
|
236
|
+
* Then calls `this.add(listener)` passing the newly make `Listener`.
|
|
237
|
+
*
|
|
238
|
+
* @param {...mixed} args
|
|
239
|
+
* @returns {module:@lumjs/core/events.Listener}
|
|
240
|
+
*/
|
|
241
|
+
listen()
|
|
242
|
+
{
|
|
243
|
+
const listener = this.makeListener(...arguments)
|
|
244
|
+
this.add(listener);
|
|
245
|
+
return listener;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Assign a new event listener that will only run once.
|
|
250
|
+
*
|
|
251
|
+
* Calls `this.listen()` passing all arguments to it,
|
|
252
|
+
* then sets the `listener.options.once` to `true`.
|
|
253
|
+
*
|
|
254
|
+
* @param {...mixed} args
|
|
255
|
+
* @returns {module:@lumjs/core/events.Listener}
|
|
256
|
+
*/
|
|
257
|
+
once()
|
|
258
|
+
{
|
|
259
|
+
const listener = this.listen(...arguments);
|
|
260
|
+
listener.options.once = true;
|
|
261
|
+
return listener;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Add a Listener instance.
|
|
266
|
+
*
|
|
267
|
+
* You'd generally use `listen()` or `once()` rather than this, but if
|
|
268
|
+
* you need to (re-)add an existing instance, this is the way to do it.
|
|
269
|
+
*
|
|
270
|
+
* @param {module:@lumjs/core/events.Listener} listener - Listener instance
|
|
271
|
+
*
|
|
272
|
+
* If the same instance is passed more than once it will have no affect,
|
|
273
|
+
* as we store the instances in a `Set` internally, so it'll only ever
|
|
274
|
+
* be stored once.
|
|
275
|
+
*
|
|
276
|
+
* @returns {module:@lumjs/core/events.Registry} `this`
|
|
277
|
+
*/
|
|
278
|
+
add(listener)
|
|
279
|
+
{
|
|
280
|
+
if (!(listener instanceof Listener))
|
|
281
|
+
{
|
|
282
|
+
console.error({listener, registry: this});
|
|
283
|
+
throw new TypeError("Invalid listener instance");
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
this.allListeners.add(listener);
|
|
287
|
+
|
|
288
|
+
for (const ename of listener.eventNames)
|
|
289
|
+
{
|
|
290
|
+
let lset;
|
|
291
|
+
if (this.listenersFor.has(ename))
|
|
292
|
+
{
|
|
293
|
+
lset = this.listenersFor.get(ename);
|
|
294
|
+
}
|
|
295
|
+
else
|
|
296
|
+
{
|
|
297
|
+
lset = new Set();
|
|
298
|
+
this.listenersFor.set(ename, lset);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
lset.add(listener);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
return this;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Remove **ALL** registered event listeners!
|
|
309
|
+
* @returns {module:@lumjs/core/events.Registry} `this`
|
|
310
|
+
*/
|
|
311
|
+
removeAll()
|
|
312
|
+
{
|
|
313
|
+
this.allListeners.clear();
|
|
314
|
+
this.listenersFor.clear();
|
|
315
|
+
return this;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Remove specific event names.
|
|
320
|
+
*
|
|
321
|
+
* It will remove any of the the specified event names
|
|
322
|
+
* from applicable listener instances, and clear the
|
|
323
|
+
* associated `listenersFor` set.
|
|
324
|
+
*
|
|
325
|
+
* If a listener has no more event names left, that listener
|
|
326
|
+
* will be removed from the `allListeners` set as well.
|
|
327
|
+
*
|
|
328
|
+
* @param {...string} names - Event names to remove
|
|
329
|
+
*
|
|
330
|
+
* If the `wildcard` string is specified here, this will simply
|
|
331
|
+
* remove any wildcard listeners currently registered.
|
|
332
|
+
* See `remove(wildcard)` or `removeAll()` if you really want
|
|
333
|
+
* to remove **ALL** listeners.
|
|
334
|
+
*
|
|
335
|
+
* @returns {module:@lumjs/core/events.Registry} `this`
|
|
336
|
+
*/
|
|
337
|
+
removeEvents(...names)
|
|
338
|
+
{
|
|
339
|
+
for (const name of names)
|
|
340
|
+
{
|
|
341
|
+
if (this.listenersFor.has(name))
|
|
342
|
+
{
|
|
343
|
+
const eventListeners = this.listenersFor.get(name);
|
|
344
|
+
for (const lsnr of eventListeners)
|
|
345
|
+
{
|
|
346
|
+
lsnr.eventNames.delete(name);
|
|
347
|
+
if (!lsnr.hasEvents)
|
|
348
|
+
{ // The last event name was removed.
|
|
349
|
+
this.removeListeners(lsnr);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
eventListeners.clear();
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
return this;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* Remove specific Listener instances
|
|
360
|
+
* @param {...module:@lumjs/core/events.Listener} listeners
|
|
361
|
+
* @returns {module:@lumjs/core/events.Registry} `this`
|
|
362
|
+
*/
|
|
363
|
+
removeListeners(...listeners)
|
|
364
|
+
{
|
|
365
|
+
for (const listener of listeners)
|
|
366
|
+
{
|
|
367
|
+
if (this.allListeners.has(listener))
|
|
368
|
+
{ // First remove it from allListeners
|
|
369
|
+
this.allListeners.delete(listener);
|
|
370
|
+
|
|
371
|
+
for (const ename of listener.eventNames)
|
|
372
|
+
{
|
|
373
|
+
if (this.listenersFor.has(ename))
|
|
374
|
+
{
|
|
375
|
+
const lset = this.listenersFor.get(ename);
|
|
376
|
+
lset.delete(listener);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
return this;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* Remove listeners based on the value type used.
|
|
386
|
+
*
|
|
387
|
+
* @param {(string|module:@lumjs/core/events.Listener)} what
|
|
388
|
+
*
|
|
389
|
+
* - If this is the `wildcard` string, then this will call `removeAll()`.
|
|
390
|
+
* - If this is any other `string` it will be split using `splitNames()`,
|
|
391
|
+
* and the resulting strings passed as arguments to `removeEvents()`.
|
|
392
|
+
* - If this is a `Listener` instance, its passed to `removeListeners()`.
|
|
393
|
+
*
|
|
394
|
+
* @returns {module:@lumjs/core/events.Registry} `this`
|
|
395
|
+
* @throws {TypeError} If `what` is none of the above values.
|
|
396
|
+
*/
|
|
397
|
+
remove(what)
|
|
398
|
+
{
|
|
399
|
+
if (what === this.options.wildcard)
|
|
400
|
+
{
|
|
401
|
+
return this.removeAll();
|
|
402
|
+
}
|
|
403
|
+
else if (typeof what === S)
|
|
404
|
+
{
|
|
405
|
+
const events = this.splitNames(what);
|
|
406
|
+
return this.removeEvents(...events);
|
|
407
|
+
}
|
|
408
|
+
else if (what instanceof Listener)
|
|
409
|
+
{
|
|
410
|
+
return this.removeListeners(what);
|
|
411
|
+
}
|
|
412
|
+
else
|
|
413
|
+
{
|
|
414
|
+
console.error({what, registry: this});
|
|
415
|
+
throw new TypeError("Invalid event name or listener instance");
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
/**
|
|
420
|
+
* Emit (trigger) one or more events.
|
|
421
|
+
*
|
|
422
|
+
* @param {(string|string[])} eventNames - Events to emit.
|
|
423
|
+
*
|
|
424
|
+
* If this is a single `string` it will be split via `splitNames()`.
|
|
425
|
+
*
|
|
426
|
+
* @param {object} [data] A data object (highly recommended);
|
|
427
|
+
* will be assigned to `event.data` if specified.
|
|
428
|
+
*
|
|
429
|
+
* @param {...any} [args] Any other arguments;
|
|
430
|
+
* will be assigned to `event.args`.
|
|
431
|
+
*
|
|
432
|
+
* Note: if a `data` object argument was passed, it will always
|
|
433
|
+
* be the first item in `event.args`.
|
|
434
|
+
*
|
|
435
|
+
* @returns {module:@lumjs/core/events~Status}
|
|
436
|
+
*/
|
|
437
|
+
emit(eventNames, ...args)
|
|
438
|
+
{
|
|
439
|
+
const sti =
|
|
440
|
+
{
|
|
441
|
+
eventNames: this.getEventNames(eventNames),
|
|
442
|
+
multiMatch: this.options.multiMatch,
|
|
443
|
+
onceRemoved: new Set(),
|
|
444
|
+
stopEmitting: false,
|
|
445
|
+
emitted: [],
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
{ // Get the targets.
|
|
449
|
+
const tgs = this.getTargets(sti);
|
|
450
|
+
sti.targets = (tgs instanceof Set) ? tgs : new Set(tgs);
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
const wilds = this.listenersFor.get(this.options.wildcard);
|
|
454
|
+
|
|
455
|
+
emitting: for (const tg of sti.targets)
|
|
456
|
+
{
|
|
457
|
+
const called = sti.targetListeners = new Set();
|
|
458
|
+
for (const ename of sti.eventNames)
|
|
459
|
+
{
|
|
460
|
+
if (!this.listenersFor.has(ename)) continue;
|
|
461
|
+
|
|
462
|
+
let listeners = this.listenersFor.get(ename);
|
|
463
|
+
if (wilds) listeners = listeners.union(wilds);
|
|
464
|
+
|
|
465
|
+
for (const lsnr of listeners)
|
|
466
|
+
{
|
|
467
|
+
if (sti.multiMatch || !called.has(lsnr))
|
|
468
|
+
{ // Let's emit an event!
|
|
469
|
+
called.add(lsnr);
|
|
470
|
+
const event = lsnr.emitEvent(ename, tg, args, sti);
|
|
471
|
+
sti.emitted.push(event);
|
|
472
|
+
if (sti.stopEmitting)
|
|
473
|
+
{
|
|
474
|
+
break emitting;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
// Nix the targetListeners property.
|
|
482
|
+
delete sti.targetListeners;
|
|
483
|
+
|
|
484
|
+
// Handle any `onceRemoved` listeners.
|
|
485
|
+
for (const lsnr of sti.onceRemoved)
|
|
486
|
+
{
|
|
487
|
+
this.removeListeners(lsnr);
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// Return the final status.
|
|
491
|
+
return sti;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
/**
|
|
495
|
+
* Get a Set of event names from various kinds of values
|
|
496
|
+
* @param {(string|Iterable)} names - Event names source
|
|
497
|
+
*
|
|
498
|
+
* If this is a string, it'll be passed to `splitNames()`.
|
|
499
|
+
* If it's any kind of `Iterable`, it'll be converted to a `Set`.
|
|
500
|
+
*
|
|
501
|
+
* @returns {Set}
|
|
502
|
+
* @throws {TypeError} If `names` is not a valid value
|
|
503
|
+
*/
|
|
504
|
+
getEventNames(names)
|
|
505
|
+
{
|
|
506
|
+
if (typeof names === S)
|
|
507
|
+
{
|
|
508
|
+
return this.splitNames(names);
|
|
509
|
+
}
|
|
510
|
+
else if (names instanceof Set)
|
|
511
|
+
{
|
|
512
|
+
return names;
|
|
513
|
+
}
|
|
514
|
+
else if (isIterable(names))
|
|
515
|
+
{
|
|
516
|
+
return new Set(names);
|
|
517
|
+
}
|
|
518
|
+
else
|
|
519
|
+
{
|
|
520
|
+
console.error({names, registry: this});
|
|
521
|
+
throw new TypeError("Invalid event names");
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
/**
|
|
526
|
+
* Split a (trimmed) string using `this.options.delimiter`
|
|
527
|
+
* @param {string} names - String to split
|
|
528
|
+
* @returns {Set}
|
|
529
|
+
*/
|
|
530
|
+
splitNames(names)
|
|
531
|
+
{
|
|
532
|
+
return new Set(names.trim().split(this.options.delimiter));
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
module.exports = LumEventRegistry;
|
package/lib/index.js
CHANGED
|
@@ -22,6 +22,7 @@ const types = require('./types');
|
|
|
22
22
|
/**
|
|
23
23
|
* Define properties on an object or function
|
|
24
24
|
* @name module:@lumjs/core.def
|
|
25
|
+
* @function
|
|
25
26
|
* @see module:@lumjs/core/types.def
|
|
26
27
|
*/
|
|
27
28
|
const def = types.def;
|
|
@@ -29,6 +30,7 @@ const def = types.def;
|
|
|
29
30
|
/**
|
|
30
31
|
* Define *lazy* properties on an object or function
|
|
31
32
|
* @alias module:@lumjs/core.lazy
|
|
33
|
+
* @function
|
|
32
34
|
* @see module:@lumjs/core/types.lazy
|
|
33
35
|
*/
|
|
34
36
|
const lazy = types.lazy;
|
|
@@ -80,7 +82,7 @@ lazy(exports, 'flags', () => require('./flags'));
|
|
|
80
82
|
lazy(exports, 'obj', () => require('./obj'));
|
|
81
83
|
|
|
82
84
|
/**
|
|
83
|
-
* A wrapper around the Javascript console
|
|
85
|
+
* A wrapper around the Javascript console «Lazy»
|
|
84
86
|
* @name module:@lumjs/core.console
|
|
85
87
|
* @type {module:@lumjs/core/console}
|
|
86
88
|
*/
|
|
@@ -138,7 +140,20 @@ from(require('./objectid'));
|
|
|
138
140
|
* @see module:@lumjs/core/meta.NYI
|
|
139
141
|
*/
|
|
140
142
|
|
|
141
|
-
|
|
143
|
+
/**
|
|
144
|
+
* A function indicating that something is deprecated
|
|
145
|
+
* @name module:@lumjs/core.deprecated
|
|
146
|
+
* @function
|
|
147
|
+
* @see module:@lumjs/core/meta.deprecated
|
|
148
|
+
*/
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Assign a getter property to an object that calls the `deprecated`
|
|
152
|
+
* function with a specific message before returning the proxied value.
|
|
153
|
+
* @name module:@lumjs/core.wrapDepr
|
|
154
|
+
* @function
|
|
155
|
+
* @see module:@lumjs/core/meta.wrapDepre
|
|
156
|
+
*/
|
|
142
157
|
|
|
143
158
|
// These are exported directly, but a meta sub-module also exists.
|
|
144
159
|
// Unlike most sub-modules there is no `meta` property in the main library.
|
|
@@ -165,3 +180,9 @@ lazy(exports, 'Enum', () => require('./enum'));
|
|
|
165
180
|
*/
|
|
166
181
|
lazy(exports, 'observable', () => require('./observable'));
|
|
167
182
|
|
|
183
|
+
/**
|
|
184
|
+
* The Events module «Lazy»
|
|
185
|
+
* @name module:@lumjs/core.events
|
|
186
|
+
* @see module:@lumjs/core/events
|
|
187
|
+
*/
|
|
188
|
+
lazy(exports, 'events', () => require('./events'));
|
package/lib/meta.js
CHANGED
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Meta-programming helpers
|
|
4
|
+
*
|
|
5
|
+
* All of the function exported by this module are also available
|
|
6
|
+
* in the main {@link module:@lumjs/core core object} itself.
|
|
7
|
+
*
|
|
8
|
+
* @module @lumjs/core/meta
|
|
9
|
+
*/
|
|
2
10
|
|
|
3
11
|
const {F} = require('./types/js');
|
|
4
12
|
|
|
@@ -13,7 +21,7 @@ const {F} = require('./types/js');
|
|
|
13
21
|
* @param {string} [msg] - A message for the Error object.
|
|
14
22
|
*
|
|
15
23
|
* @returns {string[]} An array of stack strings.
|
|
16
|
-
* @alias module:@lumjs/core.stacktrace
|
|
24
|
+
* @alias module:@lumjs/core/meta.stacktrace
|
|
17
25
|
*/
|
|
18
26
|
function stacktrace(msg)
|
|
19
27
|
{
|
|
@@ -50,7 +58,7 @@ exports.stacktrace = stacktrace;
|
|
|
50
58
|
* }
|
|
51
59
|
* ```
|
|
52
60
|
*
|
|
53
|
-
* @alias module:@lumjs/core.AbstractError
|
|
61
|
+
* @alias module:@lumjs/core/meta.AbstractError
|
|
54
62
|
*/
|
|
55
63
|
class AbstractError extends Error
|
|
56
64
|
{
|
|
@@ -82,8 +90,7 @@ exports.AbstractError = AbstractError;
|
|
|
82
90
|
|
|
83
91
|
/**
|
|
84
92
|
* Function prototypes for async, generator, and async generator functions.
|
|
85
|
-
* @
|
|
86
|
-
* @alias module:@lumjs/core.Functions
|
|
93
|
+
* @alias module:@lumjs/core/meta.Functions
|
|
87
94
|
*/
|
|
88
95
|
const Functions =
|
|
89
96
|
{
|
|
@@ -114,7 +121,7 @@ exports.Functions = Functions;
|
|
|
114
121
|
* @param {string} [prefix=''] A prefix for the error message.
|
|
115
122
|
*
|
|
116
123
|
* @returns {void}
|
|
117
|
-
* @alias module:@lumjs/core.NYI
|
|
124
|
+
* @alias module:@lumjs/core/meta.NYI
|
|
118
125
|
*/
|
|
119
126
|
function NYI(fatal=true, prefix='')
|
|
120
127
|
{
|
|
@@ -134,7 +141,7 @@ exports.NYI = NYI;
|
|
|
134
141
|
* @param {(string|string[])} [rep] Replacement suggestion(s).
|
|
135
142
|
* @param {*} [ret] Value to return
|
|
136
143
|
* @returns {mixed} `ret`
|
|
137
|
-
* @alias module:@lumjs/core.deprecated
|
|
144
|
+
* @alias module:@lumjs/core/meta.deprecated
|
|
138
145
|
*/
|
|
139
146
|
function deprecated(dep, rep, ret)
|
|
140
147
|
{
|
|
@@ -167,6 +174,8 @@ exports.deprecated = deprecated;
|
|
|
167
174
|
* @param {object} [spec.opts] Options for `def()` to add getter with.
|
|
168
175
|
*
|
|
169
176
|
* @returns {object} `obj`
|
|
177
|
+
*
|
|
178
|
+
* @alias module:@lumjs/core/meta.wrapDepr
|
|
170
179
|
*/
|
|
171
180
|
function wrapDepr(obj,prop,spec)
|
|
172
181
|
{
|