PageSourceSearch

https://generalarcade.com/js/testimonials-mobile.js

js generalarcade.com collected 2026-10-02 08:30:22 UTC 6,070 bytes, 210 lines download raw bytes

1/**
2 * Mobile Testimonials Carousel
3 */
4(function() {
5  'use strict';
6
7  function initMobileCarousel() {
8    var mobileCarousel = document.querySelector('.js-testimonials-mobile');
9    if (!mobileCarousel) return;
10
11    // Проверяем видимость элемента
12    if (mobileCarousel.offsetParent === null) {
13      // Элемент скрыт, не инициализируем
14      return;
15    }
16
17    var container = mobileCarousel.querySelector('.c-testimonials-mobile__container');
18    var track = mobileCarousel.querySelector('.js-testimonials-mobile-track');
19    var slides = mobileCarousel.querySelectorAll('.js-testimonials-mobile-slide');
20    var prevBtn = mobileCarousel.querySelector('.js-testimonials-mobile-prev');
21    var nextBtn = mobileCarousel.querySelector('.js-testimonials-mobile-next');
22    var companyLogo = mobileCarousel.querySelector('.js-testimonials-mobile-logo');
23    var companyName = mobileCarousel.querySelector('.js-testimonials-mobile-company');
24    var companyAuthor = mobileCarousel.querySelector('.js-testimonials-mobile-author');
25
26    if (!track || !container || slides.length === 0) return;
27
28    var currentIndex = 0;
29    var isAnimating = false;
30    var slideCount = slides.length;
31    var transitionDuration = 500;
32    var autoPlayInterval = null;
33    var slideWidth = 0;
34
35    // Данные о компаниях
36    var companiesData = [];
37    for (var i = 0; i < slides.length; i++) {
38      companiesData.push({
39        logo: slides[i].getAttribute('data-logo') || '',
40        company: slides[i].getAttribute('data-company') || '',
41        author: slides[i].getAttribute('data-author') || ''
42      });
43    }
44
45    // Установить размеры слайдов
46    function setupSlides() {
47      // Получаем ширину контейнера
48      slideWidth = mobileCarousel.offsetWidth || 320;
49
50      if (slideWidth === 0) {
51        slideWidth = 320;
52      }
53
54      // Устанавливаем стили контейнера
55      container.style.width = slideWidth + 'px';
56      container.style.overflow = 'hidden';
57
58      // Установить ширину каждого слайда
59      for (var i = 0; i < slides.length; i++) {
60        slides[i].style.width = slideWidth + 'px';
61        slides[i].style.minWidth = slideWidth + 'px';
62      }
63
64      // Установить ширину трека
65      track.style.display = 'flex';
66      track.style.width = (slideWidth * slideCount) + 'px';
67
68      // Обновить позицию
69      updateCarousel(false);
70    }
71
72    // Обновить отображение компании
73    function updateCompanyInfo() {
74      var data = companiesData[currentIndex];
75      if (companyLogo && data && data.logo) {
76        companyLogo.src = data.logo;
77        companyLogo.alt = data.company || '';
78      }
79      if (companyName && data) {
80        companyName.textContent = data.company || '';
81      }
82      if (companyAuthor && data) {
83        companyAuthor.textContent = data.author || '';
84      }
85    }
86
87    // Обновить позицию карусели
88    function updateCarousel(animate) {
89      if (animate !== false) {
90        track.style.transition = 'transform 0.5s ease';
91      } else {
92        track.style.transition = 'none';
93      }
94      var offset = -currentIndex * slideWidth;
95      track.style.transform = 'translateX(' + offset + 'px)';
96      updateCompanyInfo();
97    }
98
99    // Следующий слайд
100    function nextSlide() {
101      if (isAnimating) return;
102      isAnimating = true;
103
104      currentIndex++;
105      if (currentIndex >= slideCount) {
106        currentIndex = 0;
107      }
108      updateCarousel(true);
109
110      setTimeout(function() {
111        isAnimating = false;
112      }, transitionDuration);
113    }
114
115    // Предыдущий слайд
116    function prevSlide() {
117      if (isAnimating) return;
118      isAnimating = true;
119
120      currentIndex--;
121      if (currentIndex < 0) {
122        currentIndex = slideCount - 1;
123      }
124      updateCarousel(true);
125
126      setTimeout(function() {
127        isAnimating = false;
128      }, transitionDuration);
129    }
130
131    // Обработчики кнопок
132    if (nextBtn) {
133      nextBtn.addEventListener('click', function(e) {
134        e.preventDefault();
135        stopAutoPlay();
136        nextSlide();
137      });
138    }
139
140    if (prevBtn) {
141      prevBtn.addEventListener('click', function(e) {
142        e.preventDefault();
143        stopAutoPlay();
144        prevSlide();
145      });
146    }
147
148    // Touch/Swipe
149    var touchStartX = 0;
150    var touchEndX = 0;
151    var swipeThreshold = 50;
152
153    track.addEventListener('touchstart', function(e) {
154      touchStartX = e.changedTouches[0].screenX;
155      stopAutoPlay();
156    }, { passive: true });
157
158    track.addEventListener('touchend', function(e) {
159      touchEndX = e.changedTouches[0].screenX;
160      var diff = touchStartX - touchEndX;
161      if (Math.abs(diff) > swipeThreshold) {
162        if (diff > 0) {
163          nextSlide();
164        } else {
165          prevSlide();
166        }
167      }
168    }, { passive: true });
169
170    // Автовоспроизведение
171    function startAutoPlay() {
172      stopAutoPlay();
173      autoPlayInterval = setInterval(function() {
174        if (!isAnimating) {
175          nextSlide();
176        }
177      }, 5000);
178    }
179
180    function stopAutoPlay() {
181      if (autoPlayInterval) {
182        clearInterval(autoPlayInterval);
183        autoPlayInterval = null;
184      }
185    }
186
187    // Пересчитать при изменении размера окна
188    var resizeTimer;
189    window.addEventListener('resize', function() {
190      clearTimeout(resizeTimer);
191      resizeTimer = setTimeout(function() {
192        setupSlides();
193      }, 100);
194    });
195
196    // Инициализация
197    setupSlides();
198    startAutoPlay();
199
200    console.log('Mobile carousel initialized. Slides:', slideCount, 'Width:', slideWidth);
201  }
202
203  // Запуск
204  if (document.readyState === 'loading') {
205    document.addEventListener('DOMContentLoaded', initMobileCarousel);
206  } else {
207    initMobileCarousel();
208  }
209
210})();

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.