1// Rotating top banner: Rotation, Fade, Pause-on-Interaction 2jQuery(function($){ 3 4 const BREAKPOINT = 900; 5 6 const $banner = $('#mms-top-banner'); 7 if(!$banner.length) return; 8 9 const rotationSpeed = parseInt($banner.data('rotation-speed'), 10) || 6000; 10 const pauseOnInteraction = parseInt($banner.data('pause-on-interaction'), 10) || 10000; 11 12 let autoTimer = null; 13 let resumeTimer = null; 14 15 // Mobile carousel state 16 let mobileItems = []; 17 let mobileIndex = 0; 18 let mobileBuilt = false; 19 20 const $slidesWrap = $banner.find('.mms-top-banner-slides'); 21 const $dotsWrap = $banner.find('.mms-top-banner-dots'); 22 23 function clearTimers(){ 24 if(autoTimer) clearInterval(autoTimer); 25 if(resumeTimer) clearTimeout(resumeTimer); 26 autoTimer = null; 27 resumeTimer = null; 28 } 29 30 function pauseAuto(){ 31 clearTimers(); 32 resumeTimer = setTimeout(startAuto, pauseOnInteraction); 33 } 34 35 function startAuto(){ 36 clearTimers(); 37 // only rotate if there is more than 1 item/slide 38 if (isMobileMode()) { 39 if (mobileItems.length <= 1) return; 40 autoTimer = setInterval(mobileNext, rotationSpeed); 41 } else { 42 // Desktop: rotate slides (existing .mms-top-banner-slide) 43 const $slides = $banner.find('.mms-top-banner-slide'); 44 if ($slides.length <= 1) return; 45 autoTimer = setInterval(desktopNext, rotationSpeed); 46 } 47 } 48 49 function isMobileMode(){ 50 return window.innerWidth < BREAKPOINT; 51 } 52 53 /* ---------------------------- 54 DESKTOP: keep your slide logic simple 55 (shows slide groups normally) 56 -----------------------------*/ 57 58 function desktopSlides(){ 59 return $banner.find('.mms-top-banner-slide'); 60 } 61 62 function desktopActiveIndex(){ 63 const $slides = desktopSlides(); 64 const idx = $slides.index($slides.filter('.is-active')); 65 return idx >= 0 ? idx : 0; 66 } 67 68 function desktopGoTo(idx){ 69 const $slides = desktopSlides(); 70 if(!$slides.length) return; 71 72 idx = (idx + $slides.length) % $slides.length; 73 74 $slides.removeClass('is-active').hide(); 75 const $next = $slides.eq(idx).addClass('is-active').show(); 76 77 // adjust height 78 $slidesWrap.stop(true).animate({ height: $next.outerHeight(true) }, 200); 79 80 // dots 81 updateDots(idx, $slides.length); 82 } 83 84 function desktopNext(){ 85 desktopGoTo(desktopActiveIndex() + 1); 86 } 87 88 function desktopPrev(){ 89 desktopGoTo(desktopActiveIndex() - 1); 90 } 91 92 /* ---------------------------- 93 MOBILE: build item-by-item carousel 94 -----------------------------*/ 95 96 function buildMobile(){ 97 // Only build once per entry into mobile mode 98 mobileBuilt = true; 99 mobileIndex = 0; 100 mobileItems = []; 101 102 // Pull ALL items from ALL slides 103 $banner.find('.mms-top-banner-slide .mms-top-banner-item').each(function(){ 104 mobileItems.push($(this).clone(true, true)); 105 }); 106 107 // If nothing, bail 108 if(!mobileItems.length) return; 109 110 // Create viewport + track 111 const $viewport = $('<div class="mms-top-banner-mobile-viewport"></div>'); 112 const $track = $('<div class="mms-top-banner-mobile-track"></div>'); 113 114 // Append items to track 115 mobileItems.forEach($it => $track.append($it)); 116 117 $viewport.append($track); 118 119 // Replace slides area with viewport (mobile only) 120 $slidesWrap.empty().append($viewport); 121 122 // Set initial height to first item 123 setMobileHeight(); 124 125 // Build dots: one per item 126 updateDots(mobileIndex, mobileItems.length); 127 128 // Reset position 129 $track.css({ top: 0 }); 130 } 131 132 function destroyMobile(){ 133 mobileBuilt = false; 134 mobileItems = []; 135 mobileIndex = 0; 136 137 // Restore original slides markup by reloading page section would be ideal, 138 // but easiest is to keep a cached copy. 139 } 140 141 // Cache original desktop markup so we can restore it when leaving mobile 142 const originalSlidesHTML = $slidesWrap.html(); 143 144 function enterMode(){ 145 clearTimers(); 146 147 if(isMobileMode()){ 148 if(!mobileBuilt){ 149 buildMobile(); 150 } 151 } else { 152 // restore desktop markup if needed 153 if(mobileBuilt){ 154 $slidesWrap.html(originalSlidesHTML); 155 // show first active slide (or default) 156 const $slides = desktopSlides(); 157 $slides.hide().removeClass('is-active'); 158 $slides.eq(0).show().addClass('is-active'); 159 $slidesWrap.css({ height: $slides.eq(0).outerHeight(true) }); 160 mobileBuilt = false;
161 } 162 updateDots(desktopActiveIndex(), desktopSlides().length); 163 } 164 165 startAuto(); 166 } 167 168 function mobileTrack(){ 169 return $banner.find('.mms-top-banner-mobile-track'); 170 } 171 172 function setMobileHeight(){ 173 const $track = mobileTrack(); 174 const $currentItem = $track.find('.mms-top-banner-item').eq(mobileIndex); 175 if(!$currentItem.length) return; 176 177 const h = $currentItem.outerHeight(true); 178 $slidesWrap.stop(true).animate({ height: h }, 200); 179 } 180 181 function mobileGoTo(idx){ 182 const $track = mobileTrack(); 183 const count = mobileItems.length; 184 if(!count) return; 185 186 idx = (idx + count) % count; 187 mobileIndex = idx; 188 189 // Compute offset to the target item 190 let offset = 0; 191 $track.find('.mms-top-banner-item').each(function(i){ 192 if(i < mobileIndex){ 193 offset += $(this).outerHeight(true); 194 } 195 }); 196 197 // Animate track upward 198 $track.stop(true).animate({ top: -offset }, 300); 199 200 setMobileHeight(); 201 updateDots(mobileIndex, count); 202 } 203 204 function mobileNext(){ 205 mobileGoTo(mobileIndex + 1); 206 } 207 208 function mobilePrev(){ 209 mobileGoTo(mobileIndex - 1); 210 } 211 212 /* ---------------------------- 213 DOTS (shared) 214 -----------------------------*/ 215 216 function updateDots(activeIdx, total){ 217 if(!$dotsWrap.length) return; 218 219 $dotsWrap.empty(); 220 if(total <= 1) return; 221 222 for(let i=0;i<total;i++){ 223 const cls = (i === activeIdx) ? 'mms-top-banner-dot is-active' : 'mms-top-banner-dot'; 224 $dotsWrap.append('<button type="button" class="'+cls+'" data-slide="'+i+'" aria-label="Go to item '+(i+1)+'"></button>'); 225 } 226 } 227 228 /* ---------------------------- 229 EVENTS 230 -----------------------------*/ 231 232 $banner.on('click', '.mms-top-banner-next', function(){ 233 if(isMobileMode()) mobileNext(); 234 else desktopNext(); 235 pauseAuto(); 236 }); 237 238 $banner.on('click', '.mms-top-banner-prev', function(){ 239 if(isMobileMode()) mobilePrev(); 240 else desktopPrev(); 241 pauseAuto(); 242 }); 243 244 $banner.on('click', '.mms-top-banner-dot', function(){ 245 const to = parseInt($(this).data('slide'), 10) || 0; 246 if(isMobileMode()) mobileGoTo(to); 247 else desktopGoTo(to); 248 pauseAuto(); 249 }); 250 251 // Resize: rebuild mode 252 let resizeTO; 253 $(window).on('resize', function(){ 254 clearTimeout(resizeTO); 255 resizeTO = setTimeout(enterMode, 200); 256 }); 257 258 // Start 259 enterMode(); 260 261});
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.