Search

Dark theme | Light theme

August 7, 2014

Groovy Goodness: Use Custom Template Class with MarkupTemplateEngine

Since Groovy 2.3 we can use the new MarkupTemplateEngine to generate XML/HTML content. The engine compiles the template for better performance and optionally provides type checking on model attributes used in the template. We can configure the template engine to use a custom base template class instead of the default BaseTemplate. In our custom template class we can add new methods that can be invoked from our template content.

Let's create a new base template class with an icon method to output valid FontAwesome markup:

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// File: FontAwesomeTemplate.groovy
package com.mrhaki.groovy.tmpl
 
import groovy.text.markup.*
import groovy.text.*
 
abstract class FontAwesomeTemplate extends BaseTemplate {
 
    FontAwesomeTemplate(
        final MarkupTemplateEngine templateEngine,
        final Map model,
        final Map<String,String> modelTypes,
        final TemplateConfiguration configuration) {
        super(templateEngine, model, modelTypes, configuration)
    }
 
    /**
     * Generate FontAwesome markup.
     *
     * @param icon Name of the icon, will be prefixed with 'fa-'.
     * @param attributes Optional extra attributes, will be added to markup
     *                   and prefixed with 'fa-'.
     * @return Span element with class attribute value for FontAwesome
     */
    String icon(final String icon, final String[] attributes = []) {
        // Prefix attribute names with fa-.
        final faAttributes = attributes.collect { "fa-$it" }
 
        // Create markup.
        $/<span class="fa fa-${icon} ${faAttributes.join(' ')}"></span>/$
    }
 
}

Now we can create a new MarkupTemplateEngine and use our FontAwesomeTemplate class as the base template. We assign our template class to the baseTemplateClass property of TemplateConfiguration:

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import com.mrhaki.groovy.tmpl.*
import groovy.text.*
import groovy.text.markup.*
 
 
// Create configuration and set
// base template class to
// FontAwesomeTemplate.
TemplateConfiguration config = new TemplateConfiguration(
    baseTemplateClass: FontAwesomeTemplate
)
 
// Create engine with configuration.
MarkupTemplateEngine engine = new MarkupTemplateEngine(config)    
 
// Create template with text using
// the icon method.
Template template = engine.createTemplate('''
    ul {
        // Use the name of the icon as argument
        // for the icon method.
        li icon('cloud')
 
        // Any extra arguments are assumed
        // to be FontAwesome attributes.
        li icon('pencil', 'large', 'rotate-90')
    }
 
    // If we want to use the icon method in between
    // text we must use the ${stringOf notation}.
    p "This is a ${stringOf {icon('home')}} home icon."
 
    // Or use yieldUnescaped method.
    p {
        yield "This is a "
        yieldUnescaped icon('cog')
        yield " settings icon."
    }
 
''')   
 
// Render output for template.
Writer writer = new StringWriter()                         
Writable output = template.make([:]) 
output.writeTo(writer)  
String result = writer.toString()
 
 
// This is what we would expect as a result.
// (/ is the continuation character, so it is
//  actually all one line)
def expected = $/\
<ul>\
<li><span class="fa fa-cloud "></span></li>\
<li><span class="fa fa-pencil fa-large fa-rotate-90"></span></li>\
</ul>\
<p>This is a <span class="fa fa-home "></span> home icon.</p>\
<p>This is a <span class="fa fa-cog "></span> settings icon.</p>\
/$
 
assert result == expected

Code written with Groovy 2.3.6.