Skip to content

Fix: Preserve user text selection in click handler (fixes #867)#868

Open
swashbuck wants to merge 8 commits into
masterfrom
issue/867
Open

Fix: Preserve user text selection in click handler (fixes #867)#868
swashbuck wants to merge 8 commits into
masterfrom
issue/867

Conversation

@swashbuck

Copy link
Copy Markdown
Contributor

Fixes #867

Fix

The _refocusCurrentActiveElement() helper introduced focus stealing during _onBlur and _onClick flows that broke user text selection in all browsers after #844 landed. This PR replaces the removeAllRanges() approach with mouse-state-aware refocus suppression:

  • Track _isMouseDown via document-level mousedown/mouseup listeners
  • In _onBlur, skip the JAWS refocus-on-blur safety net while the user is mid drag-selection
  • In _onClick, skip the refocus when a non-collapsed selection exists
  • Harden the flag against getting stuck true by also resetting on document.mouseleave and window.blur

Why this approach

The original Firefox bug (#843) and the new all-browser regression both stem from the same cause: programmatic focus during the mousedown → mouseup window. Firefox plants a stray selection anchor, and every browser drops the active selection when focus moves away from the selected text. Tracking the mouse state lets us leave focus exactly where the user put it during a click/drag, then resume the JAWS safety net once the mouse is released.

removeAllRanges() from #844 is no longer required.

JAWS regression check

JAWS uses a virtual cursor driven from the keyboard — it does not generate mousedown/mouseup. The _isMouseDown flag will never be set during JAWS interaction, so the role=\"group\" refocus behaviour from #697 is preserved unchanged.

Hardening note (document vs body)

The existing blur/click handlers stay on $body because they rely on jQuery delegation. The new mousedown/mouseup listeners attach to document so a pointer released outside the body (drag off-page, drag to chrome, drag to another iframe) still cycles the flag. window.blur and document.mouseleave provide additional safety resets if the cleanup mouseup is missed entirely. In an iframe these all resolve to the iframe's own document/window, so the scope is correct.

Testing

  1. Enable _accessibility._isEnabled: true in config.json
  2. In Firefox AND Chrome, reload a page with body text
  3. Click-drag to select a paragraph - selection should remain after release
  4. Triple-click to select a paragraph - selection should remain
  5. Confirm copy (Cmd/Ctrl+C) works on the selected text
  6. Confirm the original Firefox - Content unexpectedly selected when _accessibility is enabled #843 Firefox repro (random clicking on body text) no longer produces phantom selections
  7. Tab through focusable elements - focus order unchanged
  8. If available: smoke test the matching, slider, and drawer plugins to confirm drag interactions still behave

Posted via collaboration with Claude Code

oliverfoster and others added 6 commits April 13, 2026 14:24
removeAllRanges() introduced in #844 also fires from _onClick via
_refocusCurrentActiveElement, wiping user drag-selections on mouseup.
Only clear the selection when it is collapsed, so the stray Firefox
anchor is removed but genuine ranges are preserved.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The isCollapsed guard was insufficient - _refocusCurrentActiveElement
is also invoked from _onClick on every click of non-focusable body
text, and the click event fires after mouseup with the user's drag
selection already committed. Move removeAllRanges out of the shared
helper and call it only on the blur path, where the Firefox stray
anchor bug actually originates. The click path now leaves the
selection untouched.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Track mousedown/mouseup state on body and skip the JAWS
refocus-on-blur logic while the mouse button is held down. The
blur fires between mousedown and mouseup on every click of
non-focusable text, and the programmatic focus call aborts the
in-progress text selection (and in Firefox plants a stray
selection anchor, which was the original #843 symptom).

Removing the refocus during active mouse interaction addresses both
the original #843 Firefox selection bug and the all-browser
selection-blocked regression from #844, without needing
removeAllRanges(). JAWS interactions are keyboard-driven, so the
group-element refocus behaviour is preserved.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
_onClick fires after mouseup. When the click lands on non-focusable
body text, _refocusCurrentActiveElement runs and moves focus to the
previously active element, which drops the user's just-formed text
selection. Skip the refocus when a non-collapsed selection exists
so the user can copy text.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Move mousedown/mouseup listeners from body to document, and also
reset _isMouseDown on document mouseleave and window blur. This
prevents the flag from getting stuck true when the user releases
the pointer outside the body or switches window/iframe mid drag,
which would otherwise suppress the JAWS refocus-on-blur safety net
until the next mousedown/mouseup cycle inside body.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@swashbuck swashbuck self-assigned this May 21, 2026
@swashbuck swashbuck added the bug label May 21, 2026
@swashbuck swashbuck changed the title Fix #867 - preserve user text selection in click handler Fix: Preserve user text selection in click handler (fixes #867) May 21, 2026
@swashbuck swashbuck moved this from New to Needs Reviewing in adapt_framework: The TODO Board May 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

Status: Needs Reviewing

Development

Successfully merging this pull request may close these issues.

Fix #844 regression - text selection blocked by removeAllRanges() in click handler

3 participants