218 lines
		
	
	
		
			7.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			218 lines
		
	
	
		
			7.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
|   | ;(function ($, window, document, undefined) { | ||
|  |   'use strict'; | ||
|  | 
 | ||
|  |   Foundation.libs.tab = { | ||
|  |     name : 'tab', | ||
|  | 
 | ||
|  |     version : '5.4.7', | ||
|  | 
 | ||
|  |     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)); |