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.