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:
Protocolbot
2026-07-08 13:59:55 -06:00
parent 2278dae455
commit 59506db7a9
+15 -8
View File
@@ -63,6 +63,7 @@ async function init() {
}
function route() {
isRouting = true;
const hash = location.hash.slice(1) || 'library';
if (hash.startsWith('protocols/')) {
showDetail(hash.split('/')[1]);
@@ -81,14 +82,15 @@ function route() {
} else {
navigate('library');
}
isRouting = false;
}
let searchTimer = null;
let currentRoute = '';
let isRouting = false;
function navigate(view) {
// Prevent double navigation from hashchange
if (currentRoute === view) return;
if (currentRoute === view && view !== 'library') return;
currentRoute = view;
document.querySelectorAll('.view').forEach(v => v.style.display = 'none');
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));
closeMenu();
updateBreadcrumb(view);
if (view === 'library') { location.hash = 'library'; loadProtocols(); }
if (view === 'collections') { location.hash = 'collections'; loadCollections(); }
if (!isRouting) {
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-collection') { editingCollectionSlug = null; resetCollectionForm(); }
if (view === 'about') { location.hash = 'about'; }
if (view === 'about') updateAboutPage();
window.scrollTo(0, 0);
}
@@ -313,7 +321,7 @@ function renderProtocolGrid(protocols) {
// --- Detail ---
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.getElementById('view-detail').style.display = 'block';
document.querySelectorAll('header nav a').forEach(a => a.classList.remove('active'));
@@ -713,7 +721,7 @@ async function saveCollection(e) {
}
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.getElementById('view-collection-detail').style.display = 'block';
document.querySelectorAll('header nav a').forEach(a => a.classList.remove('active'));
@@ -786,7 +794,6 @@ async function deleteCollection(slug) {
// --- User Profile ---
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.getElementById('view-detail').style.display = 'block';
document.querySelectorAll('header nav a').forEach(a => a.classList.remove('active'));