Skip to content

Commit

Permalink
added Groovy MarkupTemplate Engine
Browse files Browse the repository at this point in the history
The Template Engine is registered for template files with suffix '.tpl'
It is basically a clone of GroovyTemplateEngine using the Groovy MarkupTemplateEngine.

Because there are refactoring pull-requests out there, I skipped refactoring those two Engines for now.
  • Loading branch information
ancho committed Mar 13, 2015
1 parent bf8d00c commit 751c7bb
Show file tree
Hide file tree
Showing 16 changed files with 390 additions and 5 deletions.
131 changes: 131 additions & 0 deletions src/main/java/org/jbake/template/GroovyMarkupTemplateEngine.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
package org.jbake.template;

import com.orientechnologies.orient.core.record.impl.ODocument;
import groovy.lang.GString;
import groovy.lang.Writable;
import groovy.text.Template;
import groovy.text.TemplateEngine;
import groovy.text.XmlTemplateEngine;
import groovy.text.markup.MarkupTemplateEngine;
import groovy.text.markup.TemplateConfiguration;
import org.apache.commons.configuration.CompositeConfiguration;
import org.codehaus.groovy.runtime.MethodClosure;
import org.jbake.app.ConfigUtil.Keys;
import org.jbake.app.ContentStore;
import org.jbake.app.DBUtil;
import org.jbake.app.DocumentList;
import org.jbake.model.DocumentTypes;
import org.xml.sax.SAXException;

import javax.xml.parsers.ParserConfigurationException;
import java.io.*;
import java.util.*;

/**
* Renders documents using the GroovyMarkupTemplateEngine.
*
* @see <a href="http://groovy-lang.org/templating.html#_the_markuptemplateengine">Groovy MarkupTemplateEngine Documentation</a>
*
* The file extension to activate this Engine is .tpl
*/
public class GroovyMarkupTemplateEngine extends AbstractTemplateEngine {

private final Map<String, Template> cachedTemplates = new HashMap<String, Template>();

public GroovyMarkupTemplateEngine(final CompositeConfiguration config, final ContentStore db, final File destination, final File templatesPath) {
super(config, db, destination, templatesPath);
}

@Override
public void renderDocument(final Map<String, Object> model, final String templateName, final Writer writer) throws RenderingException {
try {
Template template = findTemplate(templateName);
Map<String, Object> wrappedModel = wrap(model);
Writable writable = template.make(wrappedModel);
writable.writeTo(writer);
} catch (Exception e) {
throw new RenderingException(e);
}
}

private Template findTemplate(final String templateName) throws SAXException, ParserConfigurationException, ClassNotFoundException, IOException {

TemplateConfiguration templateConfiguration = new TemplateConfiguration();
templateConfiguration.setUseDoubleQuotes(true);
templateConfiguration.setAutoIndent(true);
templateConfiguration.setAutoNewLine(true);
templateConfiguration.setAutoEscape(true);

TemplateEngine ste = new MarkupTemplateEngine(MarkupTemplateEngine.class.getClassLoader(),templatesPath,templateConfiguration);
File sourceTemplate = new File(templatesPath, templateName);
Template template = cachedTemplates.get(templateName);
if (template == null) {
template = ste.createTemplate(new InputStreamReader(new BufferedInputStream(new FileInputStream(sourceTemplate)), config.getString(Keys.TEMPLATE_ENCODING)));
cachedTemplates.put(templateName, template);
}
return template;
}

private Map<String, Object> wrap(final Map<String, Object> model) {
return new HashMap<String, Object>(model) {
@Override
public Object get(final Object property) {
if (property instanceof String || property instanceof GString) {
String key = property.toString();
if ("published_posts".equals(key)) {
List<ODocument> query = db.getPublishedPosts();
return DocumentList.wrap(query.iterator());
}
if ("published_pages".equals(key)) {
List<ODocument> query = db.getPublishedPages();
return DocumentList.wrap(query.iterator());
}
if ("published_content".equals(key)) {
List<ODocument> publishedContent = new ArrayList<ODocument>();
String[] documentTypes = DocumentTypes.getDocumentTypes();
for (String docType : documentTypes) {
List<ODocument> query = db.getPublishedContent(docType);
publishedContent.addAll(query);
}
return DocumentList.wrap(publishedContent.iterator());
}
if ("all_content".equals(key)) {
List<ODocument> allContent = new ArrayList<ODocument>();
String[] documentTypes = DocumentTypes.getDocumentTypes();
for (String docType : documentTypes) {
List<ODocument> query = db.getAllContent(docType);
allContent.addAll(query);
}
return DocumentList.wrap(allContent.iterator());
}
if ("alltags".equals(key)) {
List<ODocument> query = db.getAllTagsFromPublishedPosts();
Set<String> result = new HashSet<String>();
for (ODocument document : query) {
String[] tags = DBUtil.toStringArray(document.field("tags"));
Collections.addAll(result, tags);
}
return result;
}
String[] documentTypes = DocumentTypes.getDocumentTypes();
for (String docType : documentTypes) {
if ((docType+"s").equals(key)) {
return DocumentList.wrap(db.getAllContent(docType).iterator());
}
}
if ("tag_posts".equals(key)) {
String tag = model.get("tag").toString();
// fetch the tag posts from db
List<ODocument> query = db.getPublishedPostsByTag(tag);
return DocumentList.wrap(query.iterator());
}
if ("published_date".equals(key)) {
return new Date();
}
}

return super.get(property);
}
};
}
}
5 changes: 0 additions & 5 deletions src/main/java/org/jbake/template/GroovyTemplateEngine.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package org.jbake.template;

import com.orientechnologies.orient.core.db.document.ODatabaseDocumentTx;
import com.orientechnologies.orient.core.record.impl.ODocument;
import com.orientechnologies.orient.core.sql.query.OSQLSynchQuery;

import groovy.lang.GString;
import groovy.lang.Writable;
Expand All @@ -22,13 +20,10 @@
import javax.xml.parsers.ParserConfigurationException;

import java.io.BufferedInputStream;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collections;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
org.jbake.template.FreemarkerTemplateEngine=ftl
org.jbake.template.GroovyTemplateEngine=groovy,gsp,gxml
org.jbake.template.GroovyMarkupTemplateEngine=tpl
org.jbake.template.ThymeleafTemplateEngine=thyme,html
1 change: 1 addition & 0 deletions src/test/groovy/org/jbake/app/RendererSpec.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class RendererSpec extends Specification {
@Shared
def templateMap = [
'groovyTemplates': '.gsp',
'groovyMarkupTemplates': '.tpl',
'thymeleafTemplates': '.thyme',
'templates' : '.tfl'
]
Expand Down
9 changes: 9 additions & 0 deletions src/test/resources/groovyMarkupTemplates/allcontent.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
xmlDeclaration()
list{
all_content.each { cntnt ->
content {
uri("${config.site_host}${cntnt.uri}")
date(${cntnt.date.format("yyyy-MM-dd")})
}
}
}
26 changes: 26 additions & 0 deletions src/test/resources/groovyMarkupTemplates/archive.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
layout 'layout/main.tpl',
bodyContents: contents {
div(class:"row-fluid marketing"){
div(class:"span12"){
h2('Archive')
def last_month
posts.each {post ->
if (last_month) {
if (post.date.format("MMMM yyyy") != last_month) {
h3("${post.date.format("MMMM yyyy")}")
}
}
else {
h3("${post.date.format("MMMM yyyy")}")
}

h4 {
yield "${post.date.format("dd MMMM")} - "
a(href:"${post.uri}","${post.title}")
}
last_month = post.date.format("MMMM yyyy")
}
}
}
}
22 changes: 22 additions & 0 deletions src/test/resources/groovyMarkupTemplates/feed.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
xmlDeclaration()
rss(version:"2.0", 'xmlns:atom':'http://www.w3.org/2005/Atom') {
channel {
title('JonathanBullock.com')
link('http://jonathanbullock.com/')
atom:link(href:"http://jonathanbullock.com/feed.xml", rel:"self", type:"application/rss+xml")
description('My corner of the Internet')
language('en-gb')
pubDate("${published_date.format("EEE, d MMM yyyy HH:mm:ss Z")}")
lastBuildDate("${published_date.format("EEE, d MMM yyyy HH:mm:ss Z")}")
posts.each { post ->
item{
title("${post.title}")
link("http://jonathanbullock.com${post.uri}")
pubDate("${post.date.format("EEE, d MMM yyyy HH:mm:ss Z")}")
guid(isPermaLink:"false","${post.uri}")
description("${post.body}")
}
}
}
}
8 changes: 8 additions & 0 deletions src/test/resources/groovyMarkupTemplates/footer.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
div(class:"footer"){
p{
yieldUnescaped '&copy; Jonathan Bullock 2013 | Mixed with '
a(href:"http://twitter.github.com/bootstrap/",'Bootstrap v2.3.1')
yieldUnescaped '| Baked with '
a(href:"http://jbake.org","JBake ${version}")
}
}
59 changes: 59 additions & 0 deletions src/test/resources/groovyMarkupTemplates/header.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
meta(charset:'utf-8')
title('Jonathan Bullock')
meta(name:"viewport", content:"width=device-width, initial-scale=1.0")
meta(name:"description", content:"")
meta(name:"author", content:"Jonathan Bullock")

yieldUnescaped '<!-- Le styles -->'
link(href:"/css/bootstrap.min.css", rel:"stylesheet")
style(type:"text/css") {
yieldUnescaped """body {
padding-top: 20px;
padding-bottom: 40px;
}
/* Custom container */
.container-narrow {
margin: 0 auto;
max-width: 700px;
}
.container-narrow > hr {
margin: 30px 0;
}
/* Main marketing message and sign up button */
.jumbotron {
margin: 60px 0;
text-align: center;
}
.jumbotron h1 {
font-size: 72px;
line-height: 1;
}
.jumbotron .btn {
font-size: 21px;
padding: 14px 24px;
}
/* Supporting marketing content */
.marketing {
margin: 60px 0;
}
.marketing p + h4 {
margin-top: 28px;
}"""
}
link(href:"/css/bootstrap-responsive.min.css", rel:"stylesheet")

yieldUnescaped '<!-- HTML5 shim, for IE6-8 support of HTML5 elements -->'
yieldUnescaped '<!--[if lt IE 9]>'
script( src:"/js/html5shiv.js")
yieldUnescaped '<![endif]-->'

yieldUnescaped '<!-- Fav and touch icons -->'
yieldUnescaped '<!--<link rel="apple-touch-icon-precomposed" sizes="144x144" href="../assets/ico/apple-touch-icon-144-precomposed.png">'
link(rel:"apple-touch-icon-precomposed", sizes:"114x114", href:"../assets/ico/apple-touch-icon-114-precomposed.png")
link(rel:"apple-touch-icon-precomposed", sizes:"72x72", href:"../assets/ico/apple-touch-icon-72-precomposed.png")
link(rel:"apple-touch-icon-precomposed", href:"../assets/ico/apple-touch-icon-57-precomposed.png")
link(rel:"shortcut icon", href="../assets/ico/favicon.png")
yieldUnescaped '-->'
13 changes: 13 additions & 0 deletions src/test/resources/groovyMarkupTemplates/index.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
layout 'layout/main.tpl',
bodyContents: contents {
div(class:"row-fluid marketing"){
div(class:"span12"){
posts[0..<2].each { post ->
h4 { a(href:"${post.uri}","${post.title}") }
p("${post.date.format("dd MMMM yyyy")} - ${post.body.substring(0, 150)}...")
}
a(href:"/archive.html",'Archive')
}
}
}
28 changes: 28 additions & 0 deletions src/test/resources/groovyMarkupTemplates/layout/main.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
yieldUnescaped '<!DOCTYPE html>'
html(lang:'en'){
head {
include template: "header.tpl"
}

body {
div(class:"container-narrow"){
include template: 'menu.tpl'
hr()
bodyContents()
hr()
include template: 'footer.tpl'
}

script(src:"/js/jquery-1.9.1.min.js"){}
newLine()
script(src:"/js/bootstrap.min.js"){}
}
}
newLine()
9 changes: 9 additions & 0 deletions src/test/resources/groovyMarkupTemplates/menu.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
div(class:"masthead"){
ul(class:"nav nav-pills pull-right"){
li { a(href:"/",'Home') }
li { a(href:"/about.html",'About') }
li { a(href:"/projects.html",'Projects') }
li { a(href:"/feed.xml",'Subscribe') }
}
h3(class:"muted",'Jonathan Bullock')
}
22 changes: 22 additions & 0 deletions src/test/resources/groovyMarkupTemplates/page.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
layout 'layout/main.tpl',
bodyContents: contents {
div(class:"row-fluid marketing"){
div(class:"span12"){
h4("${content.title}")
p("${content.body}")
}
}

hr()

h5('Published Pages')
published_pages.each {page ->
a(href:"${config.site_host}${page.uri}","${page.title}")
}

}




20 changes: 20 additions & 0 deletions src/test/resources/groovyMarkupTemplates/post.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
layout 'layout/main.tpl',
bodyContents: contents {
div(class:"row-fluid marketing"){
div(class:"span12"){
h2("${content.title}")
p(class:"post-date", "${content.date.format("dd MMMM yyyy")}")
p("${content.body}")
}
}

hr()

h5('Published Posts')

published_posts.each { post ->
a(href:"${config.site_host}${post.uri}","${post.title}")
}

}
Loading

0 comments on commit 751c7bb

Please sign in to comment.