Merge "Add additional attributes to choices in ChoiceField"

This commit is contained in:
Jenkins 2014-09-25 04:01:33 +00:00 committed by Gerrit Code Review
commit 1558541985
2 changed files with 90 additions and 3 deletions

View File

@ -19,6 +19,7 @@ import netaddr
from django.core.exceptions import ValidationError # noqa
from django.core import urlresolvers
from django.forms import fields
from django.forms.util import flatatt # noqa
from django.forms import widgets
from django.utils.encoding import force_text
from django.utils.functional import Promise # noqa
@ -123,7 +124,9 @@ class MultiIPField(IPField):
class SelectWidget(widgets.Select):
"""Customizable select widget, that allows to render
data-xxx attributes from choices.
data-xxx attributes from choices. This widget also
allows user to specify additional html attributes
for choices.
.. attribute:: data_attrs
@ -137,16 +140,54 @@ class SelectWidget(widgets.Select):
A callable used to render the display value
from the option object.
.. attribute:: transform_html_attrs
A callable used to render additional HTML attributes
for the option object. It returns a dictionary
containing the html attributes and their values.
For example, to define a title attribute for the
choices:
helpText = { 'Apple': 'This is a fruit',
'Carrot': 'This is a vegetable' }
def get_title(data):
text = helpText.get(data, None)
if text:
return {'title': text}
else:
return {}
....
....
widget=forms.SelectWidget( attrs={'class': 'switchable',
'data-slug': 'source'},
transform_html_attrs=get_title )
self.fields[<field name>].choices =
([
('apple','Apple'),
('carrot','Carrot')
])
"""
def __init__(self, attrs=None, choices=(), data_attrs=(), transform=None):
def __init__(self, attrs=None, choices=(), data_attrs=(), transform=None,
transform_html_attrs=None):
self.data_attrs = data_attrs
self.transform = transform
self.transform_html_attrs = transform_html_attrs
super(SelectWidget, self).__init__(attrs, choices)
def render_option(self, selected_choices, option_value, option_label):
option_value = force_text(option_value)
other_html = (option_value in selected_choices) and \
u' selected="selected"' or ''
if callable(self.transform_html_attrs):
html_attrs = self.transform_html_attrs(option_label)
other_html += flatatt(html_attrs)
if not isinstance(option_label, (basestring, Promise)):
for data_attr in self.data_attrs:
data_value = html.conditional_escape(
@ -154,8 +195,9 @@ class SelectWidget(widgets.Select):
data_attr, "")))
other_html += ' data-%s="%s"' % (data_attr, data_value)
if self.transform:
if callable(self.transform):
option_label = self.transform(option_label)
return u'<option value="%s"%s>%s</option>' % (
html.escape(option_value), other_html,
html.conditional_escape(force_text(option_label)))

View File

@ -98,3 +98,48 @@ class FormErrorTests(test.TestCase):
self.assertEqual([error_text], self.form.non_field_errors())
resp = self._render_form()
self.assertIn(error_text, resp.content)
class TestChoiceFieldForm(forms.SelfHandlingForm):
title_dic = {"label1": {"title": "This is choice 1"},
"label2": {"title": "This is choice 2"},
"label3": {"title": "This is choice 3"}}
name = forms.CharField(max_length=255,
label="Test Name",
help_text="Please enter a name")
test_choices = forms.ChoiceField(label="Test Choices",
required=False,
help_text="Testing drop down choices",
widget=forms.fields.SelectWidget(attrs={
'class': 'switchable',
'data-slug': 'source'},
transform_html_attrs=title_dic.get))
def __init__(self, request, *args, **kwargs):
super(TestChoiceFieldForm, self).__init__(request, *args, **kwargs)
choices = ([('choice1', 'label1'),
('choice2', 'label2')])
self.fields['test_choices'].choices = choices
def handle(self, request, data):
return True
class ChoiceFieldTests(test.TestCase):
template = 'horizon/common/_form_fields.html'
def setUp(self):
super(ChoiceFieldTests, self).setUp()
self.form = TestChoiceFieldForm(self.request)
def _render_form(self):
return shortcuts.render(self.request, self.template,
{'form': self.form})
def test_choicefield_title(self):
resp = self._render_form()
self.assertContains(resp, '<option value="choice1" '
'title="This is choice 1">label1</option>', count=1, html=True)
self.assertContains(resp, '<option value="choice2" '
'title="This is choice 2">label2</option>', count=1, html=True)