Amélioration de l'interface des filtre

Voir issue #185
This commit is contained in:
Jean-Marie Favreau 2024-11-13 00:17:40 +01:00
parent c1a5f92af7
commit cf268523d8
10 changed files with 79 additions and 145 deletions

View File

@ -1,90 +0,0 @@
let underToggle = false;
const toggleElement = (event) => {
console.log(event.currentTarget.getAttribute("data-target"));
container = document.getElementById(event.currentTarget.getAttribute("data-target"));
setFilterClasses(container);
};
// Toggle select all elements
const toggleSelectAllFilterElements = (event) => {
event.preventDefault();
selectAllFilterElementsFromCheckbox(event.currentTarget);
};
const selectAllFilterElementsFromCheckbox = (checkbox) => {
const container = document.getElementById(checkbox.getAttribute("data-target"));
active = checkbox.checked;
Array.prototype.forEach.call(container.children, function(child) {
Array.prototype.forEach.call(child.getElementsByTagName("input"), function(elem) {
elem.checked = active;
});
});
setFilterClasses(container);
};
const setFilterClasses = (container) => {
if (!underToggle) {
underToggle = true;
selectionButtom = document.getElementById(container.getAttribute("data-button"));
checkboxes = container.getElementsByTagName("input");
// count the number of selected elements
nbElemsChecked = 0;
for (i = 0; i < checkboxes.length; i++) {
if (checkboxes[i].checked) {
nbElemsChecked++;
}
}
// count the number of elements
nbElems = checkboxes.length;
// if all elements are deselected, the class "no-selected" is removed and the all selection button is deselected
if (nbElemsChecked == 0) {
Array.prototype.forEach.call(checkboxes, function(checkbox) {
checkbox.parentNode.parentNode.classList.remove("no-selected");
});
selectionButtom.checked = false;
selectionButtom.indeterminate = false;
}
else {
// otherwise, for each filter element, set "no-selected" class if required
Array.prototype.forEach.call(checkboxes, function(checkbox) {
if (checkbox.checked)
checkbox.parentNode.parentNode.classList.remove("no-selected");
else
checkbox.parentNode.parentNode.classList.add("no-selected");
});
// if all elements are selected, the all selection button is selected, otherwise its set to "indeterminate"
if (nbElems == nbElemsChecked) {
selectionButtom.checked = true;
selectionButtom.indeterminate = false;
} else {
selectionButtom.indeterminate = true;
selectionButtom.checked = false;
}
}
underToggle = false;
}
}
document.addEventListener("DOMContentLoaded", function(e) {
Array.prototype.forEach.call(document.getElementsByClassName("buttons-filter"), function(buttongroup) {
buttongroup.style.display = "inline-block";
});
const buttonsAll = document.getElementsByClassName("all-elements");
Array.prototype.forEach.call(buttonsAll, function(button) {
const container = document.getElementById(button.getAttribute("data-target"));
setFilterClasses(container);
});
});

View File

@ -1152,7 +1152,7 @@ img.preview {
overflow-y: scroll;
}
.choices {
.choices[data-type=select-one] {
.choices__inner {
@extend [role="button"], .large;
.choices__item {
@ -1211,13 +1211,63 @@ img.preview {
}
.choices.is-open {
.choices[data-type=select-one].is-open {
.choices__inner {
.choices__item::after {
transform: rotate(0);
}
}
}
.choices[data-type=select-multiple] {
.choices__input {
width: 100% !important;
}
.choices__item {
@extend [role="button"];
background: transparent;
color: var(--primary);
font-size: 90%;
padding: 0.15em 0.4em 0.3em 0.4em;
display: inline-block;
margin: 0.2em !important;
height: 2.6em;
line-height: 2.2em;
button {
@extend .outline;
display: inline-block;
border: 0;
background: transparent;
text-indent: -9999px;
padding: 0;
appearance: none;
width: 1.3em;
height: 1.3em;
margin-top: 0.25em;
vertical-align: middle;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='18' viewBox='0 0 24 24' fill='none' stroke='#{to-rgb($primary-700)}' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cline x1='15' y1='9' x2='9' y2='15'%3E%3C/line%3E%3Cline x1='9' y1='9' x2='15' y2='15'%3E%3C/line%3E%3C/svg%3E");
background-position: right;
background-repeat: no-repeat;
}
}
.choices__list--dropdown {
display: none;
will-change: display;
position: relative;
max-height: 300px;
overflow: auto;
-webkit-overflow-scrolling: touch;
will-change: scroll-position;
}
.choices__list--dropdown.is-active {
display: block;
}
}
article {
.stick-bottom {
background: var(--card-sectionning-background-color);

View File

@ -74,12 +74,32 @@
</div>
<script src="{% static 'choicejs/choices.min.js' %}"></script>
<script>
const element = document.querySelector('#id_position');
const choices = new Choices(element);
const position = document.querySelector('#id_position');
const choices_position = new Choices(position);
const tags = document.querySelector('#id_tags');
const choices_tags = new Choices(tags,
{
placeholderValue: 'Chercher les étiquettes à inclure',
allowHTML: true,
delimiter: ',',
editItems: true,
removeItemButton: true,
}
);
const exclude_tags = document.querySelector('#id_exclude_tags');
const choices_exclude_tags = new Choices(exclude_tags,
{
placeholderValue: 'Chercher les étiquettes à exclure',
allowHTML: true,
delimiter: ',',
editItems: true,
removeItemButton: true,
}
);
document.querySelector(".choices__inner").classList.add("contrast");
document.querySelector(".choices__inner").classList.add("outline");
document.querySelector(".choices__inner").setAttribute("role", "button");
document.querySelector("#id_position .choices__inner").classList.add("contrast");
document.querySelector("#id_position .choices__inner").classList.add("outline");
document.querySelector("#id_position .choices__inner").setAttribute("role", "button");
</script>

View File

@ -1,14 +0,0 @@
{% load cat_extra %}
<div class="buttons-filter">
<label for="all-categories">
toutes
<input class="all-elements" type="checkbox" id="{{ widget.attrs.id }}-button" name="all-categories" onChange="toggleSelectAllFilterElements(event)" data-target="{{ widget.attrs.id }}">
</label>
</div>
{% with container_id=widget.attrs.id %}
<div class="options-filter" id="{{ widget.attrs.id }}" data-button="{{ widget.attrs.id }}-button">{% for group, options, index in widget.optgroups %}{% if group %}
<div><label>{{ group }}</label>{% endif %}{% for widget in options %}<div role="button" class="small-cat contrast">
{{ widget.value.instance | circle_cat }}{% include widget.template_name %}</div>{% endfor %}{% if group %}
</div>{% endif %}{% endfor %}
</div>
{% endwith %}

View File

@ -1,4 +0,0 @@
<label for="{{ widget.attrs.id }}">
{{ widget.label }}
<input type="{{ widget.type }}" name="{{ widget.name }}"{% if widget.value != None %} value="{{ widget.value }}"{% endif %}{% include "django/forms/widgets/attrs.html" %} onChange="toggleElement(event)" data-target="{{ container_id }}">
</label>

View File

@ -1,14 +0,0 @@
{% load cat_extra %}
<div class="buttons-filter">
<label for="all-tags">
toutes
<input class="all-elements" type="checkbox" id="{{ widget.attrs.id }}-button" name="all-tags" onChange="toggleSelectAllFilterElements(event)" data-target="{{ widget.attrs.id }}">
</label>
</div>
{% with container_id=widget.attrs.id %}
<div class="options-filter" id="{{ widget.attrs.id }}" data-button="{{ widget.attrs.id }}-button">{% for group, options, index in widget.optgroups %}{% if group %}
<div><label>{{ group }}</label>{% endif %}{% for widget in options %}<div role="button" class="small-cat">
{% include widget.template_name %}</div>{% endfor %}{% if group %}
</div>{% endif %}{% endfor %}
</div>
{% endwith %}

View File

@ -13,7 +13,6 @@
{% block entete_header %}
{% css_categories %}
<script src="{% static 'js/modal.js' %}"></script>
<script src="{% static 'js/filters.js' %}"></script>
<script src="{% static 'js/calendar-buttons.js' %}"></script>
{% endblock %}

View File

@ -12,7 +12,6 @@
{% block entete_header %}
{% css_categories %}
<script src="{% static 'js/modal.js' %}"></script>
<script src="{% static 'js/filters.js' %}"></script>
{% endblock %}
{% block ce_mois_ci_parameters %}{% block cette_semaine_parameters %}{% block a_venir_parameters %}?{{ filter.get_url }}{% endblock %}{% endblock %}{% endblock %}

View File

@ -12,7 +12,6 @@
{% block entete_header %}
{% css_categories %}
<script src="{% static 'js/modal.js' %}"></script>
<script src="{% static 'js/filters.js' %}"></script>
<script src="{% static 'js/calendar-buttons.js' %}"></script>
{% endblock %}

View File

@ -158,17 +158,6 @@ def internal_server_error(request):
def thank_you(request):
return render(request, "agenda_culturel/thank_you.html")
class CategoryCheckboxSelectMultiple(forms.CheckboxSelectMultiple):
template_name = "agenda_culturel/forms/category-checkbox.html"
option_template_name = "agenda_culturel/forms/checkbox-option.html"
class TagCheckboxSelectMultiple(forms.CheckboxSelectMultiple):
template_name = "agenda_culturel/forms/tag-checkbox.html"
option_template_name = "agenda_culturel/forms/checkbox-option.html"
class EventFilter(django_filters.FilterSet):
RECURRENT_CHOICES = [
("remove_recurrent", "Masquer les événements récurrents"),
@ -198,7 +187,7 @@ class EventFilter(django_filters.FilterSet):
lookup_expr="icontains",
field_name="tags",
exclude=True,
widget=TagCheckboxSelectMultiple,
widget=forms.SelectMultiple,
)
tags = django_filters.MultipleChoiceFilter(
@ -207,7 +196,7 @@ class EventFilter(django_filters.FilterSet):
lookup_expr="icontains",
conjoined=True,
field_name="tags",
widget=TagCheckboxSelectMultiple,
widget=forms.SelectMultiple,
)
recurrences = django_filters.ChoiceFilter(