-
Notifications
You must be signed in to change notification settings - Fork 15
/
index.js
133 lines (122 loc) · 4.12 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
const root =
(typeof globalThis !== "undefined" && globalThis) ||
(typeof self !== "undefined" && self) ||
(typeof global !== "undefined" && global);
const shouldPolyfillEvent = (function() {
try {
new root.Event("");
} catch (error) {
return true;
}
return false;
})();
const shouldPolyfillEventTarget = (function() {
try {
new root.EventTarget();
} catch (error) {
return true;
}
return false;
})();
if (shouldPolyfillEvent) {
root.Event = (function () {
function Event(type, options) {
this.bubbles = !!options && !!options.bubbles;
this.cancelable = !!options && !!options.cancelable;
this.composed = !!options && !!options.composed;
this.type = type;
}
return Event;
})();
}
if (shouldPolyfillEventTarget) {
root.EventTarget = (function () {
function EventTarget() {
this.__listeners = new Map();
}
EventTarget.prototype = Object.create(Object.prototype);
EventTarget.prototype.addEventListener = function (
type,
listener,
options
) {
if (arguments.length < 2) {
throw new TypeError(
"TypeError: Failed to execute 'addEventListener' on 'EventTarget': 2 arguments required, but only " + arguments.length + " present."
);
}
const __listeners = this.__listeners;
const actualType = type.toString();
if (!__listeners.has(actualType)) {
__listeners.set(actualType, new Map());
}
const listenersForType = __listeners.get(actualType);
if (!listenersForType.has(listener)) {
// Any given listener is only registered once
listenersForType.set(listener, options);
}
};
EventTarget.prototype.removeEventListener = function (
type,
listener,
_options
) {
if (arguments.length < 2) {
throw new TypeError(
"TypeError: Failed to execute 'addEventListener' on 'EventTarget': 2 arguments required, but only " + arguments.length + " present."
);
}
const __listeners = this.__listeners;
const actualType = type.toString();
if (__listeners.has(actualType)) {
const listenersForType = __listeners.get(actualType);
if (listenersForType.has(listener)) {
listenersForType.delete(listener);
}
}
};
EventTarget.prototype.dispatchEvent = function (event) {
if (!(event instanceof Event)) {
throw new TypeError(
"Failed to execute 'dispatchEvent' on 'EventTarget': parameter 1 is not of type 'Event'."
);
}
const type = event.type;
const __listeners = this.__listeners;
const listenersForType = __listeners.get(type);
if (listenersForType) {
for (var listnerEntry of listenersForType.entries()) {
const listener = listnerEntry[0];
const options = listnerEntry[1];
try {
if (typeof listener === "function") {
// Listener functions must be executed with the EventTarget as the `this` context.
listener.call(this, event);
} else if (listener && typeof listener.handleEvent === "function") {
// Listener objects have their handleEvent method called, if they have one
listener.handleEvent(event);
}
} catch (err) {
// We need to report the error to the global error handling event,
// but we do not want to break the loop that is executing the events.
// Unfortunately, this is the best we can do, which isn't great, because the
// native EventTarget will actually do this synchronously before moving to the next
// event in the loop.
setTimeout(() => {
throw err;
});
}
if (options && options.once) {
// If this was registered with { once: true }, we need
// to remove it now.
listenersForType.delete(listener);
}
}
}
// Since there are no cancellable events on a base EventTarget,
// this should always return true.
return true;
};
return EventTarget;
})();
}