[72837] Click position is lost when activating an inline edit field#23449
Open
HDinger wants to merge 1 commit into
Open
[72837] Click position is lost when activating an inline edit field#23449HDinger wants to merge 1 commit into
HDinger wants to merge 1 commit into
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
This PR addresses ticket #72837 by preserving the user’s click/cursor position when switching an inplace-edit field from display mode to an inline text input, even though the DOM gets replaced via Turbo Streams.
Changes:
- Introduces a module-level
Mapkeyed bydata-inplace-edit-stable-keyto persist cursor offsets across Turbo Stream replacements. - Captures the character offset on click before requesting the edit field, and restores the selection on controller connect via
setSelectionRange. - Adds helpers to compute a click-based character offset by walking text nodes.
Comment on lines
+178
to
+191
| if (e instanceof MouseEvent) { | ||
| const container = e.currentTarget as HTMLElement; | ||
|
|
||
| // For plain-text inputs: store the char offset at the click position so | ||
| // the rendered text input can place the cursor accurately via setSelectionRange. | ||
| const range = document.caretRangeFromPoint(e.clientX, e.clientY); | ||
| if (range && container.contains(range.startContainer)) { | ||
| cursorOffsets.set(key, this.getCharOffset(container, range.startContainer, range.startOffset)); | ||
| } else { | ||
| cursorOffsets.delete(key); | ||
| } | ||
| } else { | ||
| cursorOffsets.delete(key); | ||
| } |
Comment on lines
+155
to
+172
| private setCursorPosition(element:HTMLElement):void { | ||
| const key = this.stableKey; | ||
| const offset = key !== undefined ? cursorOffsets.get(key) : undefined; | ||
| if (key !== undefined) cursorOffsets.delete(key); | ||
|
|
||
| if (offset !== undefined) { | ||
| // requestAnimationFrame ensures autofocus has run and the element is focused. | ||
| // setSelectionRange is not supported on all input types (e.g. number, date) — | ||
| // those will silently keep the browser's default cursor placement. | ||
| requestAnimationFrame(() => { | ||
| try { | ||
| (element as HTMLInputElement).setSelectionRange(offset, offset); | ||
| } catch { | ||
| // ignore | ||
| } | ||
| }); | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Ticket
https://community.openproject.org/wp/72837
What are you trying to accomplish?
Remember click position when switching from display to edit field. Due to the limit of of the
setSelectionRangemethod this only works for inputs of type text.What approach did you choose and why?
On click, the char offset is determined and stored in a module-level Map, keyed by the field's
data-inplace-edit-stable-key. When the edit field controller connects to the rendered input, it reads the stored offset and applies it viasetSelectionRange.