PageSourceSearch

https://www.justborn.com/wp-content/themes/studioswift/blocks/testimonials/script.js

js justborn.com collected 2026-10-02 08:01:10 UTC 6,399 bytes, 245 lines download raw bytes

1/**
2 * Testimonials Block - Slick Slider Initialization
3 *
4 * @package StudioSwift
5 */
6
7(function ($) {
8	'use strict';
9
10	/**
11	 * Initialize testimonials slider
12	 */
13	function initTestimonialsSlider() {
14		// Check if sliders exist
15		if (!$('.js-testimonial-slider').length) {
16			return;
17		}
18
19		// Check if Slick is available
20		if (typeof $.fn.slick === 'undefined') {
21			console.error('Slick slider library not loaded');
22			return;
23		}
24
25		/**
26		 * Pause all videos in a testimonials slider, then play only the active slide's video if it has autoplay.
27		 * Keeps hidden slides from playing audio and satisfies browser autoplay rules (muted + active slide).
28		 */
29		function syncTestimonialSliderVideos($slider) {
30			if (!$slider.length || !$slider.hasClass('slick-initialized')) {
31				return;
32			}
33			$slider.find('video').each(function () {
34				this.pause();
35			});
36			$slider.find('.slick-slide.slick-active video').each(function () {
37				if (this.hasAttribute('autoplay')) {
38					var v = this;
39					var p = v.play();
40					if (p !== undefined && typeof p.catch === 'function') {
41						p.catch(function () {});
42					}
43				}
44			});
45		}
46
47		/**
48		 * Recalculate --nav-position / --content-height for one testimonials block.
49		 * Shared by init, slide change, and resize.
50		 */
51		function updateTestimonialNavForBlock($slider) {
52			if (!$slider.length || !$slider.hasClass('slick-initialized')) {
53				return;
54			}
55			const $parent = $slider.closest('.testimonials');
56			const $nav = $parent.find('.js-testimonial-nav');
57			const $testimonialContent = $parent.find('.js-testimonial-content');
58
59			let maxContentHeight = 0;
60			let relatedSlideHeight = 0;
61
62			$slider.find('.slick-slide:not(.slick-cloned)').each(function () {
63				const $slide = $(this);
64				const $content = $slide.find('.js-testimonial-content');
65
66				if (!$content.length) {
67					return;
68				}
69
70				const contentHeight = $content.outerHeight();
71				const slideHeight = $slide.outerHeight();
72
73				if (contentHeight > maxContentHeight) {
74					maxContentHeight = contentHeight;
75					relatedSlideHeight = slideHeight;
76				}
77			});
78
79			let bottomGap = 0;
80			if (relatedSlideHeight > maxContentHeight) {
81				bottomGap = (relatedSlideHeight - maxContentHeight) / 2 + 48;
82			}
83
84			if ($nav.length) {
85				$nav.css('--nav-position', bottomGap + 'px');
86			}
87			if ($testimonialContent.length) {
88				$testimonialContent.css('--content-height', maxContentHeight + 'px');
89			}
90		}
91
92		let testimonialsResizeTimer;
93		$(window)
94			.off('resize.studioswiftTestimonials')
95			.on('resize.studioswiftTestimonials', function () {
96				clearTimeout(testimonialsResizeTimer);
97				testimonialsResizeTimer = setTimeout(function () {
98					$('.js-testimonial-slider.slick-initialized').each(function () {
99						updateTestimonialNavForBlock($(this));
100					});
101				}, 150);
102			});
103
104		// Initialize each slider
105		$('.js-testimonial-slider').each(function () {
106			const $slider = $(this);
107			const $parent = $slider.closest('.testimonials');
108
109			if ($slider.hasClass('slick-initialized')) {
110				return;
111			}
112
113			// Get slider settings from data attributes
114			const autoplay = $slider.attr('data-autoplay') === 'true';
115			const speed = parseInt($slider.attr('data-speed'), 10) || 5000;
116			const slideCountRaw = parseInt($slider.attr('data-slides'), 10);
117			const slideCount =
118				Number.isFinite(slideCountRaw) && slideCountRaw > 0 ? slideCountRaw : 1;
119
120			$slider.off('init.studioswiftTestimonials afterChange.studioswiftTestimonials');
121
122			function updateNavPosition() {
123				updateTestimonialNavForBlock($slider);
124			}
125
126			$slider.on('init.studioswiftTestimonials', function () {
127				setTimeout(updateNavPosition, 100);
128				setTimeout(function () {
129					syncTestimonialSliderVideos($slider);
130				}, 150);
131			});
132
133			// One testimonial: still initialize Slick so .slick-initialized applies (slider + copy are visible in CSS).
134			if (slideCount <= 1) {
135				$slider.slick({
136					dots: false,
137					arrows: false,
138					fade: true,
139					slidesToShow: 1,
140					slidesToScroll: 1,
141					autoplay: false,
142					pauseOnHover: false,
143					pauseOnFocus: false,
144					accessibility: true,
145					adaptiveHeight: false,
146					infinite: false,
147					draggable: false,
148					swipe: false,
149					touchMove: false,
150				});
151				return;
152			}
153
154			const $prevArrow = $parent.find('.js-testimonial-prev');
155			const $nextArrow = $parent.find('.js-testimonial-next');
156			const $dotsContainer = $parent.find('.js-testimonial-dots');
157
158			$slider.on('afterChange.studioswiftTestimonials', function () {
159				setTimeout(updateNavPosition, 100);
160				syncTestimonialSliderVideos($slider);
161			});
162
163			$slider.slick({
164				dots: false,
165				arrows: true,
166				fade: true,
167				slidesToShow: 1,
168				slidesToScroll: 1,
169				autoplay: autoplay,
170				autoplaySpeed: speed,
171				pauseOnHover: false,
172				pauseOnFocus: false,
173				prevArrow: $prevArrow,
174				nextArrow: $nextArrow,
175				appendDots: $dotsContainer,
176				accessibility: true,
177				adaptiveHeight: false,
178				draggable: true,
179				swipe: true,
180				touchMove: true,
181				responsive: [
182					{
183						breakpoint: 767,
184						settings: {
185							adaptiveHeight: false,
186						},
187					},
188				],
189			});
190		});
191	}
192
193	function initTestimonialsLottie() {
194		if (typeof window.lottie === 'undefined') {
195			return;
196		}
197		if (!$('.js-testimonials-lottie').length) {
198			return;
199		}
200		$('.js-testimonials-lottie').each(function () {
201			const $lottieAnimation = $(this);
202			if ($lottieAnimation.data('lottie-initialized')) {
203				return;
204			}
205			const lottieSrc = $lottieAnimation.data('lottie-src');
206			if (!lottieSrc) {
207				return;
208			}
209			// Use window.lottie — do not name a const `lottie` here (TDZ vs global).
210			window.lottie.loadAnimation({
211				container: $lottieAnimation[0],
212				renderer: 'svg',
213				loop: true,
214				autoplay: true,
215				path: lottieSrc,
216			});
217			$lottieAnimation.data('lottie-initialized', true);
218		});
219	}
220
221	/**
222	 * Initialize on document ready
223	 */
224	$(document).ready(function () {
225		initTestimonialsSlider();
226		initTestimonialsLottie();
227	});
228
229	/**
230	 * Re-initialize when new blocks are added (Block Editor)
231	 */
232	if (typeof acf !== 'undefined') {
233		acf.addAction('render_block_preview', function () {
234			// Destroy existing slick instances in preview
235			$('.js-testimonial-slider.slick-initialized').slick('unslick');
236			// Re-initialize
237			setTimeout(function () {
238				initTestimonialsSlider();
239				initTestimonialsLottie();
240			}, 300);
241		});
242	}
243
244})(jQuery);
245

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.