diff --git a/src/renderer/html_handlebars/hbs_renderer.rs b/src/renderer/html_handlebars/hbs_renderer.rs index 2b05c30e..f1901626 100644 --- a/src/renderer/html_handlebars/hbs_renderer.rs +++ b/src/renderer/html_handlebars/hbs_renderer.rs @@ -220,12 +220,7 @@ impl HtmlHandlebars { } fn register_hbs_helpers(&self, handlebars: &mut Handlebars, html_config: &HtmlConfig) { - handlebars.register_helper( - "toc", - Box::new(helpers::toc::RenderToc { - no_section_label: html_config.no_section_label, - }), - ); + handlebars.register_helper("toc", Box::new(helpers::toc::toc)); handlebars.register_helper("previous", Box::new(helpers::navigation::previous)); handlebars.register_helper("next", Box::new(helpers::navigation::next)); } @@ -402,12 +397,12 @@ fn make_data( json!(config.book.description.clone().unwrap_or_default()), ); data.insert("favicon".to_owned(), json!("favicon.png")); + if let Some(ref livereload) = html_config.livereload_url { data.insert("livereload".to_owned(), json!(livereload)); } - // Add google analytics tag - if let Some(ref ga) = config.html_config().and_then(|html| html.google_analytics) { + if let Some(ref ga) = html.google_analytics { data.insert("google_analytics".to_owned(), json!(ga)); } @@ -415,6 +410,10 @@ fn make_data( data.insert("mathjax_support".to_owned(), json!(true)); } + if html.no_section_label { + data.insert("no_section_label".to_owned(), json!(true)); + } + // Add check to see if there is an additional style if !html.additional_css.is_empty() { let mut css = Vec::new(); diff --git a/src/renderer/html_handlebars/helpers/navigation.rs b/src/renderer/html_handlebars/helpers/navigation.rs index 0cb19174..6529679e 100644 --- a/src/renderer/html_handlebars/helpers/navigation.rs +++ b/src/renderer/html_handlebars/helpers/navigation.rs @@ -1,7 +1,7 @@ use std::collections::BTreeMap; use std::path::Path; -use handlebars::{Context, Handlebars, Helper, RenderContext, RenderError, Renderable}; +use handlebars::{Context, Handlebars, Helper, RenderContext, RenderError, Renderable, HelperResult, Output}; use serde_json; use utils; @@ -45,15 +45,15 @@ impl Target { } } -fn find_chapter(rc: &mut RenderContext, target: Target) -> Result, RenderError> { +fn find_chapter(cx: &Context, rc: &mut RenderContext, target: Target) -> Result, RenderError> { debug!("Get data from context"); - let chapters = rc.evaluate_absolute("chapters", true).and_then(|c| { + let chapters = rc.evaluate_absolute(cx, "chapters", true).and_then(|c| { serde_json::value::from_value::>(c.clone()) .map_err(|_| RenderError::new("Could not decode the JSON data")) })?; - let base_path = rc.evaluate_absolute("path", true)? + let base_path = rc.evaluate_absolute(cx, "path", true)? .as_str() .ok_or_else(|| RenderError::new("Type error for `path`, string expected"))? .replace("\"", ""); @@ -80,16 +80,17 @@ fn find_chapter(rc: &mut RenderContext, target: Target) -> Result Result<(), RenderError> { +fn render<'h: 'rc, 'rc>( + h: &'h Handlebars, + cx: &'rc Context, + rc: &'rc mut RenderContext<'h>, + out: &mut Output, + chapter: StringMap, +) -> HelperResult { trace!("Creating BTreeMap to inject in context"); let mut context = BTreeMap::new(); - let base_path = rc.evaluate_absolute("path", false)? + let base_path = rc.evaluate_absolute(cx, "path", false)? .as_str() .ok_or_else(|| RenderError::new("Type error for `path`, string expected"))? .replace("\"", ""); @@ -117,31 +118,41 @@ fn render( trace!("Render template"); - _h.template() + h.render_template() .ok_or_else(|| RenderError::new("Error with the handlebars template")) .and_then(|t| { - let mut local_rc = rc.with_context(Context::wraps(&context)?); - t.render(r, &mut local_rc) + let local_cx = Context::wraps(&context)?; + t.render(r, &local_cx, rc, out) })?; Ok(()) } -pub fn previous(_h: &Helper, r: &Handlebars, rc: &mut RenderContext) -> Result<(), RenderError> { +pub fn previous<'h: 'rc, 'rc>( + h: &'h Handlebars, + cx: &'rc Context, + rc: &'rc mut RenderContext<'h>, + out: &mut Output +) -> HelperResult { trace!("previous (handlebars helper)"); - if let Some(previous) = find_chapter(rc, Target::Previous)? { - render(_h, r, rc, &previous)?; + if let Some(previous) = find_chapter(cx, rc, Target::Previous)? { + render(h, cx, rc, out, &previous)?; } Ok(()) } -pub fn next(_h: &Helper, r: &Handlebars, rc: &mut RenderContext) -> Result<(), RenderError> { +pub fn next<'h: 'rc, 'rc>( + h: &'h Handlebars, + cx: &'rc Context, + rc: &'rc mut RenderContext<'h>, + out: &mut Output +) -> HelperResult { trace!("next (handlebars helper)"); - if let Some(next) = find_chapter(rc, Target::Next)? { - render(_h, r, rc, &next)?; + if let Some(next) = find_chapter(cx, rc, Target::Next)? { + render(h, cx, rc, out, &next)?; } Ok(()) diff --git a/src/renderer/html_handlebars/helpers/toc.rs b/src/renderer/html_handlebars/helpers/toc.rs index 72bad7f9..f25812e7 100644 --- a/src/renderer/html_handlebars/helpers/toc.rs +++ b/src/renderer/html_handlebars/helpers/toc.rs @@ -3,142 +3,134 @@ use std::path::Path; use utils; -use handlebars::{Handlebars, Helper, HelperDef, RenderContext, RenderError}; +use handlebars::{Helper, Handlebars, Context, RenderContext, Output, HelperResult, RenderError}; use pulldown_cmark::{html, Event, Parser, Tag}; use serde_json; -// Handlebars helper to construct TOC -#[derive(Clone, Copy)] -pub struct RenderToc { - pub no_section_label: bool, -} +pub fn toc(h: &Helper, _: &Handlebars, cx: &Context, rc: &mut RenderContext, out: &mut Output) -> HelperResult { + // get value from context data + // rc.get_path() is current json parent path, you should always use it like this + // param is the key of value you want to display + let chapters = rc.evaluate_absolute(cx, "chapters", true).and_then(|c| { + serde_json::value::from_value::>>(c.clone()) + .map_err(|_| RenderError::new("Could not decode the JSON data")) + })?; + let current = rc.evaluate_absolute(cx, "path", true)? + .as_str() + .ok_or_else(|| RenderError::new("Type error for `path`, string expected"))? + .replace("\"", ""); + let no_section_label = rc.evaluate_absolute(cx, "no_section_label", true)?.as_bool().unwrap_or(false); -impl HelperDef for RenderToc { - fn call(&self, _h: &Helper, _: &Handlebars, rc: &mut RenderContext) -> Result<(), RenderError> { - // get value from context data - // rc.get_path() is current json parent path, you should always use it like this - // param is the key of value you want to display - let chapters = rc.evaluate_absolute("chapters", true).and_then(|c| { - serde_json::value::from_value::>>(c.clone()) - .map_err(|_| RenderError::new("Could not decode the JSON data")) - })?; - let current = rc.evaluate_absolute("path", true)? - .as_str() - .ok_or_else(|| RenderError::new("Type error for `path`, string expected"))? - .replace("\"", ""); + out.write("
    ")?; - rc.writer.write_all(b"
      ")?; + let mut current_level = 1; - let mut current_level = 1; + for item in chapters { + // Spacer + if item.get("spacer").is_some() { + out.write("
    1. ")?; + continue; + } - for item in chapters { - // Spacer - if item.get("spacer").is_some() { - rc.writer.write_all(b"
    2. ")?; - continue; + let level = if let Some(s) = item.get("section") { + s.matches('.').count() + } else { + 1 + }; + + if level > current_level { + while level > current_level { + out.write("
    3. ")?; + out.write("
        ")?; + current_level += 1; } - - let level = if let Some(s) = item.get("section") { - s.matches('.').count() - } else { - 1 - }; - - if level > current_level { - while level > current_level { - rc.writer.write_all(b"
      1. ")?; - rc.writer.write_all(b"
          ")?; - current_level += 1; - } - rc.writer.write_all(b"
        1. ")?; - } else if level < current_level { - while level < current_level { - rc.writer.write_all(b"
        ")?; - rc.writer.write_all(b"
      2. ")?; - current_level -= 1; - } - rc.writer.write_all(b"
      3. ")?; - } else { - rc.writer.write_all(b"")?; + out.write("
      4. ")?; + } else if level < current_level { + while level < current_level { + out.write("
      ")?; + out.write("
    4. ")?; + current_level -= 1; } + out.write("
    5. ")?; + } else { + out.write("")?; + } - // Link - let path_exists = if let Some(path) = item.get("path") { - if !path.is_empty() { - rc.writer.write_all(b"")?; - true - } else { - false + if path == ¤t { + out.write(" class=\"active\"")?; } + + out.write(">")?; + true } else { false - }; - - if !self.no_section_label { - // Section does not necessarily exist - if let Some(section) = item.get("section") { - rc.writer.write_all(b"")?; - rc.writer.write_all(section.as_bytes())?; - rc.writer.write_all(b" ")?; - } } + } else { + false + }; - if let Some(name) = item.get("name") { - // Render only inline code blocks - - // filter all events that are not inline code blocks - let parser = Parser::new(name).filter(|event| match *event { - Event::Start(Tag::Code) - | Event::End(Tag::Code) - | Event::InlineHtml(_) - | Event::Text(_) => true, - _ => false, - }); - - // render markdown to html - let mut markdown_parsed_name = String::with_capacity(name.len() * 3 / 2); - html::push_html(&mut markdown_parsed_name, parser); - - // write to the handlebars template - rc.writer.write_all(markdown_parsed_name.as_bytes())?; + if no_section_label { + // Section does not necessarily exist + if let Some(section) = item.get("section") { + out.write("")?; + out.write(section)?; + out.write(" ")?; } - - if path_exists { - rc.writer.write_all(b"")?; - } - - rc.writer.write_all(b"
    6. ")?; - } - while current_level > 1 { - rc.writer.write_all(b"
    ")?; - rc.writer.write_all(b"")?; - current_level -= 1; } - rc.writer.write_all(b"
")?; - Ok(()) + if let Some(name) = item.get("name") { + // Render only inline code blocks + + // filter all events that are not inline code blocks + let parser = Parser::new(name).filter(|event| match *event { + Event::Start(Tag::Code) + | Event::End(Tag::Code) + | Event::InlineHtml(_) + | Event::Text(_) => true, + _ => false, + }); + + // render markdown to html + let mut markdown_parsed_name = String::with_capacity(name.len() * 3 / 2); + html::push_html(&mut markdown_parsed_name, parser); + + // write to the handlebars template + out.write(&markdown_parsed_name)?; + } + + if path_exists { + out.write("")?; + } + + out.write("")?; } + while current_level > 1 { + out.write("")?; + out.write("")?; + current_level -= 1; + } + + out.write("")?; + Ok(()) }