fix: prevent window listeners from triggering events twice (#10611)

fixes #10271
The prior fix in #10307 wasn't quite right, because JSDom has a difference between window and event.composedPath which sounds like a bug, and a workaround in that PR made it so the test did pass when the bug still occurred. That's also why there isn't a test here, because we can't properly test this using JSDom.
pull/10601/head
xxkl1 10 months ago committed by GitHub
parent 45e385721c
commit fc6666bc56
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
"svelte": patch
---
fix: prevent window listeners from triggering events twice

@ -1401,6 +1401,7 @@ export function delegate(events) {
* @returns {void} * @returns {void}
*/ */
function handle_event_propagation(handler_element, event) { function handle_event_propagation(handler_element, event) {
const owner_document = handler_element.ownerDocument;
const event_name = event.type; const event_name = event.type;
const path = event.composedPath?.() || []; const path = event.composedPath?.() || [];
let current_target = /** @type {null | Element} */ (path[0] || event.target); let current_target = /** @type {null | Element} */ (path[0] || event.target);
@ -1420,12 +1421,15 @@ function handle_event_propagation(handler_element, event) {
const handled_at = event.__root; const handled_at = event.__root;
if (handled_at) { if (handled_at) {
const at_idx = path.indexOf(handled_at); const at_idx = path.indexOf(handled_at);
if (at_idx !== -1 && handler_element === document) { if (
// This is the fallback document listener but the event was already handled at_idx !== -1 &&
// -> ignore, but set handle_at to document so that we're resetting the event (handler_element === document || handler_element === /** @type {any} */ (window))
) {
// This is the fallback document listener or a window listener, but the event was already handled
// -> ignore, but set handle_at to document/window so that we're resetting the event
// chain in case someone manually dispatches the same event object again. // chain in case someone manually dispatches the same event object again.
// @ts-expect-error // @ts-expect-error
event.__root = document; event.__root = handler_element;
return; return;
} }
// We're deliberately not skipping if the index is higher, because // We're deliberately not skipping if the index is higher, because
@ -1451,8 +1455,7 @@ function handle_event_propagation(handler_element, event) {
define_property(event, 'currentTarget', { define_property(event, 'currentTarget', {
configurable: true, configurable: true,
get() { get() {
// TODO: ensure correct document? return current_target || owner_document;
return current_target || document;
} }
}); });

Loading…
Cancel
Save