From b963e53fc990a7ef3afd68bb1050e1ad97335780 Mon Sep 17 00:00:00 2001 From: FoHoOV <53280503+FoHoOV@users.noreply.github.com> Date: Mon, 27 May 2024 11:04:12 +0330 Subject: [PATCH] fix: parse ongotpointercapture and onlostpointercapture events correctly (#11790) Fixes #11789 --- .changeset/sleepy-cats-eat.md | 5 +++++ .../src/compiler/phases/2-analyze/index.js | 19 +++++++------------ .../3-transform/client/visitors/template.js | 7 ++----- packages/svelte/src/constants.js | 13 +++++++++++++ .../client/dom/elements/attributes.js | 13 +++++++------ .../_config.js | 16 ++++++++++++++++ .../main.svelte | 13 +++++++++++++ 7 files changed, 63 insertions(+), 23 deletions(-) create mode 100644 .changeset/sleepy-cats-eat.md create mode 100644 packages/svelte/tests/runtime-browser/samples/browser-events-ending-with-capture/_config.js create mode 100644 packages/svelte/tests/runtime-browser/samples/browser-events-ending-with-capture/main.svelte diff --git a/.changeset/sleepy-cats-eat.md b/.changeset/sleepy-cats-eat.md new file mode 100644 index 0000000000..53efadd712 --- /dev/null +++ b/.changeset/sleepy-cats-eat.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: parse ongotpointercapture and onlostpointercapture events correctly diff --git a/packages/svelte/src/compiler/phases/2-analyze/index.js b/packages/svelte/src/compiler/phases/2-analyze/index.js index acd12efcc8..bda4ad424c 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/index.js +++ b/packages/svelte/src/compiler/phases/2-analyze/index.js @@ -18,7 +18,12 @@ import { validation_legacy, validation_runes, validation_runes_js } from './vali import check_graph_for_cycles from './utils/check_graph_for_cycles.js'; import { regex_starts_with_newline } from '../patterns.js'; import { create_attribute, is_element_node } from '../nodes.js'; -import { DelegatedEvents, namespace_mathml, namespace_svg } from '../../../constants.js'; +import { + DelegatedEvents, + is_capture_event, + namespace_mathml, + namespace_svg +} from '../../../constants.js'; import { should_proxy_or_freeze } from '../3-transform/client/utils.js'; import { analyze_css } from './css/css-analyze.js'; import { prune } from './css/css-prune.js'; @@ -1508,23 +1513,13 @@ function determine_element_spread(node) { * @param {string} event_name */ function get_attribute_event_name(event_name) { - if (is_capture_event(event_name)) { + if (is_capture_event(event_name, 'include-on')) { event_name = event_name.slice(0, -7); } event_name = event_name.slice(2); return event_name; } -/** - * @param {string} name - * @returns boolean - */ -function is_capture_event(name) { - return ( - name.endsWith('capture') && name !== 'ongotpointercapture' && name !== 'onlostpointercapture' - ); -} - /** * @param {Map} unsorted_reactive_declarations */ diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js index 3fd4c50fa5..339c890d81 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js @@ -32,6 +32,7 @@ import { EACH_IS_STRICT_EQUALS, EACH_ITEM_REACTIVE, EACH_KEYED, + is_capture_event, TEMPLATE_FRAGMENT, TEMPLATE_USE_IMPORT_NODE, TRANSITION_GLOBAL, @@ -1410,11 +1411,7 @@ function serialize_event_attribute(node, context) { const modifiers = []; let event_name = node.name.slice(2); - if ( - event_name.endsWith('capture') && - event_name !== 'ongotpointercapture' && - event_name !== 'onlostpointercapture' - ) { + if (is_capture_event(event_name)) { event_name = event_name.slice(0, -7); modifiers.push('capture'); } diff --git a/packages/svelte/src/constants.js b/packages/svelte/src/constants.js index 4df2f33ef6..63949f7e99 100644 --- a/packages/svelte/src/constants.js +++ b/packages/svelte/src/constants.js @@ -279,3 +279,16 @@ export function is_tag_valid_with_parent(tag, parent_tag) { return true; } + +/** + * @param {string} name + * @param {"include-on" | "exclude-on"} [mode] - wether if name starts with `on` or `on` is excluded at this point + */ +export function is_capture_event(name, mode = 'exclude-on') { + if (!name.endsWith('capture')) { + return false; + } + return mode == 'exclude-on' + ? name !== 'gotpointercapture' && name !== 'lostpointercapture' + : name !== 'ongotpointercapture' && name !== 'onlostpointercapture'; +} diff --git a/packages/svelte/src/internal/client/dom/elements/attributes.js b/packages/svelte/src/internal/client/dom/elements/attributes.js index 07c9504ccf..8661a9d6c4 100644 --- a/packages/svelte/src/internal/client/dom/elements/attributes.js +++ b/packages/svelte/src/internal/client/dom/elements/attributes.js @@ -1,7 +1,12 @@ import { DEV } from 'esm-env'; import { hydrating } from '../hydration.js'; import { get_descriptors, get_prototype_of, map_get, map_set } from '../../utils.js'; -import { AttributeAliases, DelegatedEvents, namespace_svg } from '../../../../constants.js'; +import { + AttributeAliases, + DelegatedEvents, + is_capture_event, + namespace_svg +} from '../../../../constants.js'; import { create_event, delegate } from './events.js'; import { add_form_reset_listener, autofocus } from './misc.js'; import { effect, effect_root } from '../../reactivity/effects.js'; @@ -172,11 +177,7 @@ export function set_attributes(element, prev, next, lowercase_attributes, css_ha let event_name = key.slice(2); var delegated = DelegatedEvents.includes(event_name); - if ( - event_name.endsWith('capture') && - event_name !== 'ongotpointercapture' && - event_name !== 'onlostpointercapture' - ) { + if (is_capture_event(event_name)) { event_name = event_name.slice(0, -7); opts.capture = true; } diff --git a/packages/svelte/tests/runtime-browser/samples/browser-events-ending-with-capture/_config.js b/packages/svelte/tests/runtime-browser/samples/browser-events-ending-with-capture/_config.js new file mode 100644 index 0000000000..687b209fda --- /dev/null +++ b/packages/svelte/tests/runtime-browser/samples/browser-events-ending-with-capture/_config.js @@ -0,0 +1,16 @@ +import { tick } from 'svelte'; +import { test } from '../../assert'; + +export default test({ + async test({ assert, window }) { + const div = window.document.querySelector('div'); + + div?.dispatchEvent(new PointerEvent('gotpointercapture')); + div?.dispatchEvent(new PointerEvent('lostpointercapture')); + + await tick(); + + assert.equal(div?.dataset.lostCaptured, 'true'); + assert.equal(div?.dataset.gotCaptured, 'true'); + } +}); diff --git a/packages/svelte/tests/runtime-browser/samples/browser-events-ending-with-capture/main.svelte b/packages/svelte/tests/runtime-browser/samples/browser-events-ending-with-capture/main.svelte new file mode 100644 index 0000000000..bdbea0af42 --- /dev/null +++ b/packages/svelte/tests/runtime-browser/samples/browser-events-ending-with-capture/main.svelte @@ -0,0 +1,13 @@ + + +
{ + e.target.dataset.gotCaptured = "true"; + }} + onlostpointercapture={(e) => { + e.target.dataset.lostCaptured = "true"; + }} +> +
+