[Checkins] SVN: zope3org/trunk/src/zorg/multiform/ implemented
tests and actions
Bernd Dorn
bernd.dorn at fhv.at
Sun Apr 9 16:38:50 EDT 2006
Log message for revision 66751:
implemented tests and actions
Changed:
U zope3org/trunk/src/zorg/multiform/README.txt
U zope3org/trunk/src/zorg/multiform/actions.txt
U zope3org/trunk/src/zorg/multiform/interfaces.py
U zope3org/trunk/src/zorg/multiform/multiform.py
-=-
Modified: zope3org/trunk/src/zorg/multiform/README.txt
===================================================================
--- zope3org/trunk/src/zorg/multiform/README.txt 2006-04-09 20:16:21 UTC (rev 66750)
+++ zope3org/trunk/src/zorg/multiform/README.txt 2006-04-09 20:38:50 UTC (rev 66751)
@@ -3,7 +3,7 @@
===================
This Package provides an API to handle multiple forms with matching
-form fields on multiple items. The cration of multiforms is derived
+form fields on multiple items. The creation of multiforms is derived
from the Form class of the formlib package.
>>> from zope import interface, schema
@@ -83,165 +83,3 @@
...
</div>
-In order to define a save action on the multiform we have to define a
-parent action on our OrderForm. A parent action is rendered only one
-time in the parent multiform, but applied to all subforms.
-
- >>> from multiform import multiform
- >>> class OrderForm2(ItemFormBase):
- ... form_fields = form.Fields(IOrder,omit_readonly=False,
- ... render_context=True)
- ...
- ... @multiform.parentAction(u"Save",condition=form.haveInputWidgets)
- ... def handle_save_action(self, action, data):
- ... form.applyChanges(self.context, self.form_fields,
- ... data, self.adapters)
- ...
- ... def template(self):
- ... return '\n<div>%s</div>\n' % '</div><div>'.join([w() for w in
- ... self.widgets])
-
-
-Now we have to set the factory on the OrdersForm.
-
- >>> class OrdersForm2(MultiFormBase):
- ... itemFormFactory=OrderForm2
- ... def template(self):
- ... res = u''
- ... names = sorted(self.subForms.keys())
- ... for name in names:
- ... res += '<div>%s</div>\n' % self.subForms[name].render()
- ... return res
-
-
-
- >>> pf = OrdersForm2(orderMapping,request)
- >>> pf.setUpWidgets()
- >>> action = [action for action in pf.subForms['1'].actions][0]
- >>> action
- <multiform.multiform.ParentAction object at ...>
-
-All available parent action names of the subforms are available through the
-subActions attribute of the multi form.
-
- >>> pf.subActionNames
- [u'actions.save']
-
-The name of the action is without the item key, because it is applied
- to all items.
-
- >>> print action.__name__
- actions.save
-
- >>> request = TestRequest()
- >>> orderMapping = dict([(str(k),Order(k,name='n%s'%k)) for k in range(2)])
- >>> request.form[pf.prefix + '.' + action.__name__]=u''
- >>> print OrdersForm2(orderMapping,request)()
- Traceback (most recent call last):
- ...
- FormError: ('No input', 'name')
-
-Ups, we have an error because we didn't provide the input data on the
-request. The form requires to have all input fields in the request if
-an action should be supplied.
-
-Let's supply request Data.
-
- >>> for i in range(2):
- ... request.form['form.%s.name' % i]='new name %s' % i
- ... request.form['form.%s.identifier' % i]= i
- >>> print OrdersForm2(orderMapping,request)()
- <div>
- <div... value="new name 0" ...
- <div... value="new name 1" ...
- </div>
-
-The above example uses inputwidgets for all editable fields in the
-forms. In the next example we implement a multiform which uses
-displaywidgets per default. Inputwidgets should only be used if the
-'Edit' action is called.
-
-So let us define a new specialized item form class, which defines a
-new parent action called ``Edit``.
-
- >>> def haveNoInputWidgets(f,action):
- ... return not form.haveInputWidgets(f,action)
-
- >>> class OrderForm3(ItemFormBase):
- ...
- ... def __init__(self,context,request,parentForm):
- ... super(OrderForm3,self).__init__(context,request,parentForm)
- ... self.form_fields = form.Fields(IOrder,omit_readonly=False,
- ... render_context=True,for_display=True)
- ...
- ...
- ... @multiform.parentAction(u"Save",condition=form.haveInputWidgets)
- ... def handle_save_action(self, action, data):
- ... import pdb;pdb.set_trace()
- ... for field in self.form_fields:
- ... field.for_display=False
- ... form.setUpWidgets()
- ... form.applyChanges(self.context, self.form_fields,
- ... data, self.adapters)
- ...
- ... @multiform.parentAction('Edit',condition=haveNoInputWidgets)
- ... def handle_edit_action(self, action, data):
- ... for field in self.form_fields:
- ... field.for_display=False
- ... self.form_reset=True
- ... def template(self):
- ... return '\n<div>%s</div>\n' % '</div><div>'.join([w() for w in
- ... self.widgets])
-
-
- >>> class OrdersForm3(OrdersForm2):
- ... itemFormFactory=OrderForm3
-
-So in our new form all widgets are display widgets per default
-
- >>> request = TestRequest()
- >>> pf = OrdersForm3(orderMapping,request)
- >>> print pf()
- <div>
- <div>0</div><div>new name 0</div>
- </div>
- <div>
- <div>1</div><div>new name 1</div>
- </div>
-
-And the save action should not be available, due to the reason that there
-are no input widgets in the sub forms.
-
- >>> pf.subActionNames
- [u'actions.edit']
-
-Now let's call the edit action to set the widgets to input widgets.
-
- >>> request.form['form.actions.edit']=u''
- >>> pf = OrdersForm3(orderMapping,request)
- >>> print pf()
- <div>
- <div...<input class="textType" ... value="new name 0" ...
- </div>
- <div>
- <div...<input class="textType" ... value="new name 1" ...
-
-Now only the save action should be available.
-
- >>> pf.subActionNames
- [u'actions.save']
-
-Let us save some data.
-
- >>> request = TestRequest()
- >>> request.form['form.actions.save']=u''
- >>> for i in range(2):
- ... request.form['form.%s.name' % i]='newer name %s' % i
- ... request.form['form.%s.identifier' % i]= i
- >>> print OrdersForm3(orderMapping,request)()
-
-
-TODO:
-
-- encode prefix, do we have to do it?
-
Modified: zope3org/trunk/src/zorg/multiform/actions.txt
===================================================================
--- zope3org/trunk/src/zorg/multiform/actions.txt 2006-04-09 20:16:21 UTC (rev 66750)
+++ zope3org/trunk/src/zorg/multiform/actions.txt 2006-04-09 20:38:50 UTC (rev 66751)
@@ -1,8 +1,18 @@
-So let us define a new specialized item form class, which defines a
-new parent action called ``Edit``.
+===================
+ Multiform Actions
+===================
+The multiform package defines a new type of action called
+ParentAction. A parent action is rendered only one time in the parent
+multiform, but applied to all subforms.
+In this example we create a specialized item form class, which defines
+a new parent action called ``Save``. Additionally two standard actions
+are defined in the multiform (parent) class called ``Edit`` and
+``Cancel```.
+
>>> from multiform.multiform import ItemFormBase,MultiFormBase
+ >>> from zope.app.form.interfaces import IInputWidget
>>> from zope.formlib import form
>>> from multiform import multiform
>>> from zope.publisher.browser import TestRequest
@@ -19,49 +29,80 @@
>>> orderMapping = dict([(str(k),Order(k,name='n%s'%k)) for k in range(2)])
- >>> def haveNoInputWidgets(f,action):
- ... return not form.haveInputWidgets(f,action)
+ >>> def isFormDisplayMode(f,action):
+ ... return not f.inputMode
+
+ >>> def isFormInputMode(f,action):
+ ... return f.inputMode
- >>> class OrderForm3(ItemFormBase):
+ >>> def isParentFormInputMode(f,action):
+ ... return f.parentForm.inputMode
+
+ >>> def hasInputWidgets(f,action):
+ ... if form.haveInputWidgets(f,action):
+ ... return True
+ ... if ISubmittedAction.providedBy(action):
+ ... tmpForm = f.parentForm.itemFormFactory(f.context,
+ ... f.request,f.parentForm)
+ ... tmpForm.setPrefix(f.prefix)
+ ... hasInput = True
+ ... form_prefix = f.prefix +'.'
+ ... for field in tmpForm.form_fields:
+ ... field.for_display=False
+ ... tmpForm.setUpWidgets()
+ ... for input, widget in \
+ ... tmpForm.widgets.__iter_input_and_widget__():
+ ... if input and IInputWidget.providedBy(widget):
+ ... name = form._widgetKey(widget, form_prefix)
+ ... if not widget.hasInput():
+ ... hasInput = False
+ ... break
+ ... return hasInput
+ ... return False
+
+ >>> class OrderForm(ItemFormBase):
+ ... inputMode=False
...
... def __init__(self,context,request,parentForm):
- ... super(OrderForm3,self).__init__(context,request,parentForm)
+ ... super(OrderForm,self).__init__(context,request,parentForm)
... self.form_fields = form.Fields(IOrder,omit_readonly=False,
- ... render_context=True,for_display=True)
+ ... render_context=True)
...
- ... @multiform.parentAction(u"Save",condition=form.haveInputWidgets)
+ ... @multiform.parentAction(u"Save",condition=isParentFormInputMode,
+ ... inputMode=True)
... def handle_save_action(self, action, data):
- ... import pdb;pdb.set_trace()
- ... for field in self.form_fields:
- ... field.for_display=False
- ... form.setUpWidgets()
... form.applyChanges(self.context, self.form_fields,
... data, self.adapters)
+ ... self.parentForm.newInputMode=False
...
- ... @multiform.parentAction('Edit',condition=haveNoInputWidgets)
- ... def handle_edit_action(self, action, data):
- ... for field in self.form_fields:
- ... field.for_display=False
- ... self.form_reset=True
...
... def template(self):
... return '\n<div>%s</div>\n' % '</div><div>'.join([w() for w in
... self.widgets])
- >>> class OrdersForm3(MultiFormBase):
- ... itemFormFactory=OrderForm3
+ >>> class OrdersForm(MultiFormBase):
+ ... itemFormFactory=OrderForm
... def template(self):
... res = u''
... names = sorted(self.subForms.keys())
... for name in names:
... res += '<div>%s</div>\n' % self.subForms[name].render()
... return res
+ ...
+ ... @form.action('Edit',condition=isFormDisplayMode)
+ ... def handle_edit_action(self, action, data):
+ ... self.newInputMode=True
+ ...
+ ... @form.action('Cancel',condition=isFormInputMode)
+ ... def handle_cancel_action(self, action, data):
+ ... self.newInputMode=False
+
So in our new form all widgets are display widgets per default
>>> request = TestRequest()
- >>> pf = OrdersForm3(orderMapping,request)
+ >>> pf = OrdersForm(orderMapping,request)
>>> print pf()
<div>
<div>0</div><div>n0</div>
@@ -74,12 +115,14 @@
are no input widgets in the sub forms.
>>> pf.subActionNames
- [u'actions.edit']
+ []
+ >>> [action.__name__ for action in pf.availableActions()]
+ [u'form.actions.edit']
Now let's call the edit action to set the widgets to input widgets.
>>> request.form['form.actions.edit']=u''
- >>> pf = OrdersForm3(orderMapping,request)
+ >>> pf = OrdersForm(orderMapping,request)
>>> print pf()
<div>
<div...<input class="textType" ... value="n0" ...
@@ -87,17 +130,69 @@
<div>
<div...<input class="textType" ... value="n1" ...
-Now only the save action should be available.
+Now the save action should be available in the subActionNames and
+the cancel action in the multiform actions.
>>> pf.subActionNames
- [u'actions.save']
+ [u'form.actions.save']
+ >>> [a.__name__ for a in pf.availableActions()]
+ [u'form.actions.cancel']
-Let us save some data.
+Now Let us save some data.
+
>>> request = TestRequest()
>>> request.form['form.actions.save']=u''
>>> for i in range(2):
... request.form['form.%s.name' % i]='newer name %s' % i
... request.form['form.%s.identifier' % i]= i
- >>> print OrdersForm3(orderMapping,request)()
+ >>> pf = OrdersForm(orderMapping,request)
+ >>> result = pf()
+After the form is called, the changes are applied to the objects.
+ >>> [obj.name for obj in orderMapping.values()]
+ [u'newer name 1', u'newer name 0']
+
+Due to the reason the save handler sets the inputMode to False,
+only display widgets are rendered in the results
+
+ >>> print result
+ <div>
+ <div>0</div><div>newer name 0</div>
+ </div>
+ <div>
+ <div>1</div><div>newer name 1</div>
+ </div>
+
+Now we should only have the edit action be available, which is a
+multiform action, therefore not contained in the subActionNames
+
+ >>> pf.subActionNames
+ []
+ >>> [a.__name__ for a in pf.availableActions()]
+ [u'form.actions.edit']
+
+Now Let us cancel the edit mode.
+
+ >>> request = TestRequest()
+ >>> request.form['form.actions.cancel']=u''
+ >>> for i in range(2):
+ ... request.form['form.%s.name' % i]='next name %s' % i
+ ... request.form['form.%s.identifier' % i]= i
+ >>> pf = OrdersForm(orderMapping,request)
+ >>> result = pf()
+
+After the form is called, the objects are left unchanged. And the form
+should be in display mode again.
+
+ >>> [obj.name for obj in orderMapping.values()]
+ [u'newer name 1', u'newer name 0']
+
+ >>> print result
+ <div>
+ <div>0</div><div>newer name 0</div>
+ </div>
+ <div>
+ <div>1</div><div>newer name 1</div>
+ </div>
+
Modified: zope3org/trunk/src/zorg/multiform/interfaces.py
===================================================================
--- zope3org/trunk/src/zorg/multiform/interfaces.py 2006-04-09 20:16:21 UTC (rev 66750)
+++ zope3org/trunk/src/zorg/multiform/interfaces.py 2006-04-09 20:38:50 UTC (rev 66751)
@@ -8,3 +8,5 @@
class IParentAction(IAction):
"""a parent action"""
+
+
Modified: zope3org/trunk/src/zorg/multiform/multiform.py
===================================================================
--- zope3org/trunk/src/zorg/multiform/multiform.py 2006-04-09 20:16:21 UTC (rev 66750)
+++ zope3org/trunk/src/zorg/multiform/multiform.py 2006-04-09 20:38:50 UTC (rev 66751)
@@ -8,6 +8,7 @@
from zope.formlib.i18n import _
from interfaces import IMultiForm, IParentAction
from zope import interface
+
class ParentAction(form.Action):
@@ -15,24 +16,28 @@
is applied to all subForms"""
implements(IParentAction)
-
+ def __init__(self, label, **options):
+ self.inputMode = options.pop('inputMode',None)
+ super(ParentAction,self).__init__(label,**options)
+
+
def __get__(self, form, class_=None):
if form is None:
return self
result = self.__class__.__new__(self.__class__)
result.__dict__.update(self.__dict__)
result.form = form
- #result.__name__ = form.prefix + '.' + result.__name__
+ result.__name__ = form.parentForm.prefix + '.' + result.__name__
interface.alsoProvides(result, IBoundAction)
return result
def submitted(self):
# override to find the matching prefix
if not self.available():
- return False
- form = self.form.parentForm
- name = "%s.%s" % (form.prefix, self.__name__)
- return name in form.request.form
+ res = False
+ else:
+ res = self.__name__ in self.form.request
+ return res
class parentAction(form.action):
@@ -46,6 +51,7 @@
class ItemFormBase(form.FormBase):
parentForm = None
+ inputMode = None
def __init__(self,context,request,parentForm):
super(ItemFormBase,self).__init__(context,request)
@@ -64,6 +70,9 @@
actions= form.availableActions(self, actions)
return actions
+
+
+
class MultiFormBase(form.FormBase):
@@ -72,31 +81,39 @@
form_fields = []
actions = []
subActionNames = []
+ inputMode = None
+ newInputMode = None
def update(self):
+ self.initInputMode()
+ self.checkInputMode()
super(MultiFormBase,self).update()
subFormReset = False
+ hasErrors = False
for form in self.subForms.values():
form.update()
- if form.form_result is None:
- if form.form_reset:
- subFormReset=True
- form.resetForm()
- form.form_reset=False
- if subFormReset:
- self.refreshSubActionNames()
+ hasErrors = hasErrors or form.errors
+ if hasErrors:
+ self.newInputMode=None
+ if self.newInputMode is not None:
+ self.setInputMode(self.newInputMode)
+ self.setUpForms(ignore_request=True)
-
def setUpWidgets(self, *args, **kw):
super(MultiFormBase,self).setUpWidgets(*args,**kw)
self.subForms = {}
self.setUpForms(*args, **kw)
def setUpForms(self, *args, **kw):
-
+
for name,item in self.context.items():
prefix = (self.prefix and self.prefix+'.' or '') + name
subForm = self.itemFormFactory(item,self.request,self)
+ if self.inputMode is not None and not self.inputMode:
+ forceInputs = getattr(self.itemFormFactory,'forceInputs',[])
+ for field in subForm.form_fields:
+ if field.__name__ not in forceInputs:
+ field.for_display=True
subForm.setPrefix(prefix)
subForm.setUpWidgets(*args, **kw)
self.subForms[name] = subForm
@@ -110,7 +127,32 @@
self.subActionNames = []
if hasattr(self.itemFormFactory,'actions'):
for action in self.itemFormFactory.actions:
- if action.__name__ in availableActions:
- self.subActionNames.append(action.__name__)
+ name = '%s.%s' % (self.prefix,action.__name__)
+ if name in availableActions:
+ self.subActionNames.append(name)
+ def setInputMode(self,v=True):
+ if self.inputMode != v:
+ self.inputMode = v
+ for form in self.subForms.values():
+ form.form_reset=True
+
+
+ def initInputMode(self):
+ self.inputMode = self.itemFormFactory.inputMode
+ if self.inputMode is None:
+ self.inputMode = False
+ for field in self.itemFormFactory.form_fields:
+ if not field.for_display:
+ self.inputMode=True
+ break
+
+ def checkInputMode(self):
+ for action in self.itemFormFactory.actions:
+ name = '%s.%s' % (self.prefix,action.__name__)
+ if name in self.request.form and action.inputMode \
+ is not None:
+ self.setInputMode(action.inputMode)
+
+
More information about the Checkins
mailing list