HTML Forms and Markup
*********************

Flatland is not explicitly a form library, although it handles that
task handily with powerful type conversion and validation error
reporting. Dedicated form libraries often provide sophisticated
“widget” or “control” features to render data fields as complex HTML
markup with CSS and JavaScript support.  The full expression of these
features is outside Flatland’s scope.

However!  Properly generating HTML form tags and filling them with
processed data is tedious and a common need, so Flatland ships with a
minimalistic yet powerful toolset for tag generation.  These tools are
both highly usable as-is and also a solid base for constructing
higher-level widgeting systems.


Markup Generation
=================

The generation formula is simple: a desired tag (such as "input") plus
a flatland Element equals a complete HTML tag with attributes like
"name" and "value" filled in using the element’s state.

Operating on "Element" rather than the raw HTTP input or the polished
final value provides a huge amount of expressive power.  For example,

* Elements carry their validation errors- place these directly next
  to the form fields, or roll them up- your choice.  Highlight failing
  fields with a "class="error"" CSS attribute right on the input
  element.

* (Re)populate form fields with exactly what the user typed, or the
  normalized version.

* Leverage the structure of the schema in template markup- if a form
  contains a list of 1 or more email addresses, loop over that list
  using your template language and render fields.

* Directly access Element properties and metadata, translation
  functions, and cross-element relations to implement complex view
  problems simply.

Flatland ships with two generator front-ends, both supporting the same
features via a shared backend.  The first, "Generator", is for use in
straight Python code, Jinja2, Mako, Genshi, or any other templating
system.  The second is a plugin for the Genshi templating library that
integrates Flatland element binding directly and naturally into your
existing <input/> tags.


Basic DWIM Binding
------------------

   >>> from flatland.out.markup import Generator
   >>> from flatland import Form, String
   >>> html = Generator()
   >>> class Login(Form):
   ...     username = String
   ...     password = String
   ...
   >>> form = Login({'username': 'jek'})

Basic “Do What I Mean” form binding:

   >>> print html.input(form['username'])
   <input name="username" value="jek" />

Likewise with Genshi.

   <input form:bind="form.username"/>

and Genshi generates:

   <input name="username" value="jek"/>


Attributes Too
--------------

Any HTML attribute can be included.  Generated attributes can be
overridden, too.

This time, the Generator is used in a Jinja2 template.

   >>> from jinja2 import Template
   >>> template = Template("""\
   ... {{ html.input(form.username, name="other", class_="custom") }}
   ... """)
   >>> print template.render(html=html, form=form)
   <input name="other" value="jek" class="custom" />

These features are very similar in Genshi, too.

   <input form:bind="form.username" name="other" class="custom"/>

Which generates the same output:

   <input name="other" value="jek" class="custom"/>

Many Python templating systems allow you to replace the indexing
operator ("form['username']") with the attribute operator
("form.username") to improve readability in templates.  As shown
above, this kind of rewriting trickery is generally not a problem for
Flatland.  Just keep name collisions in mind- if your form has a
String field called "name", is "form.name" the value of your form’s
name attribute or is it the String field?  When writing macros or
reusable functions, using the explicit "form[...]" index syntax is a
good choice to protect against unexpected mangling by the template
system no matter what the fields are named.


And More
--------

The tag and attribute generation behavior can be configured and even
post-processed just as you like it, affecting all of your tags, just
one template, a block, or even individual tags.


Controlling Attribute Transformations
=====================================

Out of the box, generation will do everything required for form
element rendering and repopulation: filling "<textarea>s", checking
checkboxes, etc. Flatland can also generate some useful *optional*
attributes, such as "id=" and "for=" linking for "<label>s".
Generation of attributes is controlled with markup options at several
levels:

Global:
   Everything generated with a Generator instance or within a Genshi
   rendering operation.

Block:
   Options can be overridden within the scope of a block, reverting to
   their previous value at the end of the block.

Tag:
   Options can overridden on a per-tag basis.

Default:
   Finally, each tag has a set of sane default behaviors.

Boolean options may be True, or False, “on” or “off”, or set to “auto”
to revert to the transformation’s built-in default setting.


Transformations
===============

Most transforms require a Flatland element for context, such as
setting an "input" tag’s "value=" to the element’s Unicode value.
These tags can be said to be “bound” to the element.

Tags need not be bound, however.  Here an unbound "textarea" can still
participate in "tabindex=" generation.

   >>> html = Generator(tabindex=100)
   >>> print html.textarea()
   <textarea></textarea>
   >>> print html.textarea(auto_tabindex=True)
   <textarea tabindex="100"></textarea>
   >>> html.set(auto_tabindex=True)
   u''
   >>> print html.textarea()
   <textarea tabindex="101"></textarea>

Setting a boolean option to “on” or True on the tag itself will always
attempt to apply the transform, allowing the transform to be applied
to arbitrary tags that normally would not be transformed.

   >>> print html.tag('squiznart', auto_tabindex=True)
   <squiznart tabindex="102" />

The Python APIs and the Generator tags use “_”-separated transform
names (valid Python identifiers) as shown below, however please note
that Genshi uses XML-friendly “-“-separated attribute names in markup.

auto-name

   Default:
      on

   Tags:
      button, form, input, select, textarea

   Sets the tag "name=" to the bound element’s ".name". Takes no
   action if the tag already contains a "name=" attribute, unless
   forced.

   Receives a "name=" attribute:

      >>> print html.input(form['username'], type="text")
      <input type="text" name="username" value="jek" />

   Uses the explicitly provided "name="foo"":

      >>> print html.input(form['username'], type="text", name='foo')
      <input type="text" name="foo" value="jek" />

   Replaces "name="foo"" with the element’s name:

      >>> print html.input(form['username'], type="text", name='foo', auto_name=True)
      <input type="text" name="username" value="jek" />

auto-value

   Default:
      on

   Tags:
      button, input, select, textarea

   Uses the bound element’s ".u" Unicode value for the tag’s value.
   The semantics of “value” vary by tag.

   "<input>" types **text**, **hidden**, **button**, **submit** and
   **reset**:

      Sets the "value=""" attribute of the tag, or omits the attribute
      if ".u" is the empty string.

      Receives a "value=" attribute:

         >>> print html.input(form['username'], type="text")
         <input type="text" name="username" value="jek" />

      Uses the explicitly provided "value="quux"":

         >>> print html.input(form['username'], type="text", value='quux')
         <input type="text" name="username" value="quux" />

   "<input>" types **password**, **image** and **file**:

      No value is added unless forced by setting auto_value on the
      tag.

         >>> print html.input(form['password'], type="password")
         <input type="password" name="password" />

      But this behavior can be forced:

         >>> print html.input(form['password'], type="password", auto_value=True)
         <input type="password" name="password" value="secret" />

   "<input>" type **radio**:

      Radio buttons will add a "checked="checked"" attribute if the
      literal "value=" matches the element’s value.  Or, if the bind
      is a "Container", "value=" will be compared against the ".u" of
      each of the container’s children until a match is found.

      If the tag lacks a "value=" attribute, no action is taken.

         >>> print form['username'].u
         jek
         >>> print html.input(form['username'], type="radio", value="quux")
         <input type="radio" name="username" value="quux" />
         >>> print html.input(form['username'], type="radio", value="jek")
         <input type="radio" name="username" value="jek" checked="checked" />

   "<input>" type **checkbox**:

      Check boxes will add a "checked="checked"" attribute if the
      literal "value=" matches the element’s value.

         >>> print form['username'].u
         jek
         >>> print html.input(form['username'], type="checkbox", value="quux")
         <input type="checkbox" name="username" value="quux" />
         >>> print html.input(form['username'], type="checkbox", value="jek")
         <input type="checkbox" name="username" value="jek" checked="checked" />

      Or, if the bind is a "Container", "value=" will be compared
      against the ".u" of each of the container’s children until a
      match is found.

         >>> from flatland import Array
         >>> Bag = Array.named('bag').of(String)
         >>> bag = Bag(['a', 'c'])
         >>> for value in 'a', 'b', 'c':
         ...     print html.input(bag, type="checkbox", value=value)
         ...
         <input type="checkbox" name="bag" value="a" checked="checked" />
         <input type="checkbox" name="bag" value="b" />
         <input type="checkbox" name="bag" value="c" checked="checked" />

      If the tag lacks a "value=" attribute, no action is taken,
      unless the bind is a Boolean.  The missing "value=" will be
      added using the schema’s "Boolean.true" value.

         >>> print html.input(form['username'], type="checkbox")
         <input type="checkbox" name="username" />
         >>> from flatland import Boolean
         >>> toggle = Boolean.named('toggle')()
         >>> print html.input(toggle, type="checkbox")
         <input type="checkbox" name="toggle" value="1" />
         >>> toggle.set(True)
         True
         >>> print html.input(toggle, type="checkbox")
         <input type="checkbox" name="toggle" value="1" checked="checked" />
         >>> toggle.true = "yes"

   "<input>" types unknown:

      For types unknown to flatland, no value is set unless forced by
      setting "form:auto-value="on"" on the tag.

   "<textarea>":

      Textareas will insert the "Element.u" inside the tag pair.
      Content supplied with "contents=" for Generators or between
      Genshi tags will be preferred unless forced.

         >>> print html.textarea(form['username'])
         <textarea name="username">jek</textarea>
         >>> print html.textarea(form['username'], contents="quux")
         <textarea name="username">quux</textarea>

      Note that in Genshi, these two forms are equivalent.

         <!-- these: -->
         <textarea form:bind="form.username"/>
         <textarea form:bind="form.username"></textarea>

         <!-- will both render as -->
         <textarea name="username">jek</textarea>

   "<select>":

      Select tags apply a "selected="selected"" attribute to their
      "<option>" tags that match the "Element.u" or, if the bind is a
      "Container", the ".u" of one of its children.

      For this matching to work, the "<option>" tags must have a
      literal value set in the markup.  The value may an explicit
      "value=" attribute, or it may be the text of the tag.  Leading
      and trailing whitespace will be stripped when considering the
      text of the tag as the value.

      The below will emit "selected="selected"" if form.field is equal
      to any of “a”, “b”, “c”, and “d”.

         <select form:bind="form.field">
            <option>a</option>
            <option value="b"/>
            <option value="c">label</option>
            <option>
              d
            </option>
         </select>

   "<button/>" and "<button value=""/>":

      Regular "<button/>" tags will insert the "Element.u" inside the
      "<button></button>" tag pair.  The output will **not** be XML-
      escaped, allowing any markup in the ".u" to render properly.

      If the tag contains a literal "value=" attribute and a value
      override is forced by setting "form:auto-value="on"", the ".u"
      will be placed in the "value=" attribute, replacing the existing
      content.  The value is escaped in this case.

         <!-- set or replace the inner *markup* -->
         <button form:bind="form.field"/>
         <button form:bind="form.field" form:auto-value="on">xyz</button>

         <!-- set the value, retaining the value= style used in the original -->
         <button form:bind="form.field" value="xyz" form:auto-value="on"/>

auto-domid

   Default:
      off

   Tags:
      button, input, select, textarea

   Sets the "id=" attribute of the tag.  Takes no action if the markup
   already contains a "id=" unless forced by setting "form:auto-
   domid="on"".

   The id is generated by combining the bound element’s
   "flattened_name" with the "domid-format" in the current scope.  The
   default format is **f_%s**.

auto-for

   Default:
      on

   Tags:
      label

   Sets the "for=" attribute of the tag to the id of the bound
   element. The id is generated using the same process as auto-domid.
   No consistency checks are performed on the generated id value.

   Defaults to “on”, and will only apply if auto-domid is also “on”.
   Takes no action if the markup already contains a "id=" unless
   forced by setting "form:auto-for="on"".

      <form:with auto-domid="on">
        <fieldset py:with="field=form.field">
          <label form:bind="field">${field.label.x}</label>
          <input type="text" form:bind="field"/>
        </fieldset>
      </form:with>

auto-tabindex

   Default:
      off

   Tags:
      button, input, select, textarea

   Sets the "tabindex" attribute of tags with an incrementing integer.

   Numbering starts at the scope’s "tabindex", which has no default.
   Assigning a value for "tabindex" will set the value for the next
   tabindex assignment, and subsequent assignments will increment by
   one.

   A "tabindex" value of 0 will block the assignment of a tabindex and
   will not be incremented.

   Takes no action if the markup already contains a "tabindex=" unless
   forced by setting "form:auto-tabindex="on"".

      <form:with auto-tabindex="on" tabindex="1">
        <!-- assigns tabindex="1" -->
        <input type="text" form:bind="form.field"/>

        <!-- leaves existing tabindex in place -->
        <input type="text" tabindex="-1" form:bind="form.field"/>

        <!-- assigns tabindex="2" -->
        <a href="#" form:auto-tabindex="on"/>
      </form:with>


Generator
=========

class Generator(markup=u'xhtml', **settings)

   General XML/HTML tag generator

   Create a generator.

   Accepts any Transformations, as well as the following:

   Parameters:
      * **markup** – tag output style: "'xml'", "'xhtml'" or
        "'html'"

      * **ordered_attributes** – if True (default), output markup
        attributes in a predictable order.  Useful for tests and
        generally a little more pleasant to read.

   begin(**settings)

      Begin a new Transformations context.

      Puts **settings into effect until a matching "end()" is called.
      Each setting specified will mask the current value, reverting
      when "end()" is called.

   end()

      End a Transformations context.

      Restores the settings that were in effect before "begin()".

   set(**settings)

      Change the Transformations in effect.

      Change the **settings in the current scope.  Changes remain in
      effect until another "set()" or a "end()" ends the current
      scope.

   form

      Generate a "<form/>" tag.

      Parameters:
         * **bind** – optional, a flatland element.

         * ****attributes** – any desired XML/HTML attributes.

      Returns:
         a printable "Tag"

      If provided with a bind, form tags can generate the *name*
      attribute.

   input

      Generate an "<input/>" tag.

      Parameters:
         * **bind** – optional, a flatland element.

         * ****attributes** – any desired XML/HTML attributes.

      Returns:
         a printable "Tag"

      If provided with a bind, input tags can generate the *name*,
      *value* and *id* attributes.  Input tags support *tabindex*
      attributes.

   textarea

      Generate a "<textarea/>" tag.

      Parameters:
         * **bind** – optional, a flatland element.

         * ****attributes** – any desired XML/HTML attributes.

      Returns:
         a printable "Tag"

      If provided with a bind, textarea tags can generate the *name*
      and *id* attributes.  If the bind has a value, it will be used
      as the tag body.  Textarea tags support *tabindex* attributes.
      To provide an alternate tag body, either supply *contents* or
      use the "open()" and "close()" method of the returned tag.

   button

      Generate a "<button/>" tag.

      Parameters:
         * **bind** – optional, a flatland element.

         * ****attributes** – any desired XML/HTML attributes.

      Returns:
         a printable "Tag"

      If provided with a bind, button tags can generate the *name*,
      *value*, and *id* attributes.  Button tags support *tabindex*
      attributes.

   select

      Generate a "<select/>" tag.

      Parameters:
         * **bind** – optional, a flatland element.

         * ****attributes** – any desired XML/HTML attributes.

      Returns:
         a printable "Tag"

      If provided with a bind, select tags can generate the *name* and
      *id* attributes.  Select tags support *tabindex* attributes.

   option

      Generate an "<option/>" tag.

      Parameters:
         * **bind** – optional, a flatland element.

         * ****attributes** – any desired XML/HTML attributes.

      Returns:
         a printable "Tag"

      If provided with a bind, option tags can generate the *value*
      attribute.  To provide tag body, either supply *contents* or use
      the "open()" and "close()" method of the returned tag:

         print generator.option.open(style='bold')
         print '<strong>contents</strong>'
         print generator.option.close()

   label

      Generate a "<label/>" tag.

      Parameters:
         * **bind** – optional, a flatland element.

         * ****attributes** – any desired XML/HTML attributes.

      Returns:
         a printable "Tag"

      If provided with a bind, label tags can generate the *for*
      attribute and fill in the tag body with the element’s "label",
      if present.

   tag(tagname, bind=None, **attributes)

      Generate any tag.

      Parameters:
         * **tagname** – the name of the tag.

         * **bind** – optional, a flatland element.

         * ****attributes** – any desired XML/HTML attributes.

      Returns:
         a printable "Tag"

      The attribute rules appropriate for *tagname* will be applied.
      For example, "tag('input')" is equivalent to "input()".

class Tag(tagname, context, dangle, paired)

   A printable markup tag.

   Tags are generated by "Generator" and are usually called
   immediately, returning a fully formed markup string:

      print generator.textarea(contents="hello!")

   For more fine-tuned control over your markup, you may instead
   choose to use the "open()" and "close()" methods of the tag:

      print generator.textarea.open()
      print "hello!"
      print generator.textarea.close()

   open(bind=None, **attributes)

      Return the opening half of the tag, e.g. "<p>".

      Parameters:
         * **bind** – optional, a flatland element.

         * ****attributes** – any desired tag attributes.

   close()

      Return the closing half of the tag, e.g. "</p>".


Genshi Directives
=================

   http://ns.discorporate.us/flatland/genshi
