123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247 |
- ;(function ($, window, document, undefined) {
- 'use strict';
- Foundation.libs.tab = {
- name : 'tab',
- version : '5.5.3',
- 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;
- // 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);
- });
- this.bindings(method, options);
- this.handle_location_hash_change();
- },
- events : function () {
- var self = this,
- S = this.S;
- var usual_tab_behavior = function (e, target) {
- var settings = S(target).closest('[' + self.attr_name() + ']').data(self.attr_name(true) + '-init');
- if (!settings.is_hover || Modernizr.touch) {
- // if user did not pressed tab key, prevent default action
- var keyCode = e.keyCode || e.which;
- if (keyCode !== 9) {
- e.preventDefault();
- e.stopPropagation();
- }
- self.toggle_active_tab(S(target).parent());
-
- }
- };
- S(this.scope)
- .off('.tab')
- // Key event: focus/tab key
- .on('keydown.fndtn.tab', '[' + this.attr_name() + '] > * > a', function(e) {
- var keyCode = e.keyCode || e.which;
- // if user pressed tab key
- if (keyCode === 13 || keyCode === 32) { // enter or space
- var el = this;
- usual_tab_behavior(e, el);
- }
- })
- // Click event: tab title
- .on('click.fndtn.tab', '[' + this.attr_name() + '] > * > a', function(e) {
- var el = this;
- usual_tab_behavior(e, el);
- })
- // 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 self = this,
- S = self.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);
- },
- go_to_hash = function(hash) {
- // This function allows correct behaviour of the browser's back button when deep linking is enabled. Without it
- // the user would get continually redirected to the default hash.
- var default_hash = settings.scroll_to_content ? self.default_tab_hashes[0] : 'fndtn-' + self.default_tab_hashes[0].replace('#', '');
- if (hash !== default_hash || window.location.hash) {
- window.location.hash = hash;
- }
- };
- // allow usage of data-tab-content attribute instead of href
- if (anchor.data('tab-content')) {
- target_hash = '#' + anchor.data('tab-content').split('#')[1];
- target = S(target_hash);
- }
- if (settings.deep_linking) {
- if (settings.scroll_to_content) {
- // retain current hash to scroll to content
- go_to_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) {
- go_to_hash('fndtn-' + location_hash.replace('#', ''));
- } else {
- go_to_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', [target]);
- tabs.triggerHandler('toggled', [tab]);
- 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));
|