buddy

node MVC discord bot
Log | Files | Refs | README

event-target-shim.mjs (23411B)


      1 /**
      2  * @author Toru Nagashima <https://github.com/mysticatea>
      3  * @copyright 2015 Toru Nagashima. All rights reserved.
      4  * See LICENSE file in root directory for full license.
      5  */
      6 /**
      7  * @typedef {object} PrivateData
      8  * @property {EventTarget} eventTarget The event target.
      9  * @property {{type:string}} event The original event object.
     10  * @property {number} eventPhase The current event phase.
     11  * @property {EventTarget|null} currentTarget The current event target.
     12  * @property {boolean} canceled The flag to prevent default.
     13  * @property {boolean} stopped The flag to stop propagation.
     14  * @property {boolean} immediateStopped The flag to stop propagation immediately.
     15  * @property {Function|null} passiveListener The listener if the current listener is passive. Otherwise this is null.
     16  * @property {number} timeStamp The unix time.
     17  * @private
     18  */
     19 
     20 /**
     21  * Private data for event wrappers.
     22  * @type {WeakMap<Event, PrivateData>}
     23  * @private
     24  */
     25 const privateData = new WeakMap();
     26 
     27 /**
     28  * Cache for wrapper classes.
     29  * @type {WeakMap<Object, Function>}
     30  * @private
     31  */
     32 const wrappers = new WeakMap();
     33 
     34 /**
     35  * Get private data.
     36  * @param {Event} event The event object to get private data.
     37  * @returns {PrivateData} The private data of the event.
     38  * @private
     39  */
     40 function pd(event) {
     41     const retv = privateData.get(event);
     42     console.assert(
     43         retv != null,
     44         "'this' is expected an Event object, but got",
     45         event
     46     );
     47     return retv
     48 }
     49 
     50 /**
     51  * https://dom.spec.whatwg.org/#set-the-canceled-flag
     52  * @param data {PrivateData} private data.
     53  */
     54 function setCancelFlag(data) {
     55     if (data.passiveListener != null) {
     56         if (
     57             typeof console !== "undefined" &&
     58             typeof console.error === "function"
     59         ) {
     60             console.error(
     61                 "Unable to preventDefault inside passive event listener invocation.",
     62                 data.passiveListener
     63             );
     64         }
     65         return
     66     }
     67     if (!data.event.cancelable) {
     68         return
     69     }
     70 
     71     data.canceled = true;
     72     if (typeof data.event.preventDefault === "function") {
     73         data.event.preventDefault();
     74     }
     75 }
     76 
     77 /**
     78  * @see https://dom.spec.whatwg.org/#interface-event
     79  * @private
     80  */
     81 /**
     82  * The event wrapper.
     83  * @constructor
     84  * @param {EventTarget} eventTarget The event target of this dispatching.
     85  * @param {Event|{type:string}} event The original event to wrap.
     86  */
     87 function Event(eventTarget, event) {
     88     privateData.set(this, {
     89         eventTarget,
     90         event,
     91         eventPhase: 2,
     92         currentTarget: eventTarget,
     93         canceled: false,
     94         stopped: false,
     95         immediateStopped: false,
     96         passiveListener: null,
     97         timeStamp: event.timeStamp || Date.now(),
     98     });
     99 
    100     // https://heycam.github.io/webidl/#Unforgeable
    101     Object.defineProperty(this, "isTrusted", { value: false, enumerable: true });
    102 
    103     // Define accessors
    104     const keys = Object.keys(event);
    105     for (let i = 0; i < keys.length; ++i) {
    106         const key = keys[i];
    107         if (!(key in this)) {
    108             Object.defineProperty(this, key, defineRedirectDescriptor(key));
    109         }
    110     }
    111 }
    112 
    113 // Should be enumerable, but class methods are not enumerable.
    114 Event.prototype = {
    115     /**
    116      * The type of this event.
    117      * @type {string}
    118      */
    119     get type() {
    120         return pd(this).event.type
    121     },
    122 
    123     /**
    124      * The target of this event.
    125      * @type {EventTarget}
    126      */
    127     get target() {
    128         return pd(this).eventTarget
    129     },
    130 
    131     /**
    132      * The target of this event.
    133      * @type {EventTarget}
    134      */
    135     get currentTarget() {
    136         return pd(this).currentTarget
    137     },
    138 
    139     /**
    140      * @returns {EventTarget[]} The composed path of this event.
    141      */
    142     composedPath() {
    143         const currentTarget = pd(this).currentTarget;
    144         if (currentTarget == null) {
    145             return []
    146         }
    147         return [currentTarget]
    148     },
    149 
    150     /**
    151      * Constant of NONE.
    152      * @type {number}
    153      */
    154     get NONE() {
    155         return 0
    156     },
    157 
    158     /**
    159      * Constant of CAPTURING_PHASE.
    160      * @type {number}
    161      */
    162     get CAPTURING_PHASE() {
    163         return 1
    164     },
    165 
    166     /**
    167      * Constant of AT_TARGET.
    168      * @type {number}
    169      */
    170     get AT_TARGET() {
    171         return 2
    172     },
    173 
    174     /**
    175      * Constant of BUBBLING_PHASE.
    176      * @type {number}
    177      */
    178     get BUBBLING_PHASE() {
    179         return 3
    180     },
    181 
    182     /**
    183      * The target of this event.
    184      * @type {number}
    185      */
    186     get eventPhase() {
    187         return pd(this).eventPhase
    188     },
    189 
    190     /**
    191      * Stop event bubbling.
    192      * @returns {void}
    193      */
    194     stopPropagation() {
    195         const data = pd(this);
    196 
    197         data.stopped = true;
    198         if (typeof data.event.stopPropagation === "function") {
    199             data.event.stopPropagation();
    200         }
    201     },
    202 
    203     /**
    204      * Stop event bubbling.
    205      * @returns {void}
    206      */
    207     stopImmediatePropagation() {
    208         const data = pd(this);
    209 
    210         data.stopped = true;
    211         data.immediateStopped = true;
    212         if (typeof data.event.stopImmediatePropagation === "function") {
    213             data.event.stopImmediatePropagation();
    214         }
    215     },
    216 
    217     /**
    218      * The flag to be bubbling.
    219      * @type {boolean}
    220      */
    221     get bubbles() {
    222         return Boolean(pd(this).event.bubbles)
    223     },
    224 
    225     /**
    226      * The flag to be cancelable.
    227      * @type {boolean}
    228      */
    229     get cancelable() {
    230         return Boolean(pd(this).event.cancelable)
    231     },
    232 
    233     /**
    234      * Cancel this event.
    235      * @returns {void}
    236      */
    237     preventDefault() {
    238         setCancelFlag(pd(this));
    239     },
    240 
    241     /**
    242      * The flag to indicate cancellation state.
    243      * @type {boolean}
    244      */
    245     get defaultPrevented() {
    246         return pd(this).canceled
    247     },
    248 
    249     /**
    250      * The flag to be composed.
    251      * @type {boolean}
    252      */
    253     get composed() {
    254         return Boolean(pd(this).event.composed)
    255     },
    256 
    257     /**
    258      * The unix time of this event.
    259      * @type {number}
    260      */
    261     get timeStamp() {
    262         return pd(this).timeStamp
    263     },
    264 
    265     /**
    266      * The target of this event.
    267      * @type {EventTarget}
    268      * @deprecated
    269      */
    270     get srcElement() {
    271         return pd(this).eventTarget
    272     },
    273 
    274     /**
    275      * The flag to stop event bubbling.
    276      * @type {boolean}
    277      * @deprecated
    278      */
    279     get cancelBubble() {
    280         return pd(this).stopped
    281     },
    282     set cancelBubble(value) {
    283         if (!value) {
    284             return
    285         }
    286         const data = pd(this);
    287 
    288         data.stopped = true;
    289         if (typeof data.event.cancelBubble === "boolean") {
    290             data.event.cancelBubble = true;
    291         }
    292     },
    293 
    294     /**
    295      * The flag to indicate cancellation state.
    296      * @type {boolean}
    297      * @deprecated
    298      */
    299     get returnValue() {
    300         return !pd(this).canceled
    301     },
    302     set returnValue(value) {
    303         if (!value) {
    304             setCancelFlag(pd(this));
    305         }
    306     },
    307 
    308     /**
    309      * Initialize this event object. But do nothing under event dispatching.
    310      * @param {string} type The event type.
    311      * @param {boolean} [bubbles=false] The flag to be possible to bubble up.
    312      * @param {boolean} [cancelable=false] The flag to be possible to cancel.
    313      * @deprecated
    314      */
    315     initEvent() {
    316         // Do nothing.
    317     },
    318 };
    319 
    320 // `constructor` is not enumerable.
    321 Object.defineProperty(Event.prototype, "constructor", {
    322     value: Event,
    323     configurable: true,
    324     writable: true,
    325 });
    326 
    327 // Ensure `event instanceof window.Event` is `true`.
    328 if (typeof window !== "undefined" && typeof window.Event !== "undefined") {
    329     Object.setPrototypeOf(Event.prototype, window.Event.prototype);
    330 
    331     // Make association for wrappers.
    332     wrappers.set(window.Event.prototype, Event);
    333 }
    334 
    335 /**
    336  * Get the property descriptor to redirect a given property.
    337  * @param {string} key Property name to define property descriptor.
    338  * @returns {PropertyDescriptor} The property descriptor to redirect the property.
    339  * @private
    340  */
    341 function defineRedirectDescriptor(key) {
    342     return {
    343         get() {
    344             return pd(this).event[key]
    345         },
    346         set(value) {
    347             pd(this).event[key] = value;
    348         },
    349         configurable: true,
    350         enumerable: true,
    351     }
    352 }
    353 
    354 /**
    355  * Get the property descriptor to call a given method property.
    356  * @param {string} key Property name to define property descriptor.
    357  * @returns {PropertyDescriptor} The property descriptor to call the method property.
    358  * @private
    359  */
    360 function defineCallDescriptor(key) {
    361     return {
    362         value() {
    363             const event = pd(this).event;
    364             return event[key].apply(event, arguments)
    365         },
    366         configurable: true,
    367         enumerable: true,
    368     }
    369 }
    370 
    371 /**
    372  * Define new wrapper class.
    373  * @param {Function} BaseEvent The base wrapper class.
    374  * @param {Object} proto The prototype of the original event.
    375  * @returns {Function} The defined wrapper class.
    376  * @private
    377  */
    378 function defineWrapper(BaseEvent, proto) {
    379     const keys = Object.keys(proto);
    380     if (keys.length === 0) {
    381         return BaseEvent
    382     }
    383 
    384     /** CustomEvent */
    385     function CustomEvent(eventTarget, event) {
    386         BaseEvent.call(this, eventTarget, event);
    387     }
    388 
    389     CustomEvent.prototype = Object.create(BaseEvent.prototype, {
    390         constructor: { value: CustomEvent, configurable: true, writable: true },
    391     });
    392 
    393     // Define accessors.
    394     for (let i = 0; i < keys.length; ++i) {
    395         const key = keys[i];
    396         if (!(key in BaseEvent.prototype)) {
    397             const descriptor = Object.getOwnPropertyDescriptor(proto, key);
    398             const isFunc = typeof descriptor.value === "function";
    399             Object.defineProperty(
    400                 CustomEvent.prototype,
    401                 key,
    402                 isFunc
    403                     ? defineCallDescriptor(key)
    404                     : defineRedirectDescriptor(key)
    405             );
    406         }
    407     }
    408 
    409     return CustomEvent
    410 }
    411 
    412 /**
    413  * Get the wrapper class of a given prototype.
    414  * @param {Object} proto The prototype of the original event to get its wrapper.
    415  * @returns {Function} The wrapper class.
    416  * @private
    417  */
    418 function getWrapper(proto) {
    419     if (proto == null || proto === Object.prototype) {
    420         return Event
    421     }
    422 
    423     let wrapper = wrappers.get(proto);
    424     if (wrapper == null) {
    425         wrapper = defineWrapper(getWrapper(Object.getPrototypeOf(proto)), proto);
    426         wrappers.set(proto, wrapper);
    427     }
    428     return wrapper
    429 }
    430 
    431 /**
    432  * Wrap a given event to management a dispatching.
    433  * @param {EventTarget} eventTarget The event target of this dispatching.
    434  * @param {Object} event The event to wrap.
    435  * @returns {Event} The wrapper instance.
    436  * @private
    437  */
    438 function wrapEvent(eventTarget, event) {
    439     const Wrapper = getWrapper(Object.getPrototypeOf(event));
    440     return new Wrapper(eventTarget, event)
    441 }
    442 
    443 /**
    444  * Get the immediateStopped flag of a given event.
    445  * @param {Event} event The event to get.
    446  * @returns {boolean} The flag to stop propagation immediately.
    447  * @private
    448  */
    449 function isStopped(event) {
    450     return pd(event).immediateStopped
    451 }
    452 
    453 /**
    454  * Set the current event phase of a given event.
    455  * @param {Event} event The event to set current target.
    456  * @param {number} eventPhase New event phase.
    457  * @returns {void}
    458  * @private
    459  */
    460 function setEventPhase(event, eventPhase) {
    461     pd(event).eventPhase = eventPhase;
    462 }
    463 
    464 /**
    465  * Set the current target of a given event.
    466  * @param {Event} event The event to set current target.
    467  * @param {EventTarget|null} currentTarget New current target.
    468  * @returns {void}
    469  * @private
    470  */
    471 function setCurrentTarget(event, currentTarget) {
    472     pd(event).currentTarget = currentTarget;
    473 }
    474 
    475 /**
    476  * Set a passive listener of a given event.
    477  * @param {Event} event The event to set current target.
    478  * @param {Function|null} passiveListener New passive listener.
    479  * @returns {void}
    480  * @private
    481  */
    482 function setPassiveListener(event, passiveListener) {
    483     pd(event).passiveListener = passiveListener;
    484 }
    485 
    486 /**
    487  * @typedef {object} ListenerNode
    488  * @property {Function} listener
    489  * @property {1|2|3} listenerType
    490  * @property {boolean} passive
    491  * @property {boolean} once
    492  * @property {ListenerNode|null} next
    493  * @private
    494  */
    495 
    496 /**
    497  * @type {WeakMap<object, Map<string, ListenerNode>>}
    498  * @private
    499  */
    500 const listenersMap = new WeakMap();
    501 
    502 // Listener types
    503 const CAPTURE = 1;
    504 const BUBBLE = 2;
    505 const ATTRIBUTE = 3;
    506 
    507 /**
    508  * Check whether a given value is an object or not.
    509  * @param {any} x The value to check.
    510  * @returns {boolean} `true` if the value is an object.
    511  */
    512 function isObject(x) {
    513     return x !== null && typeof x === "object" //eslint-disable-line no-restricted-syntax
    514 }
    515 
    516 /**
    517  * Get listeners.
    518  * @param {EventTarget} eventTarget The event target to get.
    519  * @returns {Map<string, ListenerNode>} The listeners.
    520  * @private
    521  */
    522 function getListeners(eventTarget) {
    523     const listeners = listenersMap.get(eventTarget);
    524     if (listeners == null) {
    525         throw new TypeError(
    526             "'this' is expected an EventTarget object, but got another value."
    527         )
    528     }
    529     return listeners
    530 }
    531 
    532 /**
    533  * Get the property descriptor for the event attribute of a given event.
    534  * @param {string} eventName The event name to get property descriptor.
    535  * @returns {PropertyDescriptor} The property descriptor.
    536  * @private
    537  */
    538 function defineEventAttributeDescriptor(eventName) {
    539     return {
    540         get() {
    541             const listeners = getListeners(this);
    542             let node = listeners.get(eventName);
    543             while (node != null) {
    544                 if (node.listenerType === ATTRIBUTE) {
    545                     return node.listener
    546                 }
    547                 node = node.next;
    548             }
    549             return null
    550         },
    551 
    552         set(listener) {
    553             if (typeof listener !== "function" && !isObject(listener)) {
    554                 listener = null; // eslint-disable-line no-param-reassign
    555             }
    556             const listeners = getListeners(this);
    557 
    558             // Traverse to the tail while removing old value.
    559             let prev = null;
    560             let node = listeners.get(eventName);
    561             while (node != null) {
    562                 if (node.listenerType === ATTRIBUTE) {
    563                     // Remove old value.
    564                     if (prev !== null) {
    565                         prev.next = node.next;
    566                     } else if (node.next !== null) {
    567                         listeners.set(eventName, node.next);
    568                     } else {
    569                         listeners.delete(eventName);
    570                     }
    571                 } else {
    572                     prev = node;
    573                 }
    574 
    575                 node = node.next;
    576             }
    577 
    578             // Add new value.
    579             if (listener !== null) {
    580                 const newNode = {
    581                     listener,
    582                     listenerType: ATTRIBUTE,
    583                     passive: false,
    584                     once: false,
    585                     next: null,
    586                 };
    587                 if (prev === null) {
    588                     listeners.set(eventName, newNode);
    589                 } else {
    590                     prev.next = newNode;
    591                 }
    592             }
    593         },
    594         configurable: true,
    595         enumerable: true,
    596     }
    597 }
    598 
    599 /**
    600  * Define an event attribute (e.g. `eventTarget.onclick`).
    601  * @param {Object} eventTargetPrototype The event target prototype to define an event attrbite.
    602  * @param {string} eventName The event name to define.
    603  * @returns {void}
    604  */
    605 function defineEventAttribute(eventTargetPrototype, eventName) {
    606     Object.defineProperty(
    607         eventTargetPrototype,
    608         `on${eventName}`,
    609         defineEventAttributeDescriptor(eventName)
    610     );
    611 }
    612 
    613 /**
    614  * Define a custom EventTarget with event attributes.
    615  * @param {string[]} eventNames Event names for event attributes.
    616  * @returns {EventTarget} The custom EventTarget.
    617  * @private
    618  */
    619 function defineCustomEventTarget(eventNames) {
    620     /** CustomEventTarget */
    621     function CustomEventTarget() {
    622         EventTarget.call(this);
    623     }
    624 
    625     CustomEventTarget.prototype = Object.create(EventTarget.prototype, {
    626         constructor: {
    627             value: CustomEventTarget,
    628             configurable: true,
    629             writable: true,
    630         },
    631     });
    632 
    633     for (let i = 0; i < eventNames.length; ++i) {
    634         defineEventAttribute(CustomEventTarget.prototype, eventNames[i]);
    635     }
    636 
    637     return CustomEventTarget
    638 }
    639 
    640 /**
    641  * EventTarget.
    642  *
    643  * - This is constructor if no arguments.
    644  * - This is a function which returns a CustomEventTarget constructor if there are arguments.
    645  *
    646  * For example:
    647  *
    648  *     class A extends EventTarget {}
    649  *     class B extends EventTarget("message") {}
    650  *     class C extends EventTarget("message", "error") {}
    651  *     class D extends EventTarget(["message", "error"]) {}
    652  */
    653 function EventTarget() {
    654     /*eslint-disable consistent-return */
    655     if (this instanceof EventTarget) {
    656         listenersMap.set(this, new Map());
    657         return
    658     }
    659     if (arguments.length === 1 && Array.isArray(arguments[0])) {
    660         return defineCustomEventTarget(arguments[0])
    661     }
    662     if (arguments.length > 0) {
    663         const types = new Array(arguments.length);
    664         for (let i = 0; i < arguments.length; ++i) {
    665             types[i] = arguments[i];
    666         }
    667         return defineCustomEventTarget(types)
    668     }
    669     throw new TypeError("Cannot call a class as a function")
    670     /*eslint-enable consistent-return */
    671 }
    672 
    673 // Should be enumerable, but class methods are not enumerable.
    674 EventTarget.prototype = {
    675     /**
    676      * Add a given listener to this event target.
    677      * @param {string} eventName The event name to add.
    678      * @param {Function} listener The listener to add.
    679      * @param {boolean|{capture?:boolean,passive?:boolean,once?:boolean}} [options] The options for this listener.
    680      * @returns {void}
    681      */
    682     addEventListener(eventName, listener, options) {
    683         if (listener == null) {
    684             return
    685         }
    686         if (typeof listener !== "function" && !isObject(listener)) {
    687             throw new TypeError("'listener' should be a function or an object.")
    688         }
    689 
    690         const listeners = getListeners(this);
    691         const optionsIsObj = isObject(options);
    692         const capture = optionsIsObj
    693             ? Boolean(options.capture)
    694             : Boolean(options);
    695         const listenerType = capture ? CAPTURE : BUBBLE;
    696         const newNode = {
    697             listener,
    698             listenerType,
    699             passive: optionsIsObj && Boolean(options.passive),
    700             once: optionsIsObj && Boolean(options.once),
    701             next: null,
    702         };
    703 
    704         // Set it as the first node if the first node is null.
    705         let node = listeners.get(eventName);
    706         if (node === undefined) {
    707             listeners.set(eventName, newNode);
    708             return
    709         }
    710 
    711         // Traverse to the tail while checking duplication..
    712         let prev = null;
    713         while (node != null) {
    714             if (
    715                 node.listener === listener &&
    716                 node.listenerType === listenerType
    717             ) {
    718                 // Should ignore duplication.
    719                 return
    720             }
    721             prev = node;
    722             node = node.next;
    723         }
    724 
    725         // Add it.
    726         prev.next = newNode;
    727     },
    728 
    729     /**
    730      * Remove a given listener from this event target.
    731      * @param {string} eventName The event name to remove.
    732      * @param {Function} listener The listener to remove.
    733      * @param {boolean|{capture?:boolean,passive?:boolean,once?:boolean}} [options] The options for this listener.
    734      * @returns {void}
    735      */
    736     removeEventListener(eventName, listener, options) {
    737         if (listener == null) {
    738             return
    739         }
    740 
    741         const listeners = getListeners(this);
    742         const capture = isObject(options)
    743             ? Boolean(options.capture)
    744             : Boolean(options);
    745         const listenerType = capture ? CAPTURE : BUBBLE;
    746 
    747         let prev = null;
    748         let node = listeners.get(eventName);
    749         while (node != null) {
    750             if (
    751                 node.listener === listener &&
    752                 node.listenerType === listenerType
    753             ) {
    754                 if (prev !== null) {
    755                     prev.next = node.next;
    756                 } else if (node.next !== null) {
    757                     listeners.set(eventName, node.next);
    758                 } else {
    759                     listeners.delete(eventName);
    760                 }
    761                 return
    762             }
    763 
    764             prev = node;
    765             node = node.next;
    766         }
    767     },
    768 
    769     /**
    770      * Dispatch a given event.
    771      * @param {Event|{type:string}} event The event to dispatch.
    772      * @returns {boolean} `false` if canceled.
    773      */
    774     dispatchEvent(event) {
    775         if (event == null || typeof event.type !== "string") {
    776             throw new TypeError('"event.type" should be a string.')
    777         }
    778 
    779         // If listeners aren't registered, terminate.
    780         const listeners = getListeners(this);
    781         const eventName = event.type;
    782         let node = listeners.get(eventName);
    783         if (node == null) {
    784             return true
    785         }
    786 
    787         // Since we cannot rewrite several properties, so wrap object.
    788         const wrappedEvent = wrapEvent(this, event);
    789 
    790         // This doesn't process capturing phase and bubbling phase.
    791         // This isn't participating in a tree.
    792         let prev = null;
    793         while (node != null) {
    794             // Remove this listener if it's once
    795             if (node.once) {
    796                 if (prev !== null) {
    797                     prev.next = node.next;
    798                 } else if (node.next !== null) {
    799                     listeners.set(eventName, node.next);
    800                 } else {
    801                     listeners.delete(eventName);
    802                 }
    803             } else {
    804                 prev = node;
    805             }
    806 
    807             // Call this listener
    808             setPassiveListener(
    809                 wrappedEvent,
    810                 node.passive ? node.listener : null
    811             );
    812             if (typeof node.listener === "function") {
    813                 try {
    814                     node.listener.call(this, wrappedEvent);
    815                 } catch (err) {
    816                     if (
    817                         typeof console !== "undefined" &&
    818                         typeof console.error === "function"
    819                     ) {
    820                         console.error(err);
    821                     }
    822                 }
    823             } else if (
    824                 node.listenerType !== ATTRIBUTE &&
    825                 typeof node.listener.handleEvent === "function"
    826             ) {
    827                 node.listener.handleEvent(wrappedEvent);
    828             }
    829 
    830             // Break if `event.stopImmediatePropagation` was called.
    831             if (isStopped(wrappedEvent)) {
    832                 break
    833             }
    834 
    835             node = node.next;
    836         }
    837         setPassiveListener(wrappedEvent, null);
    838         setEventPhase(wrappedEvent, 0);
    839         setCurrentTarget(wrappedEvent, null);
    840 
    841         return !wrappedEvent.defaultPrevented
    842     },
    843 };
    844 
    845 // `constructor` is not enumerable.
    846 Object.defineProperty(EventTarget.prototype, "constructor", {
    847     value: EventTarget,
    848     configurable: true,
    849     writable: true,
    850 });
    851 
    852 // Ensure `eventTarget instanceof window.EventTarget` is `true`.
    853 if (
    854     typeof window !== "undefined" &&
    855     typeof window.EventTarget !== "undefined"
    856 ) {
    857     Object.setPrototypeOf(EventTarget.prototype, window.EventTarget.prototype);
    858 }
    859 
    860 export default EventTarget;
    861 export { defineEventAttribute, EventTarget };
    862 //# sourceMappingURL=event-target-shim.mjs.map