.. % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
.. % Copyright 2001 by Object Craft P/L, Melbourne, Australia.
.. % LICENCE - see LICENCE file distributed with this software for details.
.. % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
.. _cust-ref:
**********************
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 :class:`EmptyTag` or :class:`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 :class:`NameRecorderMixin` via the :meth:`input_add` method. For more
information, see section :ref:`mixin-rec-name`, NameRecorderMixin in the Mixin
Class Reference.
The following is a simple calendar tag which formats a single month like the
unix :program:`cal(1)` program.
.. code-block:: python
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('
\n')
ctx.write_content('%s %s |
\n' \
% (calendar.month_name[month], year))
ctx.write_content('')
for i in range(7):
ctx.write_content('%s | ' \
% calendar.day_abbr[(i + 6) % 7][:2])
ctx.write_content('
\n')
calendar.setfirstweekday(6)
for r in calendar.monthcalendar(year, month):
ctx.write_content('')
for i in range(7):
if r[i]:
ctx.write_content('%s | ' % r[i])
else:
ctx.write_content(' | ')
ctx.write_content('
\n')
ctx.write_content('
\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 :meth:`register_tagclasses` method of the
application object.
.. code-block:: python
from albatross import SimpleApp
app = SimpleApp('ext.py', '.', 'start')
app.register_tagclasses(Calendar)
All Albatross application classes inherit from the :class:`ResourceMixin` in the
:mod:`albatross.context` module. Execution contexts which are used with
application objects inherit from the :class:`AppContext` class from the
:mod:`albatross.app` module which automatically retrieves all resources from the
parent application object.
If you are using the :class:`SimpleContext` class for your execution context
then you will need to call the :meth:`register_tagclasses` method of the
execution context immediately after construction.
The following is an example template file which uses the ````
tag.
.. code-block:: albatross
Calendar for
Calendar for
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.
.. code-block:: sh
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 :mod:`albatross.tags`.
:mod:`albatross.template` --- Base classes for implementing tags
================================================================
.. module:: albatross.template
The module contains the following classes which are intended to be used in
implementing custom tags.
.. class:: Tag(ctx, filename, line_num, attribs)
This is the base class upon which all tags are implemented. You are unlikely to
ever subclass this directly. The :class:`EmptyTag` and :class:`EnclosingTag`
classes inherit from this class.
.. class:: EmptyTag(ctx, filename, line_num, attribs)
Use this class as a subclass for all tags which do not require a closing tag and
therefore do not enclose content. Examples of standard HTML tags which do not
enclose content are ``
`` and ``
``.
.. class:: EnclosingTag(ctx, filename, line_num, attribs)
Use this class as a subclass for all tags which enclose content. Examples of
standard HTML tags which enclose content are ```` and ````.
.. class:: Text(text)
A simple wrapper around the string passed in the *text* constructor argument
which passes that string to the :meth:`to_html` method when the object is
converted to HTML.
.. class:: Content()
A simple wrapper around a list which calls the :meth:`to_html` method of all
list elements when the object is converted to HTML.
.. _cust-tag:
Tag Objects
-----------
.. method:: Tag.raise_error(msg)
Raises a :exc:`TemplateError` exception using the string in the *msg* argument.
.. method:: Tag.has_attrib(name)
Returns ``TRUE`` if the attribute specified in the *name* argument was defined
for the tag. All attribute names are converted to lower case by the template
parser.
.. method:: Tag.assert_has_attrib(name)
If the attribute specified in the *name* argument is not defined for the tag a
:exc:`TemplateError` exception will be raised.
.. method:: Tag.assert_any_attrib(*names)
If none of the attributes specified by the arguments are defined for the tag
a :exc:`TemplateError` exception will be raised.
.. method:: Tag.get_attrib(name [, default ``= None``])
Retrieves the value of the attribute specified in the *name* argument.
.. method:: Tag.set_attrib(name, value)
Sets the value of the attribute named in the *name* argument to the value in the
*value* argument.
.. method:: Tag.set_attrib_order(order)
Defines the order that the tag attributes will be written during conversion to
HTML. The template parser captures the attribute sequence from the template
file then calls this method.
.. method:: Tag.attrib_items()
Returns a list of attribute name, value tuples which are defined for the tag.
.. method:: Tag.write_attribs_except(ctx [, ...])
Sends all tag attributes to the :meth:`write_content` method of the execution
context in the *ctx* argument. Any attributes named in additional arguments
will not be written.
.. _cust-emptytag:
EmptyTag Objects
----------------
.. method:: EmptyTag.has_content()
Returns ``0`` to inform the template parser that the tag does not enclose
content.
.. method:: EmptyTag.to_html(ctx)
The template interpreter calls this method to convert the tag to HTML for the
execution context in the *ctx* argument. The default implementation does
nothing.
You must override this method in your tag class to perform all actions which are
necessary to "execute" the tag.
.. _cust-enclosingtag:
EnclosingTag Objects
--------------------
.. attribute:: EnclosingTag.content
An instance of the :class:`Content` class which is created during the
constructor.
.. method:: EnclosingTag.has_content()
Returns ``1`` to inform the template parser that the tag encloses content.
.. method:: EnclosingTag.append(item)
Called by the template parser to append the content in the *item* argument to
the tag. The method implementation simply passes *item* to the :meth:`append`
method of the :attr:`content` member.
You should override this method if you need to maintain multiple content lists
within your tag.
.. method:: EnclosingTag.to_html(ctx)
The template interpreter calls this method to convert the tag to HTML for the
execution context in the *ctx* argument. The default implementation passes
*ctx* to the the :meth:`to_html` method of the :attr:`content` member.
You must override this method in your tag class to perform all actions which are
necessary to "execute" the tag.
.. _cust-text:
Text Objects
------------
.. method:: Text.to_html(ctx)
Sends the wrapped text to the :meth:`write_content` method of the execution
context in the *ctx* argument. You should not ever need to subclass these
objects.
.. _cust-content:
Content Objects
---------------
.. method:: Content.append(item)
Appends the value in the *item* argument to the internal Python list.
.. method:: Content.to_html(ctx)
Sequentially invokes the :meth:`to_html` method of every item in the internal
Python list passing the *ctx* argument.