[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