Defect #44336
openAutomatic list marker insertion discards the textarea undo history and does not scroll the caret into view
Description
Since #43095 (6.1.0), pressing Enter after a list item runs the list-autofill Stimulus controller. Its insert branch cancels the native line break and splices the marker with:
this.input.value = newValue this.input.setSelectionRange(newCursor, newCursor)
Assigning input.value programmatically resets the browser's undo stack, and setSelectionRange does not scroll the textarea in Chrome. Two user-visible defects on every Enter inside a list:
1. Undo is destroyed. Everything typed before the Enter becomes unrecoverable with Ctrl+Z. Measured in Chromium on a stock 6.1.3 new-issue form: type * item one, Enter (marker auto-inserted), type item two, then Ctrl+Z 8x -> textarea stops at"* item one\n* ". With the controller detached, the same keystrokes undo to empty.
2. Caret left off-screen. When the textarea is scrolled (long note, caret at bottom), the native Enter scroll never happens (the event was canceled). The new list line is not visible until the next character is typed.
The remove branch (Enter on an empty item) uses setRangeText, which is also not undoable in Chromium.
Proposed fix (patch attached):
insert: do not cancel the event. Let the native line break run — it creates a normal undo entry and scrolls the caret into view — and append the marker at the caret from a one-shotinput(insertLineBreak) listener viadocument.execCommand('insertText'), falling back tosetRangeTextwhere execCommand is unavailable.remove: select the marker range and usedocument.execCommand('delete')(same fallback), so the removal is undoable.
Verified in Chromium (headless, Playwright) against 6.1.3 with the patch applied:
- markers still auto-insert/remove for Textile and CommonMark lines
- 8x Ctrl+Z fully reverts a typed list (identical to a controller-less textarea); one Ctrl+Z reverts break+marker in a single step
- scrollTop after Enter matches native exactly (540 -> 555 in the test layout); Ctrl+Z after marker-removal restores the marker
execCommandis deprecated but universally supported for insertText/delete in textareas, and core already relies on it (copy-to-clipboard).
- Probe data (2026-08-10, sameersbn/redmine:6.1.3-2, bundled Chromium)
| scenario | typed | after 8x Ctrl+Z |
| --- | --- | --- |
| 6.1.3 stock, controller on | `* item one\n* item two` | `* item one\n* ` (history gone) |
| controller detached | `* item one\n* item two` | `` (full undo) |
| patched, controller on | `* item one\n* item two` | `` (full undo) |
Scroll (textarea 184px client, 40 list lines, caret at bottom; "visible px" = height of caret line inside the viewport right after Enter):
| scenario | scrollTop before -> after Enter | caret line visible |
| --- | --- | --- |
| stock | 540 -> 540 | 0 px |
| native Enter (no controller) | 540 -> 555 | 15 px |
| patched | 540 -> 555 | 15 px |
Files
Updated by Jonathan Cormier 18 days ago
the toolbar buttons and shortcuts have the same root cause in app/assets/javascripts/jstoolbar/jstoolbar.js (encloseSelection / encloseLineSelection assign textarea.value), which this patch does not touch. That half is #43488, where I have attached a patch for it.
Updated by Mizuki ISHIKAWA 12 days ago
- File list_autofill_tests_and_execcommand_fallback.patch list_autofill_tests_and_execcommand_fallback.patch added
Thank you for the patch. I tested it and it works very well.
I had two concerns: execCommand is deprecated, so it should not raise an error if the function is removed in the future, and I think it would be better to have a system test for this behavior.
I have attached a patch that addresses these two points. It should be applied after the list_autofill_undo_scroll.patch
Updated by Jonathan Cormier 12 days ago
Appreciate the update, makes sense to me. Hopefully they don't fully deprecate this feature
Updated by Jonathan Cormier 11 days ago
What about Defect #43488: Undo/Redo produces unexpected results when the text in a textarea is modified automatically which has a similar solution
Updated by Jonathan Cormier 5 days ago
Found a slight modification:
Using setSelectionRange causes the linux middle-click buffer to get filled with whatever we are deleting, instead using setRangeText avoids this.
- setSelectionRange is a UI action that X11 monitors to sync the "Primary Selection" (middle-click buffer).
- setRangeText is a programmatic DOM manipulation method. When used with an empty string and the 'end' (or 'preserve') parameter, it modifies the internal value buffer of the textarea without triggering the system-level selection broadcast that "pollutes" the middle-click buffer.
Updated by Jonathan Cormier 5 days ago
Ex: textarea.setRangeText('', lineStart, lineEnd, 'end');
Updated by Jonathan Cormier 1 day ago
nvm, setRangeText just brings back the undo problems.