foundation.tab.js 6.3 KB

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