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();