1( function () { 2 function readInt( root, attr, fallback ) { 3 var raw = root.getAttribute( attr ); 4 var n = parseInt( raw, 10 ); 5 return isNaN( n ) ? fallback : n; 6 } 7 8 function prefersReducedMotion() { 9 return ( 10 typeof window.matchMedia === 'function' && 11 window.matchMedia( '(prefers-reduced-motion: reduce)' ).matches 12 ); 13 } 14 15 function shuffle( list ) { 16 var a = list.slice(); 17 var i; 18 for ( i = a.length - 1; i > 0; i-- ) { 19 var j = Math.floor( Math.random() * ( i + 1 ) ); 20 var t = a[ i ]; 21 a[ i ] = a[ j ]; 22 a[ j ] = t; 23 } 24 return a; 25 } 26 27 function logoKey( logo ) { 28 return logo && logo.src ? String( logo.src ) : ''; 29 } 30 31 /** 32 * Preload every logo into the browser cache before the grid starts. 33 * iOS often skips lazy images that sit in a 3D/off-screen projection. 34 */ 35 function preloadLogos( list ) { 36 return Promise.all( 37 list.map( function ( logo ) { 38 return new Promise( function ( resolve ) { 39 var src = logoKey( logo ); 40 if ( ! src ) { 41 resolve(); 42 return; 43 } 44 var img = new Image(); 45 img.decoding = 'async'; 46 img.onload = function () { 47 resolve(); 48 }; 49 img.onerror = function () { 50 resolve(); 51 }; 52 img.src = src; 53 } ); 54 } ) 55 ); 56 } 57 58 /** 59 * Pick `count` logos avoiding srcs in excludeMap. 60 * Prefers global uniqueness; falls back only when the pool is too small. 61 */ 62 function pickLogos( logos, count, excludeMap ) { 63 excludeMap = excludeMap || {}; 64 var available = []; 65 var i; 66 for ( i = 0; i < logos.length; i++ ) { 67 var key = logoKey( logos[ i ] ); 68 if ( key && ! excludeMap[ key ] ) { 69 available.push( logos[ i ] ); 70 } 71 } 72 73 var picked = []; 74 var used = {}; 75 var pool = shuffle( available.length ? available : logos ); 76 77 function takeFrom( source ) { 78 var s; 79 for ( s = 0; s < source.length && picked.length < count; s++ ) { 80 var k = logoKey( source[ s ] ); 81 if ( ! k || used[ k ] ) { 82 continue; 83 } 84 picked.push( source[ s ] ); 85 used[ k ] = true; 86 } 87 } 88 89 takeFrom( pool ); 90 91 if ( picked.length < count ) { 92 takeFrom( shuffle( logos ) ); 93 } 94 95 while ( picked.length < count && logos.length ) { 96 picked.push( logos[ picked.length % logos.length ] ); 97 } 98 99 return picked; 100 } 101 102 function collectSrcMap( imgGrid, fromRow ) { 103 var map = {}; 104 var r; 105 var c; 106 for ( r = fromRow; r < imgGrid.length; r++ ) { 107 for ( c = 0; c < imgGrid[ r ].length; c++ ) { 108 var key = imgGrid[ r ][ c ].getAttribute( 'data-logo-src' ) || ''; 109 if ( key ) { 110 map[ key ] = true; 111 } 112 } 113 } 114 return map; 115 } 116 117 function assignLogo( img, logo ) { 118 var src = logoKey( logo ); 119 img.setAttribute( 'data-logo-src', src ); 120 if ( img.getAttribute( 'src' ) !== src ) { 121 img.src = src; 122 } 123 } 124 125 function destroyRoot( root ) { 126 if ( ! root ) { 127 return; 128 } 129 if ( root._wsftItStop ) { 130 root._wsftItStop(); 131 root._wsftItStop = null; 132 } 133 delete root.dataset.wsftItBound; 134 root.classList.remove( 'is-loading', 'is-ready' ); 135 var scroller = root.querySelector( '.wsft-integrations-teaser__scroller' ); 136 if ( scroller ) { 137 scroller.innerHTML = ''; 138 scroller.style.transform = ''; 139 } 140 } 141 142 function initRoot( root, options ) { 143 options = options || {}; 144 if ( ! root ) { 145 return; 146 } 147 if ( root.dataset.wsftItBound === '1' ) { 148 destroyRoot( root ); 149 } 150 root.dataset.wsftItBound = '1'; 151 root.classList.add( 'is-loading' ); 152 root.classList.remove( 'is-ready' ); 153 154 var scroller = root.querySelector( '.wsft-integrations-teaser__scroller' ); 155 var logosUrl = root.getAttribute( 'data-logos-url' ) || ''; 156 if ( ! scroller || ! logosUrl ) { 157 return; 158 } 159 160 var state = { 161 padding: readInt( root, 'data-padding', 8 ), 162 cellSize: readInt( root, 'data-cell-size', 140 ), 163 duration: readInt( root, 'data-duration', 3500 ), 164 rows: readInt( root, 'data-rows', 8 ), 165 cols: readInt( root, 'data-cols', 20 ), 166 }; 167 168 var logos = []; 169 var imgGrid = []; 170 var rafId = 0; 171 var startTime = 0; 172 var lastCycle = 0; 173 var reduced = ! options.forceMotion && prefersReducedMotion(); 174 175 function applyPadding() { 176 var pad = state.padding;
177 imgGrid.forEach( function ( row ) { 178 row.forEach( function ( img ) { 179 img.style.padding = pad + 'px'; 180 } ); 181 } ); 182 } 183 184 function applyCellBackground() { 185 scroller.style.backgroundSize = state.cellSize + 'px ' + state.cellSize + 'px'; 186 root.style.setProperty( '--wsft-it-cell', state.cellSize + 'px' ); 187 } 188 189 function buildGrid() { 190 scroller.innerHTML = ''; 191 imgGrid = []; 192 193 var CELL = state.cellSize; 194 var ROWS = state.rows; 195 var cols = state.cols; 196 var roadWidth = 3000; 197 var offsetX = ( roadWidth - cols * CELL ) / 2; 198 var laneX = []; 199 var i; 200 for ( i = 0; i < cols; i++ ) { 201 laneX.push( offsetX + i * CELL ); 202 } 203 var NEAR_ROW_TOP = 12 * CELL; 204 var batch = pickLogos( logos, ROWS * cols, {} ); 205 var idx = 0; 206 207 var r; 208 var c; 209 for ( r = 0; r < ROWS; r++ ) { 210 var row = []; 211 for ( c = 0; c < laneX.length; c++ ) { 212 var img = document.createElement( 'img' ); 213 img.style.position = 'absolute'; 214 img.style.left = laneX[ c ] + 'px'; 215 img.style.top = NEAR_ROW_TOP - ( ROWS - 1 - r ) * CELL + 'px'; 216 img.style.width = CELL + 'px'; 217 img.style.height = CELL + 'px'; 218 img.alt = ''; 219 img.decoding = 'async'; 220 img.loading = 'eager'; 221 assignLogo( img, batch[ idx++ ] || logos[ 0 ] ); 222 scroller.appendChild( img ); 223 row.push( img ); 224 } 225 imgGrid.push( row ); 226 } 227
228 applyCellBackground(); 229 applyPadding(); 230 scroller.style.transform = 'translateY(0px)'; 231 } 232 233 function shiftRows() { 234 var r; 235 var c; 236 for ( r = imgGrid.length - 1; r > 0; r-- ) { 237 for ( c = 0; c < imgGrid[ 0 ].length; c++ ) { 238 var from = imgGrid[ r - 1 ][ c ]; 239 assignLogo( imgGrid[ r ][ c ], { 240 src: from.getAttribute( 'data-logo-src' ) || from.src, 241 } ); 242 } 243 } 244 245 // New top row: avoid every logo still visible in rows 1..n-1. 246 var exclude = collectSrcMap( imgGrid, 1 ); 247 var batch = pickLogos( logos, imgGrid[ 0 ].length, exclude ); 248 for ( c = 0; c < imgGrid[ 0 ].length; c++ ) { 249 assignLogo( imgGrid[ 0 ][ c ], batch[ c ] || logos[ 0 ] ); 250 } 251 } 252 253 function tick( now ) { 254 var CELL = state.cellSize; 255 var DURATION = state.duration; 256 var elapsed = now - startTime; 257 var progress = ( elapsed % DURATION ) / DURATION; 258 var cycle = Math.floor( elapsed / DURATION ); 259 260 while ( lastCycle < cycle ) { 261 lastCycle++; 262 shiftRows(); 263 } 264 265 scroller.style.transform = 'translateY(' + progress * CELL + 'px)'; 266 rafId = window.requestAnimationFrame( tick ); 267 } 268 269 function start() { 270 if ( ! logos.length ) { 271 root.classList.remove( 'is-loading' ); 272 return; 273 } 274 buildGrid(); 275 root.classList.remove( 'is-loading' ); 276 root.classList.add( 'is-ready' ); 277 if ( reduced ) { 278 return; 279 } 280 startTime = performance.now(); 281 lastCycle = 0; 282 rafId = window.requestAnimationFrame( tick ); 283 } 284 285 function stop() { 286 if ( rafId ) { 287 window.cancelAnimationFrame( rafId ); 288 rafId = 0; 289 } 290 } 291 292 root._wsftItStop = stop; 293 294 fetch( logosUrl, { credentials: 'same-origin' } ) 295 .then( function ( res ) { 296 if ( ! res.ok ) { 297 throw new Error( 'logos fetch failed' ); 298 } 299 return res.json(); 300 } ) 301 .then( function ( data ) { 302 if ( root.dataset.wsftItBound !== '1' ) { 303 return null; 304 } 305 var list = data && Array.isArray( data.logos ) ? data.logos : []; 306 logos = list.filter( function ( item ) { 307 return item && typeof item.src === 'string' && item.src; 308 } ); 309 return preloadLogos( logos ); 310 } ) 311 .then( function () { 312 if ( root.dataset.wsftItBound !== '1' ) { 313 return; 314 } 315 start(); 316 } ) 317 .catch( function () { 318 root.classList.remove( 'is-loading' ); 319 } ); 320 } 321 322 function initAll( selector ) { 323 var nodes = document.querySelectorAll( selector || '[data-wsft-it]' ); 324 nodes.forEach( function ( root ) { 325 initRoot( root ); 326 } ); 327 } 328 329 window.wsftIntegrationsTeaser = { 330 initRoot: initRoot, 331 initAll: initAll, 332 destroy: destroyRoot, 333 }; 334 335 function shouldAutoInit() { 336 // Editor loads this script for optional preview; don't auto-start there. 337 if ( document.body && document.body.classList.contains( 'block-editor-page' ) ) { 338 return false; 339 } 340 if ( document.querySelector( '.editor-styles-wrapper, .block-editor-block-list__layout' ) ) { 341 // Inside the editor canvas iframe / UI â only init when preview opts in via index.js. 342 if ( window.wp && wp.data && wp.data.select( 'core/block-editor' ) ) { 343 return false; 344 } 345 } 346 return true; 347 } 348 349 function autoInit() { 350 if ( ! shouldAutoInit() ) { 351 return; 352 } 353 initAll(); 354 } 355 356 if ( document.readyState === 'loading' ) { 357 document.addEventListener( 'DOMContentLoaded', autoInit ); 358 } else { 359 autoInit(); 360 } 361} )();
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.