PageSourceSearch

https://www.solocruceros.com/assets/js/base/modules/carousel.js?v=1785848608

js solocruceros.com collected 2026-10-01 12:22:51 UTC 5,575 bytes, 144 lines download raw bytes

1// Calcula los bullets visibles: siempre 3, agrupados de 3 en 3, aun si el total no es multiplo de 3.
2function updateCarouselBullets(swiper, carouselElement) {
3    const bullets = carouselElement.querySelectorAll('.swiper-pagination-bullet');
4    if (bullets.length === 0) return;
5
6    const total = bullets.length;
7    const realIndex = swiper.realIndex;
8    const totalReal = swiper.slides.length - (swiper.loopedSlides * 2);
9
10    // Cuenta las vueltas (loop fwd y back) para mantener el grupo de 3 correcto.
11    if (!carouselElement._swiperProgressiveData) {
12        carouselElement._swiperProgressiveData = { lastRealIndex: realIndex, totalLoops: 0 };
13    }
14    const data = carouselElement._swiperProgressiveData;
15    if (data.lastRealIndex === totalReal - 1 && realIndex === 0) data.totalLoops++;
16    if (data.lastRealIndex === 0 && realIndex === totalReal - 1) data.totalLoops--;
17    data.lastRealIndex = realIndex;
18
19    let loops = data.totalLoops;
20    if (loops < 0) loops += total + 2; // ajuste para loop inverso
21    const counter = realIndex + loops * total;
22
23    // Inicio del grupo de 3 que contiene al slide actual (con wrap modulo total).
24    const start = ((realIndex - (counter % 3)) % total + total) % total;
25    const order = { [start]: '-3', [(start + 1) % total]: '-2', [(start + 2) % total]: '-1' };
26
27    bullets.forEach((bullet, index) => {
28        const pos = order[index];
29        bullet.style.display = pos ? 'inline-block' : 'none';
30        bullet.style.order = pos || 'initial';
31    });
32}
33
34// Indica si un carousel es visible (no esta dentro de un tab-pane oculto).
35// Swiper no puede medir slides con display:none, por lo que hay que evitar
36// inicializarlo mientras este oculto.
37function isCarouselVisible(carousel) {
38    if (carousel.offsetParent === null) return false;
39    const pane = carousel.closest('.tab-pane');
40    if (pane && !pane.classList.contains('active')) return false;
41    return true;
42}
43
44function initCarousel(carousel) {
45    if (carousel._swiperInit) return;
46    carousel._swiperInit = true;
47
48    const swiperEl = carousel.querySelector('.swiper');
49    const slidesCount = swiperEl.querySelectorAll('.swiper-slide').length;
50
51    const defaults = {
52        slidesPerView: 1,
53        pagination: false,
54        loop: true
55    };
56
57    let customOptions = {};
58    if (carousel.dataset.carouselOptions) {
59        try {
60            customOptions = JSON.parse(carousel.dataset.carouselOptions);
61        } catch (e) {
62            console.warn('Error de data-carousel-options', e);
63        }
64    }
65
66    const config = { ...defaults, ...customOptions };
67
68    const navNext = carousel.querySelector('.swiper-button-next');
69    const navPrev = carousel.querySelector('.swiper-button-prev');
70
71    const swiperOptions = {
72        ...config,
73        pagination: config.pagination
74            ? {
75                el: swiperEl.querySelector('.swiper-pagination'),
76                clickable: true,
77                ...(typeof config.pagination === 'object' ? config.pagination : {})
78            }
79            : false,
80        navigation: config.navigation
81            ? {
82                ...(typeof config.navigation === 'object' ? config.navigation : {}),
83                nextEl: navNext,
84                prevEl: navPrev,
85            }
86            : false
87    };
88
89    if (customOptions.autoplay === true && slidesCount > 1) {
90        swiperOptions.autoplay = { delay: 5000, disableOnInteraction: false };
91    } else if (typeof customOptions.autoplay === 'object') {
92        swiperOptions.autoplay = { delay: 5000, ...customOptions.autoplay };
93    } else if (customOptions.autoplay === false) {
94        swiperOptions.autoplay = false;
95    }
96
97    const swiper = new Swiper(swiperEl, swiperOptions);
98    carousel._swiper = swiper;
99    carousel._swiperEl = swiperEl;
100    carousel._hasBullets = !!(config.pagination && slidesCount > 3);
101
102    // Inicializar bullets dinámicos,
103    if (carousel._hasBullets) {
104        updateCarouselBullets(swiper, swiperEl);
105
106        swiper.on('slideChange', () => {
107            updateCarouselBullets(swiper, swiperEl);
108        });
109    }
110}
111
112function initCarousels() {
113    // Solo se inicializan los carouseles visibles en este momento.
114    document.querySelectorAll('[data-carousel]').forEach(carousel => {
115        if (isCarouselVisible(carousel)) {
116            initCarousel(carousel);
117        }
118    });
119
120    // Los carouseles dentro de tab-panes ocultos se inicializan recien cuando
121    // su pestaña se muestra (shown.bs.tab), momento en el que ya tienen
122    // dimensiones reales y Swiper puede calcular slides/loop/autoplay/bullets.
123    document.querySelectorAll('[data-bs-toggle="tab"]').forEach(triggerEl => {
124        triggerEl.addEventListener('shown.bs.tab', event => {
125            const target = event.target.getAttribute('data-bs-target');
126            const pane = target ? document.querySelector(target) : null;
127            if (!pane) return;
128
129            pane.querySelectorAll('[data-carousel]').forEach(carousel => {
130                if (!isCarouselVisible(carousel)) return;
131                if (carousel._swiper) {
132                    if (carousel._swiperEl) carousel._swiperEl._swiperProgressiveData = null;
133                    carousel._swiper.destroy(true, true);
134                    carousel._swiper = null;
135                    carousel._swiperInit = false;
136                }
137                initCarousel(carousel);
138                if (carousel._hasBullets) {
139                    updateCarouselBullets(carousel._swiper, carousel._swiperEl);
140                }
141            });
142        });
143    });
144}

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.