1/** 2 * MGP Bootstrap Replacement 3 * Custom Tab and Accordion functionality without Bootstrap dependency 4 * With smooth animations 5 */ 6;(function($) { 7 'use strict'; 8 9 // Animation duration in milliseconds 10 var TRANSITION_DURATION = 300; 11 12 // Tab functionality with smooth animation 13 function initTabs() { 14 // Handle tab clicks for both old Bootstrap and new mgp- classes 15 $(document).on('click', '.nav-link, .mgp-nav-link, [data-mgbs-toggle="tab"], [data-toggle="tab"]', function(e) { 16 e.preventDefault(); 17 18 var $this = $(this); 19 var target = $this.data('mgbs-target') || $this.data('target') || $this.attr('href'); 20 21 if (!target || target === '#') return; 22 23 var $target = $(target); 24 var $tabList = $this.closest('.nav, .mgp-nav, ul'); 25 var $tabContent = $target.closest('.tab-content, .mgp-tab-content'); 26 var $currentActive = $tabContent.find('.tab-pane.active, .tab-pane.mgp-active, .mgp-tab-pane.active, .mgp-tab-pane.mgp-active'); 27 28 // Don't do anything if clicking on already active tab 29 if ($this.hasClass('active') || $this.hasClass('mgp-active')) return; 30 31 // Remove active class from all nav links in this tab group 32 $tabList.find('.nav-link, .mgp-nav-link').removeClass('active mgp-active'); 33 34 // Add active class to clicked link 35 $this.addClass('active mgp-active'); 36 37 // Animate out current tab 38 if ($currentActive.length && $currentActive[0] !== $target[0]) { 39 $currentActive.removeClass('mgp-show show'); 40 41 // After fade out, switch tabs 42 setTimeout(function() { 43 $currentActive.removeClass('active mgp-active'); 44 45 // Show new tab 46 $target.addClass('active mgp-active'); 47 48 // Force reflow for animation 49 $target[0].offsetHeight; 50 51 // Fade in new tab 52 $target.addClass('mgp-show show'); 53 54 // Trigger custom event 55 $this.trigger('shown.mgp.tab', { 56 target: $target 57 }); 58 }, TRANSITION_DURATION); 59 } else { 60 // No current active, just show target 61 $target.addClass('active mgp-active'); 62 $target[0].offsetHeight; // Force reflow 63 $target.addClass('mgp-show show'); 64 } 65 }); 66 } 67 68 // Accordion/Collapse functionality with smooth animation 69 function initCollapse() { 70 // Handle collapse triggers - use event delegation with broader selector 71 $(document).on('click', '[data-mgbs-toggle="collapse"], [data-toggle="collapse"], .mgrc-title[data-mgbs-toggle="collapse"]', function(e) { 72 e.preventDefault(); 73 e.stopPropagation(); 74 75 var $this = $(this); 76 var target = $this.attr('data-mgbs-target') || $this.attr('data-target') || $this.attr('href'); 77 78 if (!target) return; 79 80 var $target = $(target); 81 82 // Check if target exists 83 if (!$target.length) return; 84 85 var parentSelector = $this.attr('data-mgbs-parent') || $this.attr('data-parent'); 86 var isExpanded = $this.attr('aria-expanded') === 'true'; 87 88 // If accordion mode (has parent), close other items with animation 89 if (parentSelector) { 90 var $parentEl = $(parentSelector); 91 if ($parentEl.length) { 92 var $otherCollapses = $parentEl.find('.collapse.show, .collapse.mgp-show, .mgp-collapse.show, .mgp-collapse.mgp-show').not($target); 93 94 $otherCollapses.each(function() { 95 var $collapse = $(this); 96 var collapseId = $collapse.attr('id'); 97 98 // Get current height 99 var currentHeight = $collapse.outerHeight(); 100 101 // Keep visible during animation 102 $collapse.css({ 103 'display': 'block', 104 'height': currentHeight + 'px', 105 'overflow': 'hidden' 106 }); 107 108 // Force reflow before adding transition 109 $collapse[0].offsetHeight; 110 111 // Add transition and animate to 0 112 $collapse.css({ 113 'transition': 'height ' + TRANSITION_DURATION + 'ms ease', 114 'height': '0px' 115 }); 116 117 // Update trigger 118 if (collapseId) {
119 $parentEl.find('[data-mgbs-target="#' + collapseId + '"], [data-target="#' + collapseId + '"]') 120 .addClass('collapsed mgp-collapsed') 121 .attr('aria-expanded', 'false'); 122 } 123 124 // After animation, hide and clean up 125 setTimeout(function() { 126 $collapse.removeClass('show mgp-show'); 127 $collapse.css({ 128 'height': '', 129 'overflow': '', 130 'transition': '', 131 'display': 'none' 132 }); 133 }, TRANSITION_DURATION); 134 }); 135 } 136 } 137 138 // Toggle current item with animation 139 if (isExpanded) { 140 // Collapse: animate height to 0 141 var currentHeight = $target.outerHeight(); 142 143 // Keep it visible during animation 144 $target.css({ 145 'display': 'block', 146 'height': currentHeight + 'px', 147 'overflow': 'hidden' 148 }); 149 150 // Force reflow before adding transition 151 $target[0].offsetHeight; 152 153 // Now add transition and animate to 0 154 $target.css({ 155 'transition': 'height ' + TRANSITION_DURATION + 'ms ease', 156 'height': '0px' 157 }); 158 159 $this.addClass('collapsed mgp-collapsed').attr('aria-expanded', 'false'); 160 161 // After animation completes, hide and clean up 162 setTimeout(function() { 163 $target.removeClass('show mgp-show'); 164 $target.css({ 165 'height': '', 166 'overflow': '', 167 'transition': '', 168 'display': 'none' 169 }); 170 $this.trigger('hidden.mgp.collapse', { target: $target }); 171 }, TRANSITION_DURATION); 172 } else { 173 // Expand: animate height from 0 to auto 174 // First, show the element to measure its height 175 $target.css({ 176 'display': 'block', 177 'height': '0px', 178 'overflow': 'hidden', 179 'transition': 'height ' + TRANSITION_DURATION + 'ms ease' 180 }); 181 182 // Get the full height 183 var fullHeight = $target[0].scrollHeight; 184 185 // Force reflow 186 $target[0].offsetHeight; 187 188 // Animate to full height 189 $target.css('height', fullHeight + 'px'); 190 191 $this.removeClass('collapsed mgp-collapsed').attr('aria-expanded', 'true'); 192 193 setTimeout(function() { 194 $target.addClass('show mgp-show'); 195 $target.css({ 196 'height': '', 197 'overflow': '', 198 'transition': '', 199 'display': '' 200 }); 201 $this.trigger('shown.mgp.collapse', { target: $target }); 202 }, TRANSITION_DURATION); 203 } 204 }); 205 } 206 207 // Initialize on document ready 208 $(document).ready(function() { 209 initTabs(); 210 initCollapse(); 211 212 // Make first tab active if none are active 213 $('.mpdtab-nav-wrap').each(function() { 214 var $navWrap = $(this); 215 var $links = $navWrap.find('.nav-link, .mgp-nav-link'); 216 217 if ($links.filter('.active, .mgp-active').length === 0) { 218 $links.first().addClass('active mgp-active'); 219 220 var firstTarget = $links.first().data('mgbs-target') || $links.first().attr('href'); 221 if (firstTarget && firstTarget !== '#') { 222 $(firstTarget).addClass('show active mgp-show mgp-active'); 223 } 224 } 225 }); 226 227 // Initialize accordion - show items marked as open 228 $('.mgp-collapse.mgp-show, .collapse.show').each(function() { 229 var $collapse = $(this); 230 $collapse.css('display', 'block'); 231 var id = $collapse.attr('id'); 232 233 if (id) {
234 $('[data-mgbs-target="#' + id + '"], [data-target="#' + id + '"]') 235 .removeClass('collapsed mgp-collapsed') 236 .attr('aria-expanded', 'true'); 237 } 238 }); 239 240 // Initialize collapsed items - hide them 241 $('.mgp-collapse:not(.mgp-show):not(.show), .collapse:not(.mgp-show):not(.show)').each(function() { 242 $(this).css('display', 'none'); 243 }); 244 }); 245 246 // Expose functions globally if needed 247 window.mgpTabs = { 248 init: initTabs, 249 show: function(tabId) { 250 $(tabId).tab('show'); 251 } 252 }; 253 254 window.mgpCollapse = { 255 init: initCollapse, 256 toggle: function(collapseId) { 257 var $target = $(collapseId); 258 $target.toggleClass('show mgp-show'); 259 } 260 }; 261 262})(jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.