PageSourceSearch

https://wsform.com/wp-content/themes/ws-form/blocks/integrations-teaser/view.js?ver=1.0.654

js wsform.com collected 2026-10-02 14:31:44 UTC 8,800 bytes, 361 lines download raw bytes

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.