foundation.tab.js 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. /*jslint unparam: true, browser: true, indent: 2 */
  2. ;(function ($, window, document, undefined) {
  3. 'use strict';
  4. Foundation.libs.tab = {
  5. name : 'tab',
  6. version : '5.2.2',
  7. settings : {
  8. active_class: 'active',
  9. callback : function () {},
  10. deep_linking: false,
  11. scroll_to_content: true,
  12. is_hover: false
  13. },
  14. default_tab_hashes: [],
  15. init : function (scope, method, options) {
  16. var self = this,
  17. S = this.S;
  18. this.bindings(method, options);
  19. this.handle_location_hash_change();
  20. // Store the default active tabs which will be referenced when the
  21. // location hash is absent, as in the case of navigating the tabs and
  22. // returning to the first viewing via the browser Back button.
  23. S('[' + this.attr_name() + '] > dd.active > a', this.scope).each(function () {
  24. self.default_tab_hashes.push(this.hash);
  25. });
  26. },
  27. events : function () {
  28. var self = this,
  29. S = this.S;
  30. S(this.scope)
  31. .off('.tab')
  32. // Click event: tab title
  33. .on('click.fndtn.tab', '[' + this.attr_name() + '] > dd > a', function (e) {
  34. var settings = S(this).closest('[' + self.attr_name() +']').data(self.attr_name(true) + '-init');
  35. if (!settings.is_hover || Modernizr.touch) {
  36. e.preventDefault();
  37. e.stopPropagation();
  38. self.toggle_active_tab(S(this).parent());
  39. }
  40. })
  41. // Hover event: tab title
  42. .on('mouseenter.fndtn.tab', '[' + this.attr_name() + '] > dd > a', function (e) {
  43. var settings = S(this).closest('[' + self.attr_name() +']').data(self.attr_name(true) + '-init');
  44. if (settings.is_hover) self.toggle_active_tab(S(this).parent());
  45. });
  46. // Location hash change event
  47. S(window).on('hashchange.fndtn.tab', function (e) {
  48. e.preventDefault();
  49. self.handle_location_hash_change();
  50. });
  51. },
  52. handle_location_hash_change : function () {
  53. var self = this,
  54. S = this.S;
  55. S('[' + this.attr_name() + ']', this.scope).each(function () {
  56. var settings = S(this).data(self.attr_name(true) + '-init');
  57. if (settings.deep_linking) {
  58. // Match the location hash to a label
  59. var hash = self.scope.location.hash;
  60. if (hash != '') {
  61. // Check whether the location hash references a tab content div or
  62. // another element on the page (inside or outside the tab content div)
  63. var hash_element = S(hash);
  64. if (hash_element.hasClass('content') && hash_element.parent().hasClass('tab-content')) {
  65. // Tab content div
  66. self.toggle_active_tab($('[' + self.attr_name() + '] > dd > a[href=' + hash + ']').parent());
  67. } else {
  68. // Not the tab content div. If inside the tab content, find the
  69. // containing tab and toggle it as active.
  70. var hash_tab_container_id = hash_element.closest('.content').attr('id');
  71. if (hash_tab_container_id != undefined) {
  72. self.toggle_active_tab($('[' + self.attr_name() + '] > dd > a[href=#' + hash_tab_container_id + ']').parent(), hash);
  73. }
  74. }
  75. } else {
  76. // Reference the default tab hashes which were initialized in the init function
  77. for (var ind in self.default_tab_hashes) {
  78. self.toggle_active_tab($('[' + self.attr_name() + '] > dd > a[href=' + self.default_tab_hashes[ind] + ']').parent());
  79. }
  80. }
  81. }
  82. });
  83. },
  84. toggle_active_tab: function (tab, location_hash) {
  85. var S = this.S,
  86. tabs = tab.closest('[' + this.attr_name() + ']'),
  87. anchor = tab.children('a').first(),
  88. target_hash = '#' + anchor.attr('href').split('#')[1],
  89. target = S(target_hash),
  90. siblings = tab.siblings(),
  91. settings = tabs.data(this.attr_name(true) + '-init');
  92. // allow usage of data-tab-content attribute instead of href
  93. if (S(this).data(this.data_attr('tab-content'))) {
  94. target_hash = '#' + S(this).data(this.data_attr('tab-content')).split('#')[1];
  95. target = S(target_hash);
  96. }
  97. if (settings.deep_linking) {
  98. // Get the scroll Y position prior to moving to the hash ID
  99. var cur_ypos = $('body,html').scrollTop();
  100. // Update the location hash to preserve browser history
  101. // Note that the hash does not need to correspond to the
  102. // tab content ID anchor; it can be an ID inside or outside of the tab
  103. // content div.
  104. if (location_hash != undefined) {
  105. window.location.hash = location_hash;
  106. } else {
  107. window.location.hash = target_hash;
  108. }
  109. if (settings.scroll_to_content) {
  110. // If the user is requesting the content of a tab, then scroll to the
  111. // top of the title area; otherwise, scroll to the element within
  112. // the content area as defined by the hash value.
  113. if (location_hash == undefined || location_hash == target_hash) {
  114. tab.parent()[0].scrollIntoView();
  115. } else {
  116. S(target_hash)[0].scrollIntoView();
  117. }
  118. } else {
  119. // Adjust the scrollbar to the Y position prior to setting the hash
  120. // Only do this for the tab content anchor, otherwise there will be
  121. // conflicts with in-tab anchor links nested in the tab-content div
  122. if (location_hash == undefined || location_hash == target_hash) {
  123. $('body,html').scrollTop(cur_ypos);
  124. }
  125. }
  126. }
  127. // WARNING: The activation and deactivation of the tab content must
  128. // occur after the deep linking in order to properly refresh the browser
  129. // window (notably in Chrome).
  130. tab.addClass(settings.active_class).triggerHandler('opened');
  131. siblings.removeClass(settings.active_class);
  132. target.siblings().removeClass(settings.active_class).end().addClass(settings.active_class);
  133. settings.callback(tab);
  134. target.triggerHandler('toggled', [tab]);
  135. tabs.triggerHandler('toggled', [target]);
  136. },
  137. data_attr: function (str) {
  138. if (this.namespace.length > 0) {
  139. return this.namespace + '-' + str;
  140. }
  141. return str;
  142. },
  143. off : function () {},
  144. reflow : function () {}
  145. };
  146. }(jQuery, this, this.document));