%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Copyright 2001 by Object Craft P/L, Melbourne, Australia.
% LICENCE - see LICENCE file distributed with this software for details.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\chapter{Developing Custom Tags\label{cust-ref}}

In most complex applications you are likely to encounter presentation
problems which the standard collection of tags cannot easily solve.
Albatross provides a set of classes in the \module{albatross.template}
module which are designed to allow the development of custom tags.

The \module{albatross} module performs \code{from~template~import~*}
so all contents of \module{albatross.template} are available in
\module{albatross}.

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

\begin{verbatim}
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')
\end{verbatim}

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
\method{register_tagclasses()} method of the application object.

\begin{verbatim}
from albatross import SimpleApp

app = SimpleApp('ext.py', '.', 'start')
app.register_tagclasses(Calendar)
\end{verbatim}

All Albatross application classes inherit from the
\class{ResourceMixin} in the \module{albatross.context} module.
Execution contexts which are used with application objects inherit
from the \class{AppContext} class from the \module{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 \method{register_tagclasses()}
method of the execution context immediately after construction.

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

\begin{verbatim}
<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>
\end{verbatim}

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

\begin{verbatim}
cd samples/extension
python install.py
\end{verbatim}

\section{\module{albatross.template} ---
	Base classes for implementing tags}
\declaremodule{}{albatross.template}

The module contains the following classes which are intended to be
used in implementing custom tags.

\begin{classdesc}{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.
\end{classdesc}

\begin{classdesc}{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 \texttt{<BR>} and
\texttt{<HR>}.
\end{classdesc}

\begin{classdesc}{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
\texttt{<BODY>} and \texttt{<TABLE>}.
\end{classdesc}

\begin{classdesc}{Text}{text}
A simple wrapper around the string passed in the \var{text}
constructor argument which passes that string to the
\method{to_html()} method when the object is converted to HTML.
\end{classdesc}

\begin{classdesc}{Content}{}
A simple wrapper around a list which calls the \method{to_html()}
method of all list elements when the object is converted to HTML.
\end{classdesc}

\subsection{Tag Objects\label{cust-tag}}

\begin{methoddesc}[Tag]{raise_error}{msg}
Raises a \exception{TemplateError} exception using the string in the
\var{msg} argument.
\end{methoddesc}

\begin{methoddesc}[Tag]{has_attrib}{name}
Returns \code{TRUE} if the attribute specified in the \var{name}
argument was defined for the tag.  All attribute names are converted
to lower case by the template parser.
\end{methoddesc}

\begin{methoddesc}[Tag]{assert_has_attrib}{name}
If the attribute specified in the \var{name} argument is not defined
for the tag a \exception{TemplateError} exception will be raised.
\end{methoddesc}

\begin{methoddesc}[Tag]{get_attrib}{name \optional{, default \code{= None}}}
Retrieves the value of the attribute specified in the \var{name}
argument.
\end{methoddesc}

\begin{methoddesc}[Tag]{set_attrib}{name, value}
Sets the value of the attribute named in the \var{name} argument to
the value in the \var{value} argument.
\end{methoddesc}

\begin{methoddesc}[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.
\end{methoddesc}

\begin{methoddesc}[Tag]{attrib_items}{}
Returns a list of attribute name, value tuples which are defined for
the tag.
\end{methoddesc}

\begin{methoddesc}[Tag]{write_attribs_except}{ctx \optional{, \ldots}}
Sends all tag attributes to the \method{write_content()} method of the
execution context in the \var{ctx} argument.  Any attributes named in
additional arguments will not be written.
\end{methoddesc}

\subsection{EmptyTag Objects\label{cust-emptytag}}

\begin{methoddesc}[EmptyTag]{has_content}{}
Returns \code{0} to inform the template parser that the tag does
not enclose content.
\end{methoddesc}

\begin{methoddesc}[EmptyTag]{to_html}{ctx}
The template interpreter calls this method to convert the tag to HTML
for the execution context in the \var{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.
\end{methoddesc}

\subsection{EnclosingTag Objects\label{cust-enclosingtag}}

\begin{memberdesc}[EnclosingTag]{content}
An instance of the \class{Content} class which is created during the
constructor.
\end{memberdesc}

\begin{methoddesc}[EnclosingTag]{has_content}{}
Returns \code{1} to inform the template parser that the tag
encloses content.
\end{methoddesc}

\begin{methoddesc}[EnclosingTag]{append}{item}
Called by the template parser to append the content in the \var{item}
argument to the tag.  The method implementation simply passes
\var{item} to the \method{append()} method of the \member{content}
member.

You should override this method if you need to maintain multiple
content lists within your tag.
\end{methoddesc}

\begin{methoddesc}[EnclosingTag]{to_html}{ctx}
The template interpreter calls this method to convert the tag to HTML
for the execution context in the \var{ctx} argument.  The default
implementation passes \var{ctx} to the the \method{to_html()} method
of the \member{content} member.

You must override this method in your tag class to perform all actions
which are necessary to ``execute'' the tag.
\end{methoddesc}

\subsection{Text Objects\label{cust-text}}

\begin{methoddesc}[Text]{to_html}{ctx}
Sends the wrapped text to the \method{write_content()} method of the
execution context in the \var{ctx} argument.  You should not ever need
to subclass these objects.
\end{methoddesc}

\subsection{Content Objects\label{cust-content}}

\begin{methoddesc}[Content]{append}{item}
Appends the value in the \var{item} argument to the internal Python
list.
\end{methoddesc}

\begin{methoddesc}[Content]{to_html}{ctx}
Sequentially invokes the \method{to_html()} method of every item in
the internal Python list passing the \var{ctx} argument.
\end{methoddesc}
