diff --git a/src/renderer/html_handlebars/hbs_renderer.rs b/src/renderer/html_handlebars/hbs_renderer.rs
index 26f1432c..b933a359 100644
--- a/src/renderer/html_handlebars/hbs_renderer.rs
+++ b/src/renderer/html_handlebars/hbs_renderer.rs
@@ -116,7 +116,7 @@ impl HtmlHandlebars {
if ctx.is_index {
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("is_index".to_owned(), json!(true));
let rendered_index = ctx.handlebars.render("index", &ctx.data)?;
let rendered_index =
self.post_process(rendered_index, &ctx.html_config.playground, ctx.edition);
@@ -540,7 +540,8 @@ impl Renderer for HtmlHandlebars {
chapter_titles: &ctx.chapter_titles,
};
self.render_item(item, ctx, &mut print_content)?;
- is_index = false;
+ // Only the first non-draft chapter item should be treated as the "index"
+ is_index &= !matches!(item, BookItem::Chapter(ch) if !ch.is_draft_chapter());
}
// Render 404 page
diff --git a/src/renderer/html_handlebars/helpers/toc.rs b/src/renderer/html_handlebars/helpers/toc.rs
index 6ae62aa7..0884d30a 100644
--- a/src/renderer/html_handlebars/helpers/toc.rs
+++ b/src/renderer/html_handlebars/helpers/toc.rs
@@ -57,6 +57,11 @@ impl HelperDef for RenderToc {
out.write("
")?;
let mut current_level = 1;
+ // The "index" page, which has this attribute set, is supposed to alias the first chapter in
+ // the book, i.e. the first link. There seems to be no easy way to determine which chapter
+ // the "index" is aliasing from within the renderer, so this is used instead to force the
+ // first link to be active. See further below.
+ let mut is_first_chapter = ctx.data().get("is_index").is_some();
for item in chapters {
// Spacer
@@ -130,7 +135,8 @@ impl HelperDef for RenderToc {
out.write(&tmp)?;
out.write("\"")?;
- if path == ¤t_path {
+ if path == ¤t_path || is_first_chapter {
+ is_first_chapter = false;
out.write(" class=\"active\"")?;
}
diff --git a/tests/dummy_book/index_html_test/SUMMARY.md b/tests/dummy_book/index_html_test/SUMMARY.md
new file mode 100644
index 00000000..37bf68cd
--- /dev/null
+++ b/tests/dummy_book/index_html_test/SUMMARY.md
@@ -0,0 +1,11 @@
+# Summary
+
+---
+
+- [None of these should be treated as the "index chapter"]()
+
+# Part 1
+
+- [Not this either]()
+- [Chapter 1](./chapter_1.md)
+- [And not this]()
diff --git a/tests/dummy_book/index_html_test/chapter_1.md b/tests/dummy_book/index_html_test/chapter_1.md
new file mode 100644
index 00000000..b743fda3
--- /dev/null
+++ b/tests/dummy_book/index_html_test/chapter_1.md
@@ -0,0 +1 @@
+# Chapter 1
diff --git a/tests/rendered_output.rs b/tests/rendered_output.rs
index c6267830..9750a35e 100644
--- a/tests/rendered_output.rs
+++ b/tests/rendered_output.rs
@@ -467,6 +467,21 @@ fn by_default_mdbook_use_index_preprocessor_to_convert_readme_to_index() {
assert_doesnt_contain_strings(&second_index, &unexpected_strings);
}
+#[test]
+fn first_chapter_is_copied_as_index_even_if_not_first_elem() {
+ let temp = DummyBook::new().build().unwrap();
+ let mut cfg = Config::default();
+ cfg.set("book.src", "index_html_test")
+ .expect("Couldn't set config.book.src to \"index_html_test\"");
+ let md = MDBook::load_with_config(temp.path(), cfg).unwrap();
+ md.build().unwrap();
+
+ let root = temp.path().join("book");
+ let chapter = fs::read_to_string(root.join("chapter_1.html")).expect("read chapter 1");
+ let index = fs::read_to_string(root.join("index.html")).expect("read index");
+ pretty_assertions::assert_eq!(chapter, index);
+}
+
#[test]
fn theme_dir_overrides_work_correctly() {
let book_dir = dummy_book::new_copy_of_example_book().unwrap();