Try to update handlebars

This commit is contained in:
Matt Ickstadt 2018-07-24 15:52:47 -05:00
parent 49c26a93f2
commit 33f437af9d
3 changed files with 146 additions and 144 deletions

View File

@ -220,12 +220,7 @@ impl HtmlHandlebars {
} }
fn register_hbs_helpers(&self, handlebars: &mut Handlebars, html_config: &HtmlConfig) { fn register_hbs_helpers(&self, handlebars: &mut Handlebars, html_config: &HtmlConfig) {
handlebars.register_helper( handlebars.register_helper("toc", Box::new(helpers::toc::toc));
"toc",
Box::new(helpers::toc::RenderToc {
no_section_label: html_config.no_section_label,
}),
);
handlebars.register_helper("previous", Box::new(helpers::navigation::previous)); handlebars.register_helper("previous", Box::new(helpers::navigation::previous));
handlebars.register_helper("next", Box::new(helpers::navigation::next)); handlebars.register_helper("next", Box::new(helpers::navigation::next));
} }
@ -402,12 +397,12 @@ fn make_data(
json!(config.book.description.clone().unwrap_or_default()), json!(config.book.description.clone().unwrap_or_default()),
); );
data.insert("favicon".to_owned(), json!("favicon.png")); data.insert("favicon".to_owned(), json!("favicon.png"));
if let Some(ref livereload) = html_config.livereload_url { if let Some(ref livereload) = html_config.livereload_url {
data.insert("livereload".to_owned(), json!(livereload)); data.insert("livereload".to_owned(), json!(livereload));
} }
// Add google analytics tag if let Some(ref ga) = html.google_analytics {
if let Some(ref ga) = config.html_config().and_then(|html| html.google_analytics) {
data.insert("google_analytics".to_owned(), json!(ga)); data.insert("google_analytics".to_owned(), json!(ga));
} }
@ -415,6 +410,10 @@ fn make_data(
data.insert("mathjax_support".to_owned(), json!(true)); 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 // Add check to see if there is an additional style
if !html.additional_css.is_empty() { if !html.additional_css.is_empty() {
let mut css = Vec::new(); let mut css = Vec::new();

View File

@ -1,7 +1,7 @@
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::path::Path; 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 serde_json;
use utils; use utils;
@ -45,15 +45,15 @@ impl Target {
} }
} }
fn find_chapter(rc: &mut RenderContext, target: Target) -> Result<Option<StringMap>, RenderError> { fn find_chapter(cx: &Context, rc: &mut RenderContext, target: Target) -> Result<Option<StringMap>, RenderError> {
debug!("Get data from context"); 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::<Vec<StringMap>>(c.clone()) serde_json::value::from_value::<Vec<StringMap>>(c.clone())
.map_err(|_| RenderError::new("Could not decode the JSON data")) .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() .as_str()
.ok_or_else(|| RenderError::new("Type error for `path`, string expected"))? .ok_or_else(|| RenderError::new("Type error for `path`, string expected"))?
.replace("\"", ""); .replace("\"", "");
@ -80,16 +80,17 @@ fn find_chapter(rc: &mut RenderContext, target: Target) -> Result<Option<StringM
Ok(None) Ok(None)
} }
fn render( fn render<'h: 'rc, 'rc>(
_h: &Helper, h: &'h Handlebars,
r: &Handlebars, cx: &'rc Context,
rc: &mut RenderContext, rc: &'rc mut RenderContext<'h>,
chapter: &StringMap, out: &mut Output,
) -> Result<(), RenderError> { chapter: StringMap,
) -> HelperResult {
trace!("Creating BTreeMap to inject in context"); trace!("Creating BTreeMap to inject in context");
let mut context = BTreeMap::new(); let mut context = BTreeMap::new();
let base_path = rc.evaluate_absolute("path", false)? let base_path = rc.evaluate_absolute(cx, "path", false)?
.as_str() .as_str()
.ok_or_else(|| RenderError::new("Type error for `path`, string expected"))? .ok_or_else(|| RenderError::new("Type error for `path`, string expected"))?
.replace("\"", ""); .replace("\"", "");
@ -117,31 +118,41 @@ fn render(
trace!("Render template"); trace!("Render template");
_h.template() h.render_template()
.ok_or_else(|| RenderError::new("Error with the handlebars template")) .ok_or_else(|| RenderError::new("Error with the handlebars template"))
.and_then(|t| { .and_then(|t| {
let mut local_rc = rc.with_context(Context::wraps(&context)?); let local_cx = Context::wraps(&context)?;
t.render(r, &mut local_rc) t.render(r, &local_cx, rc, out)
})?; })?;
Ok(()) 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)"); trace!("previous (handlebars helper)");
if let Some(previous) = find_chapter(rc, Target::Previous)? { if let Some(previous) = find_chapter(cx, rc, Target::Previous)? {
render(_h, r, rc, &previous)?; render(h, cx, rc, out, &previous)?;
} }
Ok(()) 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)"); trace!("next (handlebars helper)");
if let Some(next) = find_chapter(rc, Target::Next)? { if let Some(next) = find_chapter(cx, rc, Target::Next)? {
render(_h, r, rc, &next)?; render(h, cx, rc, out, &next)?;
} }
Ok(()) Ok(())

View File

@ -3,38 +3,32 @@ use std::path::Path;
use utils; 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 pulldown_cmark::{html, Event, Parser, Tag};
use serde_json; use serde_json;
// Handlebars helper to construct TOC pub fn toc(h: &Helper, _: &Handlebars, cx: &Context, rc: &mut RenderContext, out: &mut Output) -> HelperResult {
#[derive(Clone, Copy)]
pub struct RenderToc {
pub no_section_label: bool,
}
impl HelperDef for RenderToc {
fn call(&self, _h: &Helper, _: &Handlebars, rc: &mut RenderContext) -> Result<(), RenderError> {
// get value from context data // get value from context data
// rc.get_path() is current json parent path, you should always use it like this // 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 // param is the key of value you want to display
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::<Vec<BTreeMap<String, String>>>(c.clone()) serde_json::value::from_value::<Vec<BTreeMap<String, String>>>(c.clone())
.map_err(|_| RenderError::new("Could not decode the JSON data")) .map_err(|_| RenderError::new("Could not decode the JSON data"))
})?; })?;
let current = rc.evaluate_absolute("path", true)? let current = rc.evaluate_absolute(cx, "path", true)?
.as_str() .as_str()
.ok_or_else(|| RenderError::new("Type error for `path`, string expected"))? .ok_or_else(|| RenderError::new("Type error for `path`, string expected"))?
.replace("\"", ""); .replace("\"", "");
let no_section_label = rc.evaluate_absolute(cx, "no_section_label", true)?.as_bool().unwrap_or(false);
rc.writer.write_all(b"<ol class=\"chapter\">")?; out.write("<ol class=\"chapter\">")?;
let mut current_level = 1; let mut current_level = 1;
for item in chapters { for item in chapters {
// Spacer // Spacer
if item.get("spacer").is_some() { if item.get("spacer").is_some() {
rc.writer.write_all(b"<li class=\"spacer\"></li>")?; out.write("<li class=\"spacer\"></li>")?;
continue; continue;
} }
@ -46,30 +40,30 @@ impl HelperDef for RenderToc {
if level > current_level { if level > current_level {
while level > current_level { while level > current_level {
rc.writer.write_all(b"<li>")?; out.write("<li>")?;
rc.writer.write_all(b"<ol class=\"section\">")?; out.write("<ol class=\"section\">")?;
current_level += 1; current_level += 1;
} }
rc.writer.write_all(b"<li>")?; out.write("<li>")?;
} else if level < current_level { } else if level < current_level {
while level < current_level { while level < current_level {
rc.writer.write_all(b"</ol>")?; out.write("</ol>")?;
rc.writer.write_all(b"</li>")?; out.write("</li>")?;
current_level -= 1; current_level -= 1;
} }
rc.writer.write_all(b"<li>")?; out.write("<li>")?;
} else { } else {
rc.writer.write_all(b"<li")?; out.write("<li")?;
if item.get("section").is_none() { if item.get("section").is_none() {
rc.writer.write_all(b" class=\"affix\"")?; out.write(" class=\"affix\"")?;
} }
rc.writer.write_all(b">")?; out.write(">")?;
} }
// Link // Link
let path_exists = if let Some(path) = item.get("path") { let path_exists = if let Some(path) = item.get("path") {
if !path.is_empty() { if !path.is_empty() {
rc.writer.write_all(b"<a href=\"")?; out.write("<a href=\"")?;
let tmp = Path::new(item.get("path").expect("Error: path should be Some(_)")) let tmp = Path::new(item.get("path").expect("Error: path should be Some(_)"))
.with_extension("html") .with_extension("html")
@ -79,16 +73,15 @@ impl HelperDef for RenderToc {
.replace("\\", "/"); .replace("\\", "/");
// Add link // Add link
rc.writer out.write(&utils::fs::path_to_root(&current))?;
.write_all(&utils::fs::path_to_root(&current).as_bytes())?; out.write(&tmp)?;
rc.writer.write_all(tmp.as_bytes())?; out.write("\"")?;
rc.writer.write_all(b"\"")?;
if path == &current { if path == &current {
rc.writer.write_all(b" class=\"active\"")?; out.write(" class=\"active\"")?;
} }
rc.writer.write_all(b">")?; out.write(">")?;
true true
} else { } else {
false false
@ -97,12 +90,12 @@ impl HelperDef for RenderToc {
false false
}; };
if !self.no_section_label { if no_section_label {
// Section does not necessarily exist // Section does not necessarily exist
if let Some(section) = item.get("section") { if let Some(section) = item.get("section") {
rc.writer.write_all(b"<strong aria-hidden=\"true\">")?; out.write("<strong aria-hidden=\"true\">")?;
rc.writer.write_all(section.as_bytes())?; out.write(section)?;
rc.writer.write_all(b"</strong> ")?; out.write("</strong> ")?;
} }
} }
@ -123,22 +116,21 @@ impl HelperDef for RenderToc {
html::push_html(&mut markdown_parsed_name, parser); html::push_html(&mut markdown_parsed_name, parser);
// write to the handlebars template // write to the handlebars template
rc.writer.write_all(markdown_parsed_name.as_bytes())?; out.write(&markdown_parsed_name)?;
} }
if path_exists { if path_exists {
rc.writer.write_all(b"</a>")?; out.write("</a>")?;
} }
rc.writer.write_all(b"</li>")?; out.write("</li>")?;
} }
while current_level > 1 { while current_level > 1 {
rc.writer.write_all(b"</ol>")?; out.write("</ol>")?;
rc.writer.write_all(b"</li>")?; out.write("</li>")?;
current_level -= 1; current_level -= 1;
} }
rc.writer.write_all(b"</ol>")?; out.write("</ol>")?;
Ok(()) Ok(())
} }
}