[Checkins] SVN: z3c.form/trunk/ - fix button update issue

Roger Ineichen roger at projekt01.ch
Sat Feb 21 02:24:28 EST 2009


Log message for revision 96859:
  - fix button update issue
  
  ButtonActions update where appending keys and values within each update call
  I guess the same is true for field widgets. I'll check that later...

Changed:
  U   z3c.form/trunk/CHANGES.txt
  U   z3c.form/trunk/src/z3c/form/button.py
  U   z3c.form/trunk/src/z3c/form/button.txt

-=-
Modified: z3c.form/trunk/CHANGES.txt
===================================================================
--- z3c.form/trunk/CHANGES.txt	2009-02-21 06:40:25 UTC (rev 96858)
+++ z3c.form/trunk/CHANGES.txt	2009-02-21 07:24:26 UTC (rev 96859)
@@ -5,6 +5,9 @@
 Version 2.0.0 (unreleased)
 --------------------------
 
+- Bug: ButtonActions update where appending keys and values within each
+  update call. 
+
 - Bug: The CollectionSequenceDataConverter no longer throws a
   "TypeError: 'NoneType' object is not iterable" when passed the value
   of a non-required field (which in the case of a List field is None).

Modified: z3c.form/trunk/src/z3c/form/button.py
===================================================================
--- z3c.form/trunk/src/z3c/form/button.py	2009-02-21 06:40:25 UTC (rev 96858)
+++ z3c.form/trunk/src/z3c/form/button.py	2009-02-21 07:24:26 UTC (rev 96859)
@@ -254,20 +254,24 @@
         prefix = util.expandPrefix(self.form.prefix)
         prefix += util.expandPrefix(self.form.buttons.prefix)
         # Walk through each field, making an action out of it.
+        orderedNames = []
         for name, button in self.form.buttons.items():
             # Step 1: Only create an action for the button, if the condition is
             #         fulfilled.
             if button.condition is not None and not button.condition(self.form):
                 continue
             # Step 2: Get the action for the given button.
-            if button.actionFactory is not None:
+            newButton = True
+            if name in self._data:
+                buttonAction = self._data[name]
+                newButton = False
+            elif button.actionFactory is not None:
                 buttonAction = button.actionFactory(self.request, button)
             else:
                 buttonAction = zope.component.getMultiAdapter(
                     (self.request, button), interfaces.IButtonAction)
             # Step 3: Set the name on the button
-            fullName = prefix + name
-            buttonAction.name = fullName
+            buttonAction.name = prefix + name
             # Step 4: Set any custom attribute values.
             title = zope.component.queryMultiAdapter(
                 (self.form, self.request, self.content, button, self),
@@ -276,15 +280,19 @@
                 buttonAction.title = title.get()
             # Step 5: Set the form
             buttonAction.form = self.form
-            zope.interface.alsoProvides(buttonAction, interfaces.IFormAware)
+            if not interfaces.IFormAware.providedBy(buttonAction):
+                zope.interface.alsoProvides(buttonAction, interfaces.IFormAware)
             # Step 6: Update the new action
             buttonAction.update()
             zope.event.notify(AfterWidgetUpdateEvent(buttonAction))
             # Step 7: Add the widget to the manager
-            self._data_keys.append(name)
-            self._data_values.append(buttonAction)
-            self._data[name] = buttonAction
-            zope.location.locate(buttonAction, self, name)
+            orderedNames.append(name)
+            if newButton:
+                # allways keep the order given from button items
+                self._data_keys = orderedNames
+                self._data_values.append(buttonAction)
+                self._data[name] = buttonAction
+                zope.location.locate(buttonAction, self, name)
 
 
 class ButtonActionHandler(action.ActionHandlerBase):

Modified: z3c.form/trunk/src/z3c/form/button.txt
===================================================================
--- z3c.form/trunk/src/z3c/form/button.txt	2009-02-21 06:40:25 UTC (rev 96858)
+++ z3c.form/trunk/src/z3c/form/button.txt	2009-02-21 07:24:26 UTC (rev 96859)
@@ -65,6 +65,7 @@
 
   >>> actions.keys()
   ['apply', 'cancel']
+
   >>> actions['apply']
   <ButtonAction 'form.buttons.apply' u'Apply'>
 
@@ -81,17 +82,30 @@
   ...     CustomButtonAction, provides=interfaces.IButtonAction)
 
 Now if we rerun update we will get this other ButtonAction
-implementation.
+implementation. Note, there are two strategies what now could happen. We can
+remove the existing action and get the new adapter based action or we can
+reuse the existing action. Since the ButtonActions class offers an API for
+remove existing actions, we reuse the existing action because it very uncommon
+to replace existing action during an for update call with an adapter. If
+someone really will add an action adapter during process time via directly
+provided interface, he is also responsible for remove existing actions.
 
+As you can see we still will get the old button action if we only call update:
+
   >>> actions.update()
+  >>> actions['apply']
+  <ButtonAction 'form.buttons.apply' u'Apply'>
 
-ISSUE duplicated button keys and values by calling update twice:
+This means we have to remove the previous action before we call update:
 
+  >>> del actions['apply']
+  >>> actions.update()
+
 Make sure we do not append a button twice to the key and value lists by calling
-update twice, Right now we do excatly that:
+update twice:
 
   >>> actions.keys()
-  ['apply', 'cancel', 'apply', 'cancel']
+  ['apply', 'cancel']
 
   >>> actions['apply']
   <CustomButtonAction 'form.buttons.apply' u'Apply'>
@@ -100,17 +114,35 @@
 actionFactory attribute.
 
   >>> def customButtonActionFactory(request, field):
-  ...     print "Just to let you know, this is a custom button."
+  ...     print "This button factory creates a button only once."
   ...     button = CustomButtonAction(request, field)
   ...     button.css = "happy"
   ...     return button
 
   >>> form.buttons['apply'].actionFactory = customButtonActionFactory
+
+Again, remove the old button action befor we call update:
+
+  >>> del actions['apply']
   >>> actions.update()
-  Just to let you know, this is a custom button.
+  This button factory creates a button only once.
+
+  >>> actions.update()
+
   >>> actions['apply'].css
   'happy'
 
+Since we only create a button once from an adapter or a factory, we can change
+the button attributes without to lose changes:
+
+  >>> actions['apply'].css = 'very happy'
+  >>> actions['apply'].css
+  'very happy'
+
+  >>> actions.update()
+  >>> actions['apply'].css
+  'very happy'
+
 But let's not digress too much and get rid of this customization
 
   >>> form.buttons['apply'].actionFactory = None



More information about the Checkins mailing list