| /*jslint unparam: true, browser: true, indent: 2 */ |
| ;(function ($, window, document, undefined) { |
| 'use strict'; |
| |
| Foundation.libs.tab = { |
| name : 'tab', |
| |
| version : '5.2.2', |
| |
| 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() + '] > dd.active > a', this.scope).each(function () { |
| self.default_tab_hashes.push(this.hash); |
| }); |
| }, |
| |
| events : function () { |
| var self = this, |
| S = this.S; |
| |
| S(this.scope) |
| .off('.tab') |
| // Click event: tab title |
| .on('click.fndtn.tab', '[' + this.attr_name() + '] > dd > a', 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()); |
| } |
| }) |
| // Hover event: tab title |
| .on('mouseenter.fndtn.tab', '[' + this.attr_name() + '] > dd > 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 = self.scope.location.hash; |
| 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('tab-content')) { |
| // Tab content div |
| self.toggle_active_tab($('[' + self.attr_name() + '] > dd > 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() + '] > dd > a[href=#' + hash_tab_container_id + ']').parent(), hash); |
| } |
| } |
| } else { |
| // Reference the default tab hashes which were initialized in the init function |
| for (var ind in self.default_tab_hashes) { |
| self.toggle_active_tab($('[' + self.attr_name() + '] > dd > 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() + ']'), |
| 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'); |
| |
| // 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) { |
| // Get the scroll Y position prior to moving to the hash ID |
| var cur_ypos = $('body,html').scrollTop(); |
| |
| // Update the location hash to preserve browser history |
| // Note that the hash does not need to correspond to the |
| // tab content ID anchor; it can be an ID inside or outside of the tab |
| // content div. |
| if (location_hash != undefined) { |
| window.location.hash = location_hash; |
| } else { |
| window.location.hash = target_hash; |
| } |
| |
| if (settings.scroll_to_content) { |
| // If the user is requesting the content of a tab, then scroll to the |
| // top of the title area; otherwise, scroll to the element within |
| // the content area as defined by the hash value. |
| if (location_hash == undefined || location_hash == target_hash) { |
| tab.parent()[0].scrollIntoView(); |
| } else { |
| S(target_hash)[0].scrollIntoView(); |
| } |
| } else { |
| // Adjust the scrollbar to the Y position prior to setting the hash |
| // Only do this for the tab content anchor, otherwise there will be |
| // conflicts with in-tab anchor links nested in the tab-content div |
| if (location_hash == undefined || location_hash == target_hash) { |
| $('body,html').scrollTop(cur_ypos); |
| } |
| } |
| } |
| |
| // 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). |
| tab.addClass(settings.active_class).triggerHandler('opened'); |
| siblings.removeClass(settings.active_class); |
| target.siblings().removeClass(settings.active_class).end().addClass(settings.active_class); |
| settings.callback(tab); |
| target.triggerHandler('toggled', [tab]); |
| tabs.triggerHandler('toggled', [target]); |
| }, |
| |
| data_attr: function (str) { |
| if (this.namespace.length > 0) { |
| return this.namespace + '-' + str; |
| } |
| |
| return str; |
| }, |
| |
| off : function () {}, |
| |
| reflow : function () {} |
| }; |
| }(jQuery, this, this.document)); |