Helma Logo
main list history

Helma 2 Templates - hannes

Spec

  1. Macros in skins are delimited by <% %>.
  2. Macros can contain both named and unnamed parameters, in any combination (see Notes for implementation details).
  3. Named parameters are denoted as name=value, unnamed parameters are denoted as value.
  4. The following types are supported as parameter values:
    1. strings: "foo"
    2. numbers: 13
    3. boolean false|true
    4. object literals: {foo: bar, x: y}
    5. array literals: [1, 2, "drei"]
  5. For string values, single or double quotes are optional unless the value contains whitespace characters.
  6. Round brackets ( ) can be used to group multiple macro parameters into one. (syntactic sugar for arrays?)
  7. Macro parameter values wrappedn in {{ }} are interpreted as nested skins.
  8. Helma provides native skin scanning/parsing features, but skins and macros are implemented in JavaScript.
  9. Nested skins and macros are passed to macros as skin and macro objects, respectively. In other words, macro evaluation and skin rendering is up to the containing macro.
  10. Todo: provide a feature for marking subtemplates within a skin file.

Parsed skins are exposed as JavaScript arrays, with the static skin parts represented by string elements, while the macro parts are represented by a MacroTag class. The MacroTag class is itself a JavaScript array, with an additional params property to expose the named parameters.

Consider for example the following skin source:

  image <% img dancer.gif dim={width: 30, height: 120} %>

It is parsed to the following construct:

  [image , [img, dancer.gif]{dim={width=30.0, height=120.0}}]

and the following conditions would evaluate to true:

  skin.length == 2;
  skin[0] == "image ";
  skin[1].length == 2;
  skin[1][0] == "img"; 
  skin[1][1] == "dancer.gif";
  skin[1].params.dim.width == 30;
  skin[1].params.dim.height == 120;

Implementation

Native template scanning support is implemented in class org.helma.template.TemplateScanner, which can be conveniently accessed using the global parseSkin(str) and parseSkinResource(path) functions. It parses skins to a java.util.List filled with Strings for the static parts and Macro tags, which are again java.util.List objects with a special param property that contains the tag's named parameters.

All this is wrapped in ScriptableLists and ScriptableMaps so you can sweep through it like it were native JavaScript arrays and objects.

I started a simple JavaScript renderer for skins parsed this way. It currently implements very simplistic if/foreach constructs.

nametypesize
Templatex.jsundefined bytes
test.skinundefined bytes

The following code shows how to use this:

  mountRepository("jslib");
  include("jslib/template/Templatex.js");
  
  function handle_get() {
    var t = new Templatex("skins/main.skin");
    t.render({topics: ["Berge", "Taeler", "Seen", "Fluesse"]});
  }

Todo

What probably remains to be done is add smarts to the parsing of parenthesised expressions such as "(foo in bar)" or "(x < y)". Currently, these are simply parsed to a separate list/array. We might use a special purpose class for this that gives some support in determining what kind of expression we're dealing with.

Examples

I removed the old examples since they didn't match the renewed spec anymore. Generally speaking, all kinds of macro syntax can be implemented based on the features discribed in this proposals, as long as they use <% %> as macro delimiters.

Comments

I removed Jürg's comments as well, for the same reason.

Links to this page: Helma 2 Templates