From 7e462eec261d10695b5a7013faf33f28c2b6c281 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Mon, 24 Jun 2024 12:03:42 -0700 Subject: [PATCH] chore: use unbound event listeners (#12165) --- .../internal/client/dom/elements/events.js | 7 ++-- packages/svelte/src/internal/client/render.js | 32 ++++++------------- 2 files changed, 13 insertions(+), 26 deletions(-) diff --git a/packages/svelte/src/internal/client/dom/elements/events.js b/packages/svelte/src/internal/client/dom/elements/events.js index ea1cdfa419..302820829d 100644 --- a/packages/svelte/src/internal/client/dom/elements/events.js +++ b/packages/svelte/src/internal/client/dom/elements/events.js @@ -44,7 +44,7 @@ export function create_event(event_name, dom, handler, options) { function target_handler(/** @type {Event} */ event) { if (!options.capture) { // Only call in the bubble phase, else delegated events would be called before the capturing events - handle_event_propagation(dom, event); + handle_event_propagation.call(dom, event); } if (!event.cancelBubble) { return handler.call(this, event); @@ -143,11 +143,12 @@ export function delegate(events) { } /** - * @param {EventTarget} handler_element + * @this {EventTarget} * @param {Event} event * @returns {void} */ -export function handle_event_propagation(handler_element, event) { +export function handle_event_propagation(event) { + var handler_element = this; var owner_document = /** @type {Node} */ (handler_element).ownerDocument; var event_name = event.type; var path = event.composedPath?.() || []; diff --git a/packages/svelte/src/internal/client/render.js b/packages/svelte/src/internal/client/render.js index d18876b373..1944f6396e 100644 --- a/packages/svelte/src/internal/client/render.js +++ b/packages/svelte/src/internal/client/render.js @@ -196,38 +196,23 @@ function _mount(Component, { target, anchor, props = {}, events, context, intro const registered_events = new Set(); - const bound_event_listener = handle_event_propagation.bind(null, target); - const bound_document_event_listener = handle_event_propagation.bind(null, document); - /** @param {Array} events */ const event_handle = (events) => { for (let i = 0; i < events.length; i++) { const event_name = events[i]; + const passive = PassiveDelegatedEvents.includes(event_name); + if (!registered_events.has(event_name)) { registered_events.add(event_name); + // Add the event listener to both the container and the document. // The container listener ensures we catch events from within in case // the outer content stops propagation of the event. - target.addEventListener( - event_name, - bound_event_listener, - PassiveDelegatedEvents.includes(event_name) - ? { - passive: true - } - : undefined - ); + target.addEventListener(event_name, handle_event_propagation, { passive }); + // The document listener ensures we catch events that originate from elements that were // manually moved outside of the container (e.g. via manual portals). - document.addEventListener( - event_name, - bound_document_event_listener, - PassiveDelegatedEvents.includes(event_name) - ? { - passive: true - } - : undefined - ); + document.addEventListener(event_name, handle_event_propagation, { passive }); } } }; @@ -264,9 +249,10 @@ function _mount(Component, { target, anchor, props = {}, events, context, intro return () => { for (const event_name of registered_events) { - target.removeEventListener(event_name, bound_event_listener); - document.removeEventListener(event_name, bound_document_event_listener); + target.removeEventListener(event_name, handle_event_propagation); + document.removeEventListener(event_name, handle_event_propagation); } + root_event_handles.delete(event_handle); mounted_components.delete(component); };