fix: back button navigation — guard hash setting during route()
When the back button triggers hashchange -> route(), the isRouting flag prevents navigate() and showDetail() from re-setting location.hash, which was creating duplicate history entries and trapping the user. Now the back button properly traverses history.
This commit is contained in:
+15
-8
@@ -63,6 +63,7 @@ async function init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function route() {
|
function route() {
|
||||||
|
isRouting = true;
|
||||||
const hash = location.hash.slice(1) || 'library';
|
const hash = location.hash.slice(1) || 'library';
|
||||||
if (hash.startsWith('protocols/')) {
|
if (hash.startsWith('protocols/')) {
|
||||||
showDetail(hash.split('/')[1]);
|
showDetail(hash.split('/')[1]);
|
||||||
@@ -81,14 +82,15 @@ function route() {
|
|||||||
} else {
|
} else {
|
||||||
navigate('library');
|
navigate('library');
|
||||||
}
|
}
|
||||||
|
isRouting = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let searchTimer = null;
|
let searchTimer = null;
|
||||||
let currentRoute = '';
|
let currentRoute = '';
|
||||||
|
let isRouting = false;
|
||||||
|
|
||||||
function navigate(view) {
|
function navigate(view) {
|
||||||
// Prevent double navigation from hashchange
|
if (currentRoute === view && view !== 'library') return;
|
||||||
if (currentRoute === view) return;
|
|
||||||
currentRoute = view;
|
currentRoute = view;
|
||||||
document.querySelectorAll('.view').forEach(v => v.style.display = 'none');
|
document.querySelectorAll('.view').forEach(v => v.style.display = 'none');
|
||||||
document.getElementById('view-' + view).style.display = 'block';
|
document.getElementById('view-' + view).style.display = 'block';
|
||||||
@@ -96,11 +98,17 @@ function navigate(view) {
|
|||||||
document.querySelectorAll('.mobile-panel a').forEach(a => a.classList.toggle('active', a.dataset.view === view));
|
document.querySelectorAll('.mobile-panel a').forEach(a => a.classList.toggle('active', a.dataset.view === view));
|
||||||
closeMenu();
|
closeMenu();
|
||||||
updateBreadcrumb(view);
|
updateBreadcrumb(view);
|
||||||
if (view === 'library') { location.hash = 'library'; loadProtocols(); }
|
if (!isRouting) {
|
||||||
if (view === 'collections') { location.hash = 'collections'; loadCollections(); }
|
if (view === 'library') { location.hash = 'protocols'; }
|
||||||
|
if (view === 'collections') { location.hash = 'collections'; }
|
||||||
|
if (view === 'about') { location.hash = 'about'; }
|
||||||
|
if (view === 'terms') { location.hash = 'terms'; }
|
||||||
|
}
|
||||||
|
if (view === 'library') loadProtocols();
|
||||||
|
if (view === 'collections') loadCollections();
|
||||||
if (view === 'create') { editingSlug = null; resetForm(); }
|
if (view === 'create') { editingSlug = null; resetForm(); }
|
||||||
if (view === 'create-collection') { editingCollectionSlug = null; resetCollectionForm(); }
|
if (view === 'create-collection') { editingCollectionSlug = null; resetCollectionForm(); }
|
||||||
if (view === 'about') { location.hash = 'about'; }
|
if (view === 'about') updateAboutPage();
|
||||||
window.scrollTo(0, 0);
|
window.scrollTo(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -313,7 +321,7 @@ function renderProtocolGrid(protocols) {
|
|||||||
|
|
||||||
// --- Detail ---
|
// --- Detail ---
|
||||||
async function showDetail(slug) {
|
async function showDetail(slug) {
|
||||||
if (location.hash !== '#protocols/' + slug) location.hash = 'protocols/' + slug;
|
location.hash = 'protocols/' + slug;
|
||||||
document.querySelectorAll('.view').forEach(v => v.style.display = 'none');
|
document.querySelectorAll('.view').forEach(v => v.style.display = 'none');
|
||||||
document.getElementById('view-detail').style.display = 'block';
|
document.getElementById('view-detail').style.display = 'block';
|
||||||
document.querySelectorAll('header nav a').forEach(a => a.classList.remove('active'));
|
document.querySelectorAll('header nav a').forEach(a => a.classList.remove('active'));
|
||||||
@@ -713,7 +721,7 @@ async function saveCollection(e) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function showCollectionDetail(slug) {
|
async function showCollectionDetail(slug) {
|
||||||
if (location.hash !== '#collections/' + slug) location.hash = 'collections/' + slug;
|
location.hash = 'collections/' + slug;
|
||||||
document.querySelectorAll('.view').forEach(v => v.style.display = 'none');
|
document.querySelectorAll('.view').forEach(v => v.style.display = 'none');
|
||||||
document.getElementById('view-collection-detail').style.display = 'block';
|
document.getElementById('view-collection-detail').style.display = 'block';
|
||||||
document.querySelectorAll('header nav a').forEach(a => a.classList.remove('active'));
|
document.querySelectorAll('header nav a').forEach(a => a.classList.remove('active'));
|
||||||
@@ -786,7 +794,6 @@ async function deleteCollection(slug) {
|
|||||||
|
|
||||||
// --- User Profile ---
|
// --- User Profile ---
|
||||||
async function showUser(username) {
|
async function showUser(username) {
|
||||||
if (location.hash !== '#users/' + username && location.hash !== '#user/' + username) location.hash = 'users/' + username;
|
|
||||||
document.querySelectorAll('.view').forEach(v => v.style.display = 'none');
|
document.querySelectorAll('.view').forEach(v => v.style.display = 'none');
|
||||||
document.getElementById('view-detail').style.display = 'block';
|
document.getElementById('view-detail').style.display = 'block';
|
||||||
document.querySelectorAll('header nav a').forEach(a => a.classList.remove('active'));
|
document.querySelectorAll('header nav a').forEach(a => a.classList.remove('active'));
|
||||||
|
|||||||
Reference in New Issue
Block a user