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.