From 4d0d4e55a7f91a630578d759ffe539cbaf00846a Mon Sep 17 00:00:00 2001 From: qaqland Date: Sun, 4 Jan 2026 16:39:29 +0800 Subject: [PATCH] Fix current page detection for clean URLs Previously, the sidebar JavaScript logic for detecting the "active" page relied on URL and assumed it would end with .html. When using clean URLs without this suffix, this logic would fail to correctly highlight the current page in the sidebar. This change moves the current page identification to server-side rendering by adding a data-current-link attribute to the HTML root element. Fixes https://github.com/rust-lang/mdBook/issues/2962 --- crates/mdbook-html/front-end/templates/index.hbs | 2 +- crates/mdbook-html/front-end/templates/toc.js.hbs | 10 +++------- crates/mdbook-html/src/html_handlebars/hbs_renderer.rs | 6 ++++++ 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/crates/mdbook-html/front-end/templates/index.hbs b/crates/mdbook-html/front-end/templates/index.hbs index b1834189f9..5d3eded19a 100644 --- a/crates/mdbook-html/front-end/templates/index.hbs +++ b/crates/mdbook-html/front-end/templates/index.hbs @@ -1,5 +1,5 @@ - + diff --git a/crates/mdbook-html/front-end/templates/toc.js.hbs b/crates/mdbook-html/front-end/templates/toc.js.hbs index 1a9f751ccf..207f3f5dc4 100644 --- a/crates/mdbook-html/front-end/templates/toc.js.hbs +++ b/crates/mdbook-html/front-end/templates/toc.js.hbs @@ -10,10 +10,7 @@ class MDBookSidebarScrollbox extends HTMLElement { connectedCallback() { this.innerHTML = '{{#toc}}{{/toc}}'; // Set the current, active page, and reveal it if it's hidden - let current_page = document.location.href.toString().split('#')[0].split('?')[0]; - if (current_page.endsWith('/')) { - current_page += 'index.html'; - } + const current_link = document.documentElement.dataset.currentLink; const links = Array.prototype.slice.call(this.querySelectorAll('a')); const l = links.length; for (let i = 0; i < l; ++i) { @@ -23,10 +20,9 @@ class MDBookSidebarScrollbox extends HTMLElement { link.href = path_to_root + href; } // The 'index' page is supposed to alias the first chapter in the book. - if (link.href === current_page + if (href === current_link || i === 0 - && path_to_root === '' - && current_page.endsWith('/index.html')) { + && current_link === 'index.html') { link.classList.add('active'); let parent = link.parentElement; while (parent) { diff --git a/crates/mdbook-html/src/html_handlebars/hbs_renderer.rs b/crates/mdbook-html/src/html_handlebars/hbs_renderer.rs index 8edac3cace..c6aae90c37 100644 --- a/crates/mdbook-html/src/html_handlebars/hbs_renderer.rs +++ b/crates/mdbook-html/src/html_handlebars/hbs_renderer.rs @@ -85,6 +85,9 @@ impl HtmlHandlebars { ctx.data.insert("title".to_owned(), json!(title)); ctx.data .insert("path_to_root".to_owned(), json!(fs::path_to_root(path))); + let current_link = path.with_extension("html").to_url_path(); + ctx.data + .insert("current_link".to_owned(), json!(current_link)); if let Some(ref section) = ch.number { ctx.data .insert("section".to_owned(), json!(section.to_string())); @@ -127,6 +130,8 @@ impl HtmlHandlebars { ctx.data.insert("path".to_owned(), json!("index.md")); ctx.data.insert("path_to_root".to_owned(), json!("")); ctx.data.insert("is_index".to_owned(), json!(true)); + ctx.data + .insert("current_link".to_owned(), json!("index.html")); let rendered_index = ctx.handlebars.render("index", &ctx.data)?; debug!("Creating index.html from {}", ctx_path); fs::write(ctx.destination.join("index.html"), rendered_index)?; @@ -180,6 +185,7 @@ impl HtmlHandlebars { // Set a dummy path to ensure other paths (e.g. in the TOC) are generated correctly data_404.insert("path".to_owned(), json!("404.md")); data_404.insert("content".to_owned(), json!(html_content_404)); + data_404.insert("current_link".to_owned(), json!("404.html")); let mut title = String::from("Page not found"); if let Some(book_title) = &ctx.config.book.title {