PageSourceSearch

https://baukunst-nrw.de/js/ObjectDetailSlider.js?v=2

js baukunst-nrw.de collected 2026-10-02 08:06:10 UTC 6,912 bytes, 166 lines download raw bytes

1/**
2 * Spezielle Klasse für den Bilder-Slider in der Objekt-Detailansicht.
3 * Nutzt Swiper anstelle von Glide für bessere Unterstützung variabler Breiten.
4 */
5export default class ObjectDetailSlider {
6    constructor(selector = '.object-images-slider') {
7        this.selector = selector;
8        this.container = document.querySelector(selector);
9
10        if (this.container) {
11            this.init();
12        }
13    }
14
15    init() {
16        const thumbContainer = document.querySelector('.object-thumbnails-slider');
17        const slideCount = this.container.querySelectorAll('.swiper-slide').length;
18        const infoContainer = document.querySelector('.image-info-container');
19        const captionEl = document.querySelector('.image-swiper-caption');
20        const photographerEl = document.querySelector('.image-photographer');
21
22        let thumbnailSwiper = null;
23        if (thumbContainer) {
24            thumbnailSwiper = new Swiper(thumbContainer, {
25                spaceBetween: 10,
26                slidesPerView: 'auto',
27                slideToClickedSlide: true,
28                watchSlidesProgress: true,
29                centeredSlides: true,
30                initialSlide: 0,
31                loop: false,
32                centerInsufficientSlides: true,
33                observer: true,
34                observeParents: true,
35            });
36        }
37
38        const updateImageText = (swiper) => {
39            const activeSlide = swiper.slides[swiper.activeIndex];
40            if (!activeSlide) return;
41
42            const caption = activeSlide.getAttribute('data-caption');
43            const photographer = activeSlide.getAttribute('data-photographer');
44            const photographerUrl = activeSlide.getAttribute('data-photographer-url');
45            const wikiurl = activeSlide.getAttribute('data-wikiurl');
46            const wikitypeName = activeSlide.getAttribute('data-wikitype-name');
47            const wikitypeUrl = activeSlide.getAttribute('data-wikitype-url');
48            const currentIndex = swiper.activeIndex + 1;
49            const totalSlides = swiper.slides.length;
50
51            if (captionEl) captionEl.textContent = caption || '';
52            if (photographerEl) {
53                let html = `Bild ${currentIndex}/${totalSlides}`;
54                if (photographer) {
55                    let photographerLabel;
56                    if (wikiurl) {
57                        // Wikipedia-Foto: unverändert, Link bereits am "Foto:"-Label.
58                        photographerLabel = `<a href="${wikiurl}" target="_blank" rel="noopener">Foto:</a> ${photographer}`;
59                    } else if (photographerUrl) {
60                        // Externe Website öffnet in neuem Tab, interne Übersicht im selben Tab.
61                        const isExternal = /^https?:\/\//i.test(photographerUrl);
62                        const targetAttr = isExternal ? ' target="_blank" rel="noopener"' : '';
63                        photographerLabel = `<a href="${photographerUrl}"${targetAttr}>${photographer}</a>`;
64                    } else {
65                        photographerLabel = photographer;
66                    }
67                    html += ` © ${photographerLabel}`;
68                }
69                if (wikitypeName) {
70                    html += `, Lizenz: <a href="${wikitypeUrl}" target="_blank" rel="noopener">${wikitypeName}</a>`;
71                }
72                photographerEl.innerHTML = html;
73            }
74        };
75
76        // Rechter Rand von image-photographer am rechten Bildrand ausrichten
77        const updatePhotographerAlignment = (swiper) => {
78            if (!photographerEl) return;
79            const activeSlide = swiper.slides[swiper.activeIndex];
80            if (!activeSlide) return;
81
82            const slideRect = activeSlide.getBoundingClientRect();
83            const cbRect = photographerEl.parentElement.getBoundingClientRect();
84            const rightPad = Math.max(0, cbRect.right - slideRect.right);
85            photographerEl.style.paddingRight = rightPad + 'px';
86            photographerEl.style.textAlign = 'right';
87        };
88
89        const swiperConfig = {
90            centeredSlides: true,
91            initialSlide: 0,
92            spaceBetween: 20,
93            slidesPerView: 'auto',
94            loop: false,
95            allowTouchMove: slideCount > 1,
96            observer: true,
97            observeParents: true,
98            keyboard: {
99                enabled: true,
100                onlyInViewport: true,
101            },
102
103            navigation: {
104                nextEl: '.swiper-button-next',
105                prevEl: '.swiper-button-prev',
106            },
107            thumbs: {
108                swiper: thumbnailSwiper,
109            },
110            on: {
111                init: function () {
112                    updateImageText(this);
113                },
114                afterInit: function () {
115                    updatePhotographerAlignment(this);
116                },
117                slideChange: function () {
118                    if (thumbnailSwiper) {
119                        thumbnailSwiper.slideTo(this.activeIndex);
120                    }
121                    if (captionEl) captionEl.textContent = this.slides[this.activeIndex]?.getAttribute('data-caption') || '';
122                    if (photographerEl) photographerEl.style.opacity = '0';
123                },
124                slideChangeTransitionEnd: function () {
125                    updateImageText(this);
126                    updatePhotographerAlignment(this);
127                    if (photographerEl) photographerEl.style.opacity = '1';
128                },
129            }
130        };
131
132        this.swiper = new Swiper(this.container, swiperConfig);
133
134        const forceReset = () => {
135            if (thumbnailSwiper) {
136                thumbnailSwiper.update();
137                thumbnailSwiper.slideTo(0, 0);
138            }
139            if (this.swiper) {
140                this.swiper.update();
141                this.swiper.slideTo(0, 0);
142                updateImageText(this.swiper);
143            }
144        };
145
146        forceReset();
147
148        setTimeout(forceReset, 100);
149        setTimeout(() => {
150            forceReset();
151            updatePhotographerAlignment(this.swiper);
152            this.container.classList.remove('not-initialized');
153
154            if (infoContainer) infoContainer.classList.remove('not-initialized');
155            const thumbWrapper = document.querySelector('.object-thumbnails-wrapper');
156            if (thumbWrapper) thumbWrapper.classList.remove('not-initialized');
157        }, 500);
158
159        window.addEventListener('resize', () => {
160            if (this.swiper) {
161                updateImageText(this.swiper);
162                updatePhotographerAlignment(this.swiper);
163            }
164        });
165    }
166}

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.