Skip to content

Commit 8b640ef

Browse files
committed
Merge branch 'release/4.7.0'
2 parents acd438a + 0cc4b46 commit 8b640ef

File tree

9 files changed

+123
-82
lines changed

9 files changed

+123
-82
lines changed

HISTORY.rst

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,24 @@ History
44
-------
55

66

7+
4.7.0 (2014-06-04)
8+
++++++++++++++++++
9+
10+
* `size` option added to formsets, forms, fields and buttons
11+
12+
713
4.6.0 (2014-05-22)
814
++++++++++++++++++
915

10-
* new bootstrap_formset_errors tag
16+
* new `bootstrap_formset_errors` tag
1117

1218

1319
4.5.0 (2014-05-21)
1420
++++++++++++++++++
1521

1622
* bug fixes in formsets
1723
* new formset renderer
18-
* new bootstrap_form_errors tag
24+
* new `bootstrap_form_errors` tag
1925

2026

2127
4.4.2 (2014-05-20)
@@ -132,7 +138,7 @@ History
132138

133139
* project refactored
134140
* added skeleton for creating documentation (fix issue #30)
135-
* fixed FileField issues
141+
* fixed `FileField` issues
136142

137143

138144

bootstrap3/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
# -*- coding: utf-8 -*-
22

3-
__version__ = '4.6.0'
3+
__version__ = '4.7.0'

bootstrap3/bootstrap.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -80,23 +80,24 @@ def theme_url():
8080
return get_bootstrap_setting('theme_url')
8181

8282

83-
def get_renderer(renderers, layout):
83+
def get_renderer(renderers, **kwargs):
84+
layout = kwargs.get('layout', '')
8485
path = renderers.get(layout, renderers['default'])
8586
mod, cls = path.rsplit(".", 1)
8687
return getattr(import_module(mod), cls)
8788

8889

89-
def get_formset_renderer(layout):
90+
def get_formset_renderer(**kwargs):
9091
renderers = get_bootstrap_setting('formset_renderers')
91-
return get_renderer(renderers, layout)
92+
return get_renderer(renderers, **kwargs)
9293

9394

94-
def get_form_renderer(layout):
95+
def get_form_renderer(**kwargs):
9596
renderers = get_bootstrap_setting('form_renderers')
96-
return get_renderer(renderers, layout)
97+
return get_renderer(renderers, **kwargs)
9798

9899

99-
def get_field_renderer(layout):
100+
def get_field_renderer(**kwargs):
100101
renderers = get_bootstrap_setting('field_renderers')
101-
return get_renderer(renderers, layout)
102+
return get_renderer(renderers, **kwargs)
102103

bootstrap3/forms.py

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22
from __future__ import unicode_literals
33

44
from django.contrib.admin.widgets import AdminFileWidget
5-
from django.forms import HiddenInput, FileInput, CheckboxSelectMultiple, Textarea, TextInput, DateInput, Select
6-
from django.forms.formsets import BaseFormSet
5+
from django.forms import HiddenInput, FileInput, CheckboxSelectMultiple, Textarea, TextInput
76

87
from .bootstrap import get_bootstrap_setting, get_form_renderer, get_field_renderer, get_formset_renderer
98
from .text import text_concat, text_value
@@ -15,48 +14,44 @@
1514
FORM_GROUP_CLASS = 'form-group'
1615

1716

18-
def render_formset(formset, layout='', **kwargs):
17+
def render_formset(formset, **kwargs):
1918
"""
2019
Render a formset to a Bootstrap layout
2120
"""
22-
# if not isinstance(formset, BaseFormSet):
23-
# raise BootstrapError('Parameter "formset" should contain a valid Django FormSet.')
24-
# forms = [render_form(f, **kwargs) for f in formset]
25-
# return text_value(formset.management_form) + '\n' + '\n'.join(forms)
26-
renderer_cls = get_formset_renderer(layout)
27-
return renderer_cls(formset, layout, **kwargs).render()
21+
renderer_cls = get_formset_renderer(**kwargs)
22+
return renderer_cls(formset, **kwargs).render()
2823

2924

30-
def render_formset_errors(form, layout='', **kwargs):
25+
def render_formset_errors(form, **kwargs):
3126
"""
3227
Render formset errors to a Bootstrap layout
3328
"""
34-
renderer_cls = get_formset_renderer(layout)
35-
return renderer_cls(form, layout, **kwargs).render_errors()
29+
renderer_cls = get_formset_renderer(**kwargs)
30+
return renderer_cls(form, **kwargs).render_errors()
3631

3732

38-
def render_form(form, layout='', **kwargs):
33+
def render_form(form, **kwargs):
3934
"""
4035
Render a formset to a Bootstrap layout
4136
"""
42-
renderer_cls = get_form_renderer(layout)
43-
return renderer_cls(form, layout, **kwargs).render()
37+
renderer_cls = get_form_renderer(**kwargs)
38+
return renderer_cls(form, **kwargs).render()
4439

4540

4641
def render_form_errors(form, layout='', type='all', **kwargs):
4742
"""
4843
Render form errors to a Bootstrap layout
4944
"""
50-
renderer_cls = get_form_renderer(layout)
51-
return renderer_cls(form, layout, **kwargs).render_errors(type)
45+
renderer_cls = get_form_renderer(**kwargs)
46+
return renderer_cls(form, **kwargs).render_errors(type)
5247

5348

54-
def render_field(field, layout='', **kwargs):
49+
def render_field(field, **kwargs):
5550
"""
5651
Render a formset to a Bootstrap layout
5752
"""
58-
renderer_cls = get_field_renderer(layout)
59-
return renderer_cls(field, layout, **kwargs).render()
53+
renderer_cls = get_field_renderer(**kwargs)
54+
return renderer_cls(field, **kwargs).render()
6055

6156

6257
def render_label(content, label_for=None, label_class=None, label_title=''):
@@ -73,18 +68,30 @@ def render_label(content, label_for=None, label_class=None, label_title=''):
7368
return render_tag('label', attrs=attrs, content=content)
7469

7570

76-
def render_button(content, button_type=None, icon=None, button_class=''):
71+
def render_button(content, button_type=None, icon=None, button_class='', size=''):
7772
"""
7873
Render a button with content
7974
"""
8075
attrs = {}
81-
attrs['class'] = add_css_class('btn', button_class)
76+
classes = add_css_class('btn', button_class)
77+
size = text_value(size).lower().strip()
78+
if size == 'xs':
79+
classes = add_css_class(classes, 'btn-xs')
80+
elif size == 'sm' or size == 'small':
81+
classes = add_css_class(classes, 'btn-sm')
82+
elif size == 'lg' or size == 'large':
83+
classes = add_css_class(classes, 'btn-lg')
84+
elif size == 'md' or size == 'medium':
85+
pass
86+
elif size:
87+
raise BootstrapError('Parameter "size" should be "xs", "sm", "lg" or empty.')
8288
if button_type:
8389
if button_type == 'submit':
84-
attrs['class'] = add_css_class(attrs['class'], 'btn-primary')
90+
classes = add_css_class(classes, 'btn-primary')
8591
elif button_type != 'reset' and button_type != 'button':
8692
raise BootstrapError('Parameter "button_type" should be "submit", "reset", "button" or empty.')
8793
attrs['type'] = button_type
94+
attrs['class'] = classes
8895
icon_content = render_icon(icon) if icon else ''
8996
return render_tag('button', attrs=attrs, content=text_concat(icon_content, content, separator=' '))
9097

bootstrap3/renderers.py

Lines changed: 56 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -19,25 +19,51 @@
1919
is_widget_with_placeholder, is_widget_required_attribute, FORM_GROUP_CLASS)
2020

2121

22-
class FormsetRenderer(object):
22+
class BaseRenderer(object):
23+
24+
def __init__(self, *args, **kwargs):
25+
self.layout = kwargs.get('layout', '')
26+
self.form_group_class = kwargs.get('form_group_class', FORM_GROUP_CLASS)
27+
self.field_class = kwargs.get('field_class', '')
28+
self.label_class = kwargs.get('label_class', '')
29+
self.show_help = kwargs.get('show_help', True)
30+
self.show_label = kwargs.get('show_label', True)
31+
self.exclude = kwargs.get('exclude', '')
32+
self.set_required = kwargs.get('set_required', True)
33+
self.size = self.parse_size(kwargs.get('size', ''))
34+
35+
def parse_size(self, size):
36+
size = text_value(size).lower().strip()
37+
if size in ('sm', 'small'):
38+
return 'small'
39+
if size in ('lg', 'large'):
40+
return 'large'
41+
if size in ('md', 'medium', ''):
42+
return 'medium'
43+
raise BootstrapError('Invalid value "%s" for parameter "size".' % size)
44+
45+
def get_size_class(self):
46+
if self.size == 'small':
47+
return 'input-sm'
48+
if self.size == 'large':
49+
return 'input-lg'
50+
return ''
51+
52+
53+
class FormsetRenderer(BaseRenderer):
2354
"""
2455
Default formset renderer
2556
"""
2657

27-
def __init__(self, formset, layout='', form_group_class=FORM_GROUP_CLASS,
28-
field_class='', label_class='', show_help=True, exclude='',
29-
set_required=True):
58+
def __init__(self, formset, *args, **kwargs):
3059
if not isinstance(formset, BaseFormSet):
3160
raise BootstrapError(
3261
'Parameter "formset" should contain a valid Django Formset.')
3362
self.formset = formset
34-
self.layout = layout
35-
self.form_group_class = form_group_class
36-
self.field_class = field_class
37-
self.label_class = label_class
38-
self.show_help = show_help
39-
self.exclude = exclude
40-
self.set_required = set_required
63+
super(FormsetRenderer, self).__init__(*args, **kwargs)
64+
65+
def render_management_form(self):
66+
return text_value(self.formset.management_form)
4167

4268
def render_forms(self):
4369
rendered_forms = []
@@ -69,28 +95,19 @@ def render_errors(self):
6995
return ''
7096

7197
def render(self):
72-
return self.render_errors() + self.render_forms()
73-
98+
return self.render_errors() + self.render_management_form() + self.render_forms()
7499

75100

76-
class FormRenderer(object):
101+
class FormRenderer(BaseRenderer):
77102
"""
78103
Default form renderer
79104
"""
80105

81-
def __init__(self, form, layout='', form_group_class=FORM_GROUP_CLASS,
82-
field_class='', label_class='', show_help=True, exclude='',
83-
set_required=True):
106+
def __init__(self, form, *args, **kwargs):
84107
if not isinstance(form, BaseForm):
85108
raise BootstrapError('Parameter "form" should contain a valid Django Form.')
86109
self.form = form
87-
self.layout = layout
88-
self.form_group_class = form_group_class
89-
self.field_class = field_class
90-
self.label_class = label_class
91-
self.show_help = show_help
92-
self.exclude = exclude
93-
self.set_required = set_required
110+
super(FormRenderer, self).__init__(*args, **kwargs)
94111

95112
def render_fields(self):
96113
rendered_fields = []
@@ -136,37 +153,30 @@ def render(self):
136153
return self.render_errors() + self.render_fields()
137154

138155

139-
class FieldRenderer(object):
156+
class FieldRenderer(BaseRenderer):
140157
"""
141158
Default field renderer
142159
"""
143160

144-
def __init__(self, field, layout='', form_group_class=FORM_GROUP_CLASS,
145-
field_class=None, label_class=None, show_label=True,
146-
show_help=True, exclude='', set_required=True,
147-
addon_before=None, addon_after=None,
148-
error_css_class='', required_css_class=''):
149-
# Only allow BoundField
161+
def __init__(self, field, *args, **kwargs):
150162
if not isinstance(field, BoundField):
151163
raise BootstrapError('Parameter "field" should contain a valid Django BoundField.')
152-
153164
self.field = field
154-
self.layout = layout
155-
self.form_group_class = form_group_class
156-
self.field_class = field_class
157-
self.label_class = label_class
158-
self.show_label = show_label
159-
self.exclude = exclude
160-
self.set_required = set_required
165+
super(FieldRenderer, self).__init__(*args, **kwargs)
166+
161167
self.widget = field.field.widget
162168
self.initial_attrs = self.widget.attrs.copy()
163-
self.field_help = text_value(mark_safe(field.help_text)) if show_help and field.help_text else ''
169+
self.field_help = text_value(mark_safe(field.help_text)) if self.show_help and field.help_text else ''
164170
self.field_errors = [conditional_escape(text_value(error)) for error in field.errors]
171+
165172
self.placeholder = field.label
166-
self.addon_before = addon_before
167-
self.addon_after = addon_after
173+
174+
self.addon_before = kwargs.get('addon_before', '')
175+
self.addon_after = kwargs.get('addon_after', '')
168176

169177
# These are set in Django or in the global BOOTSTRAP3 settings, and they can be overwritten in the template
178+
error_css_class = kwargs.get('error_css_class', '')
179+
required_css_class = kwargs.get('required_css_class', '')
170180
if error_css_class:
171181
self.form_error_class = error_css_class
172182
else:
@@ -180,13 +190,14 @@ def restore_widget_attrs(self):
180190
self.widget.attrs = self.initial_attrs
181191

182192
def add_class_attrs(self):
183-
self.widget.attrs['class'] = self.widget.attrs.get('class', '')
193+
classes = self.widget.attrs.get('class', '')
184194
if not isinstance(self.widget, (CheckboxInput,
185195
RadioSelect,
186196
CheckboxSelectMultiple,
187197
FileInput)):
188-
self.widget.attrs['class'] = add_css_class(
189-
self.widget.attrs['class'], 'form-control')
198+
classes = add_css_class(classes, 'form-control')
199+
classes = add_css_class(classes, self.get_size_class())
200+
self.widget.attrs['class'] = classes
190201

191202
def add_placeholder_attrs(self):
192203
placeholder = self.widget.attrs.get('placeholder', self.placeholder)

bootstrap3/templatetags/bootstrap3.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,7 @@ def bootstrap_field(*args, **kwargs):
317317
318318
**example**::
319319
320-
{% bootstrap_form form_field FIXTHIS %}
320+
{% bootstrap_form form_field form.subject %}
321321
"""
322322
return render_field(*args, **kwargs)
323323

bootstrap3/tests.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,23 @@ def test_input_group(self):
234234
self.assertIn('class="input-group-addon">$', res)
235235
self.assertIn('class="input-group-addon">.00', res)
236236

237+
def test_size(self):
238+
def _test_size(param, klass):
239+
res = render_template('{% bootstrap_field form.subject size="' + param + '" %}')
240+
self.assertIn(klass, res)
241+
def _test_size_medium(param):
242+
res = render_template('{% bootstrap_field form.subject size="' + param + '" %}')
243+
self.assertNotIn('input-lg', res)
244+
self.assertNotIn('input-sm', res)
245+
self.assertNotIn('input-md', res)
246+
_test_size('sm', 'input-sm')
247+
_test_size('small', 'input-sm')
248+
_test_size('lg', 'input-lg')
249+
_test_size('large', 'input-lg')
250+
_test_size_medium('md')
251+
_test_size_medium('medium')
252+
_test_size_medium('')
253+
237254

238255
class ComponentsTest(TestCase):
239256
def test_icon(self):

demo/demo/templates/demo/formset.html

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
{% bootstrap_formset_errors form %}
1111
<form role="form" method="post">
1212
{% csrf_token %}
13-
{{ form.management_form }}
1413
{% bootstrap_formset form %}
1514
{% buttons submit='OK' reset="Cancel" %}{% endbuttons %}
1615
</form>

demo/demo/templates/demo/misc.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
{% block content %}
1010

11-
{% bootstrap_button 'button' %}
11+
{% bootstrap_button 'button' size='lg' %}
1212

1313
{% bootstrap_alert "Something went wrong" alert_type='danger' %}
1414

0 commit comments

Comments
 (0)