package org.jbake.template; import de.neuland.jade4j.Jade4J; import de.neuland.jade4j.JadeConfiguration; import de.neuland.jade4j.exceptions.JadeCompilerException; import de.neuland.jade4j.filter.CDATAFilter; import de.neuland.jade4j.filter.CssFilter; import de.neuland.jade4j.filter.JsFilter; import de.neuland.jade4j.model.JadeModel; import de.neuland.jade4j.template.FileTemplateLoader; import de.neuland.jade4j.template.JadeTemplate; import de.neuland.jade4j.template.TemplateLoader; import org.apache.commons.configuration.CompositeConfiguration; import org.apache.commons.lang.StringEscapeUtils; import org.jbake.app.ConfigUtil.Keys; import org.jbake.app.ContentStore; import java.io.File; import java.io.IOException; import java.io.Writer; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; import java.util.Map; /** * Renders pages using the <a href="http://jade.org/">Jade</a> template language. * * @author Aleksandar Vidakovic * @author Mariusz Smykuła */ public class JadeTemplateEngine extends AbstractTemplateEngine { private static final String FILTER_CDATA = "cdata"; private static final String FILTER_STYLE = "css"; private static final String FILTER_SCRIPT = "js"; private JadeConfiguration jadeConfiguration = new JadeConfiguration(); public JadeTemplateEngine(final CompositeConfiguration config, final ContentStore db, final File destination, final File templatesPath) { super(config, db, destination, templatesPath); TemplateLoader loader = new FileTemplateLoader(templatesPath.getAbsolutePath() + File.separatorChar, config.getString(Keys.TEMPLATE_ENCODING)); jadeConfiguration.setTemplateLoader(loader); jadeConfiguration.setMode(Jade4J.Mode.XHTML); jadeConfiguration.setPrettyPrint(true); jadeConfiguration.setFilter(FILTER_CDATA, new CDATAFilter()); jadeConfiguration.setFilter(FILTER_SCRIPT, new JsFilter()); jadeConfiguration.setFilter(FILTER_STYLE, new CssFilter()); jadeConfiguration.getSharedVariables().put("formatter", new FormatHelper()); } @Override public void renderDocument(Map<String, Object> model, String templateName, Writer writer) throws RenderingException { try { JadeTemplate template = jadeConfiguration.getTemplate(templateName); renderTemplate(template, model, writer); } catch (IOException e) { throw new RenderingException(e); } } public void renderTemplate(JadeTemplate template, Map<String, Object> model, Writer writer) throws JadeCompilerException { JadeModel jadeModel = wrap(jadeConfiguration.getSharedVariables()); jadeModel.putAll(model); template.process(jadeModel, writer); } private JadeModel wrap(final Map<String, Object> model) { return new JadeModel(model) { @Override public Object get(final Object property) { String key = property.toString(); try { return extractors.extractAndTransform(db, key, model, new TemplateEngineAdapter.NoopAdapter()); } catch(NoModelExtractorException e) { // fallback to parent model } return super.get(property); } }; } public static class FormatHelper { private Map<String, SimpleDateFormat> formatters = new HashMap<String, SimpleDateFormat>(); public String format(Date date, String pattern) { if(date!=null && pattern!=null) { SimpleDateFormat df = formatters.get(pattern); if(df==null) { df = new SimpleDateFormat(pattern); formatters.put(pattern, df); } return df.format(date); } else { return ""; } } public String escape(String s) { return StringEscapeUtils.escapeHtml(s); } } }