zola/components/utils/src/templates.rs

109 lines
4.1 KiB
Rust
Raw Normal View History

use std::collections::HashMap;
2018-10-31 07:18:57 +00:00
use tera::{Context, Tera};
2017-08-23 10:17:24 +00:00
2019-12-21 21:52:39 +00:00
use errors::{bail, Result};
2017-08-23 10:17:24 +00:00
2017-11-27 17:09:09 +00:00
static DEFAULT_TPL: &str = include_str!("default_tpl.html");
macro_rules! render_default_tpl {
2018-10-31 07:18:57 +00:00
($filename: expr, $url: expr) => {{
let mut context = Context::new();
context.insert("filename", $filename);
context.insert("url", $url);
2019-10-20 18:08:01 +00:00
Tera::one_off(DEFAULT_TPL, &context, true).map_err(std::convert::Into::into)
2018-10-31 07:18:57 +00:00
}};
2017-11-27 17:09:09 +00:00
}
2017-08-23 10:17:24 +00:00
/// Renders the given template with the given context, but also ensures that, if the default file
/// is not found, it will look up for the equivalent template for the current theme if there is one.
/// Lastly, if it's a default template (index, section or page), it will just return an empty string
/// to avoid an error if there isn't a template with that name
2018-10-31 07:18:57 +00:00
pub fn render_template(
name: &str,
tera: &Tera,
2019-01-23 18:20:02 +00:00
context: Context,
2018-10-31 07:18:57 +00:00
theme: &Option<String>,
) -> Result<String> {
// check if it is in the templates
2017-08-23 10:17:24 +00:00
if tera.templates.contains_key(name) {
2019-10-20 18:08:01 +00:00
return tera.render(name, &context).map_err(std::convert::Into::into);
2017-08-23 10:17:24 +00:00
}
// check if it is part of a theme
2018-05-11 11:54:16 +00:00
if let Some(ref t) = *theme {
let theme_template_name = format!("{}/templates/{}", t, name);
if tera.templates.contains_key(&theme_template_name) {
2019-10-20 18:08:01 +00:00
return tera.render(&theme_template_name, &context).map_err(std::convert::Into::into);
}
}
// check if it is part of ZOLA_TERA defaults
let default_name = format!("__zola_builtins/{}", name);
if tera.templates.contains_key(&default_name) {
2019-10-20 18:08:01 +00:00
return tera.render(&default_name, &context).map_err(std::convert::Into::into);
2017-08-23 10:17:24 +00:00
}
2017-11-27 17:09:09 +00:00
// maybe it's a default one?
match name {
2018-10-31 07:18:57 +00:00
"index.html" | "section.html" => render_default_tpl!(
name,
"https://www.getzola.org/documentation/templates/pages-sections/#section-variables"
),
"page.html" => render_default_tpl!(
name,
"https://www.getzola.org/documentation/templates/pages-sections/#page-variables"
),
2018-07-16 08:54:05 +00:00
"single.html" | "list.html" => {
render_default_tpl!(name, "https://www.getzola.org/documentation/templates/taxonomies/")
2018-07-31 13:17:31 +00:00
}
2018-10-31 07:18:57 +00:00
_ => bail!("Tried to render `{}` but the template wasn't found", name),
}
2017-08-23 10:17:24 +00:00
}
/// Rewrites the path of duplicate templates to include the complete theme path
/// Theme templates will be injected into site templates, with higher priority for site
/// templates. To keep a copy of the template in case it's being extended from a site template
/// of the same name, we reinsert it with the theme path prepended
pub fn rewrite_theme_paths(tera_theme: &mut Tera, theme: &str) {
let theme_basepath = format!("{}/templates/", theme);
let mut new_templates = HashMap::new();
for (key, template) in &tera_theme.templates {
let mut tpl = template.clone();
tpl.name = format!("{}{}", theme_basepath, key);
new_templates.insert(tpl.name.clone(), tpl);
}
// Contrary to tera.extend, hashmap.extend does replace existing keys
// We can safely extend because there's no conflicting paths anymore
tera_theme.templates.extend(new_templates);
}
#[cfg(test)]
mod tests {
use super::rewrite_theme_paths;
2018-10-31 07:18:57 +00:00
use tera::Tera;
#[test]
fn can_rewrite_all_paths_of_theme() {
2017-11-27 17:09:09 +00:00
let mut tera = Tera::parse("test-templates/*.html").unwrap();
rewrite_theme_paths(&mut tera, "hyde");
// special case to make the test work: we also rename the files to
// match the imports
2020-02-10 22:09:22 +00:00
for (key, val) in &tera.templates.clone() {
tera.templates.insert(format!("hyde/templates/{}", key), val.clone());
}
2020-02-10 22:09:22 +00:00
// Adding our fake base
tera.add_raw_template("base.html", "Hello").unwrap();
tera.build_inheritance_chains().unwrap();
2020-02-10 22:09:22 +00:00
assert_eq!(
tera.templates["hyde/templates/index.html"].parent,
Some("base.html".to_string())
);
assert_eq!(
tera.templates["hyde/templates/child.html"].parent,
Some("index.html".to_string())
2020-02-10 22:09:22 +00:00
);
}
}