1/* Globale Cookie-Optionen */ 2const COOKIE_SET_OPTS = { expires: 365, path: '/' }; 3const COOKIE_REMOVE_OPTS = { path: '/' }; 4 5/* Body-Toogle für CSS-Manipulation */ 6/************************************/ 7function toggleBody(className) { 8 var body = document.body; 9 if (body.classList.contains(className)) { 10 body.classList.remove(className); 11 } else { 12 body.classList.add(className); 13 } 14} 15 16/* Blaufilter-Regel */ 17/********************/ 18function changeBluescale(value) { 19 Cookies.set('acc_bluescale', value, COOKIE_SET_OPTS); 20 var elementToChange = document.getElementById("shader-bluefilter"); 21 var transparencyValue = value / 10; 22 if (transparencyValue === 0) { 23 elementToChange.style.display = "none"; 24 } else if (transparencyValue >= 0.1 && transparencyValue <= 1.0) { 25 elementToChange.style.display = "block"; 26 } 27 elementToChange.style.backgroundColor = "rgba(245, 168, 93, " + transparencyValue + ")"; 28} 29function resetBluescale(){ 30 var elementToChange = document.getElementById("shader-bluefilter"); 31 elementToChange.style.display = "none"; 32 Cookies.remove('acc_bluescale', COOKIE_REMOVE_OPTS); 33 var bluefilterSlider = document.getElementById('bluefilterAcc'); 34 bluefilterSlider.value = 0; 35} 36 37/* Greyscale-Regel */ 38/*******************/ 39function changeGreyscale(value) { 40 Cookies.set('acc_greyscale', value, COOKIE_SET_OPTS); 41 var elementToChange = document.getElementById("shader-greyscale"); 42 var transparencyValue = value; 43 if (value === 0) { 44 elementToChange.style.display = "none"; 45 } else if (value >= 0.05 && value <= 1.0) { 46 elementToChange.style.display = "block"; 47 } 48 elementToChange.style.backgroundColor = "rgba(0, 0, 0, " + value + ")"; 49} 50function resetGreyscale(){ 51 var elementToChange = document.getElementById("shader-greyscale"); 52 elementToChange.style.display = "none"; 53 Cookies.remove('acc_greyscale', COOKIE_REMOVE_OPTS); 54 var greyscaleSlider = document.getElementById('greyscaleAcc'); 55 greyscaleSlider.value = 0; 56} 57 58/* Saturation-Regel */ 59/********************/ 60function changeSaturation(value) { 61 var elementToChange = document.getElementById("shader-saturation"); 62 if (!elementToChange) return; 63 64 var rawValue = parseFloat(value); 65 if (!Number.isFinite(rawValue)) rawValue = 0; 66 67 // Support both old 0..10 and current 0..1 slider values. 68 var transparencyValue = rawValue > 1 ? (rawValue / 10) : rawValue; 69 transparencyValue = Math.min(Math.max(transparencyValue, 0), 1); 70 71 Cookies.set('acc_saturation', transparencyValue, COOKIE_SET_OPTS); 72 73 if (transparencyValue <= 0) { 74 elementToChange.style.display = "none"; 75 } else { 76 elementToChange.style.display = "block"; 77 } 78 elementToChange.style.backgroundColor = "rgba(0, 255, 0, " + transparencyValue + ")"; 79} 80function resetSaturation(){ 81 var elementToChange = document.getElementById("shader-saturation"); 82 if (elementToChange) { 83 elementToChange.style.display = "none"; 84 } 85 Cookies.remove('acc_saturation', COOKIE_REMOVE_OPTS); 86 var saturationSlider = document.getElementById('saturationAcc'); 87 if (saturationSlider) saturationSlider.value = 0; 88} 89 90/* Kontrast einstellen */ 91/***********************/ 92function getContrastTargets() { 93 if (!document.body) return []; 94 var targets = Array.from(document.body.children).filter(function(el) { 95 if (!el || !el.matches) return false; 96 return !el.matches('header, #accesible, .modal-backdrop, #accScreenreaderPanel, #shader-bluefilter, #shader-greyscale, #shader-saturation, #acc-colorweakness-overlay, script, style, link, meta, title'); 97 }); 98 var standardNavigation = document.querySelector('header > #nav'); 99 if (standardNavigation) targets.push(standardNavigation); 100 return targets; 101} 102 103function changeContrast(value) { 104 Cookies.set('acc_contrast', value, COOKIE_SET_OPTS); 105 var contrastValue = parseFloat(value); 106 var targets = getContrastTargets(); 107 targets.forEach(function(target) { 108 target.style.setProperty('filter', 'contrast(' + contrastValue + ')'); 109 }); 110} 111function resetContrast(){ 112 var targets = getContrastTargets(); 113 targets.forEach(function(target) { 114 target.style.removeProperty('filter'); 115 }); 116 Cookies.remove('acc_contrast', COOKIE_REMOVE_OPTS); 117 var contrastSlider = document.getElementById('contrastAcc'); 118 contrastSlider.value = 0; 119} 120 121/* function changeFontsize(size) { 122 if (size === 1.0) { 123 Cookies.remove('acc_fontsize'); 124 document.body.classList.remove('accFontSizeActive'); 125 } else { 126 Cookies.set('acc_fontsize', size); 127 document.body.classList.add('accFontSizeActive'); 128 } 129 130 const selector = 'p, ul, li, span, a, small, h1, h2, h3, h4, h5, h6, b, img'; 131 const all = Array.from(document.querySelectorAll(selector)); 132 all.forEach(el => { 133 if (el.closest('.excludeAcc')) return; 134 if (el.tagName.toLowerCase() === 'a' && el.closest('p, li, h1, h2, h3, h4, h5, h6')) { 135 return; 136 } 137 if (el.tagName.toLowerCase() === 'img') { 138 if (!(el.closest('p') || el.closest('a'))) return; 139 if (!el.dataset.baseWidth || !el.dataset.baseHeight) {
140 const baseW = el.naturalWidth || el.offsetWidth || 0; 141 const baseH = el.naturalHeight || el.offsetHeight || 0; 142 if (baseW > 0) el.dataset.baseWidth = baseW; 143 if (baseH > 0) el.dataset.baseHeight = baseH; 144 } 145 if (size === 1.0) { 146 el.style.removeProperty('width'); 147 el.style.removeProperty('height'); 148 } else { 149 const baseW = parseFloat(el.dataset.baseWidth || el.offsetWidth); 150 const baseH = parseFloat(el.dataset.baseHeight || el.offsetHeight); 151 if (baseW > 0) { 152 el.style.setProperty('width', (baseW * size) + "px", 'important'); 153 } 154 if (baseH > 0) { 155 el.style.setProperty('height', (baseH * size) + "px", 'important'); 156 } 157 } 158 return; 159 } 160 if (!el.dataset.baseFontsize) { 161 const computed = window.getComputedStyle(el).fontSize; 162 el.dataset.baseFontsize = parseFloat(computed); 163 } 164 if (size === 1.0) { 165 el.style.removeProperty('font-size'); 166 } else { 167 const base = parseFloat(el.dataset.baseFontsize); 168 const newSize = base * size; 169 el.style.setProperty('font-size', newSize + "px", 'important'); 170 } 171 }); 172} 173 174function resetFontsize() { 175 const selector = 'p, ul, li, span, a, small, h1, h2, h3, h4, h5, h6, b, img'; 176 const all = Array.from(document.querySelectorAll(selector)); 177 all.forEach(el => { 178 if (el.closest('.excludeAcc')) return; 179 if (el.tagName.toLowerCase() === 'a' && el.closest('p, li, h1, h2, h3, h4, h5, h6')) { 180 return; 181 } 182 if (el.tagName.toLowerCase() === 'img' && (el.closest('p') || el.closest('a'))) { 183 el.style.removeProperty('width'); 184 el.style.removeProperty('height'); 185 return; 186 } 187 el.style.removeProperty('font-size'); 188 }); 189 Cookies.remove('acc_fontsize'); 190 document.body.classList.remove('accFontSizeActive'); 191 const fontsizeSlider = document.getElementById('fontsizeAcc'); 192 if (fontsizeSlider) fontsizeSlider.value = 1.0; 193} 194 195function changeLinespacing(size){ 196 Cookies.set('acc_linespacing', size, COOKIE_SET_OPTS); 197 document.querySelectorAll('p').forEach(el => { 198 if (el.closest('.excludeAcc')) return; 199 el.style.lineHeight = size + "em"; 200 }); 201 const newSmall = size * 0.875; 202 document.querySelectorAll('small').forEach(el => { 203 if (el.closest('.excludeAcc')) return; 204 el.style.lineHeight = newSmall + "em"; 205 }); 206 const newH1 = size * 42; 207 document.querySelectorAll('h1').forEach(el => { 208 if (el.closest('.excludeAcc')) return; 209 el.style.lineHeight = newH1 + "px"; 210 }); 211 const newH2 = size * 34; 212 document.querySelectorAll('h2').forEach(el => { 213 if (el.closest('.excludeAcc')) return; 214 el.style.lineHeight = newH2 + "px"; 215 }); 216 const newH4 = size * 18; 217 document.querySelectorAll('h4').forEach(el => { 218 if (el.closest('.excludeAcc')) return; 219 el.style.lineHeight = newH4 + "px"; 220 }); 221 document.querySelectorAll('li').forEach(el => { 222 if (el.closest('.excludeAcc')) return; 223 el.style.lineHeight = size + "em"; 224 }); 225 const newSpanFact = size * 14; 226 document.querySelectorAll('.entr.tour .entr-facts div').forEach(el => { 227 if (el.closest('.excludeAcc')) return; 228 el.style.lineHeight = newSpanFact + "px"; 229 }); 230} 231 232function resetLinespacing(){ 233 var size = 1.8; 234 document.querySelectorAll('p').forEach(el => { 235 if (el.closest('.excludeAcc')) return; 236 el.style.lineHeight = size + "em"; 237 }); 238 const newSmall = size * 0.875; 239 document.querySelectorAll('small').forEach(el => { 240 if (el.closest('.excludeAcc')) return; 241 el.style.lineHeight = newSmall + "em"; 242 }); 243 const newH1 = size * 42; 244 document.querySelectorAll('h1').forEach(el => { 245 if (el.closest('.excludeAcc')) return; 246 el.style.lineHeight = newH1 + "px"; 247 }); 248 const newH2 = size * 34; 249 document.querySelectorAll('h2').forEach(el => { 250 if (el.closest('.excludeAcc')) return; 251 el.style.lineHeight = newH2 + "px"; 252 }); 253 const newH4 = size * 18; 254 document.querySelectorAll('h4').forEach(el => { 255 if (el.closest('.excludeAcc')) return; 256 el.style.lineHeight = newH4 + "px"; 257 }); 258 document.querySelectorAll('li').forEach(el => { 259 if (el.closest('.excludeAcc')) return; 260 el.style.lineHeight = size + "em"; 261 }); 262 const newSpanFact = size * 14; 263 document.querySelectorAll('.entr.tour .entr-facts div').forEach(el => { 264 if (el.closest('.excludeAcc')) return; 265 el.style.lineHeight = newSpanFact + "px"; 266 }); 267 Cookies.remove('acc_linespacing', COOKIE_REMOVE_OPTS); 268 var linespacingSlider = document.getElementById('linespacingAcc'); 269 if (linespacingSlider) linespacingSlider.value = 1.8; 270} */ 271 272/* Schriftgröße und Zeilenabstand */ 273/**********************************/ 274(() => { 275 const COOKIE_KEY_SCALE = 'acc_fontsize'; 276 const LEGACY_COOKIE_LS = 'acc_linespacing'; 277 const COOKIE_SET_OPTS = (typeof window.COOKIE_SET_OPTS !== 'undefined') 278 ? window.COOKIE_SET_OPTS 279 : { expires: 365, sameSite: 'Lax' }; 280 const COOKIE_REMOVE_OPTS = (typeof window.COOKIE_REMOVE_OPTS !== 'undefined') 281 ? window.COOKIE_REMOVE_OPTS 282 : { sameSite: 'Lax' }; 283 const BASE_LS = 1.8; 284 const BASE_SMALL_F = 0.875; 285 const BASE_H1_PX = 42; 286 const BASE_H2_PX = 34; 287 const BASE_H4_PX = 18; 288 const BASE_FACTS_PX = 14; 289 const BNAV_MIN_FS = 18; 290 const DOWNLOADS_MIN_FS = 18; 291 const BNAV_MIN_SELECTOR = '.label, .mainmenu__item, .sidemenu__item, .menu__item-link, .menu__item-hoverlink'; 292 // const TEXT_SELECTOR = 'p, ul, li, span, a, small, h1, h2, h3, h4, h5, h6, b'; 293 const TEXT_SELECTOR = 'p, ul, li, span, a, small, h1, h2, h3, h4, h5, h6, b, label, select, option, button'; 294 const EXCLUDE_SEL = '.excludeAcc, .pill-button, #accesible, #accScreenreaderPanel'; 295 const clamp = (n, min, max) => Math.min(Math.max(n, min), max); 296 const isInside = (el, selector) => !!el.closest(selector); 297 const enforceBnavMinFont = (el) => ( 298 !!el.closest('#bnav') && ( 299 el.matches(BNAV_MIN_SELECTOR) || !!el.closest(BNAV_MIN_SELECTOR) 300 ) 301 ); 302 const enforceDownloadsMinFont = (el) => !!el.closest('#downloads'); 303 const getNumberPx = (val) => { 304 const x = parseFloat(val); 305 return Number.isFinite(x) ? x : NaN; 306 }; 307 let pendingScale = 1.0; 308 let rafId = null; 309 function scheduleApplyScale(scale) { 310 pendingScale = scale; 311 if (rafId != null) return; 312 rafId = requestAnimationFrame(() => { 313 rafId = null; 314 applyScale(pendingScale); 315 }); 316 } 317 function applyScale(scale) { 318 const s = scale; 319 if (s === 1.0) { 320 document.body.classList.remove('accFontSizeActive'); 321 } else { 322 document.body.classList.add('accFontSizeActive'); 323 } 324 const all = document.querySelectorAll(TEXT_SELECTOR); 325 all.forEach((el) => { 326 if (isInside(el, EXCLUDE_SEL)) return; 327 const tag = el.tagName.toLowerCase(); 328 if (tag === 'a' && el.closest('p, li, h1, h2, h3, h4, h5, h6')) return; 329 if (!el.dataset.baseFontsize) { 330 const compFS = getNumberPx(getComputedStyle(el).fontSize); 331 if (Number.isFinite(compFS)) { 332 el.dataset.baseFontsize = String(compFS); 333 } 334 } 335 const baseFS = parseFloat(el.dataset.baseFontsize || ''); 336 const bnavMin = enforceBnavMinFont(el) ? BNAV_MIN_FS : 0; 337 const downloadsMin = enforceDownloadsMinFont(el) ? DOWNLOADS_MIN_FS : 0; 338 const requiredMin = Math.max(bnavMin, downloadsMin); 339 if (s === 1.0) { 340 if (requiredMin > 0 && Number.isFinite(baseFS) && baseFS < requiredMin) { 341 el.style.setProperty('font-size', requiredMin + 'px', 'important'); 342 } else { 343 el.style.removeProperty('font-size'); 344 } 345 } else if (Number.isFinite(baseFS)) { 346 let newFontSize = baseFS * s; 347 if (requiredMin > 0) { 348 newFontSize = Math.max(newFontSize, requiredMin); 349 } 350 el.style.setProperty('font-size', newFontSize + 'px', 'important'); 351 } 352 let targetLHpx = null; 353 if (tag === 'p' || tag === 'li') { 354 if (Number.isFinite(baseFS)) { 355 targetLHpx = baseFS * BASE_LS * s; 356 } 357 } else if (tag === 'small') { 358 if (Number.isFinite(baseFS)) { 359 targetLHpx = baseFS * (BASE_LS * BASE_SMALL_F) * s; 360 } 361 } else if (tag === 'h1') { 362 targetLHpx = BASE_LS * BASE_H1_PX * s; 363 } else if (tag === 'h2') { 364 targetLHpx = BASE_LS * BASE_H2_PX * s; 365 } else if (tag === 'h4') {
366 targetLHpx = BASE_LS * BASE_H4_PX * s; 367 } 368 if (el.matches('.entr.tour .entr-facts div')) { 369 targetLHpx = BASE_LS * BASE_FACTS_PX * s; 370 } 371 if (s === 1.0) { 372 el.style.removeProperty('line-height'); 373 } else if (Number.isFinite(targetLHpx)) { 374 el.style.setProperty('line-height', targetLHpx + 'px', 'important'); 375 } 376 }); 377 } 378 window.changeFontsize = function changeFontsize(scaleLike) { 379 const raw = parseFloat(scaleLike); 380 const s = clamp(Number.isFinite(raw) ? raw : 1.0, 0.5, 3.0); 381 if (s === 1.0) { 382 if (window.Cookies?.remove) Cookies.remove(COOKIE_KEY_SCALE, COOKIE_REMOVE_OPTS); 383 } else { 384 if (window.Cookies?.set) Cookies.set(COOKIE_KEY_SCALE, s, COOKIE_SET_OPTS); 385 } 386 scheduleApplyScale(s); 387 }; 388 window.resetFontsize = function resetFontsize() { 389 const elements = document.querySelectorAll(TEXT_SELECTOR); 390 elements.forEach((el) => { 391 if (isInside(el, EXCLUDE_SEL)) return; 392 el.style.removeProperty('font-size'); 393 el.style.removeProperty('line-height'); 394 }); 395 if (window.Cookies?.remove) { 396 Cookies.remove(COOKIE_KEY_SCALE, COOKIE_REMOVE_OPTS); 397 Cookies.remove(LEGACY_COOKIE_LS, COOKIE_REMOVE_OPTS); 398 } 399 document.body.classList.remove('accFontSizeActive'); 400 const slider = document.getElementById('fontsizeAcc'); 401 if (slider) slider.value = 1.0; 402 scheduleApplyScale(1.0); 403 }; 404 function migrateLegacyCookieIfNeeded() { 405 if (!window.Cookies?.get) return null; 406 const legacy = Cookies.get(LEGACY_COOKIE_LS); 407 if (!legacy) return null; 408 const legacySize = parseFloat(legacy); 409 if (!Number.isFinite(legacySize) || legacySize <= 0) { 410 Cookies.remove(LEGACY_COOKIE_LS, COOKIE_REMOVE_OPTS); 411 return null; 412 } 413 const scale = clamp(legacySize / BASE_LS, 0.5, 3.0); 414 Cookies.set(COOKIE_KEY_SCALE, scale, COOKIE_SET_OPTS); 415 Cookies.remove(LEGACY_COOKIE_LS, COOKIE_REMOVE_OPTS); 416 return scale; 417 } 418 function initFromCookieOrDefault() { 419 let scale = 1.0; 420 const migrated = migrateLegacyCookieIfNeeded(); 421 if (migrated != null) { 422 scale = migrated; 423 } else if (window.Cookies?.get) { 424 const saved = parseFloat(Cookies.get(COOKIE_KEY_SCALE) || ''); 425 if (Number.isFinite(saved) && saved > 0) { 426 scale = saved; 427 } 428 } 429 const slider = document.getElementById('fontsizeAcc'); 430 if (slider) slider.value = String(scale); 431 applyScale(scale); 432 } 433 if (document.readyState === 'loading') { 434 document.addEventListener('DOMContentLoaded', initFromCookieOrDefault, { once: true }); 435 } else { 436 initFromCookieOrDefault(); 437 } 438 } 439)(); 440 441/* Vorlesefunktion */ 442/*******************/ 443var lastSelectedReadableText = ''; 444var lastAccessibilityTrigger = null; 445var accScreenreaderDrag = { 446 isDragging: false, 447 offsetX: 0, 448 offsetY: 0 449}; 450 451function initAccessibilityModalFocus() { 452 var modalEl = document.getElementById('accesible'); 453 if (!modalEl) return; 454 455 document.addEventListener('click', function(event) { 456 var trigger = event.target.closest('.openModalBtn'); 457 if (trigger) { 458 lastAccessibilityTrigger = trigger; 459 } 460 }); 461 462 modalEl.addEventListener('shown.bs.modal', function() { 463 modalEl.setAttribute('aria-hidden', 'false'); 464 var closeButton = modalEl.querySelector('.acc-modal-close'); 465 if (closeButton) closeButton.focus(); 466 }); 467 468 modalEl.addEventListener('hidden.bs.modal', function() { 469 modalEl.setAttribute('aria-hidden', 'true'); 470 if (lastAccessibilityTrigger && document.contains(lastAccessibilityTrigger)) { 471 lastAccessibilityTrigger.focus(); 472 } 473 }); 474} 475 476if (document.readyState === 'loading') { 477 document.addEventListener('DOMContentLoaded', initAccessibilityModalFocus, { once: true }); 478} else { 479 initAccessibilityModalFocus(); 480} 481 482function setScreenreaderStatus(message) { 483 var status = document.getElementById('accScreenreaderStatus'); 484 if (status) { 485 status.textContent = message; 486 } 487} 488 489function cleanupAccessibilityModalArtifacts() { 490 document.body.classList.remove('modal-open'); 491 document.body.style.removeProperty('padding-right'); 492 document.querySelectorAll('.modal-backdrop').forEach(function(backdrop) { 493 backdrop.remove(); 494 }); 495} 496 497function closeAccessibilityModalForReading() { 498 var modalEl = document.getElementById('accesible'); 499 if (!modalEl) { 500 return; 501 } 502 503 if (window.bootstrap && window.bootstrap.Modal) { 504 var instance = window.bootstrap.Modal.getInstance(modalEl); 505 if (instance) { 506 instance.hide(); 507 } 508 } 509 510 modalEl.classList.remove('show'); 511 modalEl.style.display = 'none'; 512 modalEl.setAttribute('aria-hidden', 'true'); 513 514 setTimeout(cleanupAccessibilityModalArtifacts, 180); 515} 516 517function openScreenreaderPanel() { 518 closeAccessibilityModalForReading(); 519 var panel = document.getElementById('accScreenreaderPanel'); 520 if (panel) { 521 panel.hidden = false;
522 if (!panel.dataset.positioned) { 523 panel.style.top = '96px'; 524 panel.style.right = '16px'; 525 panel.style.left = 'auto'; 526 panel.dataset.positioned = 'true'; 527 } 528 window.setTimeout(function() { 529 var closeButton = panel.querySelector('.acc-screenreader-close'); 530 if (closeButton) closeButton.focus(); 531 }, 220); 532 } 533 setScreenreaderStatus('Text markieren und auf "Vorlesen starten" klicken.'); 534} 535 536function closeScreenreaderPanel() { 537 stopSelectedText(); 538 var panel = document.getElementById('accScreenreaderPanel'); 539 if (panel) { 540 panel.hidden = true; 541 } 542} 543 544function readSelectedText() { 545 var selectedText = getSelectedText(); 546 if (!selectedText) { 547 selectedText = lastSelectedReadableText; 548 } 549 if (!selectedText) { 550 setScreenreaderStatus('Bitte markiere zuerst einen Text auf der Seite.'); 551 return; 552 } 553 speakText(selectedText); 554} 555 556function getSelectedText() { 557 var text = ''; 558 if (typeof window.getSelection !== 'undefined') { 559 text = window.getSelection().toString(); 560 } else if (typeof document.selection !== 'undefined' && document.selection.type === 'Text') { 561 text = document.selection.createRange().text; 562 } 563 return text.trim(); 564} 565 566function speakText(text) { 567 if (!('speechSynthesis' in window) || typeof window.SpeechSynthesisUtterance === 'undefined') { 568 setScreenreaderStatus('Vorlesen wird von diesem Browser nicht unterstuetzt.'); 569 return; 570 } 571 572 var utterance = new SpeechSynthesisUtterance(text); 573 var lang = document.documentElement.lang || 'de'; 574 utterance.lang = lang; 575 576 var voices = window.speechSynthesis.getVoices(); 577 var voice = voices.find(function(v) { return v.lang && v.lang.indexOf(lang) === 0; }); 578 if (voice) { 579 utterance.voice = voice; 580 } 581 582 utterance.onstart = function() { 583 setScreenreaderStatus('Vorlesen gestartet.'); 584 }; 585 utterance.onend = function() { 586 setScreenreaderStatus('Vorlesen beendet.'); 587 }; 588 utterance.onerror = function() { 589 setScreenreaderStatus('Vorlesen konnte nicht gestartet werden.'); 590 }; 591 592 window.speechSynthesis.cancel(); 593 window.speechSynthesis.speak(utterance); 594} 595 596function stopSelectedText() { 597 if ('speechSynthesis' in window) { 598 window.speechSynthesis.cancel(); 599 } 600 setScreenreaderStatus('Vorlesen gestoppt.'); 601} 602 603function clampScreenreaderPosition(panel, left, top) { 604 var maxLeft = Math.max(8, window.innerWidth - panel.offsetWidth - 8); 605 var maxTop = Math.max(8, window.innerHeight - panel.offsetHeight - 8); 606 return { 607 left: Math.min(Math.max(8, left), maxLeft), 608 top: Math.min(Math.max(8, top), maxTop) 609 }; 610} 611 612function startScreenreaderDrag(clientX, clientY) { 613 var panel = document.getElementById('accScreenreaderPanel'); 614 if (!panel || panel.hidden) { 615 return; 616 } 617 var rect = panel.getBoundingClientRect(); 618 if (rect.width === 0 || rect.height === 0) { 619 return; 620 } 621 accScreenreaderDrag.isDragging = true; 622 accScreenreaderDrag.offsetX = clientX - rect.left; 623 accScreenreaderDrag.offsetY = clientY - rect.top; 624 document.body.classList.add('acc-screenreader-dragging'); 625} 626 627function moveScreenreaderDrag(clientX, clientY) { 628 if (!accScreenreaderDrag.isDragging) { 629 return; 630 } 631 var panel = document.getElementById('accScreenreaderPanel'); 632 if (!panel) { 633 return; 634 } 635 var nextLeft = clientX - accScreenreaderDrag.offsetX; 636 var nextTop = clientY - accScreenreaderDrag.offsetY; 637 var clamped = clampScreenreaderPosition(panel, nextLeft, nextTop); 638 panel.style.left = clamped.left + 'px'; 639 panel.style.top = clamped.top + 'px'; 640 panel.style.right = 'auto'; 641} 642 643function stopScreenreaderDrag() { 644 accScreenreaderDrag.isDragging = false; 645 document.body.classList.remove('acc-screenreader-dragging'); 646} 647 648function initScreenreaderPanelInteractions() { 649 if (window.__accScreenreaderPanelInit) { 650 return; 651 } 652 window.__accScreenreaderPanelInit = true; 653 654 document.addEventListener('selectionchange', function() { 655 var selected = getSelectedText(); 656 if (selected) { 657 lastSelectedReadableText = selected; 658 setScreenreaderStatus('Text markiert. Klicke auf "Vorlesen starten".'); 659 } 660 }); 661 662 var handle = document.getElementById('accScreenreaderDragHandle'); 663 if (handle) { 664 handle.addEventListener('mousedown', function(event) { 665 if (event.button !== 0) { 666 return; 667 } 668 event.preventDefault(); 669 startScreenreaderDrag(event.clientX, event.clientY); 670 }); 671 672 handle.addEventListener('touchstart', function(event) { 673 if (!event.touches || !event.touches.length) { 674 return; 675 } 676 startScreenreaderDrag(event.touches[0].clientX, event.touches[0].clientY); 677 }, { passive: true }); 678 } 679 680 document.addEventListener('mousemove', function(event) { 681 moveScreenreaderDrag(event.clientX, event.clientY); 682 }); 683 document.addEventListener('touchmove', function(event) { 684 if (!event.touches || !event.touches.length) { 685 return; 686 } 687 moveScreenreaderDrag(event.touches[0].clientX, event.touches[0].clientY); 688 }, { passive: true }); 689 690 document.addEventListener('mouseup', stopScreenreaderDrag); 691 document.addEventListener('touchend', stopScreenreaderDrag, { passive: true }); 692 693 window.addEventListener('keydown', function(event) { 694 if (event.key === 'Escape') { 695 closeScreenreaderPanel(); 696 } 697 }); 698 699 window.addEventListener('resize', function() { 700 var panel = document.getElementById('accScreenreaderPanel'); 701 if (!panel || panel.hidden) { 702 return; 703 } 704 var rect = panel.getBoundingClientRect(); 705 var clamped = clampScreenreaderPosition(panel, rect.left, rect.top); 706 panel.style.left = clamped.left + 'px'; 707 panel.style.top = clamped.top + 'px'; 708 panel.style.right = 'auto'; 709 }); 710} 711 712if (document.readyState === 'loading') { 713 document.addEventListener('DOMContentLoaded', initScreenreaderPanelInteractions, { once: true }); 714} else { 715 initScreenreaderPanelInteractions(); 716} 717 718/* Lichtbar einblenden */ 719/***********************/ 720function showLightbar() { 721 var checkbox = document.getElementById('lightbarAcc'); 722 var lightbartop = document.getElementById('light-bar-top'); 723 var lightbarbottom = document.getElementById('light-bar-bottom'); 724 if (checkbox.checked) { 725 lightbartop.style.display = 'block'; 726 lightbarbottom.style.display = 'block'; 727 Cookies.set('acc_lightbar', 'true', COOKIE_SET_OPTS); 728 } else { 729 lightbartop.style.display = 'none'; 730 lightbarbottom.style.display = 'none'; 731 Cookies.set('acc_lightbar', 'false', COOKIE_SET_OPTS); 732 } 733} 734function resetLightbar() { 735 var checkbox = document.getElementById('lightbarAcc'); 736 var lightbartop = document.getElementById('light-bar-top'); 737 var lightbarbottom = document.getElementById('light-bar-bottom'); 738 checkbox.checked = false;
739 lightbartop.style.display = 'none'; 740 lightbarbottom.style.display = 'none'; 741 Cookies.remove('acc_lightbar', COOKIE_REMOVE_OPTS); 742} 743function updatePositionDisplay(event) { 744 var lightbartop = document.getElementById('light-bar-top'); 745 var lightbarbottom = document.getElementById('light-bar-bottom'); 746 var mouseYBtm = window.innerHeight - event.clientY; 747 var mouseYTop = event.clientY; 748 var offsetYBtm = mouseYBtm - 100; 749 var offsetYTop = mouseYTop - 100; 750 lightbarbottom.style.height = offsetYBtm + 'px'; 751 lightbartop.style.height = offsetYTop + 'px'; 752} 753document.addEventListener("DOMContentLoaded", function() { 754 var checkbox = document.getElementById('lightbarAcc'); 755 var lightbartop = document.getElementById('light-bar-top'); 756 var lightbarbottom = document.getElementById('light-bar-bottom'); 757 if (Cookies.get('acc_lightbar') === 'true') { 758 checkbox.checked = true; 759 lightbartop.style.display = 'block'; 760 lightbarbottom.style.display = 'block'; 761 } else { 762 checkbox.checked = false; 763 lightbartop.style.display = 'none'; 764 lightbarbottom.style.display = 'none'; 765 } 766}); 767window.addEventListener('mousemove', updatePositionDisplay); 768 769 770function convertLegacyActionButtonToSwitch(buttonId, labelId, defaultLabel, onchangeFn) { 771 var oldEl = document.getElementById(buttonId); 772 if (!oldEl || oldEl.tagName.toLowerCase() !== 'button') { 773 return; 774 } 775 776 var labelCard = document.createElement('label'); 777 labelCard.className = 'acc-switch-card'; 778 labelCard.setAttribute('for', buttonId); 779 780 var labelSpan = document.createElement('span'); 781 labelSpan.id = labelId; 782 labelSpan.textContent = defaultLabel; 783 784 var input = document.createElement('input'); 785 input.className = 'acc-switch-input'; 786 input.type = 'checkbox'; 787 input.id = buttonId; 788 input.setAttribute('onchange', onchangeFn + '()'); 789 790 // Preserve visible state from legacy button text/cookies if present. 791 var legacyText = (oldEl.textContent || '').toLowerCase(); 792 if (buttonId === 'nopicAcc') { 793 input.checked = legacyText.indexOf('einblenden') !== -1 || oldEl.dataset.hidden === 'true'; 794 } 795 if (buttonId === 'animationAcc') { 796 input.checked = legacyText.indexOf('einschalten') !== -1; 797 } 798 799 var ui = document.createElement('span'); 800 ui.className = 'acc-switch-ui'; 801 ui.setAttribute('aria-hidden', 'true'); 802 803 labelCard.appendChild(labelSpan); 804 labelCard.appendChild(input); 805 labelCard.appendChild(ui); 806 807 oldEl.replaceWith(labelCard); 808} 809 810function normalizeConcentrationSwitches() { 811 convertLegacyActionButtonToSwitch('nopicAcc', 'nopicAccLabel', 'Bilder ausblenden', 'toggleImages'); 812 convertLegacyActionButtonToSwitch('animationAcc', 'animationAccLabel', 'Animationen ausschalten', 'toggleAnimation'); 813} 814 815if (document.readyState === 'loading') { 816 document.addEventListener('DOMContentLoaded', normalizeConcentrationSwitches, { once: true }); 817} else { 818 normalizeConcentrationSwitches(); 819} 820/* Hidden Images */ 821/* ************* */ 822function setImagesHidden(hidden) { 823 var elements = document.getElementsByTagName('*'); 824 var checkbox = document.getElementById('nopicAcc'); 825 var label = document.getElementById('nopicAccLabel'); 826 827 for (var i = 0; i < elements.length; i++) { 828 var el = elements[i]; 829 var tag = el.tagName; 830 831 if (tag === 'IMG') { 832 if (hidden) { 833 if (!el.classList.contains('activeNoPicFilter')) el.classList.add('activeNoPicFilter'); 834 el.style.visibility = 'hidden'; 835 } else { 836 el.classList.remove('activeNoPicFilter'); 837 el.style.removeProperty('visibility'); 838 } 839 continue; 840 } 841 842 if (tag === 'CANVAS') { 843 if (hidden) { 844 if (!el.classList.contains('activeNoPicFilter')) el.classList.add('activeNoPicFilter'); 845 el.style.visibility = 'hidden'; 846 } else { 847 el.classList.remove('activeNoPicFilter'); 848 el.style.removeProperty('visibility'); 849 } 850 continue; 851 } 852 853 var bg = window.getComputedStyle(el).backgroundImage; 854 if (hidden) { 855 if (bg && bg !== 'none') { 856 if (!el.dataset.bgImage) { 857 el.dataset.bgImage = bg; 858 } 859 el.classList.add('has-background-image', 'activeNoPicFilter'); 860 el.style.backgroundImage = 'none'; 861 } 862 } else { 863 if (el.classList.contains('has-background-image') || el.classList.contains('activeNoPicFilter')) { 864 el.classList.remove('has-background-image', 'activeNoPicFilter'); 865 if (el.dataset.bgImage) { 866 el.style.backgroundImage = el.dataset.bgImage; 867 delete el.dataset.bgImage; 868 } else { 869 el.style.removeProperty('background-image'); 870 } 871 } 872 } 873 } 874 875 if (checkbox) { 876 checkbox.checked = hidden; 877 checkbox.dataset.hidden = hidden ? 'true' : 'false'; 878 } 879 if (label) { 880 label.textContent = hidden ? 'Bilder einblenden' : 'Bilder ausblenden'; 881 } 882 883 document.body.classList.toggle('accImagesHiddenActive', hidden); 884 Cookies.set('acc_toggleImages', hidden ? 'true' : 'false', COOKIE_SET_OPTS); 885} 886 887function resetImagesHidden() { 888 setImagesHidden(false); 889 Cookies.remove('acc_toggleImages', COOKIE_REMOVE_OPTS); 890} 891 892function toggleImages() { 893 var checkbox = document.getElementById('nopicAcc'); 894 if (checkbox) { 895 setImagesHidden(checkbox.checked); 896 } else { 897 var current = Cookies.get('acc_toggleImages') === 'true'; 898 setImagesHidden(!current); 899 } 900} 901 902/* Turn off Animation */ 903/**********************/ 904function applyAnimationState(disabled) { 905 var elements = document.getElementsByTagName('*'); 906 var checkbox = document.getElementById('animationAcc'); 907 var label = document.getElementById('animationAccLabel'); 908 909 for (var i = 0; i < elements.length; i++) { 910 var element = elements[i]; 911 if (disabled) { 912 if (element.classList.contains('reveal')) { 913 if (!element.getAttribute('data-original-class')) { 914 element.setAttribute('data-original-class', element.className); 915 } 916 element.classList.remove('reveal'); 917 } 918 } else { 919 var originalClass = element.getAttribute('data-original-class'); 920 if (originalClass && originalClass.indexOf('reveal') !== -1) { 921 element.className = originalClass; 922 element.removeAttribute('data-original-class'); 923 } 924 } 925 } 926 927 var fogs = document.getElementsByClassName('fog-bg'); 928 for (var j = 0; j < fogs.length; j++) { 929 fogs[j].style.display = disabled ? 'block' : 'none'; 930 } 931 932 var classTargets = ['omj-cta', 'covercontainer', 'vertical-line']; 933 for (var k = 0; k < classTargets.length; k++) { 934 var items = document.getElementsByClassName(classTargets[k]); 935 for (var m = 0; m < items.length; m++) { 936 items[m].classList.toggle('no-animate', disabled); 937 } 938 } 939 940 if (checkbox) { 941 checkbox.checked = disabled; 942 } 943 if (label) { 944 label.textContent = disabled ? 'Animationen einschalten' : 'Animationen ausschalten'; 945 } 946 947 Cookies.set('acc_animation', disabled ? 'true' : 'false', COOKIE_SET_OPTS); 948} 949 950function toggleAnimation() { 951 var checkbox = document.getElementById('animationAcc'); 952 if (checkbox) { 953 applyAnimationState(checkbox.checked); 954 } else { 955 var current = Cookies.get('acc_animation') === 'true'; 956 applyAnimationState(!current); 957 } 958} 959 960function resetAnimation() { 961 applyAnimationState(false); 962 Cookies.remove('acc_animation', COOKIE_REMOVE_OPTS); 963} 964/* Farbschwaechen-Modi */ 965/**********************/ 966const COLOR_WEAKNESS_MODES = ['protanomalyAcc', 'deuteranomalyAcc', 'tritanomalyAcc']; 967const COLOR_WEAKNESS_CLASS_MAP = { 968 protanomalyAcc: 'acc-cw-protanomaly', 969 deuteranomalyAcc: 'acc-cw-deuteranomaly', 970 tritanomalyAcc: 'acc-cw-tritanomaly' 971}; 972const COLOR_WEAKNESS_ALL_CLASSES = ['acc-cw-protanomaly', 'acc-cw-deuteranomaly', 'acc-cw-tritanomaly']; 973 974function normalizeColorWeaknessMode(mode) { 975 var map = { 976 protanomaly: 'protanomalyAcc', 977 deuteranomaly: 'deuteranomalyAcc', 978 tritanomaly: 'tritanomalyAcc' 979 }; 980 return map[mode] || mode; 981} 982 983function getColorWeaknessOverlay() { 984 return document.getElementById('acc-colorweakness-overlay'); 985} 986 987function clearColorWeaknessTargetClasses() { 988 document.querySelectorAll('.acc-colorweakness-target').forEach(function (el) { 989 el.classList.remove('acc-colorweakness-target'); 990 COLOR_WEAKNESS_ALL_CLASSES.forEach(function (cls) { 991 el.classList.remove(cls); 992 }); 993 }); 994} 995 996function getColorWeaknessTargets() { 997 var baseTargets = Array.from(document.querySelectorAll('img, video, canvas, .bg-cover, .covercontainer')); 998 var bgTargets = []; 999 document.querySelectorAll('section, article, div, li, a, figure').forEach(function (el) { 1000 if (el.closest('#accesible, #accScreenreaderPanel, .excludeAcc')) { 1001 return; 1002 } 1003 var bg = window.getComputedStyle(el).backgroundImage; 1004 if (bg && bg !== 'none') { 1005 bgTargets.push(el); 1006 } 1007 }); 1008 return Array.from(new Set(baseTargets.concat(bgTargets))); 1009} 1010 1011function applyColorWeaknessMode(modeId) { 1012 var modeClass = COLOR_WEAKNESS_CLASS_MAP[modeId] || '';
1013 var overlay = getColorWeaknessOverlay(); 1014 1015 clearColorWeaknessTargetClasses(); 1016 document.body.classList.remove('acc-colorweakness-active'); 1017 COLOR_WEAKNESS_ALL_CLASSES.forEach(function (cls) { 1018 document.body.classList.remove(cls); 1019 }); 1020 1021 if (overlay) { 1022 overlay.className = 'acc-colorweakness-overlay'; 1023 } 1024 1025 if (!modeClass) { 1026 Cookies.remove('acc_colorweakness', COOKIE_REMOVE_OPTS); 1027 return; 1028 } 1029 1030 getColorWeaknessTargets().forEach(function (el) { 1031 el.classList.add('acc-colorweakness-target', modeClass); 1032 }); 1033 1034 document.body.classList.add('acc-colorweakness-active', modeClass); 1035 1036 if (overlay) { 1037 overlay.classList.add('is-active', modeClass); 1038 } 1039 1040 Cookies.set('acc_colorweakness', modeId, COOKIE_SET_OPTS); 1041} 1042 1043function resetColorWeakness() { 1044 COLOR_WEAKNESS_MODES.forEach(function (id) { 1045 var cb = document.getElementById(id); 1046 if (cb) cb.checked = false; 1047 }); 1048 applyColorWeaknessMode(''); 1049} 1050 1051function toggleColorMode(selectedId) { 1052 COLOR_WEAKNESS_MODES.forEach(function (id) { 1053 if (id !== selectedId) { 1054 var cbOther = document.getElementById(id); 1055 if (cbOther) cbOther.checked = false; 1056 } 1057 }); 1058 1059 var checkbox = document.getElementById(selectedId); 1060 if (!checkbox || !checkbox.checked) { 1061 applyColorWeaknessMode(''); 1062 return; 1063 } 1064 1065 applyColorWeaknessMode(selectedId); 1066} 1067 1068document.addEventListener('DOMContentLoaded', function () {
1069 var savedMode = normalizeColorWeaknessMode(Cookies.get('acc_colorweakness')); 1070 if (COLOR_WEAKNESS_MODES.includes(savedMode)) { 1071 var savedCb = document.getElementById(savedMode); 1072 if (savedCb) savedCb.checked = true; 1073 applyColorWeaknessMode(savedMode); 1074 } 1075}); 1076 1077/* Lade- und Uebertragsfunktion */ 1078/*******************************/ 1079document.addEventListener("DOMContentLoaded", function(event){ 1080 var bluescale = Cookies.get('acc_bluescale'); 1081 if (bluescale && bluescale.length > 0){ 1082 changeBluescale(bluescale); 1083 var sliderBluescale = document.getElementById('bluefilterAcc'); 1084 if (sliderBluescale) sliderBluescale.value = bluescale; 1085 } 1086 1087 // --- Bilder-Zustand ANWENDEN, nicht toggeln --- 1088 var hideImages = Cookies.get('acc_toggleImages') === 'true'; 1089 setImagesHidden(hideImages); 1090 1091 var lightbar = Cookies.get('acc_lightbar'); 1092 if (lightbar && lightbar === 'true'){ 1093 showLightbar(); 1094 } 1095 1096 var toggleAnim = Cookies.get('acc_animation') === 'true'; 1097 applyAnimationState(toggleAnim); 1098 1099 var greyscale = Cookies.get('acc_greyscale'); 1100 if (greyscale && greyscale.length > 0){ 1101 changeGreyscale(greyscale); 1102 var sliderGreyscale = document.getElementById('greyscaleAcc'); 1103 if (sliderGreyscale) sliderGreyscale.value = greyscale; 1104 } 1105 1106 var contrast = Cookies.get('acc_contrast'); 1107 if (contrast && contrast.length > 0){ 1108 changeContrast(contrast); 1109 var sliderContrast = document.getElementById('contrastAcc'); 1110 if (sliderContrast) sliderContrast.value = contrast; 1111 } 1112 1113 var saturation = Cookies.get('acc_saturation'); 1114 if (saturation && saturation.length > 0){ 1115 changeSaturation(saturation); 1116 var sliderSaturation = document.getElementById('saturationAcc'); 1117 if (sliderSaturation) sliderSaturation.value = saturation; 1118 }
1119 var colorweakness = normalizeColorWeaknessMode(Cookies.get('acc_colorweakness')); 1120 if (COLOR_WEAKNESS_MODES.includes(colorweakness)) { 1121 var colorCb = document.getElementById(colorweakness); 1122 if (colorCb) colorCb.checked = true; 1123 applyColorWeaknessMode(colorweakness); 1124 } 1125var fontsize = Cookies.get('acc_fontsize'); 1126 if (fontsize && fontsize.length > 0){ 1127 changeFontsize(fontsize); 1128 var sliderFontsize = document.getElementById('fontsizeAcc'); 1129 if (sliderFontsize) sliderFontsize.value = fontsize; 1130 } 1131 1132 var linespacing = Cookies.get('acc_linespacing'); 1133 if (linespacing && linespacing.length > 0 && typeof changeLinespacing === 'function'){ 1134 changeLinespacing(linespacing); 1135 var sliderLinespacing = document.getElementById('linespacingAcc'); 1136 // (Mini-Fix für falsches Zuweisen war bereits hier korrigiert, bleibt erhalten) 1137 if (sliderLinespacing) sliderLinespacing.value = linespacing; 1138 } 1139}); 1140 1141/* Zurücksetzen */ 1142/****************/ 1143function resetAcc(){ 1144 resetBluescale(); 1145 resetGreyscale(); 1146 resetSaturation(); 1147 resetContrast(); 1148 resetFontsize(); 1149 // resetLinespacing(); 1150 resetLightbar(); 1151 resetColorWeakness(); 1152 resetAnimation(); 1153 resetImagesHidden(); 1154} 1155 1156/* Keyboard focus visibility */ 1157/*****************************/ 1158(function initKeyboardFocusMode() { 1159 function setKeyboardMode() { 1160 if (!document.body) return; 1161 document.body.classList.add('using-keyboard'); 1162 document.body.classList.remove('using-mouse'); 1163 } 1164 1165 function setPointerMode() { 1166 if (!document.body) return; 1167 document.body.classList.remove('using-keyboard'); 1168 document.body.classList.add('using-mouse'); 1169 } 1170 1171 document.addEventListener('keydown', function (event) { 1172 if (event.key === 'Tab') { 1173 setKeyboardMode(); 1174 } 1175 }); 1176 1177 document.addEventListener('mousedown', setPointerMode, true); 1178 document.addEventListener('touchstart', setPointerMode, { passive: true, capture: true }); 1179})(); 1180 1181/* Third-party button accessible names */ 1182/*************************************/ 1183(function ensureThirdPartyButtonLabels() { 1184 var CLOSE_BTN_SELECTOR = 'button#pc-sb-close.pc-icon-btn'; 1185 var CLOSE_BTN_LABEL = 'Sidebar schliessen'; 1186 1187 function setAccessibleName(button, label) { 1188 if (!button) return; 1189 var current = (button.getAttribute('aria-label') || '').trim(); 1190 if (!current) { 1191 button.setAttribute('aria-label', label); 1192 } 1193 var currentTitle = (button.getAttribute('title') || '').trim(); 1194 if (!currentTitle) { 1195 button.setAttribute('title', label); 1196 } 1197 } 1198 1199 function applyLabels() { 1200 var closeBtn = document.querySelector(CLOSE_BTN_SELECTOR); 1201 if (closeBtn) {
1202 setAccessibleName(closeBtn, CLOSE_BTN_LABEL); 1203 } 1204 } 1205 1206 if (document.readyState === 'loading') { 1207 document.addEventListener('DOMContentLoaded', applyLabels, { once: true }); 1208 } else { 1209 applyLabels(); 1210 } 1211 1212 var rafPending = false; 1213 var observer = new MutationObserver(function () { 1214 if (rafPending) return; 1215 rafPending = true; 1216 requestAnimationFrame(function () { 1217 rafPending = false; 1218 applyLabels(); 1219 }); 1220 }); 1221 1222 observer.observe(document.documentElement, { childList: true, subtree: true }); 1223})(); 1224 1225 1226 1227
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.