Merge "Add additional attributes to choices in ChoiceField"
This commit is contained in:
commit
1558541985
@ -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)))
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user