PageSourceSearch

https://saude.es.gov.br/AutarquiaTheme/js/own-carousel.js?v=Ff4eTbgZQB2Iqg7Do6IpsOUCMsNruqndtKgv94Zv1lw

js saude.es.gov.br collected 2026-09-24 19:59:16 UTC 25,685 bytes, 725 lines download raw bytes

1/********************************************************************
2 *  OWN CAROUSEL — VERSÃO ROBUSTA v3
3 *  -------------------------------------------------------------
4 *  - Corrige itemPerRow=1 (gapWidth=0)
5 *  - Corrige poucos itens (sem branco / sem travar)
6 *  - Loop infinito robusto (clones corretos + teleporte no transitionend)
7 *  - Evita width=0 na inicialização (retry com rAF)
8 *  - useVisiblePerRow robusto (considera largura real + gap/margin)
9 *  - Dots com dois modos:
10 *      dotsMode: "page" (páginas/offsets)  |  "item" (1 dot por card)
11 *  - responsive(): ignora containers não inicializados (sem crash)
12 ********************************************************************/
13
14HTMLElement.prototype.ownCarousel = function (options) {
15    const {
16        itemPerRow = 4,
17        itemWidth = 24,
18        loop = true,
19        responsive = {},
20        draggable = true,
21        mouseWheel = false,
22        autoplay = 0,
23        stopAutoplayWhenHover = true,
24        nav = false,
25        isRTL = false,
26        dots = false,
27        dotsMode = "page",      // "page" | "item"
28        useVisiblePerRow = false
29    } = options;
30
31    /* -------------------------------------------------------
32     * ELEMENTOS BASE
33     * ------------------------------------------------------- */
34    this.carousel = this.querySelector(".own-carousel");
35    this.carouselOuter =
36        this.querySelector(".own-carousel__outer") ||
37        this.querySelector("[class*='own-carousel__outer']");
38
39    if (!this.carousel || !this.carouselOuter) return;
40
41    // live collection
42    this.carouselItem = this.carousel.children;
43
44    this.index = 0;
45    this.numberOfItem = this.carouselItem.length;
46
47    // prevent double init (importante em Orchard com partial render)
48    if (this._ownCarouselInitialized) return;
49    this._ownCarouselInitialized = true;
50
51    this.useVisiblePerRow = !!useVisiblePerRow;
52    this.dotsMode = (dotsMode === "item") ? "item" : "page";
53
54    // Controles de navegação (setas)
55    this.controlsEl = this.querySelector(".own-carousel__control") || null;
56    if (!this.controlsEl) {
57        const wrapper = this.closest(".widget-servicos") || this.closest("[id^='carousel-']");
58        if (wrapper) this.controlsEl = wrapper.querySelector(".own-carousel__control");
59    }
60
61    const dotsEnabled = !!dots;
62    const dotsContainer = this.querySelector(".own-carousel__dots");
63    this.dots = [];
64
65    /* -------------------------------------------------------
66     * CONFIG BASE
67     * ------------------------------------------------------- */
68    this.itemPerRowBig = (this.itemPerRow = itemPerRow);
69    this.itemWidthBig = (this.itemWidth = itemWidth);
70    this.responsive = responsive;
71
72    this.gapWidth = (this.itemPerRow > 1)
73        ? (100 - this.itemPerRow * this.itemWidth) / (this.itemPerRow - 1)
74        : 0;
75
76    this.style.setProperty("--width", `${this.itemWidth}%`);
77    this.style.setProperty("--margin", `${this.gapWidth}%`);
78
79    /* -------------------------------------------------------
80     * helper: quantos por linha devemos considerar
81     * ------------------------------------------------------- */
82    this.visiblePerRow = null;
83
84    this.getPerRow = () => {
85        if (!this.useVisiblePerRow) return this.itemPerRow;
86        return this.visiblePerRow || this.itemPerRow;
87    };
88
89    /* -------------------------------------------------------
90     * FUNÇÕES DE VISIBILIDADE
91     * ------------------------------------------------------- */
92    this.hasScroll = () => this.numberOfItem > this.getPerRow();
93
94    this.hasNavigation = () => {
95        return !!nav || !!dotsEnabled;
96    };
97
98    this.isLoopEnabled = () => {
99        return !!loop && this.hasNavigation() && this.hasScroll();
100    };
101
102    /* -------------------------------------------------------
103     * VISÍVEIS POR LINHA (modo opcional) — ROBUSTO
104     * - usa carouselOuter (área útil real)
105     * - considera largura real do item + gap/margin
106     * ------------------------------------------------------- */
107    this.updateVisiblePerRowAndOuterWidth = () => {
108        if (!this.useVisiblePerRow) return;
109        if (!this.carouselOuter || !this.carouselItem || !this.carouselItem[0]) return;
110
111        //  MEDIR A LARGURA DISPONÍVEL REAL (não o outer que você trava)
112        // O viewport do carrossel é o PAI do outer (normalmente o container com overflow hidden)
113        const host = this.carouselOuter.parentElement || this;
114        const hostWidth = host.getBoundingClientRect().width;
115        if (!hostWidth) return;
116
117        // mede o item raiz correto (inclui padding)
118        const firstItem = this.carousel.querySelector(".own-carousel__item") || this.carouselItem[0];
119        const itemWidthPx = firstItem.getBoundingClientRect().width;
120        if (!itemWidthPx) return;
121
122        // spacing real: preferir STEP - itemWidth
123        // (margin-left no :not(:first-child) faz o firstItem ter margin=0, então não use isso)
124        let spacing = 0;
125
126        // garante recomputeStep rodado
127        if (!this.step || !Number.isFinite(this.step) || this.step <= 0) {
128            this.recomputeStep?.();
129        }
130        if (this.step && Number.isFinite(this.step) && this.step > 0) {
131            spacing = Math.max(0, this.step - itemWidthPx);
132        }
133
134        // fallback: mede distância entre item[0] e item[1] quando existe
135        if (!spacing && this.carouselItem.length > 1) {
136            const a = this.carouselItem[0].getBoundingClientRect();
137            const b = this.carouselItem[1].getBoundingClientRect();
138            spacing = Math.max(0, (b.left - a.left) - a.width);
139        }
140
141        const footprint = itemWidthPx + spacing;
142        if (!footprint) return;
143
144        // +spacing no numerador ajuda quando encaixa "no limite"
145        const maxBySpace = Math.max(1, Math.floor((hostWidth + spacing) / footprint));
146
147        // respeita o limite configurado (itemPerRow)
148        this.visiblePerRow = Math.min(this.itemPerRow, maxBySpace);
149
150        // trava outer pra centralizar (ok), mas não mede outer depois
151        const usefulWidth = this.visiblePerRow * footprint - spacing;
152        this.carouselOuter.style.width = usefulWidth + "px";
153        this.carouselOuter.style.marginLeft = "auto";
154        this.carouselOuter.style.marginRight = "auto";
155    };
156
157
158    /* -------------------------------------------------------
159     * ESTADO VISUAL ATIVO
160     * ------------------------------------------------------- */
161    this.setActiveItem = () => {
162        if (!this.carouselItem || !this.carouselItem.length) return;
163        for (let i = 0; i < this.carouselItem.length; i++) {
164            this.carouselItem[i].classList.toggle(
165                "own-carousel__item--active",
166                i === this.index
167            );
168        }
169    };
170
171    /* -------------------------------------------------------
172     * STEP / MEDIÇÃO (com retry p/ width=0)
173     * ------------------------------------------------------- */
174    this.recomputeStep = (attempt = 0) => {
175        const MAX_ATTEMPTS = 12;
176
177        const cs = getComputedStyle(this.carousel);
178        this.gapPx = Number.parseFloat(cs.columnGap || cs.gap || "0") || 0;
179        this.usesGap = this.gapPx > 0;
180
181        const perRow = this.getPerRow();
182
183        let imgWidth = 0;
184        if (perRow === 1) {
185            imgWidth = this.carouselOuter.getBoundingClientRect().width;
186        } else {
187            // mede o item raiz (inclui padding)
188            const firstItem = this.carousel.querySelector(".own-carousel__item") || this.carouselItem[0];
189            imgWidth = firstItem?.getBoundingClientRect().width || 0;
190        }
191
192        if (!imgWidth && attempt < MAX_ATTEMPTS) {
193            requestAnimationFrame(() => this.recomputeStep(attempt + 1));
194            return false;
195        }
196
197        this.imgWidth = imgWidth;
198
199        const marginOffsetPx =
200            (this.itemPerRow > 1 && this.itemWidth)
201                ? (this.gapWidth / this.itemWidth) * this.imgWidth
202                : 0;
203
204        this.step = this.usesGap
205            ? this.imgWidth + this.gapPx
206            : this.imgWidth + marginOffsetPx;
207
208        return true;
209    };
210
211    this.stepToMoveAutoplay = isRTL ? -1 : 1;
212
213    /* -------------------------------------------------------
214     * MOVIMENTAÇÃO
215     * ------------------------------------------------------- */
216    this.translateSlide = () => {
217        const dir = isRTL ? 1 : -1;
218        this.carousel.style.transform = `translate3d(${dir * this.index * this.step}px,0,0)`;
219    };
220
221    this.teleportTo = (newIndex) => {
222        this.carousel.style.transition = "none";
223        this.index = newIndex;
224        this.translateSlide();
225        void this.carousel.offsetHeight; // reflow
226        this.carousel.style.transition = "transform .25s";
227    };
228
229    /* -------------------------------------------------------
230     * DOTS (page ou item)
231     * ------------------------------------------------------- */
232    this.generateDots = () => {
233        if (!dotsEnabled || !dotsContainer) return;
234
235        dotsContainer.innerHTML = "";
236        this.dots = [];
237
238        const perRow = this.getPerRow();
239        const loopDots = this.isLoopEnabled(); // loop ativo => 1 dot por item
240        const total = (loopDots || this.dotsMode === "item")
241            ? this.numberOfItem
242            : Math.max(this.numberOfItem - perRow + 1, 1);
243
244        for (let i = 0; i < total; i++) {
245            const dot = document.createElement("span");
246            dot.classList.add("carousel-dot");
247            if (i === 0) dot.classList.add("active");
248
249            dot.addEventListener("click", () => {
250                const cc = this.cloneCount || this.getPerRow();
251                const maxStart = Math.max(this.numberOfItem - perRow, 0);
252
253                if (loopDots || this.dotsMode === "item") {
254                    // dot i = item i (índice real)
255                    if (this.isLoopEnabled()) {
256                        this.index = i + cc;
257                    } else {
258                        this.index = Math.min(i, maxStart);
259                    }
260                } else {
261                    const offset = this.isLoopEnabled() ? cc : 0;
262                    this.index = this.isLoopEnabled() ? (i + offset) : i;
263                }
264
265
266                this.translateSlide();
267                this.updateDots();
268            });
269
270            dotsContainer.appendChild(dot);
271            this.dots.push(dot);
272        }
273
274        dotsContainer.style.display = (total > 1) ? "flex" : "none";
275    };
276
277    this.updateDots = () => {
278        if (!dotsEnabled || !dotsContainer) return;
279
280        this.dots.forEach((d) => d.classList.remove("active"));
281
282        const perRow = this.getPerRow();
283        const maxStart = Math.max(this.numberOfItem - perRow, 0);
284
285        let realIndex = this.index;
286
287        if (this.isLoopEnabled()) {
288            const cc = this.cloneCount || this.getPerRow();
289            const n = this.numberOfItem;
290
291            realIndex = (this.index - cc) % n;
292            if (realIndex < 0) realIndex += n;
293        }
294
295        const loopDots = this.isLoopEnabled();
296
297        if (loopDots || this.dotsMode === "item") {
298            const idx = Math.min(realIndex, this.numberOfItem - 1);
299            if (this.dots[idx]) this.dots[idx].classList.add("active");
300        } else {
301            const idx = Math.min(realIndex, maxStart);
302            if (this.dots[idx]) this.dots[idx].classList.add("active");
303        }
304    };
305
306    /* -------------------------------------------------------
307     * LOOP (CLONES) — sempre baseado em perRow efetivo
308     * ------------------------------------------------------- */
309    this.cloneCount = 0;
310
311    this._createClonesIfNeeded = () => {
312        if (!this.isLoopEnabled()) {
313            this.cloneCount = 0;
314            this.index = 0;
315            return;
316        }
317
318        const perRow = this.getPerRow();
319        this.cloneCount = Math.min(perRow, this.numberOfItem);
320
321        const originals = Array.from(this.carousel.children); // itens reais
322
323        // APPEND: primeiros N
324        for (let i = 0; i < this.cloneCount; i++) {
325            this.carousel.appendChild(originals[i].cloneNode(true));
326        }
327
328        // PREPEND: últimos N (na ordem correta)
329        for (let i = this.cloneCount - 1; i >= 0; i--) {
330            const srcIndex = this.numberOfItem - 1 - (this.cloneCount - 1 - i);
331            this.carousel.insertBefore(originals[srcIndex].cloneNode(true), this.carousel.firstChild);
332        }
333
334        this.index = this.cloneCount;
335    };
336
337    this._normalizeIfLoopEdge = () => {
338        if (!this.isLoopEnabled()) return;
339
340        const cc = this.cloneCount || this.getPerRow();
341        const n = this.numberOfItem;
342
343        if (this.index >= cc + n) {
344            this.teleportTo(cc);
345        } else if (this.index < cc) {
346            this.teleportTo(cc + n - 1);
347        }
348    };
349
350    this.moveSlide = (delta) => {
351        const perRow = this.getPerRow();
352        const maxStart = Math.max(this.numberOfItem - perRow, 0);
353        const loopEnabled = this.isLoopEnabled();
354
355        if (!loopEnabled) {
356            const next = this.index + delta;
357            if (next < 0 || next > maxStart) return;
358
359            this.index = next;
360            this.translateSlide();
361            this.updateDots();
362            this.setActiveItem && this.setActiveItem();
363            return;
364        }
365
366        this.index += delta;
367        this.translateSlide();
368        this.updateDots();
369        this.setActiveItem && this.setActiveItem();
370    };
371
372    if (!this._loopBound) {
373        this.carousel.addEventListener("transitionend", (e) => {
374            if (e.propertyName !== "transform") return;
375            this._normalizeIfLoopEdge();
376            this.updateDots();
377        });
378        this._loopBound = true;
379    }
380
381    /* -------------------------------------------------------
382     * NAV VISIBILITY
383     * ------------------------------------------------------- */
384    this.updateNavVisibility = () => {
385        const canScroll = this.hasScroll();
386        const showNavArea = canScroll && this.hasNavigation();
387
388        if (this.controlsEl) this.controlsEl.style.display = (canScroll && !!nav) ? "flex" : "none";
389
390        if (dotsEnabled && dotsContainer) {
391            const perRow = this.getPerRow();
392            const loopDots = this.isLoopEnabled();
393            const totalDots = (loopDots || this.dotsMode === "item")
394                ? this.numberOfItem
395                : Math.max(this.numberOfItem - perRow + 1, 1);
396
397            dotsContainer.style.display = (canScroll && totalDots > 1) ? "flex" : "none";
398        }
399
400        this.classList.toggle("own-no-scroll", !canScroll);
401
402        if (!showNavArea) {
403            this.index = 0;
404            this.carousel.style.transition = "none";
405            this.carousel.style.transform = "";
406            this.carousel.style.justifyContent = "center";
407            this.carousel.style.marginBottom = "20px";
408        } else {
409            this.carousel.style.justifyContent = "flex-start";
410            this.carousel.style.transition = "transform .25s";
411            this.translateSlide();
412        }
413    };
414
415    /* -------------------------------------------------------
416     * NAV (SETAS)
417     * ------------------------------------------------------- */
418    if (nav) {
419        const navScope = this.controlsEl || this;
420
421        navScope.querySelector(".control__prev")
422            ?.addEventListener("click", () => this.moveSlide(-1));
423
424        navScope.querySelector(".control__next")
425            ?.addEventListener("click", () => this.moveSlide(1));
426    }
427
428    /* -------------------------------------------------------
429     * DRAG (Pointer) — com cálculo RTL correto
430     * ------------------------------------------------------- */
431    if (draggable && this.carouselOuter) {
432        const THRESHOLD_PX = 12;
433        const CLICK_BLOCK_MS = 350;
434
435        this._drag = this._drag || {
436            bound: false,
437            dragging: false,
438            pointerId: null,
439            firstX: 0,
440            startTransform: 0,
441            moved: false,
442            blockClickUntil: 0
443        };
444
445        const getCurrentTranslateX = () => {
446            const tr = getComputedStyle(this.carousel).transform;
447            if (tr && tr !== "none") {
448                const m = new DOMMatrixReadOnly(tr);
449                return m.m41;
450            }
451            return 0;
452        };
453
454        const finishByIndex = () => {
455            this.carousel.style.transition = "transform .25s";
456
457            const currentMove = getCurrentTranslateX();
458            const dir = isRTL ? 1 : -1;
459
460            // transform = dir * index * step  => index = transform / (dir*step)
461            const rawIndex = currentMove / (dir * this.step);
462            this.index = Math.round(rawIndex);
463
464            const perRow = this.getPerRow();
465            const maxStart = Math.max(this.numberOfItem - perRow, 0);
466
467            if (!this.isLoopEnabled()) {
468                if (this.index > maxStart) this.index = maxStart;
469                if (this.index < 0) this.index = 0;
470            }
471
472            this.translateSlide();
473            this.updateDots();
474        };
475
476        const cleanupState = () => {
477            this._drag.dragging = false;
478            this._drag.pointerId = null;
479            this.carouselOuter.style.cursor = "";
480            this.carousel.style.transition = "transform .25s";
481            this.classList.remove("is-dragging");
482            this._drag.moved = false;
483        };
484
485        if (!this._drag._clickBlockerBound) {
486            this.carouselOuter.addEventListener("click", (e) => {
487                const a = e.target?.closest?.("a, button, [role='button']");
488                if (!a) return;
489
490                if (Date.now() < (this._drag.blockClickUntil || 0)) {
491                    e.preventDefault();
492                    e.stopPropagation();
493                }
494            }, true);
495            this._drag._clickBlockerBound = true;
496        }
497
498        const bindPointer = () => {
499            const dragStart = (e) => {
500                if (e.pointerType === "mouse" && e.button !== 0) return;
501
502                this._drag.dragging = true;
503                this._drag.pointerId = e.pointerId;
504                this._drag.firstX = e.clientX;
505                this._drag.startTransform = getCurrentTranslateX();
506                this._drag.moved = false;
507
508                this.carousel.style.transition = "none";
509                this.carouselOuter.style.cursor = "grab";
510                this.classList.add("is-dragging");
511            };
512
513            const dragMove = (e) => {
514                if (!this._drag.dragging) return;
515                if (e.pointerId !== this._drag.pointerId) return;
516
517                const totalDx = e.clientX - this._drag.firstX;
518                if (Math.abs(totalDx) > THRESHOLD_PX) {
519                    this._drag.moved = true;
520                    if (!this.carouselOuter.hasPointerCapture(e.pointerId)) {
521                        try { this.carouselOuter.setPointerCapture(e.pointerId); } catch { }
522                    }
523                }
524
525                const next = this._drag.startTransform + totalDx;
526                this.carousel.style.transform = `translate3d(${next}px,0,0)`;
527            };
528
529            const dragEnd = (e) => {
530                if (!this._drag.dragging) return;
531                if (e.pointerId !== this._drag.pointerId) return;
532
533                try { this.carouselOuter.releasePointerCapture(e.pointerId); } catch { }
534
535                this._drag.blockClickUntil = this._drag.moved ? (Date.now() + CLICK_BLOCK_MS) : 0;
536
537                finishByIndex();
538                cleanupState();
539            };
540
541            const dragCancel = () => {
542                this.translateSlide();
543                this.updateDots();
544                cleanupState();
545            };
546
547            this.carouselOuter.addEventListener("pointerdown", dragStart, { passive: true });
548            this.carouselOuter.addEventListener("pointermove", dragMove, { passive: true });
549            this.carouselOuter.addEventListener("pointerup", dragEnd, { passive: true });
550            this.carouselOuter.addEventListener("pointercancel", dragCancel, { passive: true });
551        };
552
553        if (!this._drag.bound) {
554            if (window.PointerEvent) bindPointer();
555            this._drag.bound = true;
556        }
557    }
558
559    /* -------------------------------------------------------
560     * INIT — ORDEM CORRETA
561     * ------------------------------------------------------- */
562    applyAdaptiveGap(this);
563
564    // 1) mede gap/step primeiro (pra updateVisible usar gapPx)
565    this.recomputeStep();
566
567    // 2) calcula visiblePerRow com footprint real (item + gap/margin)
568    if (this.useVisiblePerRow) {
569        this.updateVisiblePerRowAndOuterWidth();
570        // como outer mudou, recalcula step
571        this.recomputeStep();
572    }
573
574    // 3) cria clones (depende de perRow final)
575    this._createClonesIfNeeded();
576
577    // 4) pinta posição inicial sem “cortar”
578    this.carousel.style.transition = "none";
579    this.translateSlide();
580    void this.carousel.offsetHeight;
581    this.carousel.style.transition = "transform .25s";
582
583    // 5) dots/nav
584    this.generateDots();
585    this.updateDots();
586    this.setActiveItem();
587    this.updateNavVisibility();
588
589    // blindagem extra: recalcular em resize do outer
590    if (window.ResizeObserver && !this._ro) {
591        this._ro = new ResizeObserver(() => {
592            applyAdaptiveGap(this);
593            this.recomputeStep();
594
595            if (this.useVisiblePerRow) {
596                this.updateVisiblePerRowAndOuterWidth();
597                this.recomputeStep();
598            }
599
600            this.updateNavVisibility && this.updateNavVisibility();
601            this.updateDots && this.updateDots();
602        });
603        const host = this.carouselOuter.parentElement || this.carouselOuter;
604        this._ro.observe(host);
605    }
606};
607
608/*****************************************************************
609 * GAP ADAPTATIVO
610 *****************************************************************/
611function calcAdaptiveGap(container) {
612    const ww = window.innerWidth;
613    const n = container.numberOfItem || 0;
614
615    const inBandA = ww <= 1399 && ww >= 1272;
616    const inBandB = ww <= 1199 && ww >= 1060;
617
618    if (!inBandA && !inBandB) return 0;
619
620    if (n >= 6) return 0;
621    if (n === 5) return 10;
622    return 20;
623}
624
625function applyAdaptiveGap(container) {
626    const px = calcAdaptiveGap(container);
627    container.style.setProperty("--gap", `${px}px`);
628
629    if (px > 0) container.classList.add("use-gap");
630    else container.classList.remove("use-gap");
631}
632
633/*****************************************************************
634 * RESPONSIVE LISTENER (SAFE)
635 *****************************************************************/
636function debounce(fn, delay) {
637    let id = null;
638    return function () {
639        clearTimeout(id);
640        id = setTimeout(() => fn.apply(this, arguments), delay);
641    };
642}
643
644function safeResponsiveUpdate() {
645    requestAnimationFrame(() => setTimeout(responsive, 100));
646}
647
648function responsive() {
649    const ww = window.innerWidth;
650    const containers = document.querySelectorAll(".own-carousel__container");
651
652    const pickBreakpoint = (map, width) => {
653        if (!map || typeof map !== "object") return null;
654
655        const keys = Object.keys(map).map(Number).filter(n => !Number.isNaN(n)).sort((a, b) => a - b);
656        if (!keys.length) return null;
657
658        const minBased = keys[0] === 0;
659        if (minBased) {
660            let chosen = keys[0];
661            for (let bp of keys) if (width >= bp) chosen = bp;
662            return chosen;
663        } else {
664            for (let bp of keys) if (width <= bp) return bp;
665            return null;
666        }
667    };
668
669    containers.forEach((c) => {
670        if (!c._ownCarouselInitialized) return;
671
672        const chosen = pickBreakpoint(c.responsive, ww);
673
674        if (chosen !== null) {
675            c.itemPerRow = c.responsive[chosen][0];
676            c.itemWidth = c.responsive[chosen][1];
677        } else {
678            c.itemPerRow = c.itemPerRowBig;
679            c.itemWidth = c.itemWidthBig;
680        }
681
682        c.gapWidth = (c.itemPerRow > 1)
683            ? (100 - c.itemPerRow * c.itemWidth) / (c.itemPerRow - 1)
684            : 0;
685
686        c.style.setProperty("--width", `${c.itemWidth}%`);
687        c.style.setProperty("--margin", `${c.gapWidth}%`);
688
689        applyAdaptiveGap(c);
690
691        // recalcula step e visible (se necessário)
692        c.recomputeStep && c.recomputeStep();
693
694        if (c.useVisiblePerRow && c.updateVisiblePerRowAndOuterWidth) {
695            c.updateVisiblePerRowAndOuterWidth();
696            c.recomputeStep && c.recomputeStep();
697        }
698
699        // reposiciona com segurança (sem recriar clones aqui)
700        const perRow = c.getPerRow ? c.getPerRow() : c.itemPerRow;
701        const maxStart = Math.max(c.numberOfItem - perRow, 0);
702
703        if (!c.hasScroll || !c.hasScroll()) {
704            c.index = 0;
705        } else if (!c.isLoopEnabled || !c.isLoopEnabled()) {
706            if (c.index > maxStart) c.index = maxStart;
707            if (c.index < 0) c.index = 0;
708        } else {
709            const cc = c.cloneCount || perRow;
710            if (c.index < cc) c.index = cc;
711            if (c.index >= cc + c.numberOfItem) c.index = cc;
712        }
713
714        c.carousel.style.transition = "none";
715        c.translateSlide && c.translateSlide();
716        void c.carousel.offsetHeight;
717        c.carousel.style.transition = "transform .25s";
718
719        c.generateDots && c.generateDots();
720        c.updateDots && c.updateDots();
721        c.updateNavVisibility && c.updateNavVisibility();
722    });
723}
724
725window.addEventListener("resize", debounce(safeResponsiveUpdate, 300));

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.