PageSourceSearch

https://www.ot-lesherbiers.fr/wp-content/themes/noyau/assets/js/PostsQuery/posts_filters.js?ver=6.8.7

js ot-lesherbiers.fr collected 2026-10-02 20:34:11 UTC 83,227 bytes, 1,892 lines download raw bytes

1ready(() => {
2
3    // Get params from WordPress wp_localize_script (Noyau\Script)
4    let currentPage = Number(PostsQueryParams.current_page)
5
6    // Get the containers' ID
7    const loadMoreBTN = document.getElementById('load-older-posts')
8    const $listingContainer = document.getElementById('post_publications')
9    const $categoryFilter = document.querySelector('#categoryFilter')
10    const $categoryButton = document.getElementsByClassName('button--filter')
11    const $countPostPerPage = document.getElementById('posts_per_page')
12    const $countTotal = document.getElementById('foundPosts')
13    const $subCategorieFilter = document.getElementById('sub-categories')
14    const $subCategoriesInput = document.getElementById('subCategoriesInput')
15    const $subCategoriesCount = document.getElementById('selectedSubCategoriesCount')
16    const $toggleSubCategoriesChoices = document.getElementById('toggleSubCategories')
17    const $toggleFilter = document.querySelector('.button--toggler')
18    const $validateFilter = document.getElementById('val
18idateSystemeFilter')
19    const $resetFilter = document.getElementById('resetSystemeFilter')
20    const $dateInput = document.getElementById('dateInput')
21    const $subCategoriesFilterContainer = document.querySelector('#subCategorieList')
22    const $dateFilterContainer = document.querySelector('#publicationDate')
23    const $keywordsFilter = document.querySelector('#keywordsFilter')
24    const $statusFilterContainer = document.querySelector('#reportStatus')
25    const $statusInput = document.getElementById('statusInput')
26    const $filters = document.querySelector('.filter__options')
27    const $resetKeywordInput = document.getElementById('keywordsReset')
28
29    // Documents
30    const $monthsFilterInput = document.querySelector('#monthsReleaseInput')
31    const $monthsFilter = document.querySelector('#monthsReleaseDate')
32    const $yearsFilterInput = document.querySelector('#yearsReleaseInput')
33    const $yearsFilter = document.querySelector('#yearsReleaseDate')
34
35
36    // Custom filters
37    const $customFiltersInput = document.querySelectorAll('.filter_custom .filter__input-container input')
38    const $customFilters = document.querySelectorAll('.filter_custom .filter__custom-container ul')
39
40    // Events
41    const $inputStartDate = jQuery('input#startDateFilterHidden');
42    const $inputTextStartDate = jQuery('input#startDateFilter');
43    const $inputEndDate = jQuery('input#endDateFilterHidden');
44    const $inputTextEndDate = jQuery('input#endDateFilter');
45
46    // Search
47    const $postTypeInput = document.querySelector('#postTypeInput')
48    const $postTypeFilter = document.querySelector('#postType')
49
50    let $archivePage = document.getElementById('archivePage')
51    let postsPerPage = 10
52
53    if (!!$archivePage) {
54        postsPerPage = $archivePage.dataset.postsperpage
55    }
56
57    // Init the PostsQuery Class
58    let Query = new PostsQuery()
59    Query._APIRoute = 'postsQuery'
60
61
62    /*
63        *  INIT parts
64     */
65    if (!!$listingContainer) {
66
67        const selectBoxes = document.querySelectorAll('.filter__input-container')
68
69        !!selectBoxes &&
70        selectBoxes.forEach((selectBox) => {
71            selectBox.addEventListener('click', function () {
72                if (this.closest('.select-box').classList.contains('is-closed')) {
73                    this.closest('.select-box').classList.replace('is-closed', 'is-open')
74                } else {
75                    this.closest('.select-box').classList.replace('is-open', 'is-closed')
76                }
77            })
78        })
79
80        document.addEventListener('click', function (event) {
81            let selectBoxes = document.querySelectorAll('.select-box.is-open')
82            selectBoxes.forEach((selectBox) => {
83                if (selectBox !== null && selectBox !== event.target.closest('.select-box')) {
84                    selectBox.classList.replace('is-open', 'is-closed')
85                }
86
87                if (selectBox === event.target.closest('.select-box')) {
88                    let radios = selectBox ? selectBox.querySelectorAll('input[type=radio]') : []
89                    !!radios && radios.forEach((radio) => {
90                        if (event.target === radio) {
91                            selectBox.classList.replace('is-open', 'is-closed')
92                        }
93                    })
94                }
95            })
96        })
97
98        let elementSelected = $filters.querySelectorAll('.selected')
99        // If no element fit the selector, we restore the "reset button" to its original state
100        if (elementSelected.length !== 0) {
101            $resetFilter.classList.remove('empty-selection')
102        }
103
104        const searchQuery = window.location.search
105        // Get the page CPT
106        window.cpt = $listingContainer.dataset.cpt
107        // Get the first count of posts (before fetching on API)
108        let countPostPerPage_HTML = $countPostPerPage.innerHTML
109        let countPostPerPage_INT = parseInt(countPostPerPage_HTML)
110
111        // Init every params
112        let initParams = new URLSearchParams(searchQuery)
113
114        if (window.cpt) {
115            Query.URLQuery = `?systemeParams=${cpt}`
116        } else {
117            let params = new URLSearchParams(searchQuery);
118            let searchedWords = String(params.get("s"));
119            Query.URLQuery = `?s=${searchedWords}`
120        }
121
122        // Init every params
123        let params = new URLSearchParams(searchQuery)
124
125        // Add view in URLQuery base
126        let view = initParams.get('view')
127        if (view) {
128            Query.URLArgs.view = {}
129            Query.URLArgs.view.parameterValue = view
130        }
131
132        // Mapping CPT → taxonomie pour les pages avec catégorie parente forcée
133        const cptTaxonomyMap = {
134            contacts: 'contacts_category',
135            events: 'events_category',
136            post: 'category',
137            documents: 'documents_category',
138            adverts: 'adverts_category',
139            consultations: 'consultations_category',
140        }
141
142        // Si catégorie parente forcée : init categoryID + taxonomy avant de charger les sous-catégories
143        if ($subCategorieFilter && $subCategorieFilter.dataset.forcedParent === '1') {
144            if ($archivePage && $archivePage.dataset.forcedCategory) {
145                window.categoryID = Number($archivePage.dataset.forcedCategory)
146                Query.URLArgs.category = {}
147                Query.URLArgs.category.parameterValue = [window.categoryID]
148            }
149            window.taxonomy = cptTaxonomyMap[window.cpt] || window.cpt + '_category'
150
151            // Si subCategories est dans l'URL, les pré-sélectionner dans le filtre
152            // pour qu'ils soient inclus dans la query initiale
153            const subCatsFromURL = params.get('subCategories')
154            if (subCatsFromURL && $subCategoriesFilterContainer) {
155                $subCategoriesFilterContainer.dataset.ids = subCatsFromURL
156                Query.URLArgs.subCategories = {}
157                Query.URLArgs.subCategories.parameterValue = subCatsFromURL.split(',')
158            }
159
160            displaySubCategories()
161        }
162
163        for (const [key, value] of params.entries()) {
164            if (key.includes('category') && value && window.cpt !== 'jobs') {
165                window.categoryID = Number(value)
166
167                if ($categoryFilter) {
168                    let $categoryCheckbox = $categoryFilter.querySelector('input[data-id="' + value + '"]')
169                    if ($categoryCheckbox) {
170                        window.categorySlug = $categoryCheckbox.dataset.slug
171                        window.taxonomy = $categoryCheckbox.dataset.taxonomy
172                        $validateFilter.classList.remove('empty-selection')
173                    } else {
174                        // Pas de checkbox correspondante : fallback comme avant
175                        if ($subCategoriesFilterContainer) {
176                            $subCategoriesFilterContainer.dataset.ids = value
177                        }
178                        window.taxonomy = key
179                    }
180                    displaySubCategories()
181                } else if ($subCategorieFilter && $subCategorieFilter.dataset.forcedParent === '1') {
182                    // Catégorie parente forcée : taxonomy et categoryID déjà initialisés plus haut
183                } else {
184                    if ($subCategoriesFilterContainer) {
185                        $subCategoriesFilterContainer.dataset.ids = value
186                    }
187                    window.taxonomy = key
188                    displaySubCategories()
189                }
190            }
191        }
192
193        /**
194         * CATEGORY Parts
195         *
196         * */
197
198        // Handle category select
199        if (!!$categoryFilter) {
200            let $categorieInputs = $categoryFilter.querySelectorAll('input[name="category"]')
201            $categorieInputs.forEach(($categorieInput) => {
202                $categorieInput.addEventListener('change', () => {
203
204                    if ($subCategorieFilter) {
205                        delete Query.URLArgs.subCategories
206
207                        $subCategorieFilter.dataset.disabled = 'disabled'
208                        $subCategoriesFilterContainer.dataset.ids = ''
209                        // Prepare the toggler for it's next action (select all)
210                        $toggleSubCategoriesChoices.dataset.selected = 'true'
211
212                        // Restore the text of the input
213                        $subCategoriesInput.value = 'Sous-catégories'
214                        // Restore the text in the toggler
215                        $toggleSubCategoriesChoices.innerHTML = 'Tout sélectionner'
216                        // Restore the default style for an inactive filter
217                        $subCategoriesInput.classList.remove('selected')
218
219                        let $subCategoriesCheckboxes = $subCategoriesFilterContainer.querySelectorAll('input[type="checkbox"]:checked')
220                        // Unchecked all the sub categories checkboxes
221                        for (let checkbox of $subCategoriesCheckboxes) {
222                            checkbox.checked = false
223                        }
224                    }
225
226                    // Get the selected range date
227                    let $categoryCheckbox = $categoryFilter.querySelector('input[type="radio"]:checked')
228                    document.querySelector('#filter_category').classList.add('selected')
229                    window.categoryID = Number($categoryCheckbox.dataset.id)
230
231                    // Store the category slug
232                    window.categorySlug = $categoryCheckbox.dataset.slug
233
234                    // Store the category taxonomy
235                    window.taxonomy = $categoryCheckbox.dataset.taxonomy
236
237                    // Execute the function that will get the subcategories and add them
238
239                    document.querySelector('#filter_category').value = $categoryCheckbox.dataset.label ?? $categoryCheckbox.getAttribute('data-placeholder')
240                    $validateFilter.classList.remove('empty-selection')
241
242                    displaySubCategories()
243                    updateCustomFiltersVisibility(getActiveCategoryIDs())
244
245                })
246            })
247
248
249        }
250
251        /***
252         * This listener is used to
253         * 1. Display the number of selected sub categories in the $subCategoriesCount
254         * 2. Display the subcategories' names in the $subCategoriesFilterContainer
255         * ***/
256        if (!!$subCategoriesFilterContainer) {
257            $subCategoriesFilterContainer.addEventListener('click', (e) => {
258
259
260                // Get the list of the checked input in the UL
261                let $subCategoriesCheckboxes = $subCategoriesFilterContainer.querySelectorAll('input[type="checkbox"]:checked')
262
263                // Init values
264                let value = ''
265
266                // We control that the number of checked element is === 0
267                // If it's true we remove all the data register during the subCatogories choice
268                // And restore to original condition
269                if ($subCategoriesCheckboxes.length === 0) {
270
271                    // Remove the argument from the URL builder
272                    delete Query.URLArgs.subCategories
273
274                    // Restore the state and the text of the sub categories choices toggler
275                    $toggleSubCategoriesChoices.dataset.selected = 'true'
276                    $toggleSubCategoriesChoices.innerHTML = 'Tout sélectionner'
277                    $subCategoriesCount.innerHTML = "0 sélectionnée"
278
279                    // Restore the original $subCategoriesInput condition
280                    $subCategoriesInput.value = 'Sous-catégories'
281                    $subCategoriesInput.classList.remove('selected')
282
283                    // Get all elements which have .selected as class
284                    let elementSelected = $filters.querySelectorAll('.selected')
285                    // If no element fit the selector, we restore the "reset button" to its original state
286                    if (elementSelected.length === 0) {
287                        $resetFilter.classList.add('empty-selection')
288                        $validateFilter.classList.add('empty-selection')
289                    }
290
291                    updateCustomFiltersVisibility(getActiveCategoryIDs())
292                } else {
293                    // If we have a selection of checkboxes :
294
295                    // The reset button is enabled
296
297                    $validateFilter.classList.remove('empty-selection')
298
299                    // The $subCategoriesInput has class selected
300                    $subCategoriesInput.classList.add('selected')
301
302                    // Change the state and the text of the sub categories choices toggler
303                    $toggleSubCategoriesChoices.innerHTML = 'Tout désélectionner'
304                    $toggleSubCategoriesChoices.dataset.selected = 'false'
305
306                    // Prepare the data which are sent to the Query object
307                    // Used to build the url arguments
308                    Query.URLArgs.subCategories = {}
309                    Query.URLArgs.subCategories.parameterValue = []
310
311                    // We loop through all the selected sub categories
312                    for (let i = 0; i < $subCategoriesCheckboxes.length; i++) {
313                        // We store the checkbox value
314                        let checkbox = $subCategoriesCheckboxes[i]
315                        Query.URLArgs.subCategories.parameterValue.push(checkbox.value)
316
317                        $subCategoriesCount.innerHTML = $subCategoriesCheckboxes.length + " sélectionnée(s)"
318
319                        // todo... Si non est là c'est qu'elle est checkée la checkbox non ?
320                        checkbox.checked = true
321
322                        // If we are on the last checkbox element of the NodeList
323                        // We don't add a comma
324                        if (i === Number($subCategoriesCheckboxes.length - 1)) {
325                            value += `${checkbox.dataset.name}`
326                        } else {
327                            value += `${checkbox.dataset.name}, `
328                        }
329                        // We limit the value to 80 characters based of a Query class method
330                        $subCategoriesInput.value = Query.truncate(value, 80, '...', ',')
331                    }
332
333                    updateCustomFiltersVisibility(getActiveCategoryIDs())
334                }
335            })
336        }
337
338
339        /***
340         * The sub categorie filter has a button that allows to toggle the selection (all/none)
341         * ***/
342        if (!!$toggleSubCategoriesChoices) {
343            $toggleSubCategoriesChoices.addEventListener('click', () => {
344
345                // Prepare the data which are sent to the Query object
346                // Used to build the url arguments
347                Query.URLArgs.subCategories = {}
348                Query.URLArgs.subCategories.parameterValue = []
349                // Init values
350                let count = 0
351                let value = ''
352
353                // Get all the checkbox
354                let $subCategoriesCheckboxes = $subCategoriesFilterContainer.querySelectorAll('input[type="checkbox"]')
355
356                // Get the selected state of the toggler
357                let checked = $toggleSubCategoriesChoices.dataset.selected
358
359                // If the toggler data selected is on false we restore the filter on its default state
360                if (checked === 'false') {
361                    // Remove the subcategories args in the URL
362                    delete Query.URLArgs.subCategories
363
364                    // Prepare the toggler for it's next action (select all)
365                    $toggleSubCategoriesChoices.dataset.selected = 'true'
366
367                    // Restore the text of the input
368                    $subCategoriesInput.value = 'Sous-catégories'
369                    // Restore the text in the toggler
370                    $toggleSubCategoriesChoices.innerHTML = 'Tout sélectionner'
371                    // Restore the default style for an inactive filter
372                    $subCategoriesInput.classList.remove('selected')
373
374                    // Unchecked all the sub categories checkboxes
375                    for (let checkbox of $subCategoriesCheckboxes) {
376                        checkbox.checked = false
377                    }
378
379                    // Get all elements which have .selected as class
380                    let elementSelected = $filters.querySelectorAll('.selected')
381                    // If no element fit the selector, we restore the "reset button" to its original state
382                    if (elementSelected.length === 0) {
383                        $resetFilter.classList.add('empty-selection')
384                        $validateFilter.classList.add('empty-selection')
385                    }
386
387                    updateCustomFiltersVisibility(getActiveCategoryIDs())
388                } else {
389                    // This is the part where we check all the checkbox
390                    // Enable the $resetFilter
391
392                    $toggleSubCategoriesChoices.dataset.selected = 'false'
393                    $toggleSubCategoriesChoices.innerHTML = 'Tout désélectionner'
394                    $validateFilter.classList.remove('empty-selection')
395
396                    // Apply the style for a active filter
397                    $subCategoriesInput.classList.add('selected')
398
399                    // We loop through all the selected sub categories
400                    for (let i = 0; i < $subCategoriesCheckboxes.length; i++) {
401                        // We store the checkbox value
402                        let checkbox = $subCategoriesCheckboxes[i]
403                        Query.URLArgs.subCategories.parameterValue.push(checkbox.value)
404
405                        // todo... Si non est là c'est qu'elle est checkée la checkbox non ?
406                        checkbox.checked = true
407
408                        // If we are on the last checkbox element of the NodeList
409                        // We don't add a comma
410                        if (i === Number($subCategoriesCheckboxes.length - 1)) {
411                            value += `${checkbox.dataset.name}`
412                        } else {
413                            value += `${checkbox.dataset.name}, `
414                        }
415                        // We limit the value to 80 characters based of a Query class method
416                        $subCategoriesInput.value = Query.truncate(value, 80, '...', ',')
417
418                        // We increment the count to display it in $subCategoriesCount
419                        count++
420                    }
421
422                    updateCustomFiltersVisibility(getActiveCategoryIDs())
423                }
424                // Update the checked categories count for the $subCategoriesCount
425                if (count === 1 || count === 0) {
426                    $subCategoriesCount.innerHTML = `${count} sélectionnée(s)`
427                } else {
428                    $subCategoriesCount.innerHTML = `${count} sélectionnée(s)`
429                }
430            })
431        }
432
433        /**
434         * Function used to get all the subcategories for a given parent category (displayed in the filter list)
435         * It is triggered on load and when a parent category is selected
436         *
437         * */
438        function displaySubCategories() {
439            if (!!$subCategorieFilter) {
440                // Init the PostsQuery Class
441                let Query = new PostsQuery()
442
443                // Set the custom creasit api route
444                Query._APIRoute = 'taxonomies'
445
446                if (window.cpt && window.cpt === 'consultations') {
447                    Query.URLArgs.state = {}
448                    Query.URLArgs.state.parameterValue = $archivePage.dataset.state
449                }
450                // Init the params to build the API endpoint (= url)
451                const params = {
452                    cpt: window.cpt,
453                    category: window.categoryID ?? '',
454                    taxonomy: window.taxonomy,
455                }
456
457
458                if (Query.URLArgs.state) {
459                    params.state = Query.URLArgs.state.parameterValue
460                }
461
462                // Get API endpoint (= url)
463                let URL = Query.getURL(params)
464                // Submit the fetch we need to get the subcategories
465                Query.fetchAPI(URL, 'GET').then(
466                    data => {
467                        let value = ''
468                        let count = 0
469                        // Exectute the code below only if more than 0 data are found
470                        if (data.length > 0) {
471                            $subCategoriesFilterContainer.innerHTML = ''
472                            $subCategoriesCount.innerHTML = '0 sélectionnée'
473
474                            // Get all the subcategories from [data-ids]
475                            let selectedsubCategories = $subCategoriesFilterContainer.dataset.ids
476                            selectedsubCategories = selectedsubCategories.split(',')
477                            selectedsubCategories = selectedsubCategories.map(function (x) {
478                                return parseInt(x, 10);
479                            });
480
481                            // Remove the class hide apply on the sub-categories select
482                            $subCategorieFilter.dataset.disabled = ''
483
484                            // For each terms that are returned we create its option
485                            // and add it to the sub-categories select
486                            data.forEach((term) => {
487                                if (term.parent !== 0) {
488                                    let checkState = ''
489                                    // If some subCategories are set in the URL params exec the code below
490                                    if (selectedsubCategories.includes(term.term_id)) {
491
492                                        selectedsubCategories.forEac
492h((category, index) => {
493                                            if (term.term_id === Number(category)) {
494                                                if (index === Number(selectedsubCategories.length - 1)) {
495                                                    value += `${term.name}`
496                                                } else {
497                                                    value += `${term.name}, `
498                                                }
499                                                count++
500                                            }
501                                        })
502                                        $subCategoriesInput.value = Query.truncate(value, 80, '...', ',')
503
504                                        // Update the checked categories count for the $subCategoriesCount
505                                        if (count === 1) {
506                                            $subCategoriesCount.innerHTML = `${count} sélectionnée(s)`
507                                        } else {
508                                            $subCategoriesCount.innerHTML = `${count} sélectionnée(s)`
509                                        }
510
511                                        $subCategoriesInput.classList.add('selected')
512                                        $toggleSubCategoriesChoices.dataset.selected = 'false'
513                                        $toggleSubCategoriesChoices.innerHTML = 'Tout désélectionner'
514
515                                        $validateFilter.classList.remove('empty-selection')
516
517                                        // Checked the sub categories that are set in the URL params
518                                        checkState = 'checked'
519                                    }
520
521                                    // Display the subcategories checkboxes and checked the selected
522                                    $subCategoriesFilterContainer.innerHTML += `<li data-level="${term.level}">
523                                <input type="checkbox" value="${term.term_id}" name="0" data-slug="${term.slug}"
524                                       id="${term.term_id}" data-name="${term.name}" ${checkState}>
525                                <label for="${term.term_id}">
526                                    ${term.name}
527                                </label>
528                            </li>`
529                                } else {
530                                    // Si $categoryFilter existe (pas de restriction parente forcée)
531                                    if ($categoryFilter) {
532                                        let $categoryCheckbox = $categoryFilter.querySelector('input[data-id="' + term.term_id + '"]')
533                                        if ($categoryCheckbox) {
534                                            $categoryCheckbox.checked = true
535                                            window.categoryID = Number($categoryCheckbox.dataset.id)
536                                            window.categorySlug = $categoryCheckbox.dataset.slug
537                                            window.taxonomy = $categoryCheckbox.dataset.taxonomy
538                                            document.querySelector('#filter_category').value = $categoryCheckbox.dataset.label ?? $categoryCheckbox.getAttribute('data-placeholder')
539                                            document.querySelector('#filter_category').classList.add('selected')
540                                        }
541                                        $validateFilter.classList.remove('empty-selection')
542                                        $resetFilter.classList.remove('empty-selection')
543                                        displaySubCategories()
544                                    }
545                                    // Si catégorie forcée parente : categoryID/taxonomy déjà initialisés
546                                }
547                            })
548
549                            // Toutes les checkboxes sont dans le DOM et cochées :
550                            // on réévalue avec parent + sous-catégories sélectionnées
551                            updateCustomFiltersVisibility(getActiveCategoryIDs())
552
553                        } else {
554                            // If no data are found we hide the su-categories select
555                            $subCategoriesInput.value = 'Sous-catégories'
556                            $subCategoriesInput.classList.remove('selected')
557                            $subCategoriesFilterContainer.innerHTML = ''
558                            $toggleSubCategoriesChoices.innerHTML = 'Tout sélectionner'
559                            $subCategoriesCount.innerHTML = '0 sélectionnée'
560                            $subCategorieFilter.dataset.disabled = 'disabled'
561                        }
562                    }
563                ).catch(err => {
564                    // TODO handle error to send
565                    console.log(err)
566                })
567            }
568        }
569
570
571        /**
572         * Show/hide custom filters based on the currently selected category.
573         *
574         * Each `.filter_custom` wrapper must have these data-attributes set in PHP:
575         *   data-activate-categories="0|1"
576         *   data-allowed-categories="[12,34,56]"  (JSON array, IDs for the current CPT)
577         *
578         * Logic mirrors setCustomFilters() in PHP:
579         *   - activate_categories == 0  → always show
580         *   - activate_categories == 1 AND allowed-categories is empty/false → always show
581         *   - activate_categories == 1 AND categoryID is in allowed-categories → show
582         *   - otherwise → hide (and reset the filter's value)
583         *
584         * @param {number|string|null} categoryID  The selected category ID, or null/'' when none.
585         */
586        /**
587         * Returns all currently active category IDs :
588         * the selected parent category + any checked subcategories.
589         *
590         * @returns {number[]}
591         */
592        function getActiveCategoryIDs() {
593            const ids = []
594
595            // Parent category
596            const parentID = parseInt(window.categoryID, 10)
597            if (!isNaN(parentID) && parentID !== 0) {
598                ids.push(parentID)
599            }
600
601            // Selected subcategories
602            if ($subCategoriesFilterContainer) {
603                $subCategoriesFilterContainer
604                    .querySelectorAll('input[type="checkbox"]:checked')
605                    .forEach(cb => {
606                        const subID = parseInt(cb.value, 10)
607                        if (!isNaN(subID) && subID !== 0) {
608                            ids.push(subID)
609                        }
610                    })
611            }
612
613            return ids
614        }
615
616        /**
617         * Show/hide custom filters based on the currently active category IDs
618         * (parent category + selected subcategories).
619         *
620         * Logic:
621         *   - activate_categories == 0                           → always show
622         *   - activate_categories == 1 + allowedCategories empty → always show
623         *   - activate_categories == 1 + at least one active ID in allowed list → show
624         *   - otherwise → hide (and reset the filter's value)
625         *
626         * @param {number|number[]|null} categoryIDs
627         */
628        function updateCustomFiltersVisibility(categoryIDs) {
629            // Normalize to a clean array of valid integers
630            const activeIDs = (Array.isArray(categoryIDs) ? categoryIDs : [categoryIDs])
631                .map(id => parseInt(id, 10))
632                .filter(id => !isNaN(id) && id !== 0)
633
634            const $customFilterWrappers = document.querySelectorAll('.filter_custom')
635
636            $customFilterWrappers.forEach(function ($wrapper) {
637                const activateCategories = parseInt($wrapper.dataset.activateCategories ?? '0', 10)
638                let allowedCategories = []
639
640                try {
641                    allowedCategories = JSON.parse($wrapper.dataset.allowedCategories ?? '[]')
642                } catch (e) {
643                    allowedCategories = []
644                }
645
646                let shouldShow = true
647
648                if (activateCategories === 1 && allowedCategories.length > 0) {
649                    // Show if at least one active ID (parent or subcat) is in the allowed list
650                    shouldShow = activeIDs.some(id => allowedCategories.includes(id))
651                }
652
653                if (shouldShow) {
654                    $wrapper.style.display = ''
655                } else {
656                    $wrapper.style.display = 'none'
657
658                    const $input = $wrapper.querySelector('.filter__input-container input')
659                    const $ul = $wrapper.querySelector('.filter__custom-container ul')
660
661                    if ($input) {
662                        $input.classList.remove('selected')
663                        $input.value = ''
664                    }
665
666                    if ($ul) {
667                        $ul.querySelectorAll('input[type="checkbox"]:checked').forEach(cb => {
668                            cb.checked = false
669                        })
670
671                        const param = $input ? $input.getAttribute('id') : null
672                        if (param && Query.URLArgs[param]) {
673                            delete Query.URLArgs[param]
674                        }
675                    }
676                }
677            })
678        }
679
680        /***
681         * Check for the filter validation button's presence and listen his click
682         *
683         * This function is used to build and submit the query to the WP API
684         * Although it builds the url parameter that will be pushed in the page url
685         ****/
686        // Apply custom filters visibility on initial load based on any category already in the URL
687        updateCustomFiltersVisibility(getActiveCategoryIDs())
688        !!$validateFilter &&
689        $validateFilter.addEventListener('click', function () {
690            let selectedSubCategoriesID = []
691            let selectedMonths = []
692            let selectedYears = []
693            let selectedCustomFilters = []
694            let selectedKeyword = ''
695            let selectedStatus = ''
696            let selectedDate = ''
697
698            // Add view in URLQuery base
699            let initParams = new URLSearchParams(window.location.search)
700            let view = initParams.get('view')
701            if (view) {
702                Query.URLArgs.view = {}
703                Query.URLArgs.view.parameterValue = view
704            } else {
705                delete Query.URLArgs.view
706            }
707
708            if (!!$subCategoriesFilterContainer) {
709                let selectedSubCategories = $subCategoriesFilterContainer.querySelectorAll('input[type="checkbox"]:checked')
710                selectedSubCategories.forEach((category) => {
711                    selectedSubCategoriesID.push(category.value)
712                })
713
714                if (selectedSubCategoriesID.length > 0) {
715                    Query.URLArgs.subCategories = {}
716                    Query.URLArgs.subCategories.parameterValue = selectedSubCategoriesID
717                } else {
718                    delete Query.URLArgs.subCategories
719                }
720            }
721
722            if (!!$dateFilterContainer) {
723                let dateCheckbox = $dateFilterContainer.querySelector('input[type="radio"]:checked')
724
725                // Init the Query.URLArgs object with the date entry
726                Query.URLArgs.date = {}
727                Query.URLArgs.date.parameterValue = []
728
729                if (dateCheckbox !== null) {
730                    if (dateCheckbox.value !== 'no_date') {
731                        // We push its value in the Query.URLArgs.cpt.parameterValue
732                        selectedDate = dateCheckbox.value
733                        Query.URLArgs.date.parameterValue.push(dateCheckbox.value)
734                    } else {
735                        selectedDate = dateCheckbox.value
736                        delete Query.URLArgs.date
737                    }
738                }
739            }
740
741            if (!!$monthsFilter) {
742                let monthsCheckbox = $monthsFilter.querySelectorAll('input[type="checkbox"]:checked')
743
744                monthsCheckbox.forEach((month) => {
745                    selectedMonths.push(month.dataset.monthnumber)
746                })
747
748                if (monthsCheckbox.length > 0) {
749                    Query.URLArgs.months = {}
750                    Query.URLArgs.months.parameterValue = selectedMonths
751                } else {
752                    delete Query.URLArgs.months
753                }
754            }
755
756            if (!!$yearsFilter) {
757                let yearsCheckboxes = $yearsFilter.querySelectorAll('input[type="checkbox"]:checked')
758
759                yearsCheckboxes.forEach((year) => {
760                    selectedYears.push(year.dataset.yearnumber)
761                })
762
763                if (yearsCheckboxes.length > 0) {
764                    Query.URLArgs.years = {}
765                    Query.URLArgs.years.parameterValue = selectedYears
766                } else {
767                    delete Query.URLArgs.years
768                }
769            }
770
771            let customParams = []
772            if (!!$customFilters) {
773                $customFilters.forEach(function ($customFilter) {
774                    let customFilterCheckboxes = $customFilter.querySelectorAll('input[type="checkbox"]:checked')
775                    let param = $customFilter.closest('.filter_custom').querySelector('.filter__input-container input').getAttribute('id')
776                    selectedCustomFilters[param] = []
777
778                    customParams.push($customFilter.closest('.filter_custom').querySelector('.filter__input-container input').getAttribute('id'))
779                    customFilterCheckboxes.forEach((option) => {
780                        selectedCustomFilters[param].push(option.value)
781                    })
782
783                    if (customFilterCheckboxes.length > 0) {
784                        Query.URLArgs[param] = {}
785                        Query.URLArgs[param].parameterValue = selectedCustomFilters[param]
786                    } else {
787                        delete Query.URLArgs[param]
788                    }
789                })
790            }
791
792            // Init the Query.URLArgs object with the keyword entry
793            if (!!$keywordsFilter) {
794                selectedKeyword = $keywordsFilter.value
795                if (selectedKeyword.length > 0) {
796                    Query.URLArgs.keyword = {}
797                    Query.URLArgs.keyword.parameterValue = selectedKeyword
798                } else {
799                    delete Query.URLArgs.keyword
800                }
801            }
802
803            if (!!$statusFilterContainer) {
804                let statusCheckbox = $statusFilterContainer.querySelector('input[type="radio"]:checked')
805
806                // Init the Query.URLArgs object with the date entry
807                Query.URLArgs.status = {}
808                Query.URLArgs.status.parameterValue = []
809
810                if (statusCheckbox !== null) {
811                    if (statusCheckbox.value !== null) {
812                        // We push its value in the Query.URLArgs.cpt.parameterValue
813                        selectedStatus = statusCheckbox.value
814                        Query.URLArgs.status.parameterValue.push(statusCheckbox.value)
815                    } else {
816                        selectedStatus = statusCheckbox.value
817                        delete Query.URLArgs.status
818                    }
819                }
820            }
821
822            if (window.cpt && window.cpt === 'consultations') {
823                Query.URLArgs.state = {}
824                Query.URLArgs.state.parameterValue = $archivePage.dataset.state
825            }
826
827            $resetFilter.classList.remove('empty-selection')
828
829            // Init the params to build the API endpoint (= url)
830            const params = {
831                pages: 1,
832                cpt: cpt,
833                category: window.categoryID ?? '',
834                subCategories: selectedSubCategoriesID,
835                numberPosts: postsPerPage,
836                months: selectedMonths ?? '',
837                years: selectedYears ?? '',
838                post_status: ['publish'],
839                dateRange: selectedDate ?? '',
840                keyword: selectedKeyword ?? '',
841                status: selectedStatus ?? '',
842            }
843
844            if (customParams.length > 0) {
845                customParams.forEach(function (customParam) {
846                    params[customParam] = selectedCustomFilters[customParam] ?? ''
847
848                    if (Query.URLArgs[customParam]) {
849                        params[customParam] = Query.URLArgs[customParam].parameterValue
850                    }
851                })
852            }
853
854            if (Query.URLArgs.startDate) {
855                params.startDate = Query.URLArgs.startDate.parameterValue
856            }
857
858            if (Query.URLArgs.endDate) {
859                params.endDate = Query.URLArgs.endDate.parameterValue
860            }
861
862            if (!!$archivePage) {
863                params.orderBy = $archivePage.dataset.orderby
864                params.order = $archivePage.dataset.order ?? ''
865
866                let $metakey = $archivePage.dataset.metakey
867                if ($metakey) {
868                    params.metaKey = $metakey
869                }
870            }
871
872            if (Query.URLArgs.state) {
873                params.state = Query.URLArgs.state.parameterValue
874            }
875
876            // Get API endpoint (= url)
877            let URL = Query.getURL(params)
878            // Fetch on the API
879            execPostFetch(URL, countPostPerPage_INT)
880        })
881
882        document.addEventListener('keydown', function (e) {
883            if (e.key !== 'Enter') return
884            if (!$validateFilter) return
885
886            const activeEl = document.activeElement
887
888            // Let native Enter behavior work on buttons and links
889            if (['BUTTON', 'A', 'SELECT'].includes(activeEl.tagName)) return
890            if (activeEl.closest('.accordion--transcription')) return
891
892            const isInKeyword = $keywordsFilter && $keywordsFilter === activeEl
893            const filtersAreVisible = $filters && getComputedStyle($filters).display !== 'none'
894
895            if (filtersAreVisible || isInKeyword) {
896                e.preventDefault()
897                $validateFilter.click()
898            }
899        })
900
901        !!$resetFilter &&
902        $resetFilter.addEventListener('click', function () {
903
904            let initParams = new URLSearchParams(window.location.search)
905            let view = initParams.get('view')
906            // Remove all the arguments in the URL
907            Object.keys(Query.URLArgs).forEach(function (arg) {
908                delete Query.URLArgs[arg]
909            })
910
911            delete Query.URLArgs.category
912
913            // Get selected input
914
915            let $selectedInputs = $filters.querySelectorAll('.selected')
916            let $selectedForgottenInputs = document.querySelectorAll('.filter__input.selected')
917            let $checkedInputs = $filters.querySelectorAll('input:checked')
918
919            $selectedInputs.forEach((input) => {
920                input.classList.remove('selected')
921                input.value = ''
922            })
923            $selectedForgottenInputs.forEach((input) => {
924                input.classList.remove('selected')
925                input.value = ''
926            })
927
928            $checkedInputs.forEach((input) => {
929                input.checked = false
930            })
931
932            if ($categoryFilter) {
933                $categoryFilter.querySelector('#filter_category').setAttribute('placeholder', 'Catégorie')
934                $categoryFilter.querySelector('#filter_category').value = ''
935            }
936
937            if ($subCategorieFilter) {
938                $subCategorieFilter.dataset.disabled = 'disabled'
939                $subCategoriesFilterContainer.dataset.ids = ''
940            }
941            if ($toggleSubCategoriesChoices) {
942                $subCategoriesCount.innerHTML = '0 sélectionnée'
943                $subCategoriesFilterContainer.innerHTML = ''
944                $toggleSubCategoriesChoices.dataset.selected = 'true'
945                $toggleSubCategoriesChoices.innerHTML = 'Tout sélectionner'
946            }
947
948            if (window.cpt && window.cpt === 'consultations') {
949                Query.URLArgs.state = {}
950                Query.URLArgs.state.parameterValue = $archivePage.dataset.state
951            }
952
953            if (view) {
954                Query.URLArgs.view = {}
955                Query.URLArgs.view.parameterValue = view
956            }
957
958
959            // Get the first number of posts (before fetching
960            // on API)
961            let countPostPerPage_HTML = $countPostPerPage.innerHTML
962            countPostPerPage_INT = parseInt(countPostPerPage_HTML)
963
964            // Init the params to build the API endpoint (= url)
965            let $orderby = $archivePage.dataset.orderby
966            let $order = $archivePage.dataset.order
967            const params = {
968                pages: 1,
969                cpt: cpt,
970                numberPosts: postsPerPage,
971                orderBy: $orderby,
972                order: $order,
973                post_status: ['publish'],
974            }
975            let $metakey = $archivePage.dataset.metakey
976            if ($metakey) {
977                params.metaKey = $metakey
978            }
979
980            if (Query.URLArgs.state) {
981                params.state = Query.URLArgs.state.parameterValue
982            }
983
984
985            window.categoryID = ''
986
987            // Si une catégorie est forcée côté back, on la restaure après le reset
988            if ($archivePage.dataset.forcedCategory) {
989                window.categoryID = Number($archivePage.dataset.forcedCategory)
990                Query.URLArgs.category = {}
991                Query.URLArgs.category.parameterValue = [window.categoryID]
992                params.category = window.categoryID
993
994                // Si catégorie parente forcée : réinitialiser les sous-catégories
995                if ($subCategorieFilter && $subCategorieFilter.dataset.forcedParent === '1') {
996                    window.taxonomy = cptTaxonomyMap[window.cpt] || window.cpt + '_category'
997                    displaySubCategories()
998                }
999            }
1000
1001            // Show all custom filters since no category is selected
1002            updateCustomFiltersVisibility(null)
1003
1004            // Inclure les subCategories de l'URL dans la query initiale si présents
1005            // (cas d'une page d'archive avec catégorie parente forcée et subCategories dans l'URL)
1006            if (Query.URLArgs.subCategories) {
1007                params.subCategories = Query.URLArgs.subCategories.parameterValue
1008            }
1009
1010            // Get API endpoint (= url)
1011            let URL = Query.getURL(params)
1012            // Fetch on the API
1013            execPostFetch(URL, countPostPerPage_INT)
1014
1015            $validateFilter.classList.add('empty-selection')
1016            $resetFilter.classList.add('empty-selection')
1017        })
1018
1019    }
1020
1021    /**
1022     * FILTERS not category
1023     */
1024
1025
1026    /***
1027     * This listener is used to
1028     * 1. Display the number of selected sub categories in the $subCategoriesCount
1029     * 2. Display the subcategories' names in the $subCategoriesFilterContainer
1030     * ***/
1031    if (!!$monthsFilter) {
1032
1033        // Get all the month from [data-ids]
1034        let selectedMonths = $monthsFilter.dataset.ids
1035
1036        if (selectedMonths) {
1037            selectedMonths = selectedMonths.split(',')
1038
1039            if (selectedMonths && selectedMonths.length > 0) {
1040                let value = ''
1041
1042                $validateFilter.classList.remove('empty-selection')
1043                for (let i = 0; i < selectedMonths.length; i++) {
1044
1045                    let month = selectedMonths[i]
1046                    let $monthToSelect = $monthsFilter.querySelector(`[data-monthnumber="${month}"]`)
1047                    $monthsFilterInput.classList.add('selected')
1048                    $monthToSelect.checked = true
1049
1050                    let $monthLabel = $monthToSelect.getAttribute('id');
1051
1052                    // If we are on the last checkbox element of the NodeList
1053                    // We don't add a comma
1054                    if (i === Number(selectedMonths.length - 1)) {
1055                        value += `${$monthLabel}`
1056                    } else {
1057                        value += `${$monthLabel}, `
1058                    }
1059                }
1060                // We limit the value to 80 characters based of a Query class method
1061                $monthsFilterInput.value = Query.truncate(value, 80, '...', ',')
1062            }
1063        }
1064
1065
1066        $monthsFilter.addEventListener('click', () => {
1067
1068            // Get the list of the checked input in the UL
1069            let $monthsFilterCheckboxes = $monthsFilter.querySelectorAll('input[type="checkbox"]:checked')
1070
1071            // Init values
1072            let count = 0
1073            let value = ''
1074
1075            // We control that the number of checked element is === 0
1076            // If it's true we remove all the data register during the subCatogories choice
1077            // And restore to original condition
1078            if ($monthsFilterCheckboxes.length === 0) {
1079
1080                // Remove the argument from the URL builder
1081                delete Query.URLArgs.months
1082
1083                // Restore the original $subCategoriesInput condition
1084                $monthsFilterInput.value = ''
1085                $monthsFilterInput.classList.remove('selected')
1086
1087                // Get all elements which have .selected as class
1088                let elementSelected = $filters.querySelectorAll('.selected')
1089                // If no element fit the selector, we restore the "reset button" to its original state
1090                if (elementSelected.length === 0) {
1091                    $resetFilter.classList.add('empty-selection')
1092                    $validateFilter.classList.add('empty-selection')
1093                }
1094            } else {
1095                // If we have a selection of checkboxes :
1096
1097                // The reset button is enabled
1098
1099                $validateFilter.classList.remove('empty-selection')
1100
1101                // The $subCategoriesInput has class selected
1102                $monthsFilterInput.classList.add('selected')
1103
1104                // Prepare the data which are sent to the Query object
1105                // Used to build the url arguments
1106                Query.URLArgs.months = {}
1107                Query.URLArgs.months.parameterValue = []
1108
1109                // We loop through all the selected sub categories
1110                for (let i = 0; i < $monthsFilterCheckboxes.length; i++) {
1111                    // We store the checkbox value
1112                    let checkbox = $monthsFilterCheckboxes[i]
1113                    Query.URLArgs.months.parameterValue.push(checkbox.value)
1114
1115                    // todo... Si on est là c'est qu'elle est checkée la checkbox non ?
1116                    // checkbox.checked = true
1117
1118                    // If we are on the last checkbox element of the NodeList
1119                    // We don't add a comma
1120                    if (i === Number($monthsFilterCheckboxes.length - 1)) {
1121                        value += `${checkbox.value}`
1122                    } else {
1123                        value += `${checkbox.value}, `
1124                    }
1125                    // We limit the value to 80 characters based of a Query class method
1126                    $monthsFilterInput.value = Query.truncate(value, 80, '...', ',')
1127
1128                    // We increment the count to display it in $subCategoriesCount
1129                    count++
1130                }
1131            }
1132        })
1133    }
1134
1135
1136    if (!!$customFilters) {
1137        $customFilters.forEach(function ($customFilter) {
1138            // Get all the month from [data-ids]
1139            let selectedOptions = $customFilter.dataset.ids
1140
1141            if (selectedOptions) {
1142                selectedOptions = selectedOptions.split(',')
1143
1144                if (selectedOptions && selectedOptions.length > 0) {
1145                    let value = ''
1146
1147                    $validateFilter.classList.remove('empty-selection')
1148                    for (let i = 0; i < selectedOptions.length; i++) {
1149
1150                        let option = selectedOptions[i]
1151                        let optionToSelect = $customFilter.querySelector(`[data-option="${option}"]`)
1152                        $customFilter.closest('.filter_custom').querySelector('.filter__input-container input').classList.add('selected')
1153                        optionToSelect.checked = true
1154
1155                        let optionLabel = optionToSelect.getAttribute('id');
1156
1157                        // If we are on the last checkbox element of the NodeList
1158                        // We don't add a comma
1159                        if (i === Number(selectedOptions.length - 1)) {
1160                            value += `${optionLabel}`
1161                        } else {
1162                            value += `${optionLabel}, `
1163                        }
1164                    }
1165                    // We limit the value to 80 characters based of a Query class method
1166                    $customFilter.closest('.filter_custom').querySelector('.filter__input-container input').value = Query.truncate(value, 80, '...', ',')
1167                }
1168            }
1169
1170
1171            $customFilter.addEventListener('click', () => {
1172
1173                // Get the list of the checked input in the UL
1174                let $customFilterCheckboxes = $customFilter.querySelectorAll('input[type="checkbox"]:checked')
1175
1176                // Init values
1177                let count = 0
1178                let value = ''
1179                let param = $customFilter.closest('.filter_custom').querySelector('.filter__input-container input').getAttribute('id')
1180
1181                // We control that the number of checked element is === 0
1182                // If it's true we remove all the data register during the subCatogories choice
1183                // And restore to original condition
1184                if ($customFilterCheckboxes.length === 0) {
1185
1186                    // Remove the argument from the URL builder
1187                    delete Query.URLArgs[param]
1188
1189                    // Restore the original $subCategoriesInput condition
1190                    $customFilter.closest('.filter_custom').querySelector('.filter__input-container input').value = ''
1191                    $customFilter.closest('.filter_custom').querySelector('.filter__input-container input').classList.remove('selected')
1192
1193                    // Get all elements which have .selected as class
1194                    let elementSelected = $filters.querySelectorAll('.selected')
1195                    // If no element fit the selector, we restore the "reset button" to its original state
1196                    if (elementSelected.length === 0) {
1197                        $resetFilter.classList.add('empty-selection')
1198                        $validateFilter.classList.add('empty-selection')
1199                    }
1200                } else {
1201                    // If we have a selection of checkboxes :
1202
1203                    // The reset button is enabled
1204
1205                    $validateFilter.classList.remove('empty-selection')
1206
1207                    // The $subCategoriesInput has class selected
1208                    $customFilter.closest('.filter_custom').querySelector('.filter__input-container input').classList.add('selected')
1209
1210                    // Prepare the data which are sent to the Query object
1211                    // Used to build the url arguments
1212                    Query.URLArgs[param] = {}
1213                    Query.URLArgs[param].parameterValue = []
1214
1215
1216                    // We loop through all the selected sub categories
1217                    for (let i = 0; i < $customFilterCheckboxes.length; i++) {
1218                        // We store the checkbox value
1219                        let checkbox = $customFilterCheckboxes[i]
1220                        Query.URLArgs[param].parameterValue.push(checkbox.value)
1221
1222                        // todo... Si on est là c'est qu'elle est checkée la checkbox non ?
1223                        // checkbox.checked = true
1224
1225                        // If we are on the last checkbox element of the NodeList
1226                        // We don't add a comma
1227                        if (i === Number($customFilterCheckboxes.length - 1)) {
1228                            value += `${checkbox.getAttribute('id')}`
1229                        } else {
1230                            value += `${checkbox.getAttribute('id')}, `
1231                        }
1232                        // We limit the value to 80 characters based of a Query class method
1233                        $customFilter.closest('.filter_custom').querySelector('.filter__input-container input').value = Query.truncate(value, 80, '...', ',')
1234
1235                        // We increment the count to display it in $subCategoriesCount
1236                        count++
1237                    }
1238                }
1239            })
1240        })
1241
1242
1243    }
1244    /***
1245     * This listener is used to
1246     * 1. Display the number of selected sub categories in the $subCategoriesCount
1247     * 2. Display the subcategories' names in the $subCategoriesFilterContainer
1248     * ***/
1249    if (!!$postTypeFilter) {
1250        $postTypeFilter.addEventListener('click', () => {
1251
1252            // Get the list of the checked input in the UL
1253            let $postTypeFilterCheckboxes = $postTypeFilter.querySelectorAll('input[type="checkbox"]:checked')
1254
1255            // Init values
1256            let count = 0
1257            let value = ''
1258
1259            // We control that the number of checked element is === 0
1260            // If it's true we remove all the data register during the subCatogories choice
1261            // And restore to original condition
1262            if ($postTypeFilterCheckboxes.length === 0) {
1263
1264                // Remove the argument from the URL builder
1265                delete Query.URLArgs.postType
1266
1267                // Restore the original $subCategoriesInput condition
1268                $postTypeInput.value = ''
1269                $postTypeInput.classList.remove('selected')
1270
1271                // Get all elements which have .selected as class
1272                let elementSelected = $filters.querySelectorAll('.selected')
1273                // If no element fit the selector, we restore the "reset button" to its original state
1274                if (elementSelected.length === 0) {
1275                    $resetFilter.classList.add('empty-selection')
1276                    $validateFilter.classList.add('empty-selection')
1277                }
1278            } else {
1279                // If we have a selection of checkboxes :
1280
1281                // The reset button is enabled
1282
1283                $validateFilter.classList.remove('empty-selection')
1284
1285                // The $subCategoriesInput has class selected
1286                $postTypeInput.classList.add('selected')
1287
1288                // Prepare the data which are sent to the Query object
1289                // Used to build the url arguments
1290                Query.URLArgs.postType = {}
1291                Query.URLArgs.postType.parameterValue = []
1292
1293                // We loop through all the selected sub categories
1294                for (let i = 0; i < $postTypeFilterCheckboxes.length; i++) {
1295                    // We store the checkbox value
1296                    let checkbox = $postTypeFilterCheckboxes[i]
1297                    Query.URLArgs.postType.parameterValue.push(checkbox.dataset.label)
1298
1299                    // todo... Si non est là c'est qu'elle est checkée la checkbox non ?
1300                    // checkbox.checked = true
1301
1302                    // If we are on the last checkbox element of the NodeList
1303                    // We don't add a comma
1304                    if (i === Number($postTypeFilterCheckboxes.length - 1)) {
1305                        value += `${checkbox.dataset.label}`
1306                    } else {
1307                        value += `${checkbox.dataset.label}, `
1308                    }
1309                    // We limit the value to 80 characters based of a Query class method
1310                    $postTypeInput.value = Query.truncate(value, 80, '...', ',')
1311
1312                    // We increment the count to display it in $subCategoriesCount
1313                    count++
1314                }
1315            }
1316        })
1317    }
1318
1319    /***
1320     * This listener is used to
1321     * 1. Display the number of selected sub categories in the $subCategoriesCount
1322     * 2. Display the subcategories' names in the $subCategoriesFilterContainer
1323     * ***/
1324    if (!!$yearsFilter) {
1325        // Get all the month from [data-ids]
1326        let selectedYears = $yearsFilter.dataset.ids
1327
1328        if (selectedYears) {
1329            selectedYears = selectedYears.split(',')
1330
1331            $validateFilter.classList.remove('empty-selection')
1332
1333            if (selectedYears.length > 0) {
1334                let value = ''
1335                for (let i = 0; i < selectedYears.length; i++) {
1336
1337                    let years = selectedYears[i]
1338                    let $yearsToSelect = $yearsFilter.querySelector(`[data-yearnumber="${years}"]`)
1339                    $yearsFilterInput.classList.add('selected')
1340                    $yearsToSelect.checked = true
1341
1342                    let $yearsLabel = $yearsToSelect.getAttribute('id');
1343
1344                    // If we are on the last checkbox element of the NodeList
1345                    // We don't add a comma
1346                    if (i === Number(selectedYears.length - 1)) {
1347                        value += `${$yearsLabel}`
1348                    } else {
1349                        value += `${$yearsLabel}, `
1350                    }
1351                }
1352                // We limit the value to 80 characters based of a Query class method
1353                $yearsFilterInput.value = Query.truncate(value, 80, '...', ',')
1354            }
1355        }
1356        $yearsFilter.addEventListener('click', () => {
1357
1358            // Get the list of the checked input in the UL
1359            let $yearsFilterCheckboxes = $yearsFilter.querySelectorAll('input[type="checkbox"]:checked')
1360
1361            // Init values
1362            let value = ''
1363
1364            // We control that the number of checked element is === 0
1365            // If it's true we remove all the data register during the subCatogories choice
1366            // And restore to original condition
1367            if ($yearsFilterCheckboxes.length === 0) {
1368
1369                // Remove the argument from the URL builder
1370                delete Query.URLArgs.years
1371
1372                // Restore the original $subCategoriesInput condition
1373                $yearsFilterInput.value = ''
1374                $yearsFilterInput.classList.remove('selected')
1375
1376                // Get all elements which have .selected as class
1377                let elementSelected = $filters.querySelectorAll('.selected')
1378                // If no element fit the selector, we restore the "reset button" to its original state
1379                if (elementSelected.length === 0) {
1380                    $resetFilter.classList.add('empty-selection')
1381                    $validateFilter.classList.add('empty-selection')
1382                }
1383            } else {
1384                // If we have a selection of checkboxes :
1385
1386                // The reset button is enabled
1387
1388                $validateFilter.classList.remove('empty-selection')
1389
1390                // The $subCategoriesInput has class selected
1391                $yearsFilterInput.classList.add('selected')
1392
1393                // Prepare the data which are sent to the Query object
1394                // Used to build the url arguments
1395                Query.URLArgs.years = {}
1396                Query.URLArgs.years.parameterValue = []
1397
1398                // We loop through all the selected sub categories
1399                for (let i = 0; i < $yearsFilterCheckboxes.length; i++) {
1400                    // We store the checkbox value
1401                    let checkbox = $yearsFilterCheckboxes[i]
1402                    Query.URLArgs.years.parameterValue.push(checkbox.value)
1403
1404                    // todo... Si non est là c'est qu'elle est checkée la checkbox non ?
1405                    // checkbox.checked = true
1406
1407                    // If we are on the last checkbox element of the NodeList
1408                    // We don't add a comma
1409                    if (i === Number($yearsFilterCheckboxes.length - 1)) {
1410                        value += `${checkbox.value}`
1411                    } else {
1412                        value += `${checkbox.value}, `
1413                    }
1414                    // We limit the value to 80 characters based of a Query class method
1415                    $yearsFilterInput.value = Query.truncate(value, 80, '...', ',')
1416                }
1417            }
1418        })
1419    }
1420
1421
1422    /***
1423     * This listener is used to
1424     * 1. Display the number of selected sub categories in the $subCategoriesCount
1425     * 2. Display the subcategories' names in the $subCategoriesFilterContainer
1426     * ***/
1427    if (!!$inputStartDate) {
1428        let argsStartDate = {
1429            dateFormat: 'dd/mm/yy',
1430            altField: $inputStartDate,
1431            altFormat: 'yymmdd',
1432            changeYear: true,
1433            yearRange: "-100:+100",
1434            changeMonth: true,
1435            showButtonPanel: true,
1436            onSelect: function () {
1437                handleDatePicker($inputTextStartDate, 'startDate', $inputStartDate.val())
1438            },
1439
1440        }
1441        acf.newDatePicker($inputTextStartDate, argsStartDate)
1442        let searchQuery = window.location.search
1443        let params = new URLSearchParams(searchQuery)
1444        if (params.get('startDate')) {
1445            let startDate = params.get('startDate').substr(0, 4) + '-' + params.get('startDate').substr(4, 2) + '-' + params.get('startDate').substr(6, 2)
1446            handleDatePicker($inputTextStartDate, 'startDate', startDate)
1447            $inputTextStartDate.datepicker("setDate", new Date(startDate))
1448        }
1449    }
1450    if (!!$inputTextEndDate) {
1451        let argsEndDate = {
1452            dateFormat: 'dd/mm/yy',
1453            altField: $inputEndDate,
1454            altFormat: 'yymmdd',
1455            changeYear: true,
1456            yearRange: "-100:+100",
1457            changeMonth: true,
1458            showButtonPanel: true,
1459            onSelect: function () {
1460                handleDatePicker($inputTextEndDate, 'endDate', $inputEndDate.val())
1461            }
1462        }
1463        acf.newDatePicker($inputTextEndDate, argsEndDate)
1464        let searchQuery = window.location.search
1465        let params = new URLSearchParams(searchQuery)
1466        if (params.get('endDate')) {
1467            let endDate = params.get('endDate').substr(0, 4) + '-' + params.get('endDate').substr(4, 2) + '-' + params.get('endDate').substr(6, 2)
1468            handleDatePicker($inputTextEndDate, 'endDate', endDate)
1469            $inputTextEndDate.datepicker("setDate", new Date(endDate))
1470        }
1471    }
1472
1473    function handleDatePicker($input, type, $selectedDate) {
1474
1475
1476        // Prepare the data which are sent to the Query object
1477        // Used to build the url arguments
1478        Query.URLArgs[type] = {}
1479        Query.URLArgs[type].parameterValue = []
1480
1481        // Enable the $resetFilter
1482
1483        // In case of no selection we restore all the style to their default state
1484        if ($selectedDate === undefined) {
1485            // Remove the subcategories args in the URL
1486            delete Query.URLArgs[type]
1487
1488            let elementSelected = $filters.querySelectorAll('.selected')
1489            // If no element fit the selector, we restore the "reset button" to its original state
1490            if (elementSelected.length === 0) {
1491                $resetFilter.classList.add('empty-selection')
1492                $validateFilter.classList.add('empty-selection')
1493            }
1494
1495            $input.removeClass('selected')
1496        } else {
1497            // This one is when a valid selection is made
1498            Query.URLArgs[type].parameterValue = $selectedDate
1499
1500            $input.addClass('selected')
1501
1502            $validateFilter.classList.remove('empty-selection')
1503        }
1504    }
1505
1506
1507    if (!!$resetKeywordInput) {
1508        $resetKeywordInput.addEventListener('click', () => {
1509
1510            //
1510 Set no value && remove the selected state
1511            $keywordsFilter.value = ''
1512            $keywordsFilter.classList.remove('selected')
1513
1514            // Relancer la recherche AVANT de recalculer l'état des boutons :
1515            // le handler du bouton Filtrer réactive le bouton Réinitialiser (il retire
1516            // empty-selection sans condition). Le clic programmatique passe outre le pointer-events:none.
1517            if (!!$validateFilter) {
1518                $validateFilter.click()
1519            }
1520
1521            // Puis on rétablit l'état des boutons selon les filtres ENCORE sélectionnés :
1522            // s'il reste une catégorie (ou autre filtre), Réinitialiser doit rester actif ;
1523            // sinon on le remet à l'état inactif.
1524            let elementSelected = $filters.querySelectorAll('.selected')
1525            if (elementSelected.length === 0) {
1526                $resetFilter.classList.add('empty-selection')
1527                $validateFilter.classList.add('empty-selection')
1528            }
1529        })
1530    }
1531
1532    /***
1533     * This listener is used to
1534     * 1. Display or not the $resetKeywordInput
1535     * 2. enable or not the $resetFilter button
1536     * ***/
1537    if (!!$keywordsFilter) {
1538        $keywordsFilter.addEventListener('input', () => {
1539            // We enable the $resetFilter
1540
1541            // Get the input value
1542            let keywordValue = $keywordsFilter.value
1543
1544            // Depends on the value's length we apply the styl
1545            if (keywordValue.length > 0) {
1546                $keywordsFilter.classList.add('selected')
1547
1548                $validateFilter.classList.remove('empty-selection')
1549            } else {
1550                $keywordsFilter.classList.remove('selected')
1551
1552                // Get all elements which have .selected as class
1553                let elementSelected = $filters.querySelectorAll('.selected')
1554                // If no element fit the selector, we restore the "reset button" to its original state
1555                if (elementSelected.length === 0) {
1556                    $resetFilter.classList.add('empty-selection')
1557                    $validateFilter.classList.add('empty-selection')
1558                }
1559            }
1560
1561        })
1562    }
1563
1564    /***
1565     * This listener is used to get the selected range date and handle the reset of the filter
1566     * ***/
1567    if (!!$dateFilterContainer) {
1568        $dateFilterContainer.addEventListener('click', () => {
1569            // Enable the $resetFilter
1570
1571
1572            // Get the selected range date
1573            let $dateCheckbox = $dateFilterContainer.querySelector('input[type="radio"]:checked')
1574
1575            // In case of no selection we restore all the style to their default state
1576            if ($dateCheckbox === null) {
1577                // Restore the input to its original state
1578                $dateInput.classList.remove('selected')
1579
1580                // Get all elements which have .selected as class
1581                let elementSelected = $filters.querySelectorAll('.selected')
1582                // If no element fit the selector, we restore the "reset button" to its original state
1583                if (elementSelected.length === 0) {
1584                    $resetFilter.classList.add('empty-selection')
1585                    $validateFilter.classList.add('empty-selection')
1586                }
1587                // The date filter is a list of radio, we need to have a default selection
1588                // That resets the state of the filter
1589            } else if ($dateCheckbox.value === 'no_date') {
1590                $dateInput.classList.remove('selected')
1591                $dateInput.value = 'Date de publication'
1592
1593                // Get all elements which have .selected as class
1594                let elementSelected = $filters.querySelectorAll('.selected')
1595                // If no element fit the selector, we restore the "reset button" to its original state
1596                if (elementSelected.length === 0) {
1597                    $resetFilter.classList.add('empty-selection')
1598                    $validateFilter.classList.add('empty-selection')
1599                }
1600            } else {
1601                // This one is when a valid selection is made
1602                $dateInput.classList.add('selected')
1603                $dateInput.value = $dateCheckbox.dataset.label ?? $dateCheckbox.getAttribute('data-placeholder')
1604
1605                $validateFilter.classList.remove('empty-selection')
1606            }
1607
1608        })
1609    }
1610
1611    if (!!$statusFilterContainer) {
1612        $statusFilterContainer.addEventListener('click', () => {
1613            // Enable the $resetFilter
1614
1615
1616            // Get the selected range date
1617            let $statusCheckbox = $statusFilterContainer.querySelector('input[type="radio"]:checked')
1618
1619            // In case of no selection we restore all the style to their default state
1620            if ($statusCheckbox === null) {
1621                // Restore the input to its original state
1622                $statusInput.classList.remove('selected')
1623
1624                // Get all elements which have .selected as class
1625                let elementSelected = $filters.querySelectorAll('.selected')
1626                // If no element fit the selector, we restore the "reset button" to its original state
1627                if (elementSelected.length === 0) {
1628                    $resetFilter.classList.add('empty-selection')
1629                }
1630                // The status filter is a list of radio, we need to have a default selection
1631                // That resets the state of the filter
1632            } else {
1633                // This one is when a valid selection is made
1634                $statusInput.classList.add('selected')
1635                $statusInput.value = $statusCheckbox.dataset.label ?? $statusCheckbox.getAttribute('placeholder')
1636                $validateFilter.classList.remove('empty-selection')
1637            }
1638
1639        })
1640    }
1641
1642    function execPostFetch(URL, countPostPerPage_INT) {
1643        Query.fetchAPI(URL, 'GET').then(
1644            data => {
1645
1646                // Store the pagination_infos' elements inside variables
1647                let postsPerPage = data.pagination_infos.postsPerPage
1648                let foundPosts = data.pagination_infos.foundPosts
1649                let pages = data.pagination_infos.pages
1650                let postCount = data.pagination_infos.postCount
1651
1652                // Get the count of all the post in the Categorie
1653                $countTotal.innerHTML = foundPosts
1654
1655                // Init the Query.URLArgs object with the sub-category entry
1656                if (pages > 1) {
1657                    Query.URLArgs.pages = {}
1658                    Query.URLArgs.pages.parameterValue = [pages]
1659                } else {
1660                    delete Query.URLArgs.pages
1661                }
1662                // Init the Query.URLArgs object with the date entry
1663                if (window.categoryID !== 'all') {
1664                    Query.URLArgs.category = {}
1665                    Query.URLArgs.category.parameterValue = [window.categoryID]
1666                } else {
1667                    delete Query.URLArgs.category
1668                }
1669
1670
1671                // Push args in URL
1672                Query.pushSearchArgsInUrl()
1673                // Append posts
1674                Query.appendPosts(data.posts, $listingContainer, false)
1675
1676                // Get the value of canPaginate function (true/false)
1677                let canPaginate = Query.canPaginate(postsPerPage, foundPosts, pages)
1678
1679                // Delete the load more button
1680                if (loadMoreBTN) {
1681                    if (canPaginate === false) {
1682                        Query.fadeOut(loadMoreBTN)
1683                    } else {
1684                        Query.fadeIn(loadMoreBTN)
1685                    }
1686                }
1687
1688                // Restore Email Address
1689                let $emailsTo = document.querySelectorAll('main a[href^="mailto:"]:not(.share-mail)');
1690                $emailsTo.forEach(e => {
1691                    e.href = e.href.replace('[^@]', '@')
1692                    e.title = e.title.replace('[^@]', '@')
1693                });
1694
1695
1696                // Get the postCount after the fetch and display it
1697                $countPostPerPage.innerHTML = Query.getCount(
1698                    postCount, countPostPerPage_INT, false)
1699            },
1700        ).catch(err => {
1701            // TODO handle error to send
1702            console.log(err)
1703        })
1704    }
1705
1706
1707    /***
1708     * Searchpage
1709     * ***/
1710        // Const
1711    const body = document.querySelector('body');
1712    const SearchInput = document.querySelector('#searchInput');
1713    const SearchPageExist = body.classList.contains('search');
1714
1715    if (SearchPageExist && SearchInput) {
1716        document.addEventListener('click', function (event) {
1717            let selectBoxes = document.querySelectorAll('.select-box.is-open')
1718            selectBoxes.forEach((selectBox) => {
1719                if (selectBox === event.target.closest('.select-box')) {
1720                    let radios = selectBox ? selectBox.querySelectorAll('input[type=radio]') : []
1721                    !!radios && radios.forEach((radio) => {
1722                        if (event.target === radio) {
1723                            selectBox.classList.replace('is-open', 'is-closed')
1724                        }
1725                    })
1726                }
1727            })
1728        })
1729    }
1730
1731    /***
1732     * Navigation
1733     * ***/
1734
1735        // Mise à jour du fil d'ariane avec l'URL archive depuis localStorage
1736    const $breadcrumbArchive = document.getElementById('breadcrumbArchive')
1737    if ($breadcrumbArchive) {
1738        const storedUrl = localStorage.getItem('back_to_archive')
1739        const storedTitle = localStorage.getItem('back_to_archive_title')
1740        if (storedUrl) {
1741            $breadcrumbArchive.href = storedUrl
1742            if (storedTitle) {
1743                $breadcrumbArchive.textContent = storedTitle
1744                $breadcrumbArchive.title = `Consulter la page ${storedTitle} (même onglet)`
1745            }
1746        }
1747    }
1748
1749    // Côté archive — stockage au clic sur une card via délégation
1750    // (les cards sont injectées dynamiquement donc on écoute sur document)
1751    if (document.getElementById('archivePage')) {
1752        document.addEventListener('click', function(e) {
1753            if (e.target.closest('.card__link')) {
1754                localStorage.setItem('back_to_archive', window.location.href)
1755                localStorage.setItem('back_to_archive_title', document.title)
1756            }
1757        })
1758    }
1759
1760    // Côté post — lecture et application du localStorage sur le bouton retour
1761    const $backBtn = document.getElementById('backToArchive')
1762    if ($backBtn) {
1763        const storedUrl = localStorage.getItem('back_to_archive')
1764        if (storedUrl) {
1765            $backBtn.href = storedUrl
1766            localStorage.removeItem('back_to_archive')
1767            localStorage.removeItem('back_to_archive_title')
1768        }
1769    }
1770
1771    //==============================================================================
1772    // ------ Filter-toggle inherited from demosaisie
1773    //==============================================================================
1774    // Create jQuery slideToggle in Vanilla JS
1775    // to see filter options in archives templates
1776
1777    (function () {
1778        var block, i, j, len, len1, ref, ref1, slideToggler, trigger,
1779            indexOf = [].indexOf;
1780
1781        slideToggler = class slideToggler {
1782            constructor(el1) {
1783                this.getHeight = this.getHeight.bind(this);
1784                this.toggle = this.toggle.bind(this);
1785                this.el = el1;
1786                if (!this.el) {
1787                    return;
1788                }
1789                window.addEventListener('resize', this.getHeight);
1790            }
1791
1792            getHeight() {
1793                var clone;
1794                clone = this.el.cloneNode(true);
1795                clone.style.cssText = 'visibility: hidden; display: block; margin: -999px 0';
1796                this.height = (this.el.parentNode.appendChild(clone)).clientHeight;
1797                this.el.parentNode.removeChild(clone);
1798                return this.height;
1799            }
1800
1801            toggle(time) {
1802                var currHeight, disp, el, end, init, repeat, start;
1803                this.getHeight();
1804                time || (time = this.height / 3 + 150);
1805                currHeight = this.el.clientHeight * (getComputedStyle(this.el).display !== 'none');
1806                [start, end] = currHeight > this.height / 2 ? [this.height, 0] : [0, this.height];
1807                disp = end - start;
1808                el = this.el;
1809                this.el.classList[end === 0 ? 'remove' : 'add']('is-open');
1810                this.el.style.cssText = "overflow: hidden; display: block;";
1811                init = (new Date).getTime();
1812                repeat = function () {
1813                    var instance, ref, repeatLoop, step;
1814                    instance = (new Date).getTime() - init;
1815                    step = start + disp * instance / time;
1816                    if (instance <= time) {
1817                        el.style.height = step + 'px'; // if Math.floor(step) in [start..end]
1818                    } else {
1819                        el.style.cssText = `display: ${(end === 0 ? 'none' : 'block')}`;
1820                    }
1821                    repeatLoop = requestAnimationFrame(repeat);
1822                    if (ref = Math.floor(step), indexOf.call((function () {
1823                        var results = [];
1824                        for (var i = start; start <= end ? i <= end : i >= end; start <= end ? i++ : i--) {
1825                            results.push(i);
1826                        }
1827                        return results;
1828                    }).apply(this), ref) < 0) {
1829                        return cancelAnimationFrame(repeatLoop);
1830                    }
1831                };
1832                return repeat();
1833            }
1834
1835        };
1836
1837        // Options Noyau
1838        let filtersCloseDefault = posts_filters_params.filters_close_default;
1839
1840        // if on tablet/mobile OR Search page Results : is closed
1841        if ((window.innerWidth < 960) || (SearchPageExist && SearchInput) || filtersCloseDefault) {
1842
1843            ref = document.querySelectorAll('.filter__options');
1844            for (i = 0, len = ref.length; i < len; i++) {
1845                block = ref[i];
1846                block.style.cssText = "display: none;";
1847                block.toggler = new slideToggler(block);
1848            }
1849
1850            ref1 = document.querySelectorAll('.filter__toggler');
1851            for (j = 0, len1 = ref1.length; j < len1; j++) {
1852                trigger = ref1[j];
1853                trigger.classList.add('is-closed');
1854                trigger.addEventListener('click', function () {
1855                    var ref2;
1856                    return (ref2 = this.parentNode.parentNode.querySelector('.filter__options').toggler) != null ? ref2.toggle(
1856) : void 0;
1857                });
1858            }
1859        } else {
1860
1861            ref = document.querySelectorAll('.filter__options');
1862            for (i = 0, len = ref.length; i < len; i++) {
1863                block = ref[i];
1864                block.style.cssText = "display: block;";
1865                block.toggler = new slideToggler(block);
1866            }
1867
1868            ref1 = document.querySelectorAll('.filter__toggler');
1869            for (j = 0, len1 = ref1.length; j < len1; j++) {
1870                trigger = ref1[j];
1871                trigger.classList.add('is-open');
1872                trigger.addEventListener('click', function () {
1873                    var ref2;
1874                    return (ref2 = this.parentNode.parentNode.querySelector('.filter__options').toggler) != null ? ref2.toggle() : void 0;
1875                });
1876            }
1877        }
1878
1879    }).call(this);
1880
1881    // Change toggler on click
1882    const filterToggler = document.querySelector(".filter__toggler");
1883
1884    function classToggle() {
1885        filterToggler.classList.toggle('is-closed');
1886        filterToggler.classList.toggle('is-open');
1887    }
1888
1889    !!filterToggler && filterToggler.addEventListener('click', classToggle);
1890
1891
1892})

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.