The majority of Mold's operators are concerned with plain text,
but a few of them are HTML-specific, in that they refer to the
nodes created by the template. Some magic is involved in this (see
section 'Implementation'), but
Mold.cast encapsulates that
In a typical use scenario, the web application somehow gets template strings from the server (it could directly fetch text files, or the strings might be in script files), compiles them once, and then uses the resulting 'molds' to build up parts of the document.
Mold consists of only a single (small) script file:
mold.js. The library is licenced
under a zlib-style license. For those
wanting to work on it, the git
repository can be gotten from
http://marijnhaverbeke.nl/git/mold. The code is also
I am not doing numbered releases, since the userbase is still small. The library interface can be considered stable, though.
You are welcome to mail me (Marijn Haverbeke) with any questions or problems you have.
A template to build a simple multiple choice widget, for example, might look like this (refer to the explanation below if something confuses you):
<div class="choice"> <h2>Choose one:</h2> <?do var odd = false;?> <ol> <?label choiceList?> <?for choice $arg?> <li class="option [?text (odd = !odd) ? "odd" : "even"?]"> <?event click handleChoice(choice);?> <?if typeof choice == "string"?> <strong><?text choice?></strong> <?else?> <?html choice.render()?> <?/if?> </li> <?/for?> </ol> </div>
This loops over an array of choices, building up a
representation of each choice, with a special case for choices
that are simple strings. Note that
also be a mold function. Templates can easily be composed like
To use Mold, you include
mold.js in your document, which
Mold object that is the interface to the
Mold.bake function, which takes a
single string as an argument, is used to transform a template
string into a mold. A mold is a function that takes a single
argument (or none, if your template does not use any parameter
data) and returns a string.
Mold uses XML processing instruction syntax for template
operators. This means '
?>' are used around all instructions, as in PHP.
Contrary to PHP, though, Mold uses several different processing
instructions which serve different roles. After the
<?', an instruction name should follow (see
below). In cases where you don't want to use angle brackets
(inside attributes in a valid XML document, for example),
[?' and '
?]' can be used as
(Note that the scanner used by Mold is rather simplistic. If
you have a string or regular expression containing
?>' inside your instruction, you should use
?\>' instead, to prevent it from being recognised
as the end of the instruction.)
The following instructions are recognised:
$argthroughout), and inserted as text ― meaning any HTML special character in it will be escaped.
text, but the result of the expression is not escaped, so HTML tags can be inserted.
do) without producing output. Can be useful for defining local variables (any variables defined in such a block will be visible to instructions coming after it.)
else) will not be evaluated/expanded.
elifthat did not fire, evaluates the expression it is given, and only expands the block following it if this produces a true value.
elifs. The block following
elseis expanded only if none of the previous conditions fired.
<?for x [expr]?>loops over the array created by the given expression.
<?for key, value in [expr]?>loops over an object. The
valuevariable in the second form can be omitted when not needed. The template fragment in the loop will be repeated once for every element in the collection, with the named variables bound to the relevant values (bound by function call, not reassigned, so they can be closed over). The variable
$i, inside the loop body, refers to the current index, starting at 0.
<' and '
>' of an HTML tag. The tag it applies to is determined as follows (the same applies for the instructions after this): When it sits before all non-text nodes in the enclosing node, it applies to the enclosing node. Otherwise, it applies to the first non-text node before it. Directly after the word
event, an event type should be given (without '
on', so something like '
click' or '
submit'). After that the handler body follows, which may refer to the
$eventvariable to get the event object. Mold supports one non-standard event,
enter, which will fire for
keypressevents with a key-code of 13.
do, except that the
$nodevariable refers to the nearest HTML node. Having access to this node means that it has to be run 'out of line', after the template has been expanded, so variables defined in this instruction are not visible to the rest of the template code. Variables defined during template expansion, on the other hand, are visible in this block.
event) HTML node. It takes a name as argument, which will become a property in the object that
Mold.cast(see below) returns, pointing to the node. When a label occurs inside a loop, the property will refer to an array of nodes. (Note that nested loops will still produce a single, flat array.)
It should be noted that, while
Mold.bake does some error checking,
it is still rather easy to pass nonsense parameters to
instructions. This can result in rather hard to debug run-time
failures (see 'Implementation'), but
could, if you really want to, be used to make the library do
things it is not designed for ― you could create your own
PHP-style loops, for example, with two
instructions, one opening the loop and one closing it.
To build HTML from a compiled template, the
Mold.cast function is used. It takes three arguments
(node, mold, arg), and replaces the content of
node with the result of applying
arg. The last argument can be left off for molds that
do not require data. If there were any labels defined in the mold
used (or molds called from that mold), the value returned by
Mold.cast will be an object containing links to the
As an alternative, there is also
Mold.castAppend, which takes the same arguments as
cast, but appends the new nodes to
the target node, instead of replacing its content.
It is possible to define custom instructions with
Mold.define, which accepts a string (the instruction
name) and a mold-like function (takes one argument, returns a
string) and defines a new instruction that takes an (optional)
expression as its argument and expands to the result of calling
the given function with the value of this expression. This is
basically a way to define pleasant shortcuts for things like
There are a few more properties of the
that can be useful. The most important one is
Mold.attachEvent. By default, Mold uses a very
simplistic event handler framework, which leaves most of the
browser incompatibilities intact (it only chooses between
libraries provide a nicer wrapper, which can be wired into Mold by
Mold.attachEvent to a function of three
(node, eventName, func), where
eventName is the type of event (without
on' prefix), and
func is a function of
one argument (the event object).
When using Prototype, for example, you might do this:
Mold.attachEvent = Event.observe;
There is also
Mold.escapeHTML, which HTML-escapes
the characters '
<>"&'. This is not
directly needed for using Mold, but since it was defined
internally anyway, and might come in useful, it is exported.
Mold.bake does is
decompose the template into instructions and pieces of plain text,
eval to turn it into a real function. This
way, loops and conditionals are straightforwardly borrowed from
the underlying interpreter, and a lot of work must only be done
label instructions need information about the nodes
in the resulting DOM tree. Rather than implement some kind of HTML
parser, Mold delays their execution until after the text has been
parsed by the browser. At expansion time their code is stored in a
(numbered) function, which closes over the variables that are
active in the template. At the place where they occur, a dummy tag
(I used empty
var tags with a special class) in
inserted. Then, after using
innerHTML to transform
the text into a DOM tree,
Mold.cast searches for such tags,
removes them, and runs the code on the relevant nodes. (If you
directly call mold functions that use these instructions, you will
see the dummy tags.)
Whether a system like this ― intricately connected to
innerHTML property ― is the most
ideal is debatable. My initial intention was to use XHTML
templates with a bunch of special tags, a kind of XSLT for
transformations. But, while
innerHTML is implemented
pretty well in most browsers, stuff like
and transforming XML trees to HTML is slightly flaky in a lot of
them (and extremely flaky in one particular browser...
you guess which).