PageSourceSearch

https://cameronveterinaryclinic.com/wp-content/plugins/vetcelerato…/reviews/js/swiper-init.js?ver=0.1.5

js cameronveterinaryclinic.com collected 2026-10-06 14:07:02 UTC 6,811 bytes, 178 lines download raw bytes

1/**
2 * Google Reviews Slider - Swiper.js Initialization
3 * Optimized for iOS/Safari compatibility
4 */
5document.addEventListener('DOMContentLoaded', function() {
6    // Initialize all sliders
7    document.querySelectorAll('.grs-swiper').forEach(function(el) {
8        var autoplay = el.dataset.autoplay !== 'false';
9        var autoplaySpeed = parseInt(el.dataset.autoplaySpeed) || 4000;
10        var slidesDesktop = parseInt(el.dataset.slidesDesktop) || 3;
11        var slidesTablet = parseInt(el.dataset.slidesTablet) || 2;
12        var slidesMobile = parseInt(el.dataset.slidesMobile) || 1;
13        // Swiper 11 disables loop with a console warning when
14        // slides <= slidesPerView; skip it up front in that case.
15        var slideCount = el.querySelectorAll('.swiper-slide').length;
16
17        var swiper = new Swiper(el, {
18            // Core settings
19            slidesPerView: slidesMobile,
20            spaceBetween: 20,
21            loop: slideCount > slidesDesktop,
22            grabCursor: true,
23
24            // iOS/Safari critical settings
25            touchEventsTarget: 'container',
26            simulateTouch: true,
27            allowTouchMove: true,
28            touchRatio: 1,
29            touchAngle: 45,
30            shortSwipes: true,
31            longSwipes: true,
32            longSwipesRatio: 0.5,
33            longSwipesMs: 300,
34            followFinger: true,
35            threshold: 5,
36            touchMoveStopPropagation: false,
37            touchStartPreventDefault: false,
38            touchReleaseOnEdges: true,
39            passiveListeners: true,
40            resistance: true,
41            resistanceRatio: 0.85,
42
43            // Autoplay
44            autoplay: autoplay ? {
45                delay: autoplaySpeed,
46                disableOnInteraction: false,
47                pauseOnMouseEnter: true
48            } : false,
49
50            // Pagination
51            // dynamicBullets injects an inline width + translateX on the
52            // .swiper-pagination element, which fights the CSS centering and
53            // shoves the dots off to one side. Keep it off so the bullets stay
54            // centered via plain text-align:center.
55            pagination: {
56                el: el.querySelector('.swiper-pagination'),
57                clickable: true,
58                dynamicBullets: false
59            },
60
61            // Nav buttons live outside the swiper element and are wired up
62            // manually below; passing them to Swiper's navigation module too
63            // would bind a second click handler and advance two slides per click.
64
65            // Responsive breakpoints
66            breakpoints: {
67                320: {
68                    slidesPerView: slidesMobile,
69                    spaceBetween: 15
70                },
71                768: {
72                    slidesPerView: slidesTablet,
73                    spaceBetween: 20
74                },
75                1024: {
76                    slidesPerView: slidesDesktop,
77                    spaceBetween: 25
78                }
79            },
80
81            // Accessibility
82            a11y: {
83                prevSlideMessage: 'Previous review',
84                nextSlideMessage: 'Next review',
85                firstSlideMessage: 'First review',
86                lastSlideMessage: 'Last review'
87            }
88        });
89
90        // iOS Safari: Restart autoplay after interaction
91        if (autoplay) {
92            el.addEventListener('touchend', function() {
93                setTimeout(function() {
94                    if (swiper.autoplay && !swiper.autoplay.running) {
95                        swiper.autoplay.start();
96                    }
97                }, 1000);
98            });
99        }
100
101        // touchend calls preventDefault, which suppresses the synthetic click
102        // that follows a tap, so mobile taps advance exactly one slide.
103        var container = el.closest('.grs-direct-slider-container');
104        var prevBtn = container ? container.querySelector('.grs-nav-prev') : null;
105        var nextBtn = container ? container.querySelector('.grs-nav-next') : null;
106
107        if (prevBtn) {
108            prevBtn.addEventListener('click', function(e) {
109                e.preventDefault();
110                e.stopPropagation();
111                swiper.slidePrev();
112            });
113            prevBtn.addEventListener('touchend', function(e) {
114                e.preventDefault();
115                e.stopPropagation();
116                swiper.slidePrev();
117            });
118        }
119
120        if (nextBtn) {
121            nextBtn.addEventListener('click', function(e) {
122                e.preventDefault();
123                e.stopPropagation();
124                swiper.slideNext();
125            });
126            nextBtn.addEventListener('touchend', function(e) {
127                e.preventDefault();
128                e.stopPropagation();
129                swiper.slideNext();
130            });
131        }
132    });
133
134    // Read more/less functionality
135    document.addEventListener('click', function(e) {
136        if (e.target.classList.contains('grs-direct-read-more')) {
137            e.preventDefault();
138            var review = e.target.closest('.grs-direct-review');
139            var text = review.querySelector('.grs-direct-text');
140            var showLess = review.querySelector('.grs-direct-hide');
141            var swiperEl = e.target.closest('.grs-swiper');
142
143            // Expand the text
144            text.classList.remove('truncated');
145            text.classList.add('expanded');
146            e.target.style.display = 'none';
147            if (showLess) showLess.style.display = 'inline';
148
149            // Update Swiper to recalculate heights
150            if (swiperEl && swiperEl.swiper) {
151                setTimeout(function() {
152                    swiperEl.swiper.update();
153                }, 50);
154            }
155        }
156
157        if (e.target.classList.contains('grs-direct-hide')) {
158            e.preventDefault();
159            var review = e.target.closest('.grs-direct-review');
160            var text = review.querySelector('.grs-direct-text');
161            var readMore = review.querySelector('.grs-direct-read-more');
162            var swiperEl = e.target.closest('.grs-swiper');
163
164            // Collapse the text
165            text.classList.remove('expanded');
166            text.classList.add('truncated');
167            e.target.style.display = 'none';
168            if (readMore) readMore.style.display = 'inline';
169
170            // Update Swiper to recalculate heights
171            if (swiperEl && swiperEl.swiper) {
172                setTimeout(function() {
173                    swiperEl.swiper.update();
174                }, 50);
175            }
176        }
177    });
178});

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.