1;(function ($, window, document, undefined) { 2 'use strict'; 3 4 Foundation.libs.tab = { 5 name : 'tab', 6 7 version : '5.5.2', 8 9 settings : { 10 active_class : 'active', 11 callback : function () {}, 12 deep_linking : false, 13 scroll_to_content : true, 14 is_hover : false 15 }, 16 17 default_tab_hashes : [], 18 19 init : function (scope, method, options) { 20 var self = this, 21 S = this.S; 22 23 // Store the default active tabs which will be referenced when the 24 // location hash is absent, as in the case of navigating the tabs and 25 // returning to the first viewing via the browser Back button. 26 S('[' + this.attr_name() + '] > .active > a', this.scope).each(function () { 27 self.default_tab_hashes.push(this.hash); 28 }); 29 30 // store the initial href, which is used to allow correct behaviour of the 31 // browser back button when deep linking is turned on. 32 self.entry_location = window.location.href; 33 34 this.bindings(method, options); 35 this.handle_location_hash_change(); 36 }, 37 38 events : function () { 39 var self = this, 40 S = this.S; 41 42 var usual_tab_behavior = function (e, target) { 43 var settings = S(target).closest('[' + self.attr_name() + ']').data(self.attr_name(true) + '-init'); 44 if (!settings.is_hover || Modernizr.touch) { 45 e.preventDefault(); 46 e.stopPropagation(); 47 self.toggle_active_tab(S(target).parent()); 48 } 49 }; 50 51 S(this.scope) 52 .off('.tab') 53 // Key event: focus/tab key 54 .on('keydown.fndtn.tab', '[' + this.attr_name() + '] > * > a', function(e) { 55 var el = this; 56 var keyCode = e.keyCode || e.which; 57 // if user pressed tab key 58 if (keyCode == 9) { 59 e.preventDefault(); 60 // TODO: Change usual_tab_behavior into accessibility function? 61 usual_tab_behavior(e, el); 62 } 63 }) 64 // Click event: tab title 65 .on('click.fndtn.tab', '[' + this.attr_name() + '] > * > a', function(e) { 66 var el = this; 67 usual_tab_behavior(e, el); 68 }) 69 // Hover event: tab title 70 .on('mouseenter.fndtn.tab', '[' + this.attr_name() + '] > * > a', function (e) { 71 var settings = S(this).closest('[' + self.attr_name() + ']').data(self.attr_name(true) + '-init'); 72 if (settings.is_hover) { 73 self.toggle_active_tab(S(this).parent()); 74 } 75 }); 76 77 // Location hash change event 78 S(window).on('hashchange.fndtn.tab', function (e) { 79 e.preventDefault(); 80 self.handle_location_hash_change(); 81 }); 82 }, 83 84 handle_location_hash_change : function () { 85 86 var self = this, 87 S = this.S; 88 89 S('[' + this.attr_name() + ']', this.scope).each(function () { 90 var settings = S(this).data(self.attr_name(true) + '-init'); 91 if (settings.deep_linking) { 92 // Match the location hash to a label 93 var hash; 94 if (settings.scroll_to_content) { 95 hash = self.scope.location.hash; 96 } else { 97 // prefix the hash to prevent anchor scrolling 98 hash = self.scope.location.hash.replace('fndtn-', ''); 99 } 100 if (hash != '') { 101 // Check whether the location hash references a tab content div or 102 // another element on the page (inside or outside the tab content div) 103 var hash_element = S(hash); 104 if (hash_element.hasClass('content') && hash_element.parent().hasClass('tabs-content')) { 105 // Tab content div 106 self.toggle_active_tab($('[' + self.attr_name() + '] > * > a[href=' + hash + ']').parent()); 107 } else { 108 // Not the tab content div. If inside the tab content, find the 109 // containing tab and toggle it as active. 110 var hash_tab_container_id = hash_element.closest('.content').attr('id'); 111 if (hash_tab_container_id != undefined) { 112 self.toggle_active_tab($('[' + self.attr_name() + '] > * > a[href=#' + hash_tab_container_id + ']').parent(), hash); 113 } 114 } 115 } else { 116 // Reference the default tab hashes which were initialized in the init function 117 for (var ind = 0; ind < self.default_tab_hashes.length; ind++) { 118 self.toggle_active_tab($('[' + self.attr_name() + '] > * > a[href=' + self.default_tab_hashes[ind] + ']').parent()); 119 } 120 } 121 } 122 }); 123 }, 124 125 toggle_active_tab : function (tab, location_hash) { 126 var self = this, 127 S = self.S, 128 tabs = tab.closest('[' + this.attr_name() + ']'), 129 tab_link = tab.find('a'), 130 anchor = tab.children('a').first(), 131 target_hash = '#' + anchor.attr('href').split('#')[1], 132 target = S(target_hash), 133 siblings = tab.siblings(), 134 settings = tabs.data(this.attr_name(true) + '-init'), 135 interpret_keyup_action = function (e) { 136 // Light modification of Heydon Pickering's Practical ARIA Examples: http://heydonworks.com/practical_aria_examples/js/a11y.js 137 138 // define current, previous and next (possible) tabs 139 140 var $original = $(this); 141 var $prev = $(this).parents('li').prev().children('[role="tab"]'); 142 var $next = $(this).parents('li').next().children('[role="tab"]'); 143 var $target; 144 145 // find the direction (prev or next) 146 147 switch (e.keyCode) { 148 case 37: 149 $target = $prev; 150 break; 151 case 39: 152 $target = $next; 153 break; 154 default: 155 $target = false 156 break; 157 } 158 159 if ($target.length) { 160 $original.attr({ 161 'tabindex' : '-1', 162 'aria-selected' : null 163 }); 164 $target.attr({ 165 'tabindex' : '0', 166 'aria-selected' : true 167 }).focus(); 168 } 169 170 // Hide panels 171 172 $('[role="tabpanel"]') 173 .attr('aria-hidden', 'true'); 174 175 // Show panel which corresponds to target 176 177 $('#' + $(document.activeElement).attr('href').substring(1)) 178 .attr('aria-hidden', null); 179 180 }, 181 go_to_hash = function(hash) { 182 // This function allows correct behaviour of the browser's back button when deep linking is enabled. Without it 183 // the user would get continually redirected to the default hash. 184 var is_entry_location = window.location.href === self.entry_location, 185 default_hash = settings.scroll_to_content ? self.default_tab_hashes[0] : is_entry_location ? window.location.hash :'fndtn-' + self.default_tab_hashes[0].replace('#', '') 186 187 if (!(is_entry_location && hash === default_hash)) { 188 window.location.hash = hash; 189 } 190 }; 191 192 // allow usage of data-tab-content attribute instead of href 193 if (anchor.data('tab-content')) { 194 target_hash = '#' + anchor.data('tab-content').split('#')[1]; 195 target = S(target_hash); 196 } 197 198 if (settings.deep_linking) { 199 200 if (settings.scroll_to_content) { 201 202 // retain current hash to scroll to content 203 go_to_hash(location_hash || target_hash); 204 205 if (location_hash == undefined || location_hash == target_hash) { 206 tab.parent()[0].scrollIntoView(); 207 } else { 208 S(target_hash)[0].scrollIntoView(); 209 } 210 } else { 211 // prefix the hashes so that the browser doesn't scroll down 212 if (location_hash != undefined) { 213 go_to_hash('fndtn-' + location_hash.replace('#', '')); 214 } else { 215 go_to_hash('fndtn-' + target_hash.replace('#', '')); 216 } 217 } 218 } 219 220 // WARNING: The activation and deactivation of the tab content must 221 // occur after the deep linking in order to properly refresh the browser 222 // window (notably in Chrome). 223 // Clean up multiple attr instances to done once 224 tab.addClass(settings.active_class).triggerHandler('opened'); 225 tab_link.attr({'aria-selected' : 'true', tabindex : 0}); 226 siblings.removeClass(settings.active_class) 227 siblings.find('a').attr({'aria-selected' : 'false', tabindex : -1}); 228 target.siblings().removeClass(settings.active_class).attr({'aria-hidden' : 'true', tabindex : -1}); 229 target.addClass(settings.active_class).attr('aria-hidden', 'false').removeAttr('tabindex'); 230 settings.callback(tab); 231 target.triggerHandler('toggled', [target]); 232 tabs.triggerHandler('toggled', [tab]); 233 234 tab_link.off('keydown').on('keydown', interpret_keyup_action ); 235 }, 236 237 data_attr : function (str) { 238 if (this.namespace.length > 0) { 239 return this.namespace + '-' + str; 240 } 241 242 return str; 243 }, 244 245 off : function () {}, 246 247 reflow : function () {} 248 }; 249}(jQuery, window, window.document));
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.