aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-10-14 00:34:46 +0000
committerAdam Soltys <[email protected]>2026-10-14 00:34:46 +0000
commit928da70638fceb622d5e83ed0792817e1bcd908e (patch)
treec7c819d957fd40eba8259e28f48e90ee62a722fc /src
parent8a5118839502adb52cd504867bb8ac602160a48c (diff)
downloadcoinosv3-master.tar.gz
coinosv3-master.zip
Closing the pager (or a picture) lands on the page under it, not wherever Back goesHEADmaster
The × was a blind history.back(), and the entry under the pager isn't always the feed: the browser's older entries outlive a background reload of the app, and boot merges entries. It took the reader to the wallet, then the chat list. closeLayer still steps Back (so the phone's Back doesn't reopen it), but if Back lands anywhere but the page under the layer, the reader is put on that page and that entry rewritten to it. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01KPw21NEpWeTGu6swVASmBt
Diffstat (limited to 'src')
-rw-r--r--src/app.js40
-rw-r--r--src/features/messages.js2
2 files changed, 38 insertions, 4 deletions
diff --git a/src/app.js b/src/app.js
index 8af6f75..3cdb59e 100644
--- a/src/app.js
+++ b/src/app.js
@@ -600,7 +600,7 @@ function imageViewer() {
// mounted viewer: morphing can replace handlers with a new render's ones.
document.querySelector('.lightbox')?.remove();
document.documentElement.classList.remove('no-scroll');
- goBack(() => { ui.lightbox = null; });
+ closeLayer('lightbox');
};
// A tap on the picture closes it at every zoom level; gestures are filtered
// by attachZoom before this click handler runs.
@@ -702,7 +702,7 @@ function attachZoom(box, img, { wheel = true } = {}) {
}, { passive: false });
}
if (typeof window !== 'undefined') {
- window.addEventListener('keydown', (e) => { if (e.key === 'Escape' && ui.lightbox) goBack(() => { ui.lightbox = null; }); });
+ window.addEventListener('keydown', (e) => { if (e.key === 'Escape' && ui.lightbox) closeLayer('lightbox'); });
// Enter walks the Send flow: from an amount (or any field) it presses the
// screen's main button — Review, Pay, Send — and with nothing focused it
// presses it again, so amount ⏎ reviews and ⏎ again confirms. A held key
@@ -1031,11 +1031,23 @@ window.addEventListener('popstate', (e) => {
snap.screen = 'wallet'; snap.tab = ui.tab ?? null;
try { history.replaceState({ nav: snap, i: st && typeof st.i === 'number' ? st.i : navIndex }, ''); } catch {}
}
+ let corrected = false;
+ if (layerClose) {
+ const want = layerClose.expect;
+ clearTimeout(layerClose.timer);
+ layerClose = null;
+ if (navSig(snap) !== navSig(want)) {
+ snap = want;
+ corrected = true;
+ try { history.replaceState({ nav: snap, i: st && typeof st.i === 'number' ? st.i : navIndex }, '', navUrl(snap)); } catch {}
+ }
+ }
restoringHistory = true;
try {
for (const f of NAV_FIELDS) ui[f] = (f === 'profEdit' || f === 'feedEdit') && snap[f] ? structuredClone(snap[f]) : f in snap ? snap[f] : null;
if (st && typeof st.i === 'number') navIndex = st.i;
else { const i = navStack.findIndex((s) => navSig(s) === navSig(snap)); if (i >= 0) navIndex = i; }
+ if (corrected && navIndex >= 0) navStack[navIndex] = snap;
render();
} finally {
restoringHistory = false;
@@ -1050,6 +1062,28 @@ function goBack(toParent) {
if (navIndex > 0) history.back();
else { toParent(); render(); }
}
+// Close something laid over the page (the media pager, the lightbox): Back,
+// so the browser's Back doesn't reopen it — but landing on the page that
+// was under it, whatever the entry Back reaches says. The entry under isn't
+// always that page (after the app was reloaded in the background the
+// browser's older entries are still there, or entries merged at boot), and
+// blind Back walked off to the wallet, the chat list. That entry becomes the
+// page under the layer. No Back to take (nothing of ours under it): shut in place.
+let layerClose = null; // { expect: the snapshot to land on, timer }
+function closeLayer(field) {
+ const cur = navStack[navIndex] || navSnapshot();
+ const expect = { ...navSnapshot(), [field]: null };
+ if (navIndex > 0 && cur) {
+ clearTimeout(layerClose && layerClose.timer);
+ // (the layer stays up until Back lands, as before; no popstate in time:
+ // a Back that went nowhere — shut where we are)
+ layerClose = { expect, timer: setTimeout(() => { if (layerClose && layerClose.expect === expect) { layerClose = null; ui[field] = null; render(); } }, 600) };
+ history.back();
+ return;
+ }
+ ui[field] = null;
+ render();
+}
// Whether an in-app Back has anywhere of ours to go. A page opened straight
// from a link has nothing under it; its Back would invent a parent.
const canGoBack = () => navIndex > 0;
@@ -6236,7 +6270,7 @@ async function importSnapshotFile(e) {
// sits just before boot so every helper it captures is defined; the hooks are
// only invoked at runtime (first render happens after loadLocale below).
const ctx = {
- h, ui, render, wallet, toast, copy, copyBtn, pasteBtn, blankSend, goBack, canGoBack, goHome, openExternal, showSend,
+ h, ui, render, wallet, toast, copy, copyBtn, pasteBtn, blankSend, goBack, canGoBack, closeLayer, goHome, openExternal, showSend,
openWalletSettings: (view) => openWalletSettings(view),
// one page of the Settings hub, from anywhere (Notifications' gear)
openSettingsPage: (page) => { clearFeatureNav(); ui.screen = 'wallet'; ui.tab = 'settings'; ui.settingsPage = page; render(); try { window.scrollTo(0, 0); } catch {} },
diff --git a/src/features/messages.js b/src/features/messages.js
index 16ae3a2..8f5adcb 100644
--- a/src/features/messages.js
+++ b/src/features/messages.js
@@ -12040,7 +12040,7 @@ export function messagesFeature(ctx) {
ui.mediaPager = { kind, start, feed: curFeedId, fromFeed, at };
render();
}
- const closeMediaPager = () => ctx.goBack(() => { ui.mediaPager = null; });
+ const closeMediaPager = () => ctx.closeLayer('mediaPager');
// still on the picture that opened the pager (nothing swiped to yet)
const pagerOnStart = () => !pager || !pager.cur || pager.cur.getAttribute('data-k') === pager.start;
// Dismissing a pager opened from the feed after moving through it lands