PageSourceSearch

https://ritzau.com/wp-content/themes/ritzau/blocks/feature-slider/view.js?ver=1781103055

js ritzau.com collected 2026-10-01 10:33:09 UTC 6,015 bytes, 154 lines download raw bytes

1(function () {
2    'use strict';
3
4    document.querySelectorAll('.ritzau-block-feature-slider').forEach(function (block) {
5        var wrapper = block.querySelector('.ritzau-block-feature-slider__wrapper');
6        var track   = block.querySelector('.ritzau-block-feature-slider__track');
7        var prevBtn = block.querySelector('.ritzau-block-feature-slider__prev');
8        var nextBtn = block.querySelector('.ritzau-block-feature-slider__next');
9
10        if (!track || !wrapper) { return; }
11
12        var realItems = Array.from(track.querySelectorAll('.ritzau-block-feature-slider__item'));
13        var count = realItems.length;
14
15        if (count === 0) { return; }
16        if (count === 1) {
17            realItems[0].classList.add('is-active');
18            if (prevBtn) { prevBtn.style.display = 'none'; }
19            if (nextBtn) { nextBtn.style.display = 'none'; }
20            return;
21        }
22
23        // ── Clone 2 items on each end so the 3-col view never shows a gap ─
24        // DOM after cloning:
25        //   [prevLastClone(0), lastClone(1), item0(2), ..., item(N-1)(N+1), firstClone(N+2), nextFirstClone(N+3)]
26        var prevLastClone  = realItems[count - 2].cloneNode(true);
27        var lastClone      = realItems[count - 1].cloneNode(true);
28        var firstClone     = realItems[0].cloneNode(true);
29        var nextFirstClone = realItems[1].cloneNode(true);
30
31        [prevLastClone, lastClone, firstClone, nextFirstClone].forEach(function (c) {
32            c.setAttribute('aria-hidden', 'true');
33        });
34
35        track.insertBefore(lastClone, realItems[0]);
36        track.insertBefore(prevLastClone, lastClone);
37        track.appendChild(firstClone);
38        track.appendChild(nextFirstClone);
39
40        // Real items occupy indices 2 … count+1.
41        // Start at index 3 (item1) so slide 1 is left, slide 2 is active center.
42        var curr        = 3;
43        var isAnimating = false;
44
45        function getCols() {
46            return window.innerWidth >= 1024 ? 3 : 1;
47        }
48
49        function getItemWidth() {
50            return wrapper.offsetWidth / getCols();
51        }
52
53        function getAllItems() {
54            return Array.from(track.querySelectorAll('.ritzau-block-feature-slider__item'));
55        }
56
57        function setItemWidths() {
58            var w = getItemWidth();
59            getAllItems().forEach(function (item) {
60                item.style.flexBasis = w + 'px';
61                item.style.width     = w + 'px';
62            });
63        }
64
65        function getTranslate(index) {
66            var cols         = getCols();
67            var itemWidth    = getItemWidth();
68            var centerOffset = cols === 3 ? 1 : 0;
69            return -(index - centerOffset) * itemWidth;
70        }
71
72        function setPosition(index, animate) {
73            track.style.transition = animate ? 'transform 0.4s ease' : 'none';
74            track.style.transform  = 'translateX(' + getTranslate(index) + 'px)';
75        }
76
77        function updateActive() {
78            getAllItems().forEach(function (item, i) {
79                item.classList.toggle('is-active', i === curr);
80            });
81        }
82
83        // ── Initialise ────────────────────────────────────────────────────
84        setItemWidths();
85        setPosition(curr, false);
86        updateActive();
87
88        // ── Navigation ────────────────────────────────────────────────────
89        function goNext() {
90            if (isAnimating) { return; }
91            isAnimating = true;
92            curr++;
93            setPosition(curr, true);
94            updateActive();
95        }
96
97        function goPrev() {
98            if (isAnimating) { return; }
99            isAnimating = true;
100            curr--;
101            setPosition(curr, true);
102            updateActive();
103        }
104
105        // Instant jump without CSS transition on items (prevents opacity/scale blink)
106        function instantJump(newCurr) {
107            block.classList.add('is-jumping');
108            curr = newCurr;
109            setPosition(curr, false);
110            updateActive();
111            requestAnimationFrame(function () {
112                requestAnimationFrame(function () {
113                    block.classList.remove('is-jumping');
114                });
115            });
116        }
117
118        // After transition, jump from clone zone back to real items
119        track.addEventListener('transitionend', function () {
120            isAnimating = false;
121            if (curr === count + 2) {
122                instantJump(2);
123            } else if (curr === 1) {
124                instantJump(count + 1);
125            }
126        });
127
128        if (prevBtn) { prevBtn.addEventListener('click', goPrev); }
129        if (nextBtn) { nextBtn.addEventListener('click', goNext); }
130
131        // ── Touch / swipe ──────────────────────────────────────────────────
132        var touchStartX = 0;
133        wrapper.addEventListener('touchstart', function (e) {
134            touchStartX = e.touches[0].clientX;
135        }, { passive: true });
136
137        wrapper.addEventListener('touchend', function (e) {
138            var diff = touchStartX - e.changedTouches[0].clientX;
139            if (Math.abs(diff) > 50) {
140                diff > 0 ? goNext() : goPrev();
141            }
142        }, { passive: true });
143
144        // ── Recalculate on resize ──────────────────────────────────────────
145        var resizeTimer;
146        window.addEventListener('resize', function () {
147            clearTimeout(resizeTimer);
148            resizeTimer = setTimeout(function () {
149                setItemWidths();
150                setPosition(curr, false);
151            }, 100);
152        });
153    });
154})();

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.