1'use strict'; 2var warning=""; 3var base=""; 4var baseTitle=""; 5var page=""; 6var fhQuery=""; 7var popupStatus = 0; 8var scroll_container_padding_horizontal=0; 9var scrollwait=false; 10var runtimes=0; 11var active=[]; 12var lazyLoader; 13 14function warnme(b64_warning) { 15 if(b64_warning!="") { 16 window.setTimeout('fancyAlert(\''+b64_warning+'\')',1); 17 } 18} 19 20function fancyAlert(b64_warning) { 21 let warning = ""; 22 try { 23 warning = decodeBase64(b64_warning); 24 } 25 catch { 26 alert('Fehler in Hinweismodul'); 27 } 28 29 if(!warning || warning == "") { 30 return; 31 } 32 33 $.confirm({ 34 title: 'Hinweis', 35 content: warning, 36 animation: 'none', 37 typeAnimated: false, 38 boxWidth: 'clamp(300px, 30vw, 50%)', 39 useBootstrap: false, 40 buttons: { 41 ok: { 42 text: "OK", 43 btnClass: 'btn-primary', 44 keys: ['enter','esc','space'], 45 }, 46 } 47 }); 48 return; 49} 50 51function decodeBase64(base64) { 52 const text = atob(base64); 53 const length = text.length; 54 const bytes = new Uint8Array(length); 55 for (let i = 0; i < length; i++) { 56 bytes[i] = text.charCodeAt(i); 57 } 58 const decoder = new TextDecoder(); // default is utf-8 59 return decoder.decode(bytes); 60} 61 62 63 64function blur_it() { 65 var alla=document.getElementsByTagName('a'); 66 if(alla) { 67 for(var i=0; i<alla.length;i++) { 68 if(alla[i]) 69 alla[i].onfocus=new Function('if(this.blur)this.blur();'); 70 } 71 } 72} 73 74/** Start-page featured carousel (#startRotate): init only when wide; re-run after narrowâwide resize. */ 75function initFeaturedStartSlider() { 76 var slider = $('#startRotate.slider'); 77 if (!slider.length) { 78 return; 79 } 80 if (!window.matchMedia || window.matchMedia('(max-width: 768px)').matches) { 81 return; 82 } 83 if (slider.data('featuredSliderBound')) { 84 var slidesFix = slider.find('ul li'); 85 if (slidesFix.length > 1 && slidesFix.filter('.active').length === 0) { 86 slidesFix.removeClass('active'); 87 slidesFix.first().addClass('active'); 88 } 89 return; 90 } 91 92 var slides = slider.find('ul li'); 93 var slideCount = slides.length; 94 var currentSlide = 0; 95 var autoplayInterval; 96 var isPlaying = true; 97 98 if (slideCount > 1) { 99 currentSlide = slides.index(slides.filter('.active')); 100 if (currentSlide === -1) { 101 currentSlide = 0; 102 slides.first().addClass('active'); 103 } 104 105 slides.each(function(index) { 106 var slide = $(this); 107 var interactiveElements = slide.find('a, button, input, select, textarea, [tabindex]:not([tabindex="-1"])'); 108 109 if (index === currentSlide) { 110 interactiveElements.each(function() { 111 $(this).removeAttr('tabindex'); 112 }); 113 slide.removeAttr('aria-hidden'); 114 } else { 115 interactiveElements.each(function() { 116 $(this).attr('tabindex', '-1'); 117 }); 118 slide.attr('aria-hidden', 'true'); 119 } 120 }); 121 122 var paginationHtml = '<div class="simple-pagination">'; 123 for (var i = 0; i < slideCount; i++) { 124 paginationHtml += '<button class="simple-dot' + (i === currentSlide ? ' active' : '') + '" data-slide="' + i + '" aria-label="Go to slide ' + (i + 1) + '"></button>'; 125 } 126 paginationHtml += '</div>'; 127 slider.append(paginationHtml); 128 129 function nextSlide() { 130 if (!isPlaying) { 131 return; 132 } 133 var nextIndex = (currentSlide + 1) % slideCount; 134 transitionToSlide(nextIndex); 135 } 136 137 function goToSlide(index) { 138 if (index === currentSlide) { 139 return; 140 } 141 transitionToSlide(index); 142 } 143 144 function transitionToSlide(index) { 145 var currentSlideEl = slides.eq(currentSlide); 146 currentSlideEl.removeClass('active'); 147 var interactiveElements = currentSlideEl.find('a, button, input, select, textarea, [tabindex]:not([tabindex="-1"])'); 148 interactiveElements.each(function() { 149 $(this).attr('tabindex', '-1'); 150 }); 151 currentSlideEl.attr('aria-hidden', 'true'); 152 153 currentSlide = index; 154 155 var newSlideEl = slides.eq(currentSlide); 156 newSlideEl.addClass('active'); 157 var activeInteractiveElements = newSlideEl.find('a, button, input, select, textarea, [tabindex="-1"]'); 158 activeInteractiveElements.each(function() { 159 $(this).removeAttr('tabindex'); 160 }); 161 newSlideEl.removeAttr('aria-hidden'); 162 163 updatePagination(); 164 } 165 166 function updatePagination() { 167 slider.find('.simple-dot').removeClass('active').eq(currentSlide).addClass('active'); 168 } 169 170 function startAutoplay() { 171 stopAutoplay(); 172 autoplayInterval = setInterval(nextSlide, 8000); 173 slider.data('featuredAutoplayId', autoplayInterval); 174 } 175 176 function stopAutoplay() { 177 if (autoplayInterval) { 178 clearInterval(autoplayInterval); 179 autoplayInterval = null; 180 } 181 slider.removeData('featuredAutoplayId'); 182 } 183 184 function attachPaginationEvents() { 185 slider.find('.simple-dot').each(function() { 186 var $button = $(this); 187 $button.on('click', function(e) { 188 e.preventDefault(); 189 var slideIndex = parseInt($button.data('slide'), 10); 190 goToSlide(slideIndex); 191 stopAutoplay(); 192 isPlaying = false;
193 }); 194 $button.on('keydown', function(e) { 195 if (e.key === 'Enter' || e.key === ' ') { 196 e.preventDefault(); 197 var slideIndex = parseInt($button.data('slide'), 10); 198 goToSlide(slideIndex); 199 stopAutoplay(); 200 isPlaying = false; 201 } 202 }); 203 }); 204 } 205 206 attachPaginationEvents(); 207 startAutoplay(); 208 } 209 210 slider.data('featuredSliderBound', true); 211} 212 213function registerFeaturedSliderViewportListener() { 214 if (window.__featuredSliderMqRegistered) { 215 return; 216 } 217 window.__featuredSliderMqRegistered = true; 218 var mq = window.matchMedia('(max-width: 768px)'); 219 function onMqChange() { 220 if (mq.matches) { 221 var s = $('#startRotate.slider'); 222 var iv = s.data('featuredAutoplayId'); 223 if (iv) { 224 clearInterval(iv); 225 s.removeData('featuredAutoplayId'); 226 } 227 /* Allow a later widen to run full init again (autoplay + dots), without stacking handlers. */ 228 s.find('.simple-pagination').remove(); 229 s.removeData('featuredSliderBound'); 230 } else { 231 initFeaturedStartSlider(); 232 } 233 } 234 if (typeof mq.addEventListener === 'function') { 235 mq.addEventListener('change', onMqChange); 236 } else if (typeof mq.addListener === 'function') { 237 mq.addListener(onMqChange); 238 } 239} 240 241var rowScrollThrottled = _.throttle(callRowPaginationSingle, 250, { leading: true, trailing: true }); 242 243function bindRowScrollEvents($rows) { 244 $rows.find('.content_row_scroll').on("scroll", rowScrollThrottled); 245} 246 247$(document).ready(function() { 248 initManualLoadMoreMode(); 249 250 $(document).keyup(function(e){ 251 if(e.which==27 && popupStatus==1){ 252 disablePopup(); 253 } 254 }); 255 256 $('#input_top_search_button').click(function(r) { 257 if($('#input_top_search').val()=="Suche...") { 258 return false; 259 } 260 document.getElementById('top_search').submit(); 261 }); 262 263 $('#input_top_search').click(function(r) { 264 if($(this).val()=="Suche...") { 265 $(this).val(''); 266 } 267 }); 268 269 $('.mobileMenuButton').on('click keydown', function(e) { 270 if (e.type === 'keydown' && e.key !== 'Enter' && e.key !== ' ') return; 271 if (e.type === 'keydown') e.preventDefault(); 272 e.preventDefault(); 273 $('.mm_toggle').toggle(); 274 }); 275 276 $('.top_categories_click>p').on('click keydown', function(e) { 277 if (e.type === 'keydown' && e.key !== 'Enter' && e.key !== ' ') return; 278 if (e.type === 'keydown') e.preventDefault(); 279 e.preventDefault(); 280 $('.top_categories_list').toggle(); 281 }); 282 $('.top_info_click>p').on('click keydown', function(e) { 283 if (e.type === 'keydown' && e.key !== 'Enter' && e.key !== ' ') return; 284 if (e.type === 'keydown') e.preventDefault(); 285 e.preventDefault(); 286 $('.top_info_list').toggle(); 287 }); 288 289 if(isTouchDevice()) { 290 $('.top_login').on('click keydown', (e) => { 291 /* Burger nav (â¤768px): submenu is always stacked in-panel â no desktop dropdown toggle. */ 292 if (window.matchMedia('(max-width: 768px)').matches) { 293 return; 294 } 295 if (e.type === 'keydown' && e.key !== 'Enter' && e.key !== ' ') return; 296 if (e.type === 'keydown') e.preventDefault(); 297 $('.top_usermenu').toggleClass('dd_visible'); 298 }); 299 } 300 else { 301 $('.top_login').removeClass('top_login_hover').addClass('top_login_hover'); 302 } 303 304 initFeaturedStartSlider(); 305 registerFeaturedSliderViewportListener(); 306 307 if(fhQuery!='') { 308 openForm(fhQuery); 309 } 310 $('#content').on('click keydown', '.scrollArrow', function(e) { 311 if (e.type === 'keydown' && e.key !== 'Enter' && e.key !== ' ') return; 312 if (e.type === 'keydown') e.preventDefault(); 313 var targ=$(this).data('target'); 314 var elcnt=$(this).data('elcnt'); 315 if($(this).data('dir')=="left") { 316 var dir=-1; 317 } else { 318 var dir=1; 319 } 320 scrollRow("#"+targ,dir,elcnt); 321 }); 322 $('.open_target_element').on('click keydown', function(e) { 323 if (e.type === 'keydown' && e.key !== 'Enter' && e.key !== ' ') return; 324 if (e.type === 'keydown') e.preventDefault(); 325 e.preventDefault(); 326 openTargetElement($(this)); 327 }); 328 329 $('.news_menu_year').off('click keydown').on('click keydown', function (e) { 330 if (e.type === 'keydown' && e.key !== 'Enter' && e.key !== ' ') return; 331 if (e.type === 'keydown') e.preventDefault(); 332 let jahr=$(this).data('jahr'); 333 $('.news_menu_'+jahr).toggle(); 334 var toggle_icon='-'; 335 // var toggle_icon='â²'; 336 if($('.news_menu_'+jahr).is(':hidden')) { 337 toggle_icon='+'; 338 // var toggle_icon='â¼'; 339 } 340 $('.news_menu_toggle_icon_'+jahr).html(toggle_icon); 341 }); 342 343 $('.content_row_scroll').on("scroll", rowScrollThrottled); 344 $('.img_popup').off('click keydown').on('click keydown', function (e) { 345 if (e.type === 'keydown' && e.key !== 'Enter' && e.key !== ' ') return; 346 if (e.type === 'keydown') e.preventDefault(); 347 showImage($(this)); 348 }); 349 350 callRowPaginationFull(); 351 352 $('.product_full_media_thumb').on('click keydown', function(e) { 353 if (e.type === 'keydown' && e.key !== 'Enter' && e.key !== ' ') return; 354 if (e.type === 'keydown') e.preventDefault(); 355 setProdMainImg($(this)); 356 }); 357 358 warnme(warning); 359}); 360 361window.onpopstate = function(event) { 362 if(event.state && event.state.tt!=undefined) { 363 contentElementName=event.state.ce; 364 targetElementName=event.state.te; 365 targetTitle=event.state.tt; 366 document.title=baseTitle+" - "+targetTitle; 367 openTargetElement('',event.state); 368 } 369}; 370
371function isManualLoadMoreMode() { 372 if (!window.matchMedia) return false; 373 var m = window.matchMedia('(max-width: 1024px)').matches; 374 var t = isTouchDevice(); 375 return m && t; 376} 377var hsManualLoadModeInitialized = false; 378 379function syncScrollLoaderPosition() { 380 var scrollLoaderElement = $('#scrollLoader'); 381 if (scrollLoaderElement.length < 1) { 382 return; 383 } 384 var visibleRows = $('.content_row').filter(function() { 385 return !$(this).hasClass('loaderhide'); 386 }); 387 if (visibleRows.length > 0) { 388 scrollLoaderElement.insertAfter(visibleRows.last()); 389 } else { 390 var firstHidden = $('.content_row.loaderhide').first(); 391 if (firstHidden.length > 0) { 392 scrollLoaderElement.insertBefore(firstHidden); 393 } 394 } 395} 396 397function normalizeManualRows() { 398 $('.content_row') 399 .not('.hs-manual-visible') 400 .addClass('loaderhide hs-manual-hidden') 401 .hide(); 402 $('.content_row.hs-manual-visible') 403 .removeClass('loaderhide hs-manual-hidden') 404 .show(); 405 syncScrollLoaderPosition(); 406} 407 408function bootstrapRowLoaderState() { 409 if (!isManualLoadMoreMode()) { 410 return; 411 } 412 var initialVisibleBudget = (window.innerHeight && window.innerHeight < 750) ? 6 : 8; 413 var allRows = $('.content_row'); 414 allRows 415 .removeClass('hs-manual-visible') 416 .addClass('loaderhide hs-manual-hidden') 417 .hide(); 418 allRows 419 .slice(0, initialVisibleBudget) 420 .addClass('hs-manual-visible') 421 .removeClass('loaderhide hs-manual-hidden') 422 .show(); 423 var visibleRows = allRows.slice(0, initialVisibleBudget); 424 visibleRows.each(function() { 425 callRowPaginationSingle($(this)); 426 }); 427 normalizeManualRows(); 428} 429 430function initManualLoadMoreMode() { 431 if (!isManualLoadMoreMode()) { 432 hsManualLoadModeInitialized = false; 433 return; 434 } 435 // Bootstrap rows only once; keep trying to init the button if it wasn't in the DOM yet 436 if (!hsManualLoadModeInitialized) { 437 bootstrapRowLoaderState(); 438 hsManualLoadModeInitialized = true; 439 } 440 var scrollLoader = $('#scrollLoader'); 441 if (scrollLoader.length < 1) { 442 scrollLoader = $(document.getElementById('scrollLoader')); 443 } 444 if (scrollLoader.length > 0 && !scrollLoader.data('hs-loader-init')) { 445 ensureScrollLoaderButton(scrollLoader); 446 scrollLoader.data('hs-loader-init', true); 447 } 448} 449 450function loadNextContentRowAjax(scrollLoaderElement, count, onComplete) { 451 if (!scrollLoaderElement || scrollLoaderElement.length < 1) { 452 if (typeof onComplete === 'function') { onComplete(); } 453 return false; 454 } 455 if (!window.HS_ROW_INDEX || window.HS_ROW_INDEX.length === 0) { 456 if (typeof onComplete === 'function') { onComplete(); } 457 return false; 458 } 459 if (scrollLoaderElement.data('hs-ajax-loading')) { 460 return true; 461 } 462 var target = Math.max(1, Number(count) || 4); 463 var batch = window.HS_ROW_INDEX.splice(0, target); 464 if (batch.length === 0) { 465 if (typeof onComplete === 'function') { onComplete(); } 466 return false; 467 } 468 var serieIds = batch.map(function(r) { return r.serie_id; }); 469 var offset = batch[0].id; 470 scrollLoaderElement.data('hs-ajax-loading', true); 471 $.ajax({ 472 url: 'index.php?c=load-rows', 473 type: 'POST', 474 data: { 475 serie_ids: serieIds.join(','), 476 offset: offset 477 }, 478 success: function(response) { 479 scrollLoaderElement.removeData('hs-ajax-loading'); 480 if (response.html) { 481 var newRows = $(response.html); 482 newRows.removeClass('loaderhide hs-manual-hidden').show(); 483 newRows.addClass('hs-manual-visible'); 484 var $lastRow = $('.content_row').last(); 485 if ($lastRow.length > 0) { 486 $lastRow.after(newRows); 487 } else { 488 scrollLoaderElement.after(newRows); 489 } 490 callRowPaginationSingle(newRows); 491 bindRowScrollEvents(newRows); 492 } 493 syncScrollLoaderPosition(); 494 if ((!window.HS_ROW_INDEX || window.HS_ROW_INDEX.length === 0) && 495 (!window.HS_DEFERRED_ROWS || window.HS_DEFERRED_ROWS.length === 0)) { 496 scrollLoaderElement.remove(); 497 } 498 if (typeof onComplete === 'function') { onComplete(); } 499 }, 500 error: function() { 501 scrollLoaderElement.removeData('hs-ajax-loading'); 502 if (typeof onComplete === 'function') { onComplete(); } 503 } 504 }); 505 return true; 506} 507 508function loadNextContentRow(scrollLoaderElement) { 509 return loadNextContentRows(scrollLoaderElement, 1); 510} 511 512function loadNextContentRows(scrollLoaderElement, count) { 513 if (!scrollLoaderElement || scrollLoaderElement.length < 1) { 514 return false;
515 } 516 var target = Math.max(1, Number(count) || 1); 517 var loaded = 0; 518 519 // 1. Reveal any hidden DOM rows synchronously 520 for (var i = 0; i < target; i++) { 521 var nextHidden = $('.content_row.loaderhide').first(); 522 if (nextHidden.length > 0) { 523 nextHidden.addClass('hs-manual-visible'); 524 nextHidden.removeClass('loaderhide hs-manual-hidden').show(); 525 callRowPaginationSingle(nextHidden); 526 bindRowScrollEvents(nextHidden); 527 loaded++; 528 } else { 529 break; 530 } 531 } 532 533 // 2. Reveal any pre-rendered deferred rows synchronously 534 var bufferLoaded = 0; 535 while (loaded < target && Array.isArray(window.HS_DEFERRED_ROWS) && window.HS_DEFERRED_ROWS.length > 0) { 536 var nextRowHtml = window.HS_DEFERRED_ROWS.shift(); 537 if (nextRowHtml) { 538 var nextRow = $(nextRowHtml); 539 nextRow.removeClass('loaderhide hs-manual-hidden').show(); 540 nextRow.addClass('hs-manual-visible'); 541 var $lastRow = $('.content_row').last(); 542 if ($lastRow.length > 0) { 543 $lastRow.after(nextRow); 544 } else { 545 scrollLoaderElement.after(nextRow); 546 } 547 callRowPaginationSingle(nextRow); 548 bindRowScrollEvents(nextRow); 549 loaded++; 550 bufferLoaded++; 551 } else { 552 break; 553 } 554 } 555 556 if (loaded > 0) { 557 syncScrollLoaderPosition(); 558 } 559 560 // 3. If still need more, fetch remainder via AJAX (exactly one call) 561 if (loaded < target) { 562 var remaining = target - loaded; 563 return loadNextContentRowAjax(scrollLoaderElement, remaining); 564 } 565 566 return loaded > 0; 567} 568 569function ensureScrollLoaderButton(scrollLoaderElement) { 570 if (!scrollLoaderElement || scrollLoaderElement.length < 1) { 571 return; 572 } 573 syncScrollLoaderPosition(); 574 scrollLoaderElement 575 .text('Mehr laden') 576 .attr('role', 'button') 577 .attr('tabindex', '0') 578 .attr('aria-label', 'Weitere Inhalte laden') 579 .css('cursor', 'pointer') 580 .off('click.loadMore keydown.loadMore') 581 .on('click.loadMore keydown.loadMore', function(e) { 582 if (e.type === 'keydown' && e.key !== 'Enter' && e.key !== ' ') return; 583 if (e.type === 'keydown') e.preventDefault(); 584 var batchSize = isManualLoadMoreMode() ? 4 : 1; 585 var loaded = loadNextContentRows(scrollLoaderElement, batchSize); 586 if (!loaded) { 587 scrollLoaderElement.remove(); 588 } 589 }); 590} 591 592$(window).scroll(_.throttle(function() { 593 if (window.__hsCatchUpRunning) return; 594 var scrollLoaderElement = $('#scrollLoader'); 595 if (scrollLoaderElement.length < 1) return; 596 if (scrollLoaderElement.data('hs-ajax-loading')) return; 597 if (isManualLoadMoreMode()) return; 598 // Detect bfcache back-button restoration on first scroll 599 if (!window.__hsFirstScrollDone) { 600 window.__hsFirstScrollDone = true; 601 var $sl = $('#scrollLoader'); 602 if ($sl.length > 0 && $(window).scrollTop() > 0) { 603 var loaderTop = $sl.offset().top; 604 var viewportBottom = $(window).scrollTop() + $(window).height(); 605 if (viewportBottom >= loaderTop) { 606 window.__hsBfcacheRestored = true; 607 setTimeout(function() { 608 window.__hsBfcacheRestored = false; 609 // After settling, trigger one load if loader is in viewport 610 var $sl = $('#scrollLoader'); 611 if ($sl.length > 0 && !$sl.data('hs-ajax-loading') && !window.__hsCatchUpRunning) { 612 var slBottom = $sl.offset().top + $sl.outerHeight(); 613 var winBottom = $(window).scrollTop() + $(window).height(); 614 if (slBottom <= winBottom) { 615 loadNextContentRow($sl); 616 } 617 } 618 }, 3000); 619 } 620 } 621 } 622 623 var hiddenVisible = $('.loaderhide'); 624 if (hiddenVisible.length > 0) { 625 var scrollLoaderElementBottom = scrollLoaderElement.offset().top + scrollLoaderElement.outerHeight(); 626 var windowBottom = $(window).scrollTop() + $(window).height(); 627 var windowTop = $(window).scrollTop(); 628 if (scrollLoaderElementBottom < windowTop) { 629 window.__hsCatchUpRunning = true; 630 var scrollLoaderOriginalText = scrollLoaderElement.text(); 631 scrollLoaderElement.text('Lädt alle Inhalte...'); 632 scrollLoaderElement.addClass('is-loading'); 633 setTimeout(function() { 634 try { 635 var loaded = loadNextContentRows(scrollLoaderElement, 1000); 636 if (!loaded) scrollLoaderElement.remove(); 637 else { 638 scrollLoaderElement.text(scrollLoaderOriginalText); 639 scrollLoaderElement.removeClass('is-loading'); 640 } 641 } catch (e) { 642 // ignore 643 } finally { 644 window.__hsCatchUpRunning = false;
645 } 646 }, 0); 647 return; 648 } else if (scrollLoaderElementBottom <= windowBottom && !window.__hsBfcacheRestored) { 649 loadNextContentRow(scrollLoaderElement); 650 } 651 } else { 652 if (!window.__hsBfcacheRestored) { 653 var loaded = loadNextContentRow(scrollLoaderElement); 654 if (!loaded) scrollLoaderElement.remove(); 655 } 656 } 657}, 100, { leading: true, trailing: true})); 658 659$(window).scroll(_.throttle(function() { 660 if (isManualLoadMoreMode()) return; 661 var $rows = $('.content_row:not(.loaderhide)'); 662 $rows.each(function() { 663 activateDeferredMedia($(this)); 664 }); 665}, 500, { leading: false, trailing: true })); 666 667window.__hsBfcacheRestored = false; 668window.__hsFirstScrollDone = false; 669 670$(window).resize(_.throttle(function() { 671 initManualLoadMoreMode(); 672 callRowPaginationFull(); 673}, 250, { leading: true, trailing: true})); 674 675function isTouchDevice() { 676 const touchy = (('ontouchstart' in window) || 677 (navigator.maxTouchPoints > 0) || 678 (navigator.msMaxTouchPoints > 0)); 679 if (touchy) return true; 680 // Fallback for browsers (e.g. Brave) that spoof touch APIs via anti-fingerprinting 681 if (window.matchMedia && window.matchMedia('(pointer: coarse)').matches) return true; 682 if (window.matchMedia && window.matchMedia('(any-pointer: coarse)').matches) return true; 683 return false; 684} 685 686function openForm(url,bgc_click_enabled,separator) { 687 if(url=="") return ''; 688 var backurl=encodeURIComponent(window.location.href); 689 $.ajax({ 690 url: url, 691 type:'POST', 692 data:{'back':backurl}, 693 dataType: 'text', 694 headers:{'Cache-control':'no-cache'}, 695 success: function (data, statusText, reqAr) { 696 if(separator==undefined) { 697 separator='||'; 698 } 699 var out=data.split(separator); 700 if(out[0]=="ERROR") { 701 alert(out[1]); 702 } else if(data!="") { 703 if(out[1]=="JS") { 704 $('#popupContent').html(out[0]); 705 setupAccessibleDialog(); 706 if(typeof(bgc_click_enabled)=="undefined" || bgc_click_enabled==1) { 707 $("#backgroundPopup").on('click keydown', function(e){ 708 if (e.type === 'keydown' && e.key !== 'Enter' && e.key !== ' ') return; 709 if (e.type === 'keydown') e.preventDefault(); 710 disablePopup(); 711 }); 712 } else { 713 $("#backgroundPopup").off('click keydown'); 714 } 715 centerPopup(); 716 loadPopup(out[2]); 717 } else { 718 $('#popupContent').html(out[0]); 719 setupAccessibleDialog(); 720 if(typeof(bgc_click_enabled)=="undefined" || bgc_click_enabled==1) { 721 $("#backgroundPopup").on('click keydown', function(e){ 722 if (e.type === 'keydown' && e.key !== 'Enter' && e.key !== ' ') return; 723 if (e.type === 'keydown') e.preventDefault(); 724 disablePopup(); 725 }); 726 } else { 727 $("#backgroundPopup").off('click keydown'); 728 } 729 centerPopup();
730 // $('#yourInputId').focus().val($('#yourInputId').val()).get(0).setSelectionRange($('#yourInputId').val().length, $('#yourInputId').val().length); 731 732 // loadPopup("$('#formBox input, #formBox select').first().focus();"); 733 const callback = function() { 734 $(this).find('input:not([type="checkbox"]):not([type="hidden"]), select').first().focus(); 735 }; 736 loadPopup(callback); 737 } 738 } else { 739 alert('Fehler!'); 740 } 741 }, 742 error: function (jqXHR, textStatus, errorThrown) { 743 alert('Fehler - '+textStatus+' '+errorThrown); 744 } 745 }); 746} 747 748// Setup accessible dialog attributes and behavior 749function setupAccessibleDialog() { 750 const popupContent = document.getElementById('popupContent'); 751 const backgroundPopup = document.getElementById('backgroundPopup'); 752 753 if (!popupContent || !backgroundPopup) return; 754 755 // Ensure sr-only CSS class exists 756 ensureSrOnlyCSS(); 757 758 // Store the element that had focus before the dialog opened 759 if (!window.lastFocusedElement) { 760 window.lastFocusedElement = document.activeElement; 761 } 762 763 // Set up the dialog container 764 popupContent.setAttribute('role', 'dialog'); 765 popupContent.setAttribute('aria-modal', 'true'); 766 767 // Try to find or create a title for the dialog 768 let dialogTitle = popupContent.querySelector('h1, h2, h3, h4, h5, h6, [role="heading"]'); 769 if (!dialogTitle) { 770 // Create a hidden title if none exists 771 dialogTitle = document.createElement('h2'); 772 dialogTitle.id = 'dialog-title'; 773 dialogTitle.className = 'sr-only'; 774 dialogTitle.textContent = 'Dialog'; 775 popupContent.insertBefore(dialogTitle, popupContent.firstChild); 776 } else { 777 // Ensure existing title has an ID 778 if (!dialogTitle.id) { 779 dialogTitle.id = 'dialog-title'; 780 } 781 } 782 783 popupContent.setAttribute('aria-labelledby', dialogTitle.id); 784 785 // Completely hide background from screen readers and accessibility tools 786 backgroundPopup.setAttribute('role', 'presentation'); 787 backgroundPopup.setAttribute('aria-hidden', 'true'); 788 backgroundPopup.setAttribute('tabindex', '-1'); 789 backgroundPopup.setAttribute('aria-label', ''); 790 backgroundPopup.setAttribute('aria-describedby', ''); 791 792 // Hide all child elements of background from screen readers 793 const backgroundChildren = backgroundPopup.querySelectorAll('*'); 794 backgroundChildren.forEach(child => { 795 child.setAttribute('aria-hidden', 'true'); 796 child.setAttribute('tabindex', '-1'); 797 }); 798 799 // Apply contrast settings based on user preferences 800 applyContrastSettings(); 801 802 // Listen for contrast preference changes 803 if (window.matchMedia) { 804 const contrastQuery = window.matchMedia('(prefers-contrast: high)'); 805 contrastQuery.addListener(applyContrastSettings); 806 } 807 808 // Trap focus within the dialog 809 trapFocus(popupContent); 810 811 // Handle Escape key to close dialog 812 $(document).off('keydown.dialog').on('keydown.dialog', function(e) { 813 if (e.key === 'Escape' && popupStatus === 1) { 814 e.preventDefault(); 815 disablePopup(); 816 } 817 }); 818} 819 820// Ensure sr-only CSS class exists for screen reader only content 821function ensureSrOnlyCSS() { 822 if (!document.getElementById('sr-only-styles')) { 823 const style = document.createElement('style'); 824 style.id = 'sr-only-styles'; 825 style.textContent = ` 826 .sr-only { 827 position: absolute !important; 828 width: 1px !important; 829 height: 1px !important; 830 padding: 0 !important; 831 margin: -1px !important; 832 overflow: hidden !important; 833 clip: rect(0, 0, 0, 0) !important; 834 white-space: nowrap !important; 835 border: 0 !important; 836 } 837 `; 838 document.head.appendChild(style); 839 } 840} 841 842// Focus trap for the dialog 843function trapFocus(element) { 844 const focusableElements = element.querySelectorAll( 845 'a[href], button, textarea, input[type="text"], input[type="radio"], input[type="checkbox"], select, [tabindex]:not([tabindex="-1"])' 846 ); 847 848 const firstFocusableElement = focusableElements[0]; 849 const lastFocusableElement = focusableElements[focusableElements.length - 1]; 850 851 // Focus the first element initially 852 if (firstFocusableElement) { 853 firstFocusableElement.focus(); 854 } 855 856 // Handle tab key navigation 857 $(element).off('keydown.trap').on('keydown.trap', function(e) { 858 if (e.key === 'Tab') { 859 if (e.shiftKey) { 860 // Shift + Tab 861 if (document.activeElement === firstFocusableElement) { 862 e.preventDefault(); 863 lastFocusableElement.focus(); 864 } 865 } else { 866 // Tab 867 if (document.activeElement === lastFocusableElement) { 868 e.preventDefault(); 869 firstFocusableElement.focus(); 870 } 871 } 872 } 873 }); 874} 875 876//loading popup 877function loadPopup(callback,nomove=false){ 878 //loads popup only if it is disabled 879 if(popupStatus==0){ 880 $("#backgroundPopup").css({ 881 "opacity": "0.4" 882 }); 883 $("#backgroundPopup").fadeIn("fast"); 884 if(callback){ 885 $("#popupContent").fadeIn("fast",function(){ 886 // Ensure accessibility is set up after content is loaded 887 setupAccessibleDialog(); 888 889 if(typeof callback === "string") { 890 const fstrings=callback.split(";;"); 891 for(let i=0;i<fstrings.length;i++) { 892 console.log(fstrings[i]); 893 Function('return ' + fstrings[i])(); 894 } 895 } 896 else if (typeof callback === 'function') { 897 // If callback is already a function, call it directly 898 callback.call(this); 899 } 900 else { 901 console.error('Callback is neither a string nor a function.'); 902 } 903 }); 904 } else { 905 $("#popupContent").fadeIn("fast", function() { 906 // Ensure accessibility is set up after content is loaded 907 setupAccessibleDialog(); 908 }); 909 } 910 if(!nomove && !isScrolledIntoView) { 911 $('html, body').animate({ 912 scrollTop: $("#popupContent").offset().top 913 }, 50); 914 } 915 popupStatus = 1; 916 } else if(callback!=undefined) { 917 // Ensure accessibility is set up for existing popup 918 setupAccessibleDialog(); 919 920 if(typeof callback === "string") { 921 const fstrings=callback.split(";;"); 922 for(let i=0;i<fstrings.length;i++) { 923 console.log(fstrings[i]); 924 Function('return ' + fstrings[i])(); 925 } 926 } 927 else if (typeof callback === 'function') { 928 // If callback is already a function, call it directly 929 callback(); 930 } 931 else {
932 console.error('Callback is neither a string nor a function.'); 933 } 934 } 935} 936//disabling popup 937function disablePopup(){ 938 //disables popup only if it is enabled 939 if(popupStatus==1){ 940 // Clean up accessibility attributes 941 cleanupAccessibleDialog(); 942 943 // rest fade out etc 944 $("#backgroundPopup").fadeOut(90); 945 $("#popupContent").fadeOut(90); 946 $("#popupContent").html(''); 947 $("#popupContent").attr('class',''); 948 $("#popupContent").removeAttr('style'); 949 $("#backgroundPopup, #popupContent").off('click keydown') 950 popupStatus=0; 951 } 952} 953 954// Clean up accessibility attributes when dialog closes 955function cleanupAccessibleDialog() { 956 const popupContent = document.getElementById('popupContent'); 957 const backgroundPopup = document.getElementById('backgroundPopup'); 958 959 if (popupContent) { 960 popupContent.removeAttribute('role'); 961 popupContent.removeAttribute('aria-modal'); 962 popupContent.removeAttribute('aria-labelledby'); 963 $(popupContent).off('keydown.trap'); 964 } 965 966 if (backgroundPopup) { 967 backgroundPopup.removeAttribute('role'); 968 backgroundPopup.removeAttribute('aria-hidden'); 969 backgroundPopup.removeAttribute('tabindex'); 970 backgroundPopup.removeAttribute('aria-label'); 971 backgroundPopup.removeAttribute('aria-describedby'); 972 973 // Restore background children accessibility 974 const backgroundChildren = backgroundPopup.querySelectorAll('*'); 975 backgroundChildren.forEach(child => { 976 child.removeAttribute('aria-hidden'); 977 child.removeAttribute('tabindex'); 978 }); 979 } 980 981 // Remove global event listeners 982 $(document).off('keydown.dialog'); 983 984 // Restore focus to the element that had focus before the dialog opened 985 if (window.lastFocusedElement && window.lastFocusedElement.focus) { 986 window.lastFocusedElement.focus(); 987 window.lastFocusedElement = null; 988 } 989} 990 991//centering popup 992function centerPopup(minTop=100){ 993 //request data for centering 994 var windowWidth = document.documentElement.clientWidth; 995 var windowHeight = document.documentElement.clientHeight; 996 var popupHeight = $("#popupContent").height(); 997 var popupWidth = $("#popupContent").width(); 998 var setTop= windowHeight/2-popupHeight/2+$(window).scrollTop(); 999 if(setTop<minTop) { 1000 setTop=minTop; 1001 } 1002 //centering 1003 $("#popupContent").css({ 1004 "position": "absolute", 1005 "top": setTop, 1006 "left": windowWidth/2-popupWidth/2 1007 }); 1008 //only need force for IE6 1009 1010 $("#backgroundPopup").css({ 1011 "height": windowHeight 1012 }); 1013} 1014 1015function isScrolledIntoView(elem) { 1016 var docViewTop = $(window).scrollTop(); 1017 var docViewBottom = docViewTop + $(window).height(); 1018 1019 var elemTop = $(elem).offset().top; 1020 var elemBottom = elemTop + $(elem).height(); 1021 return (elemTop >= docViewTop); 1022} 1023 1024function limitChars(textid, limit, infodiv) { 1025 var text = $('#'+textid).val(); 1026 var textlength = text.length; 1027 if(textlength > limit) { 1028 $('#' + infodiv).html('Sie können nicht mehr wie '+limit+' Zeichen eingeben!'); 1029 $('#'+textid).val(text.substr(0,limit)); 1030 return false; 1031 } else { 1032 $('#' + infodiv).html('Sie haben noch '+ (limit - textlength) +' Zeichen übrig.'); 1033 return true; 1034 } 1035} 1036 1037/** `.content_row_scroll` (#rowâ¦) â sibling `.steering_arrows` (no longer relies on id="â¦steerar"). */
1038function rowSteeringFromScrollCont(cont) { 1039 var $sc = $(cont); 1040 if (!$sc.length) { 1041 return $(); 1042 } 1043 var $st = $sc.closest('.content_row').children('.steering_arrows').first(); 1044 return $st.length ? $st : $(); 1045} 1046 1047/** 1048 * Card width + flex gap for a horizontal product row (desktop gap 20px, phone 6px in CSS). 1049 * Uses computed `gap`, with offsetLeft fallback; last resort 20 to match legacy behaviour. 1050 */ 1051function rowScrollCardStep(cont) { 1052 var $inner = $(cont + '>.content_row_scroll_inner'); 1053 var innerEl = $inner[0]; 1054 if (!innerEl) { 1055 return { cardW: 0, gap: 20, step: 0 }; 1056 } 1057 var $first = $inner.children('.product_list_cont').first(); 1058 var cardW = $first.length ? $first.outerWidth() : 0; 1059 var gapPx = 0; 1060 var style = window.getComputedStyle(innerEl); 1061 var rawGap = style.gap || style.columnGap || ''; 1062 if (rawGap && rawGap !== 'normal') { 1063 var parts = String(rawGap).trim().split(/\s+/); 1064 for (var p = 0; p < parts.length; p++) { 1065 var n = parseFloat(parts[p]); 1066 if (Number.isFinite(n)) { 1067 gapPx = n; 1068 break; 1069 } 1070 } 1071 } 1072 if (!Number.isFinite(gapPx) || gapPx < 0) { 1073 gapPx = 0; 1074 } 1075 if (gapPx === 0) { 1076 var cards = $inner.children('.product_list_cont'); 1077 if (cards.length >= 2) { 1078 var c0 = cards.get(0); 1079 var c1 = cards.get(1); 1080 gapPx = c1.offsetLeft - c0.offsetLeft - c0.offsetWidth; 1081 } 1082 } 1083 if (!Number.isFinite(gapPx) || gapPx < 0) { 1084 gapPx = 20; 1085 } 1086 var step = cardW + gapPx; 1087 return { cardW: cardW, gap: gapPx, step: step }; 1088} 1089 1090function scrollRow(cont,dir,elcnt) { 1091 if(dir>0) { 1092 dir=1; 1093 } else { 1094 dir=-1; 1095 } 1096 1097 let vis_width=$(cont).width(); 1098 1099 var metrics = rowScrollCardStep(cont); 1100 var prod_cont_fullsize = metrics.step; 1101 if (!prod_cont_fullsize || prod_cont_fullsize <= 0) { 1102 return; 1103 } 1104 1105 let grid_fix=$(cont).scrollLeft(); 1106 let add_grid_move=grid_fix%prod_cont_fullsize; 1107 1108 let anz_prod_cont=vis_width/prod_cont_fullsize; 1109 1110 if(dir<0 && add_grid_move>0) { 1111 add_grid_move=prod_cont_fullsize-add_grid_move; 1112 } 1113 let move_by=parseInt(anz_prod_cont)*prod_cont_fullsize-add_grid_move; 1114 1115 var pos=$(cont).scrollLeft()+(dir*move_by); 1116 $(cont).stop().animate({ 1117 scrollLeft: pos+"px" 1118 },1,"linear",function() { 1119 callRowPaginationSingle($(cont)); 1120 }); 1121} 1122 1123function callRowPaginationSingle(row_obj=null) { 1124 let current_row_obj=null; 1125 if(row_obj instanceof jQuery) { 1126 current_row_obj=row_obj; 1127 activateDeferredMedia(current_row_obj); 1128 current_row_obj.find(".steering_arrows > .scrollArrowData").each(callRowPagination); 1129 } else { 1130 current_row_obj=$(this); 1131 activateDeferredMedia(current_row_obj.parent()); 1132 current_row_obj.parent().find(".steering_arrows > .scrollArrowData").each(callRowPagination); 1133 } 1134}; 1135 1136function callRowPaginationFull() { 1137 activateDeferredMedia($('.content_row:not(.loaderhide)')); 1138 $('.content_row:not(.loaderhide)').find(".scrollArrowData").each(callRowPagination); 1139}; 1140 1141function isElementNearVisible(el, scrollCont) { 1142 var rect = el.getBoundingClientRect(); 1143 if (!scrollCont) { 1144 var winH = window.innerHeight || document.documentElement.clientHeight; 1145 var winW = window.innerWidth || document.documentElement.clientWidth; 1146 var buf = 200; 1147 return rect.top < winH + buf && rect.bottom > -buf && rect.left < winW + buf && rect.right > -buf; 1148 } 1149 var cRect = scrollCont.getBoundingClientRect(); 1150 var buf = cRect.width; 1151 if (rect.bottom < cRect.top - 200 || rect.top > cRect.bottom + 200) { 1152 return false; 1153 } 1154 return rect.right >= cRect.left - buf && rect.left <= cRect.right + buf; 1155} 1156 1157function activateDeferredMedia(scope) { 1158 if (!scope || !scope.length) { 1159 return; 1160 } 1161 if (scope.length > 1) { 1162 scope.each(function () { activateDeferredMedia($(this)); }); 1163 return; 1164 } 1165 var isMobile = isManualLoadMoreMode(); 1166 var scrollCont = scope.find('.content_row_scroll')[0]; 1167 var checkCont = isMobile ? scrollCont : null; 1168 var loadingAttr = isMobile ? 'eager' : 'lazy'; 1169 scope.find('img[data-src]').each(function () { 1170 var $img = $(this); 1171 if ($img.data('hs-media-activated')) return; 1172 if (!isElementNearVisible(this, checkCont)) return; 1173 var val = $img.attr('data-src'); 1174 if (!val || val === '') return; 1175 var picture = $img.closest('picture')[0]; 1176 if (picture) { 1177 $(picture).find('source[data-srcset]').each(function () { 1178 var $s = $(this); 1179 var sv = $s.attr('data-srcset'); 1180 if (sv && sv !== '') { 1181 $s.attr('srcset', sv); 1182 $s.removeAttr('data-srcset'); 1183 $s.removeAttr('loading'); 1184 } 1185 }); 1186 var oldImg = $img[0]; 1187 var newImg = document.createElement('img'); 1188 for (var k = 0; k < oldImg.attributes.length; k++) { 1189 var attr = oldImg.attributes[k]; 1190 if (attr.name !== 'data-src' && attr.name !== 'loading') { 1191 newImg.setAttribute(attr.name, attr.value); 1192 } 1193 } 1194 newImg.setAttribute('loading', loadingAttr); 1195 newImg.src = val; 1196 oldImg.parentNode.replaceChild(newImg, oldImg); 1197 $(newImg).data('hs-media-activated', true); 1198 } else { 1199 $img.attr('loading', loadingAttr); 1200 $img.attr('src', val); 1201 $img.removeAttr('data-src'); 1202 $img.data('hs-media-activated', true); 1203 } 1204 }); 1205} 1206 1207function callRowPagination() { 1208 let targ=""; 1209 let elcnt=0; 1210 targ=$(this).data('target'); 1211 elcnt=$(this).data('elcnt'); 1212 let cont="#"+targ; 1213 1214 let vis_width=$(cont).width(); 1215 1216 var metrics = rowScrollCardStep(cont); 1217 if (!metrics.step || metrics.step <= 0) { 1218 return; 1219 } 1220 1221 updateRowPagination(cont, metrics.step, vis_width, elcnt, metrics.gap); 1222} 1223 1224function cancelAbo(type='streaming') { 1225 var target_url=""; 1226 var info_text='Möchtest Du Dein Abonnement wirklich kündigen und alle Abo-Vorteile verlieren';
1227 info_text='Möchtest Du dieses Abonnement kündigen?'; 1228 if(type=='streaming') { 1229 target_url='mein-konto/streaming-abo/cancel/'; 1230 } 1231 if(type=='streaming_angebot') { 1232 target_url='mein-konto/streaming-angebot/cancel/'; 1233 } 1234 if(type=='dlh') { 1235 target_url='mein-konto/die-letzten-helden-abo/cancel/'; 1236 } 1237 if(confirm(info_text)) { 1238 window.location.href=target_url; 1239 } 1240 return false; 1241} 1242 1243function updateRowPagination(cont, prod_cont_fullsize, vis_width, elcnt, gapTolerance) { 1244 if (gapTolerance === undefined || !Number.isFinite(gapTolerance)) { 1245 gapTolerance = 20; 1246 } 1247 1248 var anz_prod_left=Math.ceil($(cont).scrollLeft()/prod_cont_fullsize); 1249 var left_area_prods_hidden=prod_cont_fullsize*anz_prod_left; 1250 var left_area_overlap=left_area_prods_hidden-$(cont).scrollLeft(); 1251 var effective_visible_area=Math.ceil(vis_width)-left_area_overlap; 1252 var anz_prod_visible=parseInt((effective_visible_area + gapTolerance) / prod_cont_fullsize); 1253 var showLeftNr=anz_prod_left+1; 1254 var showRightNr=(anz_prod_left+anz_prod_visible); 1255 if(showLeftNr>elcnt) showLeftNr=elcnt; 1256 if(showRightNr>elcnt) showRightNr=elcnt; 1257
1258 var $steer = rowSteeringFromScrollCont(cont); 1259 var $steerLinks = $steer.children('a'); 1260 1261 if($(cont).scrollLeft()==0) { 1262 $steerLinks.first().css('visibility','hidden'); 1263 } else { 1264 $steerLinks.first().css('visibility','visible'); 1265 } 1266 if($(cont)[0].scrollWidth<=Math.round($(cont).scrollLeft()+$(cont).width())) { 1267 $steerLinks.last().css('visibility','hidden'); 1268 } else { 1269 $steerLinks.last().css('visibility','visible'); 1270 } 1271 1272 if(anz_prod_visible>=elcnt) { 1273 $steer.css('visibility','hidden'); 1274 } else { 1275 $steer.css('visibility','visible'); 1276 var $pageNr = $steer.find('.scrollPageNr'); 1277 if ($pageNr.length) { 1278 $pageNr.html(showLeftNr+" - "+showRightNr); 1279 } else { 1280 $(cont+"pagenr").html(showLeftNr+" - "+showRightNr); 1281 } 1282 } 1283 1284} 1285 1286function openTargetElement(element,override) { 1287 if(element!="") { 1288 var contentElementName=$(element).data('content'), 1289 targetElementName=$(element).data('target'), 1290 targetTitle=$(element).data('title'); 1291 } else { 1292 var contentElementName=override.ce, 1293 targetElementName=override.te, 1294 targetTitle=override.tt; 1295 } 1296 var targetContent=$('#'+contentElementName).html(), 1297 targetElement=$('#'+targetElementName); 1298 1299 targetElement.children().addClass('hide').removeClass('unhide'); 1300 $('#'+contentElementName).removeClass('hide').addClass('unhide'); 1301 1302 document.title=baseTitle.replace(' | '+mainTitle, '')+" - "+targetTitle+' | '+mainTitle; 1303 1304 var state = {ce:contentElementName,te:targetElementName,tt:targetTitle}, 1305 title = targetTitle, 1306 path = $(element).attr('href'); 1307 1308 if(override!=undefined) { 1309 history.replaceState(state, title, path); 1310 } else { 1311 history.pushState(state, title, path); 1312 } 1313} 1314 1315function setProdMainImg(obj) { 1316 var img_cont=$('#product_full_main_img'); 1317 var index=obj.data('index'); 1318 var src=obj.data('src'); 1319 var alt=$('#product_full_media_img_'+index).attr('alt'); 1320 img_cont.attr('src',src); 1321 img_cont.attr('alt',alt); 1322 $('.product_full_media_thumb').removeClass("product_full_media_thumb_sel"); 1323 obj.addClass("product_full_media_thumb_sel"); 1324} 1325 1326function initNewsMenu() { 1327 $('.news_menu_item').off('click').on('click', function () { 1328 $(this).toggle(); 1329 }); 1330} 1331 1332function showImage(obj) { 1333 let url=$(obj).data('ipop'); 1334 let img_el=$('<img id="image_popup">'); 1335 if(img_el) { 1336 img_el.remove(); 1337 } 1338 img_el = $('<img id="image_popup">').off('load').on('load',function () { 1339 $("#backgroundPopup, #popupContent").off('click').on('click',function(){ 1340 disablePopup(); 1341 }); 1342 loadPopup(()=>{},true); 1343 }); 1344 img_el.attr('src', url); 1345 $('#popupContent').addClass('image_popup_content'); 1346 img_el.appendTo('#popupContent'); 1347} 1348 1349 1350// SHOP 1351function addItem(prodid) { 1352 if($('#prod'+prodid).length) { 1353 var amount=parseInt($('#prod'+prodid).val().match(/\d+/),10); 1354 } else { 1355 var amount=1; 1356 } 1357 var backurl=encodeURIComponent(window.location.href); 1358 new $.ajax({ 1359 url: 'warenkorb/'+prodid+'/', 1360 type:'POST', 1361 data:{'back':backurl,'amount':amount}, 1362 headers:{'Cache-control':'no-cache'}, 1363 success: function (data, statusText, reqAr) { 1364 var out=data.split('||'); 1365 if(out[0]=="ERROR") { 1366 alert(out[1]); 1367 } else if(data!="") { 1368 window.location.reload(false); 1369 } else { 1370 alert('Fehler!'); 1371 } 1372 }, 1373 error: function (jqXHR, textStatus, errorThrown) { 1374 alert('Fehler - '+textStatus+' '+errorThrown); 1375 } 1376 }); 1377} 1378function remItem(prodid,check_message) { 1379 if(!confirm(check_message)) { 1380 return ; 1381 } 1382 var backurl=encodeURIComponent(window.location.href); 1383 var wkCsrfToken=$('#WK input[name="wk_csrf_token"]').val(); 1384 new $.ajax({ 1385 url: 'warenkorb/-'+prodid+'/', 1386 type:'POST', 1387 data:{'back':backurl,'wk_csrf_token':wkCsrfToken}, 1388 headers:{'Cache-control':'no-cache'}, 1389 success: function (data, statusText, reqAr) { 1390 var out=data.split('||'); 1391 if(out[0]=="ERROR") { 1392 alert(out[1]); 1393 } else if(data!="") { 1394 window.location.href='warenkorb/'; 1395 } else { 1396 alert('Fehler!'); 1397 } 1398 }, 1399 error: function (jqXHR, textStatus, errorThrown) { 1400 alert('Fehler - '+textStatus+' '+errorThrown); 1401 } 1402 }); 1403} 1404function remAbo(aboid,check_message) { 1405 if(!confirm(check_message)) { 1406 return ; 1407 } 1408 var backurl=encodeURIComponent(window.location.href); 1409 new $.ajax({ 1410 url: 'abo-konfigurieren/-'+aboid+'/', 1411 type:'POST', 1412 data:{'back':backurl}, 1413 headers:{'Cache-control':'no-cache'}, 1414 success: function (data, statusText, reqAr) { 1415 var out=data.split('||'); 1416 if(out[0]=="ERROR") { 1417 alert(out[1]); 1418 } else if(data!="") { 1419 window.location.href='abo-konfigurieren/'; 1420 } else { 1421 alert('Fehler!'); 1422 } 1423 }, 1424 error: function (jqXHR, textStatus, errorThrown) { 1425 alert('Fehler - '+textStatus+' '+errorThrown); 1426 } 1427 }); 1428} 1429function refresh_wk() { 1430 $("#WK").submit(); 1431} 1432function setLAtoInp() { 1433 var a=document.forms['lieferadresse']; 1434 if(a) { 1435 a.adresstyp[1].checked=true; 1436 } 1437} 1438function deleteWunschlisteItem(prod_id) { 1439 if(confirm('Möchten Sie dieses Produkt von Ihrer Liste entfernen?')) { 1440 window.location.href='mein-konto/wunschliste/rem-item/'+prod_id+'/'; 1441 } 1442} 1443 1444function sendFetchData(url,data,returnUrl) { 1445 fetch(url, { 1446 method: 'POST', 1447 headers: { 1448 'Content-Type': 'application/json', 1449 }, 1450 body: JSON.stringify(data), 1451 }) 1452 .then(response => { 1453 if (!response.ok) { 1454 // Handle HTTP errors 1455 return response.json().then(errData => { 1456 throw new Error(`Error: ${errData.message}`); 1457 }); 1458 } 1459 return response.json(); 1460 }) 1461 .then(result => { 1462 if(result.result=="1") { 1463 window.location.href=returnUrl; 1464 } 1465 else { 1466 if(result.message!='') { 1467 alert('Fehler: '+result.message); 1468 } 1469 } 1470 }) 1471 .catch(error => { 1472 console.error('Error:', error); 1473 }); 1474} 1475function deleteUserlist(list_id) { 1476 if(confirm('Möchten Sie dieses Liste vollständig löschen?')) { 1477 const url = base + 'index.php?c=action&act=delete-userlist'; 1478 const returnUrl = base + 'mein-konto/listen/'; 1479 1480 const data = { 1481 list_id: list_id, 1482 }; 1483
1484 sendFetchData(url,data,returnUrl); 1485 } 1486} 1487function deleteUserlistItem(list_id,prod_id) { 1488 if(confirm('Möchten Sie dieses Hörspiel von Ihrer Liste entfernen?')) { 1489 const url = base + 'index.php?c=action&act=delete-prod-from-userlist'; 1490 const returnUrl = base + 'mein-konto/listen/'+list_id+'/'; 1491 1492 const data = { 1493 list_id: list_id, 1494 prod_id: prod_id, 1495 }; 1496 1497 sendFetchData(url,data,returnUrl); 1498 } 1499} 1500function sortUserList(list_id,sort_type,sort_order) { 1501 const url = base + 'index.php?c=action&act=sort-userlist'; 1502 const returnUrl = base + 'mein-konto/listen/'+list_id+'/'; 1503 1504 const data = { 1505 userList: { 1506 id: list_id, 1507 sort_type: sort_type, 1508 sort_order: sort_order, 1509 } 1510 }; 1511 1512 sendFetchData(url,data,returnUrl); 1513} 1514function overwritePersonalSorting(list_id) { 1515 if(confirm('Diese Listenreihenfolge als eigene Sortierung speichern?')) { 1516 const url = base + 'index.php?c=action&act=overwrite-personal-sorting-userlist'; 1517 const returnUrl = base + 'mein-konto/listen/'+list_id+'/'; 1518 1519 const data = { 1520 userList: { 1521 id: list_id, 1522 } 1523 }; 1524 1525 sendFetchData(url,data,returnUrl); 1526 } 1527} 1528 1529// BFSG Compliant High Contrast System - Reliable Implementation 1530function toggleHighContrast() { 1531 const isEnabled = document.body.classList.contains('high-contrast-mode'); 1532 1533 if (isEnabled) { 1534 // Disable high contrast 1535 disableHighContrast(); 1536 } else { 1537 // Enable high contrast 1538 enableHighContrast(); 1539 } 1540} 1541 1542function enableHighContrast() { 1543 // Add body class 1544 document.body.classList.add('high-contrast-mode'); 1545 1546 // Store preference 1547 localStorage.setItem('highContrastMode', 'true'); 1548 1549 // Update cookie for server-side detection 1550 document.cookie = 'highContrastMode=true; path=/; max-age=31536000; SameSite=Lax'; 1551 1552 // Ensure CSS is loaded 1553 loadHighContrastCSS(); 1554 1555 // Announce to screen readers 1556 announceToScreenReader('Hoher Kontrast aktiviert'); 1557} 1558 1559function disableHighContrast() { 1560 // Remove body class 1561 document.body.classList.remove('high-contrast-mode'); 1562 1563 // Store preference 1564 localStorage.setItem('highContrastMode', 'false'); 1565 1566 // Update cookie for server-side detection 1567 document.cookie = 'highContrastMode=false; path=/; max-age=31536000; SameSite=Lax'; 1568 1569 // Remove high contrast CSS 1570 removeHighContrastCSS(); 1571 1572 // Announce to screen readers 1573 announceToScreenReader('Normaler Kontrast aktiviert'); 1574} 1575 1576function loadHighContrastCSS() {
1577 let cssLink = document.getElementById('high-contrast-css'); 1578 1579 if (!cssLink) { 1580 // Create new CSS link if it doesn't exist 1581 cssLink = document.createElement('link'); 1582 cssLink.id = 'high-contrast-css'; 1583 cssLink.rel = 'stylesheet'; 1584 cssLink.type = 'text/css'; 1585 cssLink.href = 'css/styles-high-contrast.css?' + (typeof window.cacheBuster !== 'undefined' ? window.cacheBuster : Date.now()); 1586 1587 // Add error handling 1588 cssLink.onerror = function() { 1589 console.error('Failed to load high contrast CSS'); 1590 announceToScreenReader('Fehler beim Laden des hohen Kontrasts'); 1591 }; 1592 1593 cssLink.onload = function() { 1594 console.log('High contrast CSS loaded successfully'); 1595 }; 1596 1597 document.head.appendChild(cssLink); 1598 } else { 1599 // CSS already exists, ensure it's not disabled 1600 cssLink.disabled = false; 1601 } 1602} 1603 1604function removeHighContrastCSS() { 1605 const cssLink = document.getElementById('high-contrast-css'); 1606 if (cssLink) { 1607 // Don't remove the link, just disable it to avoid flash 1608 cssLink.disabled = true; 1609 } 1610} 1611 1612function announceToScreenReader(message) { 1613 let liveRegion = document.querySelector('#contrast-announcement'); 1614 1615 if (!liveRegion) { 1616 liveRegion = createLiveRegion(); 1617 } 1618 1619 // Clear any existing announcement 1620 liveRegion.textContent = ''; 1621 1622 // Add new announcement after a brief delay to ensure it's read 1623 setTimeout(() => { 1624 liveRegion.textContent = message; 1625 1626 // Clear after announcement 1627 setTimeout(() => { 1628 liveRegion.textContent = ''; 1629 }, 3000); 1630 }, 100); 1631} 1632 1633function createLiveRegion() { 1634 let liveRegion = document.querySelector('#contrast-announcement'); 1635 1636 if (!liveRegion) { 1637 liveRegion = document.createElement('div'); 1638 liveRegion.id = 'contrast-announcement'; 1639 liveRegion.className = 'sr-only'; 1640 liveRegion.setAttribute('aria-live', 'polite'); 1641 liveRegion.setAttribute('aria-atomic', 'true'); 1642 liveRegion.setAttribute('role', 'status'); 1643 document.body.appendChild(liveRegion); 1644 } 1645 1646 return liveRegion; 1647} 1648 1649function initHighContrast() { 1650 // Create live region immediately 1651 createLiveRegion(); 1652 1653 // Check multiple sources for high contrast preference 1654 const savedMode = localStorage.getItem('highContrastMode'); 1655 const urlParams = new URLSearchParams(window.location.search); 1656 const urlContrast = urlParams.get('contrast') === 'high'; 1657 const bodyHasClass = document.body.classList.contains('high-contrast-mode'); 1658 const cssExists = document.getElementById('high-contrast-css') !== null; 1659 1660 // Determine current state from multiple sources 1661 const shouldEnable = urlContrast || savedMode === 'true' || bodyHasClass || cssExists; 1662 1663 if (shouldEnable) { 1664 // Ensure everything is properly set up for high contrast 1665 document.body.classList.add('high-contrast-mode'); 1666 localStorage.setItem('highContrastMode', 'true'); 1667 document.cookie = 'highContrastMode=true; path=/; max-age=31536000; SameSite=Lax'; 1668 loadHighContrastCSS(); 1669 } else { 1670 // Ensure everything is properly set up for normal contrast 1671 document.body.classList.remove('high-contrast-mode'); 1672 localStorage.setItem('highContrastMode', 'false'); 1673 document.cookie = 'highContrastMode=false; path=/; max-age=31536000; SameSite=Lax'; 1674 removeHighContrastCSS(); 1675 } 1676} 1677 1678// Mobile menu functions (enhanced for accessibility) 1679function toggleMobileMenu(button) { 1680 const menu = document.querySelector('.mm_toggle'); 1681 const isExpanded = button.getAttribute('aria-expanded') === 'true'; 1682 1683 if (menu) { 1684 menu.style.display = isExpanded ? 'none' : 'block'; 1685 button.setAttribute('aria-expanded', !isExpanded); 1686 button.setAttribute('aria-label', isExpanded ? 'Mobiles Menu öffnen' : 'Mobiles Menu schlieÃen'); 1687 } 1688} 1689 1690function toggleCategoriesMenu(button) { 1691 const menu = document.querySelector('.top_categories_list'); 1692 const isExpanded = button.getAttribute('aria-expanded') === 'true'; 1693 1694 if (menu) { 1695 menu.style.display = isExpanded ? 'none' : 'block'; 1696 button.setAttribute('aria-expanded', !isExpanded); 1697 } 1698} 1699 1700function toggleUserMenu(button) { 1701 const menu = document.querySelector('.top_usermenu'); 1702 const isExpanded = button.getAttribute('aria-expanded') === 'true'; 1703 1704 if (menu) { 1705 menu.style.display = isExpanded ? 'none' : 'block'; 1706 button.setAttribute('aria-expanded', !isExpanded); 1707 } 1708} 1709 1710/** Narrow viewport: disclosure toggle for #top-primary-panel (BFSG: aria-expanded, Escape, resize). */ 1711function initTopNavDisclosure() { 1712 const toggle = document.getElementById('top-nav-toggle'); 1713 const panel = document.getElementById('top-primary-panel'); 1714 if (!toggle || !panel) return; 1715 1716 const mq = window.matchMedia('(max-width: 768px)'); 1717 1718 function isNarrow() { 1719 return mq.matches; 1720 } 1721 1722 function setOpen(open) { 1723 if (!isNarrow()) { 1724 panel.classList.remove('is-open'); 1725 toggle.setAttribute('aria-expanded', 'false'); 1726 toggle.setAttribute('aria-label', 'Hauptmenü öffnen'); 1727 return; 1728 } 1729 panel.classList.toggle('is-open', !!open); 1730 toggle.setAttribute('aria-expanded', open ? 'true' : 'false'); 1731 toggle.setAttribute('aria-label', open ? 'Hauptmenü schlieÃen' : 'Hauptmenü öffnen'); 1732 if (!open) { 1733 document.querySelectorAll('.top_usermenu.dd_visible').forEach((el) => el.classList.remove('dd_visible')); 1734 } 1735 } 1736 1737 toggle.addEventListener('click', function (e) { 1738 if (!isNarrow()) return; 1739 e.preventDefault(); 1740 setOpen(!panel.classList.contains('is-open')); 1741 }); 1742
1743 document.addEventListener('keydown', function topNavEsc(e) { 1744 if (e.key !== 'Escape') return; 1745 if (!isNarrow() || !panel.classList.contains('is-open')) return; 1746 setOpen(false); 1747 toggle.focus(); 1748 }); 1749 1750 function onMqChange() { 1751 if (!mq.matches) { 1752 setOpen(false); 1753 } else { 1754 document.querySelectorAll('.top_usermenu.dd_visible').forEach((el) => el.classList.remove('dd_visible')); 1755 } 1756 } 1757 if (typeof mq.addEventListener === 'function') { 1758 mq.addEventListener('change', onMqChange); 1759 } else if (typeof mq.addListener === 'function') { 1760 mq.addListener(onMqChange); 1761 } 1762 1763 panel.addEventListener('click', function (e) { 1764 if (!isNarrow() || !panel.classList.contains('is-open')) return; 1765 const a = e.target.closest('a[href]'); 1766 if (!a) return; 1767 const href = a.getAttribute('href') || ''; 1768 if (href === '' || href === '#') return; 1769 setOpen(false); 1770 }); 1771} 1772 1773// Initialize high contrast when DOM is ready 1774$(document).ready(function() { 1775 initManualLoadMoreMode(); 1776 // Initialize high contrast system 1777 initHighContrast(); 1778 initTopNavDisclosure(); 1779 1780 // Fallback delegated handler in case ensureScrollLoaderButton missed the element 1781 $(document).on('click.loadMoreFallback keydown.loadMoreFallback', '#scrollLoader', function(e) { 1782 var $btn = $(this); 1783 if ($btn.data('hs-loader-init')) return; 1784 if (e.type === 'keydown' && e.key !== 'Enter' && e.key !== ' ') return; 1785 if (e.type === 'keydown') e.preventDefault(); 1786 var batchSize = isManualLoadMoreMode() ? 4 : 1; 1787 var loaded = loadNextContentRows($btn, batchSize); 1788 if (!loaded) { 1789 $btn.remove(); 1790 } 1791 e.stopImmediatePropagation(); 1792 }); 1793 1794 // Handle mobile menu accessibility 1795 $('.mobileMenuButton').off('click').on('click', function(e) { 1796 e.preventDefault(); 1797 toggleMobileMenu(this); 1798 }); 1799}); 1800 1801// Check if user prefers high contrast 1802function prefersHighContrast() { 1803 return window.matchMedia && ( 1804 window.matchMedia('(prefers-contrast: high)').matches || 1805 window.matchMedia('(prefers-contrast: more)').matches || 1806 document.body.classList.contains('high-contrast-mode') 1807 ); 1808} 1809 1810// Apply appropriate contrast settings based on user preferences 1811function applyContrastSettings() { 1812 const backgroundPopup = document.getElementById('backgroundPopup'); 1813 if (!backgroundPopup) return; 1814 1815 if (prefersHighContrast()) { 1816 backgroundPopup.style.backgroundColor = 'rgba(0, 0, 0, 1)'; 1817 backgroundPopup.style.border = '2px solid #ffffff'; 1818 backgroundPopup.style.opacity = '1'; 1819 } else { 1820 backgroundPopup.style.backgroundColor = 'rgba(0,0,0,0.4)'; 1821 backgroundPopup.style.opacity = '1'; 1822 } 1823}
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.