Helma Logo
main list history
previous version  overview  next version

Version 7 by tobi on 05. October 2006, 23:01

While developing the first version of *Rabbit* a little idea came into my mind which suddenly opened a door for even more comfortable skin rendering.

I added a method called <code>render()</code> which mainly is wrapping renderSkin(). However, it takes a string as third argument:

function render(skin, param, str) {
    renderSkin(skin, param);
}

This string is used as name for a property of res.handlers.rendered
the rendered skin will be assigned to:

function render(skin, param, str) {
    if (str) {
      var result = this.renderSkinAsString(skin, param);
      res.handlers.rendered[str] = result;
      return result;
    } else {
      renderSkin(skin, param);
    }
}

Also note that the rendered skin is returned as result if the third argument is set making a notorious "renderAsString()" sibling obsolete.

This way, I now can do the following with render():

// directly output a rendered skin as usual
render("foo", param);
// assign a rendered skin as string to a variable
var bar = render("foo", param, "foobar");
// use the "rendered" handler as container of previously rendered skins
render(createSkin("<% rendered.foobar %>")); // displays contents of res.handlers.rendered.foobar (which is the same as bar above)

By cascading render calls, each with a third argument, it's very easy to build structures:

render("header", null, "one");
render("main", {name: "World"}, "two");
render("footer", null, "three");
render("page");

The skins:

<!-- header.skin -->
<html>
<title>Test</title>
<body>

<!-- main.skin -->
Hello, <% param.name %>!

<!-- footer.skin -->
</body>
</html>

<!-- page.skin -->
<% rendered.one %>
<% rendered.two %>
<% rendered.three %>

The above code virtually cries for dropping the third argument again and using the first (the skin name) as the name for the res.handlers.rendered property. However, then we need a different method to indicate that a skin should be rendered as string and to prevent every rendered skin being assigned to a res.handlers.rendered property...

Of course, many improvements can be made from here. What I did in a final step is to append rendered skins if the third argument specifies a property already defined in res.handlers.rendered:

function render(skin, param, str) {
    if (str) {
      var result = this.renderSkinAsString(skin, param);
      if (!res.handlers.rendered[str]) {
          res.handlers.rendered[str] = "";
      }
      res.handlers.rendered[str] += result;
      return result;
    } else {
      renderSkin(skin, param);
    }
}
 
Now it becomes really elegant to render a collection:

render("header", null, "one");
for (var i=0; i<this.size(); i+=1) {
    render("item", this.get(i), "list");
}
render("footer", null, "two");
render("page");

<!-- listitem.skin -->
<a href="<% param.url %>"><% param.name %></a>

<!-- page.skin -->
<% rendered.one %>
<% rendered.list %>
<% rendered.two %>

Here, the only ugly thing is the missing HopObejct render() method and that we have to send the item object as argument into the global render() method. Just needs to be done.

     removed
     added