Commit 3f58be29 authored by Michael Fladischer's avatar Michael Fladischer

New upstream version 1.7.1

parent 12ffacb1
......@@ -4,14 +4,13 @@ sudo: false
python:
- "2.7"
- "3.3"
- "3.4"
- "3.5"
- "3.6"
env:
- DJANGO='django>=1.8.0,<1.9.0'
- DJANGO='django>=1.10.0,<1.11.0'
- DJANGO='django>=1.11.0,<2.0'
- DJANGO='django>=2.0,<2.1'
- DJANGO='https://github.com/django/django/archive/master.tar.gz'
before_install:
- pip install --upgrade 'pytest<3.0.0'
......@@ -26,12 +25,8 @@ matrix:
exclude:
- python: "2.7"
env: DJANGO='https://github.com/django/django/archive/master.tar.gz'
- python: "3.3"
env: DJANGO='https://github.com/django/django/archive/master.tar.gz'
- python: "3.3"
env: DJANGO='django>=1.11.0,<2.0'
- python: "3.3"
env: DJANGO='django>=1.10.0,<1.11.0'
- python: "2.7"
env: DJANGO='django>=2.0,<2.1'
- python: "3.4"
env: DJANGO='https://github.com/django/django/archive/master.tar.gz'
allow_failures:
......
# CHANGELOG for django-crispy-forms
## 1.7.1 (2018/03/05)
* Bootstrap 4 template pack.
See [1.7.1 Milestone](https://github.com/django-crispy-forms/django-crispy-forms/milestone/5?closed=1)
for full issue list.
## 1.7.0 (2017/10/17)
* Fixes compatibility with Django 2.0
......
# -*- coding: utf-8 -*-
__version__ = '1.7.0'
__version__ = '1.7.1'
......@@ -370,7 +370,11 @@ class FormHelper(DynamicLayoutHandler):
}
bootstrap_size_match = re.findall('col-(lg|md|sm|xs)-(\d+)', self.label_class)
if bootstrap_size_match:
items['bootstrap_checkbox_offsets'] = ['col-%s-offset-%s' % m for m in bootstrap_size_match]
if template_pack == 'bootstrap4':
offset_pattern = 'offset-%s-%s'
else:
offset_pattern = 'col-%s-offset-%s'
items['bootstrap_checkbox_offsets'] = [offset_pattern % m for m in bootstrap_size_match]
items['attrs'] = {}
if self.attrs:
......
......@@ -143,12 +143,18 @@ class LayoutSlice(object):
else:
function(layout_object)
def update_attributes(self, **kwargs):
def update_attributes(self, **original_kwargs):
"""
Updates attributes of every layout object pointed in `self.slice` using kwargs
"""
def update_attrs(layout_object):
kwargs = original_kwargs.copy()
if hasattr(layout_object, 'attrs'):
if 'css_class' in kwargs:
if 'class' in layout_object.attrs:
layout_object.attrs['class'] += " %s" % kwargs.pop('css_class')
else:
layout_object.attrs['class'] = kwargs.pop('css_class')
layout_object.attrs.update(kwargs)
self.map(update_attrs)
......@@ -6,7 +6,7 @@
{% for choice in field.field.choices %}
<label class="checkbox{% if inline_class %} {{ inline_class }}{% endif %}">
<input type="checkbox"{% if choice.0 in field.value or choice.0|stringformat:"s" in field.value or choice.0|stringformat:"s" == field.value|default_if_none:""|stringformat:"s" %} checked="checked"{% endif %} name="{{ field.html_name }}" id="id_{{ field.html_name }}_{{ forloop.counter }}" value="{{ choice.0|unlocalize }}" {{ field.field.widget.attrs|flatatt }}>{{ choice.1|unlocalize }}
<input type="checkbox"{% if choice.0 in field.value or choice.0|stringformat:"s" in field.value or choice.0|stringformat:"s" == field.value|default_if_none:""|stringformat:"s" %} checked="checked"{% endif %} name="{{ field.html_name }}" id="id_{{ field.id_for_label }}_{{ forloop.counter }}" value="{{ choice.0|unlocalize }}" {{ field.field.widget.attrs|flatatt }}>{{ choice.1|unlocalize }}
</label>
{% endfor %}
......
......@@ -5,8 +5,8 @@
{% include 'bootstrap/layout/field_errors_block.html' %}
{% for choice in field.field.choices %}
<label for="id_{{ field.html_name }}_{{ forloop.counter }}" class="radio{% if inline_class %} {{ inline_class }}{% endif %}">
<input type="radio"{% if choice.0|stringformat:"s" == field.value|default_if_none:""|stringformat:"s" %} checked="checked"{% endif %} name="{{ field.html_name }}" id="id_{{ field.html_name }}_{{ forloop.counter }}" value="{{ choice.0|unlocalize }}" {{ field.field.widget.attrs|flatatt }}>{{ choice.1|unlocalize }}
<label for="id_{{ field.id_for_label }}_{{ forloop.counter }}" class="radio{% if inline_class %} {{ inline_class }}{% endif %}">
<input type="radio"{% if choice.0|stringformat:"s" == field.value|default_if_none:""|stringformat:"s" %} checked="checked"{% endif %} name="{{ field.html_name }}" id="id_{{ field.id_for_label }}_{{ forloop.counter }}" value="{{ choice.0|unlocalize }}" {{ field.field.widget.attrs|flatatt }}>{{ choice.1|unlocalize }}
</label>
{% endfor %}
......
......@@ -8,7 +8,7 @@
{% if not inline_class %}<div class="checkbox">{% endif %}
<label class="{% if inline_class %}checkbox-{{ inline_class }}{% endif %}">
<input type="checkbox"{% if choice.0 in field.value or choice.0|stringformat:"s" in field.value or choice.0|stringformat:"s" == field.value|default_if_none:""|stringformat:"s" %} checked="checked"{% endif %} name="{{ field.html_name }}" id="id_{{ field.html_name }}_{{ forloop.counter }}" value="{{ choice.0|unlocalize }}" {{ field.field.widget.attrs|flatatt }}>{{ choice.1|unlocalize }}
<input type="checkbox"{% if choice.0 in field.value or choice.0|stringformat:"s" in field.value or choice.0|stringformat:"s" == field.value|default_if_none:""|stringformat:"s" %} checked="checked"{% endif %} name="{{ field.html_name }}" id="id_{{ field.id_for_label }}_{{ forloop.counter }}" value="{{ choice.0|unlocalize }}" {{ field.field.widget.attrs|flatatt }}>{{ choice.1|unlocalize }}
</label>
{% if not inline_class %}</div>{% endif %}
{% endfor %}
......
......@@ -6,8 +6,8 @@
{% for choice in field.field.choices %}
{% if not inline_class %}<div class="radio">{% endif %}
<label for="id_{{ field.html_name }}_{{ forloop.counter }}" class="{% if inline_class %}radio-{{ inline_class }}{% endif %}">
<input type="radio"{% if choice.0|stringformat:"s" == field.value|default_if_none:""|stringformat:"s" %} checked="checked"{% endif %} name="{{ field.html_name }}" id="id_{{ field.html_name }}_{{ forloop.counter }}" value="{{ choice.0|unlocalize }}" {{ field.field.widget.attrs|flatatt }}>{{ choice.1|unlocalize }}
<label for="id_{{ field.id_for_label }}_{{ forloop.counter }}" class="{% if inline_class %}radio-{{ inline_class }}{% endif %}">
<input type="radio"{% if choice.0|stringformat:"s" == field.value|default_if_none:""|stringformat:"s" %} checked="checked"{% endif %} name="{{ field.html_name }}" id="id_{{ field.id_for_label }}_{{ forloop.counter }}" value="{{ choice.0|unlocalize }}" {{ field.field.widget.attrs|flatatt }}>{{ choice.1|unlocalize }}
</label>
{% if not inline_class %}</div>{% endif %}
{% endfor %}
......
......@@ -4,14 +4,14 @@
{{ field }}
{% else %}
{% if field|is_checkbox %}
<div class="form-group">
<div class="form-group{% if 'form-horizontal' in form_class %} row{% endif %}">
{% if label_class %}
<div class="{% for offset in bootstrap_checkbox_offsets %}{{ offset }} {% endfor %}{{ field_class }}">
{% endif %}
{% endif %}
<{% if tag %}{{ tag }}{% else %}div{% endif %} id="div_{{ field.auto_id }}" {% if not field|is_checkbox %}class="form-group{% else %}class="checkbox{% endif %}{% if wrapper_class %} {{ wrapper_class }}{% endif %}{% if form_group_wrapper_class %} {{ form_group_wrapper_class }}{% endif %}{% if form_show_errors%}{% if field.errors %} has-danger{% endif %}{% endif %}{% if field.css_classes %} {{ field.css_classes }}{% endif %}">
<{% if tag %}{{ tag }}{% else %}div{% endif %} id="div_{{ field.auto_id }}" class="{% if not field|is_checkbox %}form-group{% if 'form-horizontal' in form_class %} row{% endif %}{% else %}form-check{% endif %}{% if wrapper_class %} {{ wrapper_class }}{% endif %}{% if form_show_errors%}{% if field.errors %} invalid-feedback{% endif %}{% endif %}{% if field.css_classes %} {{ field.css_classes }}{% endif %}">
{% if field.label and not field|is_checkbox and form_show_labels %}
<label for="{{ field.id_for_label }}" class="form-control-label {{ label_class }}{% if field.field.required %} requiredField{% endif %}">
<label for="{{ field.id_for_label }}" class="col-form-label {{ label_class }}{% if field.field.required %} requiredField{% endif %}">
{{ field.label|safe }}{% if field.field.required %}<span class="asteriskField">*</span>{% endif %}
</label>
{% endif %}
......@@ -26,8 +26,8 @@
{% if not field|is_checkboxselectmultiple and not field|is_radioselect %}
{% if field|is_checkbox and form_show_labels %}
<label for="{{ field.id_for_label }}" class="{% if field.field.required %} requiredField{% endif %}">
{% crispy_field field %}
<label for="{{ field.id_for_label }}" class="form-check-label{% if field.field.required %} requiredField{% endif %}">
{% crispy_field field 'class' 'form-check-input' %}
{{ field.label|safe }}{% if field.field.required %}<span class="asteriskField">*</span>{% endif %}
</label>
{% include 'bootstrap4/layout/help_text_and_errors.html' %}
......
{% if inputs %}
<div class="form-group{% if form_group_wrapper_class %} {{ form_group_wrapper_class }}{% endif %}">
<div class="form-group{% if 'form-horizontal' in form_class %} row{% endif %}">
{% if label_class %}
<div class="aab {{ label_class }}"></div>
{% endif %}
......
{% load crispy_forms_filters %}
{% load l10n %}
<div class="{{ field_class }}"{% if flat_attrs %} {{ flat_attrs|safe }}{% endif %}>
<div class="{% if inline_class %}form-check{% endif %}{% if field_class %} {{ field_class }}{% endif %}"{% if flat_attrs %} {{ flat_attrs|safe }}{% endif %}>
{% include 'bootstrap4/layout/field_errors_block.html' %}
{% for choice in field.field.choices %}
{% if not inline_class %}<div class="checkbox">{% endif %}
<label class="{% if inline_class %}checkbox-{{ inline_class }}{% endif %}">
<input type="checkbox"{% if choice.0 in field.value or choice.0|stringformat:"s" in field.value or choice.0|stringformat:"s" == field.value|default_if_none:""|stringformat:"s" %} checked="checked"{% endif %} name="{{ field.html_name }}" id="id_{{ field.html_name }}_{{ forloop.counter }}" value="{{ choice.0|unlocalize }}" {{ field.field.widget.attrs|flatatt }}>
{% if not inline_class %}<div class="form-check">{% endif %}
<label id="id_{{ field.id_for_label }}_{{ forloop.counter }}" class="form-check-{% if inline_class %}{{ inline_class }}{% else %}label{% endif %}">
<input type="checkbox" class="form-check-input"{% if choice.0 in field.value or choice.0|stringformat:"s" in field.value or choice.0|stringformat:"s" == field.value|default_if_none:""|stringformat:"s" %} checked="checked"{% endif %} name="{{ field.html_name }}" id="id_{{ field.id_for_label }}_{{ forloop.counter }}" value="{{ choice.0|unlocalize }}" {{ field.field.widget.attrs|flatatt }}>
{{ choice.1|unlocalize }}
</label>
{% if not inline_class %}</div>{% endif %}
......
{% if field.is_hidden %}
{{ field }}
{% else %}
<div id="div_{{ field.auto_id }}" class="form-group{% if wrapper_class %} {{ wrapper_class }}{% endif %}{% if form_show_errors and field.errors %} has-danger{% endif %}{% if field.css_classes %} {{ field.css_classes }}{% endif %}">
<div id="div_{{ field.auto_id }}" class="form-group{% if 'form-horizontal' in form_class %} row{% endif %}{% if wrapper_class %} {{ wrapper_class }}{% endif %}{% if form_show_errors and field.errors %} has-danger{% endif %}{% if field.css_classes %} {{ field.css_classes }}{% endif %}">
{% if field.label %}
<label for="{{ field.auto_id }}" class="form-control-label {{ label_class }}{% if field.field.required %} requiredField{% endif %}">
<label for="{{ field.auto_id }}" class="{{ label_class }}{% if not inline_class %} col-form-label{% endif %}{% if field.field.required %} requiredField{% endif %}">
{{ field.label|safe }}{% if field.field.required %}<span class="asteriskField">*</span>{% endif %}
</label>
{% endif %}
......
{% load crispy_forms_field %}
<div{% if div.css_id %} id="{{ div.css_id }}"{% endif %} class="form-group{% if wrapper_class %} {{ wrapper_class }}{% endif %}{% if form_show_errors and field.errors %} has-danger{% endif %}{% if field.css_classes %} {{ field.css_classes }}{% endif %}{% if div.css_class %} {{ div.css_class }}{% endif %}" {{ div.flat_attrs|safe }}>
<div{% if div.css_id %} id="{{ div.css_id }}"{% endif %} class="form-group{% if 'form-horizontal' in form_class %} row{% endif %}{% if wrapper_class %} {{ wrapper_class }}{% endif %}{% if form_show_errors and field.errors %} has-danger{% endif %}{% if field.css_classes %} {{ field.css_classes }}{% endif %}{% if div.css_class %} {{ div.css_class }}{% endif %}" {{ div.flat_attrs|safe }}>
{% if field.label and form_show_labels %}
<label for="{{ field.id_for_label }}" class="form-control-label {{ label_class }}{% if field.field.required %} requiredField{% endif %}">
<label for="{{ field.id_for_label }}" class="col-form-label {{ label_class }}{% if field.field.required %} requiredField{% endif %}">
{{ field.label|safe }}{% if field.field.required %}<span class="asteriskField">*</span>{% endif %}
</label>
{% endif %}
......
<div{% if formactions.attrs %} {{ formactions.flat_attrs|safe }}{% endif %} class="form-group">
<div{% if formactions.attrs %} {{ formactions.flat_attrs|safe }}{% endif %} class="form-group row">
{% if label_class %}
<div class="aab {{ label_class }}"></div>
{% endif %}
......
......@@ -2,6 +2,6 @@
{% if help_text_inline %}
<span id="hint_{{ field.auto_id }}" class="text-muted">{{ field.help_text|safe }}</span>
{% else %}
<small id="hint_{{ field.auto_id }}" class="text-muted">{{ field.help_text|safe }}</small>
<small id="hint_{{ field.auto_id }}" class="form-text text-muted">{{ field.help_text|safe }}</small>
{% endif %}
{% endif %}
......@@ -4,14 +4,14 @@
{{ field }}
{% else %}
{% if field|is_checkbox %}
<div id="div_{{ field.auto_id }}" class="checkbox{% if wrapper_class %} {{ wrapper_class }}{% endif %}">
<label for="{{ field.id_for_label }}" class="{% if field.field.required %} requiredField{% endif %}">
{% crispy_field field 'class' 'checkbox' %}
<div id="div_{{ field.auto_id }}" class="form-check form-check-inline{% if wrapper_class %} {{ wrapper_class }}{% endif %}">
<label for="{{ field.id_for_label }}" class="form-check-label{% if field.field.required %} requiredField{% endif %}">
{% crispy_field field 'class' 'form-check-input' %}
{{ field.label|safe }}
</label>
</div>
{% else %}
<div id="div_{{ field.auto_id }}" class="form-group{% if wrapper_class %} {{ wrapper_class }}{% endif %}">
<div id="div_{{ field.auto_id }}" class="input-group{% if wrapper_class %} {{ wrapper_class }}{% endif %}">
<label for="{{ field.id_for_label }}" class="sr-only{% if field.field.required %} requiredField{% endif %}">
{{ field.label|safe }}
</label>
......
......@@ -3,10 +3,10 @@
{% if field.is_hidden %}
{{ field }}
{% else %}
<div id="div_{{ field.auto_id }}" class="form-group{% if wrapper_class %} {{ wrapper_class }}{% endif %}{% if form_group_wrapper_class %} {{ form_group_wrapper_class }}{% endif %}{% if form_show_errors and field.errors %} has-danger{% endif %}{% if field.css_classes %} {{ field.css_classes }}{% endif %}">
<div id="div_{{ field.auto_id }}" class="form-group{% if wrapper_class %} {{ wrapper_class }}{% endif %}{% if 'form-horizontal' in form_class %} row{% endif %}{% if form_group_wrapper_class %} {{ form_group_wrapper_class }}{% endif %}{% if form_show_errors and field.errors %} has-danger{% endif %}{% if field.css_classes %} {{ field.css_classes }}{% endif %}">
{% if field.label and form_show_labels %}
<label for="{{ field.id_for_label }}" class="form-control-label {{ label_class }}{% if field.field.required %} requiredField{% endif %}">
<label for="{{ field.id_for_label }}" class="col-form-label {{ label_class }}{% if field.field.required %} requiredField{% endif %}">
{{ field.label|safe }}{% if field.field.required %}<span class="asteriskField">*</span>{% endif %}
</label>
{% endif %}
......@@ -18,13 +18,22 @@
{% if crispy_appended_text %}<span class="input-group{% if active %} active{% endif %}{% if input_size %} {{ input_size }}{% endif %}">{{ crispy_appended_text|safe }}</span>{% endif %}
{% else %}
<div class="input-group">
{% if crispy_prepended_text %}<span class="input-group-addon{% if active %} active{% endif %}{% if input_size %} {{ input_size }}{% endif %}">{{ crispy_prepended_text|safe }}</span>{% endif %}
{% if crispy_prepended_text %}
<div class="input-group-prepend{% if active %} active{% endif %}{% if input_size %} {{ input_size }}{% endif %}">
<span class="input-group-text">{{ crispy_prepended_text|safe }}</span>
</div>
{% endif %}
{% crispy_field field %}
{% if crispy_appended_text %}<span class="input-group-addon{% if active %} active{% endif %}{% if input_size %} {{ input_size }}{% endif %}">{{ crispy_appended_text|safe }}</span>{% endif %}
{% if crispy_appended_text %}
<div class="input-group-append{% if active %} active{% endif %}{% if input_size %} {{ input_size }}{% endif %}">
<span class="input-group-text">{{ crispy_appended_text|safe }}</span>
</div>
{% endif %}
</div>
{% endif %}
{% endif %}
{% include 'bootstrap4/layout/help_text_and_errors.html' %}
</div>
</div>
{% endif %}
{% load crispy_forms_filters %}
{% load l10n %}
<div class="{{ field_class }}"{% if flat_attrs %} {{ flat_attrs|safe }}{% endif %}>
<div class="{% if inline_class %}form-check{% endif %}{% if field_class %} {{ field_class }}{% endif %}"{% if flat_attrs %} {{ flat_attrs|safe }}{% endif %}>
{% include 'bootstrap4/layout/field_errors_block.html' %}
{% for choice in field.field.choices %}
{% if not inline_class %}<div class="radio">{% endif %}
<label for="id_{{ field.html_name }}_{{ forloop.counter }}" class="{% if inline_class %}radio-{{ inline_class }}{% endif %}">
<input type="radio"{% if choice.0|stringformat:"s" == field.value|default_if_none:""|stringformat:"s" %} checked="checked"{% endif %} name="{{ field.html_name }}" id="id_{{ field.html_name }}_{{ forloop.counter }}" value="{{ choice.0|unlocalize }}" {{ field.field.widget.attrs|flatatt }}>
{% if not inline_class %}<div class="form-check">{% endif %}
<label for="id_{{ field.id_for_label }}_{{ forloop.counter }}" class="form-check-{% if inline_class %}{{ inline_class }}{% else %}label{% endif %}">
<input type="radio" class="form-check-input"{% if choice.0|stringformat:"s" == field.value|default_if_none:""|stringformat:"s" %} checked="checked"{% endif %} name="{{ field.html_name }}" id="id_{{ field.id_for_label }}_{{ forloop.counter }}" value="{{ choice.0|unlocalize }}" {{ field.field.widget.attrs|flatatt }}>
{{ choice.1|unlocalize }}
</label>
{% if not inline_class %}</div>{% endif %}
......
{% if field.is_hidden %}
{{ field }}
{% else %}
<div id="div_{{ field.auto_id }}" class="form-group{% if wrapper_class %} {{ wrapper_class }}{% endif %}{% if form_show_errors and field.errors %} has-danger{% endif %}{% if field.css_classes %} {{ field.css_classes }}{% endif %}">
<div id="div_{{ field.auto_id }}" class="form-group{% if 'form-horizontal' in form_class %} row{% endif %}{% if wrapper_class %} {{ wrapper_class }}{% endif %}{% if form_show_errors and field.errors %} has-danger{% endif %}{% if field.css_classes %} {{ field.css_classes }}{% endif %}">
{% if field.label %}
<label for="{{ field.auto_id }}" class="form-control-label {{ label_class }}{% if field.field.required %} requiredField{% endif %}">
<label for="{{ field.auto_id }}" class="{{ label_class }}{% if not inline_class %} col-form-label{% endif %}{% if field.field.required %} requiredField{% endif %}">
{{ field.label|safe }}{% if field.field.required %}<span class="asteriskField">*</span>{% endif %}
</label>
{% endif %}
......
<li class="tab-pane{% if 'active' in link.css_class %} active{% endif %}"><a href="#{{ link.css_id }}" data-toggle="tab">{{ link.name|capfirst }}{% if tab.errors %}!{% endif %}</a></li>
<li class="nav-item"><a class="nav-link{% if 'active' in link.css_class %} active{% endif %}" href="#{{ link.css_id }}" data-toggle="tab">{{ link.name|capfirst }}{% if tab.errors %}!{% endif %}</a></li>
{% load crispy_forms_field %}
<div id="div_{{ field.auto_id }}" class="form-group{% if form_show_errors and field.errors %} error{% endif %}{% if field.css_classes %} {{ field.css_classes }}{% endif %}">
<label class="form-control-label {{ label_class }}{% if field.field.required %} requiredField{% endif %}">{{ field.label|safe }}{% if field.field.required %}<span class="asteriskField">*</span>{% endif %}</label>
<div id="div_{{ field.auto_id }}" class="form-group{% if 'form-horizontal' in form_class %} row{% endif %}{% if form_show_errors and field.errors %} error{% endif %}{% if field.css_classes %} {{ field.css_classes }}{% endif %}">
<label class="col-form-label {{ label_class }}{% if field.field.required %} requiredField{% endif %}">{{ field.label|safe }}{% if field.field.required %}<span class="asteriskField">*</span>{% endif %}</label>
<div class="{{ field_class }}">
{% crispy_field field 'disabled' 'disabled' %}
{% include 'bootstrap4/layout/help_text.html' %}
......
......@@ -21,7 +21,7 @@
<tr>
{% for field in formset.forms.0 %}
{% if field.label and not field|is_checkbox and not field.is_hidden %}
<th for="{{ field.auto_id }}" class="form-control-label {% if field.field.required %}requiredField{% endif %}">
<th for="{{ field.auto_id }}" class="col-form-label {% if field.field.required %}requiredField{% endif %}">
{{ field.label|safe }}{% if field.field.required %}<span class="asteriskField">*</span>{% endif %}
</th>
{% endif %}
......@@ -31,7 +31,7 @@
</thead>
<tbody>
<tr class="hidden empty-form">
<tr class="d-none empty-form">
{% for field in formset.empty_form %}
{% include 'bootstrap4/field.html' with tag="td" form_show_labels=False %}
{% endfor %}
......
......@@ -120,7 +120,7 @@ class CrispyFieldNode(template.Node):
css_class = class_name
if (
template_pack in ['bootstrap3']
template_pack == 'bootstrap3'
and not is_checkbox(field)
and not is_file(field)
and not is_multivalue(field)
......@@ -130,7 +130,7 @@ class CrispyFieldNode(template.Node):
css_class += ' form-control-danger'
if (
template_pack in ['bootstrap4']
template_pack == 'bootstrap4'
and not is_checkbox(field)
and not is_file(field)
and not is_multivalue(field)
......
......@@ -624,10 +624,12 @@ def test_error_text_inline(settings):
html = render_crispy_form(form)
help_class = 'help-inline'
help_tag_name = 'p'
if settings.CRISPY_TEMPLATE_PACK == 'bootstrap3':
help_class = 'help-block'
elif settings.CRISPY_TEMPLATE_PACK == 'bootstrap4':
help_class = 'invalid-feedback'
help_tag_name = 'div'
matches = re.findall(
'<span id="error_\d_\w*" class="%s"' % help_class, html, re.MULTILINE
......@@ -644,9 +646,10 @@ def test_error_text_inline(settings):
help_class = 'help-block'
elif settings.CRISPY_TEMPLATE_PACK == 'bootstrap4':
help_class = 'invalid-feedback'
help_tag_name = 'p'
matches = re.findall(
'<p id="error_\d_\w*" class="%s"' % help_class,
'<%s id="error_\d_\w*" class="%s"' % (help_tag_name, help_class),
html,
re.MULTILINE
)
......@@ -709,7 +712,7 @@ def test_error_and_help_inline():
# Check that error goes before help, otherwise CSS won't work
error_position = html.find('<span id="error_1_id_email" class="help-inline">')
help_position = html.find('<small id="hint_id_email" class="text-muted">')
help_position = html.find('<small id="hint_id_email" class="form-text text-muted">')
assert error_position < help_position
......@@ -785,7 +788,7 @@ def test_label_class_and_field_class_bs4():
html = render_crispy_form(form)
assert '<div class="form-group">' in html
assert '<div class="col-lg-offset-2 col-lg-8">' in html
assert '<div class="offset-lg-2 col-lg-8">' in html
assert html.count('col-lg-8') == 7
form.helper.label_class = 'col-sm-3 col-md-4'
......@@ -793,10 +796,26 @@ def test_label_class_and_field_class_bs4():
html = render_crispy_form(form)
assert '<div class="form-group">' in html
assert '<div class="col-sm-offset-3 col-md-offset-4 col-sm-8 col-md-6">' in html
assert '<div class="offset-sm-3 offset-md-4 col-sm-8 col-md-6">' in html
assert html.count('col-sm-8') == 7
@only_bootstrap4
def test_form_group_with_form_inline_bs4():
form = SampleForm()
form.helper = FormHelper()
html = render_crispy_form(form)
assert '<div class="form-group">' in html
# .row class shouldn't be together with .form-group in inline forms
form = SampleForm()
form.helper = FormHelper()
form.helper.form_class = 'form-inline'
form.helper.field_template = 'bootstrap4/layout/inline_field.html'
html = render_crispy_form(form)
assert '<div class="form-group row">' not in html
@only_bootstrap4
def test_template_pack_bs4():
form = SampleForm()
......
......@@ -10,7 +10,7 @@ from django.shortcuts import render_to_response
from django.template import Context, Template
from django.utils.translation import ugettext_lazy as _
from crispy_forms.bootstrap import InlineCheckboxes
from crispy_forms.bootstrap import Field, InlineCheckboxes
from crispy_forms.compatibility import PY2
from crispy_forms.helper import FormHelper
from crispy_forms.layout import (
......@@ -306,9 +306,12 @@ def test_formset_layout(settings):
assert html.count('Note for first form only') == 1
if settings.CRISPY_TEMPLATE_PACK == 'uni_form':
assert html.count('formRow') == 3
else:
elif settings.CRISPY_TEMPLATE_PACK in ('bootstrap3', 'bootstrap4'):
assert html.count('row') == 3
if settings.CRISPY_TEMPLATE_PACK == 'bootstrap4':
assert html.count('form-group') == 18
def test_modelformset_layout():
CrispyModelFormSet = modelformset_factory(CrispyTestModel, form=SampleForm4, extra=3)
......@@ -556,8 +559,10 @@ def test_keepcontext_context_manager(settings):
if settings.CRISPY_TEMPLATE_PACK == 'bootstrap':
assert response.content.count(b'checkbox inline') == 3
elif settings.CRISPY_TEMPLATE_PACK in ['bootstrap3', 'bootstrap4']:
elif settings.CRISPY_TEMPLATE_PACK == 'bootstrap3':
assert response.content.count(b'checkbox-inline') == 3
elif settings.CRISPY_TEMPLATE_PACK == 'bootstrap4':
assert response.content.count(b'form-check-inline') == 3
@only_bootstrap3
......@@ -595,8 +600,34 @@ def test_bootstrap4_form_inline():
html = render_crispy_form(form)
assert html.count('class="form-inline"') == 1
assert html.count('class="form-group"') == 3
assert html.count('class="input-group"') == 3
assert html.count('<label for="id_email" class="sr-only') == 1
assert html.count('id="div_id_email" class="form-group"') == 1
assert html.count('id="div_id_email" class="input-group"') == 1
assert html.count('placeholder="email"') == 1
assert html.count('</label> <input') == 3
def test_update_attributes_class():
form = SampleForm()
form.helper = FormHelper()
form.helper.layout = Layout(
'email',
Field('password1'),
'password2',
)
form.helper['password1'].update_attributes(css_class='hello')
html = render_crispy_form(form)
assert html.count(
' class="hello textinput'
) == 1
form.helper = FormHelper()
form.helper.layout = Layout(
'email',
Field('password1', css_class="hello"),
'password2',
)
form.helper['password1'].update_attributes(css_class='hello2')
html = render_crispy_form(form)
assert html.count(
' class="hello hello2 textinput'
) == 1
......@@ -93,9 +93,7 @@ def test_field_wrapper_class(settings):
html = render_crispy_form(form)
if settings.CRISPY_TEMPLATE_PACK == 'bootstrap':
assert html.count('class="control-group testing"') == 1
elif settings.CRISPY_TEMPLATE_PACK == 'bootstrap3':
assert html.count('class="form-group testing"') == 1
elif settings.CRISPY_TEMPLATE_PACK == 'bootstrap4':
elif settings.CRISPY_TEMPLATE_PACK in ('bootstrap3', 'bootstrap4'):
assert html.count('class="form-group testing"') == 1
......@@ -139,7 +137,7 @@ def test_i18n():
@only_bootstrap
class TestBootstrapLayoutObjects(object):
def test_custom_django_widget(self):
def test_custom_django_widget(self, settings):
class CustomRadioSelect(forms.RadioSelect):
pass
......@@ -153,13 +151,20 @@ class TestBootstrapLayoutObjects(object):
form.helper.layout = Layout('inline_radios')
html = render_crispy_form(form)
assert 'class="radio"' in html
if settings.CRISPY_TEMPLATE_PACK == 'bootstrap4':
assert 'class="form-check"' in html
else:
assert 'class="radio"' in html
# Make sure an inherited CheckboxSelectMultiple gets rendered as it
form.fields['checkboxes'].widget = CustomCheckboxSelectMultiple()
form.helper.layout = Layout('checkboxes')
html = render_crispy_form(form)
assert 'class="checkbox"' in html
if settings.CRISPY_TEMPLATE_PACK == 'bootstrap4':
assert 'class="form-check"' in html
else:
assert 'class="checkbox"' in html
def test_prepended_appended_text(self, settings):
test_form = SampleForm()
......@@ -179,30 +184,33 @@ class TestBootstrapLayoutObjects(object):
assert dom.count(parse_html('<span class="add-on">#</span>')) == 1
assert dom.count(parse_html('<span class="add-on">$</span>')) == 1
if settings.CRISPY_TEMPLATE_PACK in ['bootstrap3', 'bootstrap4']:
if settings.CRISPY_TEMPLATE_PACK == 'bootstrap3':
assert html.count('<span class="input-group-addon">@</span>') == 1
assert html.count(
'<span class="input-group-addon">gmail.com</span>') == 1
assert html.count('<span class="input-group-addon">#</span>') == 1
assert html.count('<span class="input-group-addon">$</span>') == 1
if settings.CRISPY_TEMPLATE_PACK == 'bootstrap3':
test_form.helper.layout = Layout(
PrependedAppendedText('email', '@', 'gmail.com',
css_class='input-lg'), )
html = render_crispy_form(test_form)
assert 'class="input-lg' in html
assert contains_partial(html, '<span class="input-group-addon input-lg"/>' )
assert contains_partial(html, '<span class="input-group-addon input-lg"/>')
if settings.CRISPY_TEMPLATE_PACK == 'bootstrap4':
assert html.count('<span class="input-group-text">@</span>') == 1
assert html.count(
'<span class="input-group-text">gmail.com</span>') == 1
assert html.count('<span class="input-group-text">#</span>') == 1
assert html.count('<span class="input-group-text">$</span>') == 1
test_form.helper.layout = Layout(
PrependedAppendedText('email', '@', 'gmail.com',
css_class='form-control-lg'), )
html = render_crispy_form(test_form)
assert 'class="form-control-lg' in html
assert contains_partial(html, '<span class="input-group-addon"/>')
assert contains_partial(html, '<span class="input-group-text"/>')
def test_inline_radios(self, settings):
test_form = CheckboxesSampleForm()
......@@ -214,8 +222,10 @@ class TestBootstrapLayoutObjects(object):
if settings.CRISPY_TEMPLATE_PACK == 'bootstrap':
assert html.count('radio inline"') == 2
elif settings.CRISPY_TEMPLATE_PACK in ['bootstrap3', 'bootstrap4']:
elif settings.CRISPY_TEMPLATE_PACK == 'bootstrap3':
assert html.count('radio-inline"') == 2
elif settings.CRISPY_TEMPLATE_PACK == 'bootstrap4':
assert html.count('form-check-inline"') == 2
def test_accordion_and_accordiongroup(self, settings):
test_form = SampleForm()
......@@ -310,7 +320,7 @@ class TestBootstrapLayoutObjects(object):
assert html.count('<div class="alert alert-block"') == 1
assert html.count('Testing...') == 1
def test_tab_and_tab_holder(self):
def test_tab_and_tab_holder(self, settings):
test_form = SampleForm()
test_form.helper = FormHelper()
test_form.helper.layout = Layout(
......@@ -319,7 +329,7 @@ class TestBootstrapLayoutObjects(object):
'one',
'first_name',
css_id="custom-name",
css_class="first-tab-class"
css_class="first-tab-class active"
),
Tab(
'two',
......@@ -330,12 +340,20 @@ class TestBootstrapLayoutObjects(object):
)
html = render_crispy_form(test_form)
assert html.count(
'<li class="tab-pane active"><a href="#custom-name" data-toggle="tab">One</a></li>'
) == 1
if settings.CRISPY_TEMPLATE_PACK == 'bootstrap4':
assert html.count(
'<ul class="nav nav-tabs"> <li class="nav-item"><a class="nav-link active" href="#custom-name" data-toggle="tab">One</a></li>'
) == 1
assert html.count('tab-pane') == 2
else:
assert html.count(
'<ul class="nav nav-tabs"> <li class="tab-pane active"><a href="#custom-name" data-toggle="tab">One</a></li>'
) == 1
assert html.count('<li class="tab-pane') == 2
assert html.count('tab-pane') == 4
assert html.count('class="tab-pane first-tab-class active"') == 1
assert html.count('<li class="tab-pane') == 2
assert html.count('tab-pane') == 4
assert html.count('<div id="custom-name"') == 1
assert html.count('<div id="two"') == 1
assert html.count('name="first_name"') == 1
......@@ -365,15 +383,20 @@ class TestBootstrapLayoutObjects(object):
# but not duplicate class
test_form = SampleForm()
html = render_crispy_form(test_form)
assert html.count('class="tab-pane active active"') == 0
assert html.count('class="nav-item active active"') == 0
# render a new form, now with errors
test_form = SampleForm(data={'val1': 'foo'})
html = render_crispy_form(test_form)
tab_class = 'tab-pane'
# if settings.CRISPY_TEMPLATE_PACK == 'bootstrap4':
# tab_class = 'nav-link'
# else:
# tab_class = 'tab-pane'
# tab 1 should not be active
assert html.count('<div id="one" \n class="tab-pane active') == 0
assert html.count('<div id="one" \n class="{} active'.format(tab_class)) == 0
# tab 2 should be active
assert html.count('<div id="two" \n class="tab-pane active') == 1
assert html.count('<div id="two" \n class="{} active'.format(tab_class)) == 1
def test_radio_attrs(self):
form = CheckboxesSampleForm()
......@@ -399,9 +422,7 @@ class TestBootstrapLayoutObjects(object):
html = render_crispy_form(form)
form_group_class = 'control-group'
if settings.CRISPY_TEMPLATE_PACK == 'bootstrap3':
form_group_class = 'form-group'
elif settings.CRISPY_TEMPLATE_PACK == 'bootstrap4':
if settings.CRISPY_TEMPLATE_PACK in ('bootstrap3', 'bootstrap4'):
form_group_class = 'form-group'
assert html.count('class="%s extra"' % form_group_class) == 1
......@@ -454,5 +475,8 @@ class TestBootstrapLayoutObjects(object):
assert html.count('checkbox inline"') == 3
assert html.count('inline"') == 3
elif settings.CRISPY_TEMPLATE_PACK in ['bootstrap3', 'bootstrap4']:
assert html.count('checkbox-inline"') == 3
assert html.count('inline="True"') == 4