{% macro apply_classes(classes) -%} {# Apply css classes inside an element. Usage:
#} {% for css in classes %}{{ css }} {% endfor %} {%- endmacro %} {% macro apply_dattrs(data_attrs) -%} {# Apply data-attributes inside an element. Usage:
As a dictionary:
#} {% if data_attrs is mapping %} {% for attr, val in data_attrs.items() %}data-{{ attr|camel2hyphen }}='{{ val }}' {% endfor %} {% else %} {% for attr in data_attrs %}data-{{ attr }} {% endfor %} {% endif %} {%- endmacro %} {% macro dictlist_dl(data, filterkeys=[], filtervals=[], classes=[], data_attrs=[], asdict=False) %} {# Make a definition list from a dictionary - the correspondence should be dt: key, dd: value Usage: {{ dictlist_dl({'foo': 'bar'}) }}
foo
bar
Or use a namedtuple by specifying `asdict`: {{ dict_list_dl(namedtuple, asdict=True) }} #} {% if asdict %}{% set data = data._asdict() %}{% endif %}
{% for k, v in data.items() -%} {% if k not in filterkeys and v not in filtervals %}
{{ k }}
{{ v }}
{% endif %} {% endfor %}
{%- endmacro %} {% macro dict2list(data, type='ul', filterkeys=[], filtervals=[], asdict=False) %} {# Makes a list from a dictionary. Usage: {{ dict2list({'foo': 'bar'}) }} Or use a namedtuple by specifying `asdict`: {{ dict_list_dl(namedtuple, asdict=True) }} #} {% if asdict %}{% set data = data._asdict() %}{% endif %} <{{ type }}> {% for k, v in data.items() %} {% if k not in filterkeys and v not in filtervals %}
  • {{ k }}: {{ v }}
  • {% endif %} {% endfor %} {%- endmacro %} {% macro list2list(data, type='ul', filtervals=[], icons={}, classes=[], icondir='left') %} {# Makes a OL/UL from a list, with optional icons Usage: {{ list2list(['Toyota', 'V2', '747', 'John Deere'], icons={'Toyota': ['fa', 'fa-car'], 'V2': ['fa', 'fa-rocket']}, icondir='right') }} Returns: Change alignment to left or right by specifying `icondir`: {{ list2list(['Toyota'], icons={'Toyota': ['car']}, icondir='left') }} #} <{{ type }} class="{{ apply_classes(classes) }}"> {% for item in data %} {% if item and item not in filtervals %}
  • {% if item in icons.keys() %} {% if icondir == 'left' %} {{ item }} {% else %} {{ item }} {% endif %} {% else %} {{ item }} {% endif %}
  • {% endif %} {% endfor %} {%- endmacro %} {% macro dictlist2nav(data, type='ul', filterkeys=[], filtervals=[], classes=[], data_attrs=[]) %} {# Make a list of links with nav element. Format must be a list of dictionaries. Supports *one* level of nesting. #} {% if asdict %}{% set data = data._asdict() %}{% endif %} {%- endmacro %} {% macro dictlist2dropdown(data, name=None, filterkeys=[], filtervals=[], classes=[], data_attrs=[], asdict=False) %} {# Make a dropdown element. Format must be a list of dictionaries. #} {% if asdict %}{% set data = data._asdict() %}{% endif %} {%- endmacro %} {% macro list2dropdown(data, filtervals=[], classes=[], data_attrs=[]) %} {# Make a dropdown element. Format must be a list. Value and text are the same. #} {%- endmacro %} {% macro dictlist2checkboxes(data, fieldset_class='fieldset-group', filterkeys=[], filtervals=[], data_attrs=[], asdict=False) %} {# Make a checkbox group, where keys are input names, and values are labels. Format must be a list of dictionaries. #} {% if asdict %}{% set data = data._asdict() %}{% endif %}
    {% for item in data %} {% for k, v in item.items() %} {% if k not in filterkeys and v not in filtervals %} {% endif %} {% endfor %} {% endfor %}
    {%- endmacro %} {% macro objects2table(objs, classes=[], data_attrs=[], filterkeys=[], filtervals=[], filter_headings=[], pk_link=None, handle_links=True, field_macros={}, header_macros={}, asdict=False ) -%} {# Create table from a list of objects (class instantiations). Also add links for primary keys if specified. {{ objects2table( data, data_attrs={'datatable': 'true'}, filterkeys=['do-not-want'], filtervals=['some-val'], field_macros={'somefield': some_macro}, header_macros={'some-header': some_header_macro}, filter_headings=['some-heading'], classes=['table', 'table-striped', 'table-bordered'], ) }} If your data is a named tuple, use asdict=True to convert it. #} {% if asdict %}{% set data = data._asdict() %}{% endif %} {% for obj in objs %} {% if loop.first %} {% set header_keys = header_macros.keys() %} {% for heading, _ in obj.items() %} {# Allow filtering of headings. #} {% if heading not in filterkeys and heading not in filter_headings %} {% if heading in header_keys %} {% else %} {% endif %} {% endif %} {% endfor %} {% endif %} {% endfor %} {% for obj in objs %} {% for k, v in obj.items() %} {# Allowing filtering of keys and values. #} {% if k not in filterkeys %} {% if v not in filtervals %} {% else %} {% endif %} {% endif %} {% endfor %} {% endfor %}
    {{ header_macros[heading](heading) }}{{ heading }}
    {# Handle all primary key links, a common occurence #} {% if pk_link and k == 'id' %} {{ v }} {% elif handle_links and v|is_url %} {{ v }} {% elif k in field_macros.keys() %} {# If a field macro is specified by key, call it on this field for arbitrary levels of customization #} {{ field_macros[k](v) }} {% else %} {{ v }} {% endif %}
    {%- endmacro %} {% macro wtform_errors_field(field, errors, bg=True) -%} {# Specify an error field list for a given field and its errors. Usage: {{ wtform_errors_field(, ) }} Disable or enable coloring with `bg`: {{ wtform_errors_field(, , bg=False) }} #} {% if bg %}
    {% endif %}

    Error(s) for '{{ field }}':

      {% for error in errors %}
    • {{ error }}
    • {% endfor %}
    {% if bg %}
    {% endif %} {%- endmacro %} {% macro wtform_errors(formobj) -%} {# Show a list of form errors based on a given wtform instance. Usage: {{ wtform_errors() }} #} {% if formobj.errors %} {% for field, errors in formobj.errors.items() %} {{ wtform_errors_field(field, errors) }} {% endfor %} {% endif %} {%- endmacro %} {% macro wtform_form(formobj, action='.', method='GET', classes=[], data_attrs=[], btn_classes=[], input_classes=[], uploads=True, enctype=None, btn_text='Submit', formid=None, reset_btn=True, legend=None, horizontal=False, align='left', questionize=True, linebreaks=True, button_wrapper=True, use_fieldset=True, reset_btn_classes=[], wrap_inputs=False, field_classes={}, field_macros={}, fieldset_groups={} ) -%} {# Generate an entire wtform object with layout options and many customization options. Options include: - Error handling/styling - Horizontal or vertical layout - Per-field macro customization - Per-field styling - Data-attributes, classes, ids - Automatically add "?" to BooleanFields if `questionize` is set. - Add a button wrapper for styling - Add a input/label wrapper for styling - Add reset button - Wrap in fieldset/legend option - Upload support (enctype) - Other standard form options - All the other magic that comes from wtforms (descriptions, help text, defaults, error handling, etc...) - Automatically group fields by a various fieldsets (see below) Usage: {{ wtform_form( , action=url_for('myapp.index'), method='POST', classes=['form', 'form-inline'], input_classes=['input-lg', 'form-control'], btn_text='Go', formid='myform', horizontal=True, align='right', field_macros={ 'field1': myfield1macro, 'field2': myfield2macro, }, fieldset_groups={ 'Field1': 'group1', 'Field2': 'group1', 'Field3': 'group1', 'Field4': 'group2', }, ) }} Field macros can be used to customized individual fields however you like, given a macro. #}
    {% if use_fieldset and not fieldset_groups %}
    {% endif %} {% if legend and not fieldset_groups %} {{ legend }} {% endif %} {# This macro is only to DRY up the usage in the below loop. #} {%- macro _load_field(field) %} {% set valid_field = field.type not in ['CSRFTokenField', 'HiddenField'] %} {% if valid_field %} {{ _wtform_field( field, input_classes=input_classes, horizontal=horizontal, align=align, questionize=questionize, linebreaks=linebreaks, wrap_inputs=wrap_inputs, field_classes=field_classes, field_macros=field_macros, fieldset_groups=fieldset_groups, ) }} {% else %} {{ field }} {% endif %} {% endmacro -%} {# Load all fields by groups if fieldset_groups is present, otherwise load as normal iteration. #} {% if fieldset_groups %} {% set groups = formobj|group_by(fieldset_groups, 'name') %} {% for label, fields in groups.items() %}
    {% if label != '__unlabeled' %} {{ label }} {% endif %} {% for field in fields %} {{ _load_field(field) }} {% endfor %}
    {% endfor %} {% else %} {% for field in formobj %} {{ _load_field(field) }} {% endfor %} {% endif %} {% if use_fieldset and not fieldset_groups %}
    {% endif %} {% if button_wrapper %}
    {% endif %} {# Add typical form submit button. #} {# Add a reset field values button if specified. #} {% if reset_btn %} {% endif %} {% if button_wrapper %}
    {% endif %}
    {%- endmacro %} {# Handle the complex logic inside of `wtform_form` in a separate macro. Not for public use. #} {%- macro _wtform_field(field, input_classes=[], horizontal=False, align='left', questionize=True, linebreaks=True, wrap_inputs=False, field_classes={}, field_macros={}, fieldset_groups={} ) %} {% set use_field_macro = field.name in field_macros.keys() %} {% if horizontal %}
    {% endif %} {# Only show labels and descriptions if they are normal fields. #} {% if wrap_inputs and not horizontal %}
    {% endif %} {% if horizontal %}
    {% if wrap_inputs %}
    {% endif %} {% endif %} {% if not use_field_macro %} {{ field.label }}{% if field.type == 'BooleanField' and questionize %}?{% endif %} {% endif %} {% if field.description and not use_field_macro %} {% if horizontal and linebreaks %}
    {% endif %} {{ field.description }} {% endif %}{# end `if field.description` #} {% if field.flags.required and not use_field_macro %} {% if horizontal and linebreaks %}
    {% endif %} * Required {% if linebreaks %}
    {% endif %} {% endif %}{# end `if field.flags.required` #} {% if horizontal %}
    {# If horizontal mode is enabled, we can't group the fields etc into a single wrapper, so we apply to each section in each respective column #} {% if wrap_inputs %}
    {% endif %}
    {% if wrap_inputs %}
    {% endif %} {% endif %} {% if horizontal %}
    {% endif %}{# end `if horizontal` #} {% if use_field_macro %} {{ field_macros[field.name](field) }} {% else %} {% if field_classes.get(field.name) %} {{ field(class_=(input_classes + field_classes[field.name])|join(' ')) }} {% else %} {{ field(class_=input_classes|join(' ')) }} {% endif %} {% endif %} {% if linebreaks and not use_field_macro %}
    {% endif %} {% if field.errors and not use_field_macro %} {{ wtform_errors_field(field.label, field.errors, bg=False) }} {% endif %} {% if horizontal %}
    {% endif %} {% if linebreaks and not use_field_macro %}
    {% endif %} {% if horizontal %}
    {# If horizontal mode is enabled, we can't group the fields etc into a single wrapper, so we apply to each section in each respective column #} {% if wrap_inputs %}
    {% endif %} {% endif %} {% if horizontal %}

    {% endif %} {% if wrap_inputs and not horizontal %}
    {% endif %} {% endmacro -%} {%- macro recurse_dictlist(val, type='ul', classes=[], data_attrs=[]) %} {# Uses the jinja2 recursive looping to recurse over a dictionary and display as a list (ordered or unordered), or display a default value otherwise. #} {% if val is mapping %} <{{ type }} class="{{ apply_classes(classes) }}" {{ apply_dattrs(data_attrs) }}> {% for k, v in val.items() recursive %} {% if v is mapping %}
  • {{ k }}: <{{ type }} class="{{ apply_classes(classes) }}" {{ apply_dattrs(data_attrs) }}> {{ loop(v.items()) }}
  • {% else %}
  • {% if v|islist %} <{{ type }} class="{{ apply_classes(classes) }}" {{ apply_dattrs(data_attrs) }}> {% for item in v %}
  • {% for itemv in v recursive %} {{ recurse_dictlist(itemv, type=type) }} {% endfor %} {% endfor %}
  • {% else %} {{ k }}: {{ v }} {% endif %} {% endif %} {% endfor %} {% else %} {{ val }} {% endif %} {%- endmacro %}