PageSourceSearch

https://irap.org/wp-content/themes/awdd-vite/resources/js/governance-filter.js?ver=1778745656

js irap.org collected 2026-10-02 03:36:32 UTC 4,838 bytes, 124 lines download raw bytes

1/**
2 * Governance Listing — dropdown filter UX
3 *
4 * Mirrors the Library block's filter dropdown (open/close, in-panel category
5 * search, checkbox state, Reset/Cancel/Apply) but submits the form natively to
6 * a URL with `governance_category[]` params instead of going through AJAX.
7 */
8(function () {
9    'use strict';
10
11    function initForm(form) {
12        if (!form || form.dataset.governanceFilterInit === '1') return;
13        form.dataset.governanceFilterInit = '1';
14
15        const toggle    = form.querySelector('[data-filter-toggle]');
16        const panel     = form.querySelector('[data-filter-panel]');
17        const chevron   = form.querySelector('[data-filter-chevron]');
18        const search    = form.querySelector('[data-filter-search]');
19        const list      = form.querySelector('[data-filter-list]');
20        const noMatch   = form.querySelector('.filter-no-match');
21        const resetBtn  = form.querySelector('[data-filter-reset]');
22        const cancelBtn = form.querySelector('[data-filter-cancel]');
23        const checkboxes = form.querySelectorAll('[data-filter-checkbox]');
24
25        if (!toggle || !panel) return;
26
27        // Snapshot initial checked state for cancel/restore
28        let snapshot = Array.from(checkboxes).map(cb => cb.checked);
29
30        function setOpen(open) {
31            if (open) {
32                panel.hidden = false;
33                toggle.setAttribute('aria-expanded', 'true');
34                if (chevron) chevron.style.transform = 'rotate(180deg)';
35                snapshot = Array.from(checkboxes).map(cb => cb.checked);
36            } else {
37                panel.hidden = true;
38                toggle.setAttribute('aria-expanded', 'false');
39                if (chevron) chevron.style.transform = '';
40                if (search) {
41                    search.value = '';
42                    filterOptions('');
43                }
44            }
45        }
46
47        function filterOptions(term) {
48            term = (term || '').toLowerCase().trim();
49            let visibleCount = 0;
50            if (list) {
51                list.querySelectorAll('.filter-option').forEach(li => {
52                    const text = li.getAttribute('data-filter-option-text') || '';
53                    const match = term === '' || text.indexOf(term) !== -1;
54                    li.style.display = match ? '' : 'none';
55                    if (match) visibleCount++;
56                });
57            }
58            if (noMatch) noMatch.classList.toggle('hidden', visibleCount !== 0);
59        }
60
61        toggle.addEventListener('click', function (e) {
62            e.preventDefault();
63            setOpen(panel.hidden);
64        });
65
66        document.addEventListener('click', function (e) {
67            if (panel.hidden) return;
68            if (form.contains(e.target)) return;
69            setOpen(false);
70        });
71
72        document.addEventListener('keydown', function (e) {
73            if (e.key === 'Escape' && !panel.hidden) setOpen(false);
74        });
75
76        if (search) {
77            search.addEventListener('input', function () {
78                filterOptions(search.value);
79            });
80        }
81
82        if (resetBtn) {
83            resetBtn.addEventListener('click', function (e) {
84                e.preventDefault();
85                checkboxes.forEach(cb => { cb.checked = false; });
86            });
87        }
88
89        if (cancelBtn) {
90            cancelBtn.addEventListener('click', function (e) {
91                e.preventDefault();
92                checkboxes.forEach((cb, i) => { cb.checked = !!snapshot[i]; });
93                setOpen(false);
94            });
95        }
96    }
97
98    // Scroll the active pill inside each .pill-strip into view on load.
99    // Active = first pill with the "bg-asphalt" class (matches selected state).
100    function scrollActivePillIntoView() {
101        document.querySelectorAll('.pill-strip').forEach(strip => {
102            const active = strip.querySelector('.bg-asphalt');
103            if (!active) return;
104            const stripRect  = strip.getBoundingClientRect();
105            const activeRect = active.getBoundingClientRect();
106            // Skip if already fully visible.
107            if (activeRect.left >= stripRect.left && activeRect.right <= stripRect.right) return;
108            // Center the active pill within the strip without affecting page scroll.
109            const offset = (active.offsetLeft) - (strip.clientWidth / 2) + (active.offsetWidth / 2);
110            strip.scrollTo({ left: Math.max(0, offset), behavior: 'auto' });
111        });
112    }
113
114    function init() {
115        document.querySelectorAll('[data-governance-filter-form]').forEach(initForm);
116        scrollActivePillIntoView();
117    }
118
119    if (document.readyState === 'loading') {
120        document.addEventListener('DOMContentLoaded', init);
121    } else {
122        init();
123    }
124})();

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.