Skip to content

Commit

Permalink
Add input classes in template rather that Form
Browse files Browse the repository at this point in the history
  • Loading branch information
christophehenry committed Jan 31, 2024
1 parent 43de9c5 commit 8b5abf0
Show file tree
Hide file tree
Showing 7 changed files with 49 additions and 44 deletions.
37 changes: 6 additions & 31 deletions dsfr/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
from django.forms.renderers import DjangoTemplates, get_default_renderer
from django.utils.functional import cached_property

from dsfr.utils import dsfr_input_class_attr


class DsfrDjangoTemplates(DjangoTemplates):
@cached_property
Expand All @@ -26,12 +28,10 @@ class DsfrBaseForm(forms.Form):
A base form that adds the necessary class on relevant fields
"""

# These input widgets don't need the fr-input class
WIDGETS_NO_FR_INPUT = [
forms.widgets.CheckboxInput,
forms.widgets.FileInput,
forms.widgets.ClearableFileInput,
]
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for visible in self.visible_fields():
dsfr_input_class_attr(visible)

@property
def default_renderer(self):
Expand All @@ -43,31 +43,6 @@ def default_renderer(self):
else get_default_renderer()
)

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for visible in self.visible_fields():
"""
Depending on the widget, we have to add some classes:
- on the outer group
- on the form field itsef
If a class is already set, we don't force the DSFR-specific classes.
"""
if "class" not in visible.field.widget.attrs:
if type(visible.field.widget) in [
forms.widgets.Select,
forms.widgets.SelectMultiple,
]:
visible.field.widget.attrs["class"] = "fr-select"
visible.field.widget.group_class = "fr-select-group"
elif type(visible.field.widget) == forms.widgets.RadioSelect:
visible.field.widget.attrs["dsfr"] = "dsfr"
visible.field.widget.group_class = "fr-radio-group"
elif type(visible.field.widget) == forms.widgets.CheckboxSelectMultiple:
visible.field.widget.attrs["dsfr"] = "dsfr"
elif type(visible.field.widget) not in self.WIDGETS_NO_FR_INPUT:
visible.field.widget.attrs["class"] = "fr-input"

def set_autofocus_on_first_error(self):
"""
Sets the autofocus on the first field with an error message.
Expand Down
6 changes: 3 additions & 3 deletions dsfr/templates/dsfr/form_field_snippets/checkbox_snippet.html
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
{% load widget_tweaks %}
{% load widget_tweaks dsfr_tags %}
<div class="fr-checkbox-group{% if field.errors %} fr-checkbox-group--error{% endif %}{% if field.field.disabled %} fr-input-group--disabled{% endif %}">
{% if field.errors %}
{% with aria_describedby="aria-describedby:"|add:field.auto_id|add:"-desc-error" %}
{{ field|attr:"type:checkbox"|attr:aria_describedby }}
{{ field|dsfr_input_class_attr|attr:"type:checkbox"|attr:aria_describedby }}
{% endwith %}
{% else %}
{{ field|attr:"type:checkbox" }}
{{ field|dsfr_input_class_attr|attr:"type:checkbox" }}
{% endif %}
<label for="{{ field.id_for_label }}" class="fr-label">
{{ field.label_tag }}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{% load widget_tweaks %}
{% load widget_tweaks dsfr_tags %}
<fieldset class="fr-fieldset{% if field.errors %} fr-fieldset--error{% endif %}"
id="checkboxes-{{ field.auto_id }}"
aria-labelledby="{{ field.auto_id }}-legend{% if field.errors %} {{ field.auto_id }}-messages{% endif %}">
Expand All @@ -16,10 +16,10 @@
<div class="fr-checkbox-group{% if field.errors %} fr-checkbox-group--error{% endif %}{% if field.field.disabled %} fr-input-group--disabled{% endif %}">
{% if field.errors %}
{% with aria_describedby="aria-describedby:"|add:field.auto_id|add:"-desc-error" %}
{{ field|attr:"type:checkbox"|attr:aria_describedby }}
{{ field|dsfr_input_class_attr|attr:"type:checkbox"|attr:aria_describedby }}
{% endwith %}
{% else %}
{{ field|attr:"type:checkbox" }}
{{ field|dsfr_input_class_attr|attr:"type:checkbox" }}
{% endif %}
{% if field.errors %}
<div id="{{ field.auto_id }}-desc-error" class="fr-error-text">
Expand Down
6 changes: 3 additions & 3 deletions dsfr/templates/dsfr/form_field_snippets/input_snippet.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{% load widget_tweaks %}
{% load widget_tweaks dsfr_tags %}
{# Generic input snippet used by most of the field types #}
<div class="{{ field.field.widget.group_class|default:'fr-input-group' }}{% if field.errors %} {{ field.field.widget.group_class|default:'fr-input-group' }}--error{% endif %}{% if field.field.disabled %} fr-input-group--disabled{% endif %}">
<label for="{{ field.id_for_label }}" class="fr-label">
Expand All @@ -12,10 +12,10 @@
</label>
{% if field.errors %}
{% with aria_describedby="aria-describedby:"|add:field.auto_id|add:"-desc-error" %}
{{ field|attr:"aria-invalid:true"|attr:aria_describedby }}
{{ field|dsfr_input_class_attr|attr:"aria-invalid:true"|attr:aria_describedby }}
{% endwith %}
{% else %}
{{ field }}
{{ field|dsfr_input_class_attr }}
{% endif %}
{% if field.errors %}
<div id="{{ field.auto_id }}-desc-error">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{% load widget_tweaks %}
{% load widget_tweaks dsfr_tags %}
<fieldset class="fr-fieldset{% if field.errors %} fr-fieldset--error{% endif %}"
id="radio-{{ field.auto_id }}"
aria-labelledby="{{ field.auto_id }}-legend{% if field.errors %} {{ field.auto_id }}-messages{% endif %}">
Expand All @@ -15,9 +15,9 @@
<div class="fr-fieldset__content">
<div class="fr-radio-group">
{% if field.field.disabled %}
{{ field|attr:"type:radio"|add_class:"fr-radio-group"|attr:"disabled" }}
{{ field|dsfr_input_class_attr|attr:"type:radio"|attr:"disabled" }}
{% else %}
{{ field|attr:"type:radio"|add_class:"fr-radio-group" }}
{{ field|dsfr_input_class_attr|attr:"type:radio" }}
{% endif %}
</div>
</div>
Expand Down
7 changes: 6 additions & 1 deletion dsfr/templatetags/dsfr_tags.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from django import template
from django import template, forms
from django.conf import settings
from django.contrib.messages.constants import DEBUG, INFO, SUCCESS, WARNING, ERROR
from django.core.paginator import Page
from django.forms import BoundField
from django.template import Template
from django.template.context import Context
from django.utils.html import format_html, format_html_join
Expand All @@ -20,6 +21,7 @@
find_active_menu_items,
generate_random_id,
parse_tag_args,
dsfr_input_class_attr,
)

register = template.Library()
Expand Down Expand Up @@ -120,6 +122,9 @@ def dsfr_form_field(field) -> dict:
return {"field": field}


register.filter(name="dsfr_input_class_attr", filter_func=dsfr_input_class_attr)


@register.inclusion_tag("dsfr/theme_modale.html")
def dsfr_theme_modale() -> None:
"""
Expand Down
25 changes: 25 additions & 0 deletions dsfr/utils.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from django import forms
from django.core.paginator import Page
from django.utils.text import slugify
import random
Expand Down Expand Up @@ -103,3 +104,27 @@ def generate_summary_items(sections_names: list) -> list:
)

return items


def dsfr_input_class_attr(bf: forms.BoundField):
if not bf.is_hidden or "class" not in bf.field.widget.attrs:
if isinstance(
bf.field.widget, (forms.widgets.Select, forms.widgets.SelectMultiple)
):
bf.field.widget.attrs["class"] = "fr-select"
bf.field.widget.group_class = "fr-select-group"
elif isinstance(bf.field.widget, forms.widgets.RadioSelect):
bf.field.widget.attrs["dsfr"] = "dsfr"
bf.field.widget.group_class = "fr-radio-group"
elif isinstance(bf.field.widget, forms.widgets.CheckboxSelectMultiple):
bf.field.widget.attrs["dsfr"] = "dsfr"
elif not isinstance(
bf.field.widget,
(
forms.widgets.CheckboxInput,
forms.widgets.FileInput,
forms.widgets.ClearableFileInput,
),
):
bf.field.widget.attrs["class"] = "fr-input"
return bf

0 comments on commit 8b5abf0

Please sign in to comment.