[Helma-dev] FreeMarker Template Introduction

Juerg Lehni juerg at scratchdisk.com
Fri Nov 25 13:38:27 CET 2005


Despite the complete lack of reactions I write one more email that  
explains the FreeMarker template extension a bit in more detail.

I now prefer this extension a lot over the Velocity extension, it  
fits in very nicely, and since the latest updates it is even  
compatible with helma macros, and offers access to all values that  
normal skins have access to as well, plus much more (maybe a bit too  
much at the moment, but that can easily be narrowed down in the  
RhinoWrapepr):

Through the RhinoMapper, FreeMarker allows Scriptable objects  
(JavaScript scopes) as the rootMap that exposes all data to the  
template. So all i need to do is create a new scope that uses the  
global scope as its prototype, add the "this" reference to it, and  
pass this to the renderer. All the global objects known in the  
JavaScript scopes (res, req, session, path, root, etc.) are then  
available in the template engine as well, through the same notation.

And since I added support for normal skin macros (and an extended  
version, see bellow), macros in "this", "root", and even global  
macros can be called just like in skins.

So here's a little overview (without giving a full introduction in  
FreeMarker):

- Conditional statements, expressions:

   <#if !session.user?exists>
     Hello ${session.user.name}
   <#else>
     <a href="/login">Login</a>
   </#if>

- Loops:

   <table>
     <#list res.data.nodes as node>
       <tr>
         <td>${node_index + 1}.</td>
         <td>${node.name}<#if node_has_next>,</#if></td>
       </tr>
     </#list>
   </table>

- Macros:

   <@this.macro foo="bar" bla="bla" />

   <@globalMacro />

   various types can be passed as parameters: arrays, hashes, etc:

   <@root.macro array=[1, 2, 3, 4] />
   <@root.macro hash={ "foo": "bar" } />

- Macros with nested content:

   <@this.nested foo="bar">Nested text</@>

   function nested_macro(param, nested) {
     // param.foo == "bar"
     // nested == "Nested text"
   }

- Call methods and JavaScript functions:

   ${ this.href() }
   ${ this.getParent().href() }

But that's just the tip of the eisberg. You can define macros and  
functions in the template language (FTL) as well, include other  
templates, localization is built in (but not supported by the  
extension as of yet. I still need to find a nice way to do so).

All in all I think this is very powerfull and fits into Helma very  
nicely. I would prefer if some parts of the syntax could be name  
differently, but I guess that's the price I'll have to pay to have  
flexibility. : )
One could also argue about too much freedom...

One thing that I've changed is notation: response, request are not  
known in the templates. Use req.data / res.data instead, just like  
you would in the scripts. I could add these objects for backward  
"compatibility", but as other things have changed as well, I don't  
mind that they're not there any more. It's more consistent in that  
way. And I couldn't simulate session, because this has the same name  
in JavaScript and the Skin templates, so the session that links to  
session.data would override the session object that would give access  
to for example session.user.

It would be great to hear other opinions on this. FreeMarker feels  
like a natural extension to Helma and is very flexible in the way  
it's integrated. I'm pretty impressed with it. Maybe it could be  
considered for a tighter integration at a later point?

Jürg






More information about the Helma-dev mailing list