mirror of
https://github.com/wagtail/wagtail.git
synced 2024-11-25 05:02:57 +01:00
Clean up unfinished aspects of DrilldownController
This commit is contained in:
parent
7ba218a094
commit
f1520bfcdd
@ -62,6 +62,7 @@
|
||||
|
||||
.w-drilldown__submenu .w-field__label {
|
||||
@apply w-label-1;
|
||||
// Align with the submenu’s back button.
|
||||
margin-top: theme('spacing.2');
|
||||
margin-bottom: theme('spacing.3');
|
||||
}
|
||||
@ -76,8 +77,10 @@
|
||||
font-weight: theme('fontWeight.bold');
|
||||
border-radius: theme('borderRadius.full');
|
||||
background-color: theme('colors.info.100');
|
||||
border: 1px solid theme('colors.info.100');
|
||||
color: theme('colors.white.DEFAULT');
|
||||
|
||||
// Reuse the same count component as a button badge.
|
||||
.w-filter-button & {
|
||||
position: absolute;
|
||||
top: calc(-0.5 * #{$badge-size});
|
||||
|
@ -3,10 +3,10 @@
|
||||
min-height: theme('spacing[6.5]');
|
||||
|
||||
&__content {
|
||||
@apply w-pl-3 w-py-1 w-rounded-l-xl w-bg-info-100 hover:w-bg-info-125 w-p-0 w-text-white hover:w-text-white w-pr-2 w-text-14 w-flex w-items-center w-border-r w-border-white-15 w-h-full;
|
||||
@apply w-pl-3 w-py-1 w-rounded-l-xl w-bg-info-100 w-p-0 w-text-white w-pr-2 w-text-14 w-flex w-items-center w-border w-border-info-100 w-border-r-white-15 w-h-full;
|
||||
}
|
||||
|
||||
&__remove {
|
||||
@apply w-pr-3 w-py-1 w-rounded-r-xl w-bg-info-100 hover:w-bg-info-125 w-text-white hover:w-text-white w-p-0 w-pl-2 w-flex w-items-center w-justify-center w-h-full;
|
||||
@apply w-pr-3 w-py-1 w-rounded-r-xl w-border w-border-info-100 w-bg-info-100 hover:w-bg-info-125 w-text-white hover:w-text-white w-p-0 w-pl-2 w-flex w-items-center w-justify-center w-h-full;
|
||||
}
|
||||
}
|
||||
|
@ -1,19 +1,27 @@
|
||||
import { Controller } from '@hotwired/stimulus';
|
||||
|
||||
/**
|
||||
* Drilldown menu interaction combined with URL-driven
|
||||
* state management for listing filters.
|
||||
*/
|
||||
export class DrilldownController extends Controller<HTMLElement> {
|
||||
static targets = ['menu', 'toggle'];
|
||||
static targets = ['count', 'menu', 'toggle'];
|
||||
|
||||
static values = {
|
||||
// Default: main menu.
|
||||
activeSubmenu: { default: '', type: String },
|
||||
};
|
||||
|
||||
declare activeSubmenuValue: string;
|
||||
|
||||
declare readonly countTarget: HTMLElement;
|
||||
declare readonly menuTarget: HTMLElement;
|
||||
declare readonly toggleTargets: HTMLButtonElement[];
|
||||
|
||||
connect() {
|
||||
this.updateToggleCounts();
|
||||
const filteredParams = new URLSearchParams(window.location.search);
|
||||
this.countTarget.hidden = filteredParams.size === 0;
|
||||
this.countTarget.textContent = filteredParams.size.toString();
|
||||
}
|
||||
|
||||
updateParamsCount(e: Event) {
|
||||
@ -29,9 +37,12 @@ export class DrilldownController extends Controller<HTMLElement> {
|
||||
filteredParams.append(key, value);
|
||||
}
|
||||
});
|
||||
const queryString = '?' + filteredParams.toString();
|
||||
this.updateToggleCounts();
|
||||
const queryString = `?${filteredParams.toString()}`;
|
||||
window.history.replaceState(null, '', queryString);
|
||||
|
||||
// Update the drilldown’s count badge based on remaining filter parameters.
|
||||
this.countTarget.hidden = filteredParams.size === 0;
|
||||
this.countTarget.textContent = filteredParams.size.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@ -44,9 +55,12 @@ export class DrilldownController extends Controller<HTMLElement> {
|
||||
|
||||
close() {
|
||||
this.activeSubmenuValue = '';
|
||||
this.updateToggleCounts();
|
||||
}
|
||||
|
||||
/**
|
||||
* Derive the component’s targets based on the state,
|
||||
* so the drilldown state can be controlled externally more easily.
|
||||
*/
|
||||
activeSubmenuValueChanged(activeSubmenu: string, prevActiveSubmenu?: string) {
|
||||
if (prevActiveSubmenu) {
|
||||
const toggle = document.querySelector(
|
||||
@ -72,7 +86,6 @@ export class DrilldownController extends Controller<HTMLElement> {
|
||||
toggle.setAttribute('aria-expanded', expanded.toString());
|
||||
content.hidden = !expanded;
|
||||
this.menuTarget.hidden = expanded;
|
||||
this.element.classList.toggle('w-drilldown--active', expanded);
|
||||
|
||||
if (expanded) {
|
||||
content.focus();
|
||||
@ -80,37 +93,4 @@ export class DrilldownController extends Controller<HTMLElement> {
|
||||
toggle.focus();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Placeholder function until this is more correctly set up with the backend.
|
||||
*/
|
||||
updateToggleCounts() {
|
||||
let sum = 0;
|
||||
|
||||
this.toggleTargets.forEach((toggle) => {
|
||||
const content = this.element.querySelector<HTMLElement>(
|
||||
`#${toggle.getAttribute('aria-controls')}`,
|
||||
);
|
||||
const counter = toggle.querySelector<HTMLElement>('.w-drilldown__count');
|
||||
if (!content || !counter) {
|
||||
return;
|
||||
}
|
||||
// Hack to detect fields with a non-default value.
|
||||
const nbActiveFields = content.querySelectorAll(
|
||||
'[type="checkbox"]:checked, [type="radio"]:checked:not([id$="_0"]), option:checked:not(:first-child), input:not([type="checkbox"], [type="radio"]):not(:placeholder-shown)',
|
||||
).length;
|
||||
counter.hidden = nbActiveFields === 0;
|
||||
counter.textContent = nbActiveFields.toString();
|
||||
sum += nbActiveFields;
|
||||
});
|
||||
|
||||
const sumCounter = this.element.querySelector<HTMLElement>(
|
||||
'.w-drilldown__count',
|
||||
);
|
||||
if (!sumCounter) {
|
||||
return;
|
||||
}
|
||||
sumCounter.hidden = sum === 0;
|
||||
sumCounter.textContent = sum.toString();
|
||||
}
|
||||
}
|
||||
|
@ -2,10 +2,10 @@
|
||||
<ul class="w-active-filters">
|
||||
{% for filter in active_filters %}
|
||||
<li class="w-pill">
|
||||
<button data-a11y-dialog-show="filters-dialog" class="w-pill__content">
|
||||
<div class="w-pill__content">
|
||||
<span class="w-text-14">{{ filter.field_label }}:</span>
|
||||
<b class="w-ml-1">{{ filter.value }}</b>
|
||||
</button>
|
||||
</div>
|
||||
<button
|
||||
data-controller="w-swap"
|
||||
data-action="click->w-swap#replaceLazy"
|
||||
|
@ -81,17 +81,16 @@
|
||||
{% if filters %}
|
||||
<div class="w-drilldown" data-controller="w-drilldown" data-action="w-swap:success@document->w-drilldown#updateParamsCount">
|
||||
{% fragment as toggle_suffix %}
|
||||
<span class="w-drilldown__count" hidden></span>
|
||||
<span class="w-drilldown__count" data-w-drilldown-target="count" hidden></span>
|
||||
{% endfragment %}
|
||||
{% dropdown theme="drilldown" toggle_icon="sliders" toggle_classname="w-filter-button" toggle_aria_label=_("Show filters") toggle_suffix=toggle_suffix %}
|
||||
<div class="w-drilldown__contents">
|
||||
<div class="w-drilldown__menu" data-w-drilldown-target="menu">
|
||||
<h2 class="w-help-text w-pl-5 w-py-2.5 w-my-0">{% trans "Filter by" %}</h2>
|
||||
{% for field in filters.form %}
|
||||
<button class="w-drilldown__toggle" data-w-drilldown-target="toggle" data-action="click->w-drilldown#open" type="button" class="w-flex w-justify-between" aria-expanded="false" aria-controls="drilldown-{{field.auto_id}}">
|
||||
<button class="w-drilldown__toggle" type="button" aria-expanded="false" aria-controls="drilldown-{{field.auto_id}}" data-w-drilldown-target="toggle" data-action="click->w-drilldown#open">
|
||||
{{ field.label }}
|
||||
<div class="w-flex w-items-center w-gap-2">
|
||||
<span class="w-drilldown__count" hidden></span>
|
||||
{% icon name="arrow-right" %}
|
||||
</div>
|
||||
</button>
|
||||
@ -99,7 +98,7 @@
|
||||
</div>
|
||||
{% for field in filters.form %}
|
||||
<div class="w-drilldown__submenu" id="drilldown-{{field.auto_id}}" hidden tabindex="-1">
|
||||
<button class="w-drilldown__back" type="button" data-action="click->w-drilldown#close" aria-label="{% trans 'Back' %}">
|
||||
<button class="w-drilldown__back" type="button" aria-label="{% trans 'Back' %}" data-action="click->w-drilldown#close">
|
||||
{% icon name="arrow-left" %}
|
||||
</button>
|
||||
{% formattedfield field %}
|
||||
|
@ -57,10 +57,6 @@ class TestPageExplorer(WagtailTestUtils, TestCase):
|
||||
clear_button = soup.select_one(".w-active-filters .w-pill__remove")
|
||||
self.assertIsNotNone(active_filter)
|
||||
self.assertEqual(active_filter.get_text(separator=" ", strip=True), text)
|
||||
self.assertEqual(
|
||||
active_filter.attrs.get("data-a11y-dialog-show"),
|
||||
"filters-dialog",
|
||||
)
|
||||
self.assertIsNotNone(clear_button)
|
||||
self.assertNotIn(param, clear_button.attrs.get("data-w-swap-src-value"))
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user