6. Developing Custom Tags

In complex applications you may encounter presentation problems which the standard collection of tags cannot easily solve. Albatross allows you to register additional tags, which are then available for use in your templates. Custom tags are named with an alx- prefix to distinguish them from standard al- tags.

Custom tags should subclass either EmptyTag or EnclosingTag, and have a name class attribute. The name should start with alx- and contain only letters, numbers and the underscore character.

Custom tags that produce form inputs need to register the names of those inputs with the NameRecorderMixin via the input_add method. For more information, see section 7.5.2, NameRecorderMixin in the Mixin Class Reference.

The following is a simple calendar tag which formats a single month like the unix cal(1) program.

import time
import calendar
import albatross


class Calendar(albatross.EmptyTag):

    name = 'alx-calendar'

    def to_html(self, ctx):
        year = self.get_attrib('year')
        if year is not None:
            year = ctx.eval_expr(year)
        month = self.get_attrib('month')
        if month is not None:
            month = ctx.eval_expr(month)
        if month is None or year is None:
            now = time.localtime(time.time())
            if year is None:
                year = now[0]
            if month is None:
                month = now[1]
        ctx.write_content('<table>\n')
        ctx.write_content('<tr align="center"><td colspan="7">%s %s</td></tr>\n' \
                          % (calendar.month_name[month], year))
        ctx.write_content('<tr>')
        for i in range(7):
            ctx.write_content('<td>%s</td>' \
                              % calendar.day_abbr[(i + 6) % 7][:2])
        ctx.write_content('</tr>\n')
        calendar.setfirstweekday(6)
        for r in calendar.monthcalendar(year, month):
            ctx.write_content('<tr align="right">')
            for i in range(7):
                if r[i]:
                    ctx.write_content('<td>%s</td>' % r[i])
                else:
                    ctx.write_content('<td></td>')
            ctx.write_content('</tr>\n')
        ctx.write_content('</table>\n')

To use the tag in your application you must make the class available to the execution context. If you are using an Albatross application object you can do this by passing the class to the register_tagclasses() method of the application object.

from albatross import SimpleApp

app = SimpleApp('ext.py', '.', 'start')
app.register_tagclasses(Calendar)

All Albatross application classes inherit from the ResourceMixin in the albatross.context module. Execution contexts which are used with application objects inherit from the AppContext class from the albatross.app module which automatically retrieves all resources from the parent application object.

If you are using the SimpleContext class for your execution context then you will need to call the register_tagclasses() method of the execution context immediately after construction.

The following is an example template file which uses the <alx-calendar> tag.

<html>
<head><title>Calendar for <al-value expr="year"></title></head>
<body>
<h1>Calendar for <al-value expr="year"></h1>
<table cellpadding="10">
<al-for iter="r" expr="range(1,13)" cols="3" flow="across">
 <tr valign="top">
 <al-for iter="m" expr="r.value()">
  <td><alx-calendar month="m.value()" year="year"></td>
 </al-for>
 </tr>
</al-for>
</table>
</body>
</html>

A complete program which uses this extension tag and template file can be found in the samples/extension directory. Use the install.py script to install the sample.

cd samples/extension
python install.py

The implementation of the standard tags also makes a good reference when writing custom tags. All standard tags are defined in albatross.tags.



Subsections