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.