1/* 2 * This content is licensed according to the W3C Software License at 3 * https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document 4 * 5 * File: tabs-automatic.js 6 * 7 * Desc: Tablist widget that implements ARIA Authoring Practices 8 */ 9 10'use strict'; 11 12class TabsAutomatic { 13 constructor(groupNode) { 14 this.tablistNode = groupNode; 15 16 this.tabs = []; 17 18 this.firstTab = null; 19 this.lastTab = null; 20 21 this.tabs = Array.from(this.tablistNode.querySelectorAll('[role=tab]')); 22 this.tabpanels = []; 23 24 for (var i = 0; i < this.tabs.length; i += 1) { 25 var tab = this.tabs[i]; 26 var tabpanel = document.getElementById(tab.getAttribute('aria-controls')); 27 28 tab.tabIndex = -1; 29 tab.setAttribute('aria-selected', 'false'); 30 this.tabpanels.push(tabpanel); 31 32 tab.addEventListener('keydown', this.onKeydown.bind(this)); 33 tab.addEventListener('click', this.onClick.bind(this)); 34 35 if (!this.firstTab) { 36 this.firstTab = tab; 37 } 38 this.lastTab = tab; 39 } 40 41 this.setSelectedTab(this.firstTab, false); 42 } 43 44 setSelectedTab(currentTab, setFocus, click = false) { 45 if (typeof setFocus !== 'boolean') { 46 setFocus = true; 47 } 48 for (var i = 0; i < this.tabs.length; i += 1) { 49 var tab = this.tabs[i]; 50 if (currentTab === tab) { 51 if (tab && tab.classList.contains('tab-with-link') && !click) { 52 var link = tab.querySelector('a'); 53 var span = tab.querySelector('span'); 54 55 // If both elements exist, hide the <a> and show the <span> 56 if (link && span) { 57 link.classList.add('custom-hidden'); 58 span.classList.remove('custom-hidden'); 59 } 60 this.tabpanels[i].querySelector('a').classList.remove('custom-hidden'); 61 } 62 else if (tab && tab.classList.contains('tab-with-link') && click) { 63 this.tabpanels[i].querySelector('a').click(); 64 } 65 tab.setAttribute('aria-selected', 'true'); 66 tab.removeAttribute('tabindex'); 67 tab.classList.add('active'); 68 this.tabpanels[i].classList.remove('is-hidden'); 69 if (setFocus) { 70 tab.focus(); 71 } 72 } else { 73 tab.setAttribute('aria-selected', 'false'); 74 tab.tabIndex = -1; 75 tab.classList.remove('active'); 76 this.tabpanels[i].classList.add('is-hidden'); 77 } 78 } 79 } 80 81 setSelectedToPreviousTab(currentTab) { 82 var index; 83 84 if (currentTab === this.firstTab) { 85 this.setSelectedTab(this.lastTab); 86 } else { 87 index = this.tabs.indexOf(currentTab); 88 this.setSelectedTab(this.tabs[index - 1]); 89 } 90 } 91 92 setSelectedToNextTab(currentTab) { 93 var index; 94 95 if (currentTab === this.lastTab) { 96 this.setSelectedTab(this.firstTab); 97 } else { 98 index = this.tabs.indexOf(currentTab); 99 this.setSelectedTab(this.tabs[index + 1]); 100 } 101 } 102 103 /* EVENT HANDLERS */ 104 105 onKeydown(event) { 106 var tgt = event.currentTarget, 107 flag = false; 108 109 switch (event.key) { 110 case 'ArrowLeft': 111 this.setSelectedToPreviousTab(tgt); 112 flag = true; 113 break; 114 115 case 'ArrowRight': 116 this.setSelectedToNextTab(tgt); 117 flag = true; 118 break; 119 120 case 'Home': 121 this.setSelectedTab(this.firstTab); 122 flag = true; 123 break; 124 125 case 'End': 126 this.setSelectedTab(this.lastTab); 127 flag = true; 128 break; 129 130 default: 131 break; 132 } 133 134 if (flag) { 135 event.stopPropagation(); 136 event.preventDefault(); 137 } 138 } 139 140 onClick(event) { 141 this.setSelectedTab(event.currentTarget, true, true); 142 } 143} 144 145// Initialize tablist 146 147window.addEventListener('load', function () { 148 var tablists = document.querySelectorAll('[role=tablist].automatic'); 149 for (var i = 0; i < tablists.length; i++) { 150 new TabsAutomatic(tablists[i]); 151 } 152});
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.