diff --git a/django/contrib/admin/helpers.py b/django/contrib/admin/helpers.py index c4613fa24ea..a4aa8e40e32 100644 --- a/django/contrib/admin/helpers.py +++ b/django/contrib/admin/helpers.py @@ -18,6 +18,7 @@ from django.db.models.fields.related import ( from django.forms.utils import flatatt from django.template.defaultfilters import capfirst, linebreaksbr from django.urls import NoReverseMatch, reverse +from django.utils.functional import cached_property from django.utils.html import conditional_escape, format_html from django.utils.safestring import mark_safe from django.utils.translation import gettext @@ -116,10 +117,14 @@ class Fieldset: @property def media(self): - if "collapse" in self.classes: - return forms.Media(js=["admin/js/collapse.js"]) return forms.Media() + @cached_property + def is_collapsible(self): + if any([field in self.fields for field in self.form.errors]): + return False + return "collapse" in self.classes + def __iter__(self): for field in self.fields: yield Fieldline( @@ -438,6 +443,12 @@ class InlineAdminFormSet: def forms(self): return self.formset.forms + @cached_property + def is_collapsible(self): + if any(self.formset.errors): + return False + return "collapse" in self.classes + def non_form_errors(self): return self.formset.non_form_errors() diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py index 47b4821fcc5..12467de74da 100644 --- a/django/contrib/admin/options.py +++ b/django/contrib/admin/options.py @@ -2398,8 +2398,6 @@ class InlineModelAdmin(BaseModelAdmin): js = ["vendor/jquery/jquery%s.js" % extra, "jquery.init.js", "inlines.js"] if self.filter_vertical or self.filter_horizontal: js.extend(["SelectBox.js", "SelectFilter2.js"]) - if self.classes and "collapse" in self.classes: - js.append("collapse.js") return forms.Media(js=["admin/js/%s" % url for url in js]) def get_extra(self, request, obj=None, **kwargs): diff --git a/django/contrib/admin/static/admin/css/forms.css b/django/contrib/admin/static/admin/css/forms.css index fe60536d62a..539a11ae612 100644 --- a/django/contrib/admin/static/admin/css/forms.css +++ b/django/contrib/admin/static/admin/css/forms.css @@ -76,6 +76,20 @@ form ul.inline li { padding-right: 7px; } +/* FIELDSETS */ + +fieldset .fieldset-heading, +fieldset .inline-heading, +:not(.inline-related) .collapse summary { + border: 1px solid var(--header-bg); + margin: 0; + padding: 8px; + font-weight: 400; + font-size: 0.8125rem; + background: var(--header-bg); + color: var(--header-link-color); +} + /* ALIGNED FIELDSETS */ .aligned label { @@ -207,35 +221,16 @@ form div.help ul { width: 450px; } -/* COLLAPSED FIELDSETS */ +/* COLLAPSIBLE FIELDSETS */ -fieldset.collapsed * { - display: none; -} - -fieldset.collapsed h2, fieldset.collapsed { - display: block; -} - -fieldset.collapsed { - border: 1px solid var(--hairline-color); - border-radius: 4px; - overflow: hidden; -} - -fieldset.collapsed h2 { - background: var(--darkened-bg); - color: var(--body-quiet-color); -} - -fieldset .collapse-toggle { - color: var(--header-link-color); -} - -fieldset.collapsed .collapse-toggle { +.collapse summary .fieldset-heading, +.collapse summary .inline-heading { background: transparent; + border: none; + color: currentColor; display: inline; - color: var(--link-fg); + margin: 0; + padding: 0; } /* MONOSPACE TEXTAREAS */ @@ -387,14 +382,16 @@ body.popup .submit-row { position: relative; } -.inline-related h3 { +.inline-related h4, +.inline-related:not(.tabular) .collapse summary { margin: 0; color: var(--body-quiet-color); padding: 5px; font-size: 0.8125rem; background: var(--darkened-bg); - border-top: 1px solid var(--hairline-color); - border-bottom: 1px solid var(--hairline-color); + border: 1px solid var(--hairline-color); + border-left-color: var(--darkened-bg); + border-right-color: var(--darkened-bg); } .inline-related h3 span.delete { diff --git a/django/contrib/admin/static/admin/css/responsive.css b/django/contrib/admin/static/admin/css/responsive.css index b58cbd964e6..932e824c1c9 100644 --- a/django/contrib/admin/static/admin/css/responsive.css +++ b/django/contrib/admin/static/admin/css/responsive.css @@ -565,10 +565,6 @@ input[type="submit"], button { padding-top: 15px; } - fieldset.collapsed .form-row { - display: none; - } - .aligned label { width: 100%; min-width: auto; diff --git a/django/contrib/admin/templates/admin/edit_inline/stacked.html b/django/contrib/admin/templates/admin/edit_inline/stacked.html index b0331c65f83..73f459ee478 100644 --- a/django/contrib/admin/templates/admin/edit_inline/stacked.html +++ b/django/contrib/admin/templates/admin/edit_inline/stacked.html @@ -4,6 +4,7 @@ data-inline-type="stacked" data-inline-formset="{{ inline_admin_formset.inline_formset_data }}">
+ {% if inline_admin_formset.is_collapsible %}
{% endif %}

{% if inline_admin_formset.formset.max_num == 1 %} {{ inline_admin_formset.opts.verbose_name|capfirst }} @@ -11,6 +12,7 @@ {{ inline_admin_formset.opts.verbose_name_plural|capfirst }} {% endif %}

+ {% if inline_admin_formset.is_collapsible %}
{% endif %} {{ inline_admin_formset.formset.management_form }} {{ inline_admin_formset.formset.non_form_errors }} @@ -31,5 +33,6 @@ {% if inline_admin_form.needs_explicit_pk_field %}{{ inline_admin_form.pk_field.field }}{% endif %} {% if inline_admin_form.fk_field %}{{ inline_admin_form.fk_field.field }}{% endif %} {% endfor %} + {% if inline_admin_formset.is_collapsible %}
{% endif %}
diff --git a/django/contrib/admin/templates/admin/edit_inline/tabular.html b/django/contrib/admin/templates/admin/edit_inline/tabular.html index 845d3917a4a..7acfda7bd14 100644 --- a/django/contrib/admin/templates/admin/edit_inline/tabular.html +++ b/django/contrib/admin/templates/admin/edit_inline/tabular.html @@ -5,6 +5,7 @@ diff --git a/django/contrib/admin/templates/admin/includes/fieldset.html b/django/contrib/admin/templates/admin/includes/fieldset.html index 66bf714e9ab..b4eef475471 100644 --- a/django/contrib/admin/templates/admin/includes/fieldset.html +++ b/django/contrib/admin/templates/admin/includes/fieldset.html @@ -1,7 +1,9 @@ {% with prefix=fieldset.formset.prefix|default:"fieldset" id_prefix=id_prefix|default:"0" id_suffix=id_suffix|default:"0" name=fieldset.name|default:""|slugify %}
{% if name %} + {% if fieldset.is_collapsible %}
{% endif %} {{ fieldset.name }} + {% if fieldset.is_collapsible %}{% endif %} {% endif %} {% if fieldset.description %}
{{ fieldset.description|safe }}
@@ -34,5 +36,6 @@ {% if not line.fields|length == 1 %}{% endif %} {% endfor %} + {% if name and fieldset.is_collapsible %}
{% endif %}
{% endwith %} diff --git a/docs/ref/contrib/admin/index.txt b/docs/ref/contrib/admin/index.txt index 2a5652c24b8..b7e94c7387d 100644 --- a/docs/ref/contrib/admin/index.txt +++ b/docs/ref/contrib/admin/index.txt @@ -424,9 +424,16 @@ subclass:: "classes": ["wide", "collapse"], } - Fieldsets with the ``collapse`` style will be initially collapsed in - the admin and replaced with a small "click to expand" link. Fieldsets - with the ``wide`` style will be given extra horizontal space. + Fieldsets with the ``wide`` style will be given extra horizontal + space in the admin interface. + Fieldsets with a name and the ``collapse`` style will be initially + collapsed, using an expandable widget with a toggle for switching + their visibility. + + .. versionchanged:: 5.1 + + ``fieldsets`` using the ``collapse`` class now use ``
`` + and ```` elements, provided they define a ``name``. * ``description`` A string of optional extra text to be displayed at the top of each @@ -2308,8 +2315,12 @@ The ``InlineModelAdmin`` class adds or customizes: A list or tuple containing extra CSS classes to apply to the fieldset that is rendered for the inlines. Defaults to ``None``. As with classes configured in :attr:`~ModelAdmin.fieldsets`, inlines with a ``collapse`` - class will be initially collapsed and their header will have a small "show" - link. + class will be initially collapsed using an expandable widget. + + .. versionchanged:: 5.1 + + ``fieldsets`` using the ``collapse`` class now use ``
`` and + ```` elements, provided they define a ``name``. .. attribute:: InlineModelAdmin.extra diff --git a/docs/releases/5.1.txt b/docs/releases/5.1.txt index 68315205dfe..e4f0b374025 100644 --- a/docs/releases/5.1.txt +++ b/docs/releases/5.1.txt @@ -419,6 +419,12 @@ Miscellaneous a ``