1jQuery( function($) { 2 3 /** 4 * Ad slides resolve to either the ad or the fallback within a bounded 5 * window, then lock that choice for good. 6 * 7 * Earlier version: fallback shown immediately, ad crossfaded in whenever 8 * it arrived â which could be several seconds later, and read as content 9 * getting swapped out from under the visitor rather than a deliberate 10 * design. This trades that for a short (AD_RESOLVE_TIMEOUT) pause where 11 * neither is visible, in exchange for guaranteeing nothing ever gets 12 * replaced once shown. _page_banner.scss keeps both faded out 13 * (opacity, not display) during the pause so the slide still holds the 14 * fallback image's height â no layout jump either way it resolves. 15 * 16 * Watch, rather than race: theme.delay-scripts.php holds most 17 * third-party scripts back until first interaction or a 5s timeout, and 18 * on touch devices there is no mousemove to trigger that early â but the 19 * ad script itself is explicitly excluded from that delay so it can 20 * still resolve inside this window. A MutationObserver reacts the 21 * moment its content arrives, with a fast interval as a backstop for 22 * content that changes size without mutating (e.g. an <img> finishing 23 * decode). 24 * 25 * The ad is the priority, not speed: if the first slide is still 26 * deciding, the slider holds autoplay there rather than rotating away 27 * from (or resolving to the fallback in place of) an ad that just needs 28 * a bit more time â see the holdAutoplay logic below. AD_RESOLVE_TIMEOUT 29 * is a generous upper bound for genuinely slow connections, matching 30 * theme.delay-scripts.php's own 5s allowance elsewhere; a real ad load 31 * measured around ~1.2s, so this is headroom, not the expected case. 32 * watchForBlockedAdNetwork() below is the one thing allowed to cut this 33 * short â waiting out the full timeout is pointless when the ad network 34 * is confirmed blocked rather than just slow. 35 */ 36 var AD_RESOLVE_TIMEOUT = 5000; 37 38 var $adSliders = $('section.page-banner .slides').filter( function() { 39 return $(this).find('.slide.has-ad-fallback').length > 0; 40 }); 41 42 if ( $adSliders.length ) { 43 44 var resolvedSlides = new WeakSet(); 45 var timedSlides = new WeakSet(); 46 var adObserver; 47 48 /** 49 * Locks a slide to whichever outcome resolves first â ad content 50 * detected, or the bounded wait running out. One-way and idempotent: 51 * once a slide has resolved, nothing here touches it again, so a 52 * late-arriving ad after a fallback timeout is simply ignored rather 53 * than swapping the visible content. 54 */ 55 function resolveSlide( slide, outcome ) { 56 57 if ( resolvedSlides.has( slide ) ) { 58 return; 59 } 60 61 resolvedSlides.add( slide ); 62 slide.classList.add( 'resolved-' + outcome ); 63 64 if ( 'ad' === outcome ) { 65 slide.classList.add('ad-loaded'); // kept for anything else keyed to this class 66 } 67 68 /** 69 * Resolving changes the slide's height (whichever of the ad/ 70 * fallback loses leaves the flow), so slick has to remeasure â 71 * otherwise the track keeps the old height and leaves a gap 72 * under the banner. Goes through the existing debounced resize 73 * handler below. 74 */ 75 $( window ).trigger('resize'); 76 77 // Lets the slick-init code (a separate block, run later) resume 78 // autoplay once whichever slide it's holding on has settled. 79 $( slide ).trigger('adslide:resolved'); 80 } 81 82 /** 83 * Fast-fail: some browsers' built-in tracking prevention (confirmed 84 * on Microsoft Edge) let segmint.min.js itself load fine, then 85 * silently block its later calls to connect.segmint.net â the ones 86 * that actually decide and serve the ad. That failure never shows up 87 * as slowness we can measure; the script just never gets to inject 88 * anything, so every visitor it affects would otherwise sit out the 89 * full AD_RESOLVE_TIMEOUT for an ad that was never coming. 90 * 91 * Watches fetch, XHR, and plain <script>/<img> requests â it's not 92 * known which of these segmint uses for its own calls, and ad/beacon 93 * scripts commonly use any of the three â for an error targeting its 94 * domain, and resolves every still-pending ad slide to the fallback 95 * immediately rather than waiting. onBlocked is safe to call 96 * multiple times or after slides have already resolved; resolveSlide 97 * ignores anything already settled. 98 */ 99 function watchForBlockedAdNetwork( adHostPattern, onBlocked ) { 100 101 var flagged = false;
102 103 function flag() { 104 if ( flagged ) { return; } 105 flagged = true; 106 onBlocked(); 107 } 108 109 if ( window.fetch ) { 110 111 var origFetch = window.fetch; 112 113 window.fetch = function( input ) { 114 115 var url = ( 'string' === typeof input ) ? input : ( input && input.url ) || ''; 116 117 return origFetch.apply( this, arguments ).catch( function( err ) { 118 if ( adHostPattern.test( url ) ) { flag(); } 119 throw err; 120 }); 121 }; 122 } 123 124 var origOpen = XMLHttpRequest.prototype.open; 125 126 XMLHttpRequest.prototype.open = function( method, url ) { 127 if ( adHostPattern.test( url || '' ) ) { 128 this.addEventListener( 'error', flag ); 129 } 130 return origOpen.apply( this, arguments ); 131 }; 132 133 if ( window.MutationObserver ) { 134 135 new MutationObserver( function( mutations ) { 136 137 mutations.forEach( function( mutation ) { 138 139 Array.prototype.forEach.call( mutation.addedNodes || [], function( node ) { 140 141 if ( 1 !== node.nodeType ) { return; } 142 143 var els = ( 'SCRIPT' === node.tagName || 'IMG' === node.tagName ) ? 144 [ node ] : 145 ( node.querySelectorAll ? Array.prototype.slice.call( node.querySelectorAll('script[src], img[src]') ) : [] ); 146 147 els.forEach( function( el ) { 148 149 var src = el.src || el.getAttribute('src') || ''; 150 151 if ( adHostPattern.test( src ) ) { 152 el.addEventListener( 'error', flag ); 153 } 154 }); 155 }); 156 }); 157 158 }).observe( document.documentElement, { childList: true, subtree: true } ); 159 } 160 } 161 162 /** 163 * Re-run rather than resolved once, because two things arrive late 164 * and out of order: the ad script itself, and slick's clones of the 165 * slides. A clone taken before the ad landed carries an empty 166 * .slide-ad of its own and needs its own bounded wait â so this 167 * can't be a single global decision. 168 */ 169 function syncAdSlides() { 170 171 $('.slide.has-ad-fallback').each( function() { 172 173 var slide = this; 174 175 if ( resolvedSlides.has( slide ) ) { 176 return; 177 } 178 179 // Start this slide's bounded wait the first time it's seen. 180 if ( ! timedSlides.has( slide ) ) { 181 182 timedSlides.add( slide ); 183 184 setTimeout( function() { 185 resolveSlide( slide, 'fallback' ); 186 }, AD_RESOLVE_TIMEOUT ); 187 } 188 189 var ad = $( slide ).children('.slide-ad')[0]; 190 191 if ( ! ad ) { 192 return; 193 } 194 195 /** 196 * .slide-ad is stretched to fill the slide, so its own offsetHeight 197 * is always non-zero and tells us nothing. Measure what the ad 198 * injected instead â a container the script created but never 199 * filled has no child with real height. 200 */ 201 var rendered = Array.prototype.some.call( ad.children, function( el ) { 202 return el.offsetHeight > 0; 203 }); 204 205 if ( rendered ) { 206 resolveSlide( slide, 'ad' ); 207 } 208 }); 209 } 210 211 watchForBlockedAdNetwork( /segmint\.net/i, function() { 212 213 $('.slide.has-ad-fallback').each( function() { 214 resolveSlide( this, 'fallback' ); 215 }); 216 }); 217 218 syncAdSlides(); 219 220 if ( window.MutationObserver ) { 221 222 adObserver = new MutationObserver( syncAdSlides ); 223 224 $adSliders.each( function() { 225 adObserver.observe( this, { childList: true, subtree: true } ); 226 }); 227 } 228 229 // Backstop for content that changes size without mutating the DOM,
230 // e.g. an <img> inside the ad finishing decode. 231 var adBackstop = setInterval( syncAdSlides, 200 ); 232 233 // Every slide seen by now is resolved (ad detected, or its own 234 // timeout fired) well within this window; nothing left to watch for. 235 setTimeout( function() { 236 clearInterval( adBackstop ); 237 if ( adObserver ) { adObserver.disconnect(); } 238 }, AD_RESOLVE_TIMEOUT + 2000 ); 239 } 240 241 $('section.page-banner.type-slider').each( function() { 242 243 var pageSlider = $(this).find('.slides'); 244 var pageSlides = pageSlider.find('.slide'); 245 246 if ( pageSlides.length > 1 ) { 247 248 pageSlider.on( 'setPosition', function( slick ) { 249 250 // Check if screen width is above 768px (tablet size and above) 251 if (window.innerWidth > 768) { 252 253 if ( typeof pageSlider.resizerQueue !== 'undefined' ) { 254 clearTimeout( pageSlider.resizerQueue ); 255 } 256 257 pageSlider.resizerQueue = setTimeout( function() { 258 pageSlider.find('.slide').css( 'height', '' ); 259 var setHeight = pageSlider.find('.slick-track').height(); 260 pageSlides.height( setHeight ); 261 }, 200, pageSlider ); 262 } 263 }); 264 265 var settings = { 266 fade : ( pageSlider.data('animation') == 'fade' ? true : false ), 267 dots : Boolean( pageSlider.data('dots') ), 268 infinite : Boolean( pageSlider.data('infinite') ), 269 arrows : Boolean( pageSlider.data('arrows') ), 270 speed : parseInt( pageSlider.data('speed') ), 271 autoplay : Boolean( pageSlider.data('autoplay') ), 272 autoplaySpeed : parseInt( pageSlider.data('autoplay-speed') ), 273 pauseOnHover : parseInt( pageSlider.data('pause-on-hover') ), 274 adaptiveHeight : (window.innerWidth <= 768) 275 } 276 277 /** 278 * The intent ad takes priority over the rotation schedule: if the 279 * first slide is still deciding between the ad and its fallback, 280 * don't let autoplay carry the visitor away from it (or resolve 281 * it to the fallback out of impatience) â hold here and start 282 * autoplay only once that slide has settled, whichever way. 283 */ 284 var firstSlide = pageSlides.first(); 285 var holdAutoplay = settings.autoplay 286 && firstSlide.hasClass('has-ad-fallback') 287 && ! firstSlide.is('.resolved-ad, .resolved-fallback'); 288 289 if ( holdAutoplay ) { 290 settings.autoplay = false; 291 } 292 293 pageSlider.slick( settings ); 294 295 if ( holdAutoplay ) { 296 firstSlide.one( 'adslide:resolved', function() { 297 pageSlider.slick('slickPlay'); 298 }); 299 } 300 301 var resizeTimer; 302 $(window).on('resize orientationchange', function () { 303 clearTimeout(resizeTimer); 304 resizeTimer = setTimeout(function () { 305 var isMobile = window.innerWidth <= 768; 306 pageSlider.slick('slickSetOption', 'adaptiveHeight', isMobile, true); 307 pageSlider.slick('setPosition'); 308 }, 150); 309 }); 310 } 311 }); 312});
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.