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