-
Notifications
You must be signed in to change notification settings - Fork 42
/
Copy pathevents.js
180 lines (162 loc) · 4.62 KB
/
events.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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
// Event related methods and event factories
// Event listener registration for easy-to-remove event listeners.
// once Safari supports the ``signal`` option for addEventListener we can abort
// event handlers by calling AbortController.abort().
const event_listener_map = {};
/**
* Add an event listener to a DOM element under a unique id.
* If a event is registered under the same id for the same element, the old handler is removed first.
*
* @param {DOM Node} el - The element to register the event for.
* @param {string} event_type - The event type to listen for.
* @param {string} id - A unique id under which the event is registered.
* @param {function} cb - The event handler / callback function.
* @param {Object} opts - Options for the addEventListener API.
*
*/
const add_event_listener = (el, event_type, id, cb, opts = {}) => {
if (!el?.addEventListener) {
return; // nothing to do.
}
remove_event_listener(el, id); // do not register one listener twice.
if (!event_listener_map[el]) {
event_listener_map[el] = {};
}
event_listener_map[el][id] = [event_type, cb, opts.capture ? opts : undefined]; // prettier-ignore
el.addEventListener(event_type, cb, opts);
};
/**
* Remove an event listener from a DOM element under a unique id.
*
* @param {DOM Node} el - The element to register the event for.
* @param {string} id - A unique id under which the event is registered.
*
*/
const remove_event_listener = (el, id) => {
if (!el?.removeEventListener) {
return; // nothing to do.
}
const el_events = event_listener_map[el];
if (!el_events) {
return;
}
let entries;
if (id) {
// remove event listener with specific id
const entry = el_events[id];
entries = entry ? [entry] : [];
} else {
// remove all event listeners of element
entries = Object.entries(el_events);
}
for (const entry of entries || []) {
el.removeEventListener(entry[0], entry[1], entry[2]);
}
};
/**
* Await an event to be thrown.
*
* Usage:
* await events.await_event(button, "click");
*
* @param {DOM Node} el - The element to listen on.
* @param {String} event_name - The event name to listen for.
*
* @returns {Promise} - Returns a Promise which can be used for ``await`` and which will be resolved when the event is throwm.
*
*/
const await_event = (el, event_name) => {
// See: https://stackoverflow.com/a/44746691/1337474
return new Promise((resolve) =>
el.addEventListener(event_name, resolve, { once: true })
);
};
/**
* Await pattern init.
*
* Usage:
* await events.await_pattern_init(PATTERN);
*
* @param {Pattern instance} pattern - The pattern instance.
*
* @returns {Promise} - Returns a Promise which can be used for ``await`` and which will be resolved when the event is throwm.
*
*/
const await_pattern_init = (pattern) => {
// See: https://stackoverflow.com/a/44746691/1337474
return new Promise((resolve) => pattern.one("init", resolve));
};
/**
* Event factories
*/
const blur_event = () => {
return new Event("blur", {
bubbles: false,
cancelable: false,
});
};
const click_event = () => {
return new Event("click", {
bubbles: true,
cancelable: true,
});
};
const change_event = () => {
return new Event("change", {
bubbles: true,
cancelable: false,
});
};
const focus_event = () => {
return new Event("focus", {
bubbles: false,
cancelable: false,
});
};
const input_event = () => {
return new Event("input", {
bubbles: true,
cancelable: false,
});
};
const mousedown_event = () => {
return new Event("mousedown", {
bubbles: true,
cancelable: true,
});
};
const mouseup_event = () => {
return new Event("mouseup", {
bubbles: true,
cancelable: true,
});
};
const scroll_event = () => {
return new Event("scroll", {
bubbles: true,
cancelable: false,
});
};
const submit_event = () => {
return new Event("submit", {
bubbles: true,
cancelable: true,
});
};
const events = {
add_event_listener: add_event_listener,
remove_event_listener: remove_event_listener,
await_event: await_event,
await_pattern_init: await_pattern_init,
blur_event: blur_event,
click_event: click_event,
change_event: change_event,
focus_event: focus_event,
input_event: input_event,
mousedown_event: mousedown_event,
mouseup_event: mouseup_event,
scroll_event: scroll_event,
submit_event: submit_event,
};
export default events;
export { events };