PageSourceSearch

https://www.reisemobilfuchs.de/js/carousel.js

js reisemobilfuchs.de collected 2026-10-07 03:32:11 UTC 5,734 bytes, 169 lines download raw bytes

1document.addEventListener("DOMContentLoaded", function () {
2    const carousel = document.querySelector(".carousel");
3    if (!carousel) return;
4    carousel.setAttribute("tabindex", "0");
5
6    const images = Array.from(carousel.querySelectorAll("img")).filter(function (img) {
7        return img.complete ? img.naturalWidth > 0 : true;
8    });
9
10    // Nur Nachbarbilder preloaden: flüssig beim Klicken, aber mobile Daten sparen.
11    const preloadImage = function (index) {
12        const safeIndex = (index + images.length) % images.length;
13        const src = images[safeIndex].getAttribute("src");
14        if (!src) return;
15        const preload = new Image();
16        preload.src = src;
17    };
18
19    if (images.length === 0) {
20        const emptyMessage = document.createElement("div");
21        emptyMessage.className = "carousel-empty";
22        emptyMessage.textContent = "Bilder folgen in Kürze.";
23        carousel.appendChild(emptyMessage);
24        return;
25    }
26
27    let currentIndex = 0;
28    images[currentIndex].classList.add("active");
29
30    let lightbox = null;
31    let lightboxImage = null;
32    let lightboxClose = null;
33    let previousFocus = null;
34
35    const createLightbox = function () {
36        if (lightbox) return;
37
38        lightbox = document.createElement("div");
39        lightbox.className = "lightbox-backdrop";
40        lightbox.setAttribute("role", "dialog");
41        lightbox.setAttribute("aria-modal", "true");
42        lightbox.setAttribute("aria-label", "Großansicht des Bildes");
43
44        const inner = document.createElement("div");
45        inner.className = "lightbox-inner";
46
47        lightboxImage = document.createElement("img");
48        lightboxImage.className = "lightbox-image";
49        lightboxImage.alt = "";
50
51        lightboxClose = document.createElement("button");
52        lightboxClose.type = "button";
53        lightboxClose.className = "lightbox-close";
54        lightboxClose.setAttribute("aria-label", "Großansicht schließen");
55        lightboxClose.innerHTML = "×";
56
57        inner.appendChild(lightboxImage);
58        inner.appendChild(lightboxClose);
59        lightbox.appendChild(inner);
60        document.body.appendChild(lightbox);
61
62        lightbox.addEventListener("click", function (event) {
63            if (event.target === lightbox || event.target === lightboxClose) {
64                closeLightbox();
65            }
66        });
67
68        document.addEventListener("keydown", function (event) {
69            if (!lightbox || lightbox.getAttribute("data-open") !== "true") return;
70            if (event.key === "Escape") {
71                event.preventDefault();
72                closeLightbox();
73                if (lightboxClose) {
74                    lightboxClose.blur();
75                }
76            }
77        });
78    };
79
80    const openLightbox = function (index) {
81        createLightbox();
82        if (!lightbox || !lightboxImage) return;
83        const safeIndex = (index + images.length) % images.length;
84        const src = images[safeIndex].getAttribute("src");
85        if (!src) return;
86
87        previousFocus = document.activeElement;
88        lightboxImage.src = src;
89        lightbox.setAttribute("data-open", "true");
90        lightbox.classList.add("open");
91        if (lightboxClose) {
92            lightboxClose.focus();
93        }
94    };
95
96    const closeLightbox = function () {
97        if (!lightbox) return;
98        lightbox.setAttribute("data-open", "false");
99        lightbox.classList.remove("open");
100        if (previousFocus && typeof previousFocus.focus === "function") {
101            previousFocus.focus();
102        }
103    };
104
105    const counter = document.createElement("div");
106    counter.className = "carousel-counter";
107    counter.setAttribute("aria-live", "polite");
108    carousel.appendChild(counter);
109
110    const updateCounter = function () {
111        counter.textContent = (currentIndex + 1) + " / " + images.length;
112    };
113
114    const showImage = function (index) {
115        images[currentIndex].classList.remove("active");
116        currentIndex = (index + images.length) % images.length;
117        images[currentIndex].classList.add("active");
118        updateCounter();
119        preloadImage(currentIndex + 1);
120        preloadImage(currentIndex - 1);
121    };
122
123    const nav = document.createElement("div");
124    nav.classList.add("nav");
125
126    const prevButton = document.createElement("button");
127    prevButton.type = "button";
128    prevButton.innerHTML = "❮";
129    prevButton.setAttribute("aria-label", "Vorheriges Bild");
130    prevButton.addEventListener("click", function () {
131        showImage(currentIndex - 1);
132    });
133
134    const nextButton = document.createElement("button");
135    nextButton.type = "button";
136    nextButton.innerHTML = "❯";
137    nextButton.setAttribute("aria-label", "Nächstes Bild");
138    nextButton.addEventListener("click", function () {
139        showImage(currentIndex + 1);
140    });
141
142    nav.appendChild(prevButton);
143    nav.appendChild(nextButton);
144    carousel.appendChild(nav);
145
146    carousel.addEventListener("keydown", function (event) {
147        if (event.key === "ArrowLeft") {
148            event.preventDefault();
149            showImage(currentIndex - 1);
150        } else if (event.key === "ArrowRight") {
151            event.preventDefault();
152            showImage(currentIndex + 1);
153        } else if (event.key === "Enter" || event.key === " ") {
154            event.preventDefault();
155            openLightbox(currentIndex);
156        }
157    });
158
159    images.forEach(function (img, index) {
160        img.style.cursor = "zoom-in";
161        img.addEventListener("click", function () {
162            openLightbox(index);
163        });
164    });
165
166    updateCounter();
167    preloadImage(currentIndex + 1);
168    preloadImage(currentIndex - 1);
169});

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.