/renderform/templatetags/forms.py
Python | 114 lines | 96 code | 11 blank | 7 comment | 20 complexity | 0039bfd8da2aae181461755d8e409211 MD5 | raw file
1from django.template import Library, Node
2from django import forms
3import re
4
5register = Library()
6
7SPLIT_RE = re.compile(r'[\s,]+')
8
9def show_form(form, wrap_with_tag='div'):
10 "Render all fields in `form`, passing `wrap_with_tag` to `show_field`."
11 return {'form': form, 'tag': wrap_with_tag}
12register.inclusion_tag("forms/form.html")(show_form)
13
14def show_field(field, wrap_with_tag='div', classes=()):
15 "Render `field` (label, input, and help text) encosed in `wrap_with_tag`."
16 if isinstance(classes, basestring):
17 classes = classes.split(',')
18 is_checkbox = (
19 isinstance(field.field.widget, forms.widgets.CheckboxInput) or
20 getattr(field.field.widget, 'input_type', None) == 'checkbox'
21 )
22 is_radio = (
23 isinstance(field.field.widget, forms.widgets.RadioInput) or
24 getattr(field.field.widget, 'input_type', None) == 'radio'
25 )
26 return {
27 'field': field,
28 'errors': field.errors,
29 'is_hidden': field.is_hidden,
30 'is_checkbox': is_checkbox,
31 'is_radio': is_radio,
32 'tag': wrap_with_tag,
33 'classes': classes,
34 'required': field.field.required
35 }
36register.inclusion_tag("forms/field.html")(show_field)
37
38def show_errors(field_or_errors, errors=None):
39 if errors is None:
40 if isinstance(field_or_errors, forms.forms.BoundField):
41 field = field_or_errors
42 errors = field.errors.pop()
43 else:
44 field = None
45 errors = field_or_errors
46 else:
47 field = field_or_errors
48 return {'field': field, 'errors': errors}
49register.inclusion_tag("forms/errors.html")(show_errors)
50
51def show_label(field, label=None, classes=()):
52 "Render the label tag for `field`, overriding its label text with `label`."
53 if label is None:
54 label = field.label
55 if isinstance(classes, basestring):
56 classes = SPLIT_RE.split(classes)
57 return {
58 'field': field,
59 'label': label,
60 'classes': classes,
61 'required': field.field.required
62 }
63register.inclusion_tag("forms/label.html")(show_label)
64
65def show_help_text(field_or_text, classes=()):
66 "Render the text or the field's help text given by `field_or_text`."
67 if isinstance(field_or_text, basestring):
68 field = None
69 help_text = field_or_text
70 else:
71 field = field_or_text
72 help_text = field.help_text
73 if isinstance(classes, basestring):
74 classes = SPLIT_RE.split(classes)
75 return {'field': field, 'help_text': help_text, 'classes': classes}
76register.inclusion_tag("forms/help_text.html")(show_help_text)
77
78def do_class_list(parser, token):
79 "Resolve arguments, flatten lists, and split strings to get class names."
80 bits = token.split_contents()[1:]
81 class_vars = [parser.compile_filter(bit) for bit in bits]
82 return ClassListNode(class_vars)
83register.tag('class_list', do_class_list)
84
85def do_class_attr(parser, token):
86 """
87 Render a HTML class attribute if the given classes are non-empty,
88 otherwise returns an empty string to avoid including an empty attribute.
89 Takes the same arguments as `class_list`. The attribute name is prefixed
90 with a space to help avoid extraneous spaces.
91
92 """
93 bits = token.split_contents()[1:]
94 class_vars = [parser.compile_filter(bit) for bit in bits]
95 return ClassListNode(class_vars, ' class="%s"')
96register.tag('class_attr', do_class_attr)
97
98class ClassListNode(Node):
99 def __init__(self, class_vars, output_format="%s"):
100 self.class_vars = class_vars
101 self.output_format = output_format
102
103 def render(self, context):
104 classes = [var.resolve(context) for var in self.class_vars]
105 class_names = []
106 for class_ in classes:
107 if isinstance(class_, basestring):
108 class_ = [class_]
109 for names in class_:
110 for name in SPLIT_RE.split(names):
111 if name and name not in class_names:
112 class_names.append(name)
113 value = " ".join(class_names)
114 return value and self.output_format % value