1/** 2 * Tabs 3 * 4 * @since HybridMag 1.0.0 5 */ 6 (function() { 7 8 var uiwCounter = 0; 9 10 // Counter to be used to create a unique id. 11 function incrementCounter() { 12 uiwCounter = uiwCounter + 1; 13 return uiwCounter; 14 } 15 16 // Creates a uniqueId. 17 function uniqueId() { 18 var count = incrementCounter(); 19 return "th-id-" + count.toString(); 20 } 21 22 /** 23 * Tabs constructor function. 24 * 25 * @param {*} element 26 */ 27 function Tabs(element) { 28 this.element = element; 29 this.tablist = element.querySelector('ul'); 30 this.tabs = this.tablist.querySelectorAll('a'); 31 this.panels = []; 32 33 this.setup(); 34 this.addListeners(); 35 // Always open the first tab at start. 36 this.openTab(this.tabs[0], false); 37 } 38 39 // Initial Setup for the whole tab widget. 40 Tabs.prototype.setup = function() { 41 42 // Set the tablist role. 43 this.tablist.setAttribute("role", "tablist"); 44 45 for( var i = 0; i < this.tabs.length; i++ ) { 46 var tab = this.tabs[i]; 47 var panelId = tab.getAttribute('href'); 48 var ariaControl = panelId.substring(1); 49 50 var uid = uniqueId(); 51 this.setupTab(tab, uid, ariaControl); 52 53 var panel = this.element.querySelector(panelId); 54 55 // If there is not a panel just ignore. 56 if( panel != null ) { 57 panel = this.setupPanel(panel, uid); 58 this.panels.push(panel); 59 } 60 } 61 }; 62 63 // Initial setup for tabs. 64 Tabs.prototype.setupTab = function(tab, uniqueId, ariaControl) { 65 var listitem = tab.parentElement; 66 67 tab.setAttribute("id", uniqueId); 68 69 listitem.setAttribute("role", "tab"); 70 listitem.setAttribute("aria-labelledby", uniqueId); 71 listitem.setAttribute("aria-controls", ariaControl); 72 }; 73 74 // Initial setup for panels. 75 Tabs.prototype.setupPanel = function(panel, uniqueId) { 76 panel.setAttribute("aria-labelledby", uniqueId); 77 panel.setAttribute("role", "tabpanel") 78 return panel; 79 }; 80 81 // Add event listeners. 82 Tabs.prototype.addListeners = function() { 83 var self = this; 84 for( var i = 0; i < this.tabs.length; i++ ) { 85 this.tabs[i].addEventListener('click', function(event) { 86 event.preventDefault(); 87 self.openTab(this); 88 }); 89 this.tabs[i].addEventListener('keydown', function(event) { 90 self.keyDownEventListener(event); 91 }); 92 } 93 }; 94 95 // Key up event listener. 96 Tabs.prototype.keyDownEventListener = function(event) { 97 98 if( event.keyCode == 39 ) { 99 var tabId = event.target.id; 100 var tabIndex = 0; 101 var tabsLength = this.tabs.length; 102 103 var tabIndex = this.getTabPosition(tabId); 104 105 if ( tabIndex + 1 < tabsLength ) { 106 this.openTab(this.tabs[tabIndex + 1]); 107 } else { 108 this.openFirstTab(); 109 } 110 } 111 112 if( event.keyCode == 37 ) { 113 var tabId = event.target.id; 114 var tabIndex = 0; 115 var tabsLength = this.tabs.length; 116 117 var tabIndex = this.getTabPosition(tabId); 118 119 if ( tabIndex != 0 ) { 120 this.openTab(this.tabs[tabIndex - 1]); 121 } else { 122 this.openLastTab(); 123 } 124 } 125 126 }; 127 128 // Returns the array position of a given tab. 129 // See if there is any default function for this. 130 Tabs.prototype.getTabPosition = function(tabId) { 131 for( var i = 0; i < this.tabs.length; i++ ) { 132 var tab = this.tabs[i]; 133 if( tabId == tab.getAttribute('id') ) { 134 return i; 135 } 136 } 137 }; 138 139 // Opens the first tab. 140 Tabs.prototype.openFirstTab = function() { 141 this.openTab(this.tabs[0]); 142 }; 143 144 // Opens the last tab. 145 Tabs.prototype.openLastTab = function() { 146 this.openTab(this.tabs[this.tabs.length - 1]); 147 }; 148 149 // Tab opening function goes here. 150 Tabs.prototype.openTab = function(tab, setFocus) { 151 152 var listitem = tab.parentElement; 153 var tabId = tab.getAttribute('id'); 154 var panelId = listitem.getAttribute("aria-controls"); 155 156 for( var i = 0; i < this.tabs.length; i++ ) { 157 var currentTab = this.tabs[i]; 158 159 if( currentTab.getAttribute('id') == tabId ) { 160 this.activateTab(currentTab, setFocus); 161 } else { 162 this.deActivateTab(currentTab); 163 } 164 } 165 166 for( var i = 0; i < this.panels.length; i++ ) { 167 var panel = this.panels[i]; 168 169 if( panel.getAttribute('id') == panelId ) { 170 this.activatePanel(panel); 171 } else { 172 this.deActivatePanel(panel); 173 } 174 } 175 176 }; 177 178 // Activates the tab. 179 Tabs.prototype.activateTab = function(tab, setFocus) { 180 var needFocus = ( setFocus !== undefined ) ? setFocus : true; 181 var listitem = tab.parentElement; 182 183 listitem.setAttribute('aria-selected', 'true'); 184 listitem.setAttribute('aria-expanded', 'true'); 185 listitem.setAttribute('tabindex', '0'); 186 listitem.classList.add('th-ui-state-active'); 187 tab.setAttribute('tabindex', '-1'); 188 189 if ( needFocus ) { 190 tab.focus(); 191 } 192 } 193 194 // Deactivates the tab. 195 Tabs.prototype.deActivateTab = function(tab) { 196 var listitem = tab.parentElement; 197 198 listitem.setAttribute('aria-selected', 'false'); 199 listitem.setAttribute('aria-expanded', 'false'); 200 listitem.setAttribute('tabindex', '-1'); 201 listitem.classList.remove('th-ui-state-active'); 202 tab.setAttribute('tabindex', '-1'); 203 } 204 205 // Activate the panel. 206 Tabs.prototype.activatePanel = function(panel) { 207 panel.style.display = 'block'; 208 panel.setAttribute('aria-hidden', 'false'); 209 } 210 211 // Deactivate the panel. 212 Tabs.prototype.deActivatePanel = function(panel) { 213 panel.style.display = 'none'; 214 panel.setAttribute('aria-hidden', 'true'); 215 } 216 217 // Traverse through the DOM and create Tabs instances for each tab widget. 218 function init(elements) { 219 var nodes = document.querySelectorAll(elements); 220 if ( nodes == null ) { 221 return; 222 } 223 for( var i = 0; i < nodes.length; i++ ) { 224 var node = nodes[i]; 225 var tabs = new Tabs(node); 226 } 227 } 228 229 init(".hm-featured-tabs"); 230 231})();
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.