[Checkins] SVN: zope3org/trunk/src/zorg/multiform/ refactored
Bernd Dorn
bernd.dorn at fhv.at
Sun Apr 9 05:05:26 EDT 2006
Log message for revision 66708:
refactored
Changed:
U zope3org/trunk/src/zorg/multiform/README.txt
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 08:55:00 UTC (rev 66707)
+++ zope3org/trunk/src/zorg/multiform/README.txt 2006-04-09 09:05:26 UTC (rev 66708)
@@ -22,10 +22,12 @@
Let us create a new multiform class which should display IOrder objects.
- >>> from multiform.multiform import MultiForm,ItemFormBase
+ >>> from multiform.multiform import MultiFormBase,ItemFormBase
>>> from zope.formlib import form
>>> class OrderForm(ItemFormBase):
+ ... form_fields = form.Fields(IOrder,omit_readonly=False,
+ ... render_context=True)
... def __call__(self, ignore_request=False):
... widgets = form.setUpWidgets(
... self.form_fields, self.prefix, self.context, self.request,
@@ -34,37 +36,124 @@
... widgets])
- >>> class OrdersForm(MultiForm):
+ >>> class OrdersForm(MultiFormBase):
...
- ... form_fields = form.Fields(IOrder)
- ...
+ ... itemFormFactory = OrderForm
... def __call__(self, ignore_request=False):
- ... self.setUpForms()
+ ... self.setUpWidgets()
... res = u''
- ... for form in self.forms.values():
- ... res += '<div>%s</div>\n' % form(ignore_request=True)
+ ... names = sorted(self.subForms.keys())
+ ... for name in names:
+ ... res += '<div>%s</div>\n' % self.subForms[name](
+ ... ignore_request=ignore_request)
... return res
...
- ... def itemForm(self, item, **kwargs):
- ... return OrderForm(item, self, **kwargs)
-
-
>>> from zope.publisher.browser import TestRequest
>>> request = TestRequest()
>>> view = OrdersForm(orderMapping, request)
>>> print view()
<div>
- <div>1</div><div>n1</div>
+ <div>0</div><div><input ... name="form.0.name" ... value="n0" ...</div>
</div>
<div>
...
+ </div>
+
+If the request contains any form data, that will be reflected in the
+output:
+
+ >>> request.form['form.1.name'] = u'bob'
+ >>> print OrdersForm(orderMapping,request)()
<div>
- <div>4</div><div>n4</div>
+ ...
+ <div>1</div><div><input ... name="form.1.name" ... value="bob" ...</div>
+ ...
</div>
+Sometimes we don't want this behavior: we want to ignore the request values,
+particularly after a form has been processed and before it is drawn again.
+This can be accomplished with the 'ignore_request' argument in
+setUpWidgets.
+ >>> print OrdersForm(orderMapping, request)(ignore_request=True)
+ <div>
+ ...
+ <div>1</div><div><input ... name="form.1.name" ... value="n1" ...</div>
+ ...
+ </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)
+ ... def update(self):
+ ... super(OrderForm2,self).update()
+ ...
+ ... @multiform.parentAction(u"Save")
+ ... def handle_save_action(self, action, data):
+ ... form.applyChanges(self.context, self.form_fields,
+ ... data, self.adapters)
+ ... def render(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(OrdersForm):
+ ... itemFormFactory=OrderForm2
+ ... def __call__(self, ignore_request=False):
+ ... self.setUpWidgets()
+ ... res = u''
+ ... names = sorted(self.subForms.keys())
+ ... for name in names:
+ ... res += '<div>%s</div>\n' % self.subForms[name]()
+ ... return res
+
+
+
+ >>> pf = OrdersForm2(orderMapping,request)
+ >>> pf.setUpWidgets()
+ >>> action = [action for action in pf.subForms['1'].actions][0]
+ >>> action
+ <multiform.multiform.ParentAction object at ...>
+
+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>
+
+
+
TODO:
- encode prefix, do we have to do it?
Modified: zope3org/trunk/src/zorg/multiform/multiform.py
===================================================================
--- zope3org/trunk/src/zorg/multiform/multiform.py 2006-04-09 08:55:00 UTC (rev 66707)
+++ zope3org/trunk/src/zorg/multiform/multiform.py 2006-04-09 09:05:26 UTC (rev 66708)
@@ -5,292 +5,77 @@
from zope.app.form.browser.interfaces import IWidgetInputErrorView
from zope.formlib import form
+from zope.formlib.interfaces import IBoundAction
from zope.formlib.i18n import _
from interfaces import IMultiForm
+from zope import interface
-def availableActions(form, actions):
- result = []
- for action in actions:
- if not action.label in form.table.config.actions:
- continue
- condition = action.condition
- if condition is not None:
- if not condition(form, action):
- continue
- result.append(action)
- return result
+class ParentAction(form.Action):
+ """an action that is rendered in the parent multiform object and
+ is applied to all subForms"""
-class TableAction(form.Action):
+ 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__
+ interface.alsoProvides(result, IBoundAction)
+ return result
- def render(self):
-# if self.label in self.form.table.config.actions and \
-# not self.form.table.config.actions[self.label].isLocal:
-# return super(TableAction,self).render()
-# else:
-# return ""
- return super(TableAction,self).render()
+ 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
-class RowAction(form.Action):
+class parentAction(form.action):
- def render(self):
-# if self.label in self.form.table.config.actions and \
-# self.form.table.config.actions[self.label].isLocal:
-# return super(RowAction,self).render()
-# else:
-# return ""
- return super(RowAction,self).render()
-
-
-class rowAction(form.action):
-
def __call__(self, success):
- action = RowAction(self.label, success=success, **self.options)
+ action = ParentAction(self.label, success=success, **self.options)
self.actions.append(action)
return action
-class tableAction(form.action):
-
- def __call__(self, success):
- action = TableAction(self.label, success=success, **self.options)
- self.actions.append(action)
- return action
-
-
-def isRowEditMode(form, action):
- return form.mode == 'edit' and action.label in form.table.config.actions and form.row.selected
-
-
-def isRowDisplayMode(form, action):
- return form.mode == 'display' and action.label in form.table.config.actions
-
-
class ItemFormBase(form.FormBase):
- newmode = None
+ parentForm = None
- def __init__(self, item, multiForm, **kwargs):
- super(ItemFormBase,self).__init__(item,
- multiForm.request)
- self.multiForm = multiForm
- self.baseRow_actions = form.Actions()
+ def __init__(self,context,request,parentForm):
+ super(ItemFormBase,self).__init__(context,request)
+ self.parentForm=parentForm
- # build up form_fields
- # kwargs includes form relevant parameters
- self.form_fields = form.Fields()
- for field in self.multiForm.form_fields:
- isDisplay = not(self.multiForm.mode == 'edit' and self.isSelected())
- fieldkwargs = {}
- fieldkwargs['for_display'] = isDisplay
- # XXX why is render_context not set?
- fieldkwargs['render_context'] = True
- if not isDisplay and field.widget is not None:
- fieldkwargs['custom_widget'] = field.widget
- self.form_fields = self.form_fields + form.Fields(
- form.Field(field.field, **fieldkwargs),**kwargs)
- def isSelected(self):
+class MultiFormBase(form.FormBase):
- # XXX implement this, default is selected
- return True
-
- def actions():
- def _getActions(self):
- return self.baseRow_actions
- return property(_getActions)
-
- actions = actions()
- def availableActions(self, actions=None):
- if actions is not None:
- return availableActions(self, actions)
- else:
- return availableActions(self, self.actions)
+ itemFormFactory = ItemFormBase
+ subForms={}
+ form_fields = []
- def setUpWidgets(self, ignore_request=False):
- self.adapters = {}
- self.widgets = form.setUpEditWidgets(
- self.form_fields, self.prefix, self.context, self.request,
- adapters=self.adapters, ignore_request=ignore_request
- )
+ def update(self):
+ super(MultiFormBase,self).update()
+ for form in self.subForms.values():
+ form.update()
-def isFormEditMode(form, action):
- return form.mode == 'edit' and action.label in form.table.config.actions
+ def setUpWidgets(self, *args, **kw):
+ super(MultiFormBase,self).setUpWidgets(*args,**kw)
+ self.subForms = {}
+ self.setUpForms(*args, **kw)
-
-def isFormDisplayMode(form, action):
- return form.mode == 'display' and action.label in form.table.config.actions
-
-
-
-
-class MultiForm(BrowserView):
-
- implements(IMultiForm)
-
- label = u''
-
- prefix = ''
-
- status = ''
-
- errors = ()
-
- forms = {}
-
- mode = 'display'
-
- newmode = None
-
- actions =[]
-
- selectionField = ISelectable(['isSelected'])
-
- def availableActions(self, actions=None):
- if actions is not None:
- return availableActions(self, actions)
- else:
- return availableActions(self, self.actions)
-
- def setPrefix(self, prefix):
- self.prefix = prefix
-
- def checkEditMode(self, prefix):
- if "%s.actions.apply" % prefix in self.request.form:
- self.mode = 'edit'
-
- def setNewMode(self):
- if self.newmode is not None:
- self.mode = self.newmode
- self.newmode = None
- self.form_reset = True
-
- def itemForm(self, item, **kwargs):
- return ItemFormBase(item, self, **kwargs)
-
- def setUpForms(self, ignore_request=False):
- self.forms = {}
- # the context must implement IReadMapping
+ def setUpForms(self, *args, **kw):
for name,item in self.context.items():
- itemPrefix = self.prefix and self.prefix+'.' or '' + name
- if not ignore_request:
- # check edit mode with row actions
- self.checkEditMode(itemPrefix)
- kwargs = {
- 'omit_readonly':False,
- 'render_context':True,
- 'fields':self.form_fields}
- self.forms[name] = self.itemForm(item, **kwargs)
- self.forms[name].setPrefix(itemPrefix)
+ prefix = (self.prefix and self.prefix+'.' or '') + name
+ subForm = self.itemFormFactory(item,self.request,self)
+ subForm.setPrefix(prefix)
+ subForm.setUpWidgets(*args, **kw)
+ self.subForms[name] = subForm
-
- def resetForm(self):
- self.setUpForms(ignore_request=True)
- for fo in self.forms.values():
- fo.resetForm()
- def validate(self, action, data):
- # XXX implement this
-# return (getFormsData(self.widgets, self.prefix, data)
-# + checkInvariants(self.form_fields, data))
- return ()
-
-# def availableActions(self):
-# return availableActions(self, self.actions)
-
- form_result = None
- form_reset = True
-
- def update(self):
- # check edit mode with table actions
- self.checkEditMode(self.prefix)
-
- self.setUpForms()
- self.form_reset = False
-
- data = {}
- errors, action = form.handleSubmit(self.actions, data, self.validate)
- self.errors = errors
-
- if errors:
- self.status = _('There were errors')
- result = action.failure(data, errors)
- elif errors is not None:
- result = action.success(data)
- else:
- result = None
-# result = None
-
- self.form_result = result
-
- if not errors:
- for fo in self.forms.values():
- fo.update()
- if fo.errors:
- self.errors = list(self.errors) + list(fo.errors)
- self.form_reset = self.form_reset or fo.form_reset
- if fo.newmode is not None:
- self.newmode = fo.newmode
-
- if self.errors:
- self.status = _('There were errors')
- self.form_reset = False
- self.newmode = None
-
- # if actions toggle the mode
- self.setNewMode()
-
- if self.form_reset:
- # build up new forms
- self.resetForm()
- form_reset = False
-
- def error_views(self):
- for error in self.errors:
- if isinstance(error, basestring):
- yield error
- else:
- view = zapi.getMultiAdapter(
- (error, self.request),
- IWidgetInputErrorView)
- title = getattr(error, 'widget_title', None) # XXX duck typing
- if title:
- yield '%s: %s' % (title, view.snippet())
- else:
- yield view.snippet()
-
- def handOverAction(self, name, label):
- """hand over action table action to row actions with same name, label
- of all selected rows."""
- selected = False
- for formName,fo in self.forms.values():
- if self.isSelected(formName):
- # hand over submit of action to all forms
- action = "%s.actions.%s" % (fo.prefix, name)
- self.request.form[action] = label
- selected = True
- return selected
-
- def __call__(self):
- self.update()
- return self.render()
-
-
- def isSelected(self,name):
- # XXX get from request
- return False
-
- def render(self):
- # if the form has been updated, it will already have a result
- if self.form_result is None:
- if self.form_reset:
- # we reset, in case data has changed in a way that
- # causes the widgets to have different data
- self.resetForm()
- self.form_reset = False
- self.form_result = self.template()
- return self.form_result
More information about the Checkins
mailing list