UNPKG

event-target-shim

Version:

An implementation of WHATWG EventTarget interface.

1 lines 84.6 kB
{"version":3,"file":"index.mjs","sources":["../src/lib/misc.ts","../src/lib/error-handler.ts","../src/lib/global.ts","../src/lib/warning-handler.ts","../src/lib/warnings.ts","../src/lib/event.ts","../src/lib/dom-exception.ts","../src/lib/event-wrapper.ts","../src/lib/listener.ts","../src/lib/listener-list.ts","../src/lib/listener-list-map.ts","../src/lib/event-target.ts","../src/lib/event-attribute-handler.ts","../src/lib/legacy.ts"],"sourcesContent":["/**\n * Assert a condition.\n * @param condition The condition that it should satisfy.\n * @param message The error message.\n * @param args The arguments for replacing placeholders in the message.\n */\nexport function assertType(\n condition: boolean,\n message: string,\n ...args: any[]\n): asserts condition {\n if (!condition) {\n throw new TypeError(format(message, args))\n }\n}\n\n/**\n * Convert a text and arguments to one string.\n * @param message The formating text\n * @param args The arguments.\n */\nexport function format(message: string, args: any[]): string {\n let i = 0\n return message.replace(/%[os]/gu, () => anyToString(args[i++]))\n}\n\n/**\n * Convert a value to a string representation.\n * @param x The value to get the string representation.\n */\nexport function anyToString(x: any): string {\n if (typeof x !== \"object\" || x === null) {\n return String(x)\n }\n return Object.prototype.toString.call(x)\n}\n","import { anyToString, assertType } from \"./misc\"\n\ndeclare const console: any\ndeclare const dispatchEvent: any\ndeclare const ErrorEvent: any\ndeclare const process: any\n\nlet currentErrorHandler: setErrorHandler.ErrorHandler | undefined\n\n/**\n * Set the error handler.\n * @param value The error handler to set.\n */\nexport function setErrorHandler(\n value: setErrorHandler.ErrorHandler | undefined,\n): void {\n assertType(\n typeof value === \"function\" || value === undefined,\n \"The error handler must be a function or undefined, but got %o.\",\n value,\n )\n currentErrorHandler = value\n}\nexport namespace setErrorHandler {\n /**\n * The error handler.\n * @param error The thrown error object.\n */\n export type ErrorHandler = (error: Error) => void\n}\n\n/**\n * Print a error message.\n * @param maybeError The error object.\n */\nexport function reportError(maybeError: unknown): void {\n try {\n const error =\n maybeError instanceof Error\n ? maybeError\n : new Error(anyToString(maybeError))\n\n // Call the user-defined error handler if exists.\n if (currentErrorHandler) {\n currentErrorHandler(error)\n return\n }\n\n // Dispatch an `error` event if this is on a browser.\n if (\n typeof dispatchEvent === \"function\" &&\n typeof ErrorEvent === \"function\"\n ) {\n dispatchEvent(\n new ErrorEvent(\"error\", { error, message: error.message }),\n )\n }\n\n // Emit an `uncaughtException` event if this is on Node.js.\n //istanbul ignore else\n else if (\n typeof process !== \"undefined\" &&\n typeof process.emit === \"function\"\n ) {\n process.emit(\"uncaughtException\", error)\n return\n }\n\n // Otherwise, print the error.\n console.error(error)\n } catch {\n // ignore.\n }\n}\n","declare const globalThis: any\ndeclare const window: any\ndeclare const self: any\ndeclare const global: any\n\n/**\n * The global object.\n */\n//istanbul ignore next\nexport const Global: any =\n typeof window !== \"undefined\"\n ? window\n : typeof self !== \"undefined\"\n ? self\n : typeof global !== \"undefined\"\n ? global\n : typeof globalThis !== \"undefined\"\n ? globalThis\n : undefined\n","import { assertType } from \"./misc\"\n\ndeclare const console: any\n\nlet currentWarnHandler: setWarningHandler.WarningHandler | undefined\n\n/**\n * Set the warning handler.\n * @param value The warning handler to set.\n */\nexport function setWarningHandler(\n value: setWarningHandler.WarningHandler | undefined,\n): void {\n assertType(\n typeof value === \"function\" || value === undefined,\n \"The warning handler must be a function or undefined, but got %o.\",\n value,\n )\n currentWarnHandler = value\n}\nexport namespace setWarningHandler {\n /**\n * The warning information.\n */\n export interface Warning {\n /**\n * The code of this warning.\n */\n code: string\n /**\n * The message in English.\n */\n message: string\n /**\n * The arguments for replacing placeholders in the text.\n */\n args: any[]\n }\n\n /**\n * The warning handler.\n * @param warning The warning.\n */\n export type WarningHandler = (warning: Warning) => void\n}\n\n/**\n * The warning information.\n */\nexport class Warning<TArgs extends any[]> {\n readonly code: string\n readonly message: string\n\n constructor(code: string, message: string) {\n this.code = code\n this.message = message\n }\n\n /**\n * Report this warning.\n * @param args The arguments of the warning.\n */\n warn(...args: TArgs): void {\n try {\n // Call the user-defined warning handler if exists.\n if (currentWarnHandler) {\n currentWarnHandler({ ...this, args })\n return\n }\n\n // Otherwise, print the warning.\n const stack = (new Error().stack ?? \"\").replace(\n /^(?:.+?\\n){2}/gu,\n \"\\n\",\n )\n console.warn(this.message, ...args, stack)\n } catch {\n // Ignore.\n }\n }\n}\n","import { EventTarget } from \"./event-target\" // Used as only type, so no circular.\nimport { Warning } from \"./warning-handler\"\n\nexport const InitEventWasCalledWhileDispatching = new Warning<[]>(\n \"W01\",\n \"Unable to initialize event under dispatching.\",\n)\n\nexport const FalsyWasAssignedToCancelBubble = new Warning<[]>(\n \"W02\",\n \"Assigning any falsy value to 'cancelBubble' property has no effect.\",\n)\n\nexport const TruthyWasAssignedToReturnValue = new Warning<[]>(\n \"W03\",\n \"Assigning any truthy value to 'returnValue' property has no effect.\",\n)\n\nexport const NonCancelableEventWasCanceled = new Warning<[]>(\n \"W04\",\n \"Unable to preventDefault on non-cancelable events.\",\n)\n\nexport const CanceledInPassiveListener = new Warning<[]>(\n \"W05\",\n \"Unable to preventDefault inside passive event listener invocation.\",\n)\n\nexport const EventListenerWasDuplicated = new Warning<\n [type: \"bubble\" | \"capture\", callback: EventTarget.EventListener<any, any>]\n>(\n \"W06\",\n \"An event listener wasn't added because it has been added already: %o, %o\",\n)\n\nexport const OptionWasIgnored = new Warning<\n [name: \"passive\" | \"once\" | \"signal\"]\n>(\n \"W07\",\n \"The %o option value was abandoned because the event listener wasn't added as duplicated.\",\n)\n\nexport const InvalidEventListener = new Warning<\n [callback: EventTarget.EventListener<any, any> | {} | null | undefined]\n>(\n \"W08\",\n \"The 'callback' argument must be a function or an object that has 'handleEvent' method: %o\",\n)\n\nexport const InvalidAttributeHandler = new Warning<\n [callback: EventTarget.EventListener<any, any> | {}]\n>(\"W09\", \"Event attribute handler must be a function: %o\")\n","import { EventTarget } from \"./event-target\" // Used as only type, so no circular.\nimport { Global } from \"./global\"\nimport { assertType } from \"./misc\"\nimport {\n CanceledInPassiveListener,\n FalsyWasAssignedToCancelBubble,\n InitEventWasCalledWhileDispatching,\n NonCancelableEventWasCanceled,\n TruthyWasAssignedToReturnValue,\n} from \"./warnings\"\n\n/*eslint-disable class-methods-use-this */\n\n/**\n * An implementation of `Event` interface, that wraps a given event object.\n * `EventTarget` shim can control the internal state of this `Event` objects.\n * @see https://dom.spec.whatwg.org/#event\n */\nexport class Event<TEventType extends string = string> {\n /**\n * @see https://dom.spec.whatwg.org/#dom-event-none\n */\n static get NONE(): number {\n return NONE\n }\n\n /**\n * @see https://dom.spec.whatwg.org/#dom-event-capturing_phase\n */\n static get CAPTURING_PHASE(): number {\n return CAPTURING_PHASE\n }\n\n /**\n * @see https://dom.spec.whatwg.org/#dom-event-at_target\n */\n static get AT_TARGET(): number {\n return AT_TARGET\n }\n\n /**\n * @see https://dom.spec.whatwg.org/#dom-event-bubbling_phase\n */\n static get BUBBLING_PHASE(): number {\n return BUBBLING_PHASE\n }\n\n /**\n * Initialize this event instance.\n * @param type The type of this event.\n * @param eventInitDict Options to initialize.\n * @see https://dom.spec.whatwg.org/#dom-event-event\n */\n constructor(type: TEventType, eventInitDict?: Event.EventInit) {\n Object.defineProperty(this, \"isTrusted\", {\n value: false,\n enumerable: true,\n })\n\n const opts = eventInitDict ?? {}\n internalDataMap.set(this, {\n type: String(type),\n bubbles: Boolean(opts.bubbles),\n cancelable: Boolean(opts.cancelable),\n composed: Boolean(opts.composed),\n target: null,\n currentTarget: null,\n stopPropagationFlag: false,\n stopImmediatePropagationFlag: false,\n canceledFlag: false,\n inPassiveListenerFlag: false,\n dispatchFlag: false,\n timeStamp: Date.now(),\n })\n }\n\n /**\n * The type of this event.\n * @see https://dom.spec.whatwg.org/#dom-event-type\n */\n get type(): TEventType {\n return $(this).type as TEventType\n }\n\n /**\n * The event target of the current dispatching.\n * @see https://dom.spec.whatwg.org/#dom-event-target\n */\n get target(): EventTarget | null {\n return $(this).target\n }\n\n /**\n * The event target of the current dispatching.\n * @deprecated Use the `target` property instead.\n * @see https://dom.spec.whatwg.org/#dom-event-srcelement\n */\n get srcElement(): EventTarget | null {\n return $(this).target\n }\n\n /**\n * The event target of the current dispatching.\n * @see https://dom.spec.whatwg.org/#dom-event-currenttarget\n */\n get currentTarget(): EventTarget | null {\n return $(this).currentTarget\n }\n\n /**\n * The event target of the current dispatching.\n * This doesn't support node tree.\n * @see https://dom.spec.whatwg.org/#dom-event-composedpath\n */\n composedPath(): EventTarget[] {\n const currentTarget = $(this).currentTarget\n if (currentTarget) {\n return [currentTarget]\n }\n return []\n }\n\n /**\n * @see https://dom.spec.whatwg.org/#dom-event-none\n */\n get NONE(): number {\n return NONE\n }\n\n /**\n * @see https://dom.spec.whatwg.org/#dom-event-capturing_phase\n */\n get CAPTURING_PHASE(): number {\n return CAPTURING_PHASE\n }\n\n /**\n * @see https://dom.spec.whatwg.org/#dom-event-at_target\n */\n get AT_TARGET(): number {\n return AT_TARGET\n }\n\n /**\n * @see https://dom.spec.whatwg.org/#dom-event-bubbling_phase\n */\n get BUBBLING_PHASE(): number {\n return BUBBLING_PHASE\n }\n\n /**\n * The current event phase.\n * @see https://dom.spec.whatwg.org/#dom-event-eventphase\n */\n get eventPhase(): number {\n return $(this).dispatchFlag ? 2 : 0\n }\n\n /**\n * Stop event bubbling.\n * Because this shim doesn't support node tree, this merely changes the `cancelBubble` property value.\n * @see https://dom.spec.whatwg.org/#dom-event-stoppropagation\n */\n stopPropagation(): void {\n $(this).stopPropagationFlag = true\n }\n\n /**\n * `true` if event bubbling was stopped.\n * @deprecated\n * @see https://dom.spec.whatwg.org/#dom-event-cancelbubble\n */\n get cancelBubble(): boolean {\n return $(this).stopPropagationFlag\n }\n\n /**\n * Stop event bubbling if `true` is set.\n * @deprecated Use the `stopPropagation()` method instead.\n * @see https://dom.spec.whatwg.org/#dom-event-cancelbubble\n */\n set cancelBubble(value: boolean) {\n if (value) {\n $(this).stopPropagationFlag = true\n } else {\n FalsyWasAssignedToCancelBubble.warn()\n }\n }\n\n /**\n * Stop event bubbling and subsequent event listener callings.\n * @see https://dom.spec.whatwg.org/#dom-event-stopimmediatepropagation\n */\n stopImmediatePropagation(): void {\n const data = $(this)\n data.stopPropagationFlag = data.stopImmediatePropagationFlag = true\n }\n\n /**\n * `true` if this event will bubble.\n * @see https://dom.spec.whatwg.org/#dom-event-bubbles\n */\n get bubbles(): boolean {\n return $(this).bubbles\n }\n\n /**\n * `true` if this event can be canceled by the `preventDefault()` method.\n * @see https://dom.spec.whatwg.org/#dom-event-cancelable\n */\n get cancelable(): boolean {\n return $(this).cancelable\n }\n\n /**\n * `true` if the default behavior will act.\n * @deprecated Use the `defaultPrevented` proeprty instead.\n * @see https://dom.spec.whatwg.org/#dom-event-returnvalue\n */\n get returnValue(): boolean {\n return !$(this).canceledFlag\n }\n\n /**\n * Cancel the default behavior if `false` is set.\n * @deprecated Use the `preventDefault()` method instead.\n * @see https://dom.spec.whatwg.org/#dom-event-returnvalue\n */\n set returnValue(value: boolean) {\n if (!value) {\n setCancelFlag($(this))\n } else {\n TruthyWasAssignedToReturnValue.warn()\n }\n }\n\n /**\n * Cancel the default behavior.\n * @see https://dom.spec.whatwg.org/#dom-event-preventdefault\n */\n preventDefault(): void {\n setCancelFlag($(this))\n }\n\n /**\n * `true` if the default behavior was canceled.\n * @see https://dom.spec.whatwg.org/#dom-event-defaultprevented\n */\n get defaultPrevented(): boolean {\n return $(this).canceledFlag\n }\n\n /**\n * @see https://dom.spec.whatwg.org/#dom-event-composed\n */\n get composed(): boolean {\n return $(this).composed\n }\n\n /**\n * @see https://dom.spec.whatwg.org/#dom-event-istrusted\n */\n //istanbul ignore next\n get isTrusted(): boolean {\n return false\n }\n\n /**\n * @see https://dom.spec.whatwg.org/#dom-event-timestamp\n */\n get timeStamp(): number {\n return $(this).timeStamp\n }\n\n /**\n * @deprecated Don't use this method. The constructor did initialization.\n */\n initEvent(type: string, bubbles = false, cancelable = false) {\n const data = $(this)\n if (data.dispatchFlag) {\n InitEventWasCalledWhileDispatching.warn()\n return\n }\n\n internalDataMap.set(this, {\n ...data,\n type: String(type),\n bubbles: Boolean(bubbles),\n cancelable: Boolean(cancelable),\n target: null,\n currentTarget: null,\n stopPropagationFlag: false,\n stopImmediatePropagationFlag: false,\n canceledFlag: false,\n })\n }\n}\n\n/*eslint-enable class-methods-use-this */\n\nexport namespace Event {\n /**\n * The options of the `Event` constructor.\n * @see https://dom.spec.whatwg.org/#dictdef-eventinit\n */\n export interface EventInit {\n bubbles?: boolean\n cancelable?: boolean\n composed?: boolean\n }\n}\n\nexport { $ as getEventInternalData }\n\n//------------------------------------------------------------------------------\n// Helpers\n//------------------------------------------------------------------------------\n\nconst NONE = 0\nconst CAPTURING_PHASE = 1\nconst AT_TARGET = 2\nconst BUBBLING_PHASE = 3\n\n/**\n * Private data.\n */\ninterface EventInternalData {\n /**\n * The value of `type` attribute.\n */\n readonly type: string\n /**\n * The value of `bubbles` attribute.\n */\n readonly bubbles: boolean\n /**\n * The value of `cancelable` attribute.\n */\n readonly cancelable: boolean\n /**\n * The value of `composed` attribute.\n */\n readonly composed: boolean\n /**\n * The value of `timeStamp` attribute.\n */\n readonly timeStamp: number\n\n /**\n * @see https://dom.spec.whatwg.org/#dom-event-target\n */\n target: EventTarget | null\n /**\n * @see https://dom.spec.whatwg.org/#dom-event-currenttarget\n */\n currentTarget: EventTarget | null\n /**\n * @see https://dom.spec.whatwg.org/#stop-propagation-flag\n */\n stopPropagationFlag: boolean\n /**\n * @see https://dom.spec.whatwg.org/#stop-immediate-propagation-flag\n */\n stopImmediatePropagationFlag: boolean\n /**\n * @see https://dom.spec.whatwg.org/#canceled-flag\n */\n canceledFlag: boolean\n /**\n * @see https://dom.spec.whatwg.org/#in-passive-listener-flag\n */\n inPassiveListenerFlag: boolean\n /**\n * @see https://dom.spec.whatwg.org/#dispatch-flag\n */\n dispatchFlag: boolean\n}\n\n/**\n * Private data for event wrappers.\n */\nconst internalDataMap = new WeakMap<any, EventInternalData>()\n\n/**\n * Get private data.\n * @param event The event object to get private data.\n * @param name The variable name to report.\n * @returns The private data of the event.\n */\nfunction $(event: unknown, name = \"this\"): EventInternalData {\n const retv = internalDataMap.get(event)\n assertType(\n retv != null,\n \"'%s' must be an object that Event constructor created, but got another one: %o\",\n name,\n event,\n )\n return retv\n}\n\n/**\n * https://dom.spec.whatwg.org/#set-the-canceled-flag\n * @param data private data.\n */\nfunction setCancelFlag(data: EventInternalData) {\n if (data.inPassiveListenerFlag) {\n CanceledInPassiveListener.warn()\n return\n }\n if (!data.cancelable) {\n NonCancelableEventWasCanceled.warn()\n return\n }\n\n data.canceledFlag = true\n}\n\n// Set enumerable\nObject.defineProperty(Event, \"NONE\", { enumerable: true })\nObject.defineProperty(Event, \"CAPTURING_PHASE\", { enumerable: true })\nObject.defineProperty(Event, \"AT_TARGET\", { enumerable: true })\nObject.defineProperty(Event, \"BUBBLING_PHASE\", { enumerable: true })\nconst keys = Object.getOwnPropertyNames(Event.prototype)\nfor (let i = 0; i < keys.length; ++i) {\n if (keys[i] === \"constructor\") {\n continue\n }\n Object.defineProperty(Event.prototype, keys[i], { enumerable: true })\n}\n\n// Ensure `event instanceof window.Event` is `true`.\nif (typeof Global !== \"undefined\" && typeof Global.Event !== \"undefined\") {\n Object.setPrototypeOf(Event.prototype, Global.Event.prototype)\n}\n","import { Global } from \"./global\"\n\n/**\n * Create a new InvalidStateError instance.\n * @param message The error message.\n */\nexport function createInvalidStateError(message: string): Error {\n if (Global.DOMException) {\n return new Global.DOMException(message, \"InvalidStateError\")\n }\n\n if (DOMException == null) {\n DOMException = class DOMException extends Error {\n constructor(msg: string) {\n super(msg)\n if ((Error as any).captureStackTrace) {\n ;(Error as any).captureStackTrace(this, DOMException)\n }\n }\n // eslint-disable-next-line class-methods-use-this\n get code() {\n return 11\n }\n // eslint-disable-next-line class-methods-use-this\n get name() {\n return \"InvalidStateError\"\n }\n }\n Object.defineProperties(DOMException.prototype, {\n code: { enumerable: true },\n name: { enumerable: true },\n })\n defineErrorCodeProperties(DOMException)\n defineErrorCodeProperties(DOMException.prototype)\n }\n return new DOMException(message)\n}\n\n//------------------------------------------------------------------------------\n// Helpers\n//------------------------------------------------------------------------------\n\nlet DOMException: { new (message: string): Error } | undefined\n\nconst ErrorCodeMap = {\n INDEX_SIZE_ERR: 1,\n DOMSTRING_SIZE_ERR: 2,\n HIERARCHY_REQUEST_ERR: 3,\n WRONG_DOCUMENT_ERR: 4,\n INVALID_CHARACTER_ERR: 5,\n NO_DATA_ALLOWED_ERR: 6,\n NO_MODIFICATION_ALLOWED_ERR: 7,\n NOT_FOUND_ERR: 8,\n NOT_SUPPORTED_ERR: 9,\n INUSE_ATTRIBUTE_ERR: 10,\n INVALID_STATE_ERR: 11,\n SYNTAX_ERR: 12,\n INVALID_MODIFICATION_ERR: 13,\n NAMESPACE_ERR: 14,\n INVALID_ACCESS_ERR: 15,\n VALIDATION_ERR: 16,\n TYPE_MISMATCH_ERR: 17,\n SECURITY_ERR: 18,\n NETWORK_ERR: 19,\n ABORT_ERR: 20,\n URL_MISMATCH_ERR: 21,\n QUOTA_EXCEEDED_ERR: 22,\n TIMEOUT_ERR: 23,\n INVALID_NODE_TYPE_ERR: 24,\n DATA_CLONE_ERR: 25,\n}\ntype ErrorCodeMap = typeof ErrorCodeMap\n\nfunction defineErrorCodeProperties(obj: any): void {\n const keys = Object.keys(ErrorCodeMap) as (keyof ErrorCodeMap)[]\n for (let i = 0; i < keys.length; ++i) {\n const key = keys[i]\n const value = ErrorCodeMap[key]\n Object.defineProperty(obj, key, {\n get() {\n return value\n },\n configurable: true,\n enumerable: true,\n })\n }\n}\n","import { Event } from \"./event\"\nimport { Global } from \"./global\"\nimport { assertType } from \"./misc\"\n\n/**\n * An implementation of `Event` interface, that wraps a given event object.\n * This class controls the internal state of `Event`.\n * @see https://dom.spec.whatwg.org/#interface-event\n */\nexport class EventWrapper<TEventType extends string> extends Event<TEventType> {\n /**\n * Wrap a given event object to control states.\n * @param event The event-like object to wrap.\n */\n static wrap<T extends EventLike>(event: T): EventWrapperOf<T> {\n return new (getWrapperClassOf(event))(event)\n }\n\n protected constructor(event: Event<TEventType>) {\n super(event.type, {\n bubbles: event.bubbles,\n cancelable: event.cancelable,\n composed: event.composed,\n })\n\n if (event.cancelBubble) {\n super.stopPropagation()\n }\n if (event.defaultPrevented) {\n super.preventDefault()\n }\n\n internalDataMap.set(this, { original: event })\n\n // Define accessors\n const keys = Object.keys(event)\n for (let i = 0; i < keys.length; ++i) {\n const key = keys[i]\n if (!(key in this)) {\n Object.defineProperty(\n this,\n key,\n defineRedirectDescriptor(event, key),\n )\n }\n }\n }\n\n stopPropagation(): void {\n super.stopPropagation()\n\n const { original } = $(this)\n if (\"stopPropagation\" in original) {\n original.stopPropagation!()\n }\n }\n\n get cancelBubble(): boolean {\n return super.cancelBubble\n }\n set cancelBubble(value: boolean) {\n super.cancelBubble = value\n\n const { original } = $(this)\n if (\"cancelBubble\" in original) {\n original.cancelBubble = value\n }\n }\n\n stopImmediatePropagation(): void {\n super.stopImmediatePropagation()\n\n const { original } = $(this)\n if (\"stopImmediatePropagation\" in original) {\n original.stopImmediatePropagation!()\n }\n }\n\n get returnValue(): boolean {\n return super.returnValue\n }\n set returnValue(value: boolean) {\n super.returnValue = value\n\n const { original } = $(this)\n if (\"returnValue\" in original) {\n original.returnValue = value\n }\n }\n\n preventDefault(): void {\n super.preventDefault()\n\n const { original } = $(this)\n if (\"preventDefault\" in original) {\n original.preventDefault!()\n }\n }\n\n get timeStamp(): number {\n const { original } = $(this)\n if (\"timeStamp\" in original) {\n return original.timeStamp!\n }\n return super.timeStamp\n }\n}\n\n//------------------------------------------------------------------------------\n// Helpers\n//------------------------------------------------------------------------------\n\ntype EventLike = { readonly type: string } & Partial<Event>\ntype EventWrapperOf<T extends EventLike> = Event<T[\"type\"]> &\n Omit<T, keyof Event>\n\ninterface EventWrapperInternalData {\n readonly original: EventLike\n}\n\n/**\n * Private data for event wrappers.\n */\nconst internalDataMap = new WeakMap<any, EventWrapperInternalData>()\n\n/**\n * Get private data.\n * @param event The event object to get private data.\n * @returns The private data of the event.\n */\nfunction $(event: unknown): EventWrapperInternalData {\n const retv = internalDataMap.get(event)\n assertType(\n retv != null,\n \"'this' is expected an Event object, but got\",\n event,\n )\n return retv\n}\n\n/**\n * Cache for wrapper classes.\n * @type {WeakMap<Object, Function>}\n * @private\n */\nconst wrapperClassCache = new WeakMap()\n\n// Make association for wrappers.\nwrapperClassCache.set(Object.prototype, EventWrapper)\nif (typeof Global !== \"undefined\" && typeof Global.Event !== \"undefined\") {\n wrapperClassCache.set(Global.Event.prototype, EventWrapper)\n}\n\n/**\n * Get the wrapper class of a given prototype.\n * @param originalEvent The event object to wrap.\n */\nfunction getWrapperClassOf<T extends EventLike>(\n originalEvent: T,\n): { new (e: T): EventWrapperOf<T> } {\n const prototype = Object.getPrototypeOf(originalEvent)\n if (prototype == null) {\n return EventWrapper as any\n }\n\n let wrapper: any = wrapperClassCache.get(prototype)\n if (wrapper == null) {\n wrapper = defineWrapper(getWrapperClassOf(prototype), prototype)\n wrapperClassCache.set(prototype, wrapper)\n }\n\n return wrapper\n}\n\n/**\n * Define new wrapper class.\n * @param BaseEventWrapper The base wrapper class.\n * @param originalPrototype The prototype of the original event.\n */\nfunction defineWrapper(BaseEventWrapper: any, originalPrototype: any): any {\n class CustomEventWrapper extends BaseEventWrapper {}\n\n const keys = Object.keys(originalPrototype)\n for (let i = 0; i < keys.length; ++i) {\n Object.defineProperty(\n CustomEventWrapper.prototype,\n keys[i],\n defineRedirectDescriptor(originalPrototype, keys[i]),\n )\n }\n\n return CustomEventWrapper\n}\n\n/**\n * Get the property descriptor to redirect a given property.\n */\nfunction defineRedirectDescriptor(obj: any, key: string): PropertyDescriptor {\n const d = Object.getOwnPropertyDescriptor(obj, key)!\n return {\n get() {\n const original: any = $(this).original\n const value = original[key]\n if (typeof value === \"function\") {\n return value.bind(original)\n }\n return value\n },\n set(value: any) {\n const original: any = $(this).original\n original[key] = value\n },\n configurable: d.configurable,\n enumerable: d.enumerable,\n }\n}\n","import { reportError } from \"./error-handler\"\nimport { Event } from \"./event\" // Used as only type, so no circular.\nimport { EventTarget } from \"./event-target\" // Used as only type, so no circular.\n\n/**\n * The event listener concept.\n * @see https://dom.spec.whatwg.org/#concept-event-listener\n */\nexport interface Listener {\n /**\n * The callback function.\n */\n readonly callback: Listener.Callback<any, any>\n /**\n * The flags of this listener.\n * This is writable to add the removed flag.\n */\n flags: ListenerFlags\n /**\n * The `AbortSignal` to remove this listener.\n */\n readonly signal: Listener.AbortSignal | undefined\n /**\n * The `abort` event listener for the `signal`.\n * To remove it from the `signal`.\n */\n readonly signalListener: (() => void) | undefined\n}\n\nexport namespace Listener {\n export type Callback<\n TEventTarget extends EventTarget<any, any>,\n TEvent extends Event\n > = CallbackFunction<TEventTarget, TEvent> | CallbackObject<TEvent>\n\n export interface CallbackFunction<\n TEventTarget extends EventTarget<any, any>,\n TEvent extends Event\n > {\n (this: TEventTarget, event: TEvent): void\n }\n\n export interface CallbackObject<TEvent extends Event> {\n handleEvent(event: TEvent): void\n }\n\n export interface AbortSignal {\n addEventListener(type: string, callback: Callback<any, Event>): void\n removeEventListener(type: string, callback: Callback<any, Event>): void\n }\n}\n\n/**\n * Create a new listener.\n * @param callback The callback function.\n * @param capture The capture flag.\n * @param passive The passive flag.\n * @param once The once flag.\n * @param signal The abort signal.\n * @param signalListener The abort event listener for the abort signal.\n */\nexport function createListener(\n callback: Listener.Callback<any, any>,\n capture: boolean,\n passive: boolean,\n once: boolean,\n signal: Listener.AbortSignal | undefined,\n signalListener: (() => void) | undefined,\n): Listener {\n return {\n callback,\n flags:\n (capture ? ListenerFlags.Capture : 0) |\n (passive ? ListenerFlags.Passive : 0) |\n (once ? ListenerFlags.Once : 0),\n signal,\n signalListener,\n }\n}\n\n/**\n * Set the `removed` flag to the given listener.\n * @param listener The listener to check.\n */\nexport function setRemoved(listener: Listener): void {\n listener.flags |= ListenerFlags.Removed\n}\n\n/**\n * Check if the given listener has the `capture` flag or not.\n * @param listener The listener to check.\n */\nexport function isCapture(listener: Listener): boolean {\n return (listener.flags & ListenerFlags.Capture) === ListenerFlags.Capture\n}\n\n/**\n * Check if the given listener has the `passive` flag or not.\n * @param listener The listener to check.\n */\nexport function isPassive(listener: Listener): boolean {\n return (listener.flags & ListenerFlags.Passive) === ListenerFlags.Passive\n}\n\n/**\n * Check if the given listener has the `once` flag or not.\n * @param listener The listener to check.\n */\nexport function isOnce(listener: Listener): boolean {\n return (listener.flags & ListenerFlags.Once) === ListenerFlags.Once\n}\n\n/**\n * Check if the given listener has the `removed` flag or not.\n * @param listener The listener to check.\n */\nexport function isRemoved(listener: Listener): boolean {\n return (listener.flags & ListenerFlags.Removed) === ListenerFlags.Removed\n}\n\n/**\n * Call an event listener.\n * @param listener The listener to call.\n * @param target The event target object for `thisArg`.\n * @param event The event object for the first argument.\n * @param attribute `true` if this callback is an event attribute handler.\n */\nexport function invokeCallback(\n { callback }: Listener,\n target: EventTarget<any, any>,\n event: Event<any>,\n): void {\n try {\n if (typeof callback === \"function\") {\n callback.call(target, event)\n } else if (typeof callback.handleEvent === \"function\") {\n callback.handleEvent(event)\n }\n } catch (thrownError) {\n reportError(thrownError)\n }\n}\n\n//------------------------------------------------------------------------------\n// Helpers\n//------------------------------------------------------------------------------\n\n/**\n * The flags of listeners.\n */\nconst enum ListenerFlags {\n Capture = 0x01,\n Passive = 0x02,\n Once = 0x04,\n Removed = 0x08,\n}\n","import { createListener, isCapture, Listener, setRemoved } from \"./listener\"\n\n/**\n * Information of an listener list.\n */\nexport interface ListenerList {\n /**\n * The callback function of the event attribute handler.\n */\n attrCallback: Listener.CallbackFunction<any, any> | undefined\n /**\n * The listener of the event attribute handler.\n */\n attrListener: Listener | undefined\n /**\n * `true` if the `dispatchEvent` method is traversing the current `listeners` array.\n */\n cow: boolean\n /**\n * The listeners.\n * This is writable for copy-on-write.\n */\n listeners: Listener[]\n}\n\n/**\n * Find the index of given listener.\n * This returns `-1` if not found.\n * @param list The listener list.\n * @param callback The callback function to find.\n * @param capture The capture flag to find.\n */\nexport function findIndexOfListener(\n { listeners }: ListenerList,\n callback: Listener.Callback<any, any>,\n capture: boolean,\n): number {\n for (let i = 0; i < listeners.length; ++i) {\n if (\n listeners[i].callback === callback &&\n isCapture(listeners[i]) === capture\n ) {\n return i\n }\n }\n return -1\n}\n\n/**\n * Add the given listener.\n * Does copy-on-write if needed.\n * @param list The listener list.\n * @param callback The callback function.\n * @param capture The capture flag.\n * @param passive The passive flag.\n * @param once The once flag.\n * @param signal The abort signal.\n */\nexport function addListener(\n list: ListenerList,\n callback: Listener.Callback<any, any>,\n capture: boolean,\n passive: boolean,\n once: boolean,\n signal: Listener.AbortSignal | undefined,\n): Listener {\n let signalListener: (() => void) | undefined\n if (signal) {\n signalListener = removeListener.bind(null, list, callback, capture)\n signal.addEventListener(\"abort\", signalListener)\n }\n\n const listener = createListener(\n callback,\n capture,\n passive,\n once,\n signal,\n signalListener,\n )\n\n if (list.cow) {\n list.cow = false\n list.listeners = [...list.listeners, listener]\n } else {\n list.listeners.push(listener)\n }\n\n return listener\n}\n\n/**\n * Remove a listener.\n * @param list The listener list.\n * @param callback The callback function to find.\n * @param capture The capture flag to find.\n * @returns `true` if it mutated the list directly.\n */\nexport function removeListener(\n list: ListenerList,\n callback: Listener.Callback<any, any>,\n capture: boolean,\n): boolean {\n const index = findIndexOfListener(list, callback, capture)\n if (index !== -1) {\n return removeListenerAt(list, index)\n }\n return false\n}\n\n/**\n * Remove a listener.\n * @param list The listener list.\n * @param index The index of the target listener.\n * @param disableCow Disable copy-on-write if true.\n * @returns `true` if it mutated the `listeners` array directly.\n */\nexport function removeListenerAt(\n list: ListenerList,\n index: number,\n disableCow = false,\n): boolean {\n const listener = list.listeners[index]\n\n // Set the removed flag.\n setRemoved(listener)\n\n // Dispose the abort signal listener if exists.\n if (listener.signal) {\n listener.signal.removeEventListener(\"abort\", listener.signalListener!)\n }\n\n // Remove it from the array.\n if (list.cow && !disableCow) {\n list.cow = false\n list.listeners = list.listeners.filter((_, i) => i !== index)\n return false\n }\n list.listeners.splice(index, 1)\n return true\n}\n","import { ListenerList } from \"./listener-list\"\n\n/**\n * The map from event types to each listener list.\n */\nexport interface ListenerListMap {\n [type: string]: ListenerList | undefined\n}\n\n/**\n * Create a new `ListenerListMap` object.\n */\nexport function createListenerListMap(): ListenerListMap {\n return Object.create(null)\n}\n\n/**\n * Get the listener list of the given type.\n * If the listener list has not been initialized, initialize and return it.\n * @param listenerMap The listener list map.\n * @param type The event type to get.\n */\nexport function ensureListenerList(\n listenerMap: Record<string, ListenerList | undefined>,\n type: string,\n): ListenerList {\n return (listenerMap[type] ??= {\n attrCallback: undefined,\n attrListener: undefined,\n cow: false,\n listeners: [],\n })\n}\n","import { createInvalidStateError } from \"./dom-exception\"\nimport { Event, getEventInternalData } from \"./event\"\nimport { EventWrapper } from \"./event-wrapper\"\nimport { Global } from \"./global\"\nimport {\n invokeCallback,\n isCapture,\n isOnce,\n isPassive,\n isRemoved,\n Listener,\n} from \"./listener\"\nimport {\n addListener,\n findIndexOfListener,\n removeListener,\n removeListenerAt,\n} from \"./listener-list\"\nimport {\n createListenerListMap,\n ensureListenerList,\n ListenerListMap,\n} from \"./listener-list-map\"\nimport { assertType, format } from \"./misc\"\nimport {\n EventListenerWasDuplicated,\n InvalidEventListener,\n OptionWasIgnored,\n} from \"./warnings\"\n\n/**\n * An implementation of the `EventTarget` interface.\n * @see https://dom.spec.whatwg.org/#eventtarget\n */\nexport class EventTarget<\n TEventMap extends Record<string, Event> = Record<string, Event>,\n TMode extends \"standard\" | \"strict\" = \"standard\"\n> {\n /**\n * Initialize this instance.\n */\n constructor() {\n internalDataMap.set(this, createListenerListMap())\n }\n\n /**\n * Add an event listener.\n * @param type The event type.\n * @param callback The event listener.\n * @param options Options.\n */\n addEventListener<T extends string & keyof TEventMap>(\n type: T,\n callback?: EventTarget.EventListener<this, TEventMap[T]> | null,\n options?: EventTarget.AddOptions,\n ): void\n\n /**\n * Add an event listener.\n * @param type The event type.\n * @param callback The event listener.\n * @param options Options.\n */\n addEventListener(\n type: string,\n callback?: EventTarget.FallbackEventListener<this, TMode>,\n options?: EventTarget.AddOptions,\n ): void\n\n /**\n * Add an event listener.\n * @param type The event type.\n * @param callback The event listener.\n * @param capture The capture flag.\n * @deprecated Use `{capture: boolean}` object instead of a boolean value.\n */\n addEventListener<T extends string & keyof TEventMap>(\n type: T,\n callback:\n | EventTarget.EventListener<this, TEventMap[T]>\n | null\n | undefined,\n capture: boolean,\n ): void\n\n /**\n * Add an event listener.\n * @param type The event type.\n * @param callback The event listener.\n * @param capture The capture flag.\n * @deprecated Use `{capture: boolean}` object instead of a boolean value.\n */\n addEventListener(\n type: string,\n callback: EventTarget.FallbackEventListener<this, TMode>,\n capture: boolean,\n ): void\n\n // Implementation\n addEventListener<T extends string & keyof TEventMap>(\n type0: T,\n callback0?: EventTarget.EventListener<this, TEventMap[T]> | null,\n options0?: boolean | EventTarget.AddOptions,\n ): void {\n const listenerMap = $(this)\n const {\n callback,\n capture,\n once,\n passive,\n signal,\n type,\n } = normalizeAddOptions(type0, callback0, options0)\n if (callback == null || signal?.aborted) {\n return\n }\n const list = ensureListenerList(listenerMap, type)\n\n // Find existing listener.\n const i = findIndexOfListener(list, callback, capture)\n if (i !== -1) {\n warnDuplicate(list.listeners[i], passive, once, signal)\n return\n }\n\n // Add the new listener.\n addListener(list, callback, capture, passive, once, signal)\n }\n\n /**\n * Remove an added event listener.\n * @param type The event type.\n * @param callback The event listener.\n * @param options Options.\n */\n removeEventListener<T extends string & keyof TEventMap>(\n type: T,\n callback?: EventTarget.EventListener<this, TEventMap[T]> | null,\n options?: EventTarget.Options,\n ): void\n\n /**\n * Remove an added event listener.\n * @param type The event type.\n * @param callback The event listener.\n * @param options Options.\n */\n removeEventListener(\n type: string,\n callback?: EventTarget.FallbackEventListener<this, TMode>,\n options?: EventTarget.Options,\n ): void\n\n /**\n * Remove an added event listener.\n * @param type The event type.\n * @param callback The event listener.\n * @param capture The capture flag.\n * @deprecated Use `{capture: boolean}` object instead of a boolean value.\n */\n removeEventListener<T extends string & keyof TEventMap>(\n type: T,\n callback:\n | EventTarget.EventListener<this, TEventMap[T]>\n | null\n | undefined,\n capture: boolean,\n ): void\n\n /**\n * Remove an added event listener.\n * @param type The event type.\n * @param callback The event listener.\n * @param capture The capture flag.\n * @deprecated Use `{capture: boolean}` object instead of a boolean value.\n */\n removeEventListener(\n type: string,\n callback: EventTarget.FallbackEventListener<this, TMode>,\n capture: boolean,\n ): void\n\n // Implementation\n removeEventListener<T extends string & keyof TEventMap>(\n type0: T,\n callback0?: EventTarget.EventListener<this, TEventMap[T]> | null,\n options0?: boolean | EventTarget.Options,\n ): void {\n const listenerMap = $(this)\n const { callback, capture, type } = normalizeOptions(\n type0,\n callback0,\n options0,\n )\n const list = listenerMap[type]\n\n if (callback != null && list) {\n removeListener(list, callback, capture)\n }\n }\n\n /**\n * Dispatch an event.\n * @param event The `Event` object to dispatch.\n */\n dispatchEvent<T extends string & keyof TEventMap>(\n event: EventTarget.EventData<TEventMap, TMode, T>,\n ): boolean\n\n /**\n * Dispatch an event.\n * @param event The `Event` object to dispatch.\n */\n dispatchEvent(event: EventTarget.FallbackEvent<TMode>): boolean\n\n // Implementation\n dispatchEvent(\n e:\n | EventTarget.EventData<TEventMap, TMode, string>\n | EventTarget.FallbackEvent<TMode>,\n ): boolean {\n const list = $(this)[String(e.type)]\n if (list == null) {\n return true\n }\n\n const event = e instanceof Event ? e : EventWrapper.wrap(e)\n const eventData = getEventInternalData(event, \"event\")\n if (eventData.dispatchFlag) {\n throw createInvalidStateError(\"This event has been in dispatching.\")\n }\n\n eventData.dispatchFlag = true\n eventData.target = eventData.currentTarget = this\n\n if (!eventData.stopPropagationFlag) {\n const { cow, listeners } = list\n\n // Set copy-on-write flag.\n list.cow = true\n\n // Call listeners.\n for (let i = 0; i < listeners.length; ++i) {\n const listener = listeners[i]\n\n // Skip if removed.\n if (isRemoved(listener)) {\n continue\n }\n\n // Remove this listener if has the `once` flag.\n if (isOnce(listener) && removeListenerAt(list, i, !cow)) {\n // Because this listener was removed, the next index is the\n // same as the current value.\n i -= 1\n }\n\n // Call this listener with the `passive` flag.\n eventData.inPassiveListenerFlag = isPassive(listener)\n invokeCallback(listener, this, event)\n eventData.inPassiveListenerFlag = false\n\n // Stop if the `event.stopImmediatePropagation()` method was called.\n if (eventData.stopImmediatePropagationFlag) {\n break\n }\n }\n\n // Restore copy-on-write flag.\n if (!cow) {\n list.cow = false\n }\n }\n\n eventData.target = null\n eventData.currentTarget = null\n eventData.stopImmediatePropagationFlag = false\n eventData.stopPropagationFlag = false\n eventData.dispatchFlag = false\n\n return !eventData.canceledFlag\n }\n}\n\nexport namespace EventTarget {\n /**\n * The event listener.\n */\n export type EventListener<\n TEventTarget extends EventTarget<any, any>,\n TEvent extends Event\n > = CallbackFunction<TEventTarget, TEvent> | CallbackObject<TEvent>\n\n /**\n * The event listener function.\n */\n export interface CallbackFunction<\n TEventTarget extends EventTarget<any, any>,\n TEvent extends Event\n > {\n (this: TEventTarget, event: TEvent): void\n }\n\n /**\n * The event listener object.\n * @see https://dom.spec.whatwg.org/#callbackdef-eventlistener\n */\n export interface CallbackObject<TEvent extends Event> {\n handleEvent(event: TEvent): void\n }\n\n /**\n * The common options for both `addEventListener` and `removeEventListener` methods.\n * @see https://dom.spec.whatwg.org/#dictdef-eventlisteneroptions\n */\n export interface Options {\n capture?: boolean\n }\n\n /**\n * The options for the `addEventListener` methods.\n * @see https://dom.spec.whatwg.org/#dictdef-addeventlisteneroptions\n */\n export interface AddOptions extends Options {\n passive?: boolean\n once?: boolean\n signal?: AbortSignal | null | undefined\n }\n\n /**\n * The abort signal.\n * @see https://dom.spec.whatwg.org/#abortsignal\n */\n export interface AbortSignal extends EventTarget<{ abort: Event }> {\n readonly aborted: boolean\n onabort: CallbackFunction<this, Event> | null\n }\n\n /**\n * The event data to dispatch in strict mode.\n */\n export type EventData<\n TEventMap extends Record<string, Event>,\n TMode extends \"standard\" | \"strict\",\n TEventType extends string\n > = TMode extends \"strict\"\n ? IsValidEventMap<TEventMap> extends true\n ? ExplicitType<TEventType> &\n Omit<TEventMap[TEventType], keyof Event> &\n Partial<Omit<Event, \"type\">>\n : never\n : never\n\n /**\n * Define explicit `type` property if `T` is a string literal.\n * Otherwise, never.\n */\n export type ExplicitType<T extends string> = string extends T\n ? never\n : { readonly type: T }\n\n /**\n * The event listener type in standard mode.\n * Otherwise, never.\n */\n export type FallbackEventListener<\n TEventTarget extends EventTarget<any, any>,\n TMode extends \"standard\" | \"strict\"\n > = TMode extends \"standard\"\n ? EventListener<TEventTarget, Event> | null | undefined\n : never\n\n /**\n * The event type in standard mode.\n * Otherwise, never.\n */\n export type FallbackEvent<\n TMode extends \"standard\" | \"strict\"\n > = TMode extends \"standard\" ? Event : never\n\n /**\n * Check if given event map is valid.\n * It's valid if the keys of the event map are narrower than `string`.\n */\n export type IsValidEventMap<T> = string extends keyof T ? false : true\n}\n\nexport { $ as getEventTargetInternalData }\n\n//------------------------------------------------------------------------------\n// Helpers\n//------------------------------------------------------------------------------\n\n/**\n * Internal data for EventTarget\n */\ntype EventTargetInternalData = ListenerListMap\n\n/**\n * Internal d