Commit 2c74e408 by Julien Muchembled

ERP5Form: FormBox improvements

A Form is rendered by assuming the REQUEST is clean and first set 'here' as
the context. Then there may be listboxes with rely on 'here' and set 'cell'
temporarily. At last, for easier configuration of listbox fields, 'cell' has
precedence over 'here' when rendering (in particular since
commit 4fa84233).

Based on this, the only sane solution is to
- clean up the REQUEST (remove 'here' and 'cell')
- render the FormBox in the new context (which sets 'here'): inside a ListBox,
  the context is the cell
- restore 'here' and 'cell' as they were

Which allows FormBox/ListBox inside FormBox/ListBox, recursively
(but obviously no ListBox inside ListBox).

The previous code didn't work in the following case:
- a Order Line and Packing List Line having an identical tab
- the left pane for Order Line information
- the other for Packing List Line information
  (-> empty when there's no related PL)
- a listbox (with subobjects of the PL line)
Which is implemented as follows:
- a Form for the left pane
- a Form for the Packing List Line, with a FormBox
  (to display Order information) and a ListBox
- the Form for the Order Line only has a FormBox, that uses 1 of the 2 other
  Forms depending on the presence of a PL (if there's one, it's rendered in the
  context of the PL)
-> FormBox(FormBox, ListBox)

As you can see, FormBox is used here to factorize forms. Without this patch:
- the outter FormBox crashed on `del REQUEST.other['cell']`
- the inner FormBox was rendered with a wrong 'cell'

Another change is to pass the field & REQUEST to the context method.
1 parent a9f9e660
......@@ -43,8 +43,6 @@ from Products.Formulator.Errors import FormValidationError, ValidationError
import string
class FormBoxWidget(Widget.Widget):
A widget that display a form within a form.
......@@ -93,50 +91,33 @@ class FormBoxWidget(Widget.Widget):
def render(self, field, key, value, REQUEST, render_prefix=None):
Render a form in a field
return self._render(field, key, value, REQUEST, render_prefix=render_prefix)
def render_view(self, field, value, REQUEST, render_prefix=None):
Render a view form in a field
return self._render(field, None, value, REQUEST, render_prefix=render_prefix)
return self.render(field, None, value, REQUEST, render_prefix)
def _render(self, field, key, value, REQUEST, render_prefix=None):
result = ''
def render(self, field, key, value, REQUEST, render_prefix=None):
Render a form in a field
target_id = field.get_value('formbox_target_id')
if target_id not in (None, ''):
here = REQUEST['here']
if target_id:
other = REQUEST.other
here = other['here']
context_method_id = field.get_value('context_method_id')
if context_method_id:
REQUEST['original_context'] = original_here = here
REQUEST['here'] = here = getattr(here, context_method_id)()
# If 'cell' is not defined, we define 'cell' just same as 'here', so
# that we can use the same formbox for both ListBox and non-ListBox
# using 'cell' parameter.
if not REQUEST.has_key('cell'):
set_cell = True
REQUEST.set('cell', here)
set_cell = False
form = getattr(here, target_id)
except AttributeError:
'Could not get a form from formbox %s in %s' % \
result = form(REQUEST=REQUEST, key_prefix=key)
cell = other.pop('cell', None)
context = cell or here
if context_method_id:
REQUEST['here'] = original_here
del REQUEST.other['original_context']
if set_cell:
del REQUEST.other['cell']
return result
context = getattr(context, context_method_id)(
field=field, REQUEST=REQUEST)
return getattr(context, target_id)(REQUEST=REQUEST, key_prefix=key)
other['here'] = here
if cell:
other['cell'] = cell
return ''
class FormBoxEditor:
......@@ -186,10 +167,12 @@ class FormBoxValidator(Validator.Validator):
def validate(self, field, key, REQUEST):
# XXX hardcoded acquisition
# TODO: Handle 'cell' for validation inside listboxes,
# like it is done for rendering.
here = field.aq_parent.aq_parent
context_method_id = field.get_value('context_method_id')
if context_method_id:
here = getattr(here, context_method_id)()
here = getattr(here, context_method_id)(field=field, REQUEST=REQUEST)
formbox_target_id = field.get_value('formbox_target_id')
# Get current error fields
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!