1/* FAQ accordion behaviour â markup comes from inc/faq-component/render.php. 2 * 3 * Exactly one item open at a time, scoped to its own group so two accordions on one page stay 4 * independent. The open item is rendered server-side, so this script starts from whatever the 5 * template produced rather than imposing its own default. 6 * 7 * Depends on vanillaSlideDown / vanillaSlideUp from common.js, which the read-more toggle shares; 8 * this file must load after it. 9 */ 10 11(function () { 12 'use strict'; 13 14 var GROUP = '[data-faq-group]'; 15 var TRIGGER = '.cilFaq__trigger'; 16 var ITEM = 'cilFaq__item'; 17 var OPEN_ITEM = 'is-open'; 18 19 /** The group a trigger belongs to; falls back to the document if the markup is ungrouped. */ 20 function groupOf(trigger) { 21 return trigger.closest(GROUP) || document; 22 } 23 24 function panelOf(trigger) { 25 return document.getElementById(trigger.dataset.content); 26 } 27 28 function isOpen(trigger) { 29 return trigger.getAttribute('aria-expanded') === 'true'; 30 } 31 32 /** 33 * Open or close one item, keeping trigger, panel and item wrapper in sync. 34 * `animate === false` jumps straight to the end state â used only as a fallback on load. 35 */ 36 function setOpen(trigger, open, animate) { 37 var panel = panelOf(trigger); 38 if (!panel) return; 39 40 trigger.classList.toggle('active', open); 41 trigger.setAttribute('aria-expanded', open ? 'true' : 'false'); 42 43 var item = trigger.closest('.' + ITEM); 44 if (item) item.classList.toggle(OPEN_ITEM, open); 45 46 if (animate === false) { 47 if (panel._transitionCancel) panel._transitionCancel(); 48 panel.classList.toggle('active', open); 49 panel.style.height = open ? 'auto' : ''; 50 return; 51 } 52 if (open) vanillaSlideDown(panel, 'active'); 53 else vanillaSlideUp(panel, 'active'); 54 } 55 56 /** Collapse every other open item in the same group. */ 57 function closeSiblings(trigger) { 58 var triggers = groupOf(trigger).querySelectorAll(TRIGGER); 59 for (var i = 0; i < triggers.length; i++) { 60 if (triggers[i] !== trigger && isOpen(triggers[i])) setOpen(triggers[i], false); 61 } 62 } 63 64 function onClick(e) { 65 e.preventDefault(); 66 if (isOpen(this)) { 67 setOpen(this, false); 68 return; 69 } 70 closeSiblings(this); 71 setOpen(this, true); 72 var panel = panelOf(this); 73 if (panel) panel.focus(); 74 } 75 76 function init() { 77 var triggers = document.querySelectorAll(TRIGGER); 78 for (var i = 0; i < triggers.length; i++) { 79 triggers[i].addEventListener('click', onClick); 80 } 81 82 // The open item is rendered server-side, so there is normally nothing to do here. Only fall 83 // back to opening the first item when a group somehow arrives with none open. 84 var groups = document.querySelectorAll(GROUP); 85 for (var g = 0; g < groups.length; g++) { 86 var inGroup = groups[g].querySelectorAll(TRIGGER); 87 if (!inGroup.length) continue; 88 var anyOpen = false; 89 for (var j = 0; j < inGroup.length; j++) { 90 if (isOpen(inGroup[j])) { anyOpen = true; break; } 91 } 92 // No animation and no focus call: focusing would scroll the visitor down to the FAQ on load. 93 if (!anyOpen) setOpen(inGroup[0], true, false); 94 } 95 } 96 97 if (document.readyState === 'loading') { 98 document.addEventListener('DOMContentLoaded', init); 99 } else { 100 init(); 101 } 102})();
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.