zeam.form.base
==============

Widgets are responsible to render component (like actions and fields)
as HTML code for the user.

Widget
------

Widgets are multiadapters, which adapts the component they render, for
a given form, and request. So we need all that:

   >>> from zope.publisher.browser import TestRequest
   >>> request = TestRequest()

   >>> from zeam.form.base.form import Form
   >>> form1 = Form(None, request)

   >>> from zeam.form.base.actions import Action
   >>> action1 = Action(u"Do Something")
   >>> form1.actions += action1

So now we can get a widget for an action for instance:

   >>> from zeam.form.base import interfaces
   >>> from zope import component
   >>> widget1 = component.getMultiAdapter(
   ...         (action1, form1, request), interfaces.IWidget, name='input')
   >>> widget1
   <ActionWidget Do Something>

By default our widget will the same title than the component, and its
identifier will be composed with the component on and the form prefix:

   >>> action1.identifier
   'do-something'
   >>> widget1.identifier
   'form.action.do-something'
   >>> action1.title
   u'Do Something'
   >>> widget1.title
   u'Do Something'

The method render gives you the HTML to display. Our widget is an
action, so by default you get a button:

   >>> print widget1.render()
   <input type="submit" id="form-action-do-something"
          name="form.action.do-something" value="Do Something" class="action" />
   <BLANKLINE>

You can get its HTML id as well (to render any label for instance):

   >>> widget1.htmlId()
   'form-action-do-something'

Our widget implements IWidget, and IComponent:

   >>> from zope.interface.verify import verifyObject
   >>> verifyObject(interfaces.IWidget, widget1)
   True
   >>> interfaces.IWidget.extends(interfaces.IComponent)
   True

Field widget
~~~~~~~~~~~~

Like for actions, fields have widgets to be rendered. They are a bit
more advanced:

   >>> from zeam.form.base.fields import Field
   >>> field1 = Field(u"Title")
   >>> field1.description = u"Nice name for your field"
   >>> field1.required = True
   >>> form1.fields += field1

   >>> widget2 = component.getMultiAdapter(
   ...         (field1, form1, request), interfaces.IWidget, name='input')
   >>> widget2
   <FieldWidget Title>

Like for an action, all identifier and title are set correctly:

   >>> field1.identifier
   'title'
   >>> widget2.identifier
   'form.field.title'
   >>> field1.title
   u'Title'
   >>> widget2.title
   u'Title'

Prefixes of the form and the component will alter the identifier:

   >>> form2 = Form(None, request)
   >>> form2.prefix = u"something"

   >>> action2 = Action(u"Some action")
   >>> action2.prefix = u"else"
   >>> form2.actions += action2

   >>> widget3 = component.getMultiAdapter(
   ...         (action2, form2, request), interfaces.IWidget, name='input')

   >>> widget3.identifier
   'something.else.some-action'

If the prefixes are empty:

   >>> form2.prefix = u""
   >>> widget3 = component.getMultiAdapter(
   ...         (action2, form2, request), interfaces.IWidget, name='input')

   >>> widget3.identifier
   'else.some-action'

   >>> action2.prefix = u""
   >>> widget3 = component.getMultiAdapter(
   ...         (action2, form2, request), interfaces.IWidget, name='input')

   >>> widget3.identifier
   'some-action'

For convinience, the description and required is also available on the
widget (to be used while rendering that last one):

   >>> widget2.description
   u'Nice name for your field'
   >>> widget2.required
   True

As well, any error reported for the field on the form is accessible
via the widget:

   >>> widget2.error

   >>> from zeam.form.base.errors import Error
   >>> form1.errors.append(Error('Not Happy', 'form.field.someone'))
   >>> widget2.error
   >>> form1.errors.append(Error('Missing value', 'form.field.title'))
   >>> widget2.error
   <Error Missing value>

Widget are views that can be that can be renderered:

   >>> widget2.update()
   >>> widget2.render() #doctest: +NORMALIZE_WHITESPACE
   u'<input type="text" id="form-field-title" name="form.field.title"
            class="field" value="" required="required" />\n'

If field is read only then field widget is read only as well.

   >>> field1.readonly = True
   >>> widget2 =component.getMultiAdapter(
   ...         (field1, form1, request), interfaces.IWidget, name='input')
   >>> widget2.readonly
   True
   >>> widget2.update()
   >>> widget2.render() #doctest: +NORMALIZE_WHITESPACE
   u'<input type="text" id="form-field-title" name="form.field.title"
            class="field" value="" required="required" readonly="readonly" />\n'

Field widget value
~~~~~~~~~~~~~~~~~~

A field widget is able to compute a value for the field to be rendered
in the widget. It can look it on the previous request or the context,
depending of the settings.


Field widget interface
~~~~~~~~~~~~~~~~~~~~~~

Our widget implement IFieldWidget, which extend the default widget interface:

   >>> verifyObject(interfaces.IFieldWidget, widget1)
   Traceback (most recent call last):
     ...
   DoesNotImplement: An object does not implement interface <InterfaceClass zeam.form.base.interfaces.IFieldWidget>
   >>> verifyObject(interfaces.IFieldWidget, widget2)
   True
   >>> interfaces.IFieldWidget.extends(interfaces.IWidget)
   True


Widgets
-------

As you can guess, you are not going to build your widgets one by one
to render them. You can a Widgets collection to create and manage your
widgets.

Let's add an another action to our form, and let's create widgets for
them:

   >>> form1.actions += Action("Do Nothing")
   >>> list(form1.actions)
   [<Action Do Something>, <Action Do Nothing>]

   >>> from zeam.form.base.widgets import Widgets
   >>> widgets1 = Widgets(form1.actions, form=form1, request=request)
   >>> widgets1
   <Widgets>
   >>> list(widgets1)
   [<ActionWidget Do Something>, <ActionWidget Do Nothing>]
   >>> widgets1.keys()
   ['form.action.do-something', 'form.action.do-nothing']

There is an update method on a Widgets collection, which is going to
call update on each Widget of the collection:

   >>> widgets1.update()

Widgets implements IWidgets and ICollection:

   >>> verifyObject(interfaces.IWidgets, widgets1)
   True
   >>> interfaces.IWidgets.extends(interfaces.ICollection)
   True

Since Widgets are collection, you can of course use ``copy``,
``select`` or ``omit`` on your widget the selection:

   >>> widgets1copy = widgets1.copy()
   >>> widgets1copy
   <Widgets>
   >>> widgets1copy.form is widgets1.form
   True
   >>> widgets1copy.request is widgets1.request
   True
   >>> list(widgets1copy) == list(widgets1)
   True
   >>> widgets1copy is widgets1
   False

   >>> list(widgets1.omit('form.action.do-something'))
   [<ActionWidget Do Nothing>]

   >>> list(widgets1.select('form.action.do-something'))
   [<ActionWidget Do Something>]

Of course you cannot extend it with anything else than components:

   >>> widgets1.extend(42)
   Traceback (most recent call last):
     ...
   TypeError: (u'Invalid type', 42)

But you can directly add an already created widget:

   >>> widgets2 = Widgets(form=form1, request=request)
   >>> widgets2.extend(widgets1['form.action.do-nothing'])
   >>> list(widgets2)
   [<ActionWidget Do Nothing>]
   >>> widgets2.keys()
   ['form.action.do-nothing']

WidgetExtractor
---------------

Widget can render a component to HTML, but it is not their job to
extract values from a request back to a component. It's the job of a
WidgetExtractor, which might be called before the Widget is even
created.

Widget and WidgetExtractor will often work together, as the extractor
need to correctly extract the information from the request.

This design prevent widgets to cache the value they are going to
render when an action might have changed it, like it's done in other
form frameworks design. To be sure that an action doesn't change any
value to render, they are all executed before any widget is created
(even in the case of subforms).

So WidgetExtractor are multiadapters, adapting the component, form and
request, like a Widget does:

   >>> e1 = component.getMultiAdapter(
   ...         (action1, form1, request), interfaces.IWidgetExtractor)
   >>> e1
   <zeam.form.base.widgets.WidgetExtractor object at ...>

And you can extract the widget value, and errors from the request:

   >>> e1.extract()
   (<Marker NO_VALUE>, None)

But our request was empty here. Let's try with a non-empty one:

   >>> submitted_request = TestRequest(
   ...         form={'form.action.do-something': u'Do Something',
   ...                'otherfield': 42})
   >>> e2 = component.getMultiAdapter(
   ...         (action1, form1, submitted_request),
   ...         interfaces.IWidgetExtractor)
   >>> e2.extract()
   (u'Do Something', None)

An another of the extractor is to gives the request fields used for
the extraction:

   >>> e2.extractRaw()
   {'form.action.do-something': u'Do Something'}

This can be used by widgets to display again any non-validated data.

WidgetExtractor implements IWidgetExtractor, but inlike Widgets, not
IComponent:

   >>> verifyObject(interfaces.IWidgetExtractor, e1, e2)
   True
   >>> interfaces.IComponent.providedBy(e1)
   False

