From 6b52a346d5c86b7530361ffd5dfaf644244e7bf8 Mon Sep 17 00:00:00 2001 From: mARTin-B78 Date: Fri, 26 Jun 2026 22:47:25 +0200 Subject: [PATCH] fix: stop casting feed from hijacking scroll and deleting visible rows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Auto-scroll to bottom is now gated on the user being within 80px of the bottom. Scrolling up to review or edit a line freezes the feed in place — new rows are still added, but the viewport doesn't move. - Row-trimming is likewise suppressed while the user is scrolled up, so old lines stay visible as long as they're being read/edited. Trim limit raised from 80 → 600 rows so almost nothing is evicted. - A floating "↓ Live" pill button appears at the bottom of the feed whenever the user has scrolled up. Clicking it returns to the live bottom and re-enables auto-scroll. Co-Authored-By: Claude Opus 4.8 --- CHANGELOG.md | 11 +++++++++++ VERSION | 2 +- static/index.html | 4 ++-- static/js/audiobook.js | 30 +++++++++++++++++++++++++++--- static/style.css | 12 +++++++++++- 5 files changed, 52 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b53241..e23ed63 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,17 @@ Follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) · versioned wi --- +## [1.9.6] — 2026-06-26 + +### Fixed +- **Casting feed — scroll hijacking**: the feed no longer forces the view to the bottom while you are scrolled up reviewing or editing earlier lines. Auto-scroll only fires when you are already within 80px of the bottom. +- **Casting feed — vanishing text**: the trimming limit was raised from 80 to 600 rows, and trimming is now suppressed while you're scrolled up, so older lines stay visible as long as you're looking at them. + +### Added +- **Casting feed — "↓ Live" jump button**: a floating pill button appears at the bottom of the feed whenever you've scrolled up. Click it to immediately return to the live bottom of the feed and re-enable auto-scroll. + +--- + ## [1.9.5] — 2026-06-26 ### Added diff --git a/VERSION b/VERSION index 158c747..7bc1c40 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.9.5 +1.9.6 diff --git a/static/index.html b/static/index.html index c17ec8d..ce4b826 100644 --- a/static/index.html +++ b/static/index.html @@ -26,7 +26,7 @@ - + @@ -308,7 +308,7 @@ - + diff --git a/static/js/audiobook.js b/static/js/audiobook.js index 4ea9ad3..4f80712 100644 --- a/static/js/audiobook.js +++ b/static/js/audiobook.js @@ -226,7 +226,10 @@ function audiobookCastView(total, llmUrl, defaultModel, isIdle = false) {
0%
-
+
+
+ +
Characters found
reading…
@@ -463,8 +466,29 @@ STRIKTE FORMAT- UND TEXTREGELN: ? items.map(([n, info]) => `${escHtml(n)}${info.count}`).join('') : 'reading…'; }; - const MAXROWS = 80; - const trim = () => { while (feed.childElementCount > MAXROWS) feed.removeChild(feed.firstChild); feed.scrollTop = feed.scrollHeight; }; + const MAXROWS = 600; // keep most of the book visible; only trim when user is at bottom + // Whether the user has scrolled up to review/edit earlier content. + // While true: auto-scroll and trim are suppressed so their position is preserved. + let _userScrolled = false; + const jumpBtn = panel.querySelector('#ab-cv-jump-btn'); + feed.addEventListener('scroll', () => { + const atBottom = feed.scrollTop + feed.clientHeight >= feed.scrollHeight - 80; + _userScrolled = !atBottom; + if (jumpBtn) jumpBtn.hidden = atBottom; + }, { passive: true }); + const _scrollToBottom = () => { feed.scrollTop = feed.scrollHeight; }; + if (jumpBtn) { + jumpBtn.addEventListener('click', () => { + _userScrolled = false; + jumpBtn.hidden = true; + _scrollToBottom(); + }); + } + const trim = () => { + if (_userScrolled) return; // don't touch the feed while user is reading/editing + while (feed.childElementCount > MAXROWS) feed.removeChild(feed.firstChild); + _scrollToBottom(); + }; // Manual character assignment logic let assignModeSeg = null; diff --git a/static/style.css b/static/style.css index cec150a..c34ff01 100644 --- a/static/style.css +++ b/static/style.css @@ -4153,7 +4153,17 @@ code { background: var(--panel); border-radius: 4px; padding: 1px 5px; font-fami } .ab-cv-body { display: grid; grid-template-columns: 1fr 220px; gap: 12px; padding: 12px; flex: 1; min-height: 0; } -.ab-cv-feed { min-height: 0; overflow-y: auto; border: 1px solid var(--border); border-radius: 8px; padding: 6px 8px; background: var(--panel); display: flex; flex-direction: column; gap: 3px; } +.ab-cv-feed-wrap { position: relative; min-height: 0; display: flex; flex-direction: column; } +.ab-cv-feed { flex: 1; min-height: 0; overflow-y: auto; border: 1px solid var(--border); border-radius: 8px; padding: 6px 8px; background: var(--panel); display: flex; flex-direction: column; gap: 3px; } +.ab-cv-jump-btn { + position: absolute; bottom: 10px; left: 50%; transform: translateX(-50%); + display: flex; align-items: center; gap: 4px; + padding: 5px 14px; font-size: 12px; font-weight: 700; + background: var(--accent); color: #fff; border: none; border-radius: 20px; + cursor: pointer; box-shadow: 0 2px 8px rgba(0,0,0,.25); z-index: 5; + white-space: nowrap; +} +.ab-cv-jump-btn:hover { filter: brightness(1.1); } .ab-cv-row { display: block; font-family: 'Courier New', Courier, monospace;