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. 

10 

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.""" 

42 

43from django import forms, template 

44from django.template.loader import get_template 

45 

46BOOTSTRAP_COLUMN_COUNT = 12 

47 

48register = template.Library() 

49 

50 

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) 

56 

57 

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) 

63 

64 

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' 

70 

71 markup_classes = { 

72 'label': label_cols, 

73 'value': '', 

74 'single_value': '' 

75 } 

76 

77 for cl in label_cols.split(' '): 

78 splited_class = cl.split('-') 

79 

80 try: 

81 value_nb_cols = int(splited_class[-1]) 

82 except ValueError: 

83 value_nb_cols = BOOTSTRAP_COLUMN_COUNT 

84 

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) 

93 

94 markup_classes['value'] += ' ' + '-'.join(splited_class) 

95 

96 return render(element, markup_classes) 

97 

98 

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 

106 

107 

108def render(element, markup_classes): 

109 """Render various elements with our custom templates.""" 

110 element_type = element.__class__.__name__.lower() 

111 

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) 

122 

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) 

128 

129 template = get_template("html/bootstrap-form.html") 

130 context = {'form': element, 'classes': markup_classes} 

131 

132 return template.render(context) 

133 

134 

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) 

139 

140 

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) 

145 

146 

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) 

151 

152 

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)