1/** 2 * FAQ Accordion - jQuery Version 3 * Accessible accordion that allows only one panel open at a time 4 */ 5 6(function($) { 7 'use strict'; 8 9 /** 10 * Initialize accordion functionality 11 */ 12 function initAccordion($accordion) { 13 var $buttons = $accordion.find('.faq-button'); 14 15 if ($buttons.length === 0) return; 16 17 // Click handler 18 $buttons.on('click', function() { 19 toggleAccordion($(this), $accordion); 20 }); 21 22 // Keyboard navigation 23 $buttons.on('keydown', function(e) { 24 handleKeyboard(e, $(this), $buttons); 25 }); 26 } 27 28 /** 29 * Toggle accordion panel 30 */ 31 function toggleAccordion($button, $accordion) { 32 var isExpanded = $button.attr('aria-expanded') === 'true'; 33 var panelId = $button.attr('aria-controls'); 34 var $panel = $('#' + panelId); 35 36 if ($panel.length === 0) return; 37 38 // Close all other panels in this accordion 39 closeAllPanels($accordion); 40 41 // Toggle current panel 42 if (!isExpanded) { 43 openPanel($button, $panel); 44 } 45 // If it was already open, it's now closed by closeAllPanels 46 } 47 48 /** 49 * Open a specific panel 50 */ 51 function openPanel($button, $panel) { 52 $button.attr('aria-expanded', 'true'); 53 $panel.removeAttr('hidden'); 54 $panel.addClass('is-open'); 55 56 // Set max-height based on actual content height for smooth animation 57 var contentHeight = $panel[0].scrollHeight; 58 $panel.css('max-height', contentHeight + 'px'); 59 } 60 61 /** 62 * Close a specific panel 63 */ 64 function closePanel($button, $panel) { 65 $button.attr('aria-expanded', 'false'); 66 $panel.attr('hidden', ''); 67 $panel.removeClass('is-open'); 68 $panel.css('max-height', '0'); 69 } 70 71 /** 72 * Close all panels in an accordion 73 */ 74 function closeAllPanels($accordion) { 75 var $buttons = $accordion.find('.faq-button'); 76 77 $buttons.each(function() { 78 var $btn = $(this); 79 var panelId = $btn.attr('aria-controls'); 80 var $panel = $('#' + panelId); 81 82 if ($panel.length > 0 && $btn.attr('aria-expanded') === 'true') { 83 closePanel($btn, $panel); 84 } 85 }); 86 } 87 88 /** 89 * Handle keyboard navigation 90 */ 91 function handleKeyboard(event, $currentButton, $allButtons) { 92 var key = event.key; 93 var buttonsArray = $allButtons.toArray(); 94 var currentIndex = buttonsArray.indexOf($currentButton[0]); 95 96 var targetButton; 97 98 switch(key) { 99 case 'ArrowDown': 100 event.preventDefault(); 101 targetButton = buttonsArray[currentIndex + 1] || buttonsArray[0]; 102 $(targetButton).focus(); 103 break; 104 105 case 'ArrowUp': 106 event.preventDefault(); 107 targetButton = buttonsArray[currentIndex - 1] || buttonsArray[buttonsArray.length - 1]; 108 $(targetButton).focus(); 109 break; 110 111 case 'Home': 112 event.preventDefault(); 113 $(buttonsArray[0]).focus(); 114 break; 115 116 case 'End': 117 event.preventDefault(); 118 $(buttonsArray[buttonsArray.length - 1]).focus(); 119 break; 120 } 121 } 122 123 /** 124 * Initialize all accordions on page load 125 */ 126 function init() { 127 $('.faq-accordion').each(function() { 128 initAccordion($(this)); 129 }); 130 } 131 132 // Initialize when DOM is ready 133 $(document).ready(init); 134 135 // Expose init function globally for dynamic content 136 window.initFAQAccordions = init; 137 138})(jQuery);
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.