Skip to content

Commit

Permalink
Do noy allow floating labels on FileInput
Browse files Browse the repository at this point in the history
  • Loading branch information
dyve committed Mar 22, 2021
1 parent cfa9ee2 commit a62d5f1
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 19 deletions.
11 changes: 11 additions & 0 deletions docs/forms.rst
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,14 @@ Bootstrap 5 offers Input groups to combine fields and add-ons (both before and a

Note: input-group needs has-validation
https://github.com/twbs/bootstrap/blob/6b3254536bac263c39e3a536c3c13945210d91b2/site/content/docs/5.0/migration.md

Floating labels
---------------

Reference: https://getbootstrap.com/docs/5.0/forms/floating-labels/

This behavior can be triggere dby setting `layout="floating"`.

Floating labels are supported for widgets that can use `form-control`. An exception is `FileInput` and its descendants, those labels cannot be floating.

Setting `layout="floating"` has no effect on widgets that are not supported.
22 changes: 11 additions & 11 deletions example/templates/app/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,17 @@
<div class="container">
<h1>{% block title %}(no title){% endblock %}</h1>

<p>
<a href="{% url 'home' %}">home</a>
<a href="{% url 'formset_default' %}">formset</a>
<a href="{% url 'form_default' %}">form</a>
<a href="{% url 'form_by_field' %}">form_by_field</a>
<a href="{% url 'form_horizontal' %}">form_horizontal</a>
<a href="{% url 'form_inline' %}">form_inline</a>
<a href="{% url 'form_with_files' %}">form_with_files</a>
<a href="{% url 'pagination' %}">pagination</a>
<a href="{% url 'misc' %}">miscellaneous</a>
</p>
<ul class="nav nav-pills">
<li class="nav-item"><a class="nav-link" href="{% url 'home' %}">home</a></li>
<li class="nav-item"><a class="nav-link" href="{% url 'formset_default' %}">formset</a></li>
<li class="nav-item"><a class="nav-link" href="{% url 'form_default' %}">form</a></li>
<li class="nav-item"><a class="nav-link" href="{% url 'form_by_field' %}">form_by_field</a></li>
<li class="nav-item"><a class="nav-link" href="{% url 'form_horizontal' %}">form_horizontal</a></li>
<li class="nav-item"><a class="nav-link" href="{% url 'form_inline' %}">form_inline</a></li>
<li class="nav-item"><a class="nav-link" href="{% url 'form_with_files' %}">form_with_files</a></li>
<li class="nav-item"><a class="nav-link" href="{% url 'pagination' %}">pagination</a></li>
<li class="nav-item"><a class="nav-link" href="{% url 'misc' %}">miscellaneous</a></li>
</ul>

{% autoescape off %}{% bootstrap_messages %}{% endautoescape %}

Expand Down
2 changes: 1 addition & 1 deletion example/templates/app/form_with_files.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

{% block content %}

<form role="form" method="post" enctype="multipart/form-data" {% if layout != 'vertical' %}class="form-{{ layout }}"{% endif %}>
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{% bootstrap_form form layout=layout %}
{% buttons submit='OK' reset="Cancel" %}{% endbuttons %}
Expand Down
28 changes: 21 additions & 7 deletions src/django_bootstrap5/renderers.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,19 @@ def _render(self):
class FieldRenderer(BaseRenderer):
"""Default field renderer."""

FORM_CONTROL_WIDGETS = (
TextInput,
NumberInput,
EmailInput,
URLInput,
DateInput,
TimeInput,
Textarea,
PasswordInput,
FileInput,
)
FLOATING_WIDGETS = (TextInput, NumberInput, EmailInput, URLInput, DateInput, TimeInput, Textarea, PasswordInput)

def __init__(self, field, *args, **kwargs):
if not isinstance(field, BoundField):
raise BootstrapError('Parameter "field" should contain a valid Django BoundField.')
Expand Down Expand Up @@ -268,17 +281,18 @@ def __init__(self, field, *args, **kwargs):

@property
def is_floating(self):
return super().is_floating and self.is_form_control_widget(self.widget)
return super().is_floating and self.can_widget_float(self.widget) and self.is_widget_form_control(self.widget)

def restore_widget_attrs(self):
self.widget.attrs = self.initial_attrs.copy()

def is_form_control_widget(self, widget):
def is_widget_form_control(self, widget):
"""Return whether given widget is of type `form-control`."""
return isinstance(
widget,
(TextInput, NumberInput, EmailInput, URLInput, DateInput, TimeInput, Textarea, PasswordInput, FileInput),
)
return isinstance(widget, self.FORM_CONTROL_WIDGETS)

def can_widget_float(self, widget):
"""Return whether given widget can be set to `form-floating` behavior."""
return isinstance(widget, self.FLOATING_WIDGETS)

def add_widget_class_attrs(self, widget=None):
if widget is None:
Expand All @@ -287,7 +301,7 @@ def add_widget_class_attrs(self, widget=None):
classes = widget.attrs.get("class", "")
if ReadOnlyPasswordHashWidget is not None and isinstance(widget, ReadOnlyPasswordHashWidget):
classes = merge_css_classes("form-control-static", classes)
elif self.is_form_control_widget(widget):
elif self.is_widget_form_control(widget):
classes = merge_css_classes("form-control", classes)
size_prefix = "form-control"
elif isinstance(widget, Select):
Expand Down
22 changes: 22 additions & 0 deletions tests/test_bootstrap_field.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

class BootstrapFieldTest(TestCase):
def test_bootstrap_field_text(self):
"""Test field with text widget."""

class TestForm(forms.Form):
test = forms.CharField()

Expand All @@ -31,6 +33,26 @@ class TestForm(forms.Form):
),
)

def test_bootstrap_field_text_floating(self):
"""Test field with text widget in floating layout."""

class TestForm(forms.Form):
test = forms.CharField()

test_form = TestForm()
html = render_template_with_bootstrap(
"{% bootstrap_field form.test layout='floating' %}", context={"form": test_form}
)
self.assertHTMLEqual(
html,
(
'<div class="django_bootstrap5-req mb-3 form-floating">'
'<input class="form-control" id="id_test" name="test" placeholder="Test" required type="text">'
'<label for="id_test" class="form-label">Test</label>'
"</div>"
),
)

def test_bootstrap_field_file(self):
class TestForm(forms.Form):
test = forms.FileField()
Expand Down

0 comments on commit a62d5f1

Please sign in to comment.