UNPKG

37.7 kBJavaScriptView Raw
1/**
2 * Assert a condition.
3 * @param condition The condition that it should satisfy.
4 * @param message The error message.
5 * @param args The arguments for replacing placeholders in the message.
6 */
7function assertType(condition, message, ...args) {
8 if (!condition) {
9 throw new TypeError(format(message, args));
10 }
11}
12/**
13 * Convert a text and arguments to one string.
14 * @param message The formating text
15 * @param args The arguments.
16 */
17function format(message, args) {
18 let i = 0;
19 return message.replace(/%[os]/gu, () => anyToString(args[i++]));
20}
21/**
22 * Convert a value to a string representation.
23 * @param x The value to get the string representation.
24 */
25function anyToString(x) {
26 if (typeof x !== "object" || x === null) {
27 return String(x);
28 }
29 return Object.prototype.toString.call(x);
30}
31
32let currentErrorHandler;
33/**
34 * Set the error handler.
35 * @param value The error handler to set.
36 */
37function setErrorHandler(value) {
38 assertType(typeof value === "function" || value === undefined, "The error handler must be a function or undefined, but got %o.", value);
39 currentErrorHandler = value;
40}
41/**
42 * Print a error message.
43 * @param maybeError The error object.
44 */
45function reportError(maybeError) {
46 try {
47 const error = maybeError instanceof Error
48 ? maybeError
49 : new Error(anyToString(maybeError));
50 // Call the user-defined error handler if exists.
51 if (currentErrorHandler) {
52 currentErrorHandler(error);
53 return;
54 }
55 // Dispatch an `error` event if this is on a browser.
56 if (typeof dispatchEvent === "function" &&
57 typeof ErrorEvent === "function") {
58 dispatchEvent(new ErrorEvent("error", { error, message: error.message }));
59 }
60 // Emit an `uncaughtException` event if this is on Node.js.
61 //istanbul ignore else
62 else if (typeof process !== "undefined" &&
63 typeof process.emit === "function") {
64 process.emit("uncaughtException", error);
65 return;
66 }
67 // Otherwise, print the error.
68 console.error(error);
69 }
70 catch (_a) {
71 // ignore.
72 }
73}
74
75/**
76 * The global object.
77 */
78//istanbul ignore next
79const Global = typeof window !== "undefined"
80 ? window
81 : typeof self !== "undefined"
82 ? self
83 : typeof global !== "undefined"
84 ? global
85 : typeof globalThis !== "undefined"
86 ? globalThis
87 : undefined;
88
89let currentWarnHandler;
90/**
91 * Set the warning handler.
92 * @param value The warning handler to set.
93 */
94function setWarningHandler(value) {
95 assertType(typeof value === "function" || value === undefined, "The warning handler must be a function or undefined, but got %o.", value);
96 currentWarnHandler = value;
97}
98/**
99 * The warning information.
100 */
101class Warning {
102 constructor(code, message) {
103 this.code = code;
104 this.message = message;
105 }
106 /**
107 * Report this warning.
108 * @param args The arguments of the warning.
109 */
110 warn(...args) {
111 var _a;
112 try {
113 // Call the user-defined warning handler if exists.
114 if (currentWarnHandler) {
115 currentWarnHandler({ ...this, args });
116 return;
117 }
118 // Otherwise, print the warning.
119 const stack = ((_a = new Error().stack) !== null && _a !== void 0 ? _a : "").replace(/^(?:.+?\n){2}/gu, "\n");
120 console.warn(this.message, ...args, stack);
121 }
122 catch (_b) {
123 // Ignore.
124 }
125 }
126}
127
128const InitEventWasCalledWhileDispatching = new Warning("W01", "Unable to initialize event under dispatching.");
129const FalsyWasAssignedToCancelBubble = new Warning("W02", "Assigning any falsy value to 'cancelBubble' property has no effect.");
130const TruthyWasAssignedToReturnValue = new Warning("W03", "Assigning any truthy value to 'returnValue' property has no effect.");
131const NonCancelableEventWasCanceled = new Warning("W04", "Unable to preventDefault on non-cancelable events.");
132const CanceledInPassiveListener = new Warning("W05", "Unable to preventDefault inside passive event listener invocation.");
133const EventListenerWasDuplicated = new Warning("W06", "An event listener wasn't added because it has been added already: %o, %o");
134const OptionWasIgnored = new Warning("W07", "The %o option value was abandoned because the event listener wasn't added as duplicated.");
135const InvalidEventListener = new Warning("W08", "The 'callback' argument must be a function or an object that has 'handleEvent' method: %o");
136const InvalidAttributeHandler = new Warning("W09", "Event attribute handler must be a function: %o");
137
138/*eslint-disable class-methods-use-this */
139/**
140 * An implementation of `Event` interface, that wraps a given event object.
141 * `EventTarget` shim can control the internal state of this `Event` objects.
142 * @see https://dom.spec.whatwg.org/#event
143 */
144class Event {
145 /**
146 * @see https://dom.spec.whatwg.org/#dom-event-none
147 */
148 static get NONE() {
149 return NONE;
150 }
151 /**
152 * @see https://dom.spec.whatwg.org/#dom-event-capturing_phase
153 */
154 static get CAPTURING_PHASE() {
155 return CAPTURING_PHASE;
156 }
157 /**
158 * @see https://dom.spec.whatwg.org/#dom-event-at_target
159 */
160 static get AT_TARGET() {
161 return AT_TARGET;
162 }
163 /**
164 * @see https://dom.spec.whatwg.org/#dom-event-bubbling_phase
165 */
166 static get BUBBLING_PHASE() {
167 return BUBBLING_PHASE;
168 }
169 /**
170 * Initialize this event instance.
171 * @param type The type of this event.
172 * @param eventInitDict Options to initialize.
173 * @see https://dom.spec.whatwg.org/#dom-event-event
174 */
175 constructor(type, eventInitDict) {
176 Object.defineProperty(this, "isTrusted", {
177 value: false,
178 enumerable: true,
179 });
180 const opts = eventInitDict !== null && eventInitDict !== void 0 ? eventInitDict : {};
181 internalDataMap.set(this, {
182 type: String(type),
183 bubbles: Boolean(opts.bubbles),
184 cancelable: Boolean(opts.cancelable),
185 composed: Boolean(opts.composed),
186 target: null,
187 currentTarget: null,
188 stopPropagationFlag: false,
189 stopImmediatePropagationFlag: false,
190 canceledFlag: false,
191 inPassiveListenerFlag: false,
192 dispatchFlag: false,
193 timeStamp: Date.now(),
194 });
195 }
196 /**
197 * The type of this event.
198 * @see https://dom.spec.whatwg.org/#dom-event-type
199 */
200 get type() {
201 return $(this).type;
202 }
203 /**
204 * The event target of the current dispatching.
205 * @see https://dom.spec.whatwg.org/#dom-event-target
206 */
207 get target() {
208 return $(this).target;
209 }
210 /**
211 * The event target of the current dispatching.
212 * @deprecated Use the `target` property instead.
213 * @see https://dom.spec.whatwg.org/#dom-event-srcelement
214 */
215 get srcElement() {
216 return $(this).target;
217 }
218 /**
219 * The event target of the current dispatching.
220 * @see https://dom.spec.whatwg.org/#dom-event-currenttarget
221 */
222 get currentTarget() {
223 return $(this).currentTarget;
224 }
225 /**
226 * The event target of the current dispatching.
227 * This doesn't support node tree.
228 * @see https://dom.spec.whatwg.org/#dom-event-composedpath
229 */
230 composedPath() {
231 const currentTarget = $(this).currentTarget;
232 if (currentTarget) {
233 return [currentTarget];
234 }
235 return [];
236 }
237 /**
238 * @see https://dom.spec.whatwg.org/#dom-event-none
239 */
240 get NONE() {
241 return NONE;
242 }
243 /**
244 * @see https://dom.spec.whatwg.org/#dom-event-capturing_phase
245 */
246 get CAPTURING_PHASE() {
247 return CAPTURING_PHASE;
248 }
249 /**
250 * @see https://dom.spec.whatwg.org/#dom-event-at_target
251 */
252 get AT_TARGET() {
253 return AT_TARGET;
254 }
255 /**
256 * @see https://dom.spec.whatwg.org/#dom-event-bubbling_phase
257 */
258 get BUBBLING_PHASE() {
259 return BUBBLING_PHASE;
260 }
261 /**
262 * The current event phase.
263 * @see https://dom.spec.whatwg.org/#dom-event-eventphase
264 */
265 get eventPhase() {
266 return $(this).dispatchFlag ? 2 : 0;
267 }
268 /**
269 * Stop event bubbling.
270 * Because this shim doesn't support node tree, this merely changes the `cancelBubble` property value.
271 * @see https://dom.spec.whatwg.org/#dom-event-stoppropagation
272 */
273 stopPropagation() {
274 $(this).stopPropagationFlag = true;
275 }
276 /**
277 * `true` if event bubbling was stopped.
278 * @deprecated
279 * @see https://dom.spec.whatwg.org/#dom-event-cancelbubble
280 */
281 get cancelBubble() {
282 return $(this).stopPropagationFlag;
283 }
284 /**
285 * Stop event bubbling if `true` is set.
286 * @deprecated Use the `stopPropagation()` method instead.
287 * @see https://dom.spec.whatwg.org/#dom-event-cancelbubble
288 */
289 set cancelBubble(value) {
290 if (value) {
291 $(this).stopPropagationFlag = true;
292 }
293 else {
294 FalsyWasAssignedToCancelBubble.warn();
295 }
296 }
297 /**
298 * Stop event bubbling and subsequent event listener callings.
299 * @see https://dom.spec.whatwg.org/#dom-event-stopimmediatepropagation
300 */
301 stopImmediatePropagation() {
302 const data = $(this);
303 data.stopPropagationFlag = data.stopImmediatePropagationFlag = true;
304 }
305 /**
306 * `true` if this event will bubble.
307 * @see https://dom.spec.whatwg.org/#dom-event-bubbles
308 */
309 get bubbles() {
310 return $(this).bubbles;
311 }
312 /**
313 * `true` if this event can be canceled by the `preventDefault()` method.
314 * @see https://dom.spec.whatwg.org/#dom-event-cancelable
315 */
316 get cancelable() {
317 return $(this).cancelable;
318 }
319 /**
320 * `true` if the default behavior will act.
321 * @deprecated Use the `defaultPrevented` proeprty instead.
322 * @see https://dom.spec.whatwg.org/#dom-event-returnvalue
323 */
324 get returnValue() {
325 return !$(this).canceledFlag;
326 }
327 /**
328 * Cancel the default behavior if `false` is set.
329 * @deprecated Use the `preventDefault()` method instead.
330 * @see https://dom.spec.whatwg.org/#dom-event-returnvalue
331 */
332 set returnValue(value) {
333 if (!value) {
334 setCancelFlag($(this));
335 }
336 else {
337 TruthyWasAssignedToReturnValue.warn();
338 }
339 }
340 /**
341 * Cancel the default behavior.
342 * @see https://dom.spec.whatwg.org/#dom-event-preventdefault
343 */
344 preventDefault() {
345 setCancelFlag($(this));
346 }
347 /**
348 * `true` if the default behavior was canceled.
349 * @see https://dom.spec.whatwg.org/#dom-event-defaultprevented
350 */
351 get defaultPrevented() {
352 return $(this).canceledFlag;
353 }
354 /**
355 * @see https://dom.spec.whatwg.org/#dom-event-composed
356 */
357 get composed() {
358 return $(this).composed;
359 }
360 /**
361 * @see https://dom.spec.whatwg.org/#dom-event-istrusted
362 */
363 //istanbul ignore next
364 get isTrusted() {
365 return false;
366 }
367 /**
368 * @see https://dom.spec.whatwg.org/#dom-event-timestamp
369 */
370 get timeStamp() {
371 return $(this).timeStamp;
372 }
373 /**
374 * @deprecated Don't use this method. The constructor did initialization.
375 */
376 initEvent(type, bubbles = false, cancelable = false) {
377 const data = $(this);
378 if (data.dispatchFlag) {
379 InitEventWasCalledWhileDispatching.warn();
380 return;
381 }
382 internalDataMap.set(this, {
383 ...data,
384 type: String(type),
385 bubbles: Boolean(bubbles),
386 cancelable: Boolean(cancelable),
387 target: null,
388 currentTarget: null,
389 stopPropagationFlag: false,
390 stopImmediatePropagationFlag: false,
391 canceledFlag: false,
392 });
393 }
394}
395//------------------------------------------------------------------------------
396// Helpers
397//------------------------------------------------------------------------------
398const NONE = 0;
399const CAPTURING_PHASE = 1;
400const AT_TARGET = 2;
401const BUBBLING_PHASE = 3;
402/**
403 * Private data for event wrappers.
404 */
405const internalDataMap = new WeakMap();
406/**
407 * Get private data.
408 * @param event The event object to get private data.
409 * @param name The variable name to report.
410 * @returns The private data of the event.
411 */
412function $(event, name = "this") {
413 const retv = internalDataMap.get(event);
414 assertType(retv != null, "'%s' must be an object that Event constructor created, but got another one: %o", name, event);
415 return retv;
416}
417/**
418 * https://dom.spec.whatwg.org/#set-the-canceled-flag
419 * @param data private data.
420 */
421function setCancelFlag(data) {
422 if (data.inPassiveListenerFlag) {
423 CanceledInPassiveListener.warn();
424 return;
425 }
426 if (!data.cancelable) {
427 NonCancelableEventWasCanceled.warn();
428 return;
429 }
430 data.canceledFlag = true;
431}
432// Set enumerable
433Object.defineProperty(Event, "NONE", { enumerable: true });
434Object.defineProperty(Event, "CAPTURING_PHASE", { enumerable: true });
435Object.defineProperty(Event, "AT_TARGET", { enumerable: true });
436Object.defineProperty(Event, "BUBBLING_PHASE", { enumerable: true });
437const keys = Object.getOwnPropertyNames(Event.prototype);
438for (let i = 0; i < keys.length; ++i) {
439 if (keys[i] === "constructor") {
440 continue;
441 }
442 Object.defineProperty(Event.prototype, keys[i], { enumerable: true });
443}
444// Ensure `event instanceof window.Event` is `true`.
445if (typeof Global !== "undefined" && typeof Global.Event !== "undefined") {
446 Object.setPrototypeOf(Event.prototype, Global.Event.prototype);
447}
448
449/**
450 * Create a new InvalidStateError instance.
451 * @param message The error message.
452 */
453function createInvalidStateError(message) {
454 if (Global.DOMException) {
455 return new Global.DOMException(message, "InvalidStateError");
456 }
457 if (DOMException == null) {
458 DOMException = class DOMException extends Error {
459 constructor(msg) {
460 super(msg);
461 if (Error.captureStackTrace) {
462 Error.captureStackTrace(this, DOMException);
463 }
464 }
465 // eslint-disable-next-line class-methods-use-this
466 get code() {
467 return 11;
468 }
469 // eslint-disable-next-line class-methods-use-this
470 get name() {
471 return "InvalidStateError";
472 }
473 };
474 Object.defineProperties(DOMException.prototype, {
475 code: { enumerable: true },
476 name: { enumerable: true },
477 });
478 defineErrorCodeProperties(DOMException);
479 defineErrorCodeProperties(DOMException.prototype);
480 }
481 return new DOMException(message);
482}
483//------------------------------------------------------------------------------
484// Helpers
485//------------------------------------------------------------------------------
486let DOMException;
487const ErrorCodeMap = {
488 INDEX_SIZE_ERR: 1,
489 DOMSTRING_SIZE_ERR: 2,
490 HIERARCHY_REQUEST_ERR: 3,
491 WRONG_DOCUMENT_ERR: 4,
492 INVALID_CHARACTER_ERR: 5,
493 NO_DATA_ALLOWED_ERR: 6,
494 NO_MODIFICATION_ALLOWED_ERR: 7,
495 NOT_FOUND_ERR: 8,
496 NOT_SUPPORTED_ERR: 9,
497 INUSE_ATTRIBUTE_ERR: 10,
498 INVALID_STATE_ERR: 11,
499 SYNTAX_ERR: 12,
500 INVALID_MODIFICATION_ERR: 13,
501 NAMESPACE_ERR: 14,
502 INVALID_ACCESS_ERR: 15,
503 VALIDATION_ERR: 16,
504 TYPE_MISMATCH_ERR: 17,
505 SECURITY_ERR: 18,
506 NETWORK_ERR: 19,
507 ABORT_ERR: 20,
508 URL_MISMATCH_ERR: 21,
509 QUOTA_EXCEEDED_ERR: 22,
510 TIMEOUT_ERR: 23,
511 INVALID_NODE_TYPE_ERR: 24,
512 DATA_CLONE_ERR: 25,
513};
514function defineErrorCodeProperties(obj) {
515 const keys = Object.keys(ErrorCodeMap);
516 for (let i = 0; i < keys.length; ++i) {
517 const key = keys[i];
518 const value = ErrorCodeMap[key];
519 Object.defineProperty(obj, key, {
520 get() {
521 return value;
522 },
523 configurable: true,
524 enumerable: true,
525 });
526 }
527}
528
529/**
530 * An implementation of `Event` interface, that wraps a given event object.
531 * This class controls the internal state of `Event`.
532 * @see https://dom.spec.whatwg.org/#interface-event
533 */
534class EventWrapper extends Event {
535 /**
536 * Wrap a given event object to control states.
537 * @param event The event-like object to wrap.
538 */
539 static wrap(event) {
540 return new (getWrapperClassOf(event))(event);
541 }
542 constructor(event) {
543 super(event.type, {
544 bubbles: event.bubbles,
545 cancelable: event.cancelable,
546 composed: event.composed,
547 });
548 if (event.cancelBubble) {
549 super.stopPropagation();
550 }
551 if (event.defaultPrevented) {
552 super.preventDefault();
553 }
554 internalDataMap$1.set(this, { original: event });
555 // Define accessors
556 const keys = Object.keys(event);
557 for (let i = 0; i < keys.length; ++i) {
558 const key = keys[i];
559 if (!(key in this)) {
560 Object.defineProperty(this, key, defineRedirectDescriptor(event, key));
561 }
562 }
563 }
564 stopPropagation() {
565 super.stopPropagation();
566 const { original } = $$1(this);
567 if ("stopPropagation" in original) {
568 original.stopPropagation();
569 }
570 }
571 get cancelBubble() {
572 return super.cancelBubble;
573 }
574 set cancelBubble(value) {
575 super.cancelBubble = value;
576 const { original } = $$1(this);
577 if ("cancelBubble" in original) {
578 original.cancelBubble = value;
579 }
580 }
581 stopImmediatePropagation() {
582 super.stopImmediatePropagation();
583 const { original } = $$1(this);
584 if ("stopImmediatePropagation" in original) {
585 original.stopImmediatePropagation();
586 }
587 }
588 get returnValue() {
589 return super.returnValue;
590 }
591 set returnValue(value) {
592 super.returnValue = value;
593 const { original } = $$1(this);
594 if ("returnValue" in original) {
595 original.returnValue = value;
596 }
597 }
598 preventDefault() {
599 super.preventDefault();
600 const { original } = $$1(this);
601 if ("preventDefault" in original) {
602 original.preventDefault();
603 }
604 }
605 get timeStamp() {
606 const { original } = $$1(this);
607 if ("timeStamp" in original) {
608 return original.timeStamp;
609 }
610 return super.timeStamp;
611 }
612}
613/**
614 * Private data for event wrappers.
615 */
616const internalDataMap$1 = new WeakMap();
617/**
618 * Get private data.
619 * @param event The event object to get private data.
620 * @returns The private data of the event.
621 */
622function $$1(event) {
623 const retv = internalDataMap$1.get(event);
624 assertType(retv != null, "'this' is expected an Event object, but got", event);
625 return retv;
626}
627/**
628 * Cache for wrapper classes.
629 * @type {WeakMap<Object, Function>}
630 * @private
631 */
632const wrapperClassCache = new WeakMap();
633// Make association for wrappers.
634wrapperClassCache.set(Object.prototype, EventWrapper);
635if (typeof Global !== "undefined" && typeof Global.Event !== "undefined") {
636 wrapperClassCache.set(Global.Event.prototype, EventWrapper);
637}
638/**
639 * Get the wrapper class of a given prototype.
640 * @param originalEvent The event object to wrap.
641 */
642function getWrapperClassOf(originalEvent) {
643 const prototype = Object.getPrototypeOf(originalEvent);
644 if (prototype == null) {
645 return EventWrapper;
646 }
647 let wrapper = wrapperClassCache.get(prototype);
648 if (wrapper == null) {
649 wrapper = defineWrapper(getWrapperClassOf(prototype), prototype);
650 wrapperClassCache.set(prototype, wrapper);
651 }
652 return wrapper;
653}
654/**
655 * Define new wrapper class.
656 * @param BaseEventWrapper The base wrapper class.
657 * @param originalPrototype The prototype of the original event.
658 */
659function defineWrapper(BaseEventWrapper, originalPrototype) {
660 class CustomEventWrapper extends BaseEventWrapper {
661 }
662 const keys = Object.keys(originalPrototype);
663 for (let i = 0; i < keys.length; ++i) {
664 Object.defineProperty(CustomEventWrapper.prototype, keys[i], defineRedirectDescriptor(originalPrototype, keys[i]));
665 }
666 return CustomEventWrapper;
667}
668/**
669 * Get the property descriptor to redirect a given property.
670 */
671function defineRedirectDescriptor(obj, key) {
672 const d = Object.getOwnPropertyDescriptor(obj, key);
673 return {
674 get() {
675 const original = $$1(this).original;
676 const value = original[key];
677 if (typeof value === "function") {
678 return value.bind(original);
679 }
680 return value;
681 },
682 set(value) {
683 const original = $$1(this).original;
684 original[key] = value;
685 },
686 configurable: d.configurable,
687 enumerable: d.enumerable,
688 };
689}
690
691/**
692 * Create a new listener.
693 * @param callback The callback function.
694 * @param capture The capture flag.
695 * @param passive The passive flag.
696 * @param once The once flag.
697 * @param signal The abort signal.
698 * @param signalListener The abort event listener for the abort signal.
699 */
700function createListener(callback, capture, passive, once, signal, signalListener) {
701 return {
702 callback,
703 flags: (capture ? 1 /* Capture */ : 0) |
704 (passive ? 2 /* Passive */ : 0) |
705 (once ? 4 /* Once */ : 0),
706 signal,
707 signalListener,
708 };
709}
710/**
711 * Set the `removed` flag to the given listener.
712 * @param listener The listener to check.
713 */
714function setRemoved(listener) {
715 listener.flags |= 8 /* Removed */;
716}
717/**
718 * Check if the given listener has the `capture` flag or not.
719 * @param listener The listener to check.
720 */
721function isCapture(listener) {
722 return (listener.flags & 1 /* Capture */) === 1 /* Capture */;
723}
724/**
725 * Check if the given listener has the `passive` flag or not.
726 * @param listener The listener to check.
727 */
728function isPassive(listener) {
729 return (listener.flags & 2 /* Passive */) === 2 /* Passive */;
730}
731/**
732 * Check if the given listener has the `once` flag or not.
733 * @param listener The listener to check.
734 */
735function isOnce(listener) {
736 return (listener.flags & 4 /* Once */) === 4 /* Once */;
737}
738/**
739 * Check if the given listener has the `removed` flag or not.
740 * @param listener The listener to check.
741 */
742function isRemoved(listener) {
743 return (listener.flags & 8 /* Removed */) === 8 /* Removed */;
744}
745/**
746 * Call an event listener.
747 * @param listener The listener to call.
748 * @param target The event target object for `thisArg`.
749 * @param event The event object for the first argument.
750 * @param attribute `true` if this callback is an event attribute handler.
751 */
752function invokeCallback({ callback }, target, event) {
753 try {
754 if (typeof callback === "function") {
755 callback.call(target, event);
756 }
757 else if (typeof callback.handleEvent === "function") {
758 callback.handleEvent(event);
759 }
760 }
761 catch (thrownError) {
762 reportError(thrownError);
763 }
764}
765
766/**
767 * Find the index of given listener.
768 * This returns `-1` if not found.
769 * @param list The listener list.
770 * @param callback The callback function to find.
771 * @param capture The capture flag to find.
772 */
773function findIndexOfListener({ listeners }, callback, capture) {
774 for (let i = 0; i < listeners.length; ++i) {
775 if (listeners[i].callback === callback &&
776 isCapture(listeners[i]) === capture) {
777 return i;
778 }
779 }
780 return -1;
781}
782/**
783 * Add the given listener.
784 * Does copy-on-write if needed.
785 * @param list The listener list.
786 * @param callback The callback function.
787 * @param capture The capture flag.
788 * @param passive The passive flag.
789 * @param once The once flag.
790 * @param signal The abort signal.
791 */
792function addListener(list, callback, capture, passive, once, signal) {
793 let signalListener;
794 if (signal) {
795 signalListener = removeListener.bind(null, list, callback, capture);
796 signal.addEventListener("abort", signalListener);
797 }
798 const listener = createListener(callback, capture, passive, once, signal, signalListener);
799 if (list.cow) {
800 list.cow = false;
801 list.listeners = [...list.listeners, listener];
802 }
803 else {
804 list.listeners.push(listener);
805 }
806 return listener;
807}
808/**
809 * Remove a listener.
810 * @param list The listener list.
811 * @param callback The callback function to find.
812 * @param capture The capture flag to find.
813 * @returns `true` if it mutated the list directly.
814 */
815function removeListener(list, callback, capture) {
816 const index = findIndexOfListener(list, callback, capture);
817 if (index !== -1) {
818 return removeListenerAt(list, index);
819 }
820 return false;
821}
822/**
823 * Remove a listener.
824 * @param list The listener list.
825 * @param index The index of the target listener.
826 * @param disableCow Disable copy-on-write if true.
827 * @returns `true` if it mutated the `listeners` array directly.
828 */
829function removeListenerAt(list, index, disableCow = false) {
830 const listener = list.listeners[index];
831 // Set the removed flag.
832 setRemoved(listener);
833 // Dispose the abort signal listener if exists.
834 if (listener.signal) {
835 listener.signal.removeEventListener("abort", listener.signalListener);
836 }
837 // Remove it from the array.
838 if (list.cow && !disableCow) {
839 list.cow = false;
840 list.listeners = list.listeners.filter((_, i) => i !== index);
841 return false;
842 }
843 list.listeners.splice(index, 1);
844 return true;
845}
846
847/**
848 * Create a new `ListenerListMap` object.
849 */
850function createListenerListMap() {
851 return Object.create(null);
852}
853/**
854 * Get the listener list of the given type.
855 * If the listener list has not been initialized, initialize and return it.
856 * @param listenerMap The listener list map.
857 * @param type The event type to get.
858 */
859function ensureListenerList(listenerMap, type) {
860 var _a;
861 return ((_a = listenerMap[type]) !== null && _a !== void 0 ? _a : (listenerMap[type] = {
862 attrCallback: undefined,
863 attrListener: undefined,
864 cow: false,
865 listeners: [],
866 }));
867}
868
869/**
870 * An implementation of the `EventTarget` interface.
871 * @see https://dom.spec.whatwg.org/#eventtarget
872 */
873class EventTarget {
874 /**
875 * Initialize this instance.
876 */
877 constructor() {
878 internalDataMap$2.set(this, createListenerListMap());
879 }
880 // Implementation
881 addEventListener(type0, callback0, options0) {
882 const listenerMap = $$2(this);
883 const { callback, capture, once, passive, signal, type, } = normalizeAddOptions(type0, callback0, options0);
884 if (callback == null || (signal === null || signal === void 0 ? void 0 : signal.aborted)) {
885 return;
886 }
887 const list = ensureListenerList(listenerMap, type);
888 // Find existing listener.
889 const i = findIndexOfListener(list, callback, capture);
890 if (i !== -1) {
891 warnDuplicate(list.listeners[i], passive, once, signal);
892 return;
893 }
894 // Add the new listener.
895 addListener(list, callback, capture, passive, once, signal);
896 }
897 // Implementation
898 removeEventListener(type0, callback0, options0) {
899 const listenerMap = $$2(this);
900 const { callback, capture, type } = normalizeOptions(type0, callback0, options0);
901 const list = listenerMap[type];
902 if (callback != null && list) {
903 removeListener(list, callback, capture);
904 }
905 }
906 // Implementation
907 dispatchEvent(e) {
908 const list = $$2(this)[String(e.type)];
909 if (list == null) {
910 return true;
911 }
912 const event = e instanceof Event ? e : EventWrapper.wrap(e);
913 const eventData = $(event, "event");
914 if (eventData.dispatchFlag) {
915 throw createInvalidStateError("This event has been in dispatching.");
916 }
917 eventData.dispatchFlag = true;
918 eventData.target = eventData.currentTarget = this;
919 if (!eventData.stopPropagationFlag) {
920 const { cow, listeners } = list;
921 // Set copy-on-write flag.
922 list.cow = true;
923 // Call listeners.
924 for (let i = 0; i < listeners.length; ++i) {
925 const listener = listeners[i];
926 // Skip if removed.
927 if (isRemoved(listener)) {
928 continue;
929 }
930 // Remove this listener if has the `once` flag.
931 if (isOnce(listener) && removeListenerAt(list, i, !cow)) {
932 // Because this listener was removed, the next index is the
933 // same as the current value.
934 i -= 1;
935 }
936 // Call this listener with the `passive` flag.
937 eventData.inPassiveListenerFlag = isPassive(listener);
938 invokeCallback(listener, this, event);
939 eventData.inPassiveListenerFlag = false;
940 // Stop if the `event.stopImmediatePropagation()` method was called.
941 if (eventData.stopImmediatePropagationFlag) {
942 break;
943 }
944 }
945 // Restore copy-on-write flag.
946 if (!cow) {
947 list.cow = false;
948 }
949 }
950 eventData.target = null;
951 eventData.currentTarget = null;
952 eventData.stopImmediatePropagationFlag = false;
953 eventData.stopPropagationFlag = false;
954 eventData.dispatchFlag = false;
955 return !eventData.canceledFlag;
956 }
957}
958/**
959 * Internal data.
960 */
961const internalDataMap$2 = new WeakMap();
962/**
963 * Get private data.
964 * @param target The event target object to get private data.
965 * @param name The variable name to report.
966 * @returns The private data of the event.
967 */
968function $$2(target, name = "this") {
969 const retv = internalDataMap$2.get(target);
970 assertType(retv != null, "'%s' must be an object that EventTarget constructor created, but got another one: %o", name, target);
971 return retv;
972}
973/**
974 * Normalize options.
975 * @param options The options to normalize.
976 */
977function normalizeAddOptions(type, callback, options) {
978 var _a;
979 assertCallback(callback);
980 if (typeof options === "object" && options !== null) {
981 return {
982 type: String(type),
983 callback: callback !== null && callback !== void 0 ? callback : undefined,
984 capture: Boolean(options.capture),
985 passive: Boolean(options.passive),
986 once: Boolean(options.once),
987 signal: (_a = options.signal) !== null && _a !== void 0 ? _a : undefined,
988 };
989 }
990 return {
991 type: String(type),
992 callback: callback !== null && callback !== void 0 ? callback : undefined,
993 capture: Boolean(options),
994 passive: false,
995 once: false,
996 signal: undefined,
997 };
998}
999/**
1000 * Normalize options.
1001 * @param options The options to normalize.
1002 */
1003function normalizeOptions(type, callback, options) {
1004 assertCallback(callback);
1005 if (typeof options === "object" && options !== null) {
1006 return {
1007 type: String(type),
1008 callback: callback !== null && callback !== void 0 ? callback : undefined,
1009 capture: Boolean(options.capture),
1010 };
1011 }
1012 return {
1013 type: String(type),
1014 callback: callback !== null && callback !== void 0 ? callback : undefined,
1015 capture: Boolean(options),
1016 };
1017}
1018/**
1019 * Assert the type of 'callback' argument.
1020 * @param callback The callback to check.
1021 */
1022function assertCallback(callback) {
1023 if (typeof callback === "function" ||
1024 (typeof callback === "object" &&
1025 callback !== null &&
1026 typeof callback.handleEvent === "function")) {
1027 return;
1028 }
1029 if (callback == null || typeof callback === "object") {
1030 InvalidEventListener.warn(callback);
1031 return;
1032 }
1033 throw new TypeError(format(InvalidEventListener.message, [callback]));
1034}
1035/**
1036 * Print warning for duplicated.
1037 * @param listener The current listener that is duplicated.
1038 * @param passive The passive flag of the new duplicated listener.
1039 * @param once The once flag of the new duplicated listener.
1040 * @param signal The signal object of the new duplicated listener.
1041 */
1042function warnDuplicate(listener, passive, once, signal) {
1043 EventListenerWasDuplicated.warn(isCapture(listener) ? "capture" : "bubble", listener.callback);
1044 if (isPassive(listener) !== passive) {
1045 OptionWasIgnored.warn("passive");
1046 }
1047 if (isOnce(listener) !== once) {
1048 OptionWasIgnored.warn("once");
1049 }
1050 if (listener.signal !== signal) {
1051 OptionWasIgnored.warn("signal");
1052 }
1053}
1054// Set enumerable
1055const keys$1 = Object.getOwnPropertyNames(EventTarget.prototype);
1056for (let i = 0; i < keys$1.length; ++i) {
1057 if (keys$1[i] === "constructor") {
1058 continue;
1059 }
1060 Object.defineProperty(EventTarget.prototype, keys$1[i], { enumerable: true });
1061}
1062// Ensure `eventTarget instanceof window.EventTarget` is `true`.
1063if (typeof Global !== "undefined" &&
1064 typeof Global.EventTarget !== "undefined") {
1065 Object.setPrototypeOf(EventTarget.prototype, Global.EventTarget.prototype);
1066}
1067
1068/**
1069 * Get the current value of a given event attribute.
1070 * @param target The `EventTarget` object to get.
1071 * @param type The event type.
1072 */
1073function getEventAttributeValue(target, type) {
1074 var _a, _b;
1075 const listMap = $$2(target, "target");
1076 return (_b = (_a = listMap[type]) === null || _a === void 0 ? void 0 : _a.attrCallback) !== null && _b !== void 0 ? _b : null;
1077}
1078/**
1079 * Set an event listener to a given event attribute.
1080 * @param target The `EventTarget` object to set.
1081 * @param type The event type.
1082 * @param callback The event listener.
1083 */
1084function setEventAttributeValue(target, type, callback) {
1085 if (callback != null && typeof callback !== "function") {
1086 InvalidAttributeHandler.warn(callback);
1087 }
1088 if (typeof callback === "function" ||
1089 (typeof callback === "object" && callback !== null)) {
1090 upsertEventAttributeListener(target, type, callback);
1091 }
1092 else {
1093 removeEventAttributeListener(target, type);
1094 }
1095}
1096//------------------------------------------------------------------------------
1097// Helpers
1098//------------------------------------------------------------------------------
1099/**
1100 * Update or insert the given event attribute handler.
1101 * @param target The `EventTarget` object to set.
1102 * @param type The event type.
1103 * @param callback The event listener.
1104 */
1105function upsertEventAttributeListener(target, type, callback) {
1106 const list = ensureListenerList($$2(target, "target"), String(type));
1107 list.attrCallback = callback;
1108 if (list.attrListener == null) {
1109 list.attrListener = addListener(list, defineEventAttributeCallback(list), false, false, false, undefined);
1110 }
1111}
1112/**
1113 * Remove the given event attribute handler.
1114 * @param target The `EventTarget` object to remove.
1115 * @param type The event type.
1116 * @param callback The event listener.
1117 */
1118function removeEventAttributeListener(target, type) {
1119 const listMap = $$2(target, "target");
1120 const list = listMap[String(type)];
1121 if (list && list.attrListener) {
1122 removeListener(list, list.attrListener.callback, false);
1123 list.attrCallback = list.attrListener = undefined;
1124 }
1125}
1126/**
1127 * Define the callback function for the given listener list object.
1128 * It calls `attrCallback` property if the property value is a function.
1129 * @param list The `ListenerList` object.
1130 */
1131function defineEventAttributeCallback(list) {
1132 return function (event) {
1133 const callback = list.attrCallback;
1134 if (typeof callback === "function") {
1135 callback.call(this, event);
1136 }
1137 };
1138}
1139
1140/**
1141 * Define an `EventTarget` class that has event attibutes.
1142 * @param types The types to define event attributes.
1143 * @deprecated Use `getEventAttributeValue`/`setEventAttributeValue` pair on your derived class instead because of static analysis friendly.
1144 */
1145function defineCustomEventTarget(...types) {
1146 class CustomEventTarget extends EventTarget {
1147 }
1148 for (let i = 0; i < types.length; ++i) {
1149 defineEventAttribute(CustomEventTarget.prototype, types[i]);
1150 }
1151 return CustomEventTarget;
1152}
1153/**
1154 * Define an event attribute.
1155 * @param target The `EventTarget` object to define an event attribute.
1156 * @param type The event type to define.
1157 * @param _eventClass Unused, but to infer `Event` class type.
1158 * @deprecated Use `getEventAttributeValue`/`setEventAttributeValue` pair on your derived class instead because of static analysis friendly.
1159 */
1160function defineEventAttribute(target, type, _eventClass) {
1161 Object.defineProperty(target, `on${type}`, {
1162 get() {
1163 return getEventAttributeValue(this, type);
1164 },
1165 set(value) {
1166 setEventAttributeValue(this, type, value);
1167 },
1168 configurable: true,
1169 enumerable: true,
1170 });
1171}
1172
1173export default EventTarget;
1174export { Event, EventTarget, defineCustomEventTarget, defineEventAttribute, getEventAttributeValue, setErrorHandler, setEventAttributeValue, setWarningHandler };
1175//# sourceMappingURL=index.mjs.map