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