fields: fix handling of optional item fields (#8737)

External data sources would add an empty element when the list was optional but
this was not the case when using the internal elements, and things were worked
around when rendering, and inserting, sometimes, the hint as a first element.

This is changed to always have an empty element as first item, and replacing it
with the hint when rendering.
This commit is contained in:
Frédéric Péters 2015-10-21 18:11:19 +02:00
parent a46d91e7d2
commit 5c21487c4c
4 changed files with 41 additions and 11 deletions

View File

@ -211,4 +211,4 @@ def test_optional_item_field_with_data_source():
field.add_to_form(form)
widget = form.get_widget('f1')
assert widget is not None
assert widget.options == [(None, '---', 'None'), ('1', 'un', '1'), ('2', 'deux', '2')]
assert widget.options == [(None, '', 'None'), ('1', 'un', '1'), ('2', 'deux', '2')]

View File

@ -146,3 +146,30 @@ def test_map():
assert fields.MapField().get_json_value(' 42.2 ; 10.2 ') == {'lat': 42.2, 'lon': 10.2}
assert fields.MapField().get_json_value('') == None
assert fields.MapField().get_json_value('foobar') == None
def test_item_render():
field = fields.ItemField(id='1', label='Foobar', items=['a', 'b', 'c'])
form = Form()
field.add_to_form(form)
assert str(form.render()).count('<option') == 3
field = fields.ItemField(id='1', label='Foobar', items=['a', 'b', 'c'],
required=False)
form = Form()
field.add_to_form(form)
assert str(form.render()).count('<option selected="selected" value="None"></option>') == 1 # None
assert str(form.render()).count('<option') == 4 # 3 + None as first item
field = fields.ItemField(id='1', label='Foobar', items=['a', 'b', 'c'],
required=False, hint='Bla bla bla')
form = Form()
field.add_to_form(form)
assert str(form.render()).count('<option value="">Bla bla bla</option>') == 1 # ---
assert str(form.render()).count('<option') == 4
field = fields.ItemField(id='1', label='Foobar', items=['a', 'b', 'c'],
required=True, hint='Bla bla bla')
form = Form()
field.add_to_form(form)
assert str(form.render()).count('<option value="">Bla bla bla</option>') == 1 # ---
assert str(form.render()).count('<option') == 4

View File

@ -858,16 +858,16 @@ class ItemField(WidgetField):
def get_options(self):
if not self.data_source:
return self.items
options = data_sources.get_items(self.data_source)
if options and not self.required:
options = self.items[:]
else:
options = data_sources.get_items(self.data_source)
if not self.required:
if type(options[0]) is str:
options[:0] = [None]
elif len(options[0]) == 2:
options[:0] = [(None, '---')]
options[:0] = [(None, '')]
elif len(options[0]) == 3:
options[:0] = [(None, '---', None)]
options[:0] = [(None, '', None)]
return options
def perform_more_widget_changes(self, form, kwargs, edit = True):

View File

@ -1361,13 +1361,16 @@ class SingleSelectHintWidget(SingleSelectWidget):
attrs = {'id': 'form_' + self.name}
if self.attrs:
attrs.update(self.attrs)
if self.separate_hint():
return SingleSelectWidget.render_content(self)
tags = [htmltag('select', name=self.name, **attrs)]
if self.hint:
options = self.options[:]
if not self.separate_hint() and self.hint:
r = htmltag('option', value='', selected=None)
tags.append(r + htmlescape(self.hint) + htmltext('</option>'))
for object, description, key in self.options:
if not self.required:
# hint has been put as first element, skip the default empty
# value.
options = self.options[1:]
for object, description, key in options:
if self.is_selected(object):
selected = 'selected'
else: