[Checkins] SVN: z3c.form/trunk/ add new widgetmanager to mix fields and content providers in forms (merge from fieldsandcontentproviders branch)
Jean-Francois Roche
jfroche at jfroche.be
Thu Jul 1 08:00:21 EDT 2010
Log message for revision 114046:
add new widgetmanager to mix fields and content providers in forms (merge from fieldsandcontentproviders branch)
Changed:
U z3c.form/trunk/CHANGES.txt
U z3c.form/trunk/buildout.cfg
U z3c.form/trunk/setup.py
U z3c.form/trunk/src/z3c/form/README.txt
U z3c.form/trunk/src/z3c/form/configure.zcml
A z3c.form/trunk/src/z3c/form/contentprovider.py
A z3c.form/trunk/src/z3c/form/contentprovider.txt
U z3c.form/trunk/src/z3c/form/index.txt
U z3c.form/trunk/src/z3c/form/interfaces.py
U z3c.form/trunk/src/z3c/form/testing.py
A z3c.form/trunk/src/z3c/form/tests/simple_edit_with_providers.pt
U z3c.form/trunk/src/z3c/form/tests/test_doc.py
U z3c.form/trunk/src/z3c/form/util.py
-=-
Modified: z3c.form/trunk/CHANGES.txt
===================================================================
--- z3c.form/trunk/CHANGES.txt 2010-07-01 10:47:15 UTC (rev 114045)
+++ z3c.form/trunk/CHANGES.txt 2010-07-01 12:00:21 UTC (rev 114046)
@@ -5,6 +5,11 @@
2.3.5 (unreleased)
------------------
+- Feature : mix fields and content providers in forms. This allow to enrich
+ the form by interlacing html snippets produced by content providers.
+ Adding html outside the widgets avoids the systematic need of
+ subclassing or changing the full widget rendering.
+
- Bug: Radio widget was not treating value as a list in hidden mode.
Modified: z3c.form/trunk/buildout.cfg
===================================================================
--- z3c.form/trunk/buildout.cfg 2010-07-01 10:47:15 UTC (rev 114045)
+++ z3c.form/trunk/buildout.cfg 2010-07-01 12:00:21 UTC (rev 114046)
@@ -1,7 +1,7 @@
[buildout]
develop = . benchmark
parts = test test-no-z3zpt checker coverage-test coverage-report docs i18n
- benchmark python
+ benchmark python omelette
[test-environment]
CHAMELEON_DEBUG = False
@@ -77,3 +77,7 @@
recipe = zc.recipe.egg
eggs = z3c.form
interpreter = python
+
+[omelette]
+recipe = collective.recipe.omelette
+eggs = ${test:eggs}
Modified: z3c.form/trunk/setup.py
===================================================================
--- z3c.form/trunk/setup.py 2010-07-01 10:47:15 UTC (rev 114045)
+++ z3c.form/trunk/setup.py 2010-07-01 12:00:21 UTC (rev 114046)
@@ -19,11 +19,13 @@
import xml.sax.saxutils
from setuptools import setup, find_packages
+
def read(*rnames):
text = open(os.path.join(os.path.dirname(__file__), *rnames)).read()
text = unicode(text, 'utf-8').encode('ascii', 'xmlcharrefreplace')
return xml.sax.saxutils.escape(text)
+
chapters = '\n'.join(
[read('src', 'z3c', 'form', name)
for name in ('README.txt',
@@ -35,32 +37,33 @@
'zcml.txt',
'validator.txt',
'widget.txt',
+ 'contentprovider.txt',
'action.txt',
'value.txt',
'datamanager.txt',
'converter.txt',
'term.txt',
- 'util.txt')])
+ 'util.txt',
+ )])
-setup (
+setup(
name='z3c.form',
- version = '2.3.5dev',
- author = "Stephan Richter, Roger Ineichen and the Zope Community",
- author_email = "zope-dev at zope.org",
- description = "An advanced form and widget framework for Zope 3",
+ version='2.3.5dev',
+ author="Stephan Richter, Roger Ineichen and the Zope Community",
+ author_email="zope-dev at zope.org",
+ description="An advanced form and widget framework for Zope 3",
long_description=(
read('README.txt')
+ '\n\n' +
'Detailed Documentation\n'
'**********************\n'
+ '\n' + chapters
- + '\n\n' +
- read('CHANGES.txt')
- ),
- license = "ZPL 2.1",
- keywords = "zope3 form widget",
- classifiers = [
+ + '\n\n'
+ + read('CHANGES.txt')),
+ license="ZPL 2.1",
+ keywords="zope3 form widget",
+ classifiers=[
'Development Status :: 5 - Production/Stable',
'Environment :: Web Environment',
'Intended Audience :: Developers',
@@ -70,17 +73,17 @@
'Operating System :: OS Independent',
'Topic :: Internet :: WWW/HTTP',
'Framework :: Zope3'],
- url = 'http://pypi.python.org/pypi/z3c.form',
- packages = find_packages('src'),
- include_package_data = True,
- package_dir = {'':'src'},
- namespace_packages = ['z3c'],
- extras_require = dict(
- extra = [
+ url='http://pypi.python.org/pypi/z3c.form',
+ packages=find_packages('src'),
+ include_package_data=True,
+ package_dir={'': 'src'},
+ namespace_packages=['z3c'],
+ extras_require=dict(
+ extra=[
'z3c.pt >= 1.0b4',
'z3c.ptcompat',
],
- test = [
+ test=[
'lxml >= 2.1.1',
'z3c.coverage',
'z3c.template',
@@ -93,16 +96,16 @@
'zope.app.testing',
'zope.testing',
],
- zope34 = [
+ zope34=[
'zope.app.component',
],
- latest = [
+ latest=[
'zope.site',
],
- adding = ['zope.app.container'],
- docs = ['z3c.recipe.sphinxdoc'],
+ adding=['zope.app.container'],
+ docs=['z3c.recipe.sphinxdoc'],
),
- install_requires = [
+ install_requires=[
'setuptools',
'zope.browser',
'zope.component',
@@ -122,5 +125,5 @@
#'zope.site' or 'zope.app.component',
'zope.traversing',
],
- zip_safe = False,
+ zip_safe=False,
)
Modified: z3c.form/trunk/src/z3c/form/README.txt
===================================================================
--- z3c.form/trunk/src/z3c/form/README.txt 2010-07-01 10:47:15 UTC (rev 114045)
+++ z3c.form/trunk/src/z3c/form/README.txt 2010-07-01 12:00:21 UTC (rev 114046)
@@ -48,6 +48,11 @@
Explains in detail the design goals surrounding widgets and widget managers
and how they were realized with the implemented API.
+- ``contentprovider.txt`` [advanced users]
+
+ Explains how to mix content providers in forms to render more html around
+ widgets.
+
- ``action.txt`` [advanced users]
Explains in detail the design goals surrounding action managers and
Modified: z3c.form/trunk/src/z3c/form/configure.zcml
===================================================================
--- z3c.form/trunk/src/z3c/form/configure.zcml 2010-07-01 10:47:15 UTC (rev 114045)
+++ z3c.form/trunk/src/z3c/form/configure.zcml 2010-07-01 12:00:21 UTC (rev 114046)
@@ -30,6 +30,10 @@
factory=".field.FieldWidgets"
/>
+ <adapter
+ factory=".contentprovider.FieldWidgetsAndProviders"
+ />
+
<!-- Data Converters -->
<adapter
factory=".converter.FieldDataConverter"
Copied: z3c.form/trunk/src/z3c/form/contentprovider.py (from rev 114045, z3c.form/branches/fieldsandcontentproviders/src/z3c/form/contentprovider.py)
===================================================================
--- z3c.form/trunk/src/z3c/form/contentprovider.py (rev 0)
+++ z3c.form/trunk/src/z3c/form/contentprovider.py 2010-07-01 12:00:21 UTC (rev 114046)
@@ -0,0 +1,115 @@
+import zope.component
+import zope.interface
+import zope.location
+import zope.schema.interfaces
+from z3c.form.error import MultipleErrors
+from zope.contentprovider.interfaces import IContentProvider
+
+from z3c.form.field import FieldWidgets
+from z3c.form import interfaces
+from z3c.form.interfaces import IContentProviders
+
+
+class BaseProvider(object):
+ __slots__ = ('position')
+
+lookup_ = BaseProvider()
+
+
+class ContentProviders(dict):
+ zope.interface.implements(IContentProviders)
+
+ def __init__(self, names=None):
+ super(ContentProviders, self).__init__()
+ if names is not None:
+ for position, name in enumerate(names):
+ self[name] = lookup_
+
+ def __setitem__(self, key, value):
+ factory = ContentProviderFactory(factory=value, name=key)
+ super(ContentProviders, self).__setitem__(key, factory)
+
+
+class ContentProviderFactory(object):
+
+ def __init__(self, factory, name):
+ self.factory = factory
+ self.name = name
+ self.position = getattr(factory, 'position', None)
+
+ def __call__(self, manager):
+ if self.factory != lookup_:
+ contentProvider = self.factory(manager.content, manager.request, manager.form)
+ else:
+ contentProvider = zope.component.getMultiAdapter((manager.content, manager.request, manager.form),
+ IContentProvider, self.name)
+ return contentProvider
+
+
+class FieldWidgetsAndProviders(FieldWidgets):
+ zope.component.adapts(
+ interfaces.IFieldsAndContentProvidersForm, interfaces.IFormLayer, zope.interface.Interface)
+ zope.interface.implementsOnly(interfaces.IWidgets)
+
+ def update(self):
+ super(FieldWidgetsAndProviders, self).update()
+ uniqueOrderedKeys = self._data_keys
+ for name in self.form.contentProviders:
+ factory = self.form.contentProviders[name]
+ if factory.position is None:
+ raise ValueError("Position of the following"
+ " content provider should be an integer: '%s'." % name)
+ contentProvider = factory(self)
+ shortName = name
+ contentProvider.update()
+ uniqueOrderedKeys.insert(factory.position, shortName)
+ self._data_values.insert(factory.position, contentProvider)
+ self._data[shortName] = contentProvider
+ zope.location.locate(contentProvider, self, shortName)
+ # allways ensure that we add all keys and keep the order given from
+ # button items
+ self._data_keys = uniqueOrderedKeys
+
+ def extract(self):
+ """See interfaces.IWidgets"""
+ data = {}
+ errors = ()
+ for name, widget in self.items():
+ if IContentProvider.providedBy(widget):
+ continue
+ if widget.mode == interfaces.DISPLAY_MODE:
+ continue
+ value = widget.field.missing_value
+ try:
+ widget.setErrors = self.setErrors
+ raw = widget.extract()
+ if raw is not interfaces.NO_VALUE:
+ value = interfaces.IDataConverter(widget).toFieldValue(raw)
+ zope.component.getMultiAdapter(
+ (self.content,
+ self.request,
+ self.form,
+ getattr(widget, 'field', None),
+ widget),
+ interfaces.IValidator).validate(value)
+ except (zope.interface.Invalid,
+ ValueError, MultipleErrors), error:
+ view = zope.component.getMultiAdapter(
+ (error, self.request, widget, widget.field,
+ self.form, self.content), interfaces.IErrorViewSnippet)
+ view.update()
+ if self.setErrors:
+ widget.error = view
+ errors += (view,)
+ else:
+ name = widget.__name__
+ data[name] = value
+ for error in self.validate(data):
+ view = zope.component.getMultiAdapter(
+ (error, self.request, None, None, self.form, self.content),
+ interfaces.IErrorViewSnippet)
+ view.update()
+ errors += (view,)
+ if self.setErrors:
+ self.errors = errors
+ return data, errors
Copied: z3c.form/trunk/src/z3c/form/contentprovider.txt (from rev 114045, z3c.form/branches/fieldsandcontentproviders/src/z3c/form/contentprovider.txt)
===================================================================
--- z3c.form/trunk/src/z3c/form/contentprovider.txt (rev 0)
+++ z3c.form/trunk/src/z3c/form/contentprovider.txt 2010-07-01 12:00:21 UTC (rev 114046)
@@ -0,0 +1,311 @@
+=================
+Content Providers
+=================
+
+We want to mix fields and content providers.
+
+This allow to enrich the form by interlacing html snippets produced by content
+providers.
+
+For instance, we might want to render the table of results in a search form.
+
+We might also need to render HTML close to a widget as a handle used when
+improving UI with Ajax.
+
+Adding HTML outside the widgets avoids the systematic need of
+subclassing or changing the full widget rendering.
+
+Test setup
+----------
+Before we can use a widget manager, the ``IFieldWidget`` adapter
+has to be registered for the ``ITextLine`` field::
+
+ >>> import zope.component
+ >>> import zope.interface
+ >>> from z3c.form import interfaces, widget
+ >>> from z3c.form.browser import text
+ >>> from z3c.form.testing import TestRequest
+
+ >>> @zope.component.adapter(zope.schema.TextLine, TestRequest)
+ ... @zope.interface.implementer(interfaces.IFieldWidget)
+ ... def TextFieldWidget(field, request):
+ ... return widget.FieldWidget(field, text.TextWidget(request))
+
+ >>> zope.component.provideAdapter(TextFieldWidget)
+
+ >>> from z3c.form import converter
+ >>> zope.component.provideAdapter(converter.FieldDataConverter)
+ >>> zope.component.provideAdapter(converter.FieldWidgetDataConverter)
+
+We define a simple test schema with fields::
+
+ >>> import zope.interface
+ >>> import zope.schema
+
+ >>> class IPerson(zope.interface.Interface):
+ ...
+ ... id = zope.schema.TextLine(
+ ... title=u'ID',
+ ... description=u"The person's ID.",
+ ... required=True)
+ ...
+ ... fullname = zope.schema.TextLine(
+ ... title=u'FullName',
+ ... description=u"The person's name.",
+ ... required=True)
+ ...
+
+A class that implements the schema::
+
+ >>> class Person(object):
+ ... id = 'james'
+ ... fullname = 'James Bond'
+
+The usual request instance::
+
+ >>> request = TestRequest()
+
+We want to insert a content provider inbetween fields.
+We define a test content provider that renders extra help text::
+
+ >>> from zope.contentprovider.provider import ContentProviderBase
+ >>> class ExtendedHelp(ContentProviderBase):
+ ...
+ ... def update(self):
+ ... self.person = self.context.id
+ ...
+ ... def render(self):
+ ... return '<div class="ex-help">Help about person %s</div>' % self.person
+
+Form definition
+---------------
+
+The meat of the tests begins here.
+
+We define a form as usual by inheriting from ``form.Form``::
+
+ >>> from z3c.form import field, form
+ >>> from zope.interface import implements
+
+To enable content providers, the form class must :
+
+ 1. implement ``IFieldsAndContentProvidersForm``
+ 2. have a ``contentProviders`` attribute that is
+ an instance of the ``ContentProviders`` class.
+
+::
+
+ >>> from z3c.form.interfaces import IFieldsAndContentProvidersForm
+ >>> from z3c.form.contentprovider import ContentProviders
+
+Content provider assignment
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Content providers classes (factories) can be assigned directly to the
+``ContentProviders`` container::
+
+ >>> class PersonForm(form.Form):
+ ... implements(IFieldsAndContentProvidersForm)
+ ... fields = field.Fields(IPerson)
+ ... ignoreContext = True
+ ... contentProviders = ContentProviders()
+ ... contentProviders['longHelp'] = ExtendedHelp
+ ... contentProviders['longHelp'].position = 1
+
+Let's instantiate content and form instances::
+
+ >>> person = Person()
+ >>> personForm = PersonForm(person, request)
+
+Once the widget manager has been updated, it holds the content provider::
+
+ >>> from z3c.form.contentprovider import FieldWidgetsAndProviders
+ >>> manager = FieldWidgetsAndProviders(personForm, request, person)
+ >>> manager.ignoreContext = True
+ >>> manager.update()
+ >>> widgets = manager._data
+ >>> ids = widgets.keys()
+ >>> ids.sort()
+ >>> ids
+ ['fullname', 'id', 'longHelp']
+ >>> widgets['longHelp']
+ <ExtendedHelp object at ...>
+ >>> widgets['id']
+ <TextWidget 'form.widgets.id'>
+ >>> widgets['fullname']
+ <TextWidget 'form.widgets.fullname'>
+ >>> manager.get('longHelp').render()
+ '<div class="ex-help">Help about person james</div>'
+
+Content provider lookup
+~~~~~~~~~~~~~~~~~~~~~~~
+
+Forms can also refer by name to content providers.
+
+Let's register a content provider by name as usual::
+
+ >>> from zope.component import provideAdapter
+ >>> from zope.contentprovider.interfaces import IContentProvider
+ >>> from z3c.form.interfaces import IFormLayer
+ >>> provideAdapter(ExtendedHelp,
+ ... (zope.interface.Interface,
+ ... IFormLayer,
+ ... zope.interface.Interface),
+ ... provides=IContentProvider, name='longHelp')
+
+Let the form refer to it::
+
+ >>> class LookupPersonForm(form.Form):
+ ... implements(IFieldsAndContentProvidersForm)
+ ... prefix = 'form.'
+ ... fields = field.Fields(IPerson)
+ ... ignoreContext = True
+ ... contentProviders = ContentProviders(['longHelp'])
+ ... contentProviders['longHelp'].position = 2
+
+ >>> lookupForm = LookupPersonForm(person, request)
+
+After update, the widget manager refers to the content provider::
+
+ >>> from z3c.form.contentprovider import FieldWidgetsAndProviders
+ >>> manager = FieldWidgetsAndProviders(lookupForm, request, person)
+ >>> manager.ignoreContext = True
+ >>> manager.update()
+ >>> widgets = manager._data
+ >>> ids = widgets.keys()
+ >>> ids.sort()
+ >>> ids
+ ['fullname', 'id', 'longHelp']
+ >>> widgets['longHelp']
+ <ExtendedHelp object at ...>
+ >>> widgets['id']
+ <TextWidget 'form.widgets.id'>
+ >>> widgets['fullname']
+ <TextWidget 'form.widgets.fullname'>
+ >>> manager.get('longHelp').render()
+ '<div class="ex-help">Help about person james</div>'
+
+Providers position
+~~~~~~~~~~~~~~~~~~
+
+Until here, we have defined position for content providers without explaining
+how it is used.
+
+A position needs to be defined for each provider. Let's forget to define a
+position::
+
+ >>> class UndefinedPositionForm(form.Form):
+ ... implements(IFieldsAndContentProvidersForm)
+ ... prefix = 'form.'
+ ... fields = field.Fields(IPerson)
+ ... ignoreContext = True
+ ... contentProviders = ContentProviders(['longHelp'])
+
+ >>> form = UndefinedPositionForm(person, request)
+ >>> manager = FieldWidgetsAndProviders(form, request, person)
+ >>> manager.ignoreContext = True
+
+When updating the widget manager, we get an exception::
+
+ >>> manager.update()
+ Traceback (most recent call last):
+ ...
+ ValueError: Position of the following content provider should be an integer: 'longHelp'.
+
+Let's check positioning of content providers::
+
+ >>> LookupPersonForm.contentProviders['longHelp'].position = 0
+ >>> manager = FieldWidgetsAndProviders(lookupForm, request, person)
+ >>> manager.ignoreContext = True
+ >>> manager.update()
+ >>> manager.values()
+ [<ExtendedHelp object at ...>, <TextWidget 'form.widgets.id'>, <TextWidget 'form.widgets.fullname'>]
+
+ >>> LookupPersonForm.contentProviders['longHelp'].position = 1
+ >>> manager = FieldWidgetsAndProviders(lookupForm, request, person)
+ >>> manager.ignoreContext = True
+ >>> manager.update()
+ >>> manager.values()
+ [<TextWidget 'form.widgets.id'>, <ExtendedHelp object at ...>, <TextWidget 'form.widgets.fullname'>]
+
+ >>> LookupPersonForm.contentProviders['longHelp'].position = 2
+ >>> manager = FieldWidgetsAndProviders(lookupForm, request, person)
+ >>> manager.ignoreContext = True
+ >>> manager.update()
+ >>> manager.values()
+ [<TextWidget 'form.widgets.id'>, <TextWidget 'form.widgets.fullname'>, <ExtendedHelp object at ...>]
+
+Using value larger than sequence length implies end of sequence::
+
+ >>> LookupPersonForm.contentProviders['longHelp'].position = 3
+ >>> manager = FieldWidgetsAndProviders(lookupForm, request, person)
+ >>> manager.ignoreContext = True
+ >>> manager.update()
+ >>> manager.values()
+ [<TextWidget 'form.widgets.id'>, <TextWidget 'form.widgets.fullname'>, <ExtendedHelp object at ...>]
+
+A negative value is interpreted same as ``insert`` method of Python lists::
+
+ >>> LookupPersonForm.contentProviders['longHelp'].position = -1
+ >>> manager = FieldWidgetsAndProviders(lookupForm, request, person)
+ >>> manager.ignoreContext = True
+ >>> manager.update()
+ >>> manager.values()
+ [<TextWidget 'form.widgets.id'>, <ExtendedHelp object at ...>, <TextWidget 'form.widgets.fullname'>]
+
+Rendering the form
+------------------
+
+Once the form has been updated, it can be rendered.
+
+Since we have not assigned a template yet, we have to do it now.
+We have a small template as part of this example::
+
+ >>> import os
+ >>> from z3c.form import ptcompat as viewpagetemplatefile
+ >>> from z3c.form import tests
+ >>> def personTemplate(form):
+ ... form.template = viewpagetemplatefile.bind_template(
+ ... viewpagetemplatefile.ViewPageTemplateFile(
+ ... 'simple_edit_with_providers.pt',
+ ... os.path.dirname(tests.__file__)), form)
+ >>> personTemplate(personForm)
+
+To enable form updating, all widget adapters must be registered::
+
+ >>> from z3c.form.testing import setupFormDefaults
+ >>> setupFormDefaults()
+
+``FieldWidgetsAndProviders`` is registered as widget manager for
+``IFieldsAndContentProvidersForm``::
+
+ >>> personForm.update()
+ >>> personForm.widgets
+ <z3c.form.contentprovider.FieldWidgetsAndProviders object at ...>
+
+Let's render the form::
+
+ >>> print personForm.render()
+ <!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">
+ <body>
+ <form action=".">
+ <div class="row">
+ <label for="form-widgets-id">ID</label>
+ <input id="form-widgets-id" name="form.widgets.id"
+ class="text-widget required textline-field"
+ value="" type="text" />
+ </div>
+ <div class="row">
+ <div class="ex-help">Help about person james</div>
+ </div>
+ <div class="row">
+ <label for="form-widgets-fullname">FullName</label>
+ <input id="form-widgets-fullname"
+ name="form.widgets.fullname"
+ class="text-widget required textline-field"
+ value="" type="text" />
+ </div>
+ </form>
+ </body>
+ </html>
Modified: z3c.form/trunk/src/z3c/form/index.txt
===================================================================
--- z3c.form/trunk/src/z3c/form/index.txt 2010-07-01 10:47:15 UTC (rev 114045)
+++ z3c.form/trunk/src/z3c/form/index.txt 2010-07-01 12:00:21 UTC (rev 114046)
@@ -15,6 +15,7 @@
zcml
validator
widget
+ contentprovider
action
datamanager
converter
Modified: z3c.form/trunk/src/z3c/form/interfaces.py
===================================================================
--- z3c.form/trunk/src/z3c/form/interfaces.py 2010-07-01 10:47:15 UTC (rev 114045)
+++ z3c.form/trunk/src/z3c/form/interfaces.py 2010-07-01 12:00:21 UTC (rev 114046)
@@ -228,6 +228,11 @@
specification.
"""
+class IContentProviders(IManager):
+ """
+ A content provider manager
+ """
+
# ----[ Data Managers ]------------------------------------------------------
class IDataManager(zope.interface.Interface):
@@ -1007,7 +1012,15 @@
'the form.'),
schema=IFields)
+class IFieldsAndContentProvidersForm(IForm):
+ """A form that is based upon defined fields and content providers"""
+ contentProviders = zope.schema.Object(
+ title=_('Content providers'),
+ description=_('A manager describing the content providers to be used for '
+ 'the form.'),
+ schema=IContentProviders)
+
class IButtonForm(IForm):
"""A form that is based upon defined buttons."""
Modified: z3c.form/trunk/src/z3c/form/testing.py
===================================================================
--- z3c.form/trunk/src/z3c/form/testing.py 2010-07-01 10:47:15 UTC (rev 114045)
+++ z3c.form/trunk/src/z3c/form/testing.py 2010-07-01 12:00:21 UTC (rev 114046)
@@ -34,8 +34,8 @@
from z3c.form import browser, button, converter, datamanager, error, field
from z3c.form import form, interfaces, term, validator, widget
+from z3c.form import contentprovider
from z3c.form.browser import radio, select, text, textarea
-from z3c.form.browser import file as fileWidget
from z3c.form.ptcompat import AVAILABLE
@@ -205,6 +205,9 @@
zope.component.provideAdapter(datamanager.AttributeField)
# Adapter to use form.fields to generate widgets
zope.component.provideAdapter(field.FieldWidgets)
+ # Adapter that uses form.fields to generate widgets
+ # AND interlace content providers
+ zope.component.provideAdapter(contentprovider.FieldWidgetsAndProviders)
# Adapters to lookup the widget for a field
# Text Field Widget
zope.component.provideAdapter(
Copied: z3c.form/trunk/src/z3c/form/tests/simple_edit_with_providers.pt (from rev 114045, z3c.form/branches/fieldsandcontentproviders/src/z3c/form/tests/simple_edit_with_providers.pt)
===================================================================
--- z3c.form/trunk/src/z3c/form/tests/simple_edit_with_providers.pt (rev 0)
+++ z3c.form/trunk/src/z3c/form/tests/simple_edit_with_providers.pt 2010-07-01 12:00:21 UTC (rev 114046)
@@ -0,0 +1,42 @@
+<!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:tal="http://xml.zope.org/namespaces/tal">
+ <body>
+ <i tal:condition="view/status" tal:content="view/status" />
+ <ul tal:condition="view/widgets/errors">
+ <li tal:repeat="error view/widgets/errors">
+ <tal:block condition="error/widget">
+ <tal:block replace="error/widget/label" />:
+ </tal:block>
+ <tal:block replace="structure error/render" />
+ </li>
+ </ul>
+ <form action=".">
+ <tal:snippets repeat="snippet view/widgets/values">
+
+ <div class="row" tal:define="is_widget snippet/id | nothing">
+
+ <tal:widget condition="is_widget"
+ define="widget snippet">
+ <b tal:condition="widget/error"
+ tal:content="structure widget/error/render"
+ /><label tal:condition="widget/id"
+ for=""
+ tal:attributes="for widget/id"
+ tal:content="widget/label" />
+ <input type="text" tal:replace="structure widget/render" />
+ </tal:widget>
+
+ <tal:provider condition="not:is_widget"
+ define="contentprovider snippet"
+ replace="structure contentprovider/render" />
+
+ </div>
+
+ </tal:snippets>
+ <div class="action" tal:repeat="action view/actions/values">
+ <input type="submit" tal:replace="structure action/render" />
+ </div>
+ </form>
+ </body>
+</html>
Modified: z3c.form/trunk/src/z3c/form/tests/test_doc.py
===================================================================
--- z3c.form/trunk/src/z3c/form/tests/test_doc.py 2010-07-01 10:47:15 UTC (rev 114045)
+++ z3c.form/trunk/src/z3c/form/tests/test_doc.py 2010-07-01 12:00:21 UTC (rev 114046)
@@ -56,6 +56,12 @@
checker=checker,
),
doctest.DocFileSuite(
+ '../contentprovider.txt',
+ setUp=setUp, tearDown=testing.tearDown,
+ optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS|doctest.REPORT_ONLY_FIRST_FAILURE,
+ checker=checker,
+ ),
+ doctest.DocFileSuite(
'../value.txt',
setUp=placelesssetup.setUp, tearDown=placelesssetup.tearDown,
optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS,
Modified: z3c.form/trunk/src/z3c/form/util.py
===================================================================
--- z3c.form/trunk/src/z3c/form/util.py 2010-07-01 10:47:15 UTC (rev 114045)
+++ z3c.form/trunk/src/z3c/form/util.py 2010-07-01 12:00:21 UTC (rev 114046)
@@ -149,7 +149,14 @@
raise ValueError(value)
self.data.append(value)
+ def insert(self, position, value):
+ if value in self.data:
+ raise ValueError(value)
+ self.data.insert(position, value)
+ #XXX TODO: Inherit from list
+
+
class Manager(object):
"""Non-persistent IManager implementation."""
zope.interface.implements(interfaces.IManager)
@@ -203,6 +210,10 @@
def __contains__(self, name):
return bool(self.get(name))
+ #XXX TODO:
+ # Add __setitem__ that will add key, value at the end of both lists as in PEP0372
+ # Add insertBefore(key)
+ # insertAfter(key)
class SelectionManager(Manager):
"""Non-persisents ISelectionManager implementation."""
More information about the checkins
mailing list