etherpad-lite/src/static/js
John McLear 51356b9a13
fix(editor): undo/redo scrolls the viewport to follow the caret (#7562)
* fix(editor): undo/redo scrolls the viewport to follow the caret

Before: on a large pad, pressing Ctrl+Z (or Ctrl+Y, or the toolbar undo
button) updated the caret in the rep model and the DOM, but the viewport
did not follow when the caret landed below the visible area. The user
was left looking at the same scroll position while their change had
been undone somewhere they couldn't see.

Root cause: scroll.ts's `caretIsBelowOfViewport` branch ran
`outer.scrollTo(0, outer[0].innerHeight)` — a fixed offset equal to the
inner iframe's height, NOT the caret position. That was a special-case
added in PR #4639 to keep the caret visible when the user pressed Enter
at the very end of the pad. It worked for that one scenario because the
newly-appended `<div>` happened to be at the bottom of the pad too; for
any other way of putting the caret below the viewport (undo, redo,
programmatic selection change, deletion that collapsed a long block) it
scrolled to an arbitrary spot.

Fix: mirror the `caretIsAboveOfViewport` branch. After the deferred
render settles, recompute the caret's position relative to the viewport
and scroll by exactly the delta needed to bring the caret back in — plus
the configured margin. The Enter-at-last-line case still works because
the caret genuinely is near the bottom of the pad and the delta resolves
to "scroll down by a screen".

Closes #7007

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* test(7007): use real typing so undo has changesets to replay

The first iteration of the Playwright spec built the pad by writing
directly to #innerdocbody.innerHTML. That bypasses Etherpad's text
layer, so the undo module had no changeset to revert — Ctrl+Z became a
no-op and the scroll assertion saw no movement (CI failure output:
`Expected: < 2302, Received: 2302`).

Replace with real keyboard typing of 45 lines via the existing
writeToPad-style pattern, then make the edit + scroll + Ctrl+Z under
that real content. Slower (~5s per test) but faithful to how undo
interacts with the pad.

Also drop the `test.beforeEach(clearCookies)` scaffolding — it wasn't
doing anything useful here.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* refactor(7007): scroll caret into view directly in doUndoRedo

Revert the scroll.ts rewrite from the previous commits and move the
fix to the right abstraction layer: the undo/redo entry point itself.

`scrollNodeVerticallyIntoView`'s caret-below-viewport branch has a
well-documented special case (PR #4639) that scrolls to the inner
iframe's innerHeight so Enter-on-last-line stays smooth. Changing
that function for the undo case risked regressing the Enter case or
racing with the existing scrollY bookkeeping. The CI run showed the
rewrite wasn't actually producing viewport movement.

Do the simpler thing instead: in `doUndoRedo`, after the selection is
updated, call `Element.scrollIntoView({block: "center"})` on the
caret's line node. That's browser-native, works inside the
ace_inner / ace_outer iframe chain, doesn't need setTimeout, and matches
what gedit/libreoffice do.

Closes #7007

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 10:26:54 +02:00
..
pluginfw fix: correct readFileSync calls in LinkInstaller to fix plugin installation (#7467) 2026-04-06 11:22:05 +01:00
types Add creator-owned pad settings defaults (#7545) 2026-04-19 11:13:44 +01:00
vendors fix(a11y): dialog semantics, focus management, icon labels, html lang (#7584) 2026-04-24 03:04:18 +01:00
ace.ts fix: ignore errors from browser extensions in error handler and editor init (#7456) 2026-04-05 01:58:38 +01:00
ace2_common.ts Moved to ts (#6593) 2024-08-17 20:14:36 +02:00
ace2_inner.ts fix(editor): undo/redo scrolls the viewport to follow the caret (#7562) 2026-04-26 10:26:54 +02:00
AttributeManager.ts Feat/changeset ts (#6594) 2024-08-18 12:14:24 +02:00
AttributeMap.ts Moved to ts (#6593) 2024-08-17 20:14:36 +02:00
AttributePool.ts Moved to ts (#6593) 2024-08-17 20:14:36 +02:00
attributes.ts Moved to ts (#6593) 2024-08-17 20:14:36 +02:00
basic_error_handler.ts Moved to ts (#6593) 2024-08-17 20:14:36 +02:00
broadcast.ts feat: add timeslider line numbers (#7542) 2026-04-19 11:18:54 +01:00
broadcast_revisions.ts Moved to ts (#6593) 2024-08-17 20:14:36 +02:00
broadcast_slider.ts feat: add timeslider playback speed setting (#7541) 2026-04-19 09:08:37 +01:00
Builder.ts Feat/changeset ts (#6594) 2024-08-18 12:14:24 +02:00
caretPosition.ts Feat/bundle js (#6511) 2024-07-18 08:51:30 +02:00
Changeset.ts build(deps): bump jose from 5.10.0 to 6.0.12 (#7049) 2025-08-04 19:21:59 +02:00
changesettracker.ts Fixed document not accessible in iframe (#6642) 2024-09-09 11:26:12 +02:00
ChangesetUtils.ts Feat/changeset ts (#6594) 2024-08-18 12:14:24 +02:00
chat.ts fix(a11y): dialog semantics, focus management, icon labels, html lang (#7584) 2026-04-24 03:04:18 +01:00
ChatMessage.ts Moved to ts (#6593) 2024-08-17 20:14:36 +02:00
collab_client.ts fix: warn when a pending edit is not accepted (#7540) 2026-04-19 11:11:07 +01:00
colorutils.ts Moved to ts (#6593) 2024-08-17 20:14:36 +02:00
contentcollector.ts fix(editor): preserve U+00A0 non-breaking space (#3037) (#7585) 2026-04-23 08:57:30 +01:00
cssmanager.ts Moved to ts (#6593) 2024-08-17 20:14:36 +02:00
domline.ts fix(editor): preserve U+00A0 non-breaking space (#3037) (#7585) 2026-04-23 08:57:30 +01:00
index.ts Fixed index html page 2024-07-23 18:14:49 +02:00
l10n.ts feat: make cookie names configurable with prefix setting (#7450) 2026-04-05 01:58:29 +01:00
linestylefilter.ts Feat/changeset ts (#6594) 2024-08-18 12:14:24 +02:00
MergingOpAssembler.ts Feat/changeset ts (#6594) 2024-08-18 12:14:24 +02:00
Op.ts Feat/changeset ts (#6594) 2024-08-18 12:14:24 +02:00
OpAssembler.ts Feat/changeset ts (#6594) 2024-08-18 12:14:24 +02:00
OpIter.ts Feat/changeset ts (#6594) 2024-08-18 12:14:24 +02:00
pad.ts Add creator-owned pad settings defaults (#7545) 2026-04-19 11:13:44 +01:00
pad_automatic_reconnect.ts Moved to ts (#6593) 2024-08-17 20:14:36 +02:00
pad_connectionstatus.ts Moved to ts (#6593) 2024-08-17 20:14:36 +02:00
pad_cookie.ts feat: make cookie names configurable with prefix setting (#7450) 2026-04-05 01:58:29 +01:00
pad_editbar.ts fix(editbar): restore caret to pad after toolbar-select change (#7589) (#7598) 2026-04-26 08:20:40 +01:00
pad_editor.ts Add creator-owned pad settings defaults (#7545) 2026-04-19 11:13:44 +01:00
pad_impexp.ts feat!: replace Abiword with LibreOffice and add DOCX export (#7539) 2026-04-19 09:08:22 +01:00
pad_modals.ts Moved to ts (#6593) 2024-08-17 20:14:36 +02:00
pad_savedrevs.ts Moved to ts (#6593) 2024-08-17 20:14:36 +02:00
pad_userlist.ts chore: fixed recentPads being null 2025-08-12 21:44:28 +02:00
pad_utils.ts fix: RTL URL parameter rtl=false now correctly disables RTL mode (#7464) 2026-04-06 11:22:57 +01:00
rjquery.ts Moved to ts (#6593) 2024-08-17 20:14:36 +02:00
scroll.ts feat: continued with pad link functionality 2025-08-01 21:42:05 +02:00
security.ts Moved to ts (#6593) 2024-08-17 20:14:36 +02:00
skin_variants.ts chore: add button to settings popup for dark mode (#7136) 2025-09-23 17:41:22 +02:00
skiplist.ts Moved to ts (#6593) 2024-08-17 20:14:36 +02:00
SmartOpAssembler.ts Feat/changeset ts (#6594) 2024-08-18 12:14:24 +02:00
socketio.ts fix(socket.io): readd long polling 2025-03-13 14:32:00 +01:00
StringAssembler.ts Feat/changeset ts (#6594) 2024-08-18 12:14:24 +02:00
StringIterator.ts Feat/changeset ts (#6594) 2024-08-18 12:14:24 +02:00
TextLinesMutator.ts Feat/changeset ts (#6594) 2024-08-18 12:14:24 +02:00
timeslider.ts feat: add timeslider line numbers (#7542) 2026-04-19 11:18:54 +01:00
underscore.ts Moved to ts (#6593) 2024-08-17 20:14:36 +02:00
undomodule.ts fix: allow undo of clear authorship colors without disconnect (#7430) 2026-04-19 09:09:03 +01:00
welcome.ts feat: make cookie names configurable with prefix setting (#7450) 2026-04-05 01:58:29 +01:00