@@ -102,6 +102,64 @@ const create_from_string = (string) => {
102
102
return div . firstChild ;
103
103
} ;
104
104
105
+ // Event listener registration for easy-to-remove event listeners.
106
+ // once Safari supports the ``signal`` option for addEventListener we can abort
107
+ // event handlers by calling AbortController.abort().
108
+ const event_listener_map = { } ;
109
+
110
+ /**
111
+ * Add an event listener to a DOM element under a unique id.
112
+ * If a event is registered under the same id for the same element, the old hander is removed first.
113
+ *
114
+ * @param {DOM Node } el - The element to register the event for.
115
+ * @param {string } event_type - The event type to listen for.
116
+ * @param {string } id - A unique id under which the event is registered.
117
+ * @param {function } cb - The event handler / callback function.
118
+ * @param {Object } opts - Options for the addEventListener API.
119
+ *
120
+ */
121
+ const add_event_listener = ( el , event_type , id , cb , opts = { } ) => {
122
+ if ( ! el ?. addEventListener ) {
123
+ return ; // nothing to do.
124
+ }
125
+ remove_event_listener ( el , id ) ; // do not register one listener twice.
126
+
127
+ if ( ! event_listener_map [ el ] ) {
128
+ event_listener_map [ el ] = { } ;
129
+ }
130
+ event_listener_map [ el ] [ id ] = [ event_type , cb , opts . capture ? opts : undefined ] ; // prettier-ignore
131
+ el . addEventListener ( event_type , cb , opts ) ;
132
+ } ;
133
+
134
+ /**
135
+ * Remove an event listener from a DOM element under a unique id.
136
+ *
137
+ * @param {DOM Node } el - The element to register the event for.
138
+ * @param {string } id - A unique id under which the event is registered.
139
+ *
140
+ */
141
+ const remove_event_listener = ( el , id ) => {
142
+ if ( ! el ?. removeEventListener ) {
143
+ return ; // nothing to do.
144
+ }
145
+ const el_events = event_listener_map [ el ] ;
146
+ if ( ! el_events ) {
147
+ return ;
148
+ }
149
+ let entries ;
150
+ if ( id ) {
151
+ // remove event listener with specific id
152
+ const entry = el_events [ id ] ;
153
+ entries = entry ? [ entry ] : [ ] ;
154
+ } else {
155
+ // remove all event listeners of element
156
+ entries = Object . entries ( el_events ) ;
157
+ }
158
+ for ( const entry of entries || [ ] ) {
159
+ el . removeEventListener ( entry [ 0 ] , entry [ 1 ] , entry [ 2 ] ) ;
160
+ }
161
+ } ;
162
+
105
163
const dom = {
106
164
toNodeArray : toNodeArray ,
107
165
querySelectorAllAndMe : querySelectorAllAndMe ,
@@ -113,6 +171,8 @@ const dom = {
113
171
get_parents : get_parents ,
114
172
is_visible : is_visible ,
115
173
create_from_string : create_from_string ,
174
+ add_event_listener : add_event_listener ,
175
+ remove_event_listener : remove_event_listener ,
116
176
} ;
117
177
118
178
export default dom ;
0 commit comments