[Checkins] SVN: z3c.form/trunk/ Make add/remove buttons of MultiWidget conditional based on field's min/max length. Add more TODOs for MultiWidget.

Dan Korostelev nadako at gmail.com
Tue Feb 3 20:13:03 EST 2009


Log message for revision 96053:
  Make add/remove buttons of MultiWidget conditional based on field's min/max length. Add more TODOs for MultiWidget.
  
  Relabeled MultiWidget's remove button from "Remove" to "Remove selected" to avoid confusion.
  
  Re-enabled tests for z3c.pt. However, it seems that there's a strange bug with macros that I don't understand in z3c.pt. See tests/simple_groupedit.pt for more comments.
  

Changed:
  U   z3c.form/trunk/TODOS.txt
  U   z3c.form/trunk/src/z3c/form/browser/README.txt
  U   z3c.form/trunk/src/z3c/form/browser/multi.py
  U   z3c.form/trunk/src/z3c/form/browser/multi.txt
  U   z3c.form/trunk/src/z3c/form/browser/objectmulti.txt
  U   z3c.form/trunk/src/z3c/form/locales/de/LC_MESSAGES/z3c.form.po
  U   z3c.form/trunk/src/z3c/form/locales/fr/LC_MESSAGES/z3c.form.po
  U   z3c.form/trunk/src/z3c/form/locales/ru/LC_MESSAGES/z3c.form.mo
  U   z3c.form/trunk/src/z3c/form/locales/ru/LC_MESSAGES/z3c.form.po
  U   z3c.form/trunk/src/z3c/form/locales/z3c.form.pot
  U   z3c.form/trunk/src/z3c/form/locales/zh_CN/LC_MESSAGES/z3c.form.po
  U   z3c.form/trunk/src/z3c/form/tests/simple_groupedit.pt
  U   z3c.form/trunk/src/z3c/form/tests/test_doc.py
  U   z3c.form/trunk/src/z3c/form/widget.py
  U   z3c.form/trunk/src/z3c/form/widget.txt

-=-
Modified: z3c.form/trunk/TODOS.txt
===================================================================
--- z3c.form/trunk/TODOS.txt	2009-02-03 23:24:13 UTC (rev 96052)
+++ z3c.form/trunk/TODOS.txt	2009-02-04 01:13:03 UTC (rev 96053)
@@ -9,6 +9,18 @@
   and ``ISelectWidget``. We have to define more hidden widgets.
 
 
+Widgets
+-------
+
+- The MultiWidget should render a minimum number of elements by default
+  if the field defines min_length. Also, if user tries to remove elements
+  so the number of widgets becomes less than minimum - the widget should
+  add widgets to make their number minimum again. (Did you understand
+  this?:))
+
+- The MultiWidget should provide a way to reorder elements if used
+  for the ISequence field.
+
 Documentation
 -------------
 

Modified: z3c.form/trunk/src/z3c/form/browser/README.txt
===================================================================
--- z3c.form/trunk/src/z3c/form/browser/README.txt	2009-02-03 23:24:13 UTC (rev 96052)
+++ z3c.form/trunk/src/z3c/form/browser/README.txt	2009-02-04 01:13:03 UTC (rev 96053)
@@ -609,7 +609,7 @@
          class="submit-widget button-field" value="Add" />
       <input type="submit" id="bar-buttons-remove"
          name="bar.buttons.remove"
-         class="submit-widget button-field" value="Remove" />
+         class="submit-widget button-field" value="Remove selected" />
      </div>
   </div>
   <input type="hidden" name="bar.count" value="2" />
@@ -678,7 +678,7 @@
          class="submit-widget button-field" value="Add" />
       <input type="submit" id="bar-buttons-remove"
          name="bar.buttons.remove"
-         class="submit-widget button-field" value="Remove" />
+         class="submit-widget button-field" value="Remove selected" />
      </div>
   </div>
   <input type="hidden" name="bar.count" value="2" />
@@ -814,7 +814,7 @@
          class="submit-widget button-field" value="Add" />
       <input type="submit" id="bar-buttons-remove"
          name="bar.buttons.remove"
-         class="submit-widget button-field" value="Remove" />
+         class="submit-widget button-field" value="Remove selected" />
      </div>
   </div>
   <input type="hidden" name="bar.count" value="2" />
@@ -884,7 +884,7 @@
          class="submit-widget button-field" value="Add" />
       <input type="submit" id="bar-buttons-remove"
          name="bar.buttons.remove"
-         class="submit-widget button-field" value="Remove" />
+         class="submit-widget button-field" value="Remove selected" />
      </div>
   </div>
   <input type="hidden" name="bar.count" value="2" />
@@ -952,7 +952,7 @@
          class="submit-widget button-field" value="Add" />
       <input type="submit" id="bar-buttons-remove"
          name="bar.buttons.remove"
-         class="submit-widget button-field" value="Remove" />
+         class="submit-widget button-field" value="Remove selected" />
      </div>
   </div>
   <input type="hidden" name="bar.count" value="2" />
@@ -1021,7 +1021,7 @@
          class="submit-widget button-field" value="Add" />
       <input type="submit" id="bar-buttons-remove"
          name="bar.buttons.remove"
-         class="submit-widget button-field" value="Remove" />
+         class="submit-widget button-field" value="Remove selected" />
      </div>
   </div>
   <input type="hidden" name="bar.count" value="2" />
@@ -1089,7 +1089,7 @@
          class="submit-widget button-field" value="Add" />
       <input type="submit" id="bar-buttons-remove"
          name="bar.buttons.remove"
-         class="submit-widget button-field" value="Remove" />
+         class="submit-widget button-field" value="Remove selected" />
      </div>
   </div>
   <input type="hidden" name="bar.count" value="2" />
@@ -1158,7 +1158,7 @@
          class="submit-widget button-field" value="Add" />
       <input type="submit" id="bar-buttons-remove"
          name="bar.buttons.remove"
-         class="submit-widget button-field" value="Remove" />
+         class="submit-widget button-field" value="Remove selected" />
      </div>
   </div>
   <input type="hidden" name="bar.count" value="2" />
@@ -1225,7 +1225,7 @@
          class="submit-widget button-field" value="Add" />
       <input type="submit" id="bar-buttons-remove"
          name="bar.buttons.remove"
-         class="submit-widget button-field" value="Remove" />
+         class="submit-widget button-field" value="Remove selected" />
      </div>
   </div>
   <input type="hidden" name="bar.count" value="2" />
@@ -1292,7 +1292,7 @@
          class="submit-widget button-field" value="Add" />
       <input type="submit" id="bar-buttons-remove"
          name="bar.buttons.remove"
-         class="submit-widget button-field" value="Remove" />
+         class="submit-widget button-field" value="Remove selected" />
      </div>
   </div>
   <input type="hidden" name="bar.count" value="2" />
@@ -1359,7 +1359,7 @@
          class="submit-widget button-field" value="Add" />
       <input type="submit" id="bar-buttons-remove"
          name="bar.buttons.remove"
-         class="submit-widget button-field" value="Remove" />
+         class="submit-widget button-field" value="Remove selected" />
      </div>
   </div>
   <input type="hidden" name="bar.count" value="2" />
@@ -1428,7 +1428,7 @@
          class="submit-widget button-field" value="Add" />
       <input type="submit" id="bar-buttons-remove"
          name="bar.buttons.remove"
-         class="submit-widget button-field" value="Remove" />
+         class="submit-widget button-field" value="Remove selected" />
      </div>
   </div>
   <input type="hidden" name="bar.count" value="2" />
@@ -1497,7 +1497,7 @@
          class="submit-widget button-field" value="Add" />
       <input type="submit" id="bar-buttons-remove"
          name="bar.buttons.remove"
-         class="submit-widget button-field" value="Remove" />
+         class="submit-widget button-field" value="Remove selected" />
      </div>
   </div>
   <input type="hidden" name="bar.count" value="2" />
@@ -1564,7 +1564,7 @@
          class="submit-widget button-field" value="Add" />
       <input type="submit" id="bar-buttons-remove"
          name="bar.buttons.remove"
-         class="submit-widget button-field" value="Remove" />
+         class="submit-widget button-field" value="Remove selected" />
      </div>
   </div>
   <input type="hidden" name="bar.count" value="2" />
@@ -1633,7 +1633,7 @@
          class="submit-widget button-field" value="Add" />
       <input type="submit" id="bar-buttons-remove"
          name="bar.buttons.remove"
-         class="submit-widget button-field" value="Remove" />
+         class="submit-widget button-field" value="Remove selected" />
      </div>
   </div>
   <input type="hidden" name="bar.count" value="2" />
@@ -1702,7 +1702,7 @@
          class="submit-widget button-field" value="Add" />
       <input type="submit" id="bar-buttons-remove"
          name="bar.buttons.remove"
-         class="submit-widget button-field" value="Remove" />
+         class="submit-widget button-field" value="Remove selected" />
      </div>
   </div>
   <input type="hidden" name="bar.count" value="2" />
@@ -1944,7 +1944,7 @@
          class="submit-widget button-field" value="Add" />
       <input type="submit" id="bar-buttons-remove"
          name="bar.buttons.remove"
-         class="submit-widget button-field" value="Remove" />
+         class="submit-widget button-field" value="Remove selected" />
      </div>
   </div>
   <input type="hidden" name="bar.count" value="2" />
@@ -2013,7 +2013,7 @@
          class="submit-widget button-field" value="Add" />
       <input type="submit" id="bar-buttons-remove"
          name="bar.buttons.remove"
-         class="submit-widget button-field" value="Remove" />
+         class="submit-widget button-field" value="Remove selected" />
      </div>
   </div>
   <input type="hidden" name="bar.count" value="2" />
@@ -2149,7 +2149,7 @@
          class="submit-widget button-field" value="Add" />
       <input type="submit" id="bar-buttons-remove"
          name="bar.buttons.remove"
-         class="submit-widget button-field" value="Remove" />
+         class="submit-widget button-field" value="Remove selected" />
      </div>
   </div>
   <input type="hidden" name="bar.count" value="2" />
@@ -2219,7 +2219,7 @@
          class="submit-widget button-field" value="Add" />
       <input type="submit" id="bar-buttons-remove"
          name="bar.buttons.remove"
-         class="submit-widget button-field" value="Remove" />
+         class="submit-widget button-field" value="Remove selected" />
      </div>
   </div>
   <input type="hidden" name="bar.count" value="2" />
@@ -2287,7 +2287,7 @@
          class="submit-widget button-field" value="Add" />
       <input type="submit" id="bar-buttons-remove"
          name="bar.buttons.remove"
-         class="submit-widget button-field" value="Remove" />
+         class="submit-widget button-field" value="Remove selected" />
      </div>
   </div>
   <input type="hidden" name="bar.count" value="2" />
@@ -2356,7 +2356,7 @@
          class="submit-widget button-field" value="Add" />
       <input type="submit" id="bar-buttons-remove"
          name="bar.buttons.remove"
-         class="submit-widget button-field" value="Remove" />
+         class="submit-widget button-field" value="Remove selected" />
      </div>
   </div>
   <input type="hidden" name="bar.count" value="2" />
@@ -2424,7 +2424,7 @@
          class="submit-widget button-field" value="Add" />
       <input type="submit" id="bar-buttons-remove"
          name="bar.buttons.remove"
-         class="submit-widget button-field" value="Remove" />
+         class="submit-widget button-field" value="Remove selected" />
      </div>
   </div>
   <input type="hidden" name="bar.count" value="2" />
@@ -2493,7 +2493,7 @@
          class="submit-widget button-field" value="Add" />
       <input type="submit" id="bar-buttons-remove"
          name="bar.buttons.remove"
-         class="submit-widget button-field" value="Remove" />
+         class="submit-widget button-field" value="Remove selected" />
      </div>
   </div>
   <input type="hidden" name="bar.count" value="2" />
@@ -2560,7 +2560,7 @@
          class="submit-widget button-field" value="Add" />
       <input type="submit" id="bar-buttons-remove"
          name="bar.buttons.remove"
-         class="submit-widget button-field" value="Remove" />
+         class="submit-widget button-field" value="Remove selected" />
      </div>
   </div>
   <input type="hidden" name="bar.count" value="2" />
@@ -2627,7 +2627,7 @@
          class="submit-widget button-field" value="Add" />
       <input type="submit" id="bar-buttons-remove"
          name="bar.buttons.remove"
-         class="submit-widget button-field" value="Remove" />
+         class="submit-widget button-field" value="Remove selected" />
      </div>
   </div>
   <input type="hidden" name="bar.count" value="2" />
@@ -2694,7 +2694,7 @@
          class="submit-widget button-field" value="Add" />
       <input type="submit" id="bar-buttons-remove"
          name="bar.buttons.remove"
-         class="submit-widget button-field" value="Remove" />
+         class="submit-widget button-field" value="Remove selected" />
      </div>
   </div>
   <input type="hidden" name="bar.count" value="2" />
@@ -2763,7 +2763,7 @@
          class="submit-widget button-field" value="Add" />
       <input type="submit" id="bar-buttons-remove"
          name="bar.buttons.remove"
-         class="submit-widget button-field" value="Remove" />
+         class="submit-widget button-field" value="Remove selected" />
      </div>
   </div>
   <input type="hidden" name="bar.count" value="2" />
@@ -2832,7 +2832,7 @@
          class="submit-widget button-field" value="Add" />
       <input type="submit" id="bar-buttons-remove"
          name="bar.buttons.remove"
-         class="submit-widget button-field" value="Remove" />
+         class="submit-widget button-field" value="Remove selected" />
      </div>
   </div>
   <input type="hidden" name="bar.count" value="2" />
@@ -2899,7 +2899,7 @@
          class="submit-widget button-field" value="Add" />
       <input type="submit" id="bar-buttons-remove"
          name="bar.buttons.remove"
-         class="submit-widget button-field" value="Remove" />
+         class="submit-widget button-field" value="Remove selected" />
      </div>
   </div>
   <input type="hidden" name="bar.count" value="2" />
@@ -2968,7 +2968,7 @@
          class="submit-widget button-field" value="Add" />
       <input type="submit" id="bar-buttons-remove"
          name="bar.buttons.remove"
-         class="submit-widget button-field" value="Remove" />
+         class="submit-widget button-field" value="Remove selected" />
      </div>
   </div>
   <input type="hidden" name="bar.count" value="2" />
@@ -3037,7 +3037,7 @@
          class="submit-widget button-field" value="Add" />
       <input type="submit" id="bar-buttons-remove"
          name="bar.buttons.remove"
-         class="submit-widget button-field" value="Remove" />
+         class="submit-widget button-field" value="Remove selected" />
      </div>
   </div>
   <input type="hidden" name="bar.count" value="2" />

Modified: z3c.form/trunk/src/z3c/form/browser/multi.py
===================================================================
--- z3c.form/trunk/src/z3c/form/browser/multi.py	2009-02-03 23:24:13 UTC (rev 96052)
+++ z3c.form/trunk/src/z3c/form/browser/multi.py	2009-02-04 01:13:03 UTC (rev 96053)
@@ -16,6 +16,8 @@
 $Id: select.py 78513 2007-07-31 23:03:47Z srichter $
 """
 __docformat__ = "reStructuredText"
+from operator import attrgetter
+
 import zope.component
 import zope.interface
 import zope.schema
@@ -44,6 +46,7 @@
     items = ()
 
     def updateActions(self):
+        self.updateAllowAddRemove()
         if self.name is not None:
             self.prefix = self.name
         self.actions = zope.component.getMultiAdapter(
@@ -52,15 +55,18 @@
 
     def update(self):
         """See z3c.form.interfaces.IWidget."""
+        super(MultiWidget, self).update()
         self.updateActions()
-        super(MultiWidget, self).update()
         self.actions.execute()
+        self.updateActions() # Update again, as conditions may change
 
-    @button.buttonAndHandler(_('Add'), name='add')
+    @button.buttonAndHandler(_('Add'), name='add',
+                             condition=attrgetter('allowAdding'))
     def handleAdd(self, action):
         self.appendAddingWidget()
 
-    @button.buttonAndHandler(_('Remove'), name='remove')
+    @button.buttonAndHandler(_('Remove selected'), name='remove',
+                             condition=attrgetter('allowRemoving'))
     def handleRemove(self, action):
         self.widgets = [widget for widget in self.widgets
                         if ('%s.remove' % (widget.name)) not in self.request]

Modified: z3c.form/trunk/src/z3c/form/browser/multi.txt
===================================================================
--- z3c.form/trunk/src/z3c/form/browser/multi.txt	2009-02-03 23:24:13 UTC (rev 96052)
+++ z3c.form/trunk/src/z3c/form/browser/multi.txt	2009-02-04 01:13:03 UTC (rev 96053)
@@ -63,7 +63,7 @@
          class="submit-widget button-field" value="Add" />
       <input type="submit" id="widget-name-buttons-remove"
          name="widget.name.buttons.remove"
-         class="submit-widget button-field" value="Remove" />
+         class="submit-widget button-field" value="Remove selected" />
      </div>
   </div>
   <input type="hidden" name="widget.name.count" value="0" />
@@ -93,7 +93,7 @@
          class="submit-widget button-field" value="Add" />
       <input type="submit" id="widget-name-buttons-remove"
          name="widget.name.buttons.remove"
-         class="submit-widget button-field" value="Remove" />
+         class="submit-widget button-field" value="Remove selected" />
      </div>
   </div>
   <input type="hidden" name="widget.name.count" value="0" />
@@ -113,9 +113,6 @@
       <input type="submit" id="widget-name-buttons-add"
          name="widget.name.buttons.add"
          class="submit-widget button-field" value="Add" />
-      <input type="submit" id="widget-name-buttons-remove"
-         name="widget.name.buttons.remove"
-         class="submit-widget button-field" value="Remove" />
      </div>
   </div>
   <input type="hidden" name="widget.name.count" value="0" />
@@ -131,8 +128,8 @@
   >>> zope.component.provideAdapter(FieldWidgetDataConverter)
   >>> zope.component.provideAdapter(SimpleFieldValidator)
 
+  >>> widget.value = [u'42', u'43']
   >>> widget.update()
-  >>> widget.value = [u'42', u'43']
   >>> print widget.render()
   <div class="multi-widget">
       <div id="widget-id-0-row" class="row">
@@ -181,7 +178,7 @@
          class="submit-widget button-field" value="Add" />
       <input type="submit" id="widget-name-buttons-remove"
          name="widget.name.buttons.remove"
-         class="submit-widget button-field" value="Remove" />
+         class="submit-widget button-field" value="Remove selected" />
      </div>
   </div>
   <input type="hidden" name="widget.name.count" value="2" />
@@ -266,7 +263,7 @@
          class="submit-widget button-field" value="Add" />
       <input type="submit" id="widget-name-buttons-remove"
          name="widget.name.buttons.remove"
-         class="submit-widget button-field" value="Remove" />
+         class="submit-widget button-field" value="Remove selected" />
      </div>
   </div>
   <input type="hidden" name="widget.name.count" value="3" />
@@ -350,12 +347,12 @@
          class="submit-widget button-field" value="Add" />
       <input type="submit" id="widget-name-buttons-remove"
          name="widget.name.buttons.remove"
-         class="submit-widget button-field" value="Remove" />
+         class="submit-widget button-field" value="Remove selected" />
      </div>
   </div>
   <input type="hidden" name="widget.name.count" value="3" />
 
-As you can see in the above sample, the new stored value gest rendered as a
+As you can see in the above sample, the new stored value get rendered as a
 real value and the new adding value input field is gone. Now let's try to
 remove an existing value:
 
@@ -364,10 +361,10 @@
   ...                                    'widget.name.1':u'43',
   ...                                    'widget.name.2':u'44',
   ...                                    'widget.name.1.remove':u'1',
-  ...                                    'widget.name.buttons.remove':'Remove'})
+  ...                                    'widget.name.buttons.remove':'Remove selected'})
   >>> widget.update()
 
-This is good so, because the Remove is an widget-internal submit action
+This is good so, because the Remove selected is an widget-internal submit action
 
   >>> widget.extract()
   [u'42', u'43', u'44']
@@ -420,7 +417,7 @@
          class="submit-widget button-field" value="Add" />
       <input type="submit" id="widget-name-buttons-remove"
          name="widget.name.buttons.remove"
-         class="submit-widget button-field" value="Remove" />
+         class="submit-widget button-field" value="Remove selected" />
      </div>
   </div>
   <input type="hidden" name="widget.name.count" value="2" />
@@ -476,7 +473,7 @@
       <input id="widget-name-buttons-add" name="widget.name.buttons.add"
       class="submit-widget button-field" value="Add" type="submit" />
       <input id="widget-name-buttons-remove" name="widget.name.buttons.remove"
-      class="submit-widget button-field" value="Remove" type="submit" />
+      class="submit-widget button-field" value="Remove selected" type="submit" />
      </div>
   </div>
   <input type="hidden" name="widget.name.count" value="2" />
@@ -549,13 +546,199 @@
          class="submit-widget button-field" value="Add" />
       <input type="submit" id="widget-name-buttons-remove"
          name="widget.name.buttons.remove"
-         class="submit-widget button-field" value="Remove" />
+         class="submit-widget button-field" value="Remove selected" />
      </div>
   </div>
   <input type="hidden" name="widget.name.count" value="2" />
 
+The widget filters out the add and remove buttons depending on the
+current value and the field constraints. You already saw that there's
+no remove button for empty value. Now, let's check rendering with
+minimum and maximum lengths defined in the field constraints.
 
+  >>> field = zope.schema.List(
+  ...     __name__=u'foo',
+  ...     value_type=zope.schema.Int(title=u'Number'),
+  ...     min_length=1,
+  ...     max_length=3
+  ...     )
+  >>> widget.field = field
+  >>> widget.widgets = []
+  >>> widget.value = []
 
+Let's test with minimum sequence, there should be no remove button:
+
+  >>> widget.request = TestRequest(form={'widget.name.count':u'1',
+  ...                                    'widget.name.0':u'42'})
+  >>> widget.update()
+  >>> print widget.render()
+  <div class="multi-widget">
+      <div id="widget-id-0-row" class="row">
+          <div class="label">
+            <label for="widget-id-0">
+              <span>Number</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="widget-id-0-remove"
+                     name="widget.name.0.remove" />
+            </div>
+            <div class="multi-widget-input"><input
+                 type="text" id="widget-id-0" name="widget.name.0"
+                 class="text-widget required int-field" value="42" />
+          </div>
+        </div>
+      </div>
+    <div class="buttons">
+      <input type="submit" id="widget-name-buttons-add"
+         name="widget.name.buttons.add"
+         class="submit-widget button-field" value="Add" />
+     </div>
+  </div>
+  <input type="hidden" name="widget.name.count" value="1" />
+
+Now, with middle-length sequence. All buttons should be there. 
+
+  >>> widget.request = TestRequest(form={'widget.name.count':u'2',
+  ...                                    'widget.name.0':u'42',
+  ...                                    'widget.name.1':u'43'})
+  >>> widget.update()
+  >>> print widget.render()
+  <div class="multi-widget">
+      <div id="widget-id-0-row" class="row">
+          <div class="label">
+            <label for="widget-id-0">
+              <span>Number</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="widget-id-0-remove"
+                     name="widget.name.0.remove" />
+            </div>
+            <div class="multi-widget-input"><input
+                 type="text" id="widget-id-0" name="widget.name.0"
+                 class="text-widget required int-field" value="42" />
+          </div>
+        </div>
+      </div>
+      <div id="widget-id-1-row" class="row">
+          <div class="label">
+            <label for="widget-id-1">
+              <span>Number</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="widget-id-1-remove"
+                     name="widget.name.1.remove" />
+            </div>
+            <div class="multi-widget-input"><input
+                 type="text" id="widget-id-1" name="widget.name.1"
+                 class="text-widget required int-field" value="43" />
+          </div>
+        </div>
+      </div>
+    <div class="buttons">
+      <input type="submit" id="widget-name-buttons-add"
+         name="widget.name.buttons.add"
+         class="submit-widget button-field" value="Add" />
+      <input type="submit" id="widget-name-buttons-remove"
+         name="widget.name.buttons.remove"
+         class="submit-widget button-field" value="Remove selected" />
+     </div>
+  </div>
+  <input type="hidden" name="widget.name.count" value="2" />
+
+Okay, now let's check the maximum-length sequence. There should be
+no add button:
+
+  >>> widget.request = TestRequest(form={'widget.name.count':u'3',
+  ...                                    'widget.name.0':u'42',
+  ...                                    'widget.name.1':u'43',
+  ...                                    'widget.name.2':u'44'})
+  >>> widget.update()
+  >>> print widget.render()
+  <div class="multi-widget">
+      <div id="widget-id-0-row" class="row">
+          <div class="label">
+            <label for="widget-id-0">
+              <span>Number</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="widget-id-0-remove"
+                     name="widget.name.0.remove" />
+            </div>
+            <div class="multi-widget-input"><input
+                 type="text" id="widget-id-0" name="widget.name.0"
+                 class="text-widget required int-field" value="42" />
+          </div>
+        </div>
+      </div>
+      <div id="widget-id-1-row" class="row">
+          <div class="label">
+            <label for="widget-id-1">
+              <span>Number</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="widget-id-1-remove"
+                     name="widget.name.1.remove" />
+            </div>
+            <div class="multi-widget-input"><input
+                 type="text" id="widget-id-1" name="widget.name.1"
+                 class="text-widget required int-field" value="43" />
+          </div>
+        </div>
+      </div>
+      <div id="widget-id-2-row" class="row">
+          <div class="label">
+            <label for="widget-id-2">
+              <span>Number</span>
+              <span class="required">*</span>
+            </label>
+          </div>
+          <div class="widget">
+            <div class="multi-widget-checkbox">
+              <input type="checkbox" value="1"
+                     class="multi-widget-checkbox checkbox-widget"
+                     id="widget-id-2-remove"
+                     name="widget.name.2.remove" />
+            </div>
+            <div class="multi-widget-input"><input
+                 type="text" id="widget-id-2" name="widget.name.2"
+                 class="text-widget required int-field" value="44" />
+          </div>
+        </div>
+      </div>
+    <div class="buttons">
+      <input type="submit" id="widget-name-buttons-remove"
+         name="widget.name.buttons.remove"
+         class="submit-widget button-field" value="Remove selected" />
+     </div>
+  </div>
+  <input type="hidden" name="widget.name.count" value="3" />
+
+
 Displaying
 ----------
 
@@ -786,7 +969,7 @@
          class="submit-widget button-field" value="Add" />
       <input type="submit" id="widget-buttons-remove"
          name="widget.buttons.remove"
-         class="submit-widget button-field" value="Remove" />
+         class="submit-widget button-field" value="Remove selected" />
      </div>
   </div>
   <input type="hidden" name="None.count" value="2" />

Modified: z3c.form/trunk/src/z3c/form/browser/objectmulti.txt
===================================================================
--- z3c.form/trunk/src/z3c/form/browser/objectmulti.txt	2009-02-03 23:24:13 UTC (rev 96052)
+++ z3c.form/trunk/src/z3c/form/browser/objectmulti.txt	2009-02-04 01:13:03 UTC (rev 96053)
@@ -70,7 +70,7 @@
          class="submit-widget button-field" value="Add" />
       <input type="submit" id="widget-name-buttons-remove"
          name="widget.name.buttons.remove"
-         class="submit-widget button-field" value="Remove" />
+         class="submit-widget button-field" value="Remove selected" />
      </div>
   </div>
   <input type="hidden" name="widget.name.count" value="0" />
@@ -100,7 +100,7 @@
          class="submit-widget button-field" value="Add" />
       <input type="submit" id="widget-name-buttons-remove"
          name="widget.name.buttons.remove"
-         class="submit-widget button-field" value="Remove" />
+         class="submit-widget button-field" value="Remove selected" />
      </div>
   </div>
   <input type="hidden" name="widget.name.count" value="0" />
@@ -130,9 +130,6 @@
       <input type="submit" id="foo-buttons-add"
          name="foo.buttons.add"
          class="submit-widget button-field" value="Add" />
-      <input type="submit" id="foo-buttons-remove"
-         name="foo.buttons.remove"
-         class="submit-widget button-field" value="Remove" />
      </div>
   </div>
   <input type="hidden" name="foo.count" value="0" />
@@ -184,6 +181,7 @@
 just cry about it in the HTML:
 
   >>> widget.value = [{'foofield': None, 'barfield': 666}]
+  >>> widget.update()
   >>> print widget.render()
   <div class="multi-widget required">
       <div id="foo-0-row" class="row">
@@ -234,7 +232,7 @@
       <input id="foo-buttons-add" name="foo.buttons.add"
              class="submit-widget button-field" value="Add" type="submit" />
       <input id="foo-buttons-remove" name="foo.buttons.remove"
-             class="submit-widget button-field" value="Remove" type="submit" />
+             class="submit-widget button-field" value="Remove selected" type="submit" />
     </div>
   </div>
   <input type="hidden" name="foo.count" value="1" />
@@ -342,7 +340,7 @@
              type="submit" />
       <input id="foo-buttons-remove"
              name="foo.buttons.remove"
-             class="submit-widget button-field" value="Remove"
+             class="submit-widget button-field" value="Remove selected"
              type="submit" />
     </div>
   </div>
@@ -505,7 +503,7 @@
              type="submit" />
       <input id="foo-buttons-remove"
              name="foo.buttons.remove"
-             class="submit-widget button-field" value="Remove"
+             class="submit-widget button-field" value="Remove selected"
              type="submit" />
     </div>
   </div>
@@ -667,7 +665,7 @@
       <input class="submit-widget button-field" id="foo-buttons-add"
              name="foo.buttons.add" type="submit" value="Add">
       <input class="submit-widget button-field" id="foo-buttons-remove"
-             name="foo.buttons.remove" type="submit" value="Remove">
+             name="foo.buttons.remove" type="submit" value="Remove selected">
     </div>
   </div>
   <input name="foo.count" type="hidden" value="3">
@@ -707,7 +705,7 @@
   ...                                    'foo.2.widgets.barfield':u'98',
   ...                                    'foo.2-empty-marker':u'1',
   ...                                    'foo.1.remove':u'1',
-  ...                                    'foo.buttons.remove':'Remove'})
+  ...                                    'foo.buttons.remove':'Remove selected'})
   >>> widget.update()
   >>> print widget.render()
   <div class="multi-widget required">
@@ -793,13 +791,13 @@
       <input class="submit-widget button-field" id="foo-buttons-add"
              name="foo.buttons.add" type="submit" value="Add">
       <input class="submit-widget button-field" id="foo-buttons-remove"
-             name="foo.buttons.remove" type="submit" value="Remove">
+             name="foo.buttons.remove" type="submit" value="Remove selected">
     </div>
   </div>
   <input name="foo.count" type="hidden" value="2">
 
 Let's see what we get on value extraction:
-(this is good so, because Remove is a widget-internal submit)
+(this is good so, because Remove selected is a widget-internal submit)
 
   >>> value = widget.extract()
   >>> value
@@ -917,7 +915,7 @@
     </div>
     <div class="buttons">
       <input class="submit-widget button-field" id="foo-buttons-add" name="foo.buttons.add" type="submit" value="Add">
-      <input class="submit-widget button-field" id="foo-buttons-remove" name="foo.buttons.remove" type="submit" value="Remove">
+      <input class="submit-widget button-field" id="foo-buttons-remove" name="foo.buttons.remove" type="submit" value="Remove selected">
     </div>
   </div>
   <input name="foo.count" type="hidden" value="2">
@@ -1013,7 +1011,7 @@
     </div>
     <div class="buttons">
       <input class="submit-widget button-field" id="foo-buttons-add" name="foo.buttons.add" type="submit" value="Add">
-      <input class="submit-widget button-field" id="foo-buttons-remove" name="foo.buttons.remove" type="submit" value="Remove">
+      <input class="submit-widget button-field" id="foo-buttons-remove" name="foo.buttons.remove" type="submit" value="Remove selected">
     </div>
   </div>
   <input name="foo.count" type="hidden" value="2">
\ No newline at end of file

Modified: z3c.form/trunk/src/z3c/form/locales/de/LC_MESSAGES/z3c.form.po
===================================================================
--- z3c.form/trunk/src/z3c/form/locales/de/LC_MESSAGES/z3c.form.po	2009-02-03 23:24:13 UTC (rev 96052)
+++ z3c.form/trunk/src/z3c/form/locales/de/LC_MESSAGES/z3c.form.po	2009-02-04 01:13:03 UTC (rev 96053)
@@ -12,7 +12,7 @@
 msgstr ""
 "Project-Id-Version: Development/Unknown\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: Tue Feb  3 23:21:02 2009\n"
+"POT-Creation-Date: Wed Feb  4 04:06:37 2009\n"
 "PO-Revision-Date: 2008-09-08 08:27+0100\n"
 "Last-Translator: Hermann Himmelbauer <dusty at qwer.tk>\n"
 "Language-Team: Zope 3 Developers <zope3-dev at zope.org>\n"
@@ -20,13 +20,13 @@
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 
-#: src/z3c/form/browser/multi.py:59 src/z3c/form/form.py:209
+#: src/z3c/form/browser/multi.py:63 src/z3c/form/form.py:209
 msgid "Add"
 msgstr "Hinzufügen"
 
-#: src/z3c/form/browser/multi.py:63
-msgid "Remove"
-msgstr "Entfernen"
+#: src/z3c/form/browser/multi.py:68
+msgid "Remove selected"
+msgstr ""
 
 #: src/z3c/form/browser/select.py:39
 msgid "no value"
@@ -607,6 +607,9 @@
 msgid "The schema of the field for which the template should be available"
 msgstr "Das Feld, für welches das Template zur Verfügung stehen soll"
 
+#~ msgid "Remove"
+#~ msgstr "Entfernen"
+
 #~ msgid "Data Provider"
 #~ msgstr "Daten-Provider"
 

Modified: z3c.form/trunk/src/z3c/form/locales/fr/LC_MESSAGES/z3c.form.po
===================================================================
--- z3c.form/trunk/src/z3c/form/locales/fr/LC_MESSAGES/z3c.form.po	2009-02-03 23:24:13 UTC (rev 96052)
+++ z3c.form/trunk/src/z3c/form/locales/fr/LC_MESSAGES/z3c.form.po	2009-02-04 01:13:03 UTC (rev 96053)
@@ -12,7 +12,7 @@
 msgstr ""
 "Project-Id-Version: z3c.form\n"
 "Report-Msgid-Bugs-To: Zope 3 Developers <zope3-dev at zope.org>\n"
-"POT-Creation-Date: Tue Feb  3 23:21:02 2009\n"
+"POT-Creation-Date: Wed Feb  4 04:06:37 2009\n"
 "PO-Revision-Date: 2008-09-05 16:20+0200\n"
 "Last-Translator: Christophe Combelles <ccomb at free.fr>\n"
 "Language-Team: Zope 3 French Users <zope3-french-user at lists.afpy.org>\n"
@@ -20,13 +20,13 @@
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 
-#: src/z3c/form/browser/multi.py:59 src/z3c/form/form.py:209
+#: src/z3c/form/browser/multi.py:63 src/z3c/form/form.py:209
 msgid "Add"
 msgstr "Ajouter"
 
-#: src/z3c/form/browser/multi.py:63
-msgid "Remove"
-msgstr "Supprimer"
+#: src/z3c/form/browser/multi.py:68
+msgid "Remove selected"
+msgstr ""
 
 #: src/z3c/form/browser/select.py:39
 msgid "no value"
@@ -599,6 +599,9 @@
 msgid "The schema of the field for which the template should be available"
 msgstr "Le champ pour lequel le gabarit doit être disponible"
 
+#~ msgid "Remove"
+#~ msgstr "Supprimer"
+
 #~ msgid "Data Provider"
 #~ msgstr "Fournisseur de données"
 

Modified: z3c.form/trunk/src/z3c/form/locales/ru/LC_MESSAGES/z3c.form.mo
===================================================================
(Binary files differ)

Modified: z3c.form/trunk/src/z3c/form/locales/ru/LC_MESSAGES/z3c.form.po
===================================================================
--- z3c.form/trunk/src/z3c/form/locales/ru/LC_MESSAGES/z3c.form.po	2009-02-03 23:24:13 UTC (rev 96052)
+++ z3c.form/trunk/src/z3c/form/locales/ru/LC_MESSAGES/z3c.form.po	2009-02-04 01:13:03 UTC (rev 96053)
@@ -14,8 +14,8 @@
 msgid ""
 msgstr ""
 "Project-Id-Version: Development/Unknown\n"
-"POT-Creation-Date: Tue Feb  3 22:47:11 2009\n"
-"PO-Revision-Date: 2009-02-03 23:22+0300\n"
+"POT-Creation-Date: Wed Feb  4 04:06:37 2009\n"
+"PO-Revision-Date: 2009-02-04 04:07+0300\n"
 "Last-Translator: Dan Korostelev <nadako at gmail.com>\n"
 "Language-Team: Zope 3 Developers <zope3-dev at zope.org>\n"
 "MIME-Version: 1.0\n"
@@ -23,14 +23,14 @@
 "Content-Transfer-Encoding: 8bit\n"
 "Generated-By: zope/app/locales/extract.py\n"
 
-#: src/z3c/form/browser/multi.py:59
+#: src/z3c/form/browser/multi.py:63
 #: src/z3c/form/form.py:209
 msgid "Add"
 msgstr "Добавить"
 
-#: src/z3c/form/browser/multi.py:63
-msgid "Remove"
-msgstr "Удалить"
+#: src/z3c/form/browser/multi.py:68
+msgid "Remove selected"
+msgstr "Удалить выбранные"
 
 #: src/z3c/form/browser/select.py:39
 msgid "no value"
@@ -580,6 +580,8 @@
 msgid "The schema of the field for which the template should be available"
 msgstr "Схема поля, для которого шаблон должен быть доступен"
 
+#~ msgid "Remove"
+#~ msgstr "Удалить"
 #~ msgid "Data Provider"
 #~ msgstr "Поставщик данных"
 #~ msgid "The component providing the data of the field for the widget."

Modified: z3c.form/trunk/src/z3c/form/locales/z3c.form.pot
===================================================================
--- z3c.form/trunk/src/z3c/form/locales/z3c.form.pot	2009-02-03 23:24:13 UTC (rev 96052)
+++ z3c.form/trunk/src/z3c/form/locales/z3c.form.pot	2009-02-04 01:13:03 UTC (rev 96053)
@@ -14,7 +14,7 @@
 msgid ""
 msgstr ""
 "Project-Id-Version: Development/Unknown\n"
-"POT-Creation-Date: Tue Feb  3 23:21:02 2009\n"
+"POT-Creation-Date: Wed Feb  4 04:06:37 2009\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL at ADDRESS>\n"
 "Language-Team: Zope 3 Developers <zope3-dev at zope.org>\n"
@@ -23,13 +23,13 @@
 "Content-Transfer-Encoding: 8bit\n"
 "Generated-By: zope/app/locales/extract.py\n"
 
-#: src/z3c/form/browser/multi.py:59
+#: src/z3c/form/browser/multi.py:63
 #: src/z3c/form/form.py:209
 msgid "Add"
 msgstr ""
 
-#: src/z3c/form/browser/multi.py:63
-msgid "Remove"
+#: src/z3c/form/browser/multi.py:68
+msgid "Remove selected"
 msgstr ""
 
 #: src/z3c/form/browser/select.py:39

Modified: z3c.form/trunk/src/z3c/form/locales/zh_CN/LC_MESSAGES/z3c.form.po
===================================================================
--- z3c.form/trunk/src/z3c/form/locales/zh_CN/LC_MESSAGES/z3c.form.po	2009-02-03 23:24:13 UTC (rev 96052)
+++ z3c.form/trunk/src/z3c/form/locales/zh_CN/LC_MESSAGES/z3c.form.po	2009-02-04 01:13:03 UTC (rev 96053)
@@ -1,7 +1,7 @@
 msgid ""
 msgstr ""
 "Project-Id-Version: \n"
-"POT-Creation-Date: Tue Feb  3 23:21:02 2009\n"
+"POT-Creation-Date: Wed Feb  4 04:06:37 2009\n"
 "PO-Revision-Date: \n"
 "Last-Translator: \n"
 "Language-Team: \n"
@@ -11,13 +11,13 @@
 "X-Poedit-Language: Chinese\n"
 "X-Poedit-Country: CHINA\n"
 
-#: src/z3c/form/browser/multi.py:59 src/z3c/form/form.py:209
+#: src/z3c/form/browser/multi.py:63 src/z3c/form/form.py:209
 msgid "Add"
 msgstr "添加"
 
-#: src/z3c/form/browser/multi.py:63
-msgid "Remove"
-msgstr "删除"
+#: src/z3c/form/browser/multi.py:68
+msgid "Remove selected"
+msgstr ""
 
 #: src/z3c/form/browser/select.py:39
 msgid "no value"
@@ -567,6 +567,9 @@
 msgid "The schema of the field for which the template should be available"
 msgstr "模板可用的字段"
 
+#~ msgid "Remove"
+#~ msgstr "删除"
+
 #~ msgid "Data Provider"
 #~ msgstr "数据提供者"
 

Modified: z3c.form/trunk/src/z3c/form/tests/simple_groupedit.pt
===================================================================
--- z3c.form/trunk/src/z3c/form/tests/simple_groupedit.pt	2009-02-03 23:24:13 UTC (rev 96052)
+++ z3c.form/trunk/src/z3c/form/tests/simple_groupedit.pt	2009-02-04 01:13:03 UTC (rev 96053)
@@ -14,18 +14,31 @@
       </li>
     </ul>
     <form action=".">
+      <tal:XXX replace="nothing">
+       Here's an interesting bug with z3c.pt: If you move the
+       define-macro below into the <div class="row"/>, it will
+       render the widget repetition twice for some reason when
+       using the macro below in the group fieldsets. Also, it
+       randomly won't repeat twice in some cases when text nodes are
+       inserted between tags (I tried to add "a" right after the
+       last tag - <input type="text" tal:replace="blahblah" />
+       Good luck to z3c.pt debuggers. :-)
+       
+       nadako
+      </tal:XXX>
+      <metal:block metal:define-macro="rows">
       <div class="row"
-           metal:define-macro="rows"
            tal:repeat="widget view/widgets/values">
         <b tal:condition="widget/error"
-           tal:content="structure widget/error/render"
-        /><label for=""
+           tal:content="structure widget/error/render" />
+        <label for=""
                tal:attributes="for widget/id"
                tal:content="widget/label" />
-        <input type="text" tal:replace="structure widget/render"
-      /></div>
+        <input type="text" tal:replace="structure widget/render" />
+      </div>
+      </metal:block>
       <fieldset tal:condition="view/groups|nothing"
-                  tal:repeat="view view/groups">
+                tal:repeat="view view/groups">
         <legend tal:condition="view/label"
                 tal:content="view/label">Label</legend>
         <div metal:use-macro="template/macros/errors" />

Modified: z3c.form/trunk/src/z3c/form/tests/test_doc.py
===================================================================
--- z3c.form/trunk/src/z3c/form/tests/test_doc.py	2009-02-03 23:24:13 UTC (rev 96052)
+++ z3c.form/trunk/src/z3c/form/tests/test_doc.py	2009-02-04 01:13:03 UTC (rev 96053)
@@ -141,7 +141,6 @@
             optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS,
             checker=checker,
             ))
-        #for setUp in (testing.setUpZPT, testing.setUpZ3CPT))
-        for setUp in (testing.setUpZPT, ))
+        for setUp in (testing.setUpZPT, testing.setUpZ3CPT))
 
     return unittest.TestSuite(itertools.chain(*tests))

Modified: z3c.form/trunk/src/z3c/form/widget.py
===================================================================
--- z3c.form/trunk/src/z3c/form/widget.py	2009-02-03 23:24:13 UTC (rev 96052)
+++ z3c.form/trunk/src/z3c/form/widget.py	2009-02-04 01:13:03 UTC (rev 96053)
@@ -244,6 +244,7 @@
     zope.interface.implements(interfaces.IMultiWidget)
 
     allowAdding = True
+    allowRemoving = True
     # you set showLabel to False or use another template for disable (sub)
     # widget labels
     showLabel = True
@@ -332,19 +333,33 @@
         """
         oldLen = len(self.widgets)
         self.widgets = []
+        idx = 0
         if self.value:
-            for idx, v in enumerate(self.value):
+            for v in self.value:
                 widget = self.getWidget(idx)
                 self.applyValue(widget, v)
                 self.widgets.append(widget)
+                idx += 1
         missing = oldLen - len(self.widgets)
         if missing > 0:
             # add previous existing new added widgtes
-            for i in range(missing):
-                idx += 1
+            for i in xrange(missing):
                 widget = self.getWidget(idx)
                 self.widgets.append(widget)
+                idx += 1
 
+    def updateAllowAddRemove(self):
+        """Update the allowAdding/allowRemoving attributes
+        basing on field constraints and current number of widgets
+        """
+        if not zope.schema.interfaces.IMinMaxLen.providedBy(self.field):
+            return
+        max_length = self.field.max_length
+        min_length = self.field.min_length
+        num_items = len(self.widgets)
+        self.allowAdding = bool((not max_length) or (num_items < max_length))
+        self.allowRemoving = bool(num_items and (num_items > min_length))
+
     @apply
     def value():
         """This invokes updateWidgets on any value change e.g. update/extract."""

Modified: z3c.form/trunk/src/z3c/form/widget.txt
===================================================================
--- z3c.form/trunk/src/z3c/form/widget.txt	2009-02-03 23:24:13 UTC (rev 96052)
+++ z3c.form/trunk/src/z3c/form/widget.txt	2009-02-04 01:13:03 UTC (rev 96053)
@@ -619,7 +619,61 @@
   >>> multiWidget.value
   [u'42', u'43']
 
+MultiWidget also declares the ``allowAdding`` and ``allowRemoving``
+attributes that can be used in browser presentation to control add/remove
+button availability. To ease working with common cases, the
+``updateAllowAddRemove`` method provided that will set those attributes
+in respect to field's min_length and max_length, if the field provides
+zope.schema.interfaces.IMinMaxLen interface.
 
+Let's define a field with min and max length constraints and create
+a widget for it.
+
+  >>> multiField = zope.schema.List(
+  ...     value_type=zope.schema.Int(),
+  ...     min_length=2,
+  ...     max_length=5)
+
+  >>> request = TestRequest()
+  >>> multiWidget = widget.FieldWidget(multiField, widget.MultiWidget(request))
+
+Now, let's check if the function will do the right thing depending on
+the value:
+
+No value:
+
+  >>> multiWidget.updateAllowAddRemove()
+  >>> multiWidget.allowAdding, multiWidget.allowRemoving
+  (True, False)
+
+Minimum length:
+
+  >>> multiWidget.value = [u'3', u'5']
+  >>> multiWidget.updateAllowAddRemove()
+  >>> multiWidget.allowAdding, multiWidget.allowRemoving
+  (True, False)
+
+Some allowed length:
+
+  >>> multiWidget.value = [u'3', u'5', u'8', u'6']
+  >>> multiWidget.updateAllowAddRemove()
+  >>> multiWidget.allowAdding, multiWidget.allowRemoving
+  (True, True)
+
+Maximum length:
+
+  >>> multiWidget.value = [u'3', u'5', u'8', u'6', u'42']
+  >>> multiWidget.updateAllowAddRemove()
+  >>> multiWidget.allowAdding, multiWidget.allowRemoving
+  (False, True)
+
+Over maximum length:
+
+  >>> multiWidget.value = [u'3', u'5', u'8', u'6', u'42', u'45']
+  >>> multiWidget.updateAllowAddRemove()
+  >>> multiWidget.allowAdding, multiWidget.allowRemoving
+  (False, True)
+
 Widget Events
 -------------
 



More information about the Checkins mailing list