Skip to content

Commit 1d9a6c8

Browse files
authored
Merge pull request #1180 from Patternslib/scrum-1647--checklist-performance
Fix performance problems with pat-checklist
2 parents 318b190 + 69831f3 commit 1d9a6c8

File tree

7 files changed

+458
-66
lines changed

7 files changed

+458
-66
lines changed

src/core/events.js

Lines changed: 51 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1+
import utils from "./utils";
2+
13
// Event related methods and event factories
24

35
// Event listener registration for easy-to-remove event listeners.
46
// once Safari supports the ``signal`` option for addEventListener we can abort
57
// event handlers by calling AbortController.abort().
6-
export const event_listener_map = {};
8+
export const event_listener_map = new Map();
79

810
/**
911
* Add an event listener to a DOM element under a unique id.
@@ -23,48 +25,72 @@ const add_event_listener = (el, event_type, id, cb, opts = {}) => {
2325
remove_event_listener(el, id); // do not register one listener twice.
2426

2527
// Create event_listener_map entry if not existent.
26-
if (!event_listener_map[el]) {
27-
event_listener_map[el] = {};
28+
if (!event_listener_map.has(el)) {
29+
event_listener_map.set(el, new Map());
2830
}
2931
let _cb = cb;
3032
if (opts?.once === true) {
3133
// For `once` events, also remove the entry from the event_listener_map.
3234
_cb = (e) => {
33-
delete event_listener_map[el][id];
35+
event_listener_map.get(el)?.delete(id);
3436
cb(e);
3537
};
3638
}
3739
// Only `capture` option is necessary for `removeEventListener`.
38-
event_listener_map[el][id] = [event_type, _cb, opts.capture ? opts : undefined];
40+
event_listener_map
41+
.get(el)
42+
.set(id, [event_type, _cb, opts.capture ? opts : undefined]);
3943
el.addEventListener(event_type, _cb, opts);
4044
};
4145

4246
/**
4347
* Remove an event listener from a DOM element under a unique id.
4448
*
45-
* @param {DOM Node} el - The element to register the event for.
46-
* @param {string} id - A unique id under which the event is registered.
49+
* If an element and id are given, the event listeners for the given element matching the id are removed.
50+
* If an element but no id is given, all event listeners for that element are removed.
51+
* If an id but no element is given, all event listeners for any element matching the id are removed.
52+
* If no element and no id are given, all event listeners are removed.
53+
*
54+
* The id can be a wildcard string, e.g. `test-*-event`, which would match any
55+
* event which starts with "test-" and ends with "-event". The wildcard "*" can
56+
* be anywhere in the string and also be used multiple times. If no wildcard is
57+
* present the search string is used for an exact match.
58+
*
59+
* @param {DOM Node} [el] - The element to register the event for.
60+
* @param {string} [id] - A unique id under which the event is registered.
61+
* Can be a wildcard string.
4762
*
4863
*/
4964
const remove_event_listener = (el, id) => {
50-
if (!el?.removeEventListener) {
51-
return; // nothing to do.
52-
}
53-
const el_events = event_listener_map[el];
54-
if (!el_events) {
55-
return;
56-
}
57-
let entries;
58-
if (id) {
59-
// remove event listener with specific id
60-
const entry = el_events[id];
61-
entries = entry ? [entry] : [];
62-
} else {
63-
// remove all event listeners of element
64-
entries = Object.entries(el_events);
65-
}
66-
for (const entry of entries || []) {
67-
el.removeEventListener(entry[0], entry[1], entry[2]);
65+
const els = el ? [el] : event_listener_map.keys();
66+
for (const el of els) {
67+
if (!el?.removeEventListener) {
68+
return; // nothing to do.
69+
}
70+
const el_events = event_listener_map.get(el);
71+
if (!el_events) {
72+
return;
73+
}
74+
let entries;
75+
if (id) {
76+
// remove event listener with matching id
77+
entries = [...el_events.entries()].filter((entry) =>
78+
utils.regexp_from_wildcard(id).test(entry[0])
79+
);
80+
} else {
81+
// remove all event listeners of element
82+
entries = el_events.entries();
83+
}
84+
for (const entry of entries || []) {
85+
// Remove event listener
86+
el.removeEventListener(entry[1][0], entry[1][1], entry[1][2]);
87+
// Delete entry from event_listener_map
88+
event_listener_map.get(el).delete(entry[0]);
89+
// Delete element from event_listener_map if no more events are registered.
90+
if (!event_listener_map.get(el).size) {
91+
event_listener_map.delete(el);
92+
}
93+
}
6894
}
6995
};
7096

0 commit comments

Comments
 (0)