PageSourceSearch

https://www.wattner.de/wp-content/themes/kreativ-design/assets/js/main.js?ver=1.2.0

js wattner.de collected 2026-09-30 18:00:42 UTC 19,401 bytes, 579 lines download raw bytes

1function kd_page_scrolled() {
2    const body = document.body;
3
4    function handleScroll() {
5        if (window.scrollY > 100) {
6            body.classList.add('is-scrolled');
7        } else {
8            body.classList.remove('is-scrolled');
9        }
10    }
11
12    window.addEventListener('scroll', handleScroll);
13    window.addEventListener('load', handleScroll);
14
15    handleScroll();
16}
17
18function kd_meganav_toggler() {
19    document.querySelectorAll('.kd-navlist > li').forEach(li => {
20        if (li.querySelector('ul')) {
21            li.classList.add('has-children');
22        }
23    });
24
25    document.querySelectorAll('.kd-navlist > li.has-children > a').forEach(link => {
26        link.addEventListener('click', function(e) {
27            e.preventDefault();
28
29            const parentLi = this.parentElement;
30            const isOpened = parentLi.classList.contains('is-opened');
31
32            closeAllMenus();
33
34            if (!isOpened) {
35                document.querySelectorAll('.kd-navbar-expand').forEach(nav => {
36                    nav.classList.add('is-meganav-enabled');
37                });
38
39                parentLi.classList.add('is-opened');
40            }
41        });
42    });
43
44    document.addEventListener('click', function(e) {
45        if (!e.target.closest('.kd-navlist')) {
46            closeAllMenus();
47        }
48    });
49
50    // Hamburger menu functionality
51    const hamburger = document.querySelector('.kd-hamburger');
52    if (hamburger) {
53        hamburger.addEventListener('click', function(e) {
54            e.preventDefault();
55
56            const navbar = document.querySelector('.kd-navbar');
57            if (navbar) {
58                navbar.classList.toggle('is-meganav-opened');
59            }
60        });
61    }
62
63    function closeAllMenus() {
64        document.querySelectorAll('.kd-navbar-expand').forEach(nav => {
65            nav.classList.remove('is-meganav-enabled');
66        });
67
68        document.querySelectorAll('.kd-navlist > li.has-children').forEach(li => {
69            li.classList.remove('is-opened');
70        });
71    }
72}
73
74function kd_contact_handler() {
75    const emailRadio = document.querySelector('input[name="contact_type"][value="via E-Mail"]');
76    const phoneRadio = document.querySelector('input[name="contact_type"][value="via Telefon"]');
77    const emailField = document.querySelector('input[name="user_mail"]')?.closest('p');
78    const phoneField = document.querySelector('input[name="user_phone"]')?.closest('p');
79    
80    if ( !emailRadio || !phoneRadio || !emailField || !phoneField ) return;
81
82    if (emailRadio) {
83        emailRadio.checked = true;
84    }
85
86    const toggleFieldsVisibility = () => {
87        if (emailRadio && emailRadio.checked) {
88            emailField.style.display = 'block';
89            phoneField.style.display = 'none';
90        } else if (phoneRadio && phoneRadio.checked) {
91            emailField.style.display = 'none';
92            phoneField.style.display = 'block';
93        }
94    };
95
96    if (emailRadio) {
97        emailRadio.addEventListener('change', toggleFieldsVisibility);
98    }
99
100    if (phoneRadio) {
101        phoneRadio.addEventListener('change', toggleFieldsVisibility);
102    }
103
104    toggleFieldsVisibility();
105}
106
107function kd_footer_quick_links() {
108    const headings = document.querySelectorAll('.wp-block-group h6.wp-block-heading');
109
110    function handleClick(event) {
111        if (window.innerWidth <= 767) {
112            const parentGroup = this.closest('.wp-block-group');
113
114            if (parentGroup) {
115                parentGroup.classList.toggle('is-opened');
116            }
117        }
118    }
119
120    headings.forEach(heading => {
121        heading.addEventListener('click', handleClick);
122    });
123}
124
125function kdInView(selector, className, threshold = 1.0) {
126    const elements = document.querySelectorAll(selector);
127
128    if (elements.length === 0) {
129        console.warn(`No elements found for selector "${selector}"`);
130        return;
131    }
132
133    const observer = new IntersectionObserver((entries) => {
134        entries.forEach(entry => {
135            if (entry.isIntersecting && entry.intersectionRatio >= threshold) {
136                entry.target.classList.add(className);
137                observer.unobserve(entry.target);
138            }
139        });
140    }, {
141        threshold: threshold
142    });
143
144    elements.forEach(element => {
145        observer.observe(element);
146    });
147}
148
149function initWattnerCarousel() {
150    const carousels = document.querySelectorAll('.wattner-carousel');
151
152    carousels.forEach(carousel => {
153        const slides = Array.from(carousel.children);
154        const totalSlides = slides.length;
155
156        if (totalSlides <= 1) return;
157
158        let currentIndex = 0;
159
160        carousel.classList.add('carousel-initialized');
161
162        const slidesWrapper = document.createElement('div');
163        slidesWrapper.className = 'carousel-slides-wrapper';
164
165        const slidesContainer = document.createElement('div');
166        slidesContainer.className = 'carousel-slides';
167
168        slides.forEach(slide => {
169            slide.classList.add('carousel-slide');
170            slidesContainer.appendChild(slide);
171        });
172
173        slidesWrapper.appendChild(slidesContainer);
174
175        const navigation = document.createElement('div');
176        navigation.className = 'carousel-navigation';
177
178        const prevButton = document.createElement('button');
179        prevButton.className = 'carousel-nav carousel-prev';
180        prevButton.innerHTML = '‹';
181        prevButton.setAttribute('aria-label', 'Previous slide');
182
183        const nextButton = document.createElement('button');
184        nextButton.className = 'carousel-nav carousel-next';
185        nextButton.innerHTML = '›';
186        nextButton.setAttribute('aria-label', 'Next slide');
187
188        const indicator = document.createElement('div');
189        indicator.className = 'carousel-indicator';
190
191        carousel.appendChild(slidesWrapper);
192        navigation.appendChild(prevButton);
193        navigation.appendChild(indicator);
194        navigation.appendChild(nextButton);
195        carousel.appendChild(navigation);
196
197        /**
198         * Updates carousel position and navigation state
199         */
200        function updateCarousel() {
201            slidesContainer.style.transform = `translateX(-${currentIndex * 100}%)`;
202            indicator.textContent = `${currentIndex + 1} / ${totalSlides}`;
203
204            prevButton.disabled = currentIndex === 0;
205            nextButton.disabled = currentIndex === totalSlides - 1;
206        }
207
208        /**
209         * Navigate to specific slide index
210         */
211        function goToSlide(index) {
212            if (index >= 0 && index < totalSlides) {
213                currentIndex = index;
214                updateCarousel();
215            }
216        }
217
218        function nextSlide() {
219            goToSlide(currentIndex + 1);
220        }
221
222        function prevSlide() {
223            goToSlide(currentIndex - 1);
224        }
225
226        function goToFirst() {
227            goToSlide(0);
228        }
229
230        function goToLast() {
231            goToSlide(totalSlides - 1);
232        }
233
234        /**
235         * Handle keyboard navigation for accessibility
236         */
237        function handleKeyboardNavigation(e) {
238            if (document.activeElement !== carousel) return;
239
240            switch (e.key) {
241                case 'ArrowLeft':
242                    prevSlide();
243                    e.preventDefault();
244                    break;
245                case 'ArrowRight':
246                    nextSlide();
247                    e.preventDefault();
248                    break;
249                case 'Home':
250                    goToFirst();
251                    e.preventDefault();
252                    break;
253                case 'End':
254                    goToLast();
255                    e.preventDefault();
256                    break;
257            }
258        }
259
260        prevButton.addEventListener('click', prevSlide);
261        nextButton.addEventListener('click', nextSlide);
262        carousel.addEventListener('keydown', handleKeyboardNavigation);
263
264        slides.forEach(slide => {
265            slide.setAttribute('role', 'group');
266            slide.setAttribute('aria-roledescription', 'slide');
267        });
268
269        let startX = 0;
270        let startY = 0;
271        let isDragging = false;
272        let isHorizontalSwipe = false;
273
274        /**
275         * Touch event handlers for mobile swipe navigation
276         */
277        slidesContainer.addEventListener('touchstart', (e) => {
278            startX = e.touches[0].clientX;
279            startY = e.touches[0].clientY;
280            isDragging = true;
281            isHorizontalSwipe = false;
282        });
283
284        slidesContainer.addEventListener('touchmove', (e) => {
285            if (!isDragging) return;
286
287            const currentX = e.touches[0].clientX;
288            const currentY = e.touches[0].clientY;
289            const diffX = Math.abs(currentX - startX);
290            const diffY = Math.abs(currentY - startY);
291
292            if (diffX > 10 || diffY > 10) {
293                isHorizontalSwipe = diffX > diffY;
294
295                if (isHorizontalSwipe) {
296                    e.preventDefault();
297                }
298            }
299        });
300
301        slidesContainer.addEventListener('touchend', (e) => {
302            if (!isDragging) return;
303            isDragging = false;
304
305            if (isHorizontalSwipe) {
306                const endX = e.changedTouches[0].clientX;
307                const diffX = startX - endX;
308
309                if (Math.abs(diffX) > 50) {
310                    if (diffX > 0) {
311                        nextSlide();
312                    } else {
313                        prevSlide();
314                    }
315                }
316            }
317        });
318
319        carousel.setAttribute('tabindex', '0');
320        carousel.setAttribute('role', 'region');
321        carousel.setAttribute('aria-label', 'Image carousel');
322
323        updateCarousel();
324    });
325}
326
327function initWattnerTabs() {
328    function createTabNav(container) {
329        const children = Array.from(container.children);
330        const navWrapper = document.createElement('div');
331        const contentWrapper = document.createElement('div');
332
333        navWrapper.className = 'wattner-tab-nav';
334        contentWrapper.className = 'wattner-tab-contents';
335
336        children.forEach(child => {
337            const heading = child.querySelector('.wp-block-heading:first-of-type');
338
339            if (heading) {
340                const navLink = document.createElement('a');
341                navLink.textContent = heading.textContent;
342                navWrapper.appendChild(navLink);
343            }
344
345            contentWrapper.appendChild(child);
346        });
347
348        container.appendChild(navWrapper);
349        container.appendChild(contentWrapper);
350    }
351
352    function setActiveTab(container, activeIndex) {
353        const navItems = container.querySelectorAll('.wattner-tab-nav > a');
354        const contentItems = container.querySelectorAll('.wattner-tab-contents > *');
355
356        navItems.forEach((nav, index) => {
357            const isActive = index === activeIndex;
358            nav.classList.toggle('wattner-tab-nav-active', isActive);
359            nav.classList.toggle('wattner-tab-nav-inactive', !isActive);
360            nav.setAttribute('aria-selected', isActive.toString());
361        });
362
363        contentItems.forEach((content, index) => {
364            const isActive = index === activeIndex;
365            content.classList.toggle('wattner-tab-content-active', isActive);
366            content.classList.toggle('wattner-tab-content-inactive', !isActive);
367        });
368    }
369
370    const tabContainers = document.querySelectorAll('.wattner-tabs');
371
372    tabContainers.forEach(container => {
373        createTabNav(container);
374
375        const navWrapper = container.querySelector('.wattner-tab-nav');
376        const navItems = navWrapper.querySelectorAll('a');
377
378        navItems.forEach((navItem, index) => {
379            navItem.addEventListener('click', (e) => {
380                e.preventDefault();
381                setActiveTab(container, index);
382            });
383
384            navItem.setAttribute('role', 'tab');
385            navItem.setAttribute('tabindex', '0');
386            navItem.setAttribute('aria-selected', 'false');
387            navItem.setAttribute('href', '#');
388
389            navItem.addEventListener('keydown', (e) => {
390                if (e.key === 'Enter' || e.key === ' ') {
391                    e.preventDefault();
392                    setActiveTab(container, index);
393                }
394            });
395        });
396
397        navWrapper.setAttribute('role', 'tablist');
398
399        setActiveTab(container, 0);
400    });
401}
402
403/**
404 * Initialize contact filter functionality for all contact selectors on the page
405 */
406function initContactFilters() {
407    var contactSelectors = document.querySelectorAll('.wattner-contact-selector');
408    
409    contactSelectors.forEach(function(selector) {
410        var dropdownId = selector.getAttribute('data-dropdown-id');
411        var contentId = selector.getAttribute('data-content-id');
412        var buttonText = selector.getAttribute('data-button-text');
413        var ajaxUrl = selector.getAttribute('data-ajax-url');
414        var nonce = selector.getAttribute('data-nonce');
415        
416        var dropdown = document.getElementById(dropdownId);
417        var container = document.getElementById(contentId);
418        
419        if (!dropdown || !container) {
420            return;
421        }
422
423        dropdown.addEventListener('change', function() {
424            var termId = this.value;
425            var action = termId ? 'wattner_get_contact' : 'wattner_get_default_contact';
426            
427            container.classList.add('loading');
428
429            var xhr = new XMLHttpRequest();
430            xhr.open('POST', ajaxUrl, true);
431            xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
432            
433            xhr.onreadystatechange = function() {
434                if (xhr.readyState === 4) {
435                    container.classList.remove('loading');
436                    
437                    if (xhr.status === 200) {
438                        try {
439                            var response = JSON.parse(xhr.responseText);
440                            if (response.success && response.data && response.data.html) {
441                                container.innerHTML = response.data.html;
442                                container.style.display = 'block';
443                            } else {
444                                console.error('Contact AJAX Error:', response.data ? response.data.message : 'Unknown error');
445                                container.innerHTML = '<p>Error loading contact information.</p>';
446                            }
447                        } catch (e) {
448                            console.error('Contact AJAX Parse Error:', e);
449                            container.innerHTML = '<p>Error loading contact information.</p>';
450                        }
451                    } else {
452                        console.error('Contact AJAX HTTP Error:', xhr.status);
453                        container.innerHTML = '<p>Error loading contact information.</p>';
454                    }
455                }
456            };
457
458            var params = 'action=' + action + 
459                        '&nonce=' + encodeURIComponent(nonce) +
460                        '&button_text=' + encodeURIComponent(buttonText);
461            
462            if (termId) {
463                params += '&term_id=' + encodeURIComponent(termId);
464            }
465
466            xhr.send(params);
467        });
468    });
469}
470
471function initSharePost() {
472    const shareWidgets = document.querySelectorAll( '.wattner-share-widget' );
473
474    shareWidgets.forEach( function( widget ) {
475        const select = widget.querySelector( '.wattner-channel-select' );
476        const button = widget.querySelector( '.wattner-share-button' );
477
478        function updateButtonState() {
479            if ( select.value ) {
480                button.disabled = false;
481                button.style.opacity = '1';
482            } else {
483                button.disabled = true;
484                button.style.opacity = '0.5';
485            }
486        }
487
488        function shareContent() {
489            const selectedUrl = select.value;
490            if ( selectedUrl ) {
491                if ( selectedUrl.startsWith( 'mailto:' ) ) {
492                    window.location.href = selectedUrl;
493                } else {
494                    window.open( selectedUrl, '_blank', 'width=600,height=400,scrollbars=yes,resizable=yes' );
495                }
496            }
497        }
498
499        updateButtonState();
500
501        select.addEventListener( 'change', updateButtonState );
502        button.addEventListener( 'click', shareContent );
503
504        select.addEventListener( 'keypress', function( e ) {
505            if ( e.key === 'Enter' ) {
506                shareContent();
507            }
508        });
509    });
510}
511
512function initWattnerAccordion() {
513    const accordions = document.querySelectorAll('.wattner-accordion');
514    
515    accordions.forEach(accordion => {
516        const accordionItems = accordion.querySelectorAll(':scope > .wp-block-group');
517        
518        accordionItems.forEach((item, index) => {
519            const heading = item.querySelector('.wp-block-heading');
520            if (!heading) return;
521            
522            const content = Array.from(item.children).filter(child => !child.classList.contains('wp-block-heading'));
523            
524            heading.style.cursor = 'pointer';
525            heading.setAttribute('role', 'button');
526            heading.setAttribute('aria-expanded', 'false');
527            heading.setAttribute('tabindex', '0');
528            
529            content.forEach(contentEl => {
530                contentEl.style.display = 'none';
531                contentEl.setAttribute('aria-hidden', 'true');
532            });
533            
534            const toggleSection = () => {
535                const isExpanded = heading.getAttribute('aria-expanded') === 'true';
536                
537                if (isExpanded) {
538                    heading.setAttribute('aria-expanded', 'false');
539                    heading.classList.remove('accordion-active');
540                    content.forEach(contentEl => {
541                        contentEl.style.display = 'none';
542                        contentEl.setAttribute('aria-hidden', 'true');
543                    });
544                } else {
545                    heading.setAttribute('aria-expanded', 'true');
546                    heading.classList.add('accordion-active');
547                    content.forEach(contentEl => {
548                        contentEl.style.display = 'block';
549                        contentEl.setAttribute('aria-hidden', 'false');
550                    });
551                }
552            };
553            
554            heading.addEventListener('click', toggleSection);
555            heading.addEventListener('keydown', (e) => {
556                if (e.key === 'Enter' || e.key === ' ') {
557                    e.preventDefault();
558                    toggleSection();
559                }
560            });
561        });
562    });
563}
564
565document.addEventListener('DOMContentLoaded', () => {
566    kd_page_scrolled();
567    kd_meganav_toggler();
568    kd_contact_handler();
569    kd_footer_quick_links();
570    initWattnerCarousel();
571    initWattnerTabs();
572    initContactFilters();
573    initSharePost();
574    initWattnerAccordion();
575
576    if (window.matchMedia('(max-width: 1099)').matches) {
577        kdInView('#kd_news .wp-query-loop-posts', 'section-in-view', 0.5);
578    }
579});

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.