Presentation tier
=================

This document describes how to generate HTML and XML dialects with the service
offered by the framework.

:doc:`components` explains how to associate HTML or XML views to the components.

Principles
----------

With Nagare, to generate a HTML text, you always build a tree of objects in
memory, a Document Objects Model (not the DOM version of the W3C), that you
can serialize in a (X)HTML text.

One benefic effect of this serialization is that the generated HTML or XHTML
is always valid.

The framework offers to you three ways to generate the DOM:

1. functional
2. imperative
3. templating

It's important to note that these three methods all generate a DOM and so can
be freely mixed to build an aggregating DOM.

DOM element creation
--------------------

A ``Renderer`` is a DOM element factory. For example, the XHTML renderer
:class:`nagare.namespaces.xhtml.Renderer` has an attribute, for
each XHTML tag, that create a DOM element:

.. code-block:: pycon

    >>> from nagare.namespaces import xhtml
    >>> h = xhtml.Renderer()
    >>> h.div
    <Element div at 8410b6c>

DOM elements API
----------------

ElementTree API
~~~~~~~~~~~~~~~

A DOM element is an instance of the class :class:`nagare.namespaces.xml._Tag`.
As this class inherits from ``lxml.etree.Element``, the DOM element offers an
`ElementTree API. <https://docs.python.org/2.7/library/xml.etree.elementtree.html#xml.etree.ElementTree.Element>`_:

.. code-block:: pycon

    >>> from nagare.namespaces import xhtml
    >>> h = xhtml.Renderer()

    >>> root = h.div
    >>> root.set('id', 'content')

    >>> title = h.h1
    >>> title.text = 'Hello world'

    >>> root.append(title)
    >>> root.write_htmlstring()
    '<div id="content"><h1>Hello world</h1></div>'

Lxml API
~~~~~~~~

You can also `validate <http://lxml.de/validation.html>`_ a DOM tree
against a DTD, XML Schema, RelaxNG or Schematron document.

And you can use `XPath and Xsl transformations <http://lxml.de/xpathxslt.html>`_.

Functional DOM building API
~~~~~~~~~~~~~~~~~~~~~~~~~~~

The ``_Tag`` class implements a ``__call__``  method to add children, text or
attributes to a DOM element:

.. code-block:: python

     def __call__(self, *children, **attributes)

Each element in ``children`` can be a:

- DOM element that is added as a child of the DOM element
- string, unicode string, integer or float that is converted to unicode
  string and added as data to the DOM element
- list, tuple or generator which each elements are added to the DOM element
- dictionary which each items are added as attributes of the DOM element
- :doc:`component <components>` ``comp`` wich will be rendered with its
  default view (i.e ``comp.render(h)``) and the resulting DOM tree added
  to the DOM element

Each items in ``attributes`` are added as attributes of the DOM element.

.. note::

   As a keyword parameter cannot have the name of a Python reserved keyword,
   add a ``_`` character to the name (i.e: ``h.div(class_='content')``)

Using the DOM element creation API of the renderers, with the nesting of
calls to the created DOM element, a DOM tree can be built in a functional way:

.. code-block:: python

     >>> from nagare.namespaces import xhtml
     >>> h = xhtml.Renderer()

     >>> root = h.div(h.h1('Hello world'), id='content')
     >>> root.write_htmlstring()
     <div id="content"><h1>Hello world</h1></div>'

Imperative DOM building API
~~~~~~~~~~~~~~~~~~~~~~~~~~~

A DOM element is also a `context manager <https://docs.python.org/2/library/stdtypes.html#context-manager-types>`_

Once a context is opened using the ``with`` statement, children can be added
to the context manager using the ``<<`` operator on the renderer.

So a DOM tree can also be imperatively built from the nesting of contexts. With its root
finally retrieved from the attribute ``root`` of the renderer:

.. code-block:: python

   >>> from nagare.namespaces import xhtml
   >>> h = xhtml.Renderer()

   >>> with h.div:
   ...     h << { 'id' : 'content' }
   ...     with h.h1:
   ...         h << 'Hello world'

   >>> root = h.root
   >>> root.write_htmlstring()
   '<div id="content"><h1>Hello world</h1></div>'

.. note::

  In a component view, don't forget to return the tree with ``h.root``

Remember that the different ways to build a DOM tree can be freely mixed,
so the example above can be rewrote as:

.. code-block:: python

   >>> from nagare.namespaces import xhtml
   >>> h = xhtml.Renderer()

   >>> with h.div(id='content'):
   ...     h << h.h1('Hello world')

   >>> root = h.root
   >>> root.write_htmlstring()
   '<div id="content"><h1>Hello world</h1></div>'


Or, to create a HTML list from the Python list ``l``:

.. code-block:: python

   # Functional
   >>> root = h.ul([u.li(element) for element in l])

   # Imperative
   >>> with h.ul:
   ...     for element in l:
   ...         h << h.ul(element)
   >>> root = h.root

Template
~~~~~~~~

The templating system in Nagare follows the idea of the
*meld family*: the designer who creates the XHTML template only gives identifiers to nodes.
Then the developer can parse the template into a DOM tree, search for the DOM
elements given their identifiers and manipulates them in Python.

1. Creating the template
++++++++++++++++++++++++

The template must be a valid XML document, for example a XHTML template and
the namespace ``http://www.plope.com/software/meld3`` must be declared.

To mark the nodes, use the attribute ``id`` of this namespace:

.. code-block:: html

   <?xml version="1.0" encoding="UTF-8"?>
   <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
   <html xmlns="http://www.w3.org/1999/xhtml"
         xmlns:meld="http://www.plope.com/software/meld3">
       <body>
           <h1 meld:id="title">Hello</h1>
       </body>
   </html>

The Python helper method ``meld_id()`` is available to add a ``meld:id``
attribute to a DOM element:

.. code-block:: pycon

   >>> from nagare.namespaces import xhtml
   >>> h = xhtml.Renderer()

   >>> tree = h.html(
   ...            h.body(
   ...                h.h1('Hello').meld_id('title')
   ...            )
   ...        )
   >>> print tree.write_xmlstring(pretty_print=True)
   <html>
     <body>
       <h1 xmlns:ns0="http://www.plope.com/software/meld3" ns0:id="title">Hello</h1>
     </body>
   </html>

2. Parsing the template
+++++++++++++++++++++++

You can use the ``parse_htmlstring()`` method of a xhtml renderer to parse a
template:

.. code-block:: pycon

   >>> from nagare.namespaces import xhtml
   >>> h = xhtml.Renderer()

   >>> root = h.parse_html('/tmp/template.xml', xhtml=True)

   >>> print root.write_xmlstring()
   <html xmlns="http://www.w3.org/1999/xhtml" xmlns:meld="http://www.plope.com/software/meld3">
       <body>
           <h1 meld:id="title">Hello</h1>
       </body>
   </html>

3. Finding the DOM elements
+++++++++++++++++++++++++++

Use the ``findmeld()`` method of the DOM elements to retreive the marked nodes:

.. code-block:: pycon

   >>> from nagare.namespaces import xhtml
   >>> h = xhtml.Renderer()

   >>> root = h.parse_html('/tmp/template.xml', xhtml=True)

   >>> root.findmeld('title')
   <Element {http://www.w3.org/1999/xhtml}h1 at 8410c5c>

4. Manipulating the DOM elements
++++++++++++++++++++++++++++++++

Once a DOM element is found, you can manipulate it with the normal ElementTree,
Lxml, functional or imperative API:

.. code-block:: pycon

   >>> from nagare.namespaces import xhtml
   >>> h = xhtml.Renderer()

   >>> root = h.parse_html('/tmp/template.xml', xhtml=True)

   >>> t = root.findmeld('title')
   >>> t.text = 'World'

   >>> print root.write_xmlstring()
   <html xmlns="http://www.w3.org/1999/xhtml" xmlns:meld="http://www.plope.com/software/meld3">
       <body>
           <h1 meld:id="title">World</h1>
       </body>
   </html>


These three methods of the DOM elements are helpers to work with templates:

- ``fill(self, *children, **attributes)`` -- replaces the children of the
  DOM element by the given children and appends the ``attributes`` to the DOM
  element current attributes.

  .. code-block:: python

       >>> from nagare.namespaces import xhtml
       >>> h = xhtml.Renderer()

       >>> root = h.div(h.h1('Hello world'), id='content')
       >>> root.write_htmlstring()
       <div id="content"><h1>Hello world</h1></div>'

       >>> root.fill('Go to ', h.a('Nagare home', href='http://www.nagare.org'), class_='description')

       >>> root.write_htmlstring()
        '<div id="content" class="description">Go to <a href="http://www.nagare.org">Nagare home</a></div>'

- ``replace(self, *children)`` -- replace the DOM element by the given children:

  .. code-block:: python

       >>> from nagare.namespaces import xhtml
       >>> h = xhtml.Renderer()

       >>> root = h.div(h.h1('Hello world'), id='content')
       >>> root.write_htmlstring()
       <div id="content"><h1>Hello world</h1></div>'
       >>> root[0].write_htmlstring()
       <h1>Hello world</h1>

       >>> root[0].replace(h.h2('Nagare'))

       >>> root.write_htmlstring()
       '<div id="content"><h2>Nagare</h2></div>'

- ``repeat(self, iterable, childname=None)``

  Repeats an element with values from an iterable.

  If ``childname`` is not ``None``, repeat the element on which repeat was called,
  otherwise find the child element with a ``meld:id`` matching ``childname``
  and repeat that.  The element is repeated within its parent element.

  This method returns an iterable; the value of each iteration is a
  two-sequence in the form (newelement, data).  ``newelement`` is a clone of
  the template element (including clones of its children) which has already
  been seated in its parent element in the template. ``data`` is a value from
  the passed in iterable.  Changing ``newelement`` (typically based on values
  from ``data``) mutates the element "in place".

  .. code-block:: pycon

        >>> from nagare.namespaces import xhtml
        >>> h = xhtml.Renderer()

        >>> root = h.parse_xmlstring('''<ul xmlns:meld="http://www.plope.com/software/meld3">
        ...   <li meld:id="alist" align="center">A line example</li>
        ... </ul>''')

        >>> items = ['Item %d' % i for i in range(3)]

        >>> for (element, item) in root.findmeld('alist').repeat(items):
        ...     element.text = item
        ...

        >>> print root.write_xmlstring()
        <ul xmlns:meld="http://www.plope.com/software/meld3">
        <li align="center">Item 0</li>
        <li align="center">Item 1</li>
        <li align="center">Item 2</li>
        </ul>

DOM tree serialization
~~~~~~~~~~~~~~~~~~~~~~

Once a tree of DOM elements is build, it can be serialized in (X)HTML:

- ``write_xmlstring(self, encoding='utf-8', pipeline=True)`` -- serializes
  the DOM tree into a XML string, encoded according to the ``encoding``
  parameter. If ``pipeline`` is True, the eventual ``meld:id`` attributes are
  removed, else they are kept so that the xml string can be re-parse as a
  template.

- ``write_htmlstring(self, encoding='utf-8', pipeline=True)`` -- serializes
  the DOM tree into a HTML string, encoded according to the ``encoding``
  parameter. If ``pipeline`` is True, the eventual ``meld:id`` attributes are
  removed.

