diff options
| author | Adam Soltys <[email protected]> | 2026-10-11 22:39:04 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-10-11 22:39:04 -0700 |
| commit | 880abf73720acc13e07242568d56c14bca247c5e (patch) | |
| tree | 54ccc60ff0bbfccf1e23a78246f8694b2dab04a6 /src/features/messages.js | |
| parent | 8b65caee4348073f44c36d379bc654c27f5e9ee5 (diff) | |
| download | coinosv3-880abf73720acc13e07242568d56c14bca247c5e.tar.gz coinosv3-880abf73720acc13e07242568d56c14bca247c5e.zip | |
Feed: closing a full-screen picture leaves the feed where it was. The scroll memory that puts a reader back on the row they left when Back closes a thread or profile fired on every history pop, and a remembered place goes stale whenever its page is left another way (the Feed button from a thread), so a photo's × jumped the feed to wherever an earlier thread had been opened from, or to its top (Adam's recording, 2026-10-11 22:31, at the 10 s mark; reproduced on his tab: 2500 → 22361). Now the place is restored only when a pop actually leaves a thread or profile — the page being left is read in a capture-phase popstate listener, before the app's own handler re-renders — and the entries above the one it matches are dropped as stale. tools/lightbox-scroll-test.js (stale place from a thread left by the Feed button, a picture opened and closed, Back out of a thread still landing on its row). avatar-profile-test fails on HEAD before this too.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Diffstat (limited to 'src/features/messages.js')
| -rw-r--r-- | src/features/messages.js | 30 |
1 files changed, 21 insertions, 9 deletions
diff --git a/src/features/messages.js b/src/features/messages.js index 64e36c5..7c81d27 100644 --- a/src/features/messages.js +++ b/src/features/messages.js @@ -3931,15 +3931,27 @@ export function messagesFeature(ctx) { pageReturn.push({ key, y }); if (pageReturn.length > 20) pageReturn.shift(); } - if (typeof window !== 'undefined') window.addEventListener('popstate', () => { - const top = pageReturn[pageReturn.length - 1]; - if (!top || pageKey() === top.key) return; - pageReturn.pop(); - const y = top.y; - // twice: the page under it may paint its rows a frame late - requestAnimationFrame(() => { try { window.scrollTo(0, y); } catch {} - requestAnimationFrame(() => { try { if (Math.abs(window.scrollY - y) > 2) window.scrollTo(0, y); } catch {} }); }); - }); + // Only Back OUT OF a profile or thread puts the reader back. Any other + // pop — a full-screen picture closing, a sheet — leaves the page where it + // is. It used to restore the newest remembered place on every pop, and a + // place goes stale whenever its page is left some other way (the Feed + // button from a thread): a photo's × then jumped the feed to wherever an + // earlier thread had been opened from, or to its top. + let pageLeft = ''; // the page a pop is leaving, read before the app restores the entry under it + if (typeof window !== 'undefined') { + window.addEventListener('popstate', () => { pageLeft = pageKey(); }, true); // capture: before the app's own handler re-renders + window.addEventListener('popstate', () => { + const left = pageLeft; pageLeft = ''; + if (!left || pageKey() === left) return; + const i = pageReturn.map((e) => e.key).lastIndexOf(left); + if (i < 0) return; + const y = pageReturn[i].y; + pageReturn.length = i; // this entry, and anything stale above it + // twice: the page under it may paint its rows a frame late + requestAnimationFrame(() => { try { window.scrollTo(0, y); } catch {} + requestAnimationFrame(() => { try { if (Math.abs(window.scrollY - y) > 2) window.scrollTo(0, y); } catch {} }); }); + }); + } function openProfile(pk) { rememberPlace('p:' + pk); ui.profilePk = pk; |
