Fixed bug with index page links.
If there is no index page in the source directory, mdbook uses the first chapter as the index page. When doing so, mdbook doesn't render the page any differently. This causes relative links on the page to break, if the first chapter is within a sub-directory. To fix this, a redirect to the first chapter is used instead of the copy of the page.
This commit is contained in:
parent
090eba0db5
commit
c6679053f7
|
@ -32,12 +32,12 @@ impl HtmlHandlebars {
|
||||||
item: &BookItem,
|
item: &BookItem,
|
||||||
mut ctx: RenderItemContext<'_>,
|
mut ctx: RenderItemContext<'_>,
|
||||||
print_content: &mut String,
|
print_content: &mut String,
|
||||||
) -> Result<()> {
|
) -> Result<Option<PathBuf>> {
|
||||||
// FIXME: This should be made DRY-er and rely less on mutable state
|
// FIXME: This should be made DRY-er and rely less on mutable state
|
||||||
|
|
||||||
let (ch, path) = match item {
|
let (ch, path) = match item {
|
||||||
BookItem::Chapter(ch) if !ch.is_draft_chapter() => (ch, ch.path.as_ref().unwrap()),
|
BookItem::Chapter(ch) if !ch.is_draft_chapter() => (ch, ch.path.as_ref().unwrap()),
|
||||||
_ => return Ok(()),
|
_ => return Ok(None),
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(ref edit_url_template) = ctx.html_config.edit_url_template {
|
if let Some(ref edit_url_template) = ctx.html_config.edit_url_template {
|
||||||
|
@ -58,7 +58,7 @@ impl HtmlHandlebars {
|
||||||
|
|
||||||
let fixed_content =
|
let fixed_content =
|
||||||
utils::render_markdown_with_path(&ch.content, ctx.html_config.curly_quotes, Some(path));
|
utils::render_markdown_with_path(&ch.content, ctx.html_config.curly_quotes, Some(path));
|
||||||
if !ctx.is_index && ctx.html_config.print.page_break {
|
if !ctx.is_first_chapter && ctx.html_config.print.page_break {
|
||||||
// Add page break between chapters
|
// Add page break between chapters
|
||||||
// See https://developer.mozilla.org/en-US/docs/Web/CSS/break-before and https://developer.mozilla.org/en-US/docs/Web/CSS/page-break-before
|
// See https://developer.mozilla.org/en-US/docs/Web/CSS/break-before and https://developer.mozilla.org/en-US/docs/Web/CSS/page-break-before
|
||||||
// Add both two CSS properties because of the compatibility issue
|
// Add both two CSS properties because of the compatibility issue
|
||||||
|
@ -120,22 +120,7 @@ impl HtmlHandlebars {
|
||||||
debug!("Creating {}", filepath.display());
|
debug!("Creating {}", filepath.display());
|
||||||
utils::fs::write_file(&ctx.destination, &filepath, rendered.as_bytes())?;
|
utils::fs::write_file(&ctx.destination, &filepath, rendered.as_bytes())?;
|
||||||
|
|
||||||
if ctx.is_index {
|
Ok(Some(filepath))
|
||||||
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));
|
|
||||||
let rendered_index = ctx.handlebars.render("index", &ctx.data)?;
|
|
||||||
let rendered_index = self.post_process(
|
|
||||||
rendered_index,
|
|
||||||
&ctx.html_config.playground,
|
|
||||||
&ctx.html_config.code,
|
|
||||||
ctx.edition,
|
|
||||||
);
|
|
||||||
debug!("Creating index.html from {}", ctx_path);
|
|
||||||
utils::fs::write_file(&ctx.destination, "index.html", rendered_index.as_bytes())?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_404(
|
fn render_404(
|
||||||
|
@ -484,7 +469,7 @@ impl Renderer for HtmlHandlebars {
|
||||||
|
|
||||||
fn render(&self, ctx: &RenderContext) -> Result<()> {
|
fn render(&self, ctx: &RenderContext) -> Result<()> {
|
||||||
let book_config = &ctx.config.book;
|
let book_config = &ctx.config.book;
|
||||||
let html_config = ctx.config.html_config().unwrap_or_default();
|
let mut html_config = ctx.config.html_config().unwrap_or_default();
|
||||||
let src_dir = ctx.root.join(&ctx.config.book.src);
|
let src_dir = ctx.root.join(&ctx.config.book.src);
|
||||||
let destination = &ctx.destination;
|
let destination = &ctx.destination;
|
||||||
let book = &ctx.book;
|
let book = &ctx.book;
|
||||||
|
@ -535,21 +520,36 @@ impl Renderer for HtmlHandlebars {
|
||||||
fs::create_dir_all(destination)
|
fs::create_dir_all(destination)
|
||||||
.with_context(|| "Unexpected error when constructing destination path")?;
|
.with_context(|| "Unexpected error when constructing destination path")?;
|
||||||
|
|
||||||
let mut is_index = true;
|
let mut seen_index = false;
|
||||||
|
let mut first_non_draft = None;
|
||||||
for item in book.iter() {
|
for item in book.iter() {
|
||||||
let ctx = RenderItemContext {
|
let ctx = RenderItemContext {
|
||||||
handlebars: &handlebars,
|
handlebars: &handlebars,
|
||||||
destination: destination.to_path_buf(),
|
destination: destination.to_path_buf(),
|
||||||
data: data.clone(),
|
data: data.clone(),
|
||||||
is_index,
|
is_first_chapter: first_non_draft.is_none(),
|
||||||
book_config: book_config.clone(),
|
book_config: book_config.clone(),
|
||||||
html_config: html_config.clone(),
|
html_config: html_config.clone(),
|
||||||
edition: ctx.config.rust.edition,
|
edition: ctx.config.rust.edition,
|
||||||
chapter_titles: &ctx.chapter_titles,
|
chapter_titles: &ctx.chapter_titles,
|
||||||
};
|
};
|
||||||
self.render_item(item, ctx, &mut print_content)?;
|
if let Some(rendered_file) = self.render_item(item, ctx, &mut print_content)? {
|
||||||
// Only the first non-draft chapter item should be treated as the "index"
|
seen_index |= rendered_file == Path::new("index.html");
|
||||||
is_index &= !matches!(item, BookItem::Chapter(ch) if !ch.is_draft_chapter());
|
if first_non_draft.is_none() {
|
||||||
|
first_non_draft = Some(rendered_file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !seen_index {
|
||||||
|
if let Some(first_file) = first_non_draft {
|
||||||
|
let redirect_to = first_file
|
||||||
|
.to_str()
|
||||||
|
.with_context(|| "Could not convert path to str")?
|
||||||
|
.to_string();
|
||||||
|
html_config
|
||||||
|
.redirect
|
||||||
|
.insert(String::from("/index.html"), redirect_to);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render 404 page
|
// Render 404 page
|
||||||
|
@ -1053,7 +1053,7 @@ struct RenderItemContext<'a> {
|
||||||
handlebars: &'a Handlebars<'a>,
|
handlebars: &'a Handlebars<'a>,
|
||||||
destination: PathBuf,
|
destination: PathBuf,
|
||||||
data: serde_json::Map<String, serde_json::Value>,
|
data: serde_json::Map<String, serde_json::Value>,
|
||||||
is_index: bool,
|
is_first_chapter: bool,
|
||||||
book_config: BookConfig,
|
book_config: BookConfig,
|
||||||
html_config: HtmlConfig,
|
html_config: HtmlConfig,
|
||||||
edition: Option<RustEdition>,
|
edition: Option<RustEdition>,
|
||||||
|
|
|
@ -467,7 +467,7 @@ fn by_default_mdbook_use_index_preprocessor_to_convert_readme_to_index() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn first_chapter_is_copied_as_index_even_if_not_first_elem() {
|
fn redirect_to_first_chapter_if_no_index() {
|
||||||
let temp = DummyBook::new().build().unwrap();
|
let temp = DummyBook::new().build().unwrap();
|
||||||
let mut cfg = Config::default();
|
let mut cfg = Config::default();
|
||||||
cfg.set("book.src", "index_html_test")
|
cfg.set("book.src", "index_html_test")
|
||||||
|
@ -476,9 +476,9 @@ fn first_chapter_is_copied_as_index_even_if_not_first_elem() {
|
||||||
md.build().unwrap();
|
md.build().unwrap();
|
||||||
|
|
||||||
let root = temp.path().join("book");
|
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");
|
let index = fs::read_to_string(root.join("index.html")).expect("read index");
|
||||||
pretty_assertions::assert_eq!(chapter, index);
|
|
||||||
|
assert!(index.contains(r#"<meta http-equiv="refresh" content="0; URL=chapter_1.html">"#))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -874,7 +874,7 @@ fn custom_fonts() {
|
||||||
actual
|
actual
|
||||||
};
|
};
|
||||||
let has_fonts_css = |path: &Path| -> bool {
|
let has_fonts_css = |path: &Path| -> bool {
|
||||||
let contents = fs::read_to_string(path.join("book/index.html")).unwrap();
|
let contents = fs::read_to_string(path.join("book/chapter_1.html")).unwrap();
|
||||||
contents.contains("fonts/fonts.css")
|
contents.contains("fonts/fonts.css")
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue