PageSourceSearch

https://megadynegroup.com/wp-content/plugins/ammweb-instance/blocks/grid/view.js?ver=1791294283

js megadynegroup.com collected 2026-10-08 01:43:07 UTC 17,500 bytes, 573 lines download raw bytes

1(function () {
2	'use strict';
3
4	function toPositiveInt(value, fallback) {
5		const parsed = parseInt(value, 10);
6		return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
7	}
8
9	function toPositiveFloat(value, fallback) {
10		const parsed = parseFloat(value);
11		return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
12	}
13
14	function clamp(value, min, max) {
15		return Math.max(min, Math.min(max, value));
16	}
17
18	function mod(value, size) {
19		return ((value % size) + size) % size;
20	}
21
22	function getSlidesPerView(carousel, totalSlides) {
23		const computed = window.getComputedStyle(carousel);
24		let slides = toPositiveInt(computed.getPropertyValue('--amm-grid-cols-mobile'), 1);
25
26		if (window.innerWidth >= 960) {
27			slides = toPositiveInt(computed.getPropertyValue('--amm-grid-cols-desktop'), slides);
28		} else if (window.innerWidth >= 600) {
29			slides = toPositiveInt(computed.getPropertyValue('--amm-grid-cols-tablet'), slides);
30		}
31
32		return clamp(slides, 1, totalSlides);
33	}
34
35	function createButton(className, label, iconName) {
36		const button = document.createElement('button');
37		const icon = document.createElement('span');
38
39		button.type = 'button';
40		button.className = className;
41		button.setAttribute('aria-label', label);
42		icon.className = 'material-icons';
43		icon.setAttribute('aria-hidden', 'true');
44		icon.setAttribute('data-no-auto-translation', '');
45		icon.textContent = iconName;
46		button.appendChild(icon);
47
48		return button;
49	}
50
51	document.addEventListener('DOMContentLoaded', function () {
52		const carousels = document.querySelectorAll('.wp-block-amm-grid.is-carousel-enabled');
53
54		carousels.forEach(function (carousel) {
55			if (carousel.hasAttribute('data-carousel-initialized')) {
56				return;
57			}
58			let inner = carousel.querySelector('.amm-grid__inner');
59			if (!inner) {
60				return;
61			}
62			carousel.setAttribute('data-carousel-initialized', 'true');
63
64			let viewport = inner.parentElement && inner.parentElement.classList.contains('amm-grid__viewport')
65				? inner.parentElement
66				: null;
67
68			// Older saved blocks won't have the viewport wrapper yet, so add it at runtime.
69			if (!viewport) {
70				viewport = document.createElement('div');
71				viewport.className = 'amm-grid__viewport';
72				carousel.insertBefore(viewport, inner);
73				viewport.appendChild(inner);
74			}
75
76			const realSlides = Array.prototype.slice.call(inner.children);
77			const totalSlides = realSlides.length;
78			if (totalSlides < 2) {
79				return;
80			}
81
82			realSlides.forEach(function (slide, index) {
83				slide.removeAttribute('data-carousel-clone');
84				slide.removeAttribute('aria-hidden');
85				slide.setAttribute('data-carousel-real-index', String(index));
86			});
87
88			const maxSelectors = clamp(toPositiveInt(carousel.dataset.carouselMaxSelectors, 5), 1, totalSlides);
89			const cycleTimeSeconds = toPositiveFloat(carousel.dataset.carouselCycleTime, 4);
90			const autoSlideEnabled = carousel.dataset.carouselAutoSlide === 'true';
91			const featureFocusEnabled = carousel.dataset.carouselFeatureFocus === 'true';
92			const showArrows = carousel.dataset.carouselShowArrows === 'true';
93			const showDots = carousel.dataset.carouselShowDots !== 'false';
94			const focusEdgeVisibility = 0.78;
95			const transitionStyle = 'transform 320ms ease';
96			const baseTrackGap = parseFloat(window.getComputedStyle(inner).getPropertyValue('column-gap') || window.getComputedStyle(inner).getPropertyValue('gap')) || 0;
97
98			let currentSlide = 0;
99			let slidesPerView = 1;
100			let cloneCount = 0;
101			let currentPhysicalIndex = 0;
102			let renderedSlidesPerView = 0;
103			let trackSlides = realSlides.slice();
104			let autoplayInterval = null;
105			let pendingRender = false;
106			let resizeRaf = null;
107			let transitionRestoreRaf = null;
108			let isTransitioning = false;
109			let isPointerInside = false;
110			let hasFocusWithin = false;
111			let mediaEngaged = false;
112
113			const nav = document.createElement('div');
114			nav.className = 'amm-grid-carousel__nav';
115			const prev = createButton('amm-grid-carousel__arrow amm-grid-carousel__arrow--prev', 'Previous slide', 'chevron_left');
116			const next = createButton('amm-grid-carousel__arrow amm-grid-carousel__arrow--next', 'Next slide', 'chevron_right');
117			nav.appendChild(prev);
118			nav.appendChild(next);
119
120			const indicators = document.createElement('div');
121			indicators.className = 'amm-grid-carousel__indicators';
122			indicators.setAttribute('role', 'tablist');
123
124			const indicatorsParent = carousel.querySelector('.amm-grid__content') || carousel;
125			carousel.appendChild(nav);
126			indicatorsParent.appendChild(indicators);
127
128			function isMeasurable() {
129				return inner.clientWidth > 0 && viewport.clientWidth > 0 && carousel.getClientRects().length > 0;
130			}
131
132			function setTransitionEnabled(enabled) {
133				inner.style.transition = enabled ? transitionStyle : 'none';
134			}
135
136			function clearTransitionRestore() {
137				if (!transitionRestoreRaf) {
138					return;
139				}
140				window.cancelAnimationFrame(transitionRestoreRaf);
141				transitionRestoreRaf = null;
142			}
143
144			function removeClones() {
145				const clones = inner.querySelectorAll('[data-carousel-clone="true"]');
146				clones.forEach(function (clone) {
147					clone.remove();
148				});
149			}
150
151			function createClone(realIndex) {
152				const clone = realSlides[realIndex].cloneNode(true);
153				clone.setAttribute('data-carousel-clone', 'true');
154				clone.setAttribute('aria-hidden', 'true');
155				clone.setAttribute('data-carousel-real-index', String(realIndex));
156				return clone;
157			}
158
159			function rebuildClones(nextSlidesPerView) {
160				removeClones();
161				cloneCount = Math.min(totalSlides, nextSlidesPerView + 1);
162
163				if (cloneCount > 0) {
164					const prependFragment = document.createDocumentFragment();
165					for (let index = totalSlides - cloneCount; index < totalSlides; index += 1) {
166						prependFragment.appendChild(createClone(index));
167					}
168					inner.insertBefore(prependFragment, inner.firstChild);
169
170					const appendFragment = document.createDocumentFragment();
171					for (let index = 0; index < cloneCount; index += 1) {
172						appendFragment.appendChild(createClone(index));
173					}
174					inner.appendChild(appendFragment);
175				}
176
177				trackSlides = Array.prototype.slice.call(inner.children);
178				renderedSlidesPerView = nextSlidesPerView;
179				currentPhysicalIndex = cloneCount + currentSlide;
180			}
181
182			function scheduleRender() {
183				if (resizeRaf) {
184					window.cancelAnimationFrame(resizeRaf);
185				}
186				resizeRaf = window.requestAnimationFrame(function () {
187					render();
188				});
189			}
190
191			function ensureVisibleRender() {
192				if (!pendingRender) {
193					return;
194				}
195				if (isMeasurable()) {
196					scheduleRender();
197					return;
198				}
199				window.setTimeout(ensureVisibleRender, 200);
200			}
201
202			function getIndicatorWindowStart() {
203				const visibleCount = Math.min(totalSlides, maxSelectors);
204				const half = Math.floor(visibleCount / 2);
205				const maxWindowStart = Math.max(0, totalSlides - visibleCount);
206				return clamp(currentSlide - half, 0, maxWindowStart);
207			}
208
209			function getFocusScale() {
210				if (!featureFocusEnabled || slidesPerView < 2) {
211					return 1;
212				}
213				return slidesPerView % 2 === 0 ? 1.06 : 1.08;
214			}
215
216			function updateSlideWidths() {
217				const baseGap = baseTrackGap;
218				const viewportWidth = viewport.clientWidth;
219				let gap = baseGap;
220				let width = (viewportWidth - gap * (slidesPerView - 1)) / slidesPerView;
221
222				if (featureFocusEnabled && slidesPerView >= 3) {
223					const centerCount = slidesPerView % 2 === 0 ? 2 : 1;
224					const edgeCount = Math.max(0, slidesPerView - centerCount);
225					const weightedSlots = centerCount + edgeCount * focusEdgeVisibility;
226					const gapCompensationFactor = (getFocusScale() - 1) / 2;
227					const denominator = weightedSlots + gapCompensationFactor * Math.max(0, slidesPerView - 1);
228					width = (viewportWidth - baseGap * (slidesPerView - 1)) / denominator;
229					gap = baseGap + gapCompensationFactor * width;
230				}
231				inner.style.gap = gap + 'px';
232
233				trackSlides.forEach(function (slide) {
234					slide.style.width = width + 'px';
235				});
236
237				return {
238					width: width,
239					gap: gap,
240					viewportWidth: viewportWidth,
241				};
242			}
243
244			function updateViewportHeight() {
245				let maxHeight = 0;
246				viewport.style.minHeight = '';
247
248				realSlides.forEach(function (slide) {
249					const height = slide.offsetHeight;
250					if (height > maxHeight) {
251						maxHeight = height;
252					}
253				});
254
255				viewport.style.minHeight = maxHeight > 0 ? maxHeight + 'px' : '';
256			}
257
258			function getOffsetForPhysicalIndex(physicalIndex, metrics) {
259				const step = metrics.width + metrics.gap;
260				const baseOffset = physicalIndex * step;
261
262				if (!featureFocusEnabled) {
263					return baseOffset;
264				}
265
266				const centerCount = slidesPerView % 2 === 0 ? 2 : 1;
267				const focusedWidth = centerCount * metrics.width * getFocusScale() + Math.max(0, centerCount - 1) * metrics.gap;
268				const centeringOffset = (metrics.viewportWidth - focusedWidth) / 2;
269				return baseOffset - centeringOffset;
270			}
271
272			function updateFocusClasses() {
273				trackSlides.forEach(function (slide) {
274					slide.classList.remove('is-feature-focus-single');
275					slide.classList.remove('is-feature-focus-left');
276					slide.classList.remove('is-feature-focus-right');
277				});
278
279				if (!featureFocusEnabled) {
280					return;
281				}
282
283				if (slidesPerView % 2 === 1) {
284					const middleRealIndex = mod(currentSlide, totalSlides);
285					trackSlides.forEach(function (slide) {
286						const realIndex = toPositiveInt(slide.getAttribute('data-carousel-real-index'), 0);
287						if (realIndex === middleRealIndex) {
288							slide.classList.add('is-feature-focus-single');
289						}
290					});
291					return;
292				}
293
294				const leftRealIndex = mod(currentSlide, totalSlides);
295				const rightRealIndex = mod(leftRealIndex + 1, totalSlides);
296
297				trackSlides.forEach(function (slide) {
298					const realIndex = toPositiveInt(slide.getAttribute('data-carousel-real-index'), 0);
299					if (realIndex === leftRealIndex) {
300						slide.classList.add('is-feature-focus-left');
301					} else if (realIndex === rightRealIndex) {
302						slide.classList.add('is-feature-focus-right');
303					}
304				});
305			}
306
307			function updateIndicators() {
308				const visibleCount = Math.min(totalSlides, maxSelectors);
309				const windowStart = getIndicatorWindowStart();
310				const activePosition = clamp(currentSlide - windowStart, 0, visibleCount - 1);
311
312				indicators.innerHTML = '';
313
314				for (let index = 0; index < visibleCount; index += 1) {
315					const slideIndex = windowStart + index;
316					const indicator = document.createElement('button');
317					indicator.type = 'button';
318					indicator.className = 'amm-grid-carousel__indicator';
319					indicator.setAttribute('role', 'tab');
320					indicator.setAttribute('aria-label', 'Go to slide ' + (slideIndex + 1));
321					indicator.setAttribute('aria-selected', index === activePosition ? 'true' : 'false');
322					if (index === activePosition) {
323						indicator.classList.add('is-active');
324					}
325
326					indicator.addEventListener('click', function () {
327						const delta = index - activePosition;
328						if (delta === 0) {
329							return;
330						}
331						moveBy(delta);
332						resetAutoplay();
333					});
334
335					indicators.appendChild(indicator);
336				}
337			}
338
339			function updateControlsState() {
340				prev.disabled = false;
341				next.disabled = false;
342			}
343
344			function setTrackTransform(offset, animate) {
345				clearTransitionRestore();
346				setTransitionEnabled(animate);
347				inner.style.transform = 'translate3d(' + -offset + 'px, 0, 0)';
348
349				if (!animate) {
350					transitionRestoreRaf = window.requestAnimationFrame(function () {
351						setTransitionEnabled(true);
352						transitionRestoreRaf = null;
353					});
354				}
355			}
356
357			function normalizePhysicalIndex(index) {
358				const minPhysical = cloneCount;
359				const maxPhysical = cloneCount + totalSlides - 1;
360				let normalized = index;
361
362				while (normalized < minPhysical) {
363					normalized += totalSlides;
364				}
365				while (normalized > maxPhysical) {
366					normalized -= totalSlides;
367				}
368
369				return normalized;
370			}
371
372			function snapToRealRange() {
373				const normalized = normalizePhysicalIndex(currentPhysicalIndex);
374				if (normalized === currentPhysicalIndex) {
375					return;
376				}
377
378				currentPhysicalIndex = normalized;
379				const metrics = updateSlideWidths();
380				const offset = getOffsetForPhysicalIndex(currentPhysicalIndex, metrics);
381
382				setTransitionEnabled(false);
383				inner.style.transform = 'translate3d(' + -offset + 'px, 0, 0)';
384				void inner.offsetHeight;
385				setTransitionEnabled(true);
386			}
387
388			function render(options) {
389				const renderOptions = options || {};
390				if (!isMeasurable()) {
391					pendingRender = true;
392					ensureVisibleRender();
393					return;
394				}
395				pendingRender = false;
396
397				const nextSlidesPerView = getSlidesPerView(carousel, totalSlides);
398				slidesPerView = nextSlidesPerView;
399				currentSlide = mod(currentSlide, totalSlides);
400
401				let rebuilt = false;
402				if (renderedSlidesPerView !== slidesPerView || cloneCount === 0) {
403					rebuildClones(slidesPerView);
404					rebuilt = true;
405				}
406
407				if (rebuilt) {
408					currentPhysicalIndex = cloneCount + currentSlide;
409				} else if (typeof renderOptions.physicalIndex === 'number') {
410					currentPhysicalIndex = renderOptions.physicalIndex;
411				} else {
412					currentPhysicalIndex = cloneCount + currentSlide;
413				}
414
415				const metrics = updateSlideWidths();
416				const offset = getOffsetForPhysicalIndex(currentPhysicalIndex, metrics);
417				setTrackTransform(offset, !!renderOptions.animate);
418				updateViewportHeight();
419				isTransitioning = !!renderOptions.animate;
420
421				updateFocusClasses();
422				updateIndicators();
423				updateControlsState();
424
425				const canSlide = totalSlides > 1;
426				const isMobileViewport = window.innerWidth <= 767;
427				// Arrows are hidden on phones unless the block opts in (data-carousel-arrows-mobile).
428				const arrowsAllowed = !isMobileViewport || carousel.dataset.carouselArrowsMobile === 'true';
429				nav.style.display = canSlide && showArrows && arrowsAllowed ? 'flex' : 'none';
430				indicators.style.display = canSlide && showDots ? 'flex' : 'none';
431			}
432
433			function moveBy(step) {
434				if (!step) {
435					return;
436				}
437				currentSlide = mod(currentSlide + step, totalSlides);
438				currentPhysicalIndex += step;
439				render({
440					animate: true,
441					physicalIndex: currentPhysicalIndex,
442				});
443			}
444
445			function nextSlide() {
446				moveBy(1);
447			}
448
449			function previousSlide() {
450				moveBy(-1);
451			}
452
453			function startAutoplay() {
454				if (
455					!autoSlideEnabled ||
456					autoplayInterval ||
457					isPointerInside ||
458					hasFocusWithin ||
459					mediaEngaged
460				) {
461					return;
462				}
463				autoplayInterval = window.setInterval(function () {
464					nextSlide();
465				}, cycleTimeSeconds * 1000);
466			}
467
468			function stopAutoplay() {
469				if (!autoplayInterval) {
470					return;
471				}
472				window.clearInterval(autoplayInterval);
473				autoplayInterval = null;
474			}
475
476			function resetAutoplay() {
477				stopAutoplay();
478				startAutoplay();
479			}
480
481			function engageMedia() {
482				mediaEngaged = true;
483				stopAutoplay();
484				scheduleRender();
485			}
486
487			inner.addEventListener('transitionend', function (event) {
488				if (event.propertyName !== 'transform' || !isTransitioning) {
489					return;
490				}
491				isTransitioning = false;
492				snapToRealRange();
493			});
494
495			prev.addEventListener('click', function () {
496				previousSlide();
497				resetAutoplay();
498			});
499
500			next.addEventListener('click', function () {
501				nextSlide();
502				resetAutoplay();
503			});
504
505			if (typeof window.ammwebBindSwipe === 'function') {
506				window.ammwebBindSwipe(viewport, {
507					threshold: 40,
508					onStart: stopAutoplay,
509					onSwipeLeft: nextSlide,
510					onSwipeRight: previousSlide,
511					onEnd: resetAutoplay,
512				});
513			}
514
515			carousel.addEventListener('mouseenter', function () {
516				isPointerInside = true;
517				stopAutoplay();
518			});
519			carousel.addEventListener('mouseleave', function () {
520				isPointerInside = false;
521				startAutoplay();
522			});
523			carousel.addEventListener('focusin', function () {
524				hasFocusWithin = true;
525				stopAutoplay();
526			});
527			carousel.addEventListener('focusout', function (event) {
528				if (!carousel.contains(event.relatedTarget)) {
529					hasFocusWithin = false;
530					startAutoplay();
531				}
532			});
533			carousel.addEventListener('click', function (event) {
534				if (event.target.closest('[data-amm-industry-expert-play-video], [data-amm-video-modal-trigger], video, audio, iframe')) {
535					engageMedia();
536				}
537			});
538			carousel.addEventListener('play', engageMedia, true);
539			carousel.addEventListener('loadedmetadata', scheduleRender, true);
540			carousel.addEventListener('load', scheduleRender, true);
541
542			carousel.addEventListener('keydown', function (event) {
543				if (event.key === 'ArrowLeft') {
544					previousSlide();
545					resetAutoplay();
546				} else if (event.key === 'ArrowRight') {
547					nextSlide();
548					resetAutoplay();
549				}
550			});
551
552			window.addEventListener('resize', scheduleRender);
553			window.addEventListener('load', scheduleRender);
554			window.addEventListener('pageshow', scheduleRender);
555			document.addEventListener('visibilitychange', scheduleRender);
556			document.addEventListener('shown.bs.tab', scheduleRender);
557			document.addEventListener('tabsactivate', scheduleRender);
558			document.addEventListener('accordionactivate', scheduleRender);
559
560			if (typeof ResizeObserver !== 'undefined') {
561				const resizeObserver = new ResizeObserver(function () {
562					scheduleRender();
563				});
564				resizeObserver.observe(carousel);
565				resizeObserver.observe(viewport);
566				resizeObserver.observe(inner);
567			}
568
569			render();
570			startAutoplay();
571		});
572	});
573})();

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.