PageSourceSearch

https://www.mithraeum.eu/js/related-cards.js?v=1

js mithraeum.eu collected 2026-10-02 10:27:24 UTC 2,831 bytes, 65 lines download raw bytes

1window.tnmInitRelatedCards = function (scope) {
2(scope || document).querySelectorAll('[data-related-cards]').forEach(function (root) {
3	if (root.dataset.relatedReady) return;
4	root.dataset.relatedReady = '1';
5	var track = root.querySelector('.related-cards__track');
6	var cards = Array.from(track.children);
7	var controls = root.querySelector('.related-cards__controls');
8	var previous = root.querySelector('[data-related-prev]');
9	var next = root.querySelector('[data-related-next]');
10	var count = root.querySelector('.related-cards__count');
11	var reducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)');
12	var timer;
13	if (!cards.length) return;
14
15	function visibleCount() {
16		return parseInt(getComputedStyle(track).getPropertyValue('--related-visible'), 10) || 1;
17	}
18	function positions() {
19		var left = cards[0].getBoundingClientRect().left;
20		return cards.map(function (card) { return card.getBoundingClientRect().left - left; });
21	}
22	function update() {
23		var max = track.scrollWidth - track.clientWidth;
24		controls.hidden = max < 2;
25		previous.disabled = track.scrollLeft <= 2;
26		next.disabled = track.scrollLeft >= max - 2;
27		var bounds = track.getBoundingClientRect();
28		var visible = [];
29		cards.forEach(function (card, index) {
30			var rect = card.getBoundingClientRect();
31			if (rect.left >= bounds.left - 2 && rect.right <= bounds.right + 2) visible.push(index + 1);
32		});
33		if (visible.length) {
34			var first = visible[0], last = visible[visible.length - 1];
35			count.textContent = (first === last ? first : first + '–' + last) + ' of ' + cards.length;
36		}
37	}
38	function move(direction) {
39		var offsets = positions();
40		var current = offsets.reduce(function (best, offset, index) {
41			return Math.abs(offset - track.scrollLeft) < Math.abs(offsets[best] - track.scrollLeft) ? index : best;
42		}, 0);
43		var target = Math.max(0, Math.min(cards.length - 1, current + direction * visibleCount()));
44		track.scrollTo({ left: offsets[target], behavior: reducedMotion.matches ? 'instant' : 'smooth' });
45	}
46	previous.addEventListener('click', function () { move(-1); });
47	next.addEventListener('click', function () { move(1); });
48	root.addEventListener('keydown', function (event) {
49		if (event.altKey || event.ctrlKey || event.metaKey || event.shiftKey) return;
50		if (event.key !== 'ArrowLeft' && event.key !== 'ArrowRight') return;
51		event.preventDefault();
52		// Keep the gallery and the admin catalogue shortcuts from also moving.
53		event.stopPropagation();
54		move(event.key === 'ArrowLeft' ? -1 : 1);
55	});
56	track.addEventListener('scroll', function () {
57		clearTimeout(timer);
58		timer = setTimeout(update, 120);
59	}, { passive: true });
60	if (window.ResizeObserver) new ResizeObserver(update).observe(track);
61	else window.addEventListener('resize', update);
62	update();
63});
64};
65window.tnmInitRelatedCards(document);

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.