PageSourceSearch

https://www.wiesn.tv/wp-content/themes/jupiter-child/assets/js/mobile-footer-banner.js?ver=1.21.37

js wiesn.tv collected 2026-10-05 08:29:40 UTC 8,192 bytes, 235 lines download raw bytes

1/**
2 * Footer Mobil: sticky Banner unten, Rotation alle 5s, Impression/Klick-Tracking.
3 * Rotation laeuft lokal anhand der einmalig eingebetteten Bannerliste.
4 */
5(function () {
6    'use strict';
7
8    const config = window.wiesnMobileFooterBanner || {};
9    const bannerRoot = document.querySelector('[data-wiesn-mobile-footer-banner]');
10
11    if (!bannerRoot || bannerRoot.getAttribute('data-wiesn-footer-rotator') === '1') {
12        return;
13    }
14
15    bannerRoot.setAttribute('data-wiesn-footer-rotator', '1');
16
17    const banners = Array.isArray(config.banners) ? config.banners.filter((banner) => banner && banner.image) : [];
18    let lastBannerIndex = parseInt(bannerRoot.querySelector('[data-wiesn-mobile-footer-banner-link]')?.dataset.bannerIndex || '-1', 10);
19    const sessionCounts = {};
20    const interval = parseInt(String(config.interval || 5000), 10);
21    let timer = null;
22    const mobileMq = window.matchMedia('(max-width: 1023px)');
23
24    const canStart = () => {
25        if (!banners.length || !mobileMq.matches || document.hidden) {
26            return false;
27        }
28        return !document.body.classList.contains('wiesn-mobile-nav-open');
29    };
30
31    const isPaintedAndActive = () => {
32        if (bannerRoot.hidden) {
33            return false;
34        }
35        if (window.wiesnBannerRuntime && typeof window.wiesnBannerRuntime.isPlacementActive === 'function') {
36            return window.wiesnBannerRuntime.isPlacementActive('mobile_footer', bannerRoot);
37        }
38        const style = window.getComputedStyle(bannerRoot);
39        if (style.display === 'none' || style.visibility === 'hidden') {
40            return false;
41        }
42        const rect = bannerRoot.getBoundingClientRect();
43        return rect.width >= 1 && rect.height >= 1;
44    };
45
46    const pickFair = (list, excludeIndex, counts) => {
47        if (window.wiesnBannerRuntime && typeof window.wiesnBannerRuntime.pickFair === 'function') {
48            return window.wiesnBannerRuntime.pickFair(list, excludeIndex, counts);
49        }
50
51        const poolBase = list.filter((banner) => Number(banner.index) !== Number(excludeIndex));
52        const pool = poolBase.length ? poolBase : list;
53        let best = null;
54        const candidates = [];
55
56        pool.forEach((banner) => {
57            const score = Number(counts[banner.index]) || 0;
58            if (best === null || score < best) {
59                best = score;
60                candidates.length = 0;
61                candidates.push(banner);
62            } else if (score === best) {
63                candidates.push(banner);
64            }
65        });
66
67        return candidates.length ? candidates[Math.floor(Math.random() * candidates.length)] : null;
68    };
69
70    const trackClick = (index) => {
71        if (window.wiesnBannerRuntime && typeof window.wiesnBannerRuntime.isPlatform === 'function' && window.wiesnBannerRuntime.isPlatform()) {
72            return;
73        }
74        if (!config.ajaxUrl || !config.nonce) {
75            return;
76        }
77
78        const params = new URLSearchParams({
79            action: config.actions?.click || 'wiesn_mobile_footer_banner_click',
80            nonce: config.nonce,
81            index: String(index),
82        });
83
84        if (typeof navigator.sendBeacon === 'function') {
85            navigator.sendBeacon(config.ajaxUrl, params);
86            return;
87        }
88
89        fetch(config.ajaxUrl, {
90            method: 'POST',
91            headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
92            body: params.toString(),
93            keepalive: true,
94        }).catch(() => {});
95    };
96
97    const renderBanner = (payload) => {
98        const link = bannerRoot.querySelector('[data-wiesn-mobile-footer-banner-link]');
99        const img = bannerRoot.querySelector('[data-wiesn-mobile-footer-banner-image]');
100
101        if (!(link instanceof HTMLAnchorElement) || !(img instanceof HTMLImageElement) || !payload || !payload.image) {
102            return false;
103        }
104
105        const url = typeof payload.url === 'string' ? payload.url.trim() : '';
106        const alt = typeof payload.alt === 'string' ? payload.alt : '';
107        const index = typeof payload.index === 'number' ? payload.index : parseInt(String(payload.index), 10);
108
109        img.src = payload.image;
110        img.alt = alt;
111        link.dataset.bannerIndex = String(index);
112
113        if (url) {
114            link.href = url;
115            link.removeAttribute('aria-disabled');
116            link.tabIndex = 0;
117        } else {
118            link.removeAttribute('href');
119            link.setAttribute('aria-disabled', 'true');
120            link.tabIndex = -1;
121        }
122
123        bannerRoot.hidden = false;
124        lastBannerIndex = Number.isFinite(index) ? index : lastBannerIndex;
125        sessionCounts[lastBannerIndex] = (sessionCounts[lastBannerIndex] || 0) + 1;
126
127        if (window.wiesnBannerRuntime && typeof window.wiesnBannerRuntime.queueImpression === 'function') {
128            window.wiesnBannerRuntime.queueImpression('mobile_footer', lastBannerIndex, bannerRoot);
129        }
130
131        return true;
132    };
133
134    const refreshBanner = () => {
135        if (!canStart()) {
136            return;
137        }
138        if (!bannerRoot.hidden && !isPaintedAndActive()) {
139            return;
140        }
141
142        const payload = pickFair(banners, lastBannerIndex, sessionCounts);
143
144        if (!payload) {
145            return;
146        }
147
148        renderBanner(payload);
149    };
150
151    const stopTimer = () => {
152        if (timer) {
153            window.clearInterval(timer);
154            timer = null;
155        }
156    };
157
158    const hasPaintedImage = () => {
159        const img = bannerRoot.querySelector('[data-wiesn-mobile-footer-banner-image]');
160        return !bannerRoot.hidden && img instanceof HTMLImageElement && !!img.getAttribute('src');
161    };
162
163    const recordShown = (index) => {
164        if (!Number.isFinite(index) || index < 0) {
165            return;
166        }
167        lastBannerIndex = index;
168        sessionCounts[lastBannerIndex] = (sessionCounts[lastBannerIndex] || 0) + 1;
169        if (window.wiesnBannerRuntime && typeof window.wiesnBannerRuntime.queueImpression === 'function') {
170            window.wiesnBannerRuntime.queueImpression('mobile_footer', lastBannerIndex, bannerRoot);
171        }
172    };
173
174    const startTimer = () => {
175        stopTimer();
176        if (interval > 0 && banners.length > 1 && canStart()) {
177            timer = window.setInterval(() => {
178                refreshBanner();
179            }, interval);
180        }
181    };
182
183    let running = false;
184    let initialCounted = false;
185
186    const syncPlacement = () => {
187        if (canStart()) {
188            if (!running) {
189                running = true;
190                if (hasPaintedImage()) {
191                    if (!initialCounted) {
192                        recordShown(lastBannerIndex);
193                        initialCounted = true;
194                    }
195                } else {
196                    refreshBanner();
197                    initialCounted = true;
198                }
199                startTimer();
200            }
201            return;
202        }
203        running = false;
204        stopTimer();
205    };
206
207    const link = bannerRoot.querySelector('[data-wiesn-mobile-footer-banner-link]');
208    if (link instanceof HTMLAnchorElement) {
209        link.addEventListener('click', (event) => {
210            const index = parseInt(link.dataset.bannerIndex || '-1', 10);
211            if (index < 0 || !link.href || link.href === '#') {
212                event.preventDefault();
213                return;
214            }
215            trackClick(index);
216        });
217    }
218
219    syncPlacement();
220
221    if (typeof mobileMq.addEventListener === 'function') {
222        mobileMq.addEventListener('change', syncPlacement);
223    } else if (typeof mobileMq.addListener === 'function') {
224        mobileMq.addListener(syncPlacement);
225    }
226
227    window.addEventListener('resize', syncPlacement);
228    document.addEventListener('visibilitychange', syncPlacement);
229    document.addEventListener('wiesn-mobile-nav-open', syncPlacement);
230    document.addEventListener('wiesn-mobile-nav-close', syncPlacement);
231
232    window.addEventListener('pagehide', () => {
233        stopTimer();
234    });
235})();

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.