Skip to content

Commit 1558541

Browse files
Jenkinsopenstack-gerrit
Jenkins
authored andcommitted
Merge "Add additional attributes to choices in ChoiceField"
2 parents ffff280 + 7dc3c56 commit 1558541

File tree

2 files changed

+90
-3
lines changed

2 files changed

+90
-3
lines changed

horizon/forms/fields.py

+45-3
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from django.core.exceptions import ValidationError # noqa
2020
from django.core import urlresolvers
2121
from django.forms import fields
22+
from django.forms.util import flatatt # noqa
2223
from django.forms import widgets
2324
from django.utils.encoding import force_text
2425
from django.utils.functional import Promise # noqa
@@ -123,7 +124,9 @@ def clean(self, value):
123124

124125
class SelectWidget(widgets.Select):
125126
"""Customizable select widget, that allows to render
126-
data-xxx attributes from choices.
127+
data-xxx attributes from choices. This widget also
128+
allows user to specify additional html attributes
129+
for choices.
127130
128131
.. attribute:: data_attrs
129132
@@ -137,25 +140,64 @@ class SelectWidget(widgets.Select):
137140
138141
A callable used to render the display value
139142
from the option object.
143+
144+
.. attribute:: transform_html_attrs
145+
146+
A callable used to render additional HTML attributes
147+
for the option object. It returns a dictionary
148+
containing the html attributes and their values.
149+
For example, to define a title attribute for the
150+
choices:
151+
152+
helpText = { 'Apple': 'This is a fruit',
153+
'Carrot': 'This is a vegetable' }
154+
155+
def get_title(data):
156+
text = helpText.get(data, None)
157+
if text:
158+
return {'title': text}
159+
else:
160+
return {}
161+
162+
....
163+
....
164+
165+
widget=forms.SelectWidget( attrs={'class': 'switchable',
166+
'data-slug': 'source'},
167+
transform_html_attrs=get_title )
168+
169+
self.fields[<field name>].choices =
170+
([
171+
('apple','Apple'),
172+
('carrot','Carrot')
173+
])
140174
"""
141-
def __init__(self, attrs=None, choices=(), data_attrs=(), transform=None):
175+
def __init__(self, attrs=None, choices=(), data_attrs=(), transform=None,
176+
transform_html_attrs=None):
142177
self.data_attrs = data_attrs
143178
self.transform = transform
179+
self.transform_html_attrs = transform_html_attrs
144180
super(SelectWidget, self).__init__(attrs, choices)
145181

146182
def render_option(self, selected_choices, option_value, option_label):
147183
option_value = force_text(option_value)
148184
other_html = (option_value in selected_choices) and \
149185
u' selected="selected"' or ''
186+
187+
if callable(self.transform_html_attrs):
188+
html_attrs = self.transform_html_attrs(option_label)
189+
other_html += flatatt(html_attrs)
190+
150191
if not isinstance(option_label, (basestring, Promise)):
151192
for data_attr in self.data_attrs:
152193
data_value = html.conditional_escape(
153194
force_text(getattr(option_label,
154195
data_attr, "")))
155196
other_html += ' data-%s="%s"' % (data_attr, data_value)
156197

157-
if self.transform:
198+
if callable(self.transform):
158199
option_label = self.transform(option_label)
200+
159201
return u'<option value="%s"%s>%s</option>' % (
160202
html.escape(option_value), other_html,
161203
html.conditional_escape(force_text(option_label)))

horizon/test/tests/forms.py

+45
Original file line numberDiff line numberDiff line change
@@ -98,3 +98,48 @@ def test_api_error(self):
9898
self.assertEqual([error_text], self.form.non_field_errors())
9999
resp = self._render_form()
100100
self.assertIn(error_text, resp.content)
101+
102+
103+
class TestChoiceFieldForm(forms.SelfHandlingForm):
104+
title_dic = {"label1": {"title": "This is choice 1"},
105+
"label2": {"title": "This is choice 2"},
106+
"label3": {"title": "This is choice 3"}}
107+
name = forms.CharField(max_length=255,
108+
label="Test Name",
109+
help_text="Please enter a name")
110+
test_choices = forms.ChoiceField(label="Test Choices",
111+
required=False,
112+
help_text="Testing drop down choices",
113+
widget=forms.fields.SelectWidget(attrs={
114+
'class': 'switchable',
115+
'data-slug': 'source'},
116+
transform_html_attrs=title_dic.get))
117+
118+
def __init__(self, request, *args, **kwargs):
119+
super(TestChoiceFieldForm, self).__init__(request, *args, **kwargs)
120+
choices = ([('choice1', 'label1'),
121+
('choice2', 'label2')])
122+
self.fields['test_choices'].choices = choices
123+
124+
def handle(self, request, data):
125+
return True
126+
127+
128+
class ChoiceFieldTests(test.TestCase):
129+
130+
template = 'horizon/common/_form_fields.html'
131+
132+
def setUp(self):
133+
super(ChoiceFieldTests, self).setUp()
134+
self.form = TestChoiceFieldForm(self.request)
135+
136+
def _render_form(self):
137+
return shortcuts.render(self.request, self.template,
138+
{'form': self.form})
139+
140+
def test_choicefield_title(self):
141+
resp = self._render_form()
142+
self.assertContains(resp, '<option value="choice1" '
143+
'title="This is choice 1">label1</option>', count=1, html=True)
144+
self.assertContains(resp, '<option value="choice2" '
145+
'title="This is choice 2">label2</option>', count=1, html=True)

0 commit comments

Comments
 (0)