aboutsummaryrefslogtreecommitdiffstats
path: root/src/features
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-10-11 22:39:04 -0700
committerAdam Soltys <[email protected]>2026-10-11 22:39:04 -0700
commit880abf73720acc13e07242568d56c14bca247c5e (patch)
tree54ccc60ff0bbfccf1e23a78246f8694b2dab04a6 /src/features
parent8b65caee4348073f44c36d379bc654c27f5e9ee5 (diff)
downloadcoinosv3-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')
-rw-r--r--src/features/messages.js30
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;