1/** 2 * Gemeinsames Verhalten aller Seiten von relaxcrm.de. 3 * Eine Datei für alle Seiten â sonst driftet das Menü zwischen den Seiten auseinander. 4 */ 5(function () { 6 'use strict'; 7 8 // ââ Mobil-Menü âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ 9 var toggle = document.getElementById('navToggle'); 10 if (!toggle) return; 11 var header = toggle.closest('header'); 12 var links = document.getElementById('navLinks'); 13 14 function setOpen(open) { 15 header.classList.toggle('open', open); 16 toggle.setAttribute('aria-expanded', String(open)); 17 toggle.setAttribute('aria-label', open ? 'Menü schlieÃen' : 'Menü öffnen'); 18 } 19 20 toggle.addEventListener('click', function () { 21 setOpen(!header.classList.contains('open')); 22 }); 23 24 // Nach der Auswahl schlieÃen â sonst verdeckt das offene Menü das Sprungziel. 25 links.addEventListener('click', function (e) { 26 if (e.target.closest('a')) setOpen(false); 27 }); 28 29 // Escape schlieÃt; Fokus zurück auf den Button, damit die Tastatur nicht ins Leere läuft. 30 document.addEventListener('keydown', function (e) { 31 if (e.key === 'Escape' && header.classList.contains('open')) { 32 setOpen(false); 33 toggle.focus(); 34 } 35 }); 36 37 // Klick auÃerhalb schlieÃt. 38 document.addEventListener('click', function (e) { 39 if (header.classList.contains('open') && !header.contains(e.target)) setOpen(false); 40 }); 41 42 // Beim Wechsel auf Desktop-Breite zurücksetzen: die Links sind dort wieder 43 // dauerhaft sichtbar, ein hängengebliebener "open"-Zustand wäre unsichtbar 44 // aber aktiv (und würde Escape/AuÃenklick weiter abfangen). 45 var mq = window.matchMedia('(min-width: 1081px)'); 46 (mq.addEventListener ? mq.addEventListener.bind(mq, 'change') : mq.addListener.bind(mq))(function (ev) { 47 if (ev.matches) setOpen(false); 48 }); 49})(); 50 51// ââ Magazin-Ãbersicht: Branchen-Filter + Seiten ââââââââââââââââââââââââââââ 52// Rein clientseitig (statische Seite): Karten werden nach data-cat gefiltert 53// und in Seiten à PER Stück gezeigt. 54(function () { 55 'use strict'; 56 var grid = document.getElementById('magGrid'); 57 if (!grid) return; 58 var cards = Array.prototype.slice.call(grid.querySelectorAll('.card')); 59 var chips = Array.prototype.slice.call(document.querySelectorAll('.mag-chip')); 60 var pager = document.getElementById('magPager'); 61 var empty = document.getElementById('magEmpty'); 62 var PER = 9; 63 var cat = ''; 64 var page = 1; 65 66 function passend() { 67 return cat ? cards.filter(function (c) { return c.getAttribute('data-cat') === cat; }) : cards; 68 } 69 70 function render() { 71 var list = passend(); 72 var seiten = Math.max(1, Math.ceil(list.length / PER)); 73 if (page > seiten) page = seiten; 74 cards.forEach(function (c) { c.style.display = 'none'; }); 75 list.slice((page - 1) * PER, page * PER).forEach(function (c) { c.style.display = ''; }); 76 if (empty) empty.hidden = list.length !== 0; 77 78 pager.innerHTML = ''; 79 if (seiten <= 1) return; 80 var mk = function (text, ziel, opts) { 81 var b = document.createElement('button'); 82 b.type = 'button'; 83 b.textContent = text; 84 if (opts && opts.active) { b.className = 'is-active'; b.setAttribute('aria-current', 'page'); } 85 if (opts && opts.disabled) b.disabled = true; 86 b.addEventListener('click', function () { 87 page = ziel; render(); 88 grid.scrollIntoView({ behavior: 'smooth', block: 'start' }); 89 }); 90 pager.appendChild(b); 91 }; 92 mk('â¹', page - 1, { disabled: page === 1 }); 93 for (var i = 1; i <= seiten; i++) mk(String(i), i, { active: i === page }); 94 mk('âº', page + 1, { disabled: page === seiten }); 95 } 96 97 chips.forEach(function (ch) { 98 ch.addEventListener('click', function () { 99 chips.forEach(function (x) { x.classList.remove('is-active'); }); 100 ch.classList.add('is-active'); 101 cat = ch.getAttribute('data-cat') || ''; 102 page = 1; 103 render(); 104 }); 105 }); 106 107 render(); 108})(); 109 110 111// ââ Kundenstimmen-Karussell âââââââââââââââââââââââââââââââââââââââââââââââââ 112// Der Streifen funktioniert ohne dieses Skript (scroll-snap, wischbar). Hier 113// kommen dazu: Pfeile, Punkte, Pfeiltasten und ein langsamer Selbstlauf â alle 114// 9 s, nie bei âreduzierte Bewegungâ, pausiert bei Hover/Fokus/verstecktem Tab 115// und endgültig aus, sobald jemand selbst eingreift. 116(function () { 117 var ruhig = window.matchMedia && matchMedia('(prefers-reduced-motion: reduce)').matches; 118 document.querySelectorAll('[data-karussell]').forEach(function (k) { 119 var bahn = k.querySelector('.karussell-bahn'); 120 if (!bahn) return; 121 var folien = Array.prototype.slice.call(bahn.querySelectorAll('.stimme')); 122 var punkte = Array.prototype.slice.call(k.querySelectorAll('.karussell-punkte button')); 123 if (folien.length < 2) return; 124 var aktiv = 0, timer = null, t; 125 126 function zeige(i) { 127 i = (i + folien.length) % folien.length; 128 bahn.scrollTo({ left: folien[i].offsetLeft, behavior: ruhig ? 'auto' : 'smooth' }); 129 } 130 function markiere() {
131 var mitte = bahn.scrollLeft + bahn.clientWidth / 2, best = 0, abstand = Infinity; 132 folien.forEach(function (f, i) { 133 var d = Math.abs(f.offsetLeft + f.offsetWidth / 2 - mitte); 134 if (d < abstand) { abstand = d; best = i; } 135 }); 136 aktiv = best; 137 punkte.forEach(function (p, i) { p.setAttribute('aria-selected', i === best ? 'true' : 'false'); }); 138 } 139 function halt() { if (timer) { clearInterval(timer); timer = null; } } 140 function start() { 141 if (ruhig || timer) return; 142 timer = setInterval(function () { 143 if (document.hidden || k.matches(':hover') || k.contains(document.activeElement)) return; 144 zeige(aktiv + 1); 145 }, 9000); 146 } 147 148 var vor = k.querySelector('.karussell-pfeil.vor'), zurueck = k.querySelector('.karussell-pfeil.zurueck'); 149 if (vor) vor.addEventListener('click', function () { halt(); zeige(aktiv + 1); }); 150 if (zurueck) zurueck.addEventListener('click', function () { halt(); zeige(aktiv - 1); }); 151 punkte.forEach(function (p, i) { p.addEventListener('click', function () { halt(); zeige(i); }); }); 152 bahn.addEventListener('keydown', function (e) { 153 if (e.key === 'ArrowRight') { halt(); zeige(aktiv + 1); e.preventDefault(); } 154 if (e.key === 'ArrowLeft') { halt(); zeige(aktiv - 1); e.preventDefault(); } 155 }); 156 bahn.addEventListener('scroll', function () { clearTimeout(t); t = setTimeout(markiere, 80); }, { passive: true }); 157 // Nach dem Wischen endet die Snap-Animation erst später als der letzte 158 // scroll-Event â scrollend (Chrome 114+, Firefox 109+) meldet den Moment, 159 // in dem die Folie wirklich steht. Safari kennt es noch nicht; dort greift 160 // der Zeitgeber oben. 161 bahn.addEventListener('scrollend', markiere); 162 bahn.addEventListener('pointerdown', halt, { passive: true }); 163 164 markiere(); 165 start(); 166 }); 167})();
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.