File: fields.py

package info (click to toggle)
python-django-crispy-forms-foundation 0.9.0%2Bds-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 844 kB
  • sloc: javascript: 6,437; python: 1,221; makefile: 187; sh: 17
file content (209 lines) | stat: -rw-r--r-- 6,756 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
"""

References
    * `Foundation 6 Forms <https://get.foundation/sites/docs/forms.html>`_;
    * `Foundation 6 Switches <https://get.foundation/sites/docs/switch.html>`_;

"""  # noqa: E501
from crispy_forms.utils import render_field, TEMPLATE_PACK
from crispy_forms import layout as crispy_forms_layout


__all__ = [
    'Field', 'FakeField', 'Hidden', 'MultiWidgetField', 'MultiField',
    'SplitDateTimeField', 'InlineField', 'InlineJustifiedField', 'SwitchField',
    'InlineSwitchField',
]


class Field(crispy_forms_layout.Field):
    """
    Layout object, contain one field name and you can add attributes to it
    easily. For setting class attributes, you need to use ``css_class``,
    because ``class`` is a reserved Python keyword.

    Example:

    .. code-block:: python

        Field('field_name', style="color: #333;", css_class="whatever",
              id="field_name")
    """
    template = "%s/field.html"


class FakeField(Field):
    """
    Fake field is intended to be used with some app that does not honor field
    ID on the input element alike ``django-recaptcha`` that build a textarea
    with a dummy ID attribute. This leads to HTML validation error.

    Fake field works as basic Field object except a ``fake_field`` variable is
    passed to the template context.

    Actually the only difference with a ``Field`` is label element drops
    ``for`` attribute.

    You should use this field in last resort.
    """
    def render(self, form, form_style, context, template_pack=TEMPLATE_PACK):
        context['fake_field'] = True
        return super(FakeField, self).render(form, form_style, context,
                                             template_pack)


class Hidden(crispy_forms_layout.Hidden):
    """
    Hidden field. Work as basic Field except the ``hidden`` value for ``type``
    attribute.
    """
    input_type = 'hidden'
    field_classes = 'hidden'


class MultiWidgetField(crispy_forms_layout.MultiWidgetField):
    pass


class MultiField(crispy_forms_layout.MultiField):
    """
    MultiField container. Render to a MultiField
    """
    template = "%s/layout/multifield.html"
    field_template = "%s/multifield.html"


class SplitDateTimeField(Field):
    """
    Just an inherit from ``crispy_forms.layout.Field`` to have a common Field
    for displaying field with the ``django.forms.extra.SplitDateTimeWidget``
    widget.

    Simply use a specific template
    """
    template = "%s/layout/splitdatetime_field.html"


class InlineField(Field):
    """
    Layout object for rendering an inline field with Foundation

    Example:

    .. code-block:: python

        InlineField('field_name')

    Or:

    .. code-block:: python

        InlineField('field_name', label_column='large-8',
                    input_column='large-4', label_class='')

    ``label_column``, ``input_column``, ``label_class``, are optional argument.
    """
    template = "%s/layout/inline_field.html"

    def __init__(self, field, label_column='large-3', input_column='large-9',
                 label_class='', *args, **kwargs):
        self.field = field
        self.label_column = label_column+' columns'
        self.input_column = input_column+' columns'
        self.label_class = label_class

        super(InlineField, self).__init__(field, *args, **kwargs)

    def render(self, form, form_style, context, template_pack=TEMPLATE_PACK):
        context['label_column'] = self.label_column
        context['input_column'] = self.input_column
        context['label_class'] = self.label_class

        html = ''
        template = self.get_template_name(template_pack)
        for field in self.fields:
            html += render_field(field, form, form_style, context,
                                 template=template, attrs=self.attrs,
                                 template_pack=template_pack)
        return html


class InlineJustifiedField(InlineField):
    """
    Same as InlineField but default is to be right aligned with a vertical
    padding
    """
    def __init__(self, field, *args, **kwargs):
        default = 'middle text-right inline'
        kwargs['label_class'] = kwargs.get('label_class', None) or default
        super(InlineJustifiedField, self).__init__(field, *args, **kwargs)


class SwitchField(Field):
    """
    A specific field to use Foundation form switches

    You must only use this with a checkbox field and this is a *raw* usage of
    this Foundation element, you should see ``InlineSwitchField`` instead.

    Example:

    .. code-block:: python

        SwitchField('field_name', style="color: #333;", css_class="whatever",
                    id="field_name")
    """
    template = "%s/switch.html"

    def __init__(self, field, *args, **kwargs):
        self.switch_class = ['switch'] + kwargs.pop('switch_class', '').split()
        kwargs['class'] = (kwargs.pop('class', '') + ' switch-input').strip()

        super(SwitchField, self).__init__(field, *args, **kwargs)

    def render(self, form, form_style, context, template_pack=TEMPLATE_PACK):
        context['switch_class'] = " ".join(self.switch_class)
        return super(SwitchField, self).render(form, form_style, context,
                                               template_pack)


class InlineSwitchField(InlineField):
    """
    Like ``SwitchField`` it use Foundation form switches with checkbox field
    but within an ``InlineField``

    Contrary to ``SwitchField`` this play nice with the label to be able to
    display it (as Foundation form switches default behavior is to hide the
    label text)

    Example:

    .. code-block:: python

        InlineSwitchField('field_name')

    Or:

    .. code-block:: python

        InlineSwitchField('field_name', label_column='large-8',
                          input_column='large-4', label_class='',
                          switch_class="inline")

    ``label_column``, ``input_column``, ``label_class``, ``switch_class`` are
    optional argument.
    """
    template = "%s/inline_switch.html"

    def __init__(self, field, *args, **kwargs):
        self.switch_class = ['switch']+kwargs.pop('switch_class', '').split()
        kwargs['label_column'] = kwargs.pop('label_column', 'large-8')
        kwargs['input_column'] = kwargs.pop('input_column', 'large-4')
        kwargs['class'] = (kwargs.pop('class', '') + ' switch-input').strip()

        super(InlineSwitchField, self).__init__(field, *args, **kwargs)

    def render(self, form, form_style, context, template_pack=TEMPLATE_PACK):
        context['switch_class'] = " ".join(self.switch_class)
        return super(InlineSwitchField, self).render(form, form_style, context,
                                                     template_pack)