@aegisjsproject/callback-registry 1.0.1 → 1.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/events.js CHANGED
@@ -1,121 +1,223 @@
1
1
  import { hasCallback, getCallback } from './callbacks.js';
2
2
 
3
- const EVENT_PREFIX = 'data-aegis-event-on-';
3
+ const PREFIX = 'data-aegis-event-';
4
+ const EVENT_PREFIX = PREFIX + 'on-';
4
5
  const EVENT_PREFIX_LENGTH = EVENT_PREFIX.length;
5
6
  const DATA_PREFIX = 'aegisEventOn';
6
7
  const DATA_PREFIX_LENGTH = DATA_PREFIX.length;
8
+ const signalSymbol = Symbol('aegis:signal');
9
+ const controllerSymbol = Symbol('aegis:controller');
10
+ const signalRegistry = new Map();
11
+ const controllerRegistry = new Map();
7
12
 
8
- const once = 'data-aegis-event-once',
9
- passive = 'data-aegis-event-passive',
10
- capture = 'data-aegis-event-capture';
11
-
12
- const eventAttrs = [
13
- EVENT_PREFIX + 'abort',
14
- EVENT_PREFIX + 'blur',
15
- EVENT_PREFIX + 'focus',
16
- EVENT_PREFIX + 'cancel',
17
- EVENT_PREFIX + 'auxclick',
18
- EVENT_PREFIX + 'beforeinput',
19
- EVENT_PREFIX + 'beforetoggle',
20
- EVENT_PREFIX + 'canplay',
21
- EVENT_PREFIX + 'canplaythrough',
22
- EVENT_PREFIX + 'change',
23
- EVENT_PREFIX + 'click',
24
- EVENT_PREFIX + 'close',
25
- EVENT_PREFIX + 'contextmenu',
26
- EVENT_PREFIX + 'copy',
27
- EVENT_PREFIX + 'cuechange',
28
- EVENT_PREFIX + 'cut',
29
- EVENT_PREFIX + 'dblclick',
30
- EVENT_PREFIX + 'drag',
31
- EVENT_PREFIX + 'dragend',
32
- EVENT_PREFIX + 'dragenter',
33
- EVENT_PREFIX + 'dragexit',
34
- EVENT_PREFIX + 'dragleave',
35
- EVENT_PREFIX + 'dragover',
36
- EVENT_PREFIX + 'dragstart',
37
- EVENT_PREFIX + 'drop',
38
- EVENT_PREFIX + 'durationchange',
39
- EVENT_PREFIX + 'emptied',
40
- EVENT_PREFIX + 'ended',
41
- EVENT_PREFIX + 'formdata',
42
- EVENT_PREFIX + 'input',
43
- EVENT_PREFIX + 'invalid',
44
- EVENT_PREFIX + 'keydown',
45
- EVENT_PREFIX + 'keypress',
46
- EVENT_PREFIX + 'keyup',
47
- EVENT_PREFIX + 'load',
48
- EVENT_PREFIX + 'loadeddata',
49
- EVENT_PREFIX + 'loadedmetadata',
50
- EVENT_PREFIX + 'loadstart',
51
- EVENT_PREFIX + 'mousedown',
52
- EVENT_PREFIX + 'mouseenter',
53
- EVENT_PREFIX + 'mouseleave',
54
- EVENT_PREFIX + 'mousemove',
55
- EVENT_PREFIX + 'mouseout',
56
- EVENT_PREFIX + 'mouseover',
57
- EVENT_PREFIX + 'mouseup',
58
- EVENT_PREFIX + 'wheel',
59
- EVENT_PREFIX + 'paste',
60
- EVENT_PREFIX + 'pause',
61
- EVENT_PREFIX + 'play',
62
- EVENT_PREFIX + 'playing',
63
- EVENT_PREFIX + 'progress',
64
- EVENT_PREFIX + 'ratechange',
65
- EVENT_PREFIX + 'reset',
66
- EVENT_PREFIX + 'resize',
67
- EVENT_PREFIX + 'scroll',
68
- EVENT_PREFIX + 'scrollend',
69
- EVENT_PREFIX + 'securitypolicyviolation',
70
- EVENT_PREFIX + 'seeked',
71
- EVENT_PREFIX + 'seeking',
72
- EVENT_PREFIX + 'select',
73
- EVENT_PREFIX + 'slotchange',
74
- EVENT_PREFIX + 'stalled',
75
- EVENT_PREFIX + 'submit',
76
- EVENT_PREFIX + 'suspend',
77
- EVENT_PREFIX + 'timeupdate',
78
- EVENT_PREFIX + 'volumechange',
79
- EVENT_PREFIX + 'waiting',
80
- EVENT_PREFIX + 'selectstart',
81
- EVENT_PREFIX + 'selectionchange',
82
- EVENT_PREFIX + 'toggle',
83
- EVENT_PREFIX + 'pointercancel',
84
- EVENT_PREFIX + 'pointerdown',
85
- EVENT_PREFIX + 'pointerup',
86
- EVENT_PREFIX + 'pointermove',
87
- EVENT_PREFIX + 'pointerout',
88
- EVENT_PREFIX + 'pointerover',
89
- EVENT_PREFIX + 'pointerenter',
90
- EVENT_PREFIX + 'pointerleave',
91
- EVENT_PREFIX + 'gotpointercapture',
92
- EVENT_PREFIX + 'lostpointercapture',
93
- EVENT_PREFIX + 'mozfullscreenchange',
94
- EVENT_PREFIX + 'mozfullscreenerror',
95
- EVENT_PREFIX + 'animationcancel',
96
- EVENT_PREFIX + 'animationend',
97
- EVENT_PREFIX + 'animationiteration',
98
- EVENT_PREFIX + 'animationstart',
99
- EVENT_PREFIX + 'transitioncancel',
100
- EVENT_PREFIX + 'transitionend',
101
- EVENT_PREFIX + 'transitionrun',
102
- EVENT_PREFIX + 'transitionstart',
103
- EVENT_PREFIX + 'webkitanimationend',
104
- EVENT_PREFIX + 'webkitanimationiteration',
105
- EVENT_PREFIX + 'webkitanimationstart',
106
- EVENT_PREFIX + 'webkittransitionend',
107
- EVENT_PREFIX + 'error',
13
+ export const once = PREFIX + 'once';
14
+ export const passive = PREFIX + 'passive';
15
+ export const capture = PREFIX + 'capture';
16
+ export const signal = PREFIX + 'signal';
17
+ export const controller = PREFIX + 'controller';
18
+ export const onAbort = EVENT_PREFIX + 'abort';
19
+ export const onBlur = EVENT_PREFIX + 'blur';
20
+ export const onFocus = EVENT_PREFIX + 'focus';
21
+ export const onCancel = EVENT_PREFIX + 'cancel';
22
+ export const onAuxclick = EVENT_PREFIX + 'auxclick';
23
+ export const onBeforeinput = EVENT_PREFIX + 'beforeinput';
24
+ export const onBeforetoggle = EVENT_PREFIX + 'beforetoggle';
25
+ export const onCanplay = EVENT_PREFIX + 'canplay';
26
+ export const onCanplaythrough = EVENT_PREFIX + 'canplaythrough';
27
+ export const onChange = EVENT_PREFIX + 'change';
28
+ export const onClick = EVENT_PREFIX + 'click';
29
+ export const onClose = EVENT_PREFIX + 'close';
30
+ export const onContextmenu = EVENT_PREFIX + 'contextmenu';
31
+ export const onCopy = EVENT_PREFIX + 'copy';
32
+ export const onCuechange = EVENT_PREFIX + 'cuechange';
33
+ export const onCut = EVENT_PREFIX + 'cut';
34
+ export const onDblclick = EVENT_PREFIX + 'dblclick';
35
+ export const onDrag = EVENT_PREFIX + 'drag';
36
+ export const onDragend = EVENT_PREFIX + 'dragend';
37
+ export const onDragenter = EVENT_PREFIX + 'dragenter';
38
+ export const onDragexit = EVENT_PREFIX + 'dragexit';
39
+ export const onDragleave = EVENT_PREFIX + 'dragleave';
40
+ export const onDragover = EVENT_PREFIX + 'dragover';
41
+ export const onDragstart = EVENT_PREFIX + 'dragstart';
42
+ export const onDrop = EVENT_PREFIX + 'drop';
43
+ export const onDurationchange = EVENT_PREFIX + 'durationchange';
44
+ export const onEmptied = EVENT_PREFIX + 'emptied';
45
+ export const onEnded = EVENT_PREFIX + 'ended';
46
+ export const onFormdata = EVENT_PREFIX + 'formdata';
47
+ export const onInput = EVENT_PREFIX + 'input';
48
+ export const onInvalid = EVENT_PREFIX + 'invalid';
49
+ export const onKeydown = EVENT_PREFIX + 'keydown';
50
+ export const onKeypress = EVENT_PREFIX + 'keypress';
51
+ export const onKeyup = EVENT_PREFIX + 'keyup';
52
+ export const onLoad = EVENT_PREFIX + 'load';
53
+ export const onLoadeddata = EVENT_PREFIX + 'loadeddata';
54
+ export const onLoadedmetadata = EVENT_PREFIX + 'loadedmetadata';
55
+ export const onLoadstart = EVENT_PREFIX + 'loadstart';
56
+ export const onMousedown = EVENT_PREFIX + 'mousedown';
57
+ export const onMouseenter = EVENT_PREFIX + 'mouseenter';
58
+ export const onMouseleave = EVENT_PREFIX + 'mouseleave';
59
+ export const onMousemove = EVENT_PREFIX + 'mousemove';
60
+ export const onMouseout = EVENT_PREFIX + 'mouseout';
61
+ export const onMouseover = EVENT_PREFIX + 'mouseover';
62
+ export const onMouseup = EVENT_PREFIX + 'mouseup';
63
+ export const onWheel = EVENT_PREFIX + 'wheel';
64
+ export const onPaste = EVENT_PREFIX + 'paste';
65
+ export const onPause = EVENT_PREFIX + 'pause';
66
+ export const onPlay = EVENT_PREFIX + 'play';
67
+ export const onPlaying = EVENT_PREFIX + 'playing';
68
+ export const onProgress = EVENT_PREFIX + 'progress';
69
+ export const onRatechange = EVENT_PREFIX + 'ratechange';
70
+ export const onReset = EVENT_PREFIX + 'reset';
71
+ export const onResize = EVENT_PREFIX + 'resize';
72
+ export const onScroll = EVENT_PREFIX + 'scroll';
73
+ export const onScrollend = EVENT_PREFIX + 'scrollend';
74
+ export const onSecuritypolicyviolation = EVENT_PREFIX + 'securitypolicyviolation';
75
+ export const onSeeked = EVENT_PREFIX + 'seeked';
76
+ export const onSeeking = EVENT_PREFIX + 'seeking';
77
+ export const onSelect = EVENT_PREFIX + 'select';
78
+ export const onSlotchange = EVENT_PREFIX + 'slotchange';
79
+ export const onStalled = EVENT_PREFIX + 'stalled';
80
+ export const onSubmit = EVENT_PREFIX + 'submit';
81
+ export const onSuspend = EVENT_PREFIX + 'suspend';
82
+ export const onTimeupdate = EVENT_PREFIX + 'timeupdate';
83
+ export const onVolumechange = EVENT_PREFIX + 'volumechange';
84
+ export const onWaiting = EVENT_PREFIX + 'waiting';
85
+ export const onSelectstart = EVENT_PREFIX + 'selectstart';
86
+ export const onSelectionchange = EVENT_PREFIX + 'selectionchange';
87
+ export const onToggle = EVENT_PREFIX + 'toggle';
88
+ export const onPointercancel = EVENT_PREFIX + 'pointercancel';
89
+ export const onPointerdown = EVENT_PREFIX + 'pointerdown';
90
+ export const onPointerup = EVENT_PREFIX + 'pointerup';
91
+ export const onPointermove = EVENT_PREFIX + 'pointermove';
92
+ export const onPointerout = EVENT_PREFIX + 'pointerout';
93
+ export const onPointerover = EVENT_PREFIX + 'pointerover';
94
+ export const onPointerenter = EVENT_PREFIX + 'pointerenter';
95
+ export const onPointerleave = EVENT_PREFIX + 'pointerleave';
96
+ export const onGotpointercapture = EVENT_PREFIX + 'gotpointercapture';
97
+ export const onLostpointercapture = EVENT_PREFIX + 'lostpointercapture';
98
+ export const onMozfullscreenchange = EVENT_PREFIX + 'mozfullscreenchange';
99
+ export const onMozfullscreenerror = EVENT_PREFIX + 'mozfullscreenerror';
100
+ export const onAnimationcancel = EVENT_PREFIX + 'animationcancel';
101
+ export const onAnimationend = EVENT_PREFIX + 'animationend';
102
+ export const onAnimationiteration = EVENT_PREFIX + 'animationiteration';
103
+ export const onAnimationstart = EVENT_PREFIX + 'animationstart';
104
+ export const onTransitioncancel = EVENT_PREFIX + 'transitioncancel';
105
+ export const onTransitionend = EVENT_PREFIX + 'transitionend';
106
+ export const onTransitionrun = EVENT_PREFIX + 'transitionrun';
107
+ export const onTransitionstart = EVENT_PREFIX + 'transitionstart';
108
+ export const onWebkitanimationend = EVENT_PREFIX + 'webkitanimationend';
109
+ export const onWebkitanimationiteration = EVENT_PREFIX + 'webkitanimationiteration';
110
+ export const onWebkitanimationstart = EVENT_PREFIX + 'webkitanimationstart';
111
+ export const onWebkittransitionend = EVENT_PREFIX + 'webkittransitionend';
112
+ export const onError = EVENT_PREFIX + 'error';
113
+
114
+ export const eventAttrs = [
115
+ onAbort,
116
+ onBlur,
117
+ onFocus,
118
+ onCancel,
119
+ onAuxclick,
120
+ onBeforeinput,
121
+ onBeforetoggle,
122
+ onCanplay,
123
+ onCanplaythrough,
124
+ onChange,
125
+ onClick,
126
+ onClose,
127
+ onContextmenu,
128
+ onCopy,
129
+ onCuechange,
130
+ onCut,
131
+ onDblclick,
132
+ onDrag,
133
+ onDragend,
134
+ onDragenter,
135
+ onDragexit,
136
+ onDragleave,
137
+ onDragover,
138
+ onDragstart,
139
+ onDrop,
140
+ onDurationchange,
141
+ onEmptied,
142
+ onEnded,
143
+ onFormdata,
144
+ onInput,
145
+ onInvalid,
146
+ onKeydown,
147
+ onKeypress,
148
+ onKeyup,
149
+ onLoad,
150
+ onLoadeddata,
151
+ onLoadedmetadata,
152
+ onLoadstart,
153
+ onMousedown,
154
+ onMouseenter,
155
+ onMouseleave,
156
+ onMousemove,
157
+ onMouseout,
158
+ onMouseover,
159
+ onMouseup,
160
+ onWheel,
161
+ onPaste,
162
+ onPause,
163
+ onPlay,
164
+ onPlaying,
165
+ onProgress,
166
+ onRatechange,
167
+ onReset,
168
+ onResize,
169
+ onScroll,
170
+ onScrollend,
171
+ onSecuritypolicyviolation,
172
+ onSeeked,
173
+ onSeeking,
174
+ onSelect,
175
+ onSlotchange,
176
+ onStalled,
177
+ onSubmit,
178
+ onSuspend,
179
+ onTimeupdate,
180
+ onVolumechange,
181
+ onWaiting,
182
+ onSelectstart,
183
+ onSelectionchange,
184
+ onToggle,
185
+ onPointercancel,
186
+ onPointerdown,
187
+ onPointerup,
188
+ onPointermove,
189
+ onPointerout,
190
+ onPointerover,
191
+ onPointerenter,
192
+ onPointerleave,
193
+ onGotpointercapture,
194
+ onLostpointercapture,
195
+ onMozfullscreenchange,
196
+ onMozfullscreenerror,
197
+ onAnimationcancel,
198
+ onAnimationend,
199
+ onAnimationiteration,
200
+ onAnimationstart,
201
+ onTransitioncancel,
202
+ onTransitionend,
203
+ onTransitionrun,
204
+ onTransitionstart,
205
+ onWebkitanimationend,
206
+ onWebkitanimationiteration,
207
+ onWebkitanimationstart,
208
+ onWebkittransitionend,
209
+ onError,
108
210
  ];
109
211
 
110
212
  let selector = eventAttrs.map(attr => `[${CSS.escape(attr)}]`).join(', ');
111
213
 
112
214
  const attrToProp = attr => `on${attr[EVENT_PREFIX_LENGTH].toUpperCase()}${attr.substring(EVENT_PREFIX_LENGTH + 1)}`;
113
215
 
114
- const attrEntriesMap = attr => [attrToProp(attr), attr];
216
+ export const eventToProp = event => EVENT_PREFIX + event;
115
217
 
116
- const isEventDataAttr = ([name]) => name.startsWith(DATA_PREFIX);
218
+ export const hasEventAttribute = event => eventAttrs.includes(EVENT_PREFIX + event);
117
219
 
118
- const DATA_EVENTS = Object.fromEntries([...eventAttrs].map(attrEntriesMap));
220
+ const isEventDataAttr = ([name]) => name.startsWith(DATA_PREFIX);
119
221
 
120
222
  function _addListeners(el, { signal, attrFilter = EVENTS } = {}) {
121
223
  const dataset = el.dataset;
@@ -129,11 +231,11 @@ function _addListeners(el, { signal, attrFilter = EVENTS } = {}) {
129
231
  passive: dataset.hasOwnProperty('aegisEventPassive'),
130
232
  capture: dataset.hasOwnProperty('aegisEventCapture'),
131
233
  once: dataset.hasOwnProperty('aegisEventOnce'),
132
- signal,
234
+ signal: dataset.hasOwnProperty('aegisEventSignal') ? getSignal(dataset.aegisEventSignal) : signal,
133
235
  });
134
236
  }
135
237
  } catch(err) {
136
- console.error(err);
238
+ reportError(err);
137
239
  }
138
240
  }
139
241
  }
@@ -169,6 +271,7 @@ const observer = new MutationObserver(records => {
169
271
  once: record.target.hasAttribute(once),
170
272
  capture: record.target.hasAttribute(capture),
171
273
  passive: record.target.hasAttribute(passive),
274
+ signal: record.target.hasAttribute(signal) ? getSignal(record.target.getAttribute(signal)) : undefined,
172
275
  }
173
276
  );
174
277
  }
@@ -177,7 +280,106 @@ const observer = new MutationObserver(records => {
177
280
  });
178
281
  });
179
282
 
180
- export const EVENTS = { ...DATA_EVENTS, once, passive, capture };
283
+ export const EVENTS = {
284
+ onAbort,
285
+ onBlur,
286
+ onFocus,
287
+ onCancel,
288
+ onAuxclick,
289
+ onBeforeinput,
290
+ onBeforetoggle,
291
+ onCanplay,
292
+ onCanplaythrough,
293
+ onChange,
294
+ onClick,
295
+ onClose,
296
+ onContextmenu,
297
+ onCopy,
298
+ onCuechange,
299
+ onCut,
300
+ onDblclick,
301
+ onDrag,
302
+ onDragend,
303
+ onDragenter,
304
+ onDragexit,
305
+ onDragleave,
306
+ onDragover,
307
+ onDragstart,
308
+ onDrop,
309
+ onDurationchange,
310
+ onEmptied,
311
+ onEnded,
312
+ onFormdata,
313
+ onInput,
314
+ onInvalid,
315
+ onKeydown,
316
+ onKeypress,
317
+ onKeyup,
318
+ onLoad,
319
+ onLoadeddata,
320
+ onLoadedmetadata,
321
+ onLoadstart,
322
+ onMousedown,
323
+ onMouseenter,
324
+ onMouseleave,
325
+ onMousemove,
326
+ onMouseout,
327
+ onMouseover,
328
+ onMouseup,
329
+ onWheel,
330
+ onPaste,
331
+ onPause,
332
+ onPlay,
333
+ onPlaying,
334
+ onProgress,
335
+ onRatechange,
336
+ onReset,
337
+ onResize,
338
+ onScroll,
339
+ onScrollend,
340
+ onSecuritypolicyviolation,
341
+ onSeeked,
342
+ onSeeking,
343
+ onSelect,
344
+ onSlotchange,
345
+ onStalled,
346
+ onSubmit,
347
+ onSuspend,
348
+ onTimeupdate,
349
+ onVolumechange,
350
+ onWaiting,
351
+ onSelectstart,
352
+ onSelectionchange,
353
+ onToggle,
354
+ onPointercancel,
355
+ onPointerdown,
356
+ onPointerup,
357
+ onPointermove,
358
+ onPointerout,
359
+ onPointerover,
360
+ onPointerenter,
361
+ onPointerleave,
362
+ onGotpointercapture,
363
+ onLostpointercapture,
364
+ onMozfullscreenchange,
365
+ onMozfullscreenerror,
366
+ onAnimationcancel,
367
+ onAnimationend,
368
+ onAnimationiteration,
369
+ onAnimationstart,
370
+ onTransitioncancel,
371
+ onTransitionend,
372
+ onTransitionrun,
373
+ onTransitionstart,
374
+ onWebkitanimationend,
375
+ onWebkitanimationiteration,
376
+ onWebkitanimationstart,
377
+ onWebkittransitionend,
378
+ onError,
379
+ once,
380
+ passive,
381
+ capture,
382
+ };
181
383
 
182
384
  /**
183
385
  * Register an attribute to observe for adding/removing event listeners
@@ -214,6 +416,134 @@ export function registerEventAttribute(attr, {
214
416
  return fullAttr;
215
417
  }
216
418
 
419
+ /**
420
+ * Registers an `AbortController` in the controller registry and returns the key for it
421
+ *
422
+ * @param {AbortController} controller
423
+ * @returns {string} The randomly generated key with which the controller is registered
424
+ * @throws {TypeError} If controller is not an `AbortController`
425
+ * @throws {Error} Any `reason` if controller is already aborted
426
+ */
427
+ export function registerController(controller) {
428
+ if (! (controller instanceof AbortController)) {
429
+ throw new TypeError('Controller is not an `AbortSignal.');
430
+ } else if (controller.signal.aborted) {
431
+ throw controller.signal.reason;
432
+ } else if (typeof controller.signal[controllerSymbol] === 'string') {
433
+ return controller.signal[controllerSymbol];
434
+ } else {
435
+ const key = 'aegis:event:controller:' + crypto.randomUUID();
436
+ Object.defineProperty(controller.signal, controllerSymbol, { value: key, writable: false, enumerable: false });
437
+ controllerRegistry.set(key, controller);
438
+
439
+ controller.signal.addEventListener('abort', unregisterController, { once: true });
440
+
441
+ return key;
442
+ }
443
+ }
444
+
445
+ /**
446
+ * Removes a controller from the registry
447
+ *
448
+ * @param {AbortController|AbortSignal|string} key The registed key or the controller or signal it corresponds to
449
+ * @returns {boolean} Whether or not the controller was successfully unregistered
450
+ */
451
+ export function unregisterController(key) {
452
+ if (key instanceof AbortController) {
453
+ return controllerRegistry.delete(key.signal[controllerSymbol]);
454
+ } else if (key instanceof AbortSignal) {
455
+ return controllerRegistry.delete(key[controllerSymbol]);
456
+ } else {
457
+ return controllerRegistry.delete(key);
458
+ }
459
+ }
460
+
461
+ /**
462
+ * Creates and registers an `AbortController` in the controller registry and returns the key for it
463
+ *
464
+ * @param {object} options
465
+ * @param {AbortSignal} [options.signal] An optional `AbortSignal` to externally abort the controller with
466
+ * @returns {string} The randomly generated key with which the controller is registered
467
+ */
468
+ export function createController({ signal } = {}) {
469
+ const controller = new AbortController();
470
+
471
+ if (signal instanceof AbortSignal) {
472
+ signal.addEventListener('abort', ({ target }) => controller.abort(target.reason), { signal: controller.signal});
473
+ }
474
+
475
+ return registerController(controller);
476
+ }
477
+
478
+ /**
479
+ * Get a registetd controller from the registry
480
+ *
481
+ * @param {string} key Generated key with which the controller was registered
482
+ * @returns {AbortController|void} Any registered controller, if any
483
+ */
484
+ export const getController = key => controllerRegistry.get(key);
485
+
486
+ export function abortController(key, reason) {
487
+ const controller = getController(key);
488
+
489
+ if (! (controller instanceof AbortController)) {
490
+ return false;
491
+ } else if (typeof reason === 'string') {
492
+ controller.abort(new Error(reason));
493
+ return true;
494
+ } else {
495
+ controller.abort(reason);
496
+ return true;
497
+ }
498
+ }
499
+
500
+ /**
501
+ * Register an `AbortSignal` to be used in declarative HTML as a value for `data-aegis-event-signal`
502
+ *
503
+ * @param {AbortSignal} signal The signal to register
504
+ * @returns {string} The registered key
505
+ * @throws {TypeError} Thrown if not an `AbortSignal`
506
+ */
507
+ export function registerSignal(signal) {
508
+ if (! (signal instanceof AbortSignal)) {
509
+ throw new TypeError('Signal must be an `AbortSignal`.');
510
+ } else if (typeof signal[signalSymbol] === 'string') {
511
+ return signal[signalSymbol];
512
+ } else {
513
+ const key = 'aegis:event:signal:' + crypto.randomUUID();
514
+ Object.defineProperty(signal, signalSymbol, { value: key, writable: false, enumerable: false });
515
+ signalRegistry.set(key, signal);
516
+ signal.addEventListener('abort', ({ target }) => unregisterSignal(target[signalSymbol]), { once: true });
517
+
518
+ return key;
519
+ }
520
+ }
521
+
522
+ /**
523
+ * Gets and `AbortSignal` from the registry
524
+ *
525
+ * @param {string} key The registered key for the signal
526
+ * @returns {AbortSignal|void} The corresponding `AbortSignal`, if any
527
+ */
528
+ export const getSignal = key => signalRegistry.get(key);
529
+
530
+ /**
531
+ * Removes an `AbortSignal` from the registry
532
+ *
533
+ * @param {AbortSignal|string} signal An `AbortSignal` or the registered key for one
534
+ * @returns {boolean} Whether or not the signal was sucessfully unregistered
535
+ * @throws {TypeError} Throws if `signal` is not an `AbortSignal` or the key for a registered signal
536
+ */
537
+ export function unregisterSignal(signal) {
538
+ if (signal instanceof AbortSignal) {
539
+ return signalRegistry.delete(signal[signalSymbol]);
540
+ } else if (typeof signal === 'string') {
541
+ return signalRegistry.delete(signal);
542
+ } else {
543
+ throw new TypeError('Signal must be an `AbortSignal` or registered key/attribute.');
544
+ }
545
+ }
546
+
217
547
  /**
218
548
  * Add listeners to an element and its children, matching a generated query based on registered attributes
219
549
  *
@@ -231,6 +561,7 @@ export function attachListeners(target, { signal } = {}) {
231
561
 
232
562
  return target;
233
563
  }
564
+
234
565
  /**
235
566
  * Add a node to the `MutationObserver` to observe attributes and add/remove event listeners
236
567
  *
@@ -238,6 +569,7 @@ export function attachListeners(target, { signal } = {}) {
238
569
  */
239
570
  export function observeEvents(root = document) {
240
571
  attachListeners(root);
572
+
241
573
  observer.observe(root, {
242
574
  subtree: true,
243
575
  childList:true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aegisjsproject/callback-registry",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": " A callback registry for AegisJSProject",
5
5
  "keywords": [
6
6
  "aegis",
@@ -40,12 +40,13 @@
40
40
  "private": false,
41
41
  "scripts": {
42
42
  "test": "npm run lint:js && npm run run:tests",
43
+ "start": "http-server ./ -c-1 --port 8080 --gzip true --brotli true -a localhost -o /test/",
43
44
  "preversion": "npm test && npm run build",
44
45
  "prepare": "npm test && npm run build",
45
46
  "lint:js": "eslint .",
46
47
  "fix:js": "eslint . --fix",
47
48
  "build": "npm run build:js",
48
- "run:tests": "node --test",
49
+ "run:tests": "node --test *.test.js",
49
50
  "clean": "rm -f ./*.cjs",
50
51
  "build:js": "npm run clean && rollup -c rollup.config.js",
51
52
  "create:lock": "npm i --package-lock-only --ignore-scripts --no-audit --no-fund",
@@ -78,6 +79,7 @@
78
79
  "@rollup/plugin-terser": "^0.4.4",
79
80
  "@shgysk8zer0/eslint-config": "^1.0.1",
80
81
  "eslint": "^9.15.0",
82
+ "http-server": "^14.1.1",
81
83
  "rollup": "^4.27.2"
82
84
  }
83
85
  }