From 5399ccc0f4257676981ef7937ea84be36f7058a6 Mon Sep 17 00:00:00 2001 From: Karen Tracey <kmtracey@gmail.com> Date: Sat, 7 Nov 2015 10:46:50 -0500 Subject: [PATCH] Fixed #494 -- Added ability to specify classes on admin inline fieldsets. This includes the ability to collapse inlines by specifying a class named 'collapse'. --- django/contrib/admin/helpers.py | 1 + django/contrib/admin/options.py | 3 +++ .../templates/admin/edit_inline/stacked.html | 2 ++ .../templates/admin/edit_inline/tabular.html | 2 +- docs/ref/contrib/admin/index.txt | 10 ++++++++++ docs/releases/1.10.txt | 5 +++++ tests/admin_inlines/admin.py | 2 ++ tests/admin_inlines/tests.py | 19 +++++++++++++++++++ 8 files changed, 43 insertions(+), 1 deletion(-) diff --git a/django/contrib/admin/helpers.py b/django/contrib/admin/helpers.py index 1217bd78df..9cb49473fd 100644 --- a/django/contrib/admin/helpers.py +++ b/django/contrib/admin/helpers.py @@ -235,6 +235,7 @@ class InlineAdminFormSet(object): if prepopulated_fields is None: prepopulated_fields = {} self.prepopulated_fields = prepopulated_fields + self.classes = ' '.join(inline.classes) if inline.classes else '' def __iter__(self): for form, original in zip(self.formset.initial_forms, self.formset.get_queryset()): diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py index 4fb5f3ddc8..42880aba81 100644 --- a/django/contrib/admin/options.py +++ b/django/contrib/admin/options.py @@ -1800,6 +1800,7 @@ class InlineModelAdmin(BaseModelAdmin): can_delete = True show_change_link = False checks_class = InlineModelAdminChecks + classes = None def __init__(self, parent_model, admin_site): self.admin_site = admin_site @@ -1819,6 +1820,8 @@ class InlineModelAdmin(BaseModelAdmin): 'inlines%s.js' % extra] 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%s.js' % extra) 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/templates/admin/edit_inline/stacked.html b/django/contrib/admin/templates/admin/edit_inline/stacked.html index 9025a17afb..65af259a21 100644 --- a/django/contrib/admin/templates/admin/edit_inline/stacked.html +++ b/django/contrib/admin/templates/admin/edit_inline/stacked.html @@ -3,6 +3,7 @@ id="{{ inline_admin_formset.formset.prefix }}-group" data-inline-type="stacked" data-inline-formset="{{ inline_admin_formset.inline_formset_data }}"> +<fieldset class="module {{ inline_admin_formset.classes }}"> <h2>{{ inline_admin_formset.opts.verbose_name_plural|capfirst }}</h2> {{ inline_admin_formset.formset.management_form }} {{ inline_admin_formset.formset.non_form_errors }} @@ -20,4 +21,5 @@ {% if inline_admin_form.needs_explicit_pk_field %}{{ inline_admin_form.pk_field.field }}{% endif %} {{ inline_admin_form.fk_field.field }} </div>{% endfor %} +</fieldset> </div> diff --git a/django/contrib/admin/templates/admin/edit_inline/tabular.html b/django/contrib/admin/templates/admin/edit_inline/tabular.html index bcf3e6bd1c..f04faadf2f 100644 --- a/django/contrib/admin/templates/admin/edit_inline/tabular.html +++ b/django/contrib/admin/templates/admin/edit_inline/tabular.html @@ -4,7 +4,7 @@ data-inline-formset="{{ inline_admin_formset.inline_formset_data }}"> <div class="tabular inline-related {% if forloop.last %}last-related{% endif %}"> {{ inline_admin_formset.formset.management_form }} -<fieldset class="module"> +<fieldset class="module {{ inline_admin_formset.classes }}"> <h2>{{ inline_admin_formset.opts.verbose_name_plural|capfirst }}</h2> {{ inline_admin_formset.formset.non_form_errors }} <table> diff --git a/docs/ref/contrib/admin/index.txt b/docs/ref/contrib/admin/index.txt index 4173c063dc..a36859c012 100644 --- a/docs/ref/contrib/admin/index.txt +++ b/docs/ref/contrib/admin/index.txt @@ -2058,6 +2058,16 @@ The ``InlineModelAdmin`` class adds: parent model fails to validate, it may be left in an inconsistent state as described in the warning in :ref:`validation-on-modelform`. +.. attribute:: InlineModelAdmin.classes + + .. versionadded:: 1.10 + + 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. + .. attribute:: InlineModelAdmin.extra This controls the number of extra forms the formset will display in diff --git a/docs/releases/1.10.txt b/docs/releases/1.10.txt index 7be22b12f4..09c437f941 100644 --- a/docs/releases/1.10.txt +++ b/docs/releases/1.10.txt @@ -42,6 +42,11 @@ Minor features * All inline JavaScript is removed so you can enable the ``Content-Security-Policy`` HTTP header if you wish. +* The new :attr:`InlineModelAdmin.classes + <django.contrib.admin.InlineModelAdmin.classes>` attribute allows specifying + classes on inline fieldsets. Inlines with a ``collapse`` class will be + initially collapsed and their header will have a small "show" link. + :mod:`django.contrib.admindocs` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/admin_inlines/admin.py b/tests/admin_inlines/admin.py index 65d74a4c81..b7fd6424d6 100644 --- a/tests/admin_inlines/admin.py +++ b/tests/admin_inlines/admin.py @@ -20,10 +20,12 @@ class BookInline(admin.TabularInline): class NonAutoPKBookTabularInline(admin.TabularInline): model = NonAutoPKBook + classes = ('collapse',) class NonAutoPKBookStackedInline(admin.StackedInline): model = NonAutoPKBook + classes = ('collapse',) class EditablePKBookTabularInline(admin.TabularInline): diff --git a/tests/admin_inlines/tests.py b/tests/admin_inlines/tests.py index b2102480bc..0a50202340 100644 --- a/tests/admin_inlines/tests.py +++ b/tests/admin_inlines/tests.py @@ -874,6 +874,25 @@ class SeleniumFirefoxTests(AdminSeleniumWebDriverTestCase): self.assertEqual(len(self.selenium.find_elements_by_css_selector( "%s.row2" % row_selector)), 1, msg="Expect one row2 styled row") + def test_collapsed_inlines(self): + # Collapsed inlines have SHOW/HIDE links. + self.admin_login(username='super', password='secret') + self.selenium.get(self.live_server_url + reverse('admin:admin_inlines_author_add')) + # One field is in a stacked inline, other in a tabular one. + test_fields = ['id_nonautopkbook_set-0-title', 'id_nonautopkbook_set-2-0-title'] + show_links = self.selenium.find_elements_by_link_text('SHOW') + self.assertEqual(len(show_links), 2) + for show_index, field_name in enumerate(test_fields, 0): + self.assertFalse(self.selenium.find_element_by_id(field_name).is_displayed()) + show_links[show_index].click() + self.assertTrue(self.selenium.find_element_by_id(field_name).is_displayed()) + hide_links = self.selenium.find_elements_by_link_text('HIDE') + self.assertEqual(len(hide_links), 2) + for hide_index, field_name in enumerate(test_fields, 0): + self.assertTrue(self.selenium.find_element_by_id(field_name).is_displayed()) + hide_links[hide_index].click() + self.assertFalse(self.selenium.find_element_by_id(field_name).is_displayed()) + class SeleniumChromeTests(SeleniumFirefoxTests): webdriver_class = 'selenium.webdriver.chrome.webdriver.WebDriver'