.. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
.. % Copyright 2001 by Object Craft P/L, Melbourne, Australia.
.. % LICENCE - see LICENCE file distributed with this software for details.
.. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


.. _tag-ref:

*******************
Templates Reference
*******************

Albatross provides a templating system that applications use to generate HTML.
Albatross templates are loosely based on XML, but are a little more forgiving.
The primary features are:

* All standard Albatross tags use an ``al-`` prefix, with the ``alx-`` prefix
  available applications and extensions to implement their own tags.  
* For Albatross tags that enclose content you can use the XML empty tag syntax
  to indicate that there is no content.  
* All Albatross tag and attribute names are transformed to lowercase.
* Attributes may appear over multiple lines, and attribute values can be broken
  over multiple lines.  
* Attribute values can be enclosed with either single or double quotes.  
* The enclosing quote character can be used within the attribute string if it
  is escaped by a backslash (``\``). 
* The template parser uses regular expressions to locate all of the template
  tags.  All text that is not recognised as an Albatross tag or associated
  trailing whitespace is passed unchanged through the parser.  In practice this
  means that you can use the templating system for non-HTML files.

For example the following two constructs are identical. :

 .. code-block:: albatross

   <al-for iter="i" expr="seq" pagesize="10" prepare>
   </al-for>

 .. code-block:: albatross

   <AL-FOR iter="i"
           expr="seq"
           pagesize="10"
           prepare/>

The Albatross templating system includes enhanced versions of many HTML tags,
as well as tags that control the flow of execution of the template. These are
described in detail in subsequent sections. The templating system also allows
any other HTML tag to be prefixed with ``al-`` to gain access to the attribute
evaluation system.

Attributes of Albatross tags can be processed in a number of ways:

* Some attributes control the behaviour of the enhanced and flow control tags.

* Appending ``expr`` to any attribute name causes the value of the attribute
  to be evaluated and the results of the evaluation substituted for the
  attribute value.  For example:

  .. code-block:: albatross

    <al-td colspanexpr="i.span()"> 

  would produce

  .. code-block:: html

    <td colspan="3">

* Appending ``bool`` to any attribute name causes the attribute to be being
  evaluated in a boolean context. If the result is ``True``, a boolean
  HTML attribute is emitted, and if the result is ``False``, no attribute
  is emitted. For example:

  .. code-block:: albatross

    <al-input name="abc.value" disabledbool="abc.isdisabled()">

  If ``abc.isdisabled()`` evaluates as ``True``, then the ``disabled`` attribute
  is emitted:

  .. code-block:: html

    <input name="abc.value" disabled>

  But if ``abc.isdisabled()`` evaluates as ``False``, then the ``disabled``
  attribute is suppressed entirely:

  .. code-block:: html

    <input name="abc.value">

* Any other attributes are passed through unchanged.

The following example demonstrates all of these to change the styling
of alternate rows in a table:

   .. literalinclude:: doctest/tags-anytag-tr
      :language: pycon

.. _tag-escaping:

Escaping generated content
==========================

Whenever template execution results in evaluated data being written, any
characters that have special meaning in HTML are escaped to protect against
cross-site scripting attacks [#]_:

    ====  ======
    From  To
    ====  ======
    &     &amp;
    <     &lt;
    >     &gt;
    "     &quot;
    '     &#39;
    ====  ======

For example:

   .. literalinclude:: doctest/tags-escape
      :language: pycon

You may occasionally have valid reasons to want to write content without
escaping. In these cases you can use ``htmlsafe()`` to signal that the content
has already been rendered safe for HTML use:

   .. literalinclude:: doctest/tags-escape-safe
      :language: pycon

``htmlsafe()`` is a simple sub-class of the `str()` type, used to signal that
escaping is not necessary; it has no methods of it's own, and performing
operations such as string concatenation on it will result in a regular `str()`.

An alternative mechanism is to use the ``noescape`` attribute:

   .. literalinclude:: doctest/tags-escape-noescape
      :language: pycon

One potential pitfall to ``noescape`` is that the flag is separated from the
code that generated the data and the security implications are not immediately
apparent to anyone editing the code. 

.. [#] `XSS or Cross-site scripting on Wikipedia <http://en.wikipedia.org/wiki/Cross-site_scripting>`_

.. _tag-fakeapp:

Fake Application Harness
========================

Some of the explanatory examples in this chapter require application
functionality.  The following fake application is used as an execution harness
to drive the interactive examples.

   .. literalinclude:: fakeapp.py
      :language: python


.. _tag-enhhtml:

Enhanced HTML Tags
==================

Tags in this section are used in place of standard HTML tags to access values
from the execution context.

All attributes that are not recognised by Albatross are passed without
modification to the generated HTML.

.. % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
.. % <al-form>


.. _tag-form:

``<al-form>``
-------------

Albatross browser request merging depends upon the functionality provided by the
``<al-form>`` tag.  If you do no use this tag in applications then the standard
request merging will not work.

The tag will automatically generate the HTML ``<form>`` ``action``
(:ref:`tag-form-action`) and ``enctype`` (:ref:`tag-form-enctype`) attributes
if they are not supplied in the template.

If you are using an execution context that inherits from the
:class:`NameRecorderMixin` (nearly all do --- see chapter :ref:`pack-overview`)
then the execution context will raise a :exc:`ApplicationError` exception if
multiple instances of some types of input tag with the same name are added to a
form.  The ``list`` attribute of the ``<al-input>`` tag is used indicate that
multiple instances are intentional.


.. _tag-form-action:

``action="..."`` attribute
^^^^^^^^^^^^^^^^^^^^^^^^^^

If you do not supply an ``action`` attribute the tag will generate one with
based on the value returned by the :meth:`current_url` method of the execution
context.

   .. literalinclude:: doctest/tags-form-action
      :language: pycon

Note that the generated ``action`` attribute is relative to the document root.


.. _tag-form-enctype:

``enctype="..."`` attribute
^^^^^^^^^^^^^^^^^^^^^^^^^^^

If you include any file input fields then the open tag will automatically supply
an ``enctype="multipart/form-data"`` attribute.

   .. literalinclude:: doctest/tags-form-file
      :language: pycon

.. % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
.. % <al-input>


.. _tag-input:

``<al-input>``
--------------

Albatross browser request merging depends upon the functionality provided by the
``<al-input>`` tag.  If you do no use this tag in applications then the standard
request merging will not work.

In the most common usage a ``value`` (:ref:`tag-input-value`) attribute
is generated by evaluating the ``name`` (:ref:`tag-input-name`) attribute
in the execution context.  This can be overridden by supplying a ``value``
(:ref:`tag-input-value`) or ``expr`` (:ref:`tag-input-expr`) attribute.

There are a number of attributes that automatically generate the ``name``
attribute.

When merging browser requests the application object places the browser supplied
value back into the execution context value referenced by the ``name``
attribute.  The application request merging will not merge variable names
prefixed by underscore.  Use this to protect application values from browser
modification.


.. _tag-input-alias:

``alias="..."`` attribute
^^^^^^^^^^^^^^^^^^^^^^^^^

This attribute is ignored is any of the following attributes are present;
``prevpage``, ``nextpage`` (:ref:`tag-input-page`), ``treefold``,
``treeselect``, or ``treeellipsis`` (:ref:`tag-input-tree`).

The value of the ``alias`` attribute is passed to the :meth:`make_alias` method
of the execution context.  The return value is then used as the generated
``name`` (:ref:`tag-input-name`) attribute.

The execution context :meth:`make_alias` method splits the ``alias`` attribute
at the last '.' and resolves the left hand side to an object reference.  The
:meth:`albatross_alias` method is then called on that object and the result is
combined with the '.' and the right hand side of the of the ``alias`` attribute
to produce the generated ``name`` attribute.  The resolved object is entered in
the the local namespace and the session using the name returned by the
:meth:`albatross_alias` method.

The template ``samples/tree/tree1.html`` contains an example of this method for
generating a ``name`` attribute.

.. code-block:: albatross

   <al-tree iter="n" expr="tree">
    <al-for iter="c" expr="range(n.depth())">
     <al-value expr="n.line(c.value())" lookup="indent">
    </al-for>
    -<al-input type="checkbox" alias="n.value().selected">
     <al-value expr="n.value().name" whitespace="newline">
   </al-tree>

Note that each node in the tree has a checkbox that controls whether or not the
node is selected.  When processing the ``alias`` attribute the toolkit isolates
the left hand side (``n.value()``) which happens to be the current tree node of
:class:`TreeIterator` ``n``.  To generate the alias the :meth:`albatross_alias`
method of the current node is called.  In ``samples/tree/tree1.py`` the
implementation of that method looks like:

.. code-block:: python

   class Node:
       def albatross_alias(self):
           return 'node%d' % self.node_num

When the template is executed a unique name is generated for each checkbox.  The
exact HTML produced by the above fragment from the sample looks like this:

.. code-block:: html

   -<input type="checkbox" name="node12.selected" value="on">a
    |-<input type="checkbox" name="node2.selected" value="on">a
    | |-<input type="checkbox" name="node0.selected" value="on">a
    | \-<input type="checkbox" name="node1.selected" value="on">b
    \-<input type="checkbox" name="node11.selected" value="on">b
      |-<input type="checkbox" name="node6.selected" value="on">a
      | \-<input type="checkbox" name="node5.selected" value="on">a
      |   |-<input type="checkbox" name="node3.selected" value="on">a
      |   \-<input type="checkbox" name="node4.selected" value="on">b
      |-<input type="checkbox" name="node7.selected" value="on">b
      \-<input type="checkbox" name="node10.selected" value="on">c
        |-<input type="checkbox" name="node8.selected" value="on">a
        \-<input type="checkbox" name="node9.selected" value="on">b

The ``alias`` handling uses the fact that all Python objects are stored by
reference.  It obtains a reference to an existing object by resolving an
expression and stores that reference under a new name. Since both the original
expression and the new name are the same reference, the toolkit can modify the
object referenced by the original expression by using the new name.

Looking further into the ``samples/tree/tree1.py`` code you will note that the
tree being iterated is generated once and placed into the session.  This ensures
that the alias names generated always contain references to the nodes in the
tree.  If the tree was not entered into the session but was generated from
scratch every request, the nodes referenced in the alias names would not be the
same nodes as those in the tree so all input would be lost.


.. _tag-input-checked:

``checked`` attribute
^^^^^^^^^^^^^^^^^^^^^

This attribute is generated in ``radio`` and ``checkbox`` input field types if
the generated ``value`` (:ref:`tag-input-value`) attribute matches the
comparison value from ``valueexpr`` (:ref:`tag-input-valueexpr`) (or the literal
``'on'`` for the ``checkbox`` input field type).

Refer to the documentation for individual input types for more details.


.. _tag-input-expr:

``expr="..."`` attribute
^^^^^^^^^^^^^^^^^^^^^^^^

For ``text``, ``password``, ``submit``, ``reset``, ``hidden``, and ``button``
input field types the expression in the ``expr`` attribute is evaluated and the
result is used to generate the ``value`` (:ref:`tag-input-value`) attribute.  If
the result is ``None`` then no ``value`` attribute will be written.

For ``radio`` and ``checkbox`` input field types the expression in the ``expr``
attribute is evaluated and the result is compared with the generated ``value``
attribute to determine whether or not the ``checked`` (:ref:`tag-input-checked`)
attribute should be written.

Refer to the documentation for individual input types for more details.


.. _tag-input-list:

``list`` attribute
^^^^^^^^^^^^^^^^^^

If you are using an execution context that inherits from the
:class:`NameRecorderMixin` (nearly all do --- see chapter :ref:`pack-overview`)
then the execution context will raise a :exc:`ApplicationError` exception if
multiple instances of some types of input tag with the same name are added to a
form.  The ``list`` attribute of the ``<al-input>`` tag is used indicate that
multiple instances are intentional.

The presence of the ``list`` attribute on an ``<al-input>`` tag makes the
request merging in the :class:`NameRecorderMixin` class place any browser
request values for the field into a list (field not present is represented by
the empty list).

The attribute must not be used for input field types ``radio``, ``submit``, and
``image``.  The attribute is ignored for the ``file`` input field type.


.. _tag-input-name:

``name="..."`` attribute
^^^^^^^^^^^^^^^^^^^^^^^^

When determining the generated ``name`` attribute the tag looks for a
number of attributes.  Any supplied ``name`` attribute will be ignored if
any of the following attributes are present; ``prevpage``, ``nextpage``
(:ref:`tag-input-page`), ``treefold``, ``treeselect``, ``treeellipsis``
(:ref:`tag-input-tree`), ``alias`` (:ref:`tag-input-alias`), or ``nameexpr``
(:ref:`tag-input-nameexpr`).

All of the attributes that automatically generate names and are looked up in the
above sequence.  The first of those attributes found will be used to determine
the name used in the tag.


.. _tag-input-nameexpr:

``nameexpr="..."`` attribute
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

This attribute is ignored if any of the following attributes are present;
``prevpage``, ``nextpage`` (:ref:`tag-input-page`), ``treefold``,
``treeselect``, ``treeellipsis`` (:ref:`tag-input-tree`), or ``alias`` (:ref
:`tag-input-alias`).

The expression in the value of the ``nameexpr`` attribute is evaluated to
determine the generated ``name`` (:ref:`tag-input-name`) attribute.

One shortcoming of the ``alias`` attribute is that you can only perform input on
object attributes.  The ``nameexpr`` enables you to perform input on list
elements.

   .. literalinclude:: doctest/tags-input-nameexpr
      :language: pycon

When the browser request is merged into the execution context the names elements
of the ``names`` list will be replaced.


.. _tag-input-node:

``node="..."`` attribute
^^^^^^^^^^^^^^^^^^^^^^^^

The ``node`` attribute is used in conjunction with the ``treeselect``,
``treefold`` and ``treeellipsis`` (:ref:`tag-input-tree`) attributes.  It is
ignored otherwise.

When this attribute is present the node identified by evaluating the expression
in the attribute value will be used when generating the ``name`` attribute.

The ``name`` (:ref:`tag-input-name`) attribute is generated as follows:

   .. literalinclude:: doctest/tags-input-treeselect-node
      :language: pycon

Refer to the documentation for ``treeselect``, ``treefold`` and ``treeellipsis``
(:ref:`tag-input-tree`) attributes for more information.


.. _tag-input-page:

``prevpage="..."`` and ``nextpage="..."`` attributes
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The ``prevpage`` and ``nextpage`` attributes respectively select the previous
and next pages of an ``<al-for>`` :class:`ListIterator`
(:ref:`tag-for-listiter`).

An attribute value must be supplied that specifies the name of the iterator.

The ``name`` (:ref:`tag-input-name`) attribute is generated as follows:

   .. literalinclude:: doctest/tags-input-nextpage
      :language: pycon

When merging the browser request the :meth:`NamespaceMixin.set_value` (:ref
:`mixin-namespace`) method looks for field names that contain commas.  These
names are split into *operation*, *iterator*, and optional *value* then the
:meth:`set_backdoor` method of the identified iterator is invoked.

During request merging the above example will execute code equivalent to the
following. ::

   ctx.locals.i.set_backdoor('nextpage', 'nextpage,i')


.. _tag-input-tree:

``treeselect="..."``, ``treefold="..."`` and ``treeellipsis="..."`` attributes
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The ``treeselect``, ``treefold``, and ``treeellipsis`` attributes respectively
select, open/close, or expand the ellipsis of an ``<al-tree>`` node via a
:class:`LazyTreeIterator` (:ref:`tag-tree-lazytreeiter`) or
:class:`EllipsisTreeIterator` (:ref:`tag-tree-ellipsistreeiter`) iterator.

These attributes are ignored if any of the following attributes are present;
``prevpage``, or ``nextpage`` (:ref:`tag-input-page`).

An attribute value must be supplied that specifies the name of the
:class:`LazyTreeIterator` iterator.

The ``name`` (:ref:`tag-input-name`) attribute is generated as follows:

   .. literalinclude:: doctest/tags-input-treeselect
      :language: pycon

When merging the browser request the :meth:`NamespaceMixin.set_value` (:ref
:`mixin-namespace`) method looks for field names that contain commas.  These
names are split into *operation*, *iterator*, and optional *value* then the
:meth:`set_backdoor` method of the identified iterator is invoked.

During request merging the above example will execute code equivalent to the
following. ::

   ctx.locals.n.set_backdoor('treeselect', 'ino81489', 'treeselect,n,ino81489')

The "ino81489" string is generated by calling the :meth:`albatross_alias` method
for the tree node.

If the ``node``\ (:ref:`tag-input-node`) attribute is not specified, the node
referenced by the current value of the iterator will be used to determine the
alias.


.. _tag-input-value:

``value="..."`` attribute
^^^^^^^^^^^^^^^^^^^^^^^^^

When determining the generated ``value`` attribute the tag looks for a number of
attributes.  Any supplied ``value`` attribute will be ignored if either ``expr``
(:ref:`tag-input-expr`) or ``valueexpr`` (:ref:`tag-input-valueexpr`) attributes
(depending upon input type) present.

If no ``expr``, ``valueexpr``, or ``value`` attribute is present then the value
identified by the generated ``name`` (:ref:`tag-input-name`) attribute will be
taken from the local namespace.  If this value is ``None`` then no ``value``
attribute will be written.  The name used to look into the local namespace is
the result of evaluating all ``name`` related attributes.

For input field types ``radio`` and ``checkbox`` the ``valueexpr`` attribute if
present takes priority over and specified ``value`` attribute.

Refer to the documentation for individual input types for more details.


.. _tag-input-valueexpr:

``valueexpr="..."`` attribute
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

This attribute is used to generate a ``value`` (:ref:`tag-input-value`)
attribute for ``radio`` and ``checkbox`` input field types.  It is ignored for
in all other cases.

Refer to the documentation for individual input types for more details.


.. _tag-input-generic:

``type="..."`` attribute (text, password, submit, reset, hidden, button)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The tag determines the generated ``name`` (:ref:`tag-input-name`) from the
``name`` related attributes.

To determine the generated ``value`` (:ref:`tag-input-value`) attribute the tag
first looks for an ``expr`` (:ref:`tag-input-expr`) attribute, then a ``value``
attribute, and then if that fails it looks up the generated ``name`` in the
execution context.

If the generated ``name`` contains a non-empty value it will be written as the
``name`` attribute.  If the generated ``value`` is not ``None`` it will be
escaped and written as the ``value`` attribute.  Escaping values makes all
``&``, ``<``, ``>``, and ``"`` characters safe.

For example:

   .. literalinclude:: doctest/tags-input-generic
      :language: pycon

After writing all tag attributes the execution context :meth:`input_add` method
is called with the following arguments; input field type (``'text'``,
``'password``, ``'submit``, ``'reset``, ``'hidden``, or ``'button'``), the
generated ``name``, the generated ``value``, and a flag indicating whether or
not the ``list`` (:ref:`tag-input-list`) attribute was present.

Application code handling browser requests typically determines the ``submit``
input pressed by the user via the execution context :meth:`req_equals` method.
The :meth:`req_equals` method simply tests that the named input is present in
the browser request and contains a non-empty value.

For example::

   def page_process(ctx):
       if ctx.req_equals('login'):
           user = process_login(ctx.locals.username, ctx.locals.passwd)
           if user:
               ctx.locals._user = user
               ctx.add_session_vars('_user')
               ctx.set_page('home')


.. _tag-input-radio:

``type="..."`` attribute (radio)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The tag determines the generated ``name`` (:ref:`tag-input-name`) from the
``name`` related attributes.  Then an internal comparison value is determined by
evaluating the ``expr`` (:ref:`tag-input-expr`) attribute if it is present, or
by looking up the generated ``name`` in the execution context.

If the comparison value equals the generated ``value`` (:ref:`tag-input-value`)
attribute then the ``checked`` (:ref:`tag-input-checked`) attribute is written.
Both values are converted to string before being compared.

To determine the generated ``value`` attribute the tag first looks for a
``valueexpr`` (:ref:`tag-input-valueexpr`) attribute, then a ``value``
attribute.

For example:

   .. literalinclude:: doctest/tags-input-radio1
      :language: pycon

The ``expr`` attribute can be used to generate the internal comparison value.
This is then compared with the ``value`` attribute to control the state of the
``checked`` attribute.

For example:

   .. literalinclude:: doctest/tags-input-radio2
      :language: pycon

The ``valueexpr`` attribute can be used to dynamically generate the ``value``
attribute.

For example:

   .. literalinclude:: doctest/tags-input-radio3
      :language: pycon

After writing all tag attributes the execution context :meth:`input_add` method
is called with the arguments; input field type (``'radio'``), the generated
``name``, the generated ``value``, and a flag indicating whether or not the
``list`` (:ref:`tag-input-list`) attribute was present.


.. _tag-input-checkbox:

``type="..."`` attribute (checkbox)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The tag determines the generated ``name`` (:ref:`tag-input-name`) from the
``name`` related attributes.  Then an internal comparison value is determined by
evaluating the ``expr`` (:ref:`tag-input-expr`) attribute if it is present, or
by looking up the generated ``name`` in the execution context.

If the comparison value equals the generated ``value`` (:ref:`tag-input-value`)
attribute then the ``checked`` (:ref:`tag-input-checked`) attribute is written.
Both values are converted to string before being compared.

If the internal comparison value is either a list or tuple the ``checked``
attribute is written if the generated ``value`` attribute is present in the
list/tuple.

To determine the generated ``value`` attribute the tag first looks for a
``valueexpr`` (:ref:`tag-input-valueexpr`) attribute, then a ``value``
attribute, and then if that fails it defaults to the value ``'on'``.

For example:

   .. literalinclude:: doctest/tags-input-checkbox
      :language: pycon

After writing all tag attributes the execution context :meth:`input_add` method
is called with the arguments; input field type (``'checkbox'``), the generated
``name``, the generated ``value``, and a flag indicating whether or not the
``list`` (:ref:`tag-input-list`) attribute was present.


.. _tag-input-image:

``type="..."`` attribute (image)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The tag determines the generated ``name`` (:ref:`tag-input-name`) from the
``name`` related attributes.

For example:

   .. literalinclude:: doctest/tags-input-image
      :language: pycon

After writing all tag attributes the execution context :meth:`input_add` method
is called with the arguments; input field type (``'image'``), the generated
``name``, ``None``, and a flag indicating whether or not the ``list`` (:ref
:`tag-input-list`) attribute was present.

When a browser submits input to an ``image`` input it sends an ``x`` and ``y``
value for the field.  These are saved as attributes of the field.

For example, if an image input named ``map`` was clicked by the user, then the
code to detect and process the input would look something like this::

   def page_process(ctx):
       if ctx.req_equals('map'):
           map_clicked_at(ctx.locals.map.x, ctx.locals.map.y)


.. _tag-input-file:

``type="..."`` attribute (file)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The tag determines the generated ``name`` (:ref:`tag-input-name`) from the
``name`` related attributes.

If you are using an execution context that inherits from the
:class:`NameRecorderMixin` (:ref:`mixin-recorder`) then using this input field
type will automatically cause the enclosing ``<al-form>`` (:ref:`tag-form`) tag
to include an ``enctype="multipart/form-data"`` (:ref:`tag-form-enctype`)
attribute.

For example:

   .. literalinclude:: doctest/tags-input-file
      :language: pycon

After writing all tag attributes the execution context :meth:`input_add` method
is called with the arguments; input field type (``'file'``), the generated
``name``, ``None``, and a flag indicating whether or not the ``list`` (:ref
:`tag-input-list`) attribute was present.

The request merging allows the user to submit more than one file in a ``file``
input field.  To simplify application code the :class:`Request` always returns a
list of :class:`FileField` objects for ``file`` inputs.

Application code to process ``file`` inputs typically looks like the following::

   def page_process(ctx):
       if ctx.req_equals('resume'):
           for r in ctx.locals.resume:
               if r.filename:
                   save_uploaded_resume(r.filename, r.file.read())

.. % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
.. % <al-select>


.. _tag-select:

``<al-select>``
---------------

Albatross browser request merging depends upon the functionality provided by the
``<al-select>`` tag.  If you do no use this tag in applications then the
standard request merging will not work.

To determine the ``name`` (:ref:`tag-select-name`) attribute in the generated
tag a number of attributes are used.  The generated name is evaluated in the
execution context to determine an internal compare value.

The compare value is used to control which option tags are generated with the
``selected`` (:ref:`tag-option-selected`) attribute. ``<select>`` tags in multi-
select mode are supported by list or tuple compare values.

The ``<al-select>`` tag can automatically generate the list of enclosed
``<option>`` tags using the ``optionexpr`` (:ref:`tag-select-optionexpr`)
attribute, or can work with enclosed ``<al-option>`` (:ref:`tag-option`) tags.


.. _tag-select-alias:

``alias="..."`` attribute
^^^^^^^^^^^^^^^^^^^^^^^^^

The value of the ``alias`` attribute is passed to the :meth:`make_alias` method
of the execution context.  The return value is then used as the generated
``name`` (:ref:`tag-select-name`) attribute.

The execution context :meth:`make_alias` method splits the ``alias`` attribute
at the last '.' and resolves the left hand side to an object reference.  The
:meth:`albatross_alias` method is then called on that object and the result is
combined with the '.' and the right hand side of the of the ``alias`` attribute
to produce the generated ``name`` attribute.  The resolved object is entered in
the the local namespace and the session using the name returned by the
:meth:`albatross_alias` method.

Refer to the documentation of the ``alias`` attribute of the ``<al-input>`` tag
(:ref:`tag-input-alias`) for an example of the mechanism described above.


.. _tag-select-list:

``list`` attribute
^^^^^^^^^^^^^^^^^^

If you are using an execution context that inherits from the
:class:`NameRecorderMixin` (nearly all do --- see chapter :ref:`pack-overview`)
then the execution context will raise a :exc:`ApplicationError` exception if
multiple instances of a non-multi-select ``<al-select>`` tag with the same name
are added to a form.  The ``list`` attribute is used indicate that multiple
instances are intentional.

The presence of the ``list`` attribute on an ``<al-select>`` tag makes the
request merging in the :class:`NameRecorderMixin` class place any browser
request values for the field into a list (field not present is represented by
the empty list).


.. _tag-select-multiple:

``multiple`` attribute
^^^^^^^^^^^^^^^^^^^^^^

For the purposes of the :class:`NameRecorderMixin` class, this attribute
performs the same role as the ``list`` (:ref:`tag-select-list`) attribute.  It
tells the browser request merging to place all input values into a list (field
not present is represented by the empty list).


.. _tag-select-name:

``name="..."`` attribute
^^^^^^^^^^^^^^^^^^^^^^^^

When determining the generated ``name`` attribute the tag looks for a number of
attributes.  Any supplied ``name`` attribute will be ignored if either the
``alias`` (:ref:`tag-select-alias`) or ``nameexpr`` (:ref:`tag-select-nameexpr`)
attributes are present.


.. _tag-select-nameexpr:

``nameexpr="..."`` attribute
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

This attribute is ignored if the ``alias`` (:ref:`tag-select-alias`) attribute
is present.

The expression in the value of the ``nameexpr`` attribute is evaluated to
determine the generated ``name`` (:ref:`tag-select-name`) attribute.

One shortcoming of the ``alias`` attribute is that you can only perform input on
object attributes.  The ``nameexpr`` enables you to perform input on list
elements.

Refer to the documentation of the ``nameexpr`` attribute of the ``<al-input>``
tag (:ref:`tag-input-nameexpr`) for an example.


.. _tag-select-noescape:

``noescape`` attribute
^^^^^^^^^^^^^^^^^^^^^^

The ``noescape`` attribute is used with the ``optionexpr``
(:ref:`tag-select-optionexpr`) attribute to suppress escaping of each option
value returned by the expression. The `htmlsafe()` mechanism provides an
alternative way to achieve this (see :ref:`tag-escaping` for more details).


.. _tag-select-optionexpr:

``optionexpr="..."`` attribute
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

If this attribute is present the expression in the attribute value is evaluated
to determine a sequence of option values.  One ``<option>`` tag is generated for
each item in the sequence.

When this attribute is not present all of the directly enclosed ``<al-option>``
(:ref:`tag-option`) tags are processed to generate the enclosed ``<option>``
tags.

If an item in the ``optionexpr`` sequence is not a tuple, it is converted to
string and then compared with the comparison value derived from the ``name``
(:ref:`tag-select-name`) attribute.

To support multiple selected ``<option>`` tags the comparison value must be
either a list or tuple.

For example:

   .. literalinclude:: doctest/tags-input-select3
      :language: pycon

If an item in the ``optionexpr`` sequence is a tuple it must contain two values.
The first value is used to specify the ``value`` attribute of the generated
``<option>`` tag and the second value provides the ``<option>`` tag content.

For example:

   .. literalinclude:: doctest/tags-input-select4
      :language: pycon

All values generated by the ``optionexpr`` method are escaped to make all ``&``,
``<``, ``>``, and ``"`` characters safe.

.. % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
.. % <al-option>


.. _tag-option:

``<al-option>``
---------------

Unless explicitly overridden, the ``selected`` attribute is controlled by the
comparison of the value of the enclosing ``<al-select>`` (:ref:`tag-select`) tag
with the evaluated value of the ``<al-option>`` tag.

The value of the ``<al-option>`` tag is specified either by evaluating the
``valueexpr`` (:ref:`tag-option-valueexpr`) attribute, or the ``value`` (:ref
:`tag-option-value`) attribute, or if neither attribute is present, by the
content enclosed by the ``<al-option>`` tag.  The enclosed content of the tag is
evaluated before it is compared. This allows the content to be generated using
other Albatross tags.

Albatross browser request merging depends upon the functionality provided by the
``<al-option>`` tag.  If you do no use this tag in applications then the
standard request merging will not work.

For example --- this shows how the ``<al-option>`` content is evaluated before
it is compared with the ``<al-select>`` value:

   .. literalinclude:: doctest/tags-input-select1
      :language: pycon


.. _tag-option-selected:

``selected`` attribute
^^^^^^^^^^^^^^^^^^^^^^

The ``selected`` attribute overrides the value comparison logic. When the
``selectedbool`` form is used, this allows the ``selected`` flag to be
controlled via arbitrary logic.


.. _tag-option-value:

``value="..."`` attribute
^^^^^^^^^^^^^^^^^^^^^^^^^

Use the ``value`` attribute to specify a value to be compared with the
comparison value of the enclosing ``<al-select>`` (:ref:`tag-select`) tag.

   .. literalinclude:: doctest/tags-input-select2
      :language: pycon


.. _tag-option-valueexpr:

``valueexpr="..."`` attribute
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Use the ``valueexpr`` attribute to specify an expression to be evaluated to
derive the value to be compared with the comparison value of the enclosing
``<al-select>`` (:ref:`tag-select`) tag.

If the ``valueexpr`` attribute evaluates to a 2-tuple, the first item becomes
the value and the second becomes the label.

   .. literalinclude:: doctest/tags-input-select5
      :language: pycon


.. _tag-option-label:

``label="..."`` attribute
^^^^^^^^^^^^^^^^^^^^^^^^^

Use the ``label`` attribute to specify the control label. This overrides the
body of the ``<al-option>`` tag.


.. _tag-option-labelexpr:

``labelexpr="..."`` attribute
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Use the ``labelexpr`` attribute to specify an expression to be evaluated to
derive the control label. This overrides the body of the ``<al-option>`` tag.

   .. literalinclude:: doctest/tags-input-select6
      :language: pycon

.. % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
.. % <al-textarea>


.. _tag-textarea:

``<al-textarea>``
-----------------

Albatross browser request merging depends upon the functionality provided by the
``<al-textarea>`` tag.  If you do no use this tag in applications then the
standard request merging will not work.


.. _tag-textarea-alias:

``alias="..."`` attribute
^^^^^^^^^^^^^^^^^^^^^^^^^

The value of the ``alias`` attribute is passed to the :meth:`make_alias` method
of the execution context.  The return value is then used as the generated
``name`` (:ref:`tag-textarea-name`) attribute.

The execution context :meth:`make_alias` method splits the ``alias`` attribute
at the last '.' and resolves the left hand side to an object reference.  The
:meth:`albatross_alias` method is then called on that object and the result is
combined with the '.' and the right hand side of the of the ``alias`` attribute
to produce the generated ``name`` attribute.  The resolved object is entered in
the the local namespace and the session using the name returned by the
:meth:`albatross_alias` method.

Refer to the documentation of the ``alias`` attribute of the ``<al-input>`` tag
(:ref:`tag-input-alias`) for an example of the mechanism described above.


.. _tag-textarea-list:

``list`` attribute
^^^^^^^^^^^^^^^^^^

If you are using an execution context that inherits from the
:class:`NameRecorderMixin` (nearly all do --- see chapter :ref:`pack-overview`)
then the execution context will raise a :exc:`ApplicationError` exception if
multiple instances of an ``<al-textarea>`` tag with the same name are added to a
form. The ``list`` attribute is used indicate that multiple instances are
intentional.

The presence of the ``list`` attribute on an ``<al-textarea>`` tag makes the
request merging in the :class:`NameRecorderMixin` class place any browser
request values for the field into a list (field not present is represented by
the empty list).


.. _tag-textarea-name:

``name="..."`` attribute
^^^^^^^^^^^^^^^^^^^^^^^^

When determining the generated ``name`` attribute the tag looks for a
number of attributes.  Any supplied ``name`` attribute will be ignored
if either the ``alias`` (:ref:`tag-textarea-alias`) or ``nameexpr``
(:ref:`tag-textarea-nameexpr`) attributes are present.

If the value identified by the generated ``name`` attribute does not exist in
the execution context then the enclosed content will be supplied as the initial
tag value.

For example:

   .. literalinclude:: doctest/tags-textarea1
      :language: pycon

Before the tag value is written it is escaped to make all ``&``, ``<``, ``>``,
and ``"`` characters safe.


.. _tag-textarea-nameexpr:

``nameexpr="..."`` attribute
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

This attribute is ignored if the ``alias`` (:ref:`tag-textarea-alias`) attribute
is present.

The expression in the value of the ``nameexpr`` attribute is evaluated to
determine the generated ``name`` (:ref:`tag-textarea-name`) attribute.

One shortcoming of the ``alias`` attribute is that you can only perform input on
object attributes.  The ``nameexpr`` enables you to perform input on list
elements.

Refer to the documentation of the ``nameexpr`` attribute of the ``<al-input>``
tag (:ref:`tag-input-nameexpr`) for an example.


.. _tag-textarea-noescape:

``noescape`` attribute
^^^^^^^^^^^^^^^^^^^^^^

The ``noescape`` attribute is used to suppress escaping of the execution
context value associated with the ``name`` (:ref:`tag-textarea-name`)
attribute. The `htmlsafe()` mechanism provides an alternative way to achieve
this (see :ref:`tag-escaping` for more details).

   .. literalinclude:: doctest/tags-textarea2
      :language: pycon

.. % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
.. % <al-a>


.. _tag-a:

``<al-a>``
----------

This tag acts as an enhanced version of the standard HTML ``<a>`` tag.


.. _tag-a-expr:

``expr="..."`` attributes
^^^^^^^^^^^^^^^^^^^^^^^^^

This attribute is ignored is any of the following attributes are present;
``prevpage``, ``nextpage`` (:ref:`tag-a-page`), ``treefold``, ``treeselect``, or
``treeellipsis`` (:ref:`tag-a-tree`).

The specified expression is evaluated to generate an ``href``
(:ref:`tag-a-href`) attribute.  The generated attribute is then processed as per
the ``href`` attribute.


.. _tag-a-href:

``href="..."`` attributes
^^^^^^^^^^^^^^^^^^^^^^^^^

This attribute is ignored is any of the following attributes are present;
``prevpage``, ``nextpage`` (:ref:`tag-a-page`), ``treefold``, ``treeselect``,
``treeellipsis`` (:ref:`tag-a-tree`), or ``expr`` (:ref:`tag-a-expr`).

When the ``expr`` attribute is used, then generated value is processed in the
same as a value supplied in the ``href`` attribute.

If the ``href`` does not contain a '?' (separates the path from the query), but
does contain a '=' then the ``href`` is rewritten as *current_url*?*href*.

   .. literalinclude:: doctest/tags-a2
      :language: pycon

If the ``href`` does not contain either a '?' or a '=' then the ``href`` is
assumed to be a page identifier so it is transformed into a redirect url by the
:meth:`redirect_url` execution context method.

   .. literalinclude:: doctest/tags-a3
      :language: pycon


.. _tag-a-node:

``node="..."`` attribute
^^^^^^^^^^^^^^^^^^^^^^^^

The ``node`` attribute is used in conjunction with the ``treeselect``,
``treefold`` and ``treeellipsis`` (:ref:`tag-a-tree`) attributes.  It is ignored
otherwise.

When this attribute is present the node identified by evaluating the expression
in the attribute value will be used when generating the ``href``
(:ref:`tag-a-href`) attribute.


.. _tag-a-page:

``prevpage="..."`` and ``nextpage="..."`` attributes
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The ``prevpage`` and ``nextpage`` attributes generate an ``href``
(:ref:`tag-a-href`) attribute that respectively selects the previous and next
pages of an ``<al-for>`` :class:`ListIterator` (:ref:`tag-for-listiter`).

The attribute value specifies the name of the iterator.

The generated ``href`` attribute is of the form *current_url*?*name*,*iter*=1
where *current_url* is the path component returned from the Python
:func:`urlparse.urlparse` function (via the execution context
:meth:`current_url` method), *name* is either ``prevpage`` or ``nextpage``, and
*iter* is the specified iterator.

For example:

   .. literalinclude:: doctest/tags-a1
      :language: pycon


.. _tag-a-tree:

``treeselect="..."``, ``treefold="..."`` and ``treeellipsis="..."`` attributes
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

These attributes are ignored if any either the ``prevpage`` (:ref:`tag-a-page`),
or ``nextpage`` attributes are present.

The ``treeselect``, ``treefold``, and ``treeellipsis`` attributes generate an
``href`` (:ref:`tag-a-href`) attribute that respectively select, open/close, or
expand the ellipsis of an ``<al-tree>`` (:ref:`tag-tree`) node via a
:class:`LazyTreeIterator` (:ref:`tag-tree-lazytreeiter`) or
:class:`EllipsisTreeIterator` (:ref:`tag-tree-ellipsistreeiter`) iterator.

Refer to the ``<al-input>`` tag for more information on how to use these
attributes (:ref:`tag-input-tree`).

If the ``node`` (:ref:`tag-a-node`) attribute if it is present it defines the
node to operate upon.  Otherwise the node operated upon is the current value of
the :class:`LazyTreeIterator` iterator.

The attribute value specifies the name of the :class:`LazyTreeIterator`
iterator.

The generated ``href`` attribute is of the form
*current_url*?*name*,*iter*,*alias*=1 where *current_url* is the path component
returned from the Python :func:`urlparse.urlparse` function (via the execution
context :meth:`current_url` method), *name* is either ``treeselect``,
``treefold`` or ``treeellipsis``, *iter* is the specified iterator, and *alias*
is the values returned by the :meth:`albatross_alias` method of the specified
node.

.. % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
.. % <al-img>


.. _tag-img:

``<al-img>``
------------

Use this tag to dynamically generate the ``src`` (:ref:`tag-img-src`) attribute
of an ``<img>`` tag.


.. _tag-img-expr:

``expr="..."`` attribute
^^^^^^^^^^^^^^^^^^^^^^^^

You must supply an ``expr`` attribute containing an expression that is evaluated
to generate the output ``src`` (:ref:`tag-img-src`) attribute of the ``<img>``
tag.

For example:

   .. literalinclude:: doctest/tags-img
      :language: pycon


.. _tag-img-src:

``src="..."`` attribute
^^^^^^^^^^^^^^^^^^^^^^^

This attribute is ignored.  Use the ``expr`` (:ref:`tag-img-expr`) attribute to
generate the ``<src>`` attribute.

.. _tag-execflow:

Execution and Control Flow
==========================

Tags in this section provide just enough programming capability to allow
template files to react to and format values from the execution context.

.. % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
.. % <al-require>


.. _tag-require:

``<al-require>``
----------------

This tag is used to specify the minimum version of the Albatross templating
system that will correctly parse your template, or to specify templating
features (that may be implemented by extension modules) that are required to
parse your template.

If the templating system has a lower version number, or the extension feature is
not available, an :exc:`ApplicationError` Exception is raised when the template
is parsed.


.. _tag-include-version:

``version="..."`` attribute
^^^^^^^^^^^^^^^^^^^^^^^^^^^

This attribute specifies the minimum version of the Albatross templating system
required to correctly parse your template. Specify the lowest version that will
correctly parse your template.

+--------------------+-------------------+--------------------------------+
| Templating Version | Albatross Version | Template feature               |
+====================+===================+================================+
| 1                  | up to 1.20        |                                |
+--------------------+-------------------+--------------------------------+
| 2                  | 1.30 and up       | prefixing any tag with ``al-`` |
|                    |                   | now allows any attribute to be |
|                    |                   | evaluated                      |
+--------------------+-------------------+--------------------------------+
| 3                  | 1.42 and up       | push alternate expression      |
|                    |                   | evaluation namespaces          |
+--------------------+-------------------+--------------------------------+

.. _tag-include-feature:

``feature="..."`` attribute
^^^^^^^^^^^^^^^^^^^^^^^^^^^

If the ``feature`` attribute is present, it specifies a comma-separated list of
templating features that will be required to correctly parse your template.

+--------------------+----------------------------------------------------+
| Name               | Template feature                                   |
+====================+====================================================+
| namespace          | push alternate expression evaluation namespaces    |
+--------------------+----------------------------------------------------+

.. % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
.. % <al-include>


.. _tag-include:

``<al-include>``
----------------

Use this tag to load and execute another template file at the current location.
You can specify the name of the included template file by name using the
``name`` (:ref:`tag-include-name`) attribute or by expression using the ``expr``
(:ref:`tag-include-expr`) attribute.


.. _tag-include-expr:

``expr="..."`` attribute
^^^^^^^^^^^^^^^^^^^^^^^^

If the ``expr`` attribute is present it is evaluated when the template is
executed to generate the name of a template file.  The specified template file
is loaded and executed with the output replacing the ``<al-include>`` tag.

For example:

   .. literalinclude:: doctest/tags-include1
      :language: pycon


.. _tag-include-name:

``name="..."`` attribute
^^^^^^^^^^^^^^^^^^^^^^^^

This attribute is ignored if the ``expr`` attribute is present.

When the template is executed the specified template file is loaded and executed
with the output replacing the ``<al-include>`` tag.

For example:

   .. literalinclude:: doctest/tags-include2
      :language: pycon

.. % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
.. % <al-comment>


.. _tag-comment:

``<al-comment>``
----------------

This tag suppresses the execution and output of any contained content, although
the contained content must be syntactically correct.

For example:

   .. literalinclude:: doctest/tags-comment
      :language: pycon

.. % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
.. % <al-flush>


.. _tag-flush:

``<al-flush>``
--------------

When the template file interpreter encounters an ``<al-flush>`` during execution
it flushes all accumulated HTML to output.

Usually HTML is accumulated in the execution context and is not sent to the
output until the :meth:`flush_content` is called.  This gives programs the
opportunity to handle exceptions encountered during template execution without
partial output leaking to the browser.

When the program is performing an operation that runs for some time this
behaviour may give user the impression that the application has entered an
infinite loop.  In these cases it is usually a good idea to provide incremental
feedback to the user by placing ``<al-flush>`` tags in your template files.

   .. literalinclude:: doctest/tags-flush
      :language: pycon

.. % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
.. % <al-if>


.. _tag-if:

``<al-if>``/``<al-elif>``/``<al-else>``
---------------------------------------

Use of these tags parallels the `if`/`elif`/`else` keywords in Python.

The ``<al-if>`` tag is a content enclosing tag while ``<al-elif>`` and
``<al-else>`` are empty tags that partition the content of the enclosing
``<al-if>`` tag.


.. _tag-if-expr:

``expr="..."`` attribute
^^^^^^^^^^^^^^^^^^^^^^^^

The ``expr`` attribute is used in the ``<al-if>`` and ``<al-elif>`` tags to
specify a test expression.  The expression is evaluated when the template is
executed.

If the text expression in the ``expr`` attribute of the ``<al-if>`` tag
evaluates to a ``TRUE`` value then the enclosed content up to either the next
``<al-elif>`` or ``<al-else>`` tag will be executed.

For example:

   .. literalinclude:: doctest/tags-if1
      :language: pycon

If the expression in the ``expr`` attribute of the ``<al-if>`` tag evaluates
``FALSE`` then the enclosed content following the ``<al-else>`` tag is executed.

For example:

   .. literalinclude:: doctest/tags-if2
      :language: pycon

The ``<al-elif>`` tag is used to chain a number of expression that are tested in
sequence.  The first test that evaluates ``TRUE`` determines the content that is
executed.

For example:

   .. literalinclude:: doctest/tags-if3
      :language: pycon

.. % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
.. % <al-value>


.. _tag-value:

``<al-value>``
--------------

This tag allows you to evaluate simple expressions and write the result to
output.


.. _tag-value-date:

``date="..."`` attribute
^^^^^^^^^^^^^^^^^^^^^^^^

If a ``date`` attribute is specified then the enclosed format string is passed
to the Python :func:`time.strftime` function along with the result of the
expression in the ``expr`` (:ref:`tag-value-expr`) attribute.  The result of
:func:`time.strftime` is then written to the output.

For example:

   .. literalinclude:: doctest/tags-value3
      :language: pycon


.. _tag-value-expr:

``expr="..."`` attribute
^^^^^^^^^^^^^^^^^^^^^^^^

This attribute must the specified.  It contains an expression that is evaluated
when the template is executed and the result is written as a string to the
output.

For example:

   .. literalinclude:: doctest/tags-value1
      :language: pycon


.. _tag-value-lookup:

``lookup="..."`` attribute
^^^^^^^^^^^^^^^^^^^^^^^^^^

When the ``lookup`` attribute is specified the result of the expression in the
``expr`` (:ref:`tag-value-expr`) attribute is used to retrieve content from the
lookup table named in the ``lookup`` attribute.  This is a very useful way to
separate the internal representation of program value from the presentation of
that value.

For example:

   .. literalinclude:: doctest/tags-value4
      :language: pycon

Please refer to the ``<al-lookup>`` tag reference for an explanation of that tag
and more complex examples.


.. _tag-value-noescape:

``noescape`` attribute
^^^^^^^^^^^^^^^^^^^^^^

If the ``noescape`` attribute is present then the value is not escaped.  Only
use this attribute when you are sure that the result of the expression is safe.
Without this attribute all ``&``, ``<``, ``>``, and ``"`` are escaped.  The
`htmlsafe()` mechanism provides an alternative way to achieve this (see
:ref:`tag-escaping` for more details).

For example:

   .. literalinclude:: doctest/tags-value2
      :language: pycon

.. % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
.. % <al-exec>


.. _tag-exec:

``<al-exec>``
-------------

This tag allows you to place arbitrary Python code in a template file.


.. _tag-exec-expr:

``expr="..."`` attribute
^^^^^^^^^^^^^^^^^^^^^^^^

The expression is specified in the ``expr`` attribute.  It is compiled using
*kind* = ``'exec'`` and evaluated when the template is executed.

For example:

   .. literalinclude:: doctest/tags-exec1
      :language: pycon

If you need to include the same quote character used to enclose the attribute
value in your expression you can escape it using a backslash ("$\\").

For example:

   .. literalinclude:: doctest/tags-exec2
      :language: pycon

.. % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
.. % <al-for>


.. _tag-for:

``<al-for>``
------------

This tag implements a loop in almost the same way as the `for` keyword
in Python.

The tag uses an instance of the :class:`ListIterator` (:ref:`tag-for-listiter`)
identified in the local namespace by the ``iter`` (:ref:`tag-for-iter`)
attribute to iterate over the sequence defined by the expression in the ``expr``
(:ref:`tag-for-expr`) attribute.

   .. literalinclude:: doctest/tags-for1
      :language: pycon

Note that you must use the :meth:`value` method of the iterator to retrieve the
current sequence value, or set a template namespace name via the ``vars``
attribute into which it will be stored.

When using pagination mode via the ``pagesize`` (:ref:`tag-for-pagesize`)
attribute the ``prevpage`` and ``nextpage`` attributes of the ``<al-input>``
(:ref:`tag-input`) and ``<al-a>`` (:ref:`tag-a`) tags can be used to
automatically page forwards and backwards through a sequence.

The following simulates pagination via the :meth:`set_backdoor`
:class:`ListIterator` method and shows other data that is maintained by the
iterator.

   .. literalinclude:: doctest/tags-for7
      :language: pycon


.. _tag-for-cols:

``cols="..."`` attribute
^^^^^^^^^^^^^^^^^^^^^^^^

This attribute is used to format a sequence as multiple columns.  The attribute
value is an integer that specifies the number of columns.

Rather than evaluate the enclosed content once for each item in the sequence,
the tag evaluates the content for each *row of items* in the sequence.  The
items in each row can be formatted by using an inner ``<al-for>`` tag.

By default the items flow down columns.  To flow across columns you must
use the ``flow`` (:ref:`tag-for-flow`)

For example:

   .. literalinclude:: doctest/tags-for5
      :language: pycon

Multi-column formatting does not support ``pagesize="..."``,
``namespace="..."`` or ``vars="..."``` attributes.


.. _tag-for-continue:

``continue`` attribute
^^^^^^^^^^^^^^^^^^^^^^

When paginating items via the ``pagesize`` (:ref:`tag-for-pagesize`) attribute,
the iterator index will reset to the first index displayed on the page if you
use an iterator more than once on the page.  The ``continue`` attribute
suppresses the sequence index reset causing the elements to flow on from the
previous page.

For example:

   .. literalinclude:: doctest/tags-for3
      :language: pycon


.. _tag-for-expr:

``expr="..."`` attribute
^^^^^^^^^^^^^^^^^^^^^^^^

The ``expr`` attribute specifies an expression that yields a sequence that the
iterator specified in the ``iter`` (:ref:`tag-for-iter`) attribute will iterate
over.  All of the enclosed content is then evaluated for each element in the
sequence.

For example:

   .. literalinclude:: doctest/tags-for1
      :language: pycon


.. _tag-for-flow:

``flow="..."`` attribute
^^^^^^^^^^^^^^^^^^^^^^^^

This attribute is used with the ``cols`` (:ref:`tag-for-cols`) attribute to
control the flow of values across columns.  The default value is ``"down"``.
Use the value ``"across"`` to flow items across columns.

Rather than evaluate the enclosed content once for each item in the sequence,
the tag evaluates the content for each *row of items* in the sequence.  The
items in each row can be formatted by using an inner ``<al-for>`` tag.

For example:

   .. literalinclude:: doctest/tags-for6
      :language: pycon

Multi-column formatting does not support pagination.


.. _tag-for-iter:

``iter="..."`` attribute
^^^^^^^^^^^^^^^^^^^^^^^^

This attribute specifies the name of the :class:`ListIterator`
(:ref:`tag-for-listiter`) that will be used to iterate over the items in
the sequence defined by the expression in the ``expr`` (:ref:`tag-for-expr`)
attribute.


.. _tag-for-namespace:

``namespace="..."`` attribute
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The ``namespace`` attribute specifies an expression that yields a sequence
in the same manner as the ``expr`` attribute (:ref:`tag-for-expr`), however
it also pushes an evaluation namespace for each item in the sequence. See the
``<al-namespace>`` (:ref:`tag-namespace`) tag for more details on namespaces.

For example:

   .. literalinclude:: doctest/tags-for-namespace
      :language: pycon

``namespace="..."`` cannot be used with the ``cols="..."``
(:ref:`tag-for-cols`), ``vars="..."`` or ``expr="..."`` attributes.

.. _tag-for-pagesize:

``pagesize="..."`` attribute
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

This attribute is used to present a sequence of data one page at a time.  The
attribute value must be an integer that specifies the number of items to display
in each page.

Use of the ``pagesize`` attribute places the sequence iterator into page mode
and limits the number of elements that will be displayed.

For example:

   .. literalinclude:: doctest/tags-for2
      :language: pycon

Pagination support requires that session support be present in the execution
context.  All of the Albatross application objects provide session capable
execution contexts by default.  The :class:`SimpleContext` class does not
support sessions so it is necessary to augment the class for the above example.
Note also that when the ``<al-for>`` tag processes the ``pagesize`` attribute it
places the sequence iterator into the session.


.. _tag-for-prepare:

``prepare`` attribute
^^^^^^^^^^^^^^^^^^^^^

This attribute allows you to place pagination controls before the formatted
sequence content.

When the ``prepare`` attribute is present the ``<al-for>`` tag will perform all
processing but will not write any output.  This allows you to test pagination
results before presenting output.

For example:

   .. literalinclude:: doctest/tags-for4
      :language: pycon

Note the XML empty tag syntax on the ``<al-for prepare>`` tag.


.. _tag-for-vars:

``vars="..."`` attribute
^^^^^^^^^^^^^^^^^^^^^^^^

If this attribute is set, the current value of the iterator (as returned by
:meth:`value` will be saved to a variable of this name in the local namespace.

For example:

   .. literalinclude:: doctest/tags-for8
      :language: pycon

If the attribute is set to a comma separated list of variables, the iterator
value will be unpacked into these variables. The iterator values must iterable
in this case (typically a tuple or list). If there are more variables listed
than there are values to be unpacked, then the unused variables are left
unchanged. Conversely, if there are more values than variables, only the values
with corresponding names will be unpacked.

For example:

   .. literalinclude:: doctest/tags-for9
      :language: pycon


.. _tag-for-listiter:

ListIterator Objects
^^^^^^^^^^^^^^^^^^^^

The iterator named in the ``iter`` (:ref:`tag-for-iter`) attribute of the
``<al-for>`` tag is an instance of this class.  By using an object to iterate
over the sequence the toolkit is able to provide additional data that is useful
in formatting HTML.

The iterator will retrieve each value from the sequence exactly once. This
allows you to use objects that act as sequences by implementing the Python
sequence protocol.  Only :meth:`__getitem__` is required unless you use
pagination, then :meth:`__len__` is also required.


.. method:: ListIterator.pagesize()

   Returns the pagesize that was set in the ``pagesize`` attribute.


.. method:: ListIterator.has_prevpage()

   Returns ``TRUE`` if the page :attr:`start` index is greater than zero indicating
   that there is a previous page.


.. method:: ListIterator.has_nextpage()

   Returns ``TRUE`` if the sequence length is greater than the page :attr:`start`
   index plus the :attr:`_pagesize` member indicating that there is a next page.

   If the iterator has not been placed into "page mode" by the presence of a
   ``pagesize`` attribute a :class:`ListIteratorError` exception will be raised.


.. method:: ListIterator.index()

   Returns the index of the current sequence element.


.. method:: ListIterator.start()

   Returns the index of the first sequence element on the page.


.. method:: ListIterator.count()

   Returns the index of the current sequence element within the current page.  This
   is equivalent to ``index() - start()``.


.. method:: ListIterator.value()

   Returns the current sequence element.

Most of the methods and all of the members are not meant to be accessed from
your code but are documented below to help clarify how the iterator behaves.


.. attribute:: ListIterator._index
   :noindex:

   Current sequence index --- returned by :attr:`index()`.


.. attribute:: ListIterator._start
   :noindex:

   Sequence index of first element on page --- returned by :attr:`start()`.


.. attribute:: ListIterator._count
   :noindex:

   Sequence index of current element on page --- returned by :attr:`count()`.


.. attribute:: ListIterator._seq
   :noindex:

   Sequence being iterated over --- initialised to ``None`` and set by
   :meth:`set_sequence`.


.. attribute:: ListIterator._have_value
   :noindex:

   Indicates the state of the current element.  There are three possible values:
   ``None`` indicates that the state is unknown and will be established when the
   sequence is next accessed, zero indicates that the end of sequence has been
   reached and there is no valid element, and one indicates the current element is
   valid.


.. attribute:: ListIterator._pagesize
   :noindex:

   Current page size --- initialised to ``0`` and set by the presence of a
   ``pagesize`` attribute in the ``<al-for>`` tag.


.. method:: ListIterator.__getstate__()

   When "page mode" is enabled the iterator is saved into the session (via the
   execution context :meth:`add_session_vars` method).  This restricts the Python
   pickler to saving only the :attr:`_start` and :attr:`_pagesize` members.


.. method:: ListIterator.__setstate__(tup)

   Restores an iterator from the Python pickler.


.. method:: ListIterator.__len__()

   When in "page mode" it returns the :attr:`_pagesize` member else it returns the
   length of the sequence.


.. method:: ListIterator.set_backdoor(op, value)

   The ``<al-input>`` and ``<al-a>`` tags provide ``nextpage`` and ``prevpage``
   attributes that generate names using a special backdoor format.  When the
   browser request is merged the :meth:`set_value` method of the
   :class:`NamespaceMixin` directs list backdoor input fields to this method.
   Refer to the documentation in section :ref:`mixin-namespace`.

   The *value* argument is the browser submitted value for the backdoor field.  If
   a value was submitted for the backdoor field then the *op* argument is
   processed.  If *op* equals ``"prevpage"`` or ``"nextpage"`` then the iterator
   selects the previous or next page respectively.


.. method:: ListIterator.get_backdoor(op)

   When generating backdoor fields for the ``<al-input>`` and ``<al-a>`` tags the
   toolkit calls this method to determine the value that will assigned to that
   field.  The method returns ``1``.


.. method:: ListIterator.set_pagesize(size)

   Sets the :attr:`_pagesize` member to *size*.


.. method:: ListIterator.has_sequence()

   Returns whether or not a sequence has been placed into the iterator
   (:attr:`_seq` is not ``None``).


.. method:: ListIterator.set_sequence(seq)

   Sets the :attr:`_seq` to *seq*.


.. method:: ListIterator.reset_index()

   If the ``<al-for>`` tag does not contain a ``continue`` attribute then this is
   called just before executing the tag content for the first element in the
   sequence.  It sets the :attr:`_index` member to :attr:`_start`.


.. method:: ListIterator.reset_count()

   This is called just before executing the tag content for the first element in
   the sequence.  It sets the :attr:`_count` member to zero.


.. method:: ListIterator.clear_value()

   Sets the :attr:`_have_value` member to ``None`` which causes the next call of
   :attr:`has_value()` to retrieve the sequence element indexed by :attr:`_index`.


.. method:: ListIterator.has_value()

   When the :attr:`_have_value` member is ``None`` this method tries to retrieve
   the sequence element indexed by :attr:`_index`.  If an element is returned by
   the sequence it is saved in the :attr:`_value` member and :attr:`_have_value` is
   set to one.  If an :exc:`IndexError` exception is raised by the sequence then
   :attr:`_have_value` is set to zero.

   The method returns TRUE if a sequence member is contained in :attr:`_value`.

   By this mechanism the iterator retrieves each value from the sequence exactly
   once.


.. method:: ListIterator.next()

   Retrieves the next value (if available) from the sequence into the
   :attr:`_value` member.


.. method:: ListIterator.set_value(value)

   A back door hack for multi-column output that sets respective values of the
   iterator to sequences created by slicing the sequence in the ``expr`` attribute
   of the ``<al-for>`` tag.

.. % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
.. % <al-lookup>


.. _tag-lookup:

``<al-lookup>``
---------------

The ``<al-lookup>`` tag uses a dictionary-style lookup to choose one of the
contained ``<al-item>`` HTML fragments.  If no ``<al-item>`` tag matches, then
the tag returns any content that was not enclosed by an ``<al-item>`` tag.  The
``<al-item>`` key values are derived by evaluating their ``expr`` attribute.

The ``<al-lookup>`` element will either be expanded in place if an ``expr``
attribute is given or, if named with an ``name="..."`` attribute, expanded later
via an ``<al-value>`` ``lookup="..."`` tag.


.. _tag-lookup-expr:

``expr="..."`` attribute
^^^^^^^^^^^^^^^^^^^^^^^^

If the ``expr`` attribute is used, this is evaluated and the content of the
matching ``<al-item>`` element is returned. If no match occurs, the unenclosed
content is returned.

This form of the tag is akin to the switch or case statements that appear in
some languages.


.. _tag-lookup-name:

``name="..."`` attribute
^^^^^^^^^^^^^^^^^^^^^^^^

If the ``name="..."`` is used, the tag becomes a named lookup and expansion is
deferred until the lookup is referenced via the ``<al-value>`` element. In this
case, the lookup is performed on the evaluated value of the ``<al-value>``
``expr`` attribute.

For example:

   .. literalinclude:: doctest/tags-lookup
      :language: pycon

By placing lookup tables in separate template files you can eliminate redundant
processing via the :meth:`run_template_once` execution context method.  This
method is defined in the :class:`AppContext` class that is used as a base for
all application execution contexts.

As the above example demonstrates, you are able to place arbitrary template HTML
inside the lookup items.  As the content of the item is only executed when
referenced, all expressions are evaluated in the context of the template HTML
that references the item.

.. % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
.. % <al-item>


.. _tag-item:

``<al-item>``
-------------

The ``<al-item>`` tag must only be used as a child tag of an ``<al-lookup>``
(:ref:`tag-lookup`) tag.  to allow internal application values to be converted
to display form.


.. _tag-item-expr:

``expr="..."`` attribute
^^^^^^^^^^^^^^^^^^^^^^^^

The ``expr`` attribute defines an expression that is evaluated to generate a
lookup table key for the parent ``<al-lookup>`` (:ref:`tag-lookup`) tag.  When
the parent ``<al-lookup>`` is executed all of the ``expr`` expressions are
evaluated to build a dictionary of items.

For example:

   .. literalinclude:: doctest/tags-item
      :language: pycon

.. % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
.. % <al-tree>


.. _tag-tree:

``<al-tree>``
-------------

This tag is used to display tree structured data.  A pre-order traversal (node
visited before each child) of the tree is performed and the enclosed content is
evaluated for each node in the tree.

The ``treefold``, ``treeselect``, and ``treeellipsis`` attributes on the
``<al-input>`` (:ref:`tag-input`) tag allow the user to open, close, and select
lazy tree nodes.

Section :ref:`tug-tree` contains an example of a simple usage of the
``<al-tree>`` tag.

The ``samples/tree/tree1`` sample program takes the simple example further and
implements an application that places a checkbox next to the name of each node
name.  A unique input field name is generated for each checkbox by using the
``alias`` attribute described in section :ref:`tag-input`.

The ``samples/tree/tree2`` sample program demonstrates the use of the ``lazy``
``<al-tree>`` attribute that enables lazy child loading mode.

The ``samples/tree/tree3`` sample program demonstrates the use of the
``ellipsis`` ``<al-tree>`` attribute.


.. _tag-tree-ellipsis:

``ellipsis`` attribute
^^^^^^^^^^^^^^^^^^^^^^

The ``ellipsis`` attribute extends the ``lazy`` (:ref:`tag-tree-lazy`)
traversal.  It collapses nodes close to the root of tree as deeper nodes are
opened.


.. _tag-tree-expr:

``expr="..."`` attribute
^^^^^^^^^^^^^^^^^^^^^^^^

The ``expr`` attribute defines the root of the tree traversal.


.. _tag-tree-iter:

``iter="..."`` attribute
^^^^^^^^^^^^^^^^^^^^^^^^

This attribute specifies the name of the :class:`TreeIterator`
(:ref:`tag-tree-treeiter`) that will be used to iterate over the nodes in
the tree defined by the expression in the ``expr`` (:ref:`tag-tree-expr`)
attribute.


.. _tag-tree-lazy:

``lazy`` attribute
^^^^^^^^^^^^^^^^^^

The ``lazy`` attribute allows lazy traversal of the tree, with child nodes only
being loaded when their parent is open.


.. _tag-tree-single:

``single`` attribute
^^^^^^^^^^^^^^^^^^^^

The ``single`` attribute places the tree in single select mode. Whenever a new
node is selected by browser input the previous selected node(s) will be
deselected.


.. _tag-treenode:

TreeNode Objects
^^^^^^^^^^^^^^^^

There is no actual :class:`TreeNode` class.  Trees can be constructed from
objects of any class as long as they implement the interface described here.


.. attribute:: TreeNode.children

   This member must only be present in non leaf nodes.  It contains a list of
   immediate child nodes of this node.

   When using lazy loaded trees this member should be initialised to an empty list
   in the constructor.  The presence of the :attr:`children` member makes the
   toolkit treat the node as a non-leaf node.


.. attribute:: TreeNode.children_loaded

   This member needs only be present in non leaf nodes that are referenced by an
   ``<al-tree>`` tag in lazy mode.  It should be initialised to ``0`` in the node
   constructor.  The toolkit will set the member to ``1`` once it has called the
   :meth:`load_children` method of the node.


.. method:: TreeNode.load_children(ctx)

   This method must be defined for nodes that are referenced by an ``<al-tree>``
   tag in lazy mode.  It should must populate the :attr:`children` member with the
   immediate child nodes.

   The toolkit will call this method when it needs to display the child nodes of a
   node and they have not yet been loaded (:attr:`children_loaded`\ ``== 0``).

   The toolkit "knows" when it needs to see the child nodes of a particular node so
   it asks that node to load the children.  This allows potentially huge trees to
   be browsed by having the toolkit only load those nodes that are visible.


.. method:: TreeNode.albatross_alias()

   This method must be defined for nodes that are referenced by an ``<al-tree>``
   tag in lazy mode.  It must return a unique string identifier for this node that
   is suitable for use as part of an HTML input field name or URL component via the
   special ``treeselect``, ``treefold`` and ``treeellipsis`` attributes.  The
   identifier must be the same each time the program is run (so ``str(id(self))``
   will not work).

   The :class:`TreeIterator` uses the node identifier to record which nodes are
   open and which are selected.  The same identifier is also used when the node is
   referenced via an ``alias`` (:ref:`tag-input-alias`) attribute of an
   ``<al-input>`` tag.


.. _tag-tree-treeiter:

TreeIterator Objects
^^^^^^^^^^^^^^^^^^^^

An instance of :class:`TreeIterator` class (or the sub-classes
:class:`LazyTreeIterator` (:ref:`tag-tree-lazytreeiter`) or
:class:`EllipsisTreeIterator` (:ref:`tag-tree-ellipsistreeiter`)) will be
placed into the execution context using the name specified in the ``iter``
(:ref:`tag-tree-iter`) attribute.  This iterator will contain traversal
data for the current node each time the tag content is executed.

Note that it is also acceptable to create an instance of one of the TreeIterator
classes prior to rendering the template.  The :meth:`set_selected_aliases` or
:meth:`set_open_aliases` methods can then be used to render the tree with nodes
already selected or open.

By using an object to iterate over the tree the toolkit is able to provide
additional data that is useful in formatting HTML.  The toolkit also places the
iterator into the session (you must be using an application class that supports
sessions).


.. method:: TreeIterator.value()

   Returns the current node.


.. method:: TreeIterator.tree_depth()

   Returns the depth of the visible tree, from the root to deepest node. A single
   node tree has a depth of one.


.. method:: TreeIterator.depth()

   Returns the depth of the current node.


.. method:: TreeIterator.span()

   Is shorthand for ``n.tree_depth() - n.depth()``.  It is intended to be used for
   the ``colspan`` of the table cell containing the node name when laying the tree
   out in a table.  See the ``samples/tree/tree2.html`` template for just such an
   example.


.. method:: TreeIterator.line(depth)

   Only useful when displaying a tree in tabular form where the root is in the
   first column of the first row.  Returns the type of line that should be
   displayed in each column up to the depth of the current node.

   A return value of ``0`` indicates no line, ``1`` indicates a line that joins a
   node later than this node, and ``2`` indicates a line that terminates at this
   node.

   The example in section :ref:`tug-tree` uses this method.


.. method:: TreeIterator.is_open()

   Returns ``TRUE`` if the current node is open.  For non-lazy iterators,  this is
   always ``TRUE`` except on leaf nodes.


.. method:: TreeIterator.is_selected()

   For non-lazy iterators, this always returns ``FALSE``.


.. method:: TreeIterator.has_children()

   Returns ``TRUE`` if the current node has children (ie. it defines a
   :attr:`children` member).

Most of the methods and all of the members are not meant to be accessed from
your code but are documented below to help clarify how the iterator behaves.


.. attribute:: TreeIterator._value
   :noindex:

   Stores a reference to the current tree node --- returned by :meth:`value`.


.. attribute:: TreeIterator._stack
   :noindex:

   As the tree is being traversed this list attribute records all parent nodes
   between the current node and the root.  This is used to determine which branch
   lines should be drawn for the current node.


.. attribute:: TreeIterator._line
   :noindex:

   Stores the branch line drawing information for the current node. Elements of
   this list are returned by :meth:`line(depth)`.


.. attribute:: TreeIterator._tree_depth
   :noindex:

   Stores the depth of the tree from the root to the deepest visible node.  A
   single node tree has a depth of 1.  This is calculated immediately before the
   tree is displayed.  This is returned by :meth:`tree_depth`.


.. method:: TreeIterator.set_line(line)

   Saves the *line* argument in :attr:`_line`.


.. method:: TreeIterator.set_value(node)

   Sets the :attr:`_value` to the *node* argument.


.. method:: TreeIterator.node_is_open(ctx, node)

   Called internally whenever the toolkit needs to determine the open state of a
   tree node.  For non-lazy iterators, it returns whether or not the node in the
   *node* argument has children (because non-lazy iterators are always open).


.. _tag-tree-lazytreeiter:

LazyTreeIterator Objects
^^^^^^^^^^^^^^^^^^^^^^^^

``<al-tree>`` tags that include the ``lazy`` attribute use an instance of the
:class:`LazyTreeIterator` class. This class supports all the methods of the
:class:`TreeIterator` class, as well as the following:


.. method:: TreeIterator.is_open()

   Returns ``TRUE`` is the current node is open.  Calls the :meth:`albatross_alias`
   method of the current node and returns ``TRUE`` if the returned alias exists in
   the :attr:`_open_aliases` dictionary member.


.. method:: TreeIterator.is_selected()

   Returns ``TRUE`` if the current node is selected.  Calls the
   :meth:`albatross_alias` method of the current node and returns ``TRUE`` if the
   returned alias exists in the :attr:`_selected_aliases` dictionary member.

Some methods are designed to be called from application code, not from
templates.


.. method:: TreeIterator.close_all()

   Closes all tree nodes by reinitialising the :attr:`_open_aliases` to the empty
   dictionary.


.. method:: TreeIterator.deselect_all()

   Deselects all tree nodes by reinitialising the :attr:`_selected_aliases` to the
   empty dictionary.


.. method:: TreeIterator.get_selected_aliases()

   Returns a sorted list of aliases for all nodes that are selected (ie. in the
   :attr:`_selected_aliases` member).


.. method:: TreeIterator.set_selected_aliases(aliases)

   Builds a new :attr:`_selected_aliases` member from the sequence of aliases
   passed in the *aliases* argument.


.. method:: TreeIterator.get_open_aliases()

   Returns a sorted list of aliases for all nodes that are open (ie. in the
   :attr:`_open_aliases` member).


.. method:: TreeIterator.set_open_aliases(aliases)

   Builds a new :attr:`_open_aliases` member from the sequence of aliases passed in
   the *aliases* argument.

:class:`LazyTreeIterator` instances add the follow private methods and members:


.. attribute:: LazyTreeIterator._key
   :noindex:

   This member caches the value returned by the :meth:`albatross_alias` method for
   the current node.  This key is then used to look up the :attr:`_open_aliases`
   and :attr:`_selected_aliases` members.


.. attribute:: LazyTreeIterator._open_aliases
   :noindex:

   A dictionary that contains the aliases for all tree nodes that are currently
   open.  The contents of this dictionary is maintained via the
   :meth:`set_backdoor` method.


.. attribute:: LazyTreeIterator._selected_aliases
   :noindex:

   A dictionary that contains the aliases for all tree nodes that are currently
   selected.  The contents of this dictionary is maintained via the
   :meth:`set_backdoor` method.


.. method:: LazyTreeIterator.__getstate__()

   Used to save the iterator in the session.  This restricts the Python pickler to
   saving only the :attr:`_lazy`, :attr:`_open_aliases` and
   :attr:`_selected_aliases` members.


.. method:: LazyTreeIterator.__setstate__(tup)

   Restores an iterator from the Python pickler.


.. method:: LazyTreeIterator.set_value(node)

   Sets the :attr:`_value` to the *node* argument.  When operating in lazy mode the
   :meth:`albatross_alias` method is called for *node* and the result is cached in
   :attr:`_key`.


.. method:: LazyTreeIterator.node_is_open(ctx, node)

   Called internally whenever the toolkit needs to determine the open state of a
   tree node.  It returns whether or not the node in the *node* argument is open.
   This always returns ``0`` for leaf nodes as they do not have children.

   When in lazy mode the open state of *node* is retrieved from
   :attr:`_open_aliases`.  If the node state is open then the method checks the
   value of the node :attr:`children_loaded` member.  If :attr:`children_loaded` is
   ``FALSE`` then the node :meth:`load_children` is called to load the children of
   *node*.


.. method:: LazyTreeIterator.set_backdoor(op, key, value)

   The ``<al-input>`` and ``<al-a>`` tags provide ``treefold`` and ``treeselect``
   attributes that generate names using a special backdoor format.  When the
   browser request is processed, the :meth:`set_value` method of the
   :class:`NamespaceMixin` directs tree backdoor input fields to this method.
   Refer to the documentation in section :ref:`mixin-namespace`.

   When the *op* argument is ``"treeselect"`` the :attr:`_selected_aliases` is
   updated for the node identified by the *key* argument.  If *value* is ``FALSE``
   the key is removed else it is added.

   When the *op* argument is ``"treefold"`` and *value* argument is ``TRUE`` then
   the open state of the node identified by the *key* argument is toggled.


.. method:: LazyTreeIterator.get_backdoor(op, key)

   When generating backdoor fields for the ``<al-input>`` and ``<al-a>`` tags the
   toolkit calls this method to determine the value that will assigned to that
   field.

   When *op* is ``"treeselect"`` the method returns the current selected state of
   the node identified by *key*.

   When *op* is ``"treefold"`` the method returns ``1``.


.. _tag-tree-ellipsistreeiter:

EllipsisTreeIterator Objects
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

:class:`EllipsisTreeIterator` objects are created by using the ``ellipsis``
attribute on an ``<al-tree>`` tag. Ellipsis trees are a variant of lazy trees
where nodes at shallower levels are progressively collapsed into ellipses as the
user opens deeper nodes.   The user can reopen the collapsed nodes by selecting
an ellipsis.

They support all the methods of the :class:`LazyTreeIterator`
(:ref:`tag-tree-lazytreeiter`), as well as the following methods:


.. method:: EllipsisTreeIterator.node_type()

   Returns ``0`` for a regular node, or ``1`` for nodes that have been collapsed
   into an ellipsis. This is actually implemented on the :class:`LazyTreeIterator`,
   but will always return ``0`` there.

:class:`EllipsisTreeIterator` objects also have the following private methods
and members:


.. attribute:: EllipsisTreeIterator._noellipsis_alias
   :noindex:

   Records the last ellipsis to be selected by the user, and is used to suppress
   the generate of an ellipsis at that location next time the tree is rendered.


.. method:: EllipsisTreeIterator.node_use_ellipsis(ctx, node)

   Returns ``TRUE`` if it is acceptable to render the specified ``node`` as an
   ellipsis. If the node's alias matches :attr:`_noellipsis_alias`, ``FALSE`` is
   return, otherwise ``TRUE`` is returned if any of the node's children are open.

The behaviour of the :meth:`set_backdoor` and :meth:`get_backdoor` methods has
been extended to recognise a ``treeellipsis`` op. This is used to process
browser requests to open an ellipsis (it sets the :attr:`_noellipsis_alias`
member.

.. _tag-namespace:

``<al-namespace>``
------------------

The ``<al-namespace>`` tag allows you to specify an object
within ``ctx.locals`` to become the evaluation context for any
contained elements. Within the scope, ``name`` attributes on contained
``<al-input>``, ``<al-select>``, and ``<al-textarea>`` will automatically
be prefixed with the namespace name.

For example:

  .. literalinclude:: doctest/tags-namespace
     :language: pycon

.. _tag-macroproc:

Macro Processing
================

Tags in this section provide a simple macro processing environment for template
files.

The main purpose of Albatross macros is to provide a mechanism to divide your
HTML into presentation structure and presentation appearance.  By defining
appearance presentation tricks inside macros you can make global changes to your
web application appearance by changing one macro.

The ``<al-macro>`` (:ref:`tag-macro`) and ``<al-usearg>`` (:ref:`tag-usearg`)
tags are used to define macros, while ``<al-expand>`` (:ref:`tag-expand`) and
``<al-setarg>`` (:ref:`tag-setarg`) are used to invoke and expand previously
defined macros.

The :class:`ResourceMixin` (:ref:`mixin-resource`) and :class:`ExecuteMixin`
(:ref:`mixin-execute`) classes provide the Albatross macro definition and
execution facilities respectively.

.. % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
.. % <al-macro>


.. _tag-macro:

``<al-macro>``
--------------

The ``<al-macro>`` tag is used to define a macro.  All enclosed content becomes
part of the macro definition.

Executing the macro registers the macro with the execution context via the
:meth:`register_macro` method using the name in the ``name``
(:ref:`tag-macro-name`) attribute.

Note that the execution of the macro content is deferred until later when the
macro is expanded via the ``<al-expand>`` (:ref:`tag-expand`) tag.  This means
that executing a macro definition produces no output.  Output is produced only
when the macro is expanded.

   .. literalinclude:: doctest/tags-macro1
      :language: pycon

The deferred execution also means that you can include content that only works
within the context of the ``<al-expand>`` tag.

   .. literalinclude:: doctest/tags-macro2
      :language: pycon

In the above example the content of the macro makes reference to a *oops* that
is not defined in the execution context when the macro was defined.

Inside a macro definition you can use as yet undefined macros.

   .. literalinclude:: doctest/tags-macro4
      :language: pycon

Care must by taken to ensure that you do not make circular macro references else
you will cause a stack overflow.


.. _tag-macro-name:

``name="..."`` attribute
^^^^^^^^^^^^^^^^^^^^^^^^

The ``name`` attribute is used to uniquely identify the macro in the
application.

.. % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
.. % <al-usearg>


.. _tag-usearg:

``<al-usearg>``
---------------

The ``<al-usearg>`` tag is used inside a macro definition to define the location
where content enclosed by the ``<al-expand>`` (:ref:`tag-expand`) tag should be
placed when the macro is expanded.

All content enclosed by the ``<al-expand>`` tag is passed to the macro as the
unnamed argument.  The unnamed argument is retrieved in the macro definition by
using an ``<al-usearg>`` tag without specifying a ``name``
(:ref:`tag-usearg-name`) attribute.  When a macro expects only one argument it
is best to use this mechanism.

   .. literalinclude:: doctest/tags-macro3
      :language: pycon


.. _tag-usearg-name:

``name="..."`` attribute
^^^^^^^^^^^^^^^^^^^^^^^^

Macros can be defined to accept multiple arguments.  The ``name`` attribute is
used to retrieve named arguments.  When invoking a macro that accepts named
arguments the ``<al-setarg>`` (:ref:`tag-setarg`) tag and ``name`` attribute are
used to define the content for each named argument.

   .. literalinclude:: doctest/tags-macro7
      :language: pycon

.. % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
.. % <al-setdefault>


.. _tag-setdefault:

``<al-setdefault>``
-------------------

The ``<al-setdefault>`` tag is used inside a macro definition to specify default
content for a named macro argument. The content enclosed by this tag will be
used if the caller does not override it with a ``<al-setarg>`` tag.

Note that only named arguments can have a default as the unnamed argument is
always set, implicitly or explicitly, by the calling ``<al-expand>`` tag.

   .. literalinclude:: doctest/tags-macro11
      :language: pycon


.. _tag-setdefault-name:

``name="..."`` attribute
^^^^^^^^^^^^^^^^^^^^^^^^

The ``name`` attribute is used to identify the named macro argument that will
receive the enclosed content.

.. % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
.. % <al-expand>


.. _tag-expand:

``<al-expand>``
---------------

The ``<al-expand>`` tag is used to expand a previously defined macro.

You can pass macro expansions as arguments to other macros.

   .. literalinclude:: doctest/tags-macro5
      :language: pycon

All arguments to macros are executed each time they are used in the macro
definition.  This means that you need to be aware of side effects when using
arguments more than once inside a macro.

   .. literalinclude:: doctest/tags-macro6
      :language: pycon


.. _tag-expand-name:

``name="..."`` attribute
^^^^^^^^^^^^^^^^^^^^^^^^

The ``name`` attribute contains the name of the macro that will be expanded.
Macros are defined and names using the ``<al-macro>`` (:ref:`tag-macro`) tag.


.. _tag-expand-namespace:

``namespace="..."`` attribute
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

This runs the macro in the specified namespace. 

For example:

   .. literalinclude:: doctest/tags-macro-namespace
      :language: pycon

See the ``<al-namespace>`` (:ref:`tag-namespace`) tag for more information
on namespaces.

.. _tag-expand-arg:

``...arg="..."`` attributes
^^^^^^^^^^^^^^^^^^^^^^^^^^^

When macro arguments are simple strings, they can be specified as
``<al-expand>`` attributes by appending ``arg`` to the argument name. So, to set
an argument called ``title``, you could add an ``titlearg`` attribute to the
``<al-expand>`` tag.

   .. literalinclude:: doctest/tags-macro9
      :language: pycon

If the macro argument is longer or needs to contain markup, the ``<al-setarg>``
(:ref:`tag-setarg`) tag should be used instead.


.. _tag-expand-argexpr:

``...argexpr="..."`` attributes
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Macro arguments can also be derived by evaluating a python expression.
Attributes of the ``<al-expand>`` tag that end in ``argexpr`` are evaluated, and
the base name becomes the macro argument of that name.

For example:

.. code-block:: albatross

   <al-expand name="pagelayout" titleargexpr="foo" />

is functionally equivilent to:

.. code-block:: albatross

   <al-expand name="pagelayout">
       <al-setarg name="title"><al-value expr="foo"></al-setarg>
   </al-expand>

For a more complete example:

   .. literalinclude:: doctest/tags-macro10
      :language: pycon


.. % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
.. % <al-setarg>


.. _tag-setarg:

``<al-setarg>``
---------------

The ``<al-setarg>`` tag is used pass content to a macro.  All content enclosed
by the tag will be passed as an argument to the macro named by the parent
``<al-expand>`` (:ref:`tag-expand`) tag.

The ``<al-setarg>`` tag is normally used to pass content to macros that define
named arguments, but can also be used to enclose the unnamed argument.

   .. literalinclude:: doctest/tags-macro8
      :language: pycon


.. _tag-setarg-name:

``name="..."`` attribute
^^^^^^^^^^^^^^^^^^^^^^^^

The ``name`` attribute is used to identify the named macro argument that will
receive the enclosed content.

