PageSourceSearch

https://www.isere.fr/themes/custom/theme-eolas-base/eolas_base/assets/js/combobox.js?1790240184

js isere.fr collected 2026-09-24 08:56:45 UTC 4,926 bytes, 128 lines download raw bytes

1const comboBox = () => {
2  const comboBoxes = document.querySelectorAll('.js-combobox'); // Targeting all comboboxes
3
4  comboBoxes.forEach((comboBoxElement) => {
5    let currentIndex = -1; // Tracks the current highlighted index for each combobox
6    let originalAriaLabel = comboBoxElement.getAttribute('aria-label'); // Store the aria-label of the button
7    let originalButtonText = comboBoxElement.innerText.trim(); // Store the original value of the button
8
9    const button = comboBoxElement;
10    const ariaControlsValue = button.getAttribute('aria-controls');
11
12    if(ariaControlsValue) {
13      const listbox = document.querySelector(`#${ariaControlsValue}`);
14      const options = Array.from(listbox.querySelectorAll('[role="option"]'));
15
16      // Open Listbox
17      button.addEventListener('click', () => {
18        const expanded = button.getAttribute('aria-expanded') === 'true';
19        button.setAttribute('aria-expanded', !expanded);
20        listbox.classList.toggle('u-hidden');
21        listbox.setAttribute('aria-hidden', expanded);
22
23        if (!expanded) {
24          // Highlight current selected index
25          currentIndex = options.findIndex(option => option.hasAttribute('aria-selected'));
26          highlightOption(currentIndex);
27          listbox.focus();
28        }
29      });
30
31      // Keyboard Navigation for the Button
32      button.addEventListener('keydown', (event) => {
33        if (event.key === 'ArrowDown') {
34          event.preventDefault();
35          // Open the listbox if it's not already open
36          if (button.getAttribute('aria-expanded') === 'false') {
37            button.click(); // This will open the listbox
38          } else {
39            // If the listbox is open, navigate down
40            currentIndex = (currentIndex + 1) % options.length; // Cycle down
41            highlightOption(currentIndex);
42            updateButtonText(currentIndex);
43          }
44        } else if (event.key === 'ArrowUp') {
45          event.preventDefault();
46          currentIndex = (currentIndex - 1 + options.length) % options.length; // Cycle up
47          highlightOption(currentIndex);
48          updateButtonText(currentIndex);
49        }
50      });
51
52      // Keyboard Navigation for the Listbox
53      listbox.addEventListener('keydown', (event) => {
54        if (event.key === 'ArrowDown') {
55          event.preventDefault();
56          currentIndex = (currentIndex + 1) % options.length; // Cycle down
57          highlightOption(currentIndex);
58          updateButtonText(currentIndex);
59        } else if (event.key === 'ArrowUp') {
60          event.preventDefault();
61          currentIndex = (currentIndex - 1 + options.length) % options.length; // Cycle up
62          highlightOption(currentIndex);
63          updateButtonText(currentIndex);
64        } else if (event.key === 'Enter') {
65          event.preventDefault();
66          selectOption(currentIndex);
67        } else if (event.key === 'Escape') {
68          closeListbox();
69
70          // Reset button value on Escape
71          button.firstChild.textContent = originalButtonText; // Restore original value
72          button.setAttribute('aria-label', originalAriaLabel); // Restore aria-label
73        }
74      });
75
76      // Highlight Option
77      function highlightOption(index) {
78        options.forEach((option, i) => {
79          if (i === index) {
80            option.setAttribute('aria-selected', 'true');
81            option.querySelector('a').focus();
82          } else {
83            option.removeAttribute('aria-selected');
84          }
85        });
86      }
87
88      // Update Button Text Dynamically
89      function updateButtonText(index) {
90        if (index >= 0 && index < options.length) {
91          const selectedOption = options[index];
92          const selectedText = selectedOption.textContent.trim();
93
94          // Update the dynamic text portion of the button (Page X)
95          const buttonText = `${selectedText}`;
96
97          // Update the button's text content, leaving <i> and <span> untouched
98          button.firstChild.textContent = Drupal.t(`${selectedText}`);
99
100          // Update the aria-label as well
101          button.setAttribute('aria-label', Drupal.t(`Sélectionné : ${selectedText}`));
102        }
103      }
104
105      // Select Option and Navigate
106      function selectOption(index) {
107        if (index >= 0 && index < options.length) {
108          const link = options[index].querySelector('a');
109          updateButtonText(index);
110          closeListbox();
111          if (link && link.href) {
112            window.location.href = link.href; // Navigate to the selected page
113          }
114        }
115      }
116
117      // Close Listbox
118      function closeListbox() {
119        listbox.classList.add('u-hidden');
120        listbox.setAttribute('aria-hidden', 'true');
121        button.setAttribute('aria-expanded', 'false');
122        button.focus();
123      }
124    }
125  });
126};
127
128const load_comboBox = window.addEventListener("DOMContentLoaded", comboBox);

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.