2
0

013-bootstrap-tabcollapse.js 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. !function ($) {
  2. "use strict";
  3. // TABCOLLAPSE CLASS DEFINITION
  4. // ======================
  5. var TabCollapse = function (el, options) {
  6. this.options = options;
  7. this.$tabs = $(el);
  8. this._accordionVisible = false; //content is attached to tabs at first
  9. this._initAccordion();
  10. this._checkStateOnResize();
  11. // checkState() has gone to setTimeout for making it possible to attach listeners to
  12. // shown-accordion.bs.tabcollapse event on page load.
  13. // See https://github.com/flatlogic/bootstrap-tabcollapse/issues/23
  14. var that = this;
  15. setTimeout(function() {
  16. that.checkState();
  17. }, 0);
  18. };
  19. TabCollapse.DEFAULTS = {
  20. accordionClass: 'visible-xs',
  21. tabsClass: 'hidden-xs',
  22. accordionTemplate: function(heading, groupId, parentId, active) {
  23. return '<div class="panel panel-default">' +
  24. ' <div class="panel-heading">' +
  25. ' <h4 class="panel-title">' +
  26. ' </h4>' +
  27. ' </div>' +
  28. ' <div id="' + groupId + '" class="panel-collapse collapse ' + (active ? 'in' : '') + '">' +
  29. ' <div class="panel-body js-tabcollapse-panel-body">' +
  30. ' </div>' +
  31. ' </div>' +
  32. '</div>'
  33. }
  34. };
  35. TabCollapse.prototype.checkState = function(){
  36. if (this.$tabs.is(':visible') && this._accordionVisible){
  37. this.showTabs();
  38. this._accordionVisible = false;
  39. } else if (this.$accordion.is(':visible') && !this._accordionVisible){
  40. this.showAccordion();
  41. this._accordionVisible = true;
  42. }
  43. };
  44. TabCollapse.prototype.showTabs = function(){
  45. var view = this;
  46. this.$tabs.trigger($.Event('show-tabs.bs.tabcollapse'));
  47. var $panelHeadings = this.$accordion.find('.js-tabcollapse-panel-heading').detach();
  48. $panelHeadings.each(function() {
  49. var $panelHeading = $(this),
  50. $parentLi = $panelHeading.data('bs.tabcollapse.parentLi');
  51. var $oldHeading = view._panelHeadingToTabHeading($panelHeading);
  52. $parentLi.removeClass('active');
  53. if ($parentLi.parent().hasClass('dropdown-menu') && !$parentLi.siblings('li').hasClass('active')) {
  54. $parentLi.parent().parent().removeClass('active');
  55. }
  56. if (!$oldHeading.hasClass('collapsed')) {
  57. $parentLi.addClass('active');
  58. $('.tab-pane').removeClass('active');
  59. $($panelHeading.attr('href')).addClass('active');
  60. if ($parentLi.parent().hasClass('dropdown-menu')) {
  61. $parentLi.parent().parent().addClass('active');
  62. }
  63. } else {
  64. $oldHeading.removeClass('collapsed');
  65. }
  66. $parentLi.append($panelHeading);
  67. });
  68. if (!$('li').hasClass('active')) {
  69. $('li').first().addClass('active')
  70. }
  71. var $panelBodies = this.$accordion.find('.js-tabcollapse-panel-body');
  72. $panelBodies.each(function(){
  73. var $panelBody = $(this),
  74. $tabPane = $panelBody.data('bs.tabcollapse.tabpane');
  75. $tabPane.append($panelBody.contents().detach());
  76. });
  77. this.$accordion.html('');
  78. if(this.options.updateLinks) {
  79. var $tabContents = this.getTabContentElement();
  80. $tabContents.find('[data-toggle-was="tab"], [data-toggle-was="pill"]').each(function() {
  81. var $el = $(this);
  82. var href = $el.attr('href').replace(/-collapse$/g, '');
  83. $el.attr({
  84. 'data-toggle': $el.attr('data-toggle-was'),
  85. 'data-toggle-was': '',
  86. 'data-parent': '',
  87. href: href
  88. });
  89. });
  90. }
  91. this.$tabs.trigger($.Event('shown-tabs.bs.tabcollapse'));
  92. };
  93. TabCollapse.prototype.getTabContentElement = function(){
  94. var $tabContents = $(this.options.tabContentSelector);
  95. if($tabContents.length === 0) {
  96. $tabContents = this.$tabs.siblings('.tab-content');
  97. }
  98. return $tabContents;
  99. };
  100. TabCollapse.prototype.showAccordion = function(){
  101. this.$tabs.trigger($.Event('show-accordion.bs.tabcollapse'));
  102. var $headings = this.$tabs.find('li:not(.dropdown) [data-toggle="tab"], li:not(.dropdown) [data-toggle="pill"]'),
  103. view = this;
  104. $headings.each(function(){
  105. var $heading = $(this),
  106. $parentLi = $heading.parent();
  107. $heading.data('bs.tabcollapse.parentLi', $parentLi);
  108. view.$accordion.append(view._createAccordionGroup(view.$accordion.attr('id'), $heading.detach()));
  109. });
  110. if(this.options.updateLinks) {
  111. var parentId = this.$accordion.attr('id');
  112. var $selector = this.$accordion.find('.js-tabcollapse-panel-body');
  113. $selector.find('[data-toggle="tab"], [data-toggle="pill"]').each(function() {
  114. var $el = $(this);
  115. var href = $el.attr('href') + '-collapse';
  116. $el.attr({
  117. 'data-toggle-was': $el.attr('data-toggle'),
  118. 'data-toggle': 'collapse',
  119. 'data-parent': '#' + parentId,
  120. href: href
  121. });
  122. });
  123. }
  124. this.$tabs.trigger($.Event('shown-accordion.bs.tabcollapse'));
  125. };
  126. TabCollapse.prototype._panelHeadingToTabHeading = function($heading) {
  127. var href = $heading.attr('href').replace(/-collapse$/g, '');
  128. $heading.attr({
  129. 'data-toggle': 'tab',
  130. 'href': href,
  131. 'data-parent': ''
  132. });
  133. return $heading;
  134. };
  135. TabCollapse.prototype._tabHeadingToPanelHeading = function($heading, groupId, parentId, active) {
  136. $heading.addClass('js-tabcollapse-panel-heading ' + (active ? '' : 'collapsed'));
  137. $heading.attr({
  138. 'data-toggle': 'collapse',
  139. 'data-parent': '#' + parentId,
  140. 'href': '#' + groupId
  141. });
  142. return $heading;
  143. };
  144. TabCollapse.prototype._checkStateOnResize = function(){
  145. var view = this;
  146. $(window).resize(function(){
  147. clearTimeout(view._resizeTimeout);
  148. view._resizeTimeout = setTimeout(function(){
  149. view.checkState();
  150. }, 100);
  151. });
  152. };
  153. TabCollapse.prototype._initAccordion = function(){
  154. var randomString = function() {
  155. var result = "",
  156. possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
  157. for( var i=0; i < 5; i++ ) {
  158. result += possible.charAt(Math.floor(Math.random() * possible.length));
  159. }
  160. return result;
  161. };
  162. var srcId = this.$tabs.attr('id'),
  163. accordionId = (srcId ? srcId : randomString()) + '-accordion';
  164. this.$accordion = $('<div class="panel-group ' + this.options.accordionClass + '" id="' + accordionId +'"></div>');
  165. this.$tabs.after(this.$accordion);
  166. this.$tabs.addClass(this.options.tabsClass);
  167. this.getTabContentElement().addClass(this.options.tabsClass);
  168. };
  169. TabCollapse.prototype._createAccordionGroup = function(parentId, $heading){
  170. var tabSelector = $heading.attr('data-target'),
  171. active = $heading.data('bs.tabcollapse.parentLi').is('.active');
  172. if (!tabSelector) {
  173. tabSelector = $heading.attr('href');
  174. tabSelector = tabSelector && tabSelector.replace(/.*(?=#[^\s]*$)/, ''); //strip for ie7
  175. }
  176. var $tabPane = $(tabSelector),
  177. groupId = $tabPane.attr('id') + '-collapse',
  178. $panel = $(this.options.accordionTemplate($heading, groupId, parentId, active));
  179. $panel.find('.panel-heading > .panel-title').append(this._tabHeadingToPanelHeading($heading, groupId, parentId, active));
  180. $panel.find('.panel-body').append($tabPane.contents().detach())
  181. .data('bs.tabcollapse.tabpane', $tabPane);
  182. return $panel;
  183. };
  184. // TABCOLLAPSE PLUGIN DEFINITION
  185. // =======================
  186. $.fn.tabCollapse = function (option) {
  187. return this.each(function () {
  188. var $this = $(this);
  189. var data = $this.data('bs.tabcollapse');
  190. var options = $.extend({}, TabCollapse.DEFAULTS, $this.data(), typeof option === 'object' && option);
  191. if (!data) $this.data('bs.tabcollapse', new TabCollapse(this, options));
  192. });
  193. };
  194. $.fn.tabCollapse.Constructor = TabCollapse;
  195. }(window.jQuery);