Skip to content

[72837] Click position is lost when activating an inline edit field#23449

Open
HDinger wants to merge 1 commit into
release/17.5from
bug/72837-click-position-is-lost-when-activating-an-inline-edit-field-2
Open

[72837] Click position is lost when activating an inline edit field#23449
HDinger wants to merge 1 commit into
release/17.5from
bug/72837-click-position-is-lost-when-activating-an-inline-edit-field-2

Conversation

@HDinger
Copy link
Copy Markdown
Contributor

@HDinger HDinger commented May 29, 2026

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 setSelectionRange method 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 via setSelectionRange.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 Map keyed by data-inplace-edit-stable-key to 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
}
});
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Development

Successfully merging this pull request may close these issues.

2 participants