PageSourceSearch

https://www.loisstern.com/templates/aurora-aron/js/main.js?cb=1790858557

js loisstern.com collected 2026-10-05 02:44:52 UTC 7,751 bytes, 235 lines download raw bytes

1(function () {
2    var isLoggedIn = document.body.classList.contains("bodyLoggedIn");
3    var isEditMode = document.body.classList.contains("editMode");
4
5    var root = document.documentElement;
6    var scrollToTopElements = document.querySelectorAll("[data-scrolltotop]");
7
8    // SITE LOAD
9    document.addEventListener("DOMContentLoaded", function () {
10        // if site is already scrolled on page load, add class
11        if (window.scrollY >= 1) {
12            scrollToTopElements.forEach((elem) => {
13                elem.classList.add("scrolled");
14            });
15        }
16    });
17
18    // SCROLL
19    window.addEventListener("scroll", function () {
20        if (window.scrollY >= 1) {
21            scrollToTopElements.forEach((elem) => {
22                elem.classList.add("scrolled");
23            });
24        } else {
25            scrollToTopElements.forEach((elem) => {
26                elem.classList.remove("scrolled");
27            });
28        }
29    });
30
31    // ADD WINDOW HEIGHT VARIABLE
32    var windowHeightEvents = ["load", "resize", "orientationchange"];
33    windowHeightEvents.forEach((event) => {
34        window.addEventListener(event, function (e) {
35            // window.innerWidth returns it including the scrollbar
36            root.style.setProperty("--window-width", getComputedStyle(root).width);
37            root.style.setProperty("--window-height", window.innerHeight + "px");
38        });
39    });
40
41    // ADD SHOW ICON TO EVERY ACTIVE/CURRENT MENU ITEM
42    var activeCurrentNavItems = document.querySelectorAll(".nav-item.l0.active, .nav-item.l0.current");
43    activeCurrentNavItems.forEach((elem) => {
44        elem.classList.add("show");
45    });
46
47    // CLICK EVENT ON SCROLL TO TOP BUTTON
48    scrollToTopElements.forEach((elem) => {
49        elem.addEventListener("click", function () {
50            scrollToTop();
51        });
52    });
53
54    // RESPONSIVE TABLES
55    var tableElems = document.querySelectorAll("section table");
56    function detectScrollbar(elem) {
57        const container = elem.closest(".container") || elem.parentElement;
58        const styles = window.getComputedStyle(container);
59        const totalWidth = container.clientWidth;
60        const paddingLeft = parseFloat(styles.paddingLeft);
61        const paddingRight = parseFloat(styles.paddingRight);
62        const containerWidth = totalWidth - paddingLeft - paddingRight;
63
64        // offsetWidth ist gerundet, die Container-Breite bei Prozent-/vw-Padding nicht (338 > 337.5) -> 1px Toleranz
65        return elem.getBoundingClientRect().width - containerWidth > 1;
66    }
67    tableElems.forEach((elem) => {
68        function handleScrollbar(elem) {
69            var isSmaller = detectScrollbar(elem);
70            if (isSmaller) {
71                wrapper.classList.add("overflow");
72                wrapper.addEventListener("scroll", function (e) {
73                    var pos = wrapper.scrollLeft;
74                    pos > 0 ? wrapper.classList.add("scrolled") : wrapper.classList.remove("scrolled");
75                });
76            } else {
77                wrapper.classList.remove("overflow");
78                wrapper.classList.remove("scrolled");
79            }
80        }
81
82        // create wrapper elem
83        var wrapper = document.createElement("div");
84        wrapper.classList.add("table-responsive");
85
86        // move table inside wrapper elem
87        elem.parentNode.insertBefore(wrapper, elem);
88        wrapper.appendChild(elem);
89
90        // handleScrollbar
91        handleScrollbar(elem);
92
93        // Webfonts aendern die Tabellenbreite nach dem ersten Messen -> erneut pruefen
94        if (document.fonts) {
95            document.fonts.ready.then(function () {
96                handleScrollbar(elem);
97            });
98        }
99
100        window.addEventListener("resize", function (e) {
101            handleScrollbar(elem);
102        });
103    });
104
105    // CALL KLARO WINDOW FROM FOOTER MENU
106    var footers = document.querySelectorAll("ul.footer-nav li a");
107    footers.forEach(function (item) {
108        if (item.innerHTML == "Cookies" || item.innerText == "Cookies") {
109            item.addEventListener("click", function (event) {
110                event.preventDefault();
111                // force klaro window
112                return klaro.show(undefined, true);
113            });
114        }
115    });
116})();
117
118document.addEventListener('DOMContentLoaded', () => {
119	// INIT TOOLTIPS
120	const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]');
121	const tooltipList = [...tooltipTriggerList].map((tooltipTriggerEl) => new bootstrap.Tooltip(tooltipTriggerEl));
122
123	// INIT POPOVERS
124	const popoverTriggerList = document.querySelectorAll('[data-bs-toggle="popover"]');
125	const popoverList = [...popoverTriggerList].map((popoverTriggerEl) => new bootstrap.Popover(popoverTriggerEl));
126});
127
128// SCROLL-TO-TOP FUNCTION
129function scrollToTop() {
130	window.scroll({
131		top: 0,
132		left: 0,
133		behavior: 'smooth',
134	});
135}
136
137document.addEventListener('DOMContentLoaded', () => {
138	const delay = 200;
139	const queue = [];
140	const elements = document.querySelectorAll('.fade-in-left, .fade-in-right, .fade-in-top, .fade-in-bottom');
141	let isProcessing = false;
142
143	const observer = new IntersectionObserver(
144		(entries) => {
145			entries.forEach((entry) => {
146				if (entry.isIntersecting) {
147					queue.push(entry.target);
148					observer.unobserve(entry.target); // only trigger once
149
150					processQueue();
151				}
152			});
153		},
154		{
155			threshold: 0.2,
156		}
157	);
158	const processQueue = () => {
159		if (isProcessing) return;
160		if (queue.length === 0) return;
161
162		isProcessing = true;
163
164		const element = queue.shift();
165
166		element.classList.add('visible');
167
168		setTimeout(() => {
169			isProcessing = false;
170			processQueue();
171		}, delay);
172	};
173
174	for (const element of elements) {
175		observer.observe(element);
176	}
177
178	// Section-Reveals (Setting "Einblende-Effekt") brauchen eine eigene Schwelle: eine Section
179	// kann hoeher als der Viewport sein und dann nie 20 % Sichtbarkeit erreichen.
180	// Im Backend-Editiermodus bleibt alles sichtbar - der Redakteur soll die Seite sehen,
181	// nicht erst hinscrollen muessen.
182	const revealElements = document.body.classList.contains('fw-edit-mode')
183		? []
184		: document.querySelectorAll('[class*="pel-reveal-"]');
185	const revealObserver = new IntersectionObserver(
186		(entries) => {
187			entries.forEach((entry) => {
188				if (entry.isIntersecting) {
189					queue.push(entry.target);
190					revealObserver.unobserve(entry.target);
191
192					processQueue();
193				}
194			});
195		},
196		{
197			rootMargin: '0px 0px -10% 0px',
198		}
199	);
200
201	for (const element of revealElements) {
202		// Startzustand erst per JS setzen - ohne JS bleibt die Section sichtbar statt auf opacity:0
203		element.classList.add('reveal-prep');
204		revealObserver.observe(element);
205	}
206});
207
208// MASKOTTCHEN — Spruchwechsel bei Klick. No-op, solange kein Maskottchen im DOM ist.
209document.addEventListener('DOMContentLoaded', () => {
210	const mascot = document.querySelector('[data-mascot]');
211	if (!mascot) return;
212
213	const bubble = mascot.querySelector('[data-mascot-bubble]');
214	const trigger = mascot.querySelector('.mascot-trigger');
215	const sayings = [...mascot.querySelectorAll('[data-mascot-sayings] li')].map((item) => item.textContent);
216	if (!bubble || !trigger || sayings.length === 0) return;
217
218	// Die Blase zeigt beim Laden bereits Spruch 0 (serverseitig gerendert).
219	let currentIndex = 0;
220	let hideTimeout;
221
222	trigger.addEventListener('click', () => {
223		let nextIndex = currentIndex;
224		while (nextIndex === currentIndex && sayings.length > 1) {
225			nextIndex = Math.floor(Math.random() * sayings.length);
226		}
227
228		currentIndex = nextIndex;
229		bubble.textContent = sayings[nextIndex];
230		mascot.classList.add('speaking');
231
232		clearTimeout(hideTimeout);
233		hideTimeout = setTimeout(() => mascot.classList.remove('speaking'), 5000);
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.