Widget-aware views
==================
This package provides a view mixin class that can be used like a display form.
The view is set up with widgets based on schema interfaces and/or form fields,
and are available in 'display' mode.
First, let's load this package's ZCML so that we can run the tests:
>>> configuration = """\
...
...
...
...
...
...
... """
>>> from StringIO import StringIO
>>> from zope.configuration import xmlconfig
>>> xmlconfig.xmlconfig(StringIO(configuration))
As with auto-forms, the widgets come from a primary schema interface, and
optionally one or more secondary interfaces. Let's define two.
>>> from zope.interface import Interface
>>> from zope import schema
>>> class IDefaultSchema(Interface):
... title = schema.TextLine(title=u"Title")
... body = schema.Text(title=u"Body")
>>> class ISecondarySchema(Interface):
... summary = schema.Text(title=u"Summary")
Let us also annotate these with some field hints, putting 'summary' into a
secondary schema.
>>> from plone.supermodel.interfaces import FIELDSETS_KEY
>>> from plone.supermodel.model import Fieldset
>>> ISecondarySchema.setTaggedValue(FIELDSETS_KEY, [Fieldset('secondary', fields=['summary'])])
A display form normally operates on a given context, although you could set
``ignoreContext = True`` and/or implement ``getContent()`` if applicable. The
schema interfaces need to be provided by or adaptable from the context. For
the purposes of this test, we'll just make them directly provided.
>>> from zope.interface import implements
>>> class Context(object):
... implements(IDefaultSchema, ISecondarySchema)
... title = u""
... body = u""
... summary = u""
We can now define a display form view. This should sub class or mix in
WidgetsView. It must define either an ``index`` callable (usually a page
template set by the ```` directive) or override the ``render``
method. It should also set the ``schema`` and ``additionalSchemata`` properties
as required, using class variables, instance variables or properties.
>>> from plone.autoform.view import WidgetsView
>>> class TestView(WidgetsView):
... schema = IDefaultSchema
... additionalSchemata = (ISecondarySchema,)
... def render(self):
... return u"
My title widget says %s
" % self.w['title'].render()
We need a test context and request, marked with the ``IFormLayer`` interface to
make z3c.form happy:
>>> from zope.publisher.browser import TestRequest
>>> from z3c.form import interfaces
>>> context = Context()
>>> request = TestRequest(environ={'AUTHENTICATED_USER': 'user1'}, skin=interfaces.IFormLayer)
Let us try to render this, to demonstrate that the widgets will be properly
set up.
>>> context.title = u"Test title"
>>> context.body = u"Body"
>>> context.summary = u"Summary"
>>> view = TestView(context, request)
>>> print view()
My title widget says
Test title
More generally, the view supports the contract of display forms. After being
updated, we have access to widgets in the default fieldset:
>>> view.widgets.items()
[('title', ),
('body', )]
There is also a shortcut to allow access to any widget by (possibly prefixed)
name:
>>> view.w.items()
[('body', ),
('ISecondarySchema.summary', ),
('title', )]
You can also see fieldsets (groups) either in order:
>>> view.groups
(,)
or looked up by name:
>>> view.fieldsets.items()
[('secondary', )]
Note how the schema name is used as a prefix to all additional schemata. If
you wish to flatten the namespace, you can set ignorePrefix to true:
>>> view = TestView(context, request)
>>> view.ignorePrefix = True
>>> view.update()
>>> view.w.items()
[('body', ),
('summary', ),
('title', )]
For supporting widget traversal it is necessary that after updating
the form the widgets are present:
>>> view2 = TestView(context, request)
>>> view2.update()
>>> view2.widgets
>>> view2.widgets.keys()
['title', 'body']