1(function($) { 2 Drupal.behaviors.accordionTabs = { 3 attach: function(context, settings) { 4 let tabCounter = 0; 5 6 $('.coh-accordion-tabs', context).once().each(function() { 7 const container = this; 8 const tabInner = container.querySelector('.coh-accordion-tabs-inner'); 9 if (!tabInner) return; 10 11 const tabItems = tabInner.querySelectorAll('.coh-accordion-tabs-nav .coh-style-tab-items'); 12 const tabLinks = tabInner.querySelectorAll('.coh-accordion-tabs-nav .coh-style-tab-items a'); 13 const tabContent = tabInner.querySelectorAll('.coh-accordion-tabs-content-wrapper .coh-accordion-tabs-content'); 14 15 const componentId = `tabs-${++tabCounter}`; 16 17 const dataString = tabInner.dataset.cohAccordion; 18 let accordionSetting; 19 20 try { 21 accordionSetting = JSON.parse(dataString); 22 } catch (e) { 23 console.error('Invalid JSON in data-coh-accordion:', dataString); 24 return; 25 } 26 27 const accordionOrTab = accordionSetting.styles?.xl?.accordionOrTab; 28 29 if (accordionOrTab === "tabs") { 30 // Set role on the tablist 31 tabInner.setAttribute('role', 'tablist'); 32 tabInner.setAttribute('aria-label', 'Tabs component'); 33 34 // Set roles on tab items 35 tabItems.forEach(li => { 36 li.parentElement.setAttribute('role', 'presentation'); 37 li.setAttribute('role', 'presentation'); 38 }); 39 40 // Assign roles and ARIA attributes to tabs and panels 41 tabLinks.forEach((link, index) => { 42 const tabId = `${componentId}-tab-${index}`; 43 const panelId = `${componentId}-panel-${index}`; 44 const panel = tabContent[index]; 45 46 // Set tab attributes 47 link.setAttribute('role', 'tab'); 48 link.setAttribute('id', tabId); 49 link.setAttribute('aria-controls', panelId); 50 51 const parentElement = link.closest('.coh-style-tab-items'); 52 const isActive = parentElement.classList.contains('is-active'); 53 54 link.setAttribute('aria-selected', isActive ? 'true' : 'false'); 55 link.setAttribute('tabindex', isActive ? '0' : '-1'); 56 57 // Set panel attributes 58 if (panel) { 59 panel.setAttribute('role', 'tabpanel'); 60 panel.setAttribute('tabindex', isActive ? '0' : '-1'); 61 panel.setAttribute('id', panelId); 62 panel.setAttribute('aria-labelledby', tabId); 63 panel.setAttribute('aria-hidden', isActive ? 'false' : 'true'); 64 } 65 66 link.addEventListener('click', function(e) { 67 68 // Deselect all tabs and hide all panels 69 tabLinks.forEach((l, i) => { 70 l.setAttribute('aria-selected', 'false'); 71 l.setAttribute('tabindex', '-1'); 72 tabContent[i].setAttribute('aria-hidden', 'true'); 73 tabContent[i].setAttribute('tabindex', '-1'); 74 }); 75 76 // Activate clicked tab and corresponding panel 77 this.setAttribute('aria-selected', 'true'); 78 this.setAttribute('tabindex', '0'); 79 panel.setAttribute('aria-hidden', 'false'); 80 panel.setAttribute('tabindex', '0'); 81 }); 82 83 // Keyboard navigation 84 link.addEventListener('keydown', (event) => { 85 if (event.key === 'Enter') { 86 event.preventDefault(); 87 } 88 89 let newIndex; 90 91 if (event.key === 'ArrowRight') { 92 newIndex = (index + 1) % tabLinks.length; 93 } else if (event.key === 'ArrowLeft') { 94 newIndex = (index - 1 + tabLinks.length) % tabLinks.length; 95 } 96 97 if (newIndex !== undefined) { 98 tabLinks.forEach((t, i) => { 99 t.setAttribute('tabindex', i === newIndex ? '0' : '-1'); 100 t.setAttribute('aria-selected', i === newIndex ? 'true' : 'false'); 101 }); 102 103 tabLinks[newIndex].focus(); 104 tabLinks[newIndex].click(); 105 } 106 }); 107 }); 108 } 109 }); 110 } 111 }; 112})(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.