; (function ($, window, document, undefined) { 'use strict'; Foundation.libs.tab = { name: 'tab', version: '5.5.0', settings: { active_class: 'active', callback: function () { }, deep_linking: false, scroll_to_content: true, is_hover: false }, default_tab_hashes: [], init: function (scope, method, options) { var self = this, S = this.S; this.bindings(method, options); this.handle_location_hash_change(); // Store the default active tabs which will be referenced when the // location hash is absent, as in the case of navigating the tabs and // returning to the first viewing via the browser Back button. S('[' + this.attr_name() + '] > .active > a', this.scope).each(function () { self.default_tab_hashes.push(this.hash); }); }, events: function () { var self = this, S = this.S; var usual_tab_behavior = function (e) { var settings = S(this).closest('[' + self.attr_name() + ']').data(self.attr_name(true) + '-init'); if (!settings.is_hover || Modernizr.touch) { e.preventDefault(); e.stopPropagation(); self.toggle_active_tab(S(this).parent()); } }; S(this.scope) .off('.tab') // Click event: tab title .on('focus.fndtn.tab', '[' + this.attr_name() + '] > * > a', usual_tab_behavior) .on('click.fndtn.tab', '[' + this.attr_name() + '] > * > a', usual_tab_behavior) // Hover event: tab title .on('mouseenter.fndtn.tab', '[' + this.attr_name() + '] > * > a', function (e) { var settings = S(this).closest('[' + self.attr_name() + ']').data(self.attr_name(true) + '-init'); if (settings.is_hover) self.toggle_active_tab(S(this).parent()); }); // Location hash change event S(window).on('hashchange.fndtn.tab', function (e) { e.preventDefault(); self.handle_location_hash_change(); }); }, handle_location_hash_change: function () { var self = this, S = this.S; S('[' + this.attr_name() + ']', this.scope).each(function () { var settings = S(this).data(self.attr_name(true) + '-init'); if (settings.deep_linking) { // Match the location hash to a label var hash; if (settings.scroll_to_content) { hash = self.scope.location.hash; } else { // prefix the hash to prevent anchor scrolling hash = self.scope.location.hash.replace('fndtn-', ''); } if (hash != '') { // Check whether the location hash references a tab content div or // another element on the page (inside or outside the tab content div) var hash_element = S(hash); if (hash_element.hasClass('content') && hash_element.parent().hasClass('tabs-content')) { // Tab content div self.toggle_active_tab($('[' + self.attr_name() + '] > * > a[href=' + hash + ']').parent()); } else { // Not the tab content div. If inside the tab content, find the // containing tab and toggle it as active. var hash_tab_container_id = hash_element.closest('.content').attr('id'); if (hash_tab_container_id != undefined) { self.toggle_active_tab($('[' + self.attr_name() + '] > * > a[href=#' + hash_tab_container_id + ']').parent(), hash); } } } else { // Reference the default tab hashes which were initialized in the init function for (var ind = 0; ind < self.default_tab_hashes.length; ind++) { self.toggle_active_tab($('[' + self.attr_name() + '] > * > a[href=' + self.default_tab_hashes[ind] + ']').parent()); } } } }); }, toggle_active_tab: function (tab, location_hash) { var S = this.S, tabs = tab.closest('[' + this.attr_name() + ']'), tab_link = tab.find('a'), anchor = tab.children('a').first(), target_hash = '#' + anchor.attr('href').split('#')[1], target = S(target_hash), siblings = tab.siblings(), settings = tabs.data(this.attr_name(true) + '-init'), interpret_keyup_action = function (e) { // Light modification of Heydon Pickering's Practical ARIA Examples: http://heydonworks.com/practical_aria_examples/js/a11y.js // define current, previous and next (possible) tabs var $original = $(this); var $prev = $(this).parents('li').prev().children('[role="tab"]'); var $next = $(this).parents('li').next().children('[role="tab"]'); var $target; // find the direction (prev or next) switch (e.keyCode) { case 37: $target = $prev; break; case 39: $target = $next; break; default: $target = false break; } if ($target.length) { $original.attr({ 'tabindex': '-1', 'aria-selected': null }); $target.attr({ 'tabindex': '0', 'aria-selected': true }).focus(); } // Hide panels $('[role="tabpanel"]') .attr('aria-hidden', 'true'); // Show panel which corresponds to target $('#' + $(document.activeElement).attr('href').substring(1)) .attr('aria-hidden', null); }; // allow usage of data-tab-content attribute instead of href if (S(this).data(this.data_attr('tab-content'))) { target_hash = '#' + S(this).data(this.data_attr('tab-content')).split('#')[1]; target = S(target_hash); } if (settings.deep_linking) { if (settings.scroll_to_content) { // retain current hash to scroll to content window.location.hash = location_hash || target_hash; if (location_hash == undefined || location_hash == target_hash) { tab.parent()[0].scrollIntoView(); } else { S(target_hash)[0].scrollIntoView(); } } else { // prefix the hashes so that the browser doesn't scroll down if (location_hash != undefined) { window.location.hash = 'fndtn-' + location_hash.replace('#', ''); } else { window.location.hash = 'fndtn-' + target_hash.replace('#', ''); } } } // WARNING: The activation and deactivation of the tab content must // occur after the deep linking in order to properly refresh the browser // window (notably in Chrome). // Clean up multiple attr instances to done once tab.addClass(settings.active_class).triggerHandler('opened'); tab_link.attr({'aria-selected': 'true', tabindex: 0}); siblings.removeClass(settings.active_class) siblings.find('a').attr({'aria-selected': 'false', tabindex: -1}); target.siblings().removeClass(settings.active_class).attr({'aria-hidden': 'true', tabindex: -1}); target.addClass(settings.active_class).attr('aria-hidden', 'false').removeAttr('tabindex'); settings.callback(tab); target.triggerHandler('toggled', [tab]); tabs.triggerHandler('toggled', [target]); tab_link.off('keydown').on('keydown', interpret_keyup_action); }, data_attr: function (str) { if (this.namespace.length > 0) { return this.namespace + '-' + str; } return str; }, off: function () { }, reflow: function () { } }; }(jQuery, window, window.document));