Commit ba489a0f authored by Julien Muchembled's avatar Julien Muchembled

Fix {Field,Widget}.render_view API so that Listbox's non-editable cells can access 'cell' in TALES:

 * add a 'REQUEST=None' parameter to every render_view method:
   * new patches in FormulatorPatch to fix render_view of Field, Widget,
     MultiItemsWidget, LabelWidget, FileWidget, PasswordWidget and RadioWidget
   * reorder parameters in OOoChartWidget.render_view
   * add a 'REQUEST=None' parameter to DurationField.render_sub_field_view
 * forward REQUEST to field.get_value in:
   * ListWidget_render_view (my goal)
   * TALESWidget_render_view (why not?)
 * PatchedLinkWidget.render_view and
   MultiRelationStringFieldWidget.render_view
   needn't call get_request anymore if REQUEST isn't None
 * PatchedLinkWidget.render_view: change REQUEST.get('cell') into
   getattr(REQUEST,'cell',None) since 'cell' may be an attribute of REQUEST
 * add a unit test to check the signature of all registered fields/widgets

git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@21048 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent 78c28403
...@@ -64,7 +64,7 @@ class DurationWidget(FormulatorPatch.IntegerWidget): ...@@ -64,7 +64,7 @@ class DurationWidget(FormulatorPatch.IntegerWidget):
default="", default="",
required=1) required=1)
def render_view(self, field, value): def render_view(self, field, value, REQUEST=None):
sub_field_render_list = [] sub_field_render_list = []
for title, sub_key, convertion in (('Hour', 'hour', HOUR_IN_SECOND), for title, sub_key, convertion in (('Hour', 'hour', HOUR_IN_SECOND),
('Minute', 'minute', MINUTE_IN_SECOND)): ('Minute', 'minute', MINUTE_IN_SECOND)):
...@@ -74,10 +74,10 @@ class DurationWidget(FormulatorPatch.IntegerWidget): ...@@ -74,10 +74,10 @@ class DurationWidget(FormulatorPatch.IntegerWidget):
sub_value, value = divmod(value, convertion) sub_value, value = divmod(value, convertion)
sub_field_render_list.append(self.render_sub_field_view( sub_field_render_list.append(self.render_sub_field_view(
field,sub_value)) field,sub_value, REQUEST))
# Render second # Render second
sub_field_render_list.append(self.render_sub_field_view( sub_field_render_list.append(self.render_sub_field_view(
field, value)) field, value, REQUEST))
return ':'.join(sub_field_render_list) return ':'.join(sub_field_render_list)
def render(self, field, key, value, REQUEST): def render(self, field, key, value, REQUEST):
...@@ -97,12 +97,12 @@ class DurationWidget(FormulatorPatch.IntegerWidget): ...@@ -97,12 +97,12 @@ class DurationWidget(FormulatorPatch.IntegerWidget):
value, REQUEST, 'second')) value, REQUEST, 'second'))
return ':'.join(sub_field_render_list) return ':'.join(sub_field_render_list)
def render_sub_field_view(self, field, value): def render_sub_field_view(self, field, value, REQUEST=None):
""" """
Render dynamically a subfield Render dynamically a subfield
""" """
return FormulatorPatch.IntegerFieldWidgetInstance.render_view(field, return FormulatorPatch.IntegerFieldWidgetInstance.render_view(field, value,
value) REQUEST)
def render_sub_field(self, field, key, value, REQUEST, keyword): def render_sub_field(self, field, key, value, REQUEST, keyword):
""" """
......
...@@ -87,7 +87,7 @@ class EditorWidget(Widget.TextAreaWidget): ...@@ -87,7 +87,7 @@ class EditorWidget(Widget.TextAreaWidget):
'inputname' : key 'inputname' : key
}) })
def render_view(self, field, value): def render_view(self, field, value, REQUEST=None):
""" """
Render form in view only mode. Render form in view only mode.
""" """
......
...@@ -68,6 +68,11 @@ def Field_render(self, value=None, REQUEST=None, key=None): ...@@ -68,6 +68,11 @@ def Field_render(self, value=None, REQUEST=None, key=None):
""" """
return self._render_helper(self.generate_field_key(key=key), value, REQUEST) return self._render_helper(self.generate_field_key(key=key), value, REQUEST)
def Field_render_view(self, value=None, REQUEST=None):
"""Render value to be viewed.
"""
return self.widget.render_view(self, value, REQUEST)
def Field_render_sub_field(self, id, value=None, REQUEST=None, key=None): def Field_render_sub_field(self, id, value=None, REQUEST=None, key=None):
"""Render a sub field, as part of complete rendering of widget in """Render a sub field, as part of complete rendering of widget in
a form. Works like render() but for sub field. a form. Works like render() but for sub field.
...@@ -98,7 +103,7 @@ def Field_render_helper(self, key, value, REQUEST): ...@@ -98,7 +103,7 @@ def Field_render_helper(self, key, value, REQUEST):
if self.get_value('hidden', REQUEST=REQUEST): if self.get_value('hidden', REQUEST=REQUEST):
return self.widget.render_hidden(self, key, value, REQUEST) return self.widget.render_hidden(self, key, value, REQUEST)
elif (not self.get_value('editable', REQUEST=REQUEST)): elif (not self.get_value('editable', REQUEST=REQUEST)):
return self.widget.render_view(self, value) return self.widget.render_view(self, value, REQUEST)
else: else:
return self.widget.render(self, key, value, REQUEST) return self.widget.render(self, key, value, REQUEST)
...@@ -113,6 +118,7 @@ def Field_render_odf(self, field=None, key=None, value=None, REQUEST=None, rende ...@@ -113,6 +118,7 @@ def Field_render_odf(self, field=None, key=None, value=None, REQUEST=None, rende
Field.generate_field_key = Field_generate_field_key Field.generate_field_key = Field_generate_field_key
Field.render = Field_render Field.render = Field_render
Field.render_view = Field_render_view
Field.render_sub_field = Field_render_sub_field Field.render_sub_field = Field_render_sub_field
Field.generate_subfield_key = Field_generate_subfield_key Field.generate_subfield_key = Field_generate_subfield_key
Field.validate_sub_field = Field_validate_sub_field Field.validate_sub_field = Field_validate_sub_field
...@@ -307,7 +313,7 @@ def CheckBoxWidget_render(self, field, key, value, REQUEST): ...@@ -307,7 +313,7 @@ def CheckBoxWidget_render(self, field, key, value, REQUEST):
CheckBoxWidget.render = CheckBoxWidget_render CheckBoxWidget.render = CheckBoxWidget_render
def CheckBoxWidget_render_view(self, field, value): def CheckBoxWidget_render_view(self, field, value, REQUEST=None):
"""Render checkbox in view mode. """Render checkbox in view mode.
""" """
if value: if value:
...@@ -332,26 +338,28 @@ from Products.Formulator.StandardFields import LinkField ...@@ -332,26 +338,28 @@ from Products.Formulator.StandardFields import LinkField
from Globals import get_request from Globals import get_request
from urlparse import urljoin from urlparse import urljoin
class PatchedLinkWidget(TextWidget) : class PatchedLinkWidget(TextWidget):
def render_view(self, field, value) : def render_view(self, field, value, REQUEST=None):
"""Render link. """Render link.
""" """
link_type = field.get_value('link_type', REQUEST=REQUEST)
if REQUEST is None:
REQUEST = get_request() REQUEST = get_request()
link_type = field.get_value('link_type')
if link_type == 'internal': if link_type == 'internal':
value = urljoin(REQUEST['BASE0'], value) value = urljoin(REQUEST['BASE0'], value)
elif link_type == 'relative': elif link_type == 'relative':
value = urljoin(REQUEST['URL1'], value) value = urljoin(REQUEST['URL1'], value)
return '<a href="%s">%s</a>' % (value, field.get_value('title', cell=REQUEST.get('cell'))) return '<a href="%s">%s</a>' % (value,
field.get_value('title', cell=getattr(REQUEST,'cell',None)))
PatchedLinkWidgetInstance = PatchedLinkWidget() PatchedLinkWidgetInstance = PatchedLinkWidget()
LinkField.widget = PatchedLinkWidgetInstance LinkField.widget = PatchedLinkWidgetInstance
# Patch the render_view of TextField to enclose the value within <span> html tags if css class defined # Patch the render_view of TextField to enclose the value within <span> html tags if css class defined
def TextWidget_patched_render_view(self, field, value): def TextWidget_patched_render_view(self, field, value, REQUEST=None):
"""Render text as non-editable. """Render text as non-editable.
This renderer is designed to be type error resistant. This renderer is designed to be type error resistant.
in we get a non string value. It does escape the result in we get a non string value. It does escape the result
...@@ -405,11 +413,11 @@ class IntegerWidget(TextWidget) : ...@@ -405,11 +413,11 @@ class IntegerWidget(TextWidget) :
size=field.get_value('display_width'), size=field.get_value('display_width'),
extra=field.get_value('extra')) extra=field.get_value('extra'))
def render_view(self, field, value): def render_view(self, field, value, REQUEST=None):
"""Render a non-editable interger.""" """Render a non-editable interger."""
if isinstance(value, float): if isinstance(value, float):
value = int(value) value = int(value)
return TextWidget.render_view(self, field, value) return TextWidget.render_view(self, field, value, REQUEST)
from Products.Formulator.StandardFields import IntegerField from Products.Formulator.StandardFields import IntegerField
...@@ -487,9 +495,17 @@ def Widget_render_hidden(self, field, key, value, REQUEST): ...@@ -487,9 +495,17 @@ def Widget_render_hidden(self, field, key, value, REQUEST):
extra=extra) extra=extra)
return result return result
def Widget_render_view(self, field, value, REQUEST=None):
"""Renders this widget for public viewing.
"""
# default implementation
if value is None:
return ''
return value
Widget.render_hidden = Widget_render_hidden Widget.render_hidden = Widget_render_hidden
# default render_pdf for a Widget # default render_pdf for a Widget
Widget.render_pdf = Widget.render_view Widget.render_pdf = Widget.render_view = Widget_render_view
def Widget_render_css(self, field, REQUEST): def Widget_render_css(self, field, REQUEST):
""" """
...@@ -518,6 +534,17 @@ def Widget_get_javascript_list(self, field, REQUEST): ...@@ -518,6 +534,17 @@ def Widget_get_javascript_list(self, field, REQUEST):
return [] return []
Widget.get_javascript_list = Widget_get_javascript_list Widget.get_javascript_list = Widget_get_javascript_list
from Products.Formulator import Widget as WidgetModule
for widget_name in ('MultiItemsWidget', 'LabelWidget',
'FileWidget', 'PasswordWidget', 'RadioWidget'):
widget = getattr(WidgetModule, widget_name)
widget._old_render_view = widget.render_view
widget.render_view = lambda self, field, value, REQUEST=None: \
self._old_render_view(field, value)
from Products.Formulator.Validator import LinesValidator from Products.Formulator.Validator import LinesValidator
def LinesValidator_validate(self, field, key, REQUEST): def LinesValidator_validate(self, field, key, REQUEST):
...@@ -747,14 +774,14 @@ def ListWidget_render(self, field, key, value, REQUEST): ...@@ -747,14 +774,14 @@ def ListWidget_render(self, field, key, value, REQUEST):
return "\n".join([list_widget, input_hidden]) return "\n".join([list_widget, input_hidden])
def ListWidget_render_view(self, field, value): def ListWidget_render_view(self, field, value, REQUEST=None):
""" """
This method is not as efficient as using a StringField in read only. This method is not as efficient as using a StringField in read only.
Always consider to change the field in your Form. Always consider to change the field in your Form.
""" """
if value is None: if value is None:
return '' return ''
title_list = [x[0] for x in field.get_value("items") if x[1]==value] title_list = [x[0] for x in field.get_value("items", REQUEST=REQUEST) if x[1]==value]
if len(title_list) == 0: if len(title_list) == 0:
return "??? (%s)" % value return "??? (%s)" % value
else: else:
...@@ -986,7 +1013,7 @@ class PatchedDateTimeWidget(DateTimeWidget): ...@@ -986,7 +1013,7 @@ class PatchedDateTimeWidget(DateTimeWidget):
else: else:
return date_result return date_result
def render_view(self, field, value): def render_view(self, field, value, REQUEST=None):
return self.format_value(field, value, mode='html') return self.format_value(field, value, mode='html')
def render_pdf(self, field, value): def render_pdf(self, field, value):
...@@ -1324,7 +1351,7 @@ class FloatWidget(TextWidget): ...@@ -1324,7 +1351,7 @@ class FloatWidget(TextWidget):
**extra_keys) **extra_keys)
def render_view(self, field, value): def render_view(self, field, value, REQUEST=None):
""" """
Render Float display field. Render Float display field.
This patch add: This patch add:
...@@ -1497,12 +1524,12 @@ Field.get_javascript_list = Field_get_javascript_list ...@@ -1497,12 +1524,12 @@ Field.get_javascript_list = Field_get_javascript_list
from Products.Formulator.TALESField import TALESWidget from Products.Formulator.TALESField import TALESWidget
def TALESWidget_render_view(self, field, value): def TALESWidget_render_view(self, field, value, REQUEST=None):
""" """
Render TALES as read only Render TALES as read only
""" """
if value == None: if value == None:
text = field.get_value('default') text = field.get_value('default', REQUEST=REQUEST)
else: else:
if value != "": if value != "":
text = value._text text = value._text
...@@ -1559,7 +1586,7 @@ def LinesTextAreaWidget_render(self, field, key, value, REQUEST): ...@@ -1559,7 +1586,7 @@ def LinesTextAreaWidget_render(self, field, key, value, REQUEST):
LinesTextAreaWidget.render = LinesTextAreaWidget_render LinesTextAreaWidget.render = LinesTextAreaWidget_render
original_LinesTextAreaWidget_render_view = LinesTextAreaWidget.render_view original_LinesTextAreaWidget_render_view = LinesTextAreaWidget.render_view
def LinesTextAreaWidget_render_view(self, field, value): def LinesTextAreaWidget_render_view(self, field, value, REQUEST=None):
if isinstance(value, (str, unicode)): if isinstance(value, (str, unicode)):
value = [value] value = [value]
return original_LinesTextAreaWidget_render_view(self, field, value) return original_LinesTextAreaWidget_render_view(self, field, value)
......
...@@ -69,9 +69,9 @@ class ImageFieldWidget(Widget.TextWidget): ...@@ -69,9 +69,9 @@ class ImageFieldWidget(Widget.TextWidget):
def render(self, field, key, value, REQUEST): def render(self, field, key, value, REQUEST):
"""Render image field as a link to the image """Render image field as a link to the image
""" """
return self.render_view(field, value) return self.render_view(field, value, REQUEST)
def render_view(self, field, value): def render_view(self, field, value, REQUEST=None):
"""Render image field as a link to the image """Render image field as a link to the image
""" """
# Url is already defined in value # Url is already defined in value
......
...@@ -287,14 +287,15 @@ class MultiRelationStringFieldWidget(Widget.LinesTextAreaWidget, ...@@ -287,14 +287,15 @@ class MultiRelationStringFieldWidget(Widget.LinesTextAreaWidget,
REQUEST.set('_v_relation_field_index', relation_field_index + 1) REQUEST.set('_v_relation_field_index', relation_field_index + 1)
return html_string return html_string
def render_view(self, field, value): def render_view(self, field, value, REQUEST=None):
""" """
Render read only field. Render read only field.
XXX Improved rendering required XXX Improved rendering required
""" """
html_string = self.default_widget_rendering_instance.render_view( html_string = self.default_widget_rendering_instance.render_view(
field, value) field, value, REQUEST)
if REQUEST is None:
REQUEST = get_request() REQUEST = get_request()
relation_html_string = self.render_relation_link(field, value, REQUEST) relation_html_string = self.render_relation_link(field, value, REQUEST)
if relation_html_string != '': if relation_html_string != '':
......
...@@ -378,7 +378,7 @@ class OOoChartWidget(Widget.Widget): ...@@ -378,7 +378,7 @@ class OOoChartWidget(Widget.Widget):
return extra_argument_dict return extra_argument_dict
def render_view(self, field, value, key=None, REQUEST=None, render_format='html'): def render_view(self, field, value, REQUEST=None, key=None, render_format='html'):
""" """
Render a Chart in read-only. Render a Chart in read-only.
""" """
......
...@@ -259,7 +259,7 @@ class POSBoxWidget(Widget.Widget): ...@@ -259,7 +259,7 @@ class POSBoxWidget(Widget.Widget):
resource_category_fastResourceEntry = field.get_value('resource_category_fastResourceEntry') resource_category_fastResourceEntry = field.get_value('resource_category_fastResourceEntry')
) )
def render_view(self, field, value): def render_view(self, field, value, REQUEST=None):
""" """
Render point of sales widget Render point of sales widget
""" """
......
...@@ -145,7 +145,7 @@ class ParallelListWidget(Widget.MultiListWidget, ...@@ -145,7 +145,7 @@ class ParallelListWidget(Widget.MultiListWidget,
result = self.sub_widget[sub_field_property_dict['field_type']].render_view( result = self.sub_widget[sub_field_property_dict['field_type']].render_view(
field, field,
sub_field_property_dict['value'], sub_field_property_dict['value'],
) REQUEST)
for parameter in ('title', 'required', 'size', 'default', 'first_item', for parameter in ('title', 'required', 'size', 'default', 'first_item',
'items'): 'items'):
# As it doesn't seem possible to delete value in the REQUEST, # As it doesn't seem possible to delete value in the REQUEST,
......
...@@ -51,6 +51,7 @@ from Testing import ZopeTestCase ...@@ -51,6 +51,7 @@ from Testing import ZopeTestCase
ZopeTestCase.installProduct('ERP5Form') ZopeTestCase.installProduct('ERP5Form')
from Acquisition import aq_base from Acquisition import aq_base
from Products.Formulator.FieldRegistry import FieldRegistry
from Products.Formulator.StandardFields import FloatField from Products.Formulator.StandardFields import FloatField
from Products.Formulator.StandardFields import StringField from Products.Formulator.StandardFields import StringField
from Products.Formulator.StandardFields import DateTimeField from Products.Formulator.StandardFields import DateTimeField
...@@ -65,6 +66,23 @@ from Products.ERP5Form import Form ...@@ -65,6 +66,23 @@ from Products.ERP5Form import Form
from Products.ERP5Form import ProxyField from Products.ERP5Form import ProxyField
class TestRenderViewAPI(unittest.TestCase):
"""For all fields and widgets, tests the signature of the render_view method.
In particular, render_view must accept a 'REQUEST' parameter after 'value'.
"""
def getTitle(self):
return "{Field,Widget}.render_view"
def test_signature(self):
for field in FieldRegistry.get_field_classes().itervalues():
self.assertEquals(('self', 'value', 'REQUEST'),
field.render_view.im_func.func_code.co_varnames)
if field is not ProxyField.ProxyField:
self.assertEquals(('self', 'field', 'value', 'REQUEST'),
field.widget.render_view.im_func.func_code.co_varnames[:4])
class TestFloatField(unittest.TestCase): class TestFloatField(unittest.TestCase):
"""Tests Float field """Tests Float field
""" """
...@@ -515,6 +533,7 @@ def makeDummyOid(): ...@@ -515,6 +533,7 @@ def makeDummyOid():
def test_suite(): def test_suite():
suite = unittest.TestSuite() suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestRenderViewAPI))
suite.addTest(unittest.makeSuite(TestFloatField)) suite.addTest(unittest.makeSuite(TestFloatField))
suite.addTest(unittest.makeSuite(TestStringField)) suite.addTest(unittest.makeSuite(TestStringField))
suite.addTest(unittest.makeSuite(TestProxyField)) suite.addTest(unittest.makeSuite(TestProxyField))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment