PageSourceSearch

https://www.rebootonline.com/static/js/components/new-testimonials.js

js rebootonline.com collected 2026-10-02 02:33:16 UTC 4,436 bytes, 149 lines download raw bytes

1(() => {
2    const carousel = document.getElementById("tcarousel");
3    if (!carousel) return;
4
5    const track = carousel.querySelector(".tcarousel__track");
6    const cards = Array.from(track.querySelectorAll(".tcard"));
7
8    const fill = document.getElementById("tFill");
9    const idxEl = document.getElementById("tIndex");
10    const totalEl = document.getElementById("tTotal");
11    const prevBtn = document.getElementById("tPrev");
12    const nextBtn = document.getElementById("tNext");
13
14    let currentIndex = 0;
15    let settleTimer = null;
16    let snapRestoreTimer = null;
17
18    function isOverflowMode() {
19        return window.innerWidth <= 768;
20    }
21
22    function leftAlignScrollLeft(cardEl) {
23        const trackRect = track.getBoundingClientRect();
24        const cardRect = cardEl.getBoundingClientRect();
25        return track.scrollLeft + (cardRect.left - trackRect.left);
26    }
27
28    function setEndSpacer() {
29        const spacer = track.querySelector(".carousel__spacer");
30        if (!spacer || !cards.length) return;
31
32        if (isOverflowMode()) {
33            spacer.style.flexBasis = "16px";
34            return;
35        }
36
37        spacer.style.flexBasis = "0px";
38        const last = cards[cards.length - 1];
39        const lastW = last.getBoundingClientRect().width;
40        const needed = Math.max(0, Math.ceil(track.clientWidth - lastW));
41        spacer.style.flexBasis = needed + "px";
42    }
43
44    function getMaxIndex() {
45        if (isOverflowMode()) {
46            return cards.length - 1;
47        }
48
49        const carouselWidth = carousel.clientWidth;
50        let perView = 1;
51        if (carouselWidth >= 1538) perView = 3;
52        else if (carouselWidth >= 1012) perView = 2;
53
54        return Math.max(0, cards.length - perView);
55    }
56
57    function nearestLeftMostIndex() {
58        const trackRect = track.getBoundingClientRect();
59        const targetLeft = trackRect.left;
60
61        let best = 0;
62        let bestDist = Infinity;
63
64        for (let i = 0; i < cards.length; i++) {
65            const cardLeft = cards[i].getBoundingClientRect().left;
66            const dist = Math.abs(cardLeft - targetLeft);
67            if (dist < bestDist) {
68                bestDist = dist;
69                best = i;
70            }
71        }
72        return best;
73    }
74
75    function render(i) {
76        const maxIndex = getMaxIndex();
77        currentIndex = Math.max(0, Math.min(i, maxIndex));
78
79        idxEl.textContent = String(currentIndex + 1);
80        totalEl.textContent = String(maxIndex + 1);
81        fill.style.width = `${((currentIndex + 1) / (maxIndex + 1)) * 100}%`;
82
83        prevBtn.disabled = currentIndex === 0;
84        nextBtn.disabled = currentIndex === maxIndex;
85    }
86
87    function scrollToIndex(i) {
88        const maxIndex = getMaxIndex();
89        const targetIndex = Math.max(0, Math.min(i, maxIndex));
90        const targetLeft = leftAlignScrollLeft(cards[targetIndex]);
91
92        track.style.scrollSnapType = "none";
93        clearTimeout(snapRestoreTimer);
94
95        render(targetIndex);
96
97        track.scrollTo({
98            left: targetLeft,
99            behavior: "smooth"
100        });
101
102        snapRestoreTimer = setTimeout(() => {
103            track.style.scrollSnapType = "x mandatory";
104            render(nearestLeftMostIndex());
105        }, 350);
106    }
107
108    prevBtn.addEventListener("click", () => {
109        scrollToIndex(currentIndex - 1);
110    });
111
112    nextBtn.addEventListener("click", () => {
113        scrollToIndex(currentIndex + 1);
114    });
115
116    track.addEventListener("scroll", () => {
117        clearTimeout(settleTimer);
118        settleTimer = setTimeout(() => {
119            render(nearestLeftMostIndex());
120        }, 120);
121    });
122
123    window.addEventListener("resize", () => {
124        setEndSpacer();
125        track.style.scrollSnapType = "none";
126        track.scrollTo({
127            left: leftAlignScrollLeft(cards[Math.min(currentIndex, cards.length - 1)]) || 0,
128            behavior: "auto"
129        });
130        track.style.scrollSnapType = "x mandatory";
131        render(nearestLeftMostIndex());
132    });
133
134    window.addEventListener("load", () => {
135        setEndSpacer();
136        track.scrollTo({
137            left: leftAlignScrollLeft(cards[currentIndex]) || 0,
138            behavior: "auto"
139        });
140        render(nearestLeftMostIndex());
141    });
142
143    setEndSpacer();
144    render(0);
145    track.scrollTo({
146        left: leftAlignScrollLeft(cards[0]) || 0,
147        behavior: "auto"
148    });
149})();

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.