Posts tagged with “template”

Introducing the Proton Template Engine (part 3)

Thursday, 29 January, 2009

Templates are usually made up of other templates, especially if you want to re-use page/document components. Proton supports an include function to embed one template inside another.

For example, a fragment of a template (include2.xhtml) containing 2 paragraphs of text…

<div>
    <p eid="para1">PARA 1 TEXT</p>
    <p eid="para2">PARA 2 TEXT</p>
</div>

…can be embedded in another template (include1.xhtml)…

<body>
    <h1 eid="title">PAGE TITLE GOES HERE</h1>

    <div eid="includedcontent">
    INCLUDED CONTENT GOES HERE
    </div>
</body>

…and then populated with data, using the following snippet of code:


tmp = self.templates['include1.xhtml']
tmp.setelement('title', 'Page Title')
tmp.include('includedcontent', 'include2.xhtml')
tmp.setelement('para1', 'First paragraph of text')
tmp.setelement('para2', 'Second paragraph of text')

 

On the ‘syntactic sugar front’, as an alternative to the more explicit repeat function (for repeating elements in the output), Proton supports setting lists of values rather than single-values. Consider the template:

<ul>
    <li rid="list-item" eid="list-item">LIST ITEMS</li>
</ul>

The list can be populated without having to explicitly call repeat, using the following code snippet:


lst = [ 'a', 'b', 'c', 'd', 'e', 'f', 'g' ]
tmp.setelement('list-item', lst)

If your objects are decorated with properties (@property), then Proton also supports automatically setting the values in the page, using the convention of id followed by colon followed by property. For example, using the following template:

<dl>
    <dt>X Value</dt>
    <dd eid="prop:x">prop x here</dd>
    <dt>Y Value</dt>
    <dd eid="prop:y">prop y here</dd>
</dl>

A class Temp, with properties x and y can be set in the template, with the name prop and the values will be automatically populated.


class Temp(object):
    def __init__(self, x, y):
        self._x = x
        self._y = y

    @property
    def x(self):
        return self._x

    @property
    def y(self):
        return self._y

t = Temp('100', '500')
tmp.setelement('prop', t)

Introducing the Proton Template Engine (part 2)

Tuesday, 27 January, 2009

In a typical template engine, there will be some form of conditional logic, for changing the display of a section of a document. This will generally be an if-statement wrapping one or more elements, perhaps enabling or disabling sections based on access rights, showing more detail based on data, and so on.

Proton supports this logic with the facility to hide an element (marked with the eid attribute). For example, in this excerpt of a navigation menu:

<ul class="menu">
    <li eid="accounts"><a href="/accounts">Account Summary</a></li>
    <li eid="transactions"><a href="/transactions">View / Download Transactions</a></li>
    <li eid="transfer"><a href="/transfer">Transfer Funds</a></li>
    <li eid="bills"><a href="/bills">Bill Payments</a></li>
    <li eid="autopayments"><a href="/autopayments">Automatic Payments</a></li>
    <li eid="exchange"><a href="/exchange">Foreign Exchange</a></li>
</ul>

The following code will switch off the “transactions”, “autopayments” and “exchange” elements:


tmp.hide('autopayments')
tmp.hide('exchange')
tmp.hide('transactions')

Resulting in output of:

<ul class="menu">
    <li><a href="/accounts">Account Summary</a></li>
    <li><a href="/transfer">Transfer Funds</a></li>
    <li><a href="/bills">Bill Payments</a></li>
</ul>

You can see this example in action in the test hiding.py.

Another, less common but equally useful, feature of template engines is the facility to translate text (in other words, i18n or the internationalisation of output). Proton supports translation by setting a translation function on a template. For example, consider the following template:

<html>
<head>
<title>Page Title</title>
</head>
<body>
    <h1>Page Title</h1>

    <p id="para1">Some translated text</p>
    <p id="para2">Not translated text</p>
</body>
</html>

In this case, translation doesn’t rely on the 3 attributes (eid, aid, rid) — rather a default set of named (xhtml) elements are translated (the set can, of course, be overridden). The following code demonstrates translation in action:


fr = {
    'Page Title' : 'Titre de la page',
    'Some translated text' : 'Certains textes traduits'
}

def translate(text):
    if text in fr:
        return fr[text]
    else:
        return text

tmp = self.templates['tests/i18n.xhtml']
tmp.translate = translate

And the resulting output:

<html>
<head>
<title>Titre de la page</title>
</head>
<body>
    <h1>Titre de la page</h1>

    <p id="para1">Certains textes traduits</p>
    <p id="para2">Not translated text</p>
</body>
</html>

Introducing the Proton Template Engine

Tuesday, 20 January, 2009

I haven’t come across many (any?) templating engines for Python 3, so it seemed like a good idea to update my own attempt, and then release as an open source (LGPL) project.

Proton is a simple, “code-less” engine for xml/xhtml templates. Code-less, because it uses 3 types of ID (attribute) in a template file, rather than snippets of code — this moves the complexity out of the template and into the application (where I think it belongs).

The following template demonstrates basic use of the 3 IDs:

<html>
<head>
<title eid="title">PAGE TITLE</title>
</head>
<body>
    <h1 eid="title">PAGE TITLE</h1>

    <p><a eid="link" aid="link" href="">LINK ITEM</a></p>

    <ul>
        <li rid="list-item" eid="list-item">LIST ITEMS</li>
    </ul>
</body>
</html>

The attribute “eid” is used to change the value of an element, or hide the element. “aid” is used to change the value of an attribute, and “rid” is used for repeating elements. This might seem a bit simplistic, but it covers the fundamentals of most templating tasks.

The following code demonstrates the use of the template:


tmp = Templates()['test.xhtml']

tmp.setelement('title', 'An Xhtml Page', '*')
tmp.setelement('link', 'This is a link to Google')
tmp.setattribute('link', 'href', 'http://www.google.com')

tmp.repeat('list-item', 5)
for x in range(0, 5):
    tmp.setelement('list-item', 'test%s' % x, x)

print(str(tmp))

I used an earlier version of Proton for my own (rather ill-fated) project; a web-based system for timesheet and invoice management, so it has been tested in some relatively complicated scenarios — however, I am keen to hear where it falls down. i.e. complex pages where using 3 attributes just doesn’t cut it.