{# Form -- These macros are designed for building forms. They should be called like so: -------------------------------------------------------------------------------- {%- import "macros/form.html" as _form with context -%} {% call _form.form(form) %} {% call _form.fieldset('My legend 1') %} {{ _form.field(form.field1) }} {{ _form.field(form.field2) }} {% endcall %} {% call _form.fieldset('My legend 2') %} {% call _form.aside() %}

This text describes how the fields in this fieldset work.

{% endcall %} {% call _form.field() %} {{ _form.control(form.field3a) }} {{ _form.control(form.field3b) }} {% endcall %} {{ _form.field(form.field4) }} {% endcall %} {% call _form.buttons() %} {{ _form.button('Save') }} {{ _form.button('Cancel', url='/some-url') }} {% endcall %} {% endcall %} -------------------------------------------------------------------------------- #} {# Field types -- A list of the different type of fields that are accepted and the associated name they are given for formatting. There are currently 5 different form field styles - text, select, textarea, tick, ticks, and hidden. If a field type isn't listed below, it is assumed to be a `text` field. If you create another form type, it should be added to the list below and given an appropriate type. #} {% set field_types = { 'AssetField': 'asset', 'BooleanField': 'tick', 'CheckboxField': 'ticks', 'DateField': 'text', 'DateTimeField': 'text', 'DocumentCheckboxField': 'ticks', 'DocumentSelectField': 'select', 'FloatField': 'text', 'HiddenField': 'hidden', 'IntegerField': 'text', 'LatLonField': 'formfield', 'PasswordField': 'text', 'PriceField': 'text', 'RadioField': 'ticks', 'ReCAPTCHAField': 'captcha', 'SelectField': 'select', 'SlugField': 'text', 'StringField': 'text', 'StringListField': 'textarea', 'TextField': 'text', 'TimeField': 'text', 'TextAreaField': 'textarea', 'YesNoField': 'ticks', '_Option': 'tick' } %} {# Form -- The main containing form element. Unless an action is provided, the form macro will try to obtain the action from the current URL using `request.full_path` (if it exists). Form methods are assumed to be `POST` unless a `method` is provided. The macro will loop through `form` and insert all `hidden` field types (see field_types) into the top of the form and so these do not need to be included manually when the macro is called. -------------------------------------------------------------------------------- {% call _form.form(form) %} ... {% endcall %} -------------------------------------------------------------------------------- As standard you can also pass `class` to apply a custom class style to the containing element. You can also pass any other HTML attribute using keyword arguments and these will be applied to the container. -------------------------------------------------------------------------------- {% call _form.form( form=form, action='/some-url', method='POST', class='some-class', **{'data-some-attribute': 'Some value'} ) %} ... {% endcall %} -------------------------------------------------------------------------------- #} {% macro form(form, action=None, method='POST', class=None) -%} {% if action == None %} {%- set args = request.view_args or {} -%} {%- set _ = args.update(request.args or {}) -%} {%- set action = url_for(request.endpoint, **args) -%} {% endif %}
{# If the HTTP method is CSRF protected then add the current CSRF token as a hidden field to the form. #} {%- if method in config.CSRF_METHODS and csrf_token -%} {%- endif -%} {%- if form -%} {%- for item in form if field_types[item.type] == 'hidden' -%} {{ input(item) }} {%- endfor -%} {%- endif -%} {{ caller() }}
{%- endmacro %} {# Fieldset -- A fieldset element containing multiple form fields. The fieldset macro is not required as part of the form construction, but can be used to improve the visual appearance of a form. It allows you to break up the form fields into different sections, optionally providing each section with a legend. -------------------------------------------------------------------------------- {% call _form.fieldset('My legend') %} ... {% endcall %} -------------------------------------------------------------------------------- As standard you can also pass `class` to apply a custom class style to the containing element. You can also pass any other HTML attribute using keyword arguments and these will be applied to the container. You can use this same approach to pass HTML attributes to the `legend` macros. -------------------------------------------------------------------------------- {% call _form.fieldset( legend_text='My legend', class='some-class', legend_attrs={'data-some-attribute': 'Some value'}, **{'data-some-attribute': 'Some value'} ) %} ... {% endcall %} -------------------------------------------------------------------------------- #} {% macro fieldset(legend_text=None, class=None, legend_attrs=None) -%} {%- set legend_attrs = legend_attrs or {} -%}
{%- if legend_text -%} {{ legend(text=legend_text, **legend_attrs) }} {% endif %} {{ caller() }}
{%- endmacro %} {# Legend -- A legend element inserted into the top of a `fieldset` macro. -------------------------------------------------------------------------------- {{ _form.legend('My legend') }} -------------------------------------------------------------------------------- As standard you can also pass `class` to apply a custom class style to the containing element. You can also pass any other HTML attribute using keyword arguments and these will be applied to the container. -------------------------------------------------------------------------------- {{ _form.legend( text='My legend', class='some-class', **{'data-some-attribute': 'Some value'} ) }} -------------------------------------------------------------------------------- #} {% macro legend(text, class=None) -%} {{ text }} {%- endmacro %} {# Aside -- A block of HTML used to describe the functionality of it's adjacent fields. In order to use this macro correctly it should be inserted at the top of the form or fieldset macro. -------------------------------------------------------------------------------- {% call _form.aside() %} ... {% endcall %} -------------------------------------------------------------------------------- As standard you can also pass `class` to apply a custom class style to the containing element. You can also pass any other HTML attribute using keyword arguments and these will be applied to the container. -------------------------------------------------------------------------------- {% call _form.aside( class='some-class', **{'data-some-attribute': 'Some value'} ) %} ... {% endcall %} -------------------------------------------------------------------------------- #} {% macro aside(class=None) -%}
{{ caller() }}
{%- endmacro %} {# Field -- A containing element used to group one or more `control` macros together on a single row. If there is no caller provided when this macro is called, a `field` parameter must be passed. This is then used to render the `control` macro with the WTForms field information provided. Alternatively, multiple controls can be inserted using a caller. These will then appear side by side within the field container. -------------------------------------------------------------------------------- {% call _form.field() %} ... {% endcall %} -------------------------------------------------------------------------------- {{ _form.field(form.field1) }} -------------------------------------------------------------------------------- As standard you can also pass `class` to apply a custom class style to the containing element. You can also pass any other HTML attribute using keyword arguments and these will be applied to the container. You can use this same approach to pass HTML attributes to the `control`, `label`, and `input` macros. -------------------------------------------------------------------------------- {{ _form.field( field=form.field1 class='some-class', control_attrs={'data-some-attribute': 'Some value'}, label_attrs={'data-some-attribute': 'Some value'}, input_attrs={'data-some-attribute': 'Some value'}, **{'data-some-attribute': 'Some value'} ) }} -------------------------------------------------------------------------------- #} {% macro field( field, class=None, input_attrs=None, label_attrs=None, control_attrs=None ) -%} {%- set input_attrs = input_attrs or {} -%} {%- set label_attrs = label_attrs or {} -%} {%- set control_attrs = control_attrs or {} -%}
{%- if caller -%} {{ caller() }} {%- elif field_types[field.type] == 'formfield' %} {% for sub_field in field %} {{ control(sub_field) }} {% endfor %} {%- else -%} {{ control( field, input_attrs=input_attrs, label_attrs=label_attrs, **control_attrs ) }} {%- endif -%}
{%- endmacro %} {# Control -- A containing element used to group a single `input` macro. If there is no caller provided when this macro is called, a `field` parameter must be passed. This is then used to render the `input` macro and `label` macro (if applicable) with the WTForms field information provided. Labels are omitted from controls when the field type is a `tick`. -------------------------------------------------------------------------------- {% call _form.control() %} {{ _form.input(form.field1) }} {% endcall %} -------------------------------------------------------------------------------- {{ _form.control(form.field1) }} -------------------------------------------------------------------------------- As standard you can also pass `class` to apply a custom class style to the containing element. You can also pass any other HTML attribute using keyword arguments and these will be applied to the container. You can use this same approach to pass HTML attributes to the `label` and `input` macros. -------------------------------------------------------------------------------- {{ _form.control( field=form.field1 class='some-class', label_attrs={'data-some-attribute': 'Some value'}, input_attrs={'data-some-attribute': 'Some value'}, **{'data-some-attribute': 'Some value'} ) }} -------------------------------------------------------------------------------- #} {% macro control( field, class=None, input_attrs=None, label_attrs=None ) -%} {%- set input_attrs = input_attrs or {} -%} {%- set label_attrs = label_attrs or {} -%}
{%- if caller -%} {{ caller() }} {%- else -%} {%- if not field_types[field.type] in ['tick', 'captcha'] -%} {{ label(field, **label_attrs) }} {%- endif -%} {{ input(field, label_attrs=label_attrs, **input_attrs) }} {%- endif -%}
{%- endmacro %} {# Label -- A label element used for all form fields. You can optionally pass a string value through as `text` to overide the text in the label. -------------------------------------------------------------------------------- {{ _form.label(form.field1) }} -------------------------------------------------------------------------------- As standard you can also pass `class` to apply a custom class style to the containing element. You can also pass any other HTML attribute using keyword arguments and these will be applied to the container. -------------------------------------------------------------------------------- {{ _form.label( field=form.field1, text='Some label', class='some-class', **{'data-some-attribute': 'Some value'} ) }} -------------------------------------------------------------------------------- #} {% macro label(field, text=None, class=None) -%} {%- set _class = 'mh-field__label' -%} {%- if not field.flags.required -%} {%- set _class = _class + ' ' + 'mh-field__label--optional' -%} {%- endif -%} {%- if class -%} {%- set _class = _class + ' ' + class -%} {%- endif -%} {%- set _text = label_text(text) if text else label_text(field.label.text) -%} {{ field.label(text=_text, class=_class, **kwargs) }} {%- endmacro %} {# Label text -- To provide more control over the `label` element, an element containing the label text is inserted into the label. -------------------------------------------------------------------------------- {% call _form.label() %} {{ _form.label-text(form.field1.text) }} {% endcall %} -------------------------------------------------------------------------------- #} {% macro label_text(text) -%} {{ text }} {%- if field.errors and field_types[field.type] in ['tick', 'ticks'] -%} {{ error(field) }} {%- endif -%} {%- endmacro %} {# Input -- A macro used to choose the appropriate way to render a standard WTforms form field element. -------------------------------------------------------------------------------- {{ _form.input(form.field1) }} -------------------------------------------------------------------------------- As standard you can also pass `class` to apply a custom class style to the containing element. You can also pass any other HTML attribute using keyword arguments and these will be applied to the container. You can use this same approach to pass HTML attributes to the `label` macro (where applicable). -------------------------------------------------------------------------------- {{ _form.input( field=form.field1, class='some-class', label_attrs={'data-some-attribute': 'Some value'}, **{'data-some-attribute': 'Some value'} ) }} -------------------------------------------------------------------------------- #} {% macro input(field, class=None, label_attrs=None) -%} {%- set label_attrs = label_attrs or {} -%} {%- set _type = field_types[field.type] -%} {%- set _class = 'mh-field__' + _type if _type else 'text' -%} {%- set _class = _class + ' ' + class if class else _class -%} {%- if field.errors and 'data-field-error' not in kwargs -%} {%- set _error = kwargs.update({'data-field-error': true}) -%} {%- endif -%} {%- if _type == 'tick' -%}
{{ field(class="mh-field__tick-input", **kwargs) }} {{ label(field, **label_attrs) }}
{%- elif _type == 'ticks' -%}
{%- for option in field -%} {{ input(option, **kwargs) }} {%- endfor -%}
{%- else -%} {{ field(class=_class, **kwargs) }} {%- endif -%} {%- if not _type in ['tick', 'ticks', 'hidden'] -%} {{ error(field) }} {%- endif -%} {%- endmacro %} {# Error -- An error message shown against the form field when it has an error. All fields (excluding tick fields) have the error shown next to the input element. Tick fields have the error shown as part of the field label instead. -------------------------------------------------------------------------------- {{ _form.error(form.field1) }} -------------------------------------------------------------------------------- #} {% macro error(field) -%} {%- if field.errors -%} {{ ' '.join(field.errors) }} {%- endif -%} {%- endmacro %} {# Buttons -- A containing element used for one or more button elements. If the form only has one button, then you can add it using the `buttons` macro. If you need more than one button, you can use the `button` macro to include any number of buttons in a row. -------------------------------------------------------------------------------- {{ _form.buttons('Save') }} -------------------------------------------------------------------------------- {% call _form.buttons() %} ... {% endcall %} -------------------------------------------------------------------------------- As standard you can also pass `class` to apply a custom class style to the containing element. You can also pass any other HTML attribute using keyword arguments and these will be applied to the container. You can use this same approach to pass HTML attributes to the `button` macro. -------------------------------------------------------------------------------- {{ _form.buttons( button_text='Save', class='some-class', button_attrs={'data-some-attribute': 'Some value'}, **{'data-some-attribute': 'Some value'} ) }} -------------------------------------------------------------------------------- #} {% macro buttons(button_text=None, class=None, button_attrs=None) -%} {%- set button_attrs = button_attrs or {} -%}
{%- if caller -%} {{ caller() }} {%- else -%} {{ button(button_text, **button_attrs) }} {%- endif -%}
{%- endmacro %} {# Button -- A single button element. If you wish to use an `` tag instead of a `