Helma 2 Templates - ORF.at
From our experience with Helma's skin templating features we came to the following general conclusions for further developments in version 2.0:
- Helma core has to remain as simple as we know it.
- Separation of presentation and logic has priority.
- Backwards-compatibility is required in any way.
- Other concepts (templating engines) should only be considered as pluggable extensions to helma.
That's why we come up with a
- A skin is identified via a label using a new syntax (open for discussion, I am using
<% anchor %>in the example).
- There is only one single level of label hierarchy, ie. a flat collection of labels.
- Skin labels are to be used as reference in functions and macros. This provides both, familiar access to as well as advanced rendering (loops, switch/case-like conditions?) of skins.
- Skins can contain local symbols (or call it variables) containing a string value that can be re-used throughout one single skin. (Syntax open for discussion.)
- Macros in skins are delimited by <% %>.
- There are no nested macros in macros. (I know, this will hardly stand the desire.)
- Object mappings extend the macro handler for easier access to properties of the contained object.
- Each HopObject contains certain macros from scratch (e.g. loop w/ sorting, skin embedding etc.) -> scaffolding!
- HopObject properties and the corresponding form input in a skin (display, check, error messaging) are firmly and closely connected, generally and finally.
- Certain macros already come implemented with useful parameter options. E.g. if the macro renders a number it should provide a way for reflecting the amount in the measure unit like "no comment", "one comment", "5 comments".
<% define greeting="Hello" %> <% greeting %>, <% session.user.name %>! <% this.render skin="#time" %>. There are currently <% this.users.size %> other users logged in: <% this.users.loop skin="#user" %> <% anchor name="now" %> <% now format="EEE, dd.MM.yyyy, HH:mm'h'" %> <% anchor name="time" %> Today is <% this.render skin="#now" %>. <% anchor name="user%> <% greeting %>, <% user.name %>!
The imagined output of rendering the above skin:
Hello, Brian! Today is Wed, 15.02.2006, 15:31h. There are currently 3 other users logged in: Hello, Adele! Hello, Carver! Hello, Diane!
Lets assume an antville-like object-structure. We have a skin on site-level, and want to display a localized h1-headerlist, a paragraph with a verbose localized string of the number of topics (=Site.topics.count()), and a table (with rows of alternating colors) of all topic names, and their number of stories (=Topic.count()). If no topics are present then the whole table should not be rendered.Assumptions:
- Helma is automagically mapping all 1:1 child objects and 1:n collections of the current path handler to global handlers: site.topics becomes "topics", topic.stories "stories". The handler of the default collection is named "children".
- There is a HopObject-wide
countmacro that takes three additional parameters called "none", "one" and "many" of which only "many" is rendered with the actual number of items calculated by Helma.
- topic.counter is a macro that gets its function body newly assigned each iteration (needs to be elaborated).
- Inline skins work similar to HTML anchor elements. Helma should stop rendering the skin itself as soon as it detects an
<% anchor %>macro. With each following occurence of an
<% anchor %>the previous anchor skin is ended and a new one begins.
<h1>Headerlist<h1> <small>(sorry, I currently have no idea what this headerlist thing is about...)</small> <p> <% topics.count prefix="Number of topics: " none="no topics" one="1 topic" many=" topics" %> </p> <% topics.list prefix="<table>" suffix="</table>" skin="#topicItem" %> <% anchor name="topicItem" %> <tr> <td <% topic.counter odd='style="background-color: yellow;"' %>> <% topic.name %> <% stories.count prefix="(" suffix=")" %> </td> </tr>