loading table of contents...

4.3.4. Writing Templates

A template accesses variables in its current environment that have been provided by the controller. In a CoreMedia Content Application Engine template, the property self has a special meaning: it denotes the target object on which the template was invoked. It is the equivalent of the this object reference in Java methods. A simple FreeMarker template to display the title property of a target object of type com.company.Article and set the Content-Type HTTP response header looks as follows:

<@cm.responseHeader name="Content-Type" value="text/html; charset=UTF-8"/>
<#-- @ftlvariable name="self" type="com.company.Article" -->
${self.title}

While the @ftlvariable comment is not necessary, it serves as a hint for the IntelliJ IDEA development environment to support code completion for the self variable.

Template Output Escaping for HTML

To prevent output that allows cross-site scripting (XSS) attacks, the CAE switches on HTML escaping for all FreeMarker templates by default. More precisely, each FreeMarker template is automatically wrapped in an #escape directive:

<#escape x as x?html>
  ...
</#escape>

This #escape directive leads to all FreeMarker "interpolations" (${...} expressions) being HTML-escaped when written to the output stream. All literal output of the template is of course not escaped. See FreeMarker online documentation for details.

In special cases, it might be necessary to disable escaping. For this purpose, FreeMarker provides the directive #noescape. However, this directive is only allowed nested inside an #escape directive, so because the outer #escape directive is implicit, an IDE could regard this an error.

To always have valid templates and to also be able to change the escaping type to something other than HTML, the CAE only wraps templates that do not contain any #escape directives themselves. Thus, to switch off escaping, you have to make the outer escaping explicit:

<#escape x as x?html>
  ...
  <#noescape>...</#noescape>
  ...
</#escape>
[Caution]Caution

Note that disabling HTML escaping can lead to cross-site scripting (XSS) vulnerabilities if a templates outputs unchecked data like user input that may contain scripts.

The same applies to the use case of changing the escaping type to something other than HTML:

<#escape x as x?xml>
  ...
</#escape>

Like said above, specifying any #escape directive in your template completely disables any automatic escaping normally added by the CAE. Otherwise, specifying custom escaping would have lead to double escaping, which is not desired.

Template Inclusion

Other templates can be included via FreeMarker's <#include> directive. However, in this case the view dispatcher is not involved in determining the included file. In order to involve the view dispatcher, you need to use the include macro from the Content Application Engine's FreeMarker library cae.ftl. This library is auto-imported under the namespace cm. In FreeMarker, custom macros are invoked using <@namespace.macro>. The macro @cm.include requires an attribute self to determine the target object for the view. The following code will find the appropriate template named "teaser" for anObject and include its output into the current page. Inside that template, self is temporarily bound to anObject:

<@cm.include self=anObject view="teaser"/>

Assuming that anObject is of type Article, the template Article.teaser.ftl will be included. The view attribute is optional; the default template (in this example, Article.ftl) will be chosen in case it is omitted. When no template for the view name "teaser" is found, the search will end with a failure - the default template is not used as a fallback! Also, the include will fail if anObject is null (unless you specify a default value of cm.UNDEFINED for self, see reference).

A template including the teaser views of all objects in its articles property would look as follows. Within each teaser template, self will be bound to the respective article object. Note the use of FreeMarker's built-in #list directive:

<#list self.articles as article>
  <@cm.include self=article view="teaser"/>
</#list>

When looking for the appropriate template, the Content Application Engine performs the same steps as in an object-oriented language. If no template is defined for a target bean type, it will be inherited from its super type: the CAE will look for the template upwards in the inheritance hierarchy. It also considers interfaces, so you can register templates for interfaces, too.

Rendering Markup

Markup properties are also rendered by including them. Assuming self has a method getText returning a com.coremedia.xml.Markup, this template snippet will render the text value using the default markup view.

<@cm.include self=self.text/>

The CoreMedia CAE defines a default view for objects of type com.coremedia.xml.Markup that converts CoreMedia richtext to XHTML. See Section 4.3.4.1, “Rendering Markup” for details.

Template Parameters

CAE includes allow handing over parameters from the calling template to the included one. This is implemented by temporarily setting a request scope attribute and resetting it to its old value after the included fragment returns.

In a FreeMarker template, the include macro and the getLink function support such parameters by using a hash-valued parameter named params. Macro include also allows adding parameters as additional attribute-value pairs to the macro itself. These two includes are equivalent:

<@cm.include self=article view="teaser"
             params={ "images": false }/>

<@cm.include self=article view="teaser" images=false/>

Within the "teaser" template, the variable images will be set to false and will revert to its original value (if any) afterwards.

Linking

Like include, linking also works with objects. To compute a URL to an object and a view, you can use the CAE FreeMarker library function getLink():

<a href="${cm.getLink(article, "teaser")}">more</a>

This function consults the LinkFormatter strategy to compute a URL and hands in its first parameter as the target object and its second parameter as the (optional) view identifier. The link formatter strategy requires a link scheme that is able to handle the class of the object. All generated content beans implement the ContentBean interface for which a link scheme exists; so there is no need to implement another one. It is necessary for beans that originate from other sources.

Using the function in an expression (FreeMarker: "interpolation"), the formatted URL is written directly to the page. If the URL is used several times within the template or if you feel that the actual template code looks cleaner when separating URL computation and usage, use FreeMarker's #assign directive to assign the resulting URL to a variable:

<#assign teaserLink><@cae.link target=article view="teaser"/></#assign>
<a href="${teaserLink}">more</a>

You can hand over parameters to the LinkFormatter as an optional third parameter of the getLink() function, specified as a FreeMarker hash of name-value pairs. If you do not want to specify a view, you can also hand over parameters as the second parameter. Do not forget to quote the keys and not quote the values (unless they are strings, of course).