PageSourceSearch

https://ritzau.com/wp-content/themes/ritzau/blocks/via-ritzau-latest-news-feed/view.js?ver=1782478992

js ritzau.com collected 2026-10-01 10:33:07 UTC 6,413 bytes, 158 lines download raw bytes

1/**
2 * Block: ritzau/via-ritzau-latest-news-feed — Frontend view script
3 *
4 * - Padding is calculated from the container's bounding rect so the first card
5 *   aligns exactly with the section heading/text above it.
6 * - Hard stop at both ends: can't drag past the first or last card's container edge.
7 * - Momentum / inertia after release.
8 * - Native browser drag (link drag) is suppressed; clicks still work — and a click
9 *   is suppressed when a drag occurred (cards are links).
10 */
11(function () {
12    'use strict';
13
14    document.querySelectorAll('.ritzau-block-via-ritzau-latest-news-feed__track').forEach(function (track) {
15        var block     = track.closest('.ritzau-block-via-ritzau-latest-news-feed');
16        var container = block ? block.querySelector('.ritzau-block-via-ritzau-latest-news-feed__container') : null;
17
18        var isDown      = false;
19        var startX      = 0;
20        var startScroll = 0;
21        var hasDragged  = false;
22        var velocity    = 0;   // px/ms
23        var lastX       = 0;
24        var lastTime    = 0;
25        var rafId       = null;
26        var maxScroll   = 0;
27
28        // ── Align padding with the container's edges ──────────────────────
29        // Runs on load and on every resize so it's always in sync.
30        function updatePadding() {
31            if (!container) { return; }
32
33            var containerRect  = container.getBoundingClientRect();
34            var containerStyle = window.getComputedStyle(container);
35            var trackWidth     = track.clientWidth;   // visible width, excludes scrollbar
36
37            var innerLeft  = containerRect.left  + parseFloat(containerStyle.paddingLeft  || 0);
38            var innerRight = containerRect.right - parseFloat(containerStyle.paddingRight || 0);
39
40            var leftPad  = Math.round(Math.max(16, innerLeft));
41            var rightPad = Math.round(Math.max(16, trackWidth - innerRight));
42
43            track.style.paddingLeft  = leftPad  + 'px';
44            track.style.paddingRight = rightPad + 'px';
45
46            // Let the browser reflow before reading scrollWidth
47            requestAnimationFrame(function () {
48                maxScroll = track.scrollWidth - track.clientWidth;
49            });
50        }
51
52        updatePadding();
53        window.addEventListener('resize', updatePadding);
54
55        // ── Prevent native browser drag on links/images inside the track ──
56        track.addEventListener('dragstart', function (e) {
57            e.preventDefault();
58        });
59
60        // ── Drag start ────────────────────────────────────────────────────
61        track.addEventListener('mousedown', function (e) {
62            if (e.button !== 0) { return; }
63            if (rafId) { cancelAnimationFrame(rafId); rafId = null; }
64
65            isDown      = true;
66            hasDragged  = false;
67            velocity    = 0;
68            startX      = e.clientX;
69            startScroll = track.scrollLeft;
70            lastX       = e.clientX;
71            lastTime    = Date.now();
72
73            track.classList.add('is-dragging');
74        });
75
76        // ── Drag move ─────────────────────────────────────────────────────
77        document.addEventListener('mousemove', function (e) {
78            if (!isDown) { return; }
79            e.preventDefault();
80
81            var x   = e.clientX;
82            var now = Date.now();
83            var dt  = now - lastTime;
84
85            if (dt > 0) {
86                velocity = (lastX - x) / dt;  // px/ms, positive = dragging forward (left)
87            }
88            lastX    = x;
89            lastTime = now;
90
91            if (Math.abs(x - startX) > 4) { hasDragged = true; }
92
93            // Hard stop: clamp to [0, maxScroll]
94            var desired = startScroll - (x - startX);
95            track.scrollLeft = Math.max(0, Math.min(maxScroll, desired));
96        });
97
98        // ── Drag end ──────────────────────────────────────────────────────
99        document.addEventListener('mouseup', function () {
100            if (!isDown) { return; }
101            isDown = false;
102            track.classList.remove('is-dragging');
103
104            if (hasDragged && Math.abs(velocity) > 0.08) {
105                applyInertia(velocity * 16);  // px/ms → approx px/frame @60fps
106            } else {
107                snapToStartIfNear();
108            }
109        });
110
111        // ── Inertia ───────────────────────────────────────────────────────
112        function applyInertia(v) {
113            var FRICTION = 0.93;
114            rafId = requestAnimationFrame(function step() {
115                var next = track.scrollLeft + v;
116
117                // Hard stop at boundaries
118                if (next <= 0) {
119                    track.scrollLeft = 0;
120                    rafId = null;
121                    return;
122                }
123                if (next >= maxScroll) {
124                    track.scrollLeft = maxScroll;
125                    rafId = null;
126                    return;
127                }
128
129                if (Math.abs(v) < 0.4) {
130                    rafId = null;
131                    snapToStartIfNear();
132                    return;
133                }
134
135                track.scrollLeft = next;
136                v *= FRICTION;
137                rafId = requestAnimationFrame(step);
138            });
139        }
140
141        // ── Snap to start if close to the beginning ────────────────────────
142        function snapToStartIfNear() {
143            if (track.scrollLeft < 40) {
144                track.scrollTo({ left: 0, behavior: 'smooth' });
145            }
146        }
147
148        // ── Block link clicks when a drag occurred ─────────────────────────
149        track.addEventListener('click', function (e) {
150            if (hasDragged) {
151                e.preventDefault();
152                e.stopPropagation();
153                hasDragged = false;
154            }
155        }, true);
156    });
157
158}());

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.