.. % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% .. % 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('\n' \ % (calendar.month_name[month], year)) ctx.write_content('') for i in range(7): ctx.write_content('' \ % 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('' % r[i]) else: ctx.write_content('') ctx.write_content('\n') ctx.write_content('
%s %s
%s
%s
\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 <al-value expr="year">

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.