1(function ($) { 2 function getOwlInstance($carousel) { 3 try { 4 return $carousel && $carousel.data ? $carousel.data('owl.carousel') : null; 5 } catch (e) { 6 return null; 7 } 8 } 9 10 function ensureVideoSourceLoaded(videoEl) { 11 var $video = $(videoEl); 12 var $source = $video.find('source[data-src]'); 13 if ($source.length && !$source.attr('src')) { 14 // Lazy slide: promote data-src â src and trigger load 15 $source.attr('src', $source.attr('data-src')); 16 try { 17 videoEl.load(); 18 } catch (e) { 19 // ignore 20 } 21 } 22 // First slide already has src set server-side â nothing extra needed. 23 } 24 25 function preloadVideoInItem($item) { 26 if (!$item || !$item.length) return; 27 var videoEl = $item.find('video.banner-bg-video-el').first().get(0); 28 if (!videoEl) return; 29 30 ensureVideoSourceLoaded(videoEl); 31 try { 32 // Fully buffer adjacent slides (not just metadata) so the next video is 33 // ready to play the instant it becomes active â removes the frozen-poster 34 // "pause" at slide change. 35 videoEl.preload = 'auto'; 36 videoEl.muted = true; 37 videoEl.playsInline = true; 38 videoEl.loop = false; 39 if (videoEl.readyState < 2) { 40 try { videoEl.load(); } catch (e) { /* ignore */ } 41 } 42 } catch (e) { 43 // ignore 44 } 45 } 46 47 // Defer work until the page has loaded and the main thread is idle. Buffering 48 // slides the visitor cannot see must never compete with the LCP image for 49 // bandwidth, so neighbour preloading waits for this on the first pass. 50 function afterPageSettled(fn) { 51 function run() { 52 if (window.requestIdleCallback) { 53 window.requestIdleCallback(fn, { timeout: 3000 }); 54 } else { 55 setTimeout(fn, 1000); 56 } 57 } 58 if (document.readyState === 'complete') { 59 run(); 60 } else { 61 $(window).one('load', run); 62 } 63 } 64 65 function pauseAllVideos($scope) { 66 $scope.find('video.banner-bg-video-el').each(function () { 67 try { 68 this.pause(); 69 } catch (e) { 70 // ignore 71 } 72 73 try { 74 $(this).closest('.banner-bg-video').removeClass('is-playing'); 75 } catch (e) { 76 // ignore 77 } 78 }); 79 } 80 81 function stopAutoplay($carousel) { 82 var owl = getOwlInstance($carousel); 83 if (!owl) return; 84 try { 85 $carousel.trigger('stop.owl.autoplay'); 86 } catch (e) { 87 // ignore 88 } 89 } 90 91 function resumeAutoplay($carousel) { 92 var owl = getOwlInstance($carousel); 93 if (!owl) return; 94 if (!owl.settings || !owl.settings.autoplay) return; 95 96 var timeout = $carousel.data('defaultAutoplayTimeout'); 97 if (!timeout) { 98 timeout = owl.settings.autoplayTimeout || 7000; 99 $carousel.data('defaultAutoplayTimeout', timeout); 100 } 101 102 try { 103 $carousel.trigger('play.owl.autoplay', [timeout]); 104 } catch (e) { 105 // ignore 106 } 107 } 108 109 function bindEndedOnce(videoEl, $carousel) { 110 var $video = $(videoEl); 111 if ($video.data('endedBound')) return; 112 $video.data('endedBound', true); 113 114 videoEl.addEventListener( 115 'ended', 116 function () { 117 try { 118 if ($video.closest('.owl-item').hasClass('active')) { 119 $carousel.trigger('next.owl.carousel'); 120 } 121 } catch (e) { 122 // ignore 123 } 124 }, 125 false 126 ); 127 } 128 129 function restartAndPlay(videoEl) { 130 var started = false; 131 var $wrapper = null; 132 try { 133 $wrapper = $(videoEl).closest('.banner-bg-video'); 134 $wrapper.removeClass('is-playing'); 135 } catch (e) { 136 $wrapper = null; 137 } 138 139 try { 140 videoEl.muted = true; 141 videoEl.playsInline = true; 142 videoEl.loop = false; 143 // Encourage buffering while active. 144 videoEl.preload = 'auto'; 145 } catch (e) { 146 // ignore 147 } 148 149 var tryStart = function () { 150 if (started) return; 151 started = true; 152 153 try { 154 videoEl.currentTime = 0; 155 } catch (e) { 156 // ignore 157 } 158 159 try { 160 var promise = videoEl.play(); 161 if (promise && typeof promise.catch === 'function') { 162 promise.catch(function () { 163 // Autoplay might be blocked; ignore. 164 }); 165 } 166 } catch (e) { 167 // ignore 168 } 169 }; 170 171 try { 172 // Fade in only when we actually start rendering video frames. 173 videoEl.addEventListener( 174 'playing', 175 function () { 176 try { 177 if ($wrapper && $wrapper.length) $wrapper.addClass('is-playing'); 178 } catch (e) { 179 // ignore 180 } 181 }, 182 { once: true } 183 ); 184 } catch (e) { 185 // ignore 186 } 187 188 if (videoEl.readyState >= 1) {
189 tryStart(); 190 return; 191 } 192 193 try { 194 videoEl.addEventListener('loadedmetadata', tryStart, { once: true }); 195 videoEl.addEventListener('canplay', tryStart, { once: true }); 196 } catch (e) { 197 // ignore 198 } 199 } 200 201 function handleCarousel($carousel) { 202 var owl = getOwlInstance($carousel); 203 if (!owl) return; 204 205 // De-dupe duplicate owl events for the same logical slide. 206 var relIndex = null; 207 try { 208 relIndex = owl.relative(owl.current()); 209 } catch (e) { 210 relIndex = null; 211 } 212 if (relIndex !== null && $carousel.data('lastRelIndex') === relIndex) { 213 return; 214 } 215 $carousel.data('lastRelIndex', relIndex); 216 217 pauseAllVideos($carousel); 218 219 var $activeItem = $carousel.find('.owl-item.active').first(); 220 var $activeVideos = $activeItem.find('video.banner-bg-video-el'); 221 222 if (!$activeVideos.length) { 223 resumeAutoplay($carousel); 224 return; 225 } 226 227 // Video slide: stop Owl autoplay and advance on video ended. 228 stopAutoplay($carousel); 229 230 // Preload adjacent items for smoother next/prev (covers loop wrap-around). 231 try { 232 var currentAbs = owl.current(); 233 var $items = $carousel.find('.owl-item'); 234 235 // The active slide is about to play, so it is always warmed immediately. 236 preloadVideoInItem($items.eq(currentAbs)); 237 238 var preloadNeighbours = function () { 239 preloadVideoInItem($items.eq(currentAbs + 1)); 240 preloadVideoInItem($items.eq(currentAbs - 1)); 241 preloadVideoInItem($items.first()); 242 preloadVideoInItem($items.last()); 243 }; 244 245 // On the very first pass this runs during initial page load, where 246 // buffering up to four ~1MB videos starves the LCP image. Hold the 247 // neighbours until the page is idle; once warmed, later slide changes 248 // preload straight away so next/prev stays instant. 249 if ($carousel.data('bannerVideoWarmed')) { 250 preloadNeighbours(); 251 } else { 252 $carousel.data('bannerVideoWarmed', true); 253 afterPageSettled(preloadNeighbours); 254 } 255 } catch (e) { 256 // ignore 257 } 258 259 $activeVideos.each(function () { 260 try { 261 ensureVideoSourceLoaded(this); 262 bindEndedOnce(this, $carousel); 263 restartAndPlay(this); 264 } catch (e) { 265 // ignore 266 } 267 }); 268 } 269 270 $(function () { 271 $('.page-banner-slider, #home_banner_slider').each(function () { 272 var $carousel = $(this); 273 274 $carousel.on('initialized.owl.carousel translated.owl.carousel', function () { 275 setTimeout(function () { 276 handleCarousel($carousel); 277 }, 0); 278 }); 279 280 // In case Owl is already initialized. 281 setTimeout(function () { 282 handleCarousel($carousel); 283 }, 0); 284 }); 285 }); 286})(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.