1// utility functions 2if(!Util) function Util () {}; 3 4Util.addClass = function(el, className) { 5 var classList = className.split(' '); 6 el.classList.add(classList[0]); 7 if (classList.length > 1) Util.addClass(el, classList.slice(1).join(' ')); 8}; 9 10Util.removeClass = function(el, className) { 11 var classList = className.split(' '); 12 el.classList.remove(classList[0]); 13 if (classList.length > 1) Util.removeClass(el, classList.slice(1).join(' ')); 14}; 15 16Util.toggleClass = function(el, className, bool) { 17 if(bool) Util.addClass(el, className); 18 else Util.removeClass(el, className); 19}; 20 21Util.setAttributes = function(el, attrs) { 22 for(var key in attrs) { 23 el.setAttribute(key, attrs[key]); 24 } 25}; 26 27Util.hasClass = function(el, className) { 28 return el.classList.contains(className); 29}; 30 31Util.getChildrenByClassName = function(el, className) { 32 var children = el.children, 33 childrenByClass = []; 34 for (var i = 0; i < children.length; i++) { 35 if (Util.hasClass(children[i], className)) childrenByClass.push(children[i]); 36 } 37 return childrenByClass; 38}; 39 40Util.getIndexInArray = function(array, el) { 41 return Array.prototype.indexOf.call(array, el); 42}; 43 44 45// File#: _1_tabs 46// Usage: codyhouse.co/license 47(function() { 48 var Tab = function(element) { 49 this.element = element; 50 this.tabList = this.element.getElementsByClassName('js-tabs__controls')[0]; 51 this.listItems = this.tabList.getElementsByTagName('li'); 52 this.triggers = this.tabList.getElementsByTagName('a'); 53 this.panelsList = this.element.getElementsByClassName('js-tabs__panels')[0]; 54 this.panels = Util.getChildrenByClassName(this.panelsList, 'js-tabs__panel'); 55 this.hideClass = this.element.getAttribute('data-hide-panel-class') ? this.element.getAttribute('data-hide-panel-class') : 'th8-hide'; 56 this.customShowClass = this.element.getAttribute('data-show-panel-class') ? this.element.getAttribute('data-show-panel-class') : false; 57 this.layout = this.element.getAttribute('data-tabs-layout') ? this.element.getAttribute('data-tabs-layout') : 'horizontal'; 58 // deep linking options 59 this.deepLinkOn = this.element.getAttribute('data-deep-link') == 'on'; 60 // init tabs 61 this.initTab(); 62 }; 63 64 Tab.prototype.initTab = function() { 65 //set initial aria attributes 66 this.tabList.setAttribute('role', 'tablist'); 67 Util.addClass(this.element, 'tabs--no-interaction'); 68 69 for( var i = 0; i < this.triggers.length; i++) { 70 var bool = (i == 0), 71 panelId = this.panels[i].getAttribute('id'); 72 this.listItems[i].setAttribute('role', 'presentation'); 73 Util.setAttributes(this.triggers[i], {'role': 'tab', 'aria-selected': bool, 'aria-controls': panelId, 'id': 'tab-'+panelId}); 74 Util.addClass(this.triggers[i], 'js-tabs__trigger'); 75 Util.setAttributes(this.panels[i], {'role': 'tabpanel', 'aria-labelledby': 'tab-'+panelId}); 76 Util.toggleClass(this.panels[i], this.hideClass, !bool); 77 if(bool && this.customShowClass) Util.addClass(this.panels[i], this.customShowClass); 78 79 if(!bool) this.triggers[i].setAttribute('tabindex', '-1'); 80 } 81 82 //listen for Tab events 83 this.initTabEvents(); 84 85 // check deep linking option 86 this.initDeepLink(); 87 }; 88 89 Tab.prototype.initTabEvents = function() { 90 var self = this; 91 //click on a new tab -> select content 92 this.tabList.addEventListener('click', function(event) { 93 if( event.target.closest('.js-tabs__trigger') ) self.triggerTab(event.target.closest('.js-tabs__trigger'), event); 94 }); 95 //arrow keys to navigate through tabs 96 this.tabList.addEventListener('keydown', function(event) { 97 ; 98 if( !event.target.closest('.js-tabs__trigger') ) return; 99 if( tabNavigateNext(event, self.layout) ) { 100 event.preventDefault(); 101 self.selectNewTab('next'); 102 } else if( tabNavigatePrev(event, self.layout) ) { 103 event.preventDefault(); 104 self.selectNewTab('prev'); 105 } 106 }); 107 }; 108 109 Tab.prototype.selectNewTab = function(direction) { 110 var selectedTab = this.tabList.querySelector('[aria-selected="true"]'), 111 index = Util.getIndexInArray(this.triggers, selectedTab); 112 index = (direction == 'next') ? index + 1 : index - 1; 113 //make sure index is in the correct interval 114 //-> from last element go to first using the right arrow, from first element go to last using the left arrow 115 if(index < 0) index = this.listItems.length - 1; 116 if(index >= this.listItems.length) index = 0; 117 this.triggerTab(this.triggers[index]); 118 this.triggers[index].focus(); 119 }; 120 121 Tab.prototype.triggerTab = function(tabTrigger, event) { 122 var self = this; 123 event && event.preventDefault(); 124 var index = Util.getIndexInArray(this.triggers, tabTrigger); 125 //no need to do anything if tab was already selected 126 if(this.triggers[index].getAttribute('aria-selected') == 'true') return; 127 128 Util.removeClass(this.element, 'tabs--no-interaction'); 129 130 for( var i = 0; i < this.triggers.length; i++) { 131 var bool = (i == index); 132 Util.toggleClass(this.panels[i], this.hideClass, !bool); 133 if(this.customShowClass) Util.toggleClass(this.panels[i], this.customShowClass, bool); 134 this.triggers[i].setAttribute('aria-selected', bool); 135 bool ? this.triggers[i].setAttribute('tabindex', '0') : this.triggers[i].setAttribute('tabindex', '-1'); 136 } 137 138 // update url if deepLink is on 139 if(this.deepLinkOn) { 140 history.replaceState(null, '', '#'+tabTrigger.getAttribute('aria-controls')); 141 } 142 }; 143 144 Tab.prototype.initDeepLink = function() { 145 if(!this.deepLinkOn) return; 146 var hash = window.location.hash.substr(1); 147 var self = this; 148 if(!hash || hash == '') return; 149 for(var i = 0; i < this.panels.length; i++) { 150 if(this.panels[i].getAttribute('id') == hash) { 151 this.triggerTab(this.triggers[i], false); 152 setTimeout(function(){self.panels[i].scrollIntoView(true);}); 153 break; 154 } 155 }; 156 }; 157 158 function tabNavigateNext(event, layout) { 159 if(layout == 'horizontal' && (event.keyCode && event.keyCode == 39 || event.key && event.key == 'ArrowRight')) {return true;} 160 else if(layout == 'vertical' && (event.keyCode && event.keyCode == 40 || event.key && event.key == 'ArrowDown')) {return true;} 161 else {return false;} 162 }; 163 164 function tabNavigatePrev(event, layout) { 165 if(layout == 'horizontal' && (event.keyCode && event.keyCode == 37 || event.key && event.key == 'ArrowLeft')) {return true;} 166 else if(layout == 'vertical' && (event.keyCode && event.keyCode == 38 || event.key && event.key == 'ArrowUp')) {return true;} 167 else {return false;} 168 }; 169 170 window.Tab = Tab; 171 172 //initialize the Tab objects 173 var tabs = document.getElementsByClassName('js-tabs'); 174 if( tabs.length > 0 ) { 175 for( var i = 0; i < tabs.length; i++) { 176 (function(i){new Tab(tabs[i]);})(i); 177 } 178 } 179}());
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.