Coverage for distro_tracker/html/templatetags/bootstrap.py: 81%
68 statements
« prev ^ index » next coverage.py v6.5.0, created at 2025-01-12 09:15 +0000
« prev ^ index » next coverage.py v6.5.0, created at 2025-01-12 09:15 +0000
1# Copyright 2015-2016 The Distro Tracker Developers
2# See the COPYRIGHT file at the top-level directory of this distribution and
3# at https://deb.li/DTAuthors
4#
5# This file is part of Distro Tracker. It is subject to the license terms
6# in the LICENSE file found in the top-level directory of this
7# distribution and at https://deb.li/DTLicense. No part of Distro Tracker,
8# including this file, may be copied, modified, propagated, or distributed
9# except according to the terms contained in the LICENSE file.
11# This file has been forked from django-bootstrap-form which was
12# BSD licensed:
13#
14# Copyright (c) Ming Hsien Tzang and individual contributors.
15# All rights reserved.
16#
17# Redistribution and use in source and binary forms, with or without
18# modification, are permitted provided that the following conditions are met:
19#
20# 1. Redistributions of source code must retain the above copyright notice,
21# this list of conditions and the following disclaimer.
22#
23# 2. Redistributions in binary form must reproduce the above copyright
24# notice, this list of conditions and the following disclaimer in the
25# documentation and/or other materials provided with the distribution.
26#
27# 3. Neither the name of django-bootstrap-form nor the names of its
28# contributors may be used to endorse or promote products derived from
29# this software without specific prior written permission.
30#
31# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
32# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
33# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
34# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
35# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
37# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
38# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
39# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
40# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41"""Template tags to inject bootstrap-specific content on various elements."""
43from django import forms, template
44from django.template.loader import get_template
46BOOTSTRAP_COLUMN_COUNT = 12
48register = template.Library()
51@register.filter
52def bootstrap(element):
53 """Apply normal bootstrap formatting to a form."""
54 markup_classes = {'label': '', 'value': '', 'single_value': ''}
55 return render(element, markup_classes)
58@register.filter
59def bootstrap_inline(element):
60 """Apply inline bootstrap formatting to a form."""
61 markup_classes = {'label': 'sr-only', 'value': '', 'single_value': ''}
62 return render(element, markup_classes)
65@register.filter
66def bootstrap_horizontal(element, label_cols=None):
67 """Apply horizontal bootstrap formatting to a form."""
68 if not label_cols: 68 ↛ 71line 68 didn't jump to line 71
69 label_cols = 'col-sm-2'
71 markup_classes = {
72 'label': label_cols,
73 'value': '',
74 'single_value': ''
75 }
77 for cl in label_cols.split(' '):
78 splited_class = cl.split('-')
80 try:
81 value_nb_cols = int(splited_class[-1])
82 except ValueError:
83 value_nb_cols = BOOTSTRAP_COLUMN_COUNT
85 if value_nb_cols >= BOOTSTRAP_COLUMN_COUNT: 85 ↛ 86line 85 didn't jump to line 86, because the condition on line 85 was never true
86 splited_class[-1] = BOOTSTRAP_COLUMN_COUNT
87 else:
88 offset_class = cl.split('-')
89 offset_class[-1] = 'offset-' + str(value_nb_cols)
90 splited_class[-1] = str(BOOTSTRAP_COLUMN_COUNT - value_nb_cols)
91 markup_classes['single_value'] += ' ' + '-'.join(offset_class)
92 markup_classes['single_value'] += ' ' + '-'.join(splited_class)
94 markup_classes['value'] += ' ' + '-'.join(splited_class)
96 return render(element, markup_classes)
99def add_input_classes(field):
100 """Add bootstrap classes to a field."""
101 if (not is_checkbox(field) and not is_multiple_checkbox(field) and
102 not is_radio(field) and not is_file(field)):
103 field_classes = field.field.widget.attrs.get('class', '')
104 field_classes += ' form-control'
105 field.field.widget.attrs['class'] = field_classes
108def render(element, markup_classes):
109 """Render various elements with our custom templates."""
110 element_type = element.__class__.__name__.lower()
112 if element_type == 'boundfield': 112 ↛ 113line 112 didn't jump to line 113, because the condition on line 112 was never true
113 add_input_classes(element)
114 template = get_template("html/bootstrap-field.html")
115 context = {'field': element, 'classes': markup_classes}
116 else:
117 has_management = getattr(element, 'management_form', None)
118 if has_management: 118 ↛ 119line 118 didn't jump to line 119, because the condition on line 118 was never true
119 for form in element.forms:
120 for field in form.visible_fields():
121 add_input_classes(field)
123 template = get_template("html/bootstrap-formset.html")
124 context = {'formset': element, 'classes': markup_classes}
125 else:
126 for field in element.visible_fields():
127 add_input_classes(field)
129 template = get_template("html/bootstrap-form.html")
130 context = {'form': element, 'classes': markup_classes}
132 return template.render(context)
135@register.filter
136def is_checkbox(field):
137 """Return True if the field is a Checkbox, False otherwise."""
138 return isinstance(field.field.widget, forms.CheckboxInput)
141@register.filter
142def is_multiple_checkbox(field):
143 """Return True if the field is a MultipleCheckbox, False otherwise."""
144 return isinstance(field.field.widget, forms.CheckboxSelectMultiple)
147@register.filter
148def is_radio(field):
149 """Return True if the field is a radio selector, False otherwise."""
150 return isinstance(field.field.widget, forms.RadioSelect)
153@register.filter
154def is_file(field):
155 """Return True if the field is a file selector, False otherwise."""
156 return isinstance(field.field.widget, forms.FileInput)