[Checkins] SVN: z3c.form/trunk/ Look up widgets for fields implementing IChoice by querying for an adapter for (field, field.vocabulary, request) instead of just (field, request), so it can be differentiated according to the type of the source used for the field. (Inspired by how zope.formlib handles the same case.)

Wolfgang Schnerring wosc at wosc.de
Thu Feb 12 02:29:55 EST 2009


Log message for revision 96460:
  Look up widgets for fields implementing IChoice by querying for an adapter for (field, field.vocabulary, request) instead of just (field, request), so it can be differentiated according to the type of the source used for the field. (Inspired by how zope.formlib handles the same case.)
  --This line, and those below, will
    be ignored--
  
  M    CHANGES.txt
  M    src/z3c/form/browser/select.zcml
  M    src/z3c/form/browser/tests.py
  M    src/z3c/form/browser/select.py
  A    src/z3c/form/browser/select-source.txt
  M    src/z3c/form/testing.py
  

Changed:
  U   z3c.form/trunk/CHANGES.txt
  A   z3c.form/trunk/src/z3c/form/browser/select-source.txt
  U   z3c.form/trunk/src/z3c/form/browser/select.py
  U   z3c.form/trunk/src/z3c/form/browser/select.zcml
  U   z3c.form/trunk/src/z3c/form/browser/tests.py
  U   z3c.form/trunk/src/z3c/form/testing.py

-=-
Modified: z3c.form/trunk/CHANGES.txt
===================================================================
--- z3c.form/trunk/CHANGES.txt	2009-02-12 05:25:08 UTC (rev 96459)
+++ z3c.form/trunk/CHANGES.txt	2009-02-12 07:29:55 UTC (rev 96460)
@@ -107,6 +107,9 @@
 - Bug: SingleCheckBoxFieldWidget doesn't repeat the label twice (once in
   <div class="label">, and once in the <label> next to the checkbox).
 
+- Feature: The widget for fields implementing IChoice is now looked up by
+  querying for an adapter for (field, field.vocabulary, request) so it can be
+  differentiated according to the type of the source used for the field.
 
 Version 1.9.0 (2008-08-26)
 --------------------------

Added: z3c.form/trunk/src/z3c/form/browser/select-source.txt
===================================================================
--- z3c.form/trunk/src/z3c/form/browser/select-source.txt	                        (rev 0)
+++ z3c.form/trunk/src/z3c/form/browser/select-source.txt	2009-02-12 07:29:55 UTC (rev 96460)
@@ -0,0 +1,72 @@
+=====================================
+Customizing widget lookup for IChoice
+=====================================
+
+Widgets for fields implementing IChoice are looked up not only according to the
+field, but also according to the source used by the field.
+
+  >>> import z3c.form.testing
+  >>> import zope.interface
+  >>> import zope.component
+  >>> from z3c.form import interfaces
+  >>> from z3c.form.testing import TestRequest
+
+  >>> z3c.form.testing.setupFormDefaults()
+  >>> def setupWidget(field):
+  ...     request = TestRequest()
+  ...     widget = zope.component.getMultiAdapter((field, request),
+  ...         interfaces.IFieldWidget)
+  ...     widget.id = 'foo'
+  ...     widget.name = 'bar'
+  ...     return widget
+
+We define a sample field and source:
+
+  >>> from zope.schema import vocabulary
+  >>> terms = [vocabulary.SimpleTerm(*value) for value in
+  ...          [(True, 'yes', 'Yes'), (False, 'no', 'No')]]
+  >>> vocabulary = vocabulary.SimpleVocabulary(terms)
+  >>> field = zope.schema.Choice(default=True, vocabulary=vocabulary)
+
+The default widget is the SelectWidget:
+
+  >>> widget = setupWidget(field)
+  >>> type(widget)
+  <class 'z3c.form.browser.select.SelectWidget'>
+
+But now we define a marker interface and have our source provide it:
+
+  >>> from z3c.form.widget import FieldWidget
+  >>> class ISampleSource(zope.interface.Interface):
+  ...     pass
+  >>> zope.interface.alsoProvides(vocabulary, ISampleSource)
+
+We can then create and register a special widget for fields using sources with
+the ISampleSource marker:
+
+  >>> class SampleSelectWidget(z3c.form.browser.select.SelectWidget):
+  ...     pass
+  >>> def SampleSelectFieldWidget(field, source, request):
+  ...     return FieldWidget(field, SampleSelectWidget(request))
+  >>> zope.component.provideAdapter(
+  ...   SampleSelectFieldWidget,
+  ...   (zope.schema.interfaces.IChoice, ISampleSource, interfaces.IFormLayer),
+  ...   interfaces.IFieldWidget)
+
+If we now look up the widget for the field, we get the specialized widget:
+
+  >>> widget = setupWidget(field)
+  >>> type(widget)
+  <class 'SampleSelectWidget'>
+
+Backwards compatibility
+-----------------------
+
+To maintain backwards compatibility, SelectFieldWidget() still can be called
+without passing a source:
+
+  >>> import z3c.form.browser.select
+  >>> request = TestRequest()
+  >>> widget = z3c.form.browser.select.SelectFieldWidget(field, request)
+  >>> type(widget)
+  <class 'z3c.form.browser.select.SelectWidget'>

Modified: z3c.form/trunk/src/z3c/form/browser/select.py
===================================================================
--- z3c.form/trunk/src/z3c/form/browser/select.py	2009-02-12 05:25:08 UTC (rev 96459)
+++ z3c.form/trunk/src/z3c/form/browser/select.py	2009-02-12 07:29:55 UTC (rev 96460)
@@ -75,9 +75,25 @@
 
 @zope.component.adapter(zope.schema.interfaces.IChoice, interfaces.IFormLayer)
 @zope.interface.implementer(interfaces.IFieldWidget)
-def SelectFieldWidget(field, request):
+def ChoiceWidgetDispatcher(field, request):
+    """Dispatch widget for IChoice based also on its source."""
+    return zope.component.getMultiAdapter((field, field.vocabulary, request),
+                                          interfaces.IFieldWidget)
+
+
+# IBaseVocabulary can change to ISource once vocabularies are deprecated
+ at zope.component.adapter(zope.schema.interfaces.IChoice,
+                        zope.schema.interfaces.IBaseVocabulary,
+                        interfaces.IFormLayer)
+ at zope.interface.implementer(interfaces.IFieldWidget)
+def SelectFieldWidget(field, source, request=None):
     """IFieldWidget factory for SelectWidget."""
-    return FieldWidget(field, SelectWidget(request))
+    # BBB: emulate our pre-2.0 signature (field, request)
+    if request is None:
+        real_request = source
+    else:
+        real_request = request
+    return FieldWidget(field, SelectWidget(real_request))
 
 
 @zope.component.adapter(
@@ -98,4 +114,4 @@
 @zope.interface.implementer(interfaces.IFieldWidget)
 def CollectionChoiceSelectFieldWidget(field, value_type, request):
     """IFieldWidget factory for SelectWidget."""
-    return SelectFieldWidget(field, request)
+    return SelectFieldWidget(field, None, request)

Modified: z3c.form/trunk/src/z3c/form/browser/select.zcml
===================================================================
--- z3c.form/trunk/src/z3c/form/browser/select.zcml	2009-02-12 05:25:08 UTC (rev 96459)
+++ z3c.form/trunk/src/z3c/form/browser/select.zcml	2009-02-12 07:29:55 UTC (rev 96460)
@@ -11,6 +11,10 @@
   </class>
 
   <adapter
+      factory=".select.ChoiceWidgetDispatcher"
+      />
+
+  <adapter
       factory=".select.SelectFieldWidget"
       />
 

Modified: z3c.form/trunk/src/z3c/form/browser/tests.py
===================================================================
--- z3c.form/trunk/src/z3c/form/browser/tests.py	2009-02-12 05:25:08 UTC (rev 96459)
+++ z3c.form/trunk/src/z3c/form/browser/tests.py	2009-02-12 07:29:55 UTC (rev 96460)
@@ -71,6 +71,11 @@
                      optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS,
                      checker=checker,
                      ),
+        DocFileSuite('select-source.txt',
+                     setUp=setUp, tearDown=testing.tearDown,
+                     optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS,
+                     checker=checker,
+                     ),
         DocFileSuite('submit.txt',
                      setUp=setUp, tearDown=testing.tearDown,
                      optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS,

Modified: z3c.form/trunk/src/z3c/form/testing.py
===================================================================
--- z3c.form/trunk/src/z3c/form/testing.py	2009-02-12 05:25:08 UTC (rev 96459)
+++ z3c.form/trunk/src/z3c/form/testing.py	2009-02-12 07:29:55 UTC (rev 96460)
@@ -281,6 +281,7 @@
         IPageTemplate, name=interfaces.DISPLAY_MODE)
 
     # Select Widget
+    zope.component.provideAdapter(select.ChoiceWidgetDispatcher)
     zope.component.provideAdapter(select.SelectFieldWidget)
     zope.component.provideAdapter(
         widget.WidgetTemplateFactory(getPath('select_input.pt'), 'text/html'),



More information about the Checkins mailing list