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:
1 parent
3f57e2ae26
commit
79100c5321
2 files changed
+30
-10
No files matched your search
+2
-2
@@ -13,7 +13,7 @@ import {
|
|||||||
npToggleStar, updateMediaSession, updateNpColorMode, reconcileNativeState, initKeyboardShortcuts,
|
npToggleStar, updateMediaSession, updateNpColorMode, reconcileNativeState, initKeyboardShortcuts,
|
||||||
} from './player/player.js';
|
} from './player/player.js';
|
||||||
import {
|
import {
|
||||||
navigate, _navGoBack, _navLoad, onHeaderSearch, closeHeaderSearch,
|
navigate, _navGoBack, _navOnPopState, _navLoad, onHeaderSearch, closeHeaderSearch,
|
||||||
onGlobalSearch, s_goArtist, s_goAlbum, playerBarGoArtist, playerBarGoAlbum,
|
onGlobalSearch, s_goArtist, s_goAlbum, playerBarGoArtist, playerBarGoAlbum,
|
||||||
searchSimilarArtist, searchAndPreview, loadItunesAlbum, closeEventsModal,
|
searchSimilarArtist, searchAndPreview, loadItunesAlbum, closeEventsModal,
|
||||||
loadAlbums, loadStarred, loadRandom, filterStarred, filterPlaylist,
|
loadAlbums, loadStarred, loadRandom, filterStarred, filterPlaylist,
|
||||||
@@ -299,7 +299,7 @@ window.addEventListener('load', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
window.addEventListener('popstate', () => _navGoBack());
|
window.addEventListener('popstate', (e) => _navOnPopState(e.state));
|
||||||
document.addEventListener('keydown', e => {
|
document.addEventListener('keydown', e => {
|
||||||
if(e.key !== 'Backspace') return;
|
if(e.key !== 'Backspace') return;
|
||||||
const t = document.activeElement?.tagName;
|
const t = document.activeElement?.tagName;
|
||||||
|
|||||||
+28
-8
@@ -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() {
|
export function _navGoBack() {
|
||||||
if(document.getElementById('np-sheet')?.classList.contains('open')) { closeNpMenu(); return; }
|
if(document.getElementById('np-sheet')?.classList.contains('open')) { closeNpMenu(); return; }
|
||||||
if(S.npOpen) { closeNowPlaying(); return; }
|
if(S.npOpen) { closeNowPlaying(); return; }
|
||||||
if(S._navCursor > 0) {
|
if(S._navCursor > 0) history.back();
|
||||||
S._navCursor--;
|
}
|
||||||
const entry = S._navStack[S._navCursor];
|
|
||||||
_navSave();
|
// Browser/mouse Back OR Forward — both fire popstate. Apply whichever entry the browser moved to
|
||||||
S._navJumping = true;
|
// via nsIdx from the history state; this is what makes Forward work. Never pushState here — that
|
||||||
navigate(entry.page, entry.data);
|
// would wipe the browser's forward stack. navigate() pushes only on genuine new navigation.
|
||||||
S._navJumping = false;
|
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;
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user