[Zope3-checkins] SVN: Zope3/branches/testbrowser-integration/src/zope/testbrowser/ - Add tests for radio buttons

Gary Poster gary at zope.com
Mon Aug 8 15:57:57 EDT 2005


Log message for revision 37795:
  - Add tests for radio buttons
  
  - Add ability to get and set select fields by display
  
  - Divide up interfaces so they don't lie about options
  
  - Change getControl to allow a search (which actually matches part of the
    doctest that was wrong before).
  
  - Add labels to controls.html test page so you can see where we want to go with
    the radio and checkbox displayOptions and displayValue
  
  

Changed:
  U   Zope3/branches/testbrowser-integration/src/zope/testbrowser/README.txt
  U   Zope3/branches/testbrowser-integration/src/zope/testbrowser/browser.py
  U   Zope3/branches/testbrowser-integration/src/zope/testbrowser/ftests/controls.html
  U   Zope3/branches/testbrowser-integration/src/zope/testbrowser/interfaces.py

-=-
Modified: Zope3/branches/testbrowser-integration/src/zope/testbrowser/README.txt
===================================================================
--- Zope3/branches/testbrowser-integration/src/zope/testbrowser/README.txt	2005-08-08 19:35:55 UTC (rev 37794)
+++ Zope3/branches/testbrowser-integration/src/zope/testbrowser/README.txt	2005-08-08 19:57:57 UTC (rev 37795)
@@ -9,12 +9,21 @@
     >>> browser = Browser()
     >>> browser.addHeader('Authorization', 'Basic mgr:mgrpw')
 
+It can send arbitrary headers; this is helpful for setting the language value,
+so that your tests format values the way you expect in your tests, if you rely
+on zope.i18n locale-based formatting or a similar approach.
+
+    >>> browser.addHeader('Accept-Language', 'en-US')
+
 The browser can `open` web pages:
 
     >>> browser.open('http://localhost/@@/testbrowser/simple.html')
     >>> browser.url
     'http://localhost/@@/testbrowser/simple.html'
 
+Once you have opened a web page initially, best practice for writing
+testbrowser doctests suggests using 'click' to navigate further (as discussed
+below), except in unusual circumstances.
 
 Page Contents
 -------------
@@ -281,16 +290,57 @@
 ~~~~~~~~~~~~~~~
 
 But the value of a control is not always everything that there is to know or
-that is interesting.  In those cases, one can access the control object:
+that is interesting.  In those cases, one can access the control object.  The
+string passed into the function will be matched against the value, id and name
+of the control, just as when using the control mapping.
 
+    >>> ctrl = browser.getControl('text-value')
+    >>> ctrl
+    <Control name='text-value' type='text'>
+    >>> ctrl = browser.getControl('text-value-id')
+    >>> ctrl
+    <Control name='text-value' type='text'>
+    >>> ctrl = browser.getControl('More Text')
+    >>> ctrl
+    <Control name='text-value' type='text'>
+
+If you want to search explicitly by name, value, and/or id, you may also use
+keyword arguments 'name', 'text', and 'id'.
+
     >>> ctrl = browser.getControl(name='text-value')
     >>> ctrl
     <Control name='text-value' type='text'>
+    >>> ctrl = browser.getControl(id='text-value-id')
+    >>> ctrl
+    <Control name='text-value' type='text'>
+    >>> ctrl = browser.getControl(text='More Text')
+    >>> ctrl
+    <Control name='text-value' type='text'>
+    >>> ctrl = browser.getControl(
+    ...     id='text-value-id', name='text-value', text='More Text')
+    >>> ctrl
+    <Control name='text-value' type='text'>
+    >>> ctrl = browser.getControl(
+    ...     id='does not exist', name='does not exist', text='More Text')
+    >>> ctrl
+    <Control name='text-value' type='text'>
 
-The string passed into the function will be matched against the value, id and
-name of the control, just as when using the controll mapping.  The control has
-several useful attributes:
+You may not use both the default argument and any of the other named arguments.
 
+    >>> ctrl = browser.getControl('text-value', name='text-value')
+    Traceback (most recent call last):
+    ...    
+    ValueError: ...
+
+Controls provide IControl.
+
+    >>> from zope.interface.verify import verifyObject
+    >>> from zope.testbrowser import interfaces
+    >>> verifyObject(interfaces.IControl, ctrl)
+    True
+
+They have several useful attributes:
+
   - the name as which the control is known to the form:
 
     >>> ctrl.name
@@ -312,21 +362,52 @@
     >>> ctrl.disabled
     False
 
-  - there is a flag to tell us whether the control can have multiple values:
+  - and there is a flag to tell us whether the control can have multiple
+    values:
 
     >>> ctrl.multiple
     False
 
-  - and finally there is an attribute that provides all available value
-    options.  This is of course not sensible for a text input control and thus
-    not available:
+Additionally, controllers for select, radio, and checkbox provide IListControl.
+These fields have three other attributes (at least in theory--see below):
 
+    >>> ctrl = browser.getControl('multi-select-value')
+    >>> ctrl
+    <ListControl name='multi-select-value' type='select'>
+    >>> ctrl.disabled
+    False
+    >>> ctrl.multiple
+    True
+    >>> verifyObject(interfaces.IListControl, ctrl)
+    True
+
+  - 'options' lists all available value options.
+
     >>> ctrl.options
-    Traceback (most recent call last):
-    ...    
-    AttributeError: options
+    ['1', '2', '3']
 
+  - 'displayOptions' lists all available options by value.
 
+    >>> ctrl.displayOptions
+    ['One', 'Two', 'Three']
+
+  - 'displayValue' lets you get and set the displayed values of the control
+    of the select box, rather than the actual values.
+
+    >>> ctrl.value
+    []
+    >>> ctrl.displayValue
+    []
+    >>> ctrl.displayValue = ['One', 'Two']
+    >>> ctrl.displayValue
+    ['One', 'Two']
+    >>> ctrl.value
+    ['1', '2']
+
+Unfortunately, radio fields and checkbox fields do not yet implement
+displayOptions and displayValue, although we hope to support them eventually
+(i.e., basing off of label tags).
+
 Various Controls
 ~~~~~~~~~~~~~~~~
 
@@ -338,9 +419,11 @@
 
   - Password Control
 
-    >>> ctrl = browser.getControl(name='password-value')
+    >>> ctrl = browser.getControl('password-value')
     >>> ctrl
     <Control name='password-value' type='password'>
+    >>> verifyObject(interfaces.IControl, ctrl)
+    True
     >>> ctrl.value
     'pass now'
     >>> ctrl.value = 'Password'
@@ -348,16 +431,14 @@
     False
     >>> ctrl.multiple
     False
-    >>> ctrl.options
-    Traceback (most recent call last):
-    ...    
-    AttributeError: options
 
   - Hidden Control
 
-    >>> ctrl = browser.getControl(name='hidden-value')
+    >>> ctrl = browser.getControl('hidden-value')
     >>> ctrl
     <Control name='hidden-value' type='hidden'>
+    >>> verifyObject(interfaces.IControl, ctrl)
+    True
     >>> ctrl.value
     'Hidden'
     >>> ctrl.value = 'More Hidden'
@@ -365,16 +446,14 @@
     False
     >>> ctrl.multiple
     False
-    >>> ctrl.options
-    Traceback (most recent call last):
-    ...    
-    AttributeError: options
     
   - Text Area Control
 
-    >>> ctrl = browser.getControl(name='textarea-value')
+    >>> ctrl = browser.getControl('textarea-value')
     >>> ctrl
     <Control name='textarea-value' type='textarea'>
+    >>> verifyObject(interfaces.IControl, ctrl)
+    True
     >>> ctrl.value
     '\n        Text inside\n        area!\n      '
     >>> ctrl.value = 'A lot of\n text.'
@@ -382,16 +461,14 @@
     False
     >>> ctrl.multiple
     False
-    >>> ctrl.options
-    Traceback (most recent call last):
-    ...    
-    AttributeError: options
 
   - File Control
 
-    >>> ctrl = browser.getControl(name='file-value')
+    >>> ctrl = browser.getControl('file-value')
     >>> ctrl
     <Control name='file-value' type='file'>
+    >>> verifyObject(interfaces.IControl, ctrl)
+    True
     >>> ctrl.value
     >>> import cStringIO
     >>> ctrl.value = cStringIO.StringIO('File contents')
@@ -399,16 +476,14 @@
     False
     >>> ctrl.multiple
     False
-    >>> ctrl.options
-    Traceback (most recent call last):
-    ...    
-    AttributeError: options
 
   - Selection Control (Single-Valued)
 
-    >>> ctrl = browser.getControl(name='single-select-value')
+    >>> ctrl = browser.getControl('single-select-value')
     >>> ctrl
-    <Control name='single-select-value' type='select'>
+    <ListControl name='single-select-value' type='select'>
+    >>> verifyObject(interfaces.IListControl, ctrl)
+    True
     >>> ctrl.value
     ['1']
     >>> ctrl.value = ['2']
@@ -418,27 +493,29 @@
     False
     >>> ctrl.options
     ['1', '2', '3']
+    >>> ctrl.displayOptions
+    ['One', 'Two', 'Three']
+    >>> ctrl.displayValue
+    ['Two']
+    >>> ctrl.displayValue = ['Three']
+    >>> ctrl.displayValue
+    ['Three']
+    >>> ctrl.value
+    ['3']
 
   - Selection Control (Multi-Valued)
 
-    >>> ctrl = browser.getControl(name='multi-select-value')
-    >>> ctrl
-    <Control name='multi-select-value' type='select'>
-    >>> ctrl.value
-    []
-    >>> ctrl.value = ['1', '2']
-    >>> ctrl.disabled
-    False
-    >>> ctrl.multiple
-    True
-    >>> ctrl.options
-    ['1', '2', '3']
+    This was already demonstrated in the introduction to control objects above.
 
   - Checkbox Control (Single-Valued; Unvalued)
 
-    >>> ctrl = browser.getControl(name='single-unvalued-checkbox-value')
+    >>> ctrl = browser.getControl('single-unvalued-checkbox-value')
     >>> ctrl
-    <Control name='single-unvalued-checkbox-value' type='checkbox'>
+    <ListControl name='single-unvalued-checkbox-value' type='checkbox'>
+    >>> interfaces.IListControl.providedBy(ctrl)
+    True
+    >>> verifyObject(interfaces.IControl, ctrl) # IListControl when implemented
+    True
     >>> ctrl.value
     True
     >>> ctrl.value = False
@@ -448,12 +525,28 @@
     True
     >>> ctrl.options
     [True]
+    >>> ctrl.displayOptions # we wish this would work!
+    Traceback (most recent call last):
+    ...    
+    NotImplementedError: ...
+    >>> ctrl.displayValue # we wish this would work!
+    Traceback (most recent call last):
+    ...    
+    NotImplementedError: ...
+    >>> ctrl.displayValue = ['One'] # we wish this would work!
+    Traceback (most recent call last):
+    ...    
+    NotImplementedError: ...
 
   - Checkbox Control (Single-Valued, Valued)
 
-    >>> ctrl = browser.getControl(name='single-valued-checkbox-value')
+    >>> ctrl = browser.getControl('single-valued-checkbox-value')
     >>> ctrl
-    <Control name='single-valued-checkbox-value' type='checkbox'>
+    <ListControl name='single-valued-checkbox-value' type='checkbox'>
+    >>> interfaces.IListControl.providedBy(ctrl)
+    True
+    >>> verifyObject(interfaces.IControl, ctrl) # IListControl when implemented
+    True
     >>> ctrl.value
     ['1']
     >>> ctrl.value = []
@@ -463,12 +556,28 @@
     True
     >>> ctrl.options
     ['1']
+    >>> ctrl.displayOptions # we wish this would work!
+    Traceback (most recent call last):
+    ...    
+    NotImplementedError: ...
+    >>> ctrl.displayValue # we wish this would work!
+    Traceback (most recent call last):
+    ...    
+    NotImplementedError: ...
+    >>> ctrl.displayValue = ['One'] # we wish this would work!
+    Traceback (most recent call last):
+    ...    
+    NotImplementedError: ...
 
   - Checkbox Control (Multi-Valued)
 
-    >>> ctrl = browser.getControl(name='multi-checkbox-value')
+    >>> ctrl = browser.getControl('multi-checkbox-value')
     >>> ctrl
-    <Control name='multi-checkbox-value' type='checkbox'>
+    <ListControl name='multi-checkbox-value' type='checkbox'>
+    >>> interfaces.IListControl.providedBy(ctrl)
+    True
+    >>> verifyObject(interfaces.IControl, ctrl) # IListControl when implemented
+    True
     >>> ctrl.value
     ['1', '3']
     >>> ctrl.value = ['1', '2']
@@ -478,38 +587,79 @@
     True
     >>> ctrl.options
     ['1', '2', '3']
+    >>> ctrl.displayOptions # we wish this would work!
+    Traceback (most recent call last):
+    ...    
+    NotImplementedError: ...
+    >>> ctrl.displayValue # we wish this would work!
+    Traceback (most recent call last):
+    ...    
+    NotImplementedError: ...
+    >>> ctrl.displayValue = ['One'] # we wish this would work!
+    Traceback (most recent call last):
+    ...    
+    NotImplementedError: ...
 
-  - Image Control
+  - Radio Control
 
-    >>> ctrl = browser.getControl(name='image-value')
+    >>> ctrl = browser.getControl('radio-value')
     >>> ctrl
-    <Control name='image-value' type='image'>
+    <ListControl name='radio-value' type='radio'>
+    >>> interfaces.IListControl.providedBy(ctrl)
+    True
+    >>> verifyObject(interfaces.IControl, ctrl) # IListControl when implemented
+    True
     >>> ctrl.value
-    ''
+    ['2']
+    >>> ctrl.value = []
+    >>> ctrl.value
+    []
     >>> ctrl.disabled
     False
     >>> ctrl.multiple
     False
     >>> ctrl.options
+    ['1', '2', '3']
+    >>> ctrl.displayOptions # we wish this would work!
     Traceback (most recent call last):
     ...    
-    AttributeError: options
+    NotImplementedError: ...
+    >>> ctrl.displayValue # we wish this would work!
+    Traceback (most recent call last):
+    ...    
+    NotImplementedError: ...
+    >>> ctrl.displayValue = ['One'] # we wish this would work!
+    Traceback (most recent call last):
+    ...    
+    NotImplementedError: ...
 
+  - Image Control
+
+    >>> ctrl = browser.getControl('image-value')
+    >>> ctrl
+    <Control name='image-value' type='image'>
+    >>> verifyObject(interfaces.IControl, ctrl)
+    True
+    >>> ctrl.value
+    ''
+    >>> ctrl.disabled
+    False
+    >>> ctrl.multiple
+    False
+
   - Submit Control
 
-    >>> ctrl = browser.getControl(name='submit-value')
+    >>> ctrl = browser.getControl('submit-value')
     >>> ctrl
     <Control name='submit-value' type='submit'>
+    >>> verifyObject(interfaces.IControl, ctrl)
+    True
     >>> ctrl.value
     'Submit'
     >>> ctrl.disabled
     False
     >>> ctrl.multiple
     False
-    >>> ctrl.options
-    Traceback (most recent call last):
-    ...    
-    AttributeError: options
 
 
 Using Submitting Controls
@@ -523,7 +673,7 @@
     <html>
     ...
     <em>Other Text</em>
-    <input type="text" name="text-value" value="Some Text" />
+    <input type="text" name="text-value" id="text-value-id" value="Some Text" />
     ...
     <em>Submit</em>
     <input type="submit" name="submit-value" value="Submit" />
@@ -539,7 +689,7 @@
     <html>
     ...
     <em>Other Text</em>
-    <input type="text" name="text-value" value="Some Text" />
+    <input type="text" name="text-value" id="text-value-id" value="Some Text" />
     ...
     <em>1</em>
     <em>1</em>
@@ -609,7 +759,7 @@
 Besides those attributes, you have also a couple of methods.  Like for the
 browser, you can get control objects
 
-    >>> form.getControl(name='text-value')
+    >>> form.getControl('text-value')
     <Control name='text-value' type='text'>
 
 and submit the form:

Modified: Zope3/branches/testbrowser-integration/src/zope/testbrowser/browser.py
===================================================================
--- Zope3/branches/testbrowser-integration/src/zope/testbrowser/browser.py	2005-08-08 19:35:55 UTC (rev 37794)
+++ Zope3/branches/testbrowser-integration/src/zope/testbrowser/browser.py	2005-08-08 19:57:57 UTC (rev 37795)
@@ -155,12 +155,20 @@
                 text_regex=text_regex, url_regex=url_regex)
         self._changed()
 
-    def getControl(self, text=None, id=None, name=None):
+    def getControl(self, search=None, text=None, id=None, name=None):
         """See zope.testbrowser.interfaces.IBrowser"""
+        if search is not None:
+            if text is not None or id is not None or name is not None:
+                raise ValueError(
+                    'May not pass both search value and any of '
+                    'text, id, or name')
+            text = id = name = search
         form, control = self._findControl(text, id, name)
         if control is None:
-            raise ValueError('could not locate control: ' + text)
-        return Control(control)
+            raise ValueError(
+                'could not locate control: text %r, id %r, name %r' %
+                (text, id, name))
+        return controlFactory(control)
 
     def _findControl(self, text, id, name, type=None, form=None):
         for control_form, control in self._controls:
@@ -253,21 +261,50 @@
     def clear(self):
         self.mech_control.clear()
 
+    def __repr__(self):
+        return "<%s name=%r type=%r>" % (
+            self.__class__.__name__, self.name, self.type)
+
+class ListControl(Control):
+    zope.interface.implements(interfaces.IListControl)
+
+    @apply
+    def displayValue():
+        """See zope.testbrowser.interfaces.IListControl"""
+        # not implemented for anything other than select;
+        # would be nice if ClientForm implemented for checkbox and radio.
+        # attribute error for all others.
+
+        def fget(self):
+            return self.mech_control.get_value_by_label()
+
+        def fset(self, value):
+            self.mech_control.set_value_by_label(value)
+
+        return property(fget, fset)
+
     @property
+    def displayOptions(self):
+        """See zope.testbrowser.interfaces.IListControl"""
+        # not implemented for anything other than select;
+        # would be nice if ClientForm implemented for checkbox and radio.
+        # attribute error for all others.
+        return self.mech_control.possible_items(by_label=True)
+
+    @property
     def options(self):
-        """See zope.testbrowser.interfaces.IControl"""
+        """See zope.testbrowser.interfaces.IListControl"""
         if (self.type == 'checkbox'
         and self.mech_control.possible_items() == ['on']):
             return [True]
-        try:
-            return self.mech_control.possible_items()
-        except:
-            raise AttributeError('options')
+        return self.mech_control.possible_items()
 
-    def __repr__(self):
-        return "<Control name=%r type=%r>" %(self.name, self.type)
+def controlFactory(control):
+    if control.type in ('checkbox', 'select', 'radio'):
+        return ListControl(control)
+    else:
+        return Control(control)
 
-
 class FormsMapping(object):
     """All forms on the page of the browser."""
     zope.interface.implements(interfaces.IFormsMapping)
@@ -313,7 +350,7 @@
                                                   form=self.mech_form)
         if control is None:
             raise KeyError(key)
-        return Control(control).value
+        return controlFactory(control).value
 
     def get(self, key, default=None):
         """See zope.interface.common.mapping.IReadMapping"""
@@ -336,7 +373,7 @@
         form, control = self.browser._findControl(key, key, key)
         if control is None:
             raise KeyError(key)
-        Control(control).value = value
+        controlFactory(control).value = value
 
     def update(self, mapping):
         """See zope.testbrowser.interfaces.IControlsMapping"""
@@ -379,10 +416,17 @@
             self.browser._clickSubmit(form, control, coord)
             self.browser._changed()
 
-    def getControl(self, text=None, id=None, name=None):
+
+    def getControl(self, search=None, text=None, id=None, name=None):
         """See zope.testbrowser.interfaces.IForm"""
+        if search is not None:
+            if text is not None or id is not None or name is not None:
+                raise ValueError(
+                    'May not pass both search value and any of '
+                    'text, id, or name')
+            text = id = name = search
         form, control = self.browser._findControl(text, id, name,
                                                   form=self.mech_form)
         if control is None:
             raise ValueError('could not locate control: ' + text)
-        return Control(control)
+        return controlFactory(control)

Modified: Zope3/branches/testbrowser-integration/src/zope/testbrowser/ftests/controls.html
===================================================================
--- Zope3/branches/testbrowser-integration/src/zope/testbrowser/ftests/controls.html	2005-08-08 19:35:55 UTC (rev 37794)
+++ Zope3/branches/testbrowser-integration/src/zope/testbrowser/ftests/controls.html	2005-08-08 19:57:57 UTC (rev 37795)
@@ -5,79 +5,117 @@
 
     <form action="controls.html" method="post">
 
-      <em tal:condition="request/text-value|nothing"
-          tal:content="request/text-value" />
-      <input type="text" name="text-value" value="Some Text" />
+      <div>
+        <em tal:condition="request/text-value|nothing"
+            tal:content="request/text-value"></em>
+        <input type="text" name="text-value" id='text-value-id'
+               value="Some Text" />
+      </div>
 
-      <em tal:condition="request/password-value|nothing"
-          tal:content="request/password-value" />
-      <input type="password" name="password-value" value="Password" />
-      
-      <em tal:condition="request/hidden-value|nothing"
-          tal:content="request/hidden-value" />
-      <input type="hidden" name="hidden-value" value="Hidden" />
+      <div>
+        <em tal:condition="request/password-value|nothing"
+            tal:content="request/password-value"></em>
+        <input type="password" name="password-value" value="Password" />
+      </div>
 
-      <em tal:condition="request/textarea-value|nothing"
-          tal:content="request/textarea-value" />
-      <textarea name="textarea-value">
-        Text inside
-        area!
-      </textarea>
+      <div>
+        <em tal:condition="request/hidden-value|nothing"
+            tal:content="request/hidden-value"></em>
+        <input type="hidden" name="hidden-value" value="Hidden" />
+        (hidden)
+      </div>
 
-      <em tal:condition="request/file-value|nothing"
-          tal:content="request/file-value" />
-      <input type="file" name="file-value" />
+      <div>
+        <em tal:condition="request/textarea-value|nothing"
+            tal:content="request/textarea-value"></em>
+        <textarea name="textarea-value">
+          Text inside
+          area!
+        </textarea>
+      </div>
 
-      <em tal:condition="request/single-select-value|nothing"
-          tal:content="request/single-select-value" />
-      <select name="single-select-value">
-        <option value="1">One</option>
-        <option value="2">Two</option>
-        <option value="3">Three</option>
-      </select>
+      <div>
+        <em tal:condition="request/file-value|nothing"
+            tal:content="request/file-value"></em>
+        <input type="file" name="file-value" />
+      </div>
 
-      <em tal:condition="request/multi-select-value|nothing"
-          tal:content="request/multi-select-value" />
-      <select name="multi-select-value" multiple="multiple">
-        <option value="1">One</option>
-        <option value="2">Two</option>
-        <option value="3">Three</option>
-      </select>
-      
-      <em tal:condition="request/single-unvalued-checkbox-value|nothing"
-          tal:content="request/single-unvalued-checkbox-value" />
-      <input type="checkbox" name="single-unvalued-checkbox-value" 
-             checked="checked" />
+      <div>
+        <em tal:condition="request/single-select-value|nothing"
+            tal:content="request/single-select-value"></em>
+        <select name="single-select-value">
+          <option value="1">One</option>
+          <option value="2">Two</option>
+          <option value="3">Three</option>
+        </select>
+      </div>
 
-      <em tal:condition="request/single-valued-checkbox-value|nothing"
-          tal:content="request/single-valued-checkbox-value" />
-      <input type="checkbox" name="single-valued-checkbox-value" 
-             value="1" checked="checked" />
+      <div>
+        <em tal:condition="request/multi-select-value|nothing"
+            tal:content="request/multi-select-value"></em>
+        <select name="multi-select-value" multiple="multiple">
+          <option value="1">One</option>
+          <option value="2">Two</option>
+          <option value="3">Three</option>
+        </select>
+      </div>
 
-      <em tal:condition="request/multi-checkbox-value|nothing"
-          tal:content="request/multi-checkbox-value" />
-      <input type="checkbox" name="multi-checkbox-value" value="1" 
-             checked="checked" />
-      <input type="checkbox" name="multi-checkbox-value" value="2" />
-      <input type="checkbox" name="multi-checkbox-value" value="3" 
-             checked="checked" />
+      <div>
+        <em tal:condition="request/single-unvalued-checkbox-value|nothing"
+            tal:content="request/single-unvalued-checkbox-value"></em>
+        <input type="checkbox" name="single-unvalued-checkbox-value" 
+               id="single-unvalued-checkbox" checked="checked" />
+        <label for="single-unvalued-checkbox">Single Unvalued</label>
+      </div>
 
-      <em tal:condition="request/radio-value|nothing"
-          tal:content="request/radio-value" />
-      <radio name="radio-value" value="1" />
-      <radio name="radio-value" value="2" selected="selected" />
-      <radio name="radio-value" value="3" />
+      <div>
+        <em tal:condition="request/single-valued-checkbox-value|nothing"
+            tal:content="request/single-valued-checkbox-value"></em>
+        <input type="checkbox" name="single-valued-checkbox-value" 
+               id="single-valued-checkbox" value="1" checked="checked" />
+        <label for="single-valued-checkbox">Single Valued</label>
+      </div>
 
-      <em tal:condition="request/image-value.x|nothing"
-          tal:content="request/image-value.x" />
-      <em tal:condition="request/image-value.y|nothing"
-          tal:content="request/image-value.y" />
-      <input type="image" name="image-value" src="zope3logo.gif" />
+      <div>
+        <em tal:condition="request/multi-checkbox-value|nothing"
+            tal:content="request/multi-checkbox-value"></em>
+        <input type="checkbox" name="multi-checkbox-value" value="1" 
+               id="multi-checkbox-value-1" checked="checked" />
+        <label for="multi-checkbox-value-1">One</label>
+        <input type="checkbox" name="multi-checkbox-value" value="2" 
+               id="multi-checkbox-value-2" />
+        <label for="multi-checkbox-value-2">Two</label>
+        <input type="checkbox" name="multi-checkbox-value" value="3" 
+               id="multi-checkbox-value-3" checked="checked" />
+        <label for="multi-checkbox-value-3">Three</label>
+      </div>
 
-      <em tal:condition="request/submit-value|nothing"
-          tal:content="request/submit-value" />
-      <input type="submit" name="submit-value" value="Submit" />
+      <div>
+        <em tal:condition="request/radio-value|nothing"
+            tal:content="request/radio-value"></em>
+        <input type="radio" name="radio-value" id="radio-value-1" value="1" />
+        <label for="radio-value-1">One</label>
+        <input type="radio" name="radio-value" id="radio-value-2" value="2"
+               checked="checked" />
+        <label for="radio-value-2">Two</label>
+        <input type="radio" name="radio-value" id="radio-value-3" value="3" />
+        <label for="radio-value-3">Three</label>
+      </div>
+
+      <div>
+        <em tal:condition="request/image-value.x|nothing"
+            tal:content="request/image-value.x"></em>
+        <em tal:condition="request/image-value.y|nothing"
+            tal:content="request/image-value.y"></em>
+        <input type="image" name="image-value" src="zope3logo.gif" />
+      </div>
+
+      <div>
+        <em tal:condition="request/submit-value|nothing"
+            tal:content="request/submit-value"></em>
+        <input type="submit" name="submit-value" value="Submit" />
+      </div>
     </form>
 
   </body>
-</html>
\ No newline at end of file
+</html>

Modified: Zope3/branches/testbrowser-integration/src/zope/testbrowser/interfaces.py
===================================================================
--- Zope3/branches/testbrowser-integration/src/zope/testbrowser/interfaces.py	2005-08-08 19:35:55 UTC (rev 37794)
+++ Zope3/branches/testbrowser-integration/src/zope/testbrowser/interfaces.py	2005-08-08 19:57:57 UTC (rev 37795)
@@ -55,11 +55,6 @@
         values=['text', 'password', 'hidden', 'submit', 'checkbox', 'select',
                 'radio', 'image', 'file'],
         required=True)
-
-    options = zope.schema.List(
-        title=u"Options",
-        description=u"A list of possible values for the control.",
-        required=False)
         
     disabled = zope.schema.Bool(
         title=u"Disabled",
@@ -67,14 +62,6 @@
         default=False,
         required=False)
 
-    readonly = zope.schema.Bool(
-        title=u"Readonly",
-        description=u"Describes whether a new value can be assigned to the "
-                    u"control. For example, the hidden input field is "
-                    u"read-only.",
-        default=False,
-        required=False)
-
     multiple = zope.schema.Bool(
         title=u"Multiple",
         description=u"Describes whether this control can hold multiple values.",
@@ -83,8 +70,30 @@
 
     def clear():
         """Clear the value of the control."""
-        
 
+class IListControl(IControl):
+    """A radio button, checkbox, or select control"""
+
+    options = zope.schema.List(
+        title=u"Options",
+        description=u"""\
+        A list of possible values for the control.""",
+        required=True)
+
+    displayOptions = zope.schema.List(
+        # TODO: currently only implemented for select by ClientForm
+        title=u"Options",
+        description=u"""\
+        A list of possible display values for the control.""",
+        required=True)
+
+    displayValue = zope.schema.Field(
+        # TODO: currently only implemented for select by ClientForm
+        title=u"Value",
+        description=u"The value of the control, as rendered by the display",
+        default=None,
+        required=True)
+
 class IFormsMapping(zope.interface.common.mapping.IReadMapping):
     """A mapping of all forms in a page."""
 



More information about the Zope3-Checkins mailing list