Fixed #27471 -- Made admin's filter choices collapsable.
This commit is contained in:
parent
37602e4948
commit
27aa7035f5
|
@ -148,12 +148,35 @@
|
|||
border-bottom: none;
|
||||
}
|
||||
|
||||
#changelist-filter h3 {
|
||||
#changelist-filter h3,
|
||||
#changelist-filter details summary {
|
||||
font-weight: 400;
|
||||
padding: 0 15px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
#changelist-filter details summary > * {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
#changelist-filter details > summary {
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
#changelist-filter details > summary::-webkit-details-marker {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#changelist-filter details > summary::before {
|
||||
content: '→';
|
||||
font-weight: bold;
|
||||
color: var(--link-hover-color);
|
||||
}
|
||||
|
||||
#changelist-filter details[open] > summary::before {
|
||||
content: '↓';
|
||||
}
|
||||
|
||||
#changelist-filter ul {
|
||||
margin: 5px 0;
|
||||
padding: 0 15px 15px;
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
/**
|
||||
* Persist changelist filters state (collapsed/expanded).
|
||||
*/
|
||||
'use strict';
|
||||
{
|
||||
// Init filters.
|
||||
let filters = JSON.parse(sessionStorage.getItem('django.admin.filtersState'));
|
||||
|
||||
if (!filters) {
|
||||
filters = {};
|
||||
}
|
||||
|
||||
Object.entries(filters).forEach(([key, value]) => {
|
||||
const detailElement = document.querySelector(`[data-filter-title='${key}']`);
|
||||
|
||||
// Check if the filter is present, it could be from other view.
|
||||
if (detailElement) {
|
||||
value ? detailElement.setAttribute('open', '') : detailElement.removeAttribute('open');
|
||||
}
|
||||
});
|
||||
|
||||
// Save filter state when clicks.
|
||||
const details = document.querySelectorAll('details');
|
||||
details.forEach(detail => {
|
||||
detail.addEventListener('toggle', event => {
|
||||
filters[`${event.target.dataset.filterTitle}`] = detail.open;
|
||||
sessionStorage.setItem('django.admin.filtersState', JSON.stringify(filters));
|
||||
});
|
||||
});
|
||||
}
|
|
@ -21,6 +21,7 @@
|
|||
{% block extrahead %}
|
||||
{{ block.super }}
|
||||
{{ media.js }}
|
||||
<script src="{% static 'admin/js/filters.js' %}" defer></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block bodyclass %}{{ block.super }} app-{{ opts.app_label }} model-{{ opts.model_name }} change-list{% endblock %}
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
{% load i18n %}
|
||||
<h3>{% blocktranslate with filter_title=title %} By {{ filter_title }} {% endblocktranslate %}</h3>
|
||||
<ul>
|
||||
{% for choice in choices %}
|
||||
<details data-filter-title="{{ title }}" open>
|
||||
<summary>
|
||||
{% blocktranslate with filter_title=title %} By {{ filter_title }} {% endblocktranslate %}
|
||||
</summary>
|
||||
<ul>
|
||||
{% for choice in choices %}
|
||||
<li{% if choice.selected %} class="selected"{% endif %}>
|
||||
<a href="{{ choice.query_string|iriencode }}">{{ choice.display }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</details>
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 26 KiB |
Binary file not shown.
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 40 KiB |
|
@ -1810,3 +1810,55 @@ class SeleniumTests(AdminSeleniumTestCase):
|
|||
)
|
||||
finally:
|
||||
alert.dismiss()
|
||||
|
||||
def test_collapse_filters(self):
|
||||
from selenium.webdriver.common.by import By
|
||||
|
||||
self.admin_login(username="super", password="secret")
|
||||
self.selenium.get(self.live_server_url + reverse("admin:auth_user_changelist"))
|
||||
|
||||
# The UserAdmin has 3 field filters by default: "staff status",
|
||||
# "superuser status", and "active".
|
||||
details = self.selenium.find_elements(By.CSS_SELECTOR, "details")
|
||||
# All filters are opened at first.
|
||||
for detail in details:
|
||||
self.assertTrue(detail.get_attribute("open"))
|
||||
# Collapse "staff' and "superuser" filters.
|
||||
for detail in details[:2]:
|
||||
summary = detail.find_element(By.CSS_SELECTOR, "summary")
|
||||
summary.click()
|
||||
self.assertFalse(detail.get_attribute("open"))
|
||||
# Filters are in the same state after refresh.
|
||||
self.selenium.refresh()
|
||||
self.assertFalse(
|
||||
self.selenium.find_element(
|
||||
By.CSS_SELECTOR, "[data-filter-title='staff status']"
|
||||
).get_attribute("open")
|
||||
)
|
||||
self.assertFalse(
|
||||
self.selenium.find_element(
|
||||
By.CSS_SELECTOR, "[data-filter-title='superuser status']"
|
||||
).get_attribute("open")
|
||||
)
|
||||
self.assertTrue(
|
||||
self.selenium.find_element(
|
||||
By.CSS_SELECTOR, "[data-filter-title='active']"
|
||||
).get_attribute("open")
|
||||
)
|
||||
# Collapse a filter on another view (Bands).
|
||||
self.selenium.get(
|
||||
self.live_server_url + reverse("admin:admin_changelist_band_changelist")
|
||||
)
|
||||
self.selenium.find_element(By.CSS_SELECTOR, "summary").click()
|
||||
# Go to Users view and then, back again to Bands view.
|
||||
self.selenium.get(self.live_server_url + reverse("admin:auth_user_changelist"))
|
||||
self.selenium.get(
|
||||
self.live_server_url + reverse("admin:admin_changelist_band_changelist")
|
||||
)
|
||||
# The filter remains in the same state.
|
||||
self.assertFalse(
|
||||
self.selenium.find_element(
|
||||
By.CSS_SELECTOR,
|
||||
"[data-filter-title='number of members']",
|
||||
).get_attribute("open")
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue