@@ -144,6 +144,7 @@ export function set_custom_element_data(node, prop, value) {
144
144
*/
145
145
export function set_attributes ( element , prev , next , lowercase_attributes , css_hash ) {
146
146
var has_hash = css_hash . length !== 0 ;
147
+ var current = prev || { } ;
147
148
148
149
for ( var key in prev ) {
149
150
if ( ! ( key in next ) ) {
@@ -167,14 +168,18 @@ export function set_attributes(element, prev, next, lowercase_attributes, css_ha
167
168
for ( const key in next ) {
168
169
// let instead of var because referenced in a closure
169
170
let value = next [ key ] ;
170
- if ( value === prev ?. [ key ] ) continue ;
171
+ var prev_value = current [ key ] ;
172
+ if ( value === prev_value ) continue ;
173
+
174
+ current [ key ] = value ;
171
175
172
176
var prefix = key [ 0 ] + key [ 1 ] ; // this is faster than key.slice(0, 2)
173
177
if ( prefix === '$$' ) continue ;
174
178
175
179
if ( prefix === 'on' ) {
176
180
/** @type {{ capture?: true } } */
177
181
const opts = { } ;
182
+ const event_handle_key = '$$' + key ;
178
183
let event_name = key . slice ( 2 ) ;
179
184
var delegated = DelegatedEvents . includes ( event_name ) ;
180
185
@@ -183,21 +188,35 @@ export function set_attributes(element, prev, next, lowercase_attributes, css_ha
183
188
opts . capture = true ;
184
189
}
185
190
186
- if ( ! delegated && prev ?. [ key ] ) {
187
- element . removeEventListener ( event_name , /** @type {any } */ ( prev [ key ] ) , opts ) ;
191
+ if ( ! delegated && prev_value ) {
192
+ // Listening to same event but different handler -> our handle function below takes care of this
193
+ // If we were to remove and add listeners in this case, it could happen that the event is "swallowed"
194
+ // (the browser seems to not know yet that a new one exists now) and doesn't reach the handler
195
+ // https://github.com/sveltejs/svelte/issues/11903
196
+ if ( value != null ) continue ;
197
+
198
+ element . removeEventListener ( event_name , current [ event_handle_key ] , opts ) ;
199
+ current [ event_handle_key ] = null ;
188
200
}
189
201
190
202
if ( value != null ) {
191
203
if ( ! delegated ) {
192
- // we use `addEventListener` here because these events are not delegated
204
+ /**
205
+ * @this {any}
206
+ * @param {Event } evt
207
+ */
208
+ function handle ( evt ) {
209
+ current [ key ] . call ( this , evt ) ;
210
+ }
211
+
193
212
if ( ! prev ) {
194
213
events . push ( [
195
214
key ,
196
215
value ,
197
- ( ) => ( next [ key ] = create_event ( event_name , element , value , opts ) )
216
+ ( ) => ( current [ event_handle_key ] = create_event ( event_name , element , handle , opts ) )
198
217
] ) ;
199
218
} else {
200
- next [ key ] = create_event ( event_name , element , value , opts ) ;
219
+ current [ event_handle_key ] = create_event ( event_name , element , handle , opts ) ;
201
220
}
202
221
} else {
203
222
// @ts -ignore
@@ -252,7 +271,7 @@ export function set_attributes(element, prev, next, lowercase_attributes, css_ha
252
271
effect ( ( ) => {
253
272
if ( ! element . isConnected ) return ;
254
273
for ( const [ key , value , evt ] of events ) {
255
- if ( next [ key ] === value ) {
274
+ if ( current [ key ] === value ) {
256
275
evt ( ) ;
257
276
}
258
277
}
@@ -261,7 +280,7 @@ export function set_attributes(element, prev, next, lowercase_attributes, css_ha
261
280
} ) ;
262
281
}
263
282
264
- return next ;
283
+ return current ;
265
284
}
266
285
267
286
/**
0 commit comments