fix(web): browser/mouse Forward navigation now works (not only Back)

The popstate listener always called _navGoBack(), but both Back and Forward fire
popstate — so Forward was treated as Back and never restored the page you came from.
_navGoBack also pushState()'d on every back, which wiped the browser's forward stack
entirely.

Route all history through the History API: navigate() pushes a state (nsIdx) only on
genuine new navigation; popstate now applies whichever entry the browser moved to via
_navOnPopState(state.nsIdx), covering Back AND Forward with no pushState in the
handler. In-app back buttons / Backspace go through history.back() so there's a single
path and the browser stack stays in sync. NowPlaying overlays still close first on a
back press.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
HoneyandClaude Opus 4.8 committed 2026-07-24 22:49:40 +02:00
1 parent 3f57e2ae26
commit 79100c5321
2 files changed
+30 -10

No files matched your search

+28 -8
View File
@@ -86,16 +86,36 @@ export function navigate(page, data=null) {
}
}
// In-app back button / Backspace: dismiss NowPlaying overlays first, otherwise let the browser step
// back (→ popstate → _navOnPopState). Routing through the History API keeps the browser's back/
// forward stack in sync, so browser/mouse Forward works too.
export function _navGoBack() {
if(document.getElementById('np-sheet')?.classList.contains('open')) { closeNpMenu(); return; }
if(S.npOpen) { closeNowPlaying(); return; }
if(S._navCursor > 0) {
S._navCursor--;
const entry = S._navStack[S._navCursor];
_navSave();
S._navJumping = true;
navigate(entry.page, entry.data);
S._navJumping = false;
if(S._navCursor > 0) history.back();
}
// Browser/mouse Back OR Forward — both fire popstate. Apply whichever entry the browser moved to
// via nsIdx from the history state; this is what makes Forward work. Never pushState here — that
// would wipe the browser's forward stack. navigate() pushes only on genuine new navigation.
export function _navOnPopState(state) {
// Mirror the soft-back: a Back press with an overlay open just closes it and stays on the page.
if(document.getElementById('np-sheet')?.classList.contains('open')) {
closeNpMenu();
try { history.pushState({ nsIdx: S._navCursor }, '', ''); } catch {}
return;
}
try { history.pushState({ nsIdx: S._navCursor }, '', ''); } catch {}
if(S.npOpen) {
closeNowPlaying();
try { history.pushState({ nsIdx: S._navCursor }, '', ''); } catch {}
return;
}
const idx = (state && typeof state.nsIdx === 'number') ? state.nsIdx : 0;
if(idx < 0 || idx >= S._navStack.length) return;
S._navCursor = idx;
const entry = S._navStack[idx];
_navSave();
S._navJumping = true;
navigate(entry.page, entry.data);
S._navJumping = false;
}