PageSourceSearch

https://deinperfectday.de/wp-content/plugins/perfectday-pages-plug…/js/perfectday-pages.min.js?ver=0.28.1

js deinperfectday.de collected 2026-10-02 00:20:06 UTC 16,571 bytes, 482 lines download raw bytes

1(function () {
2'use strict';
3var header = document.getElementById('site-header');
4if (header) {
5var onScroll = function () { header.classList.toggle('scrolled', window.scrollY > 8); };
6document.addEventListener('scroll', onScroll, { passive: true });
7onScroll();
8}
9var megaToggle = document.getElementById('megaToggle');
10var megaMenu   = document.getElementById('mega-menu');
11var megaClose  = document.getElementById('megaClose');
12if (megaToggle && megaMenu) {
13var openMega = function () {
14megaMenu.hidden = false;
15megaToggle.setAttribute('aria-expanded', 'true');
16megaToggle.setAttribute('aria-label', 'Hauptmenü schließen');
17document.body.classList.add('pd-mega-open');
18var firstLink = megaMenu.querySelector('a, button');
19if (firstLink) {
20setTimeout(function () { firstLink.focus({ preventScroll: true }); }, 100);
21}
22};
23var closeMega = function (returnFocus) {
24megaMenu.hidden = true;
25megaToggle.setAttribute('aria-expanded', 'false');
26megaToggle.setAttribute('aria-label', 'Hauptmenü öffnen');
27document.body.classList.remove('pd-mega-open');
28if (returnFocus !== false) {
29megaToggle.focus({ preventScroll: true });
30}
31};
32megaToggle.addEventListener('click', function () {
33if (megaMenu.hidden) openMega();
34else closeMega();
35});
36if (megaClose) {
37megaClose.addEventListener('click', function () { closeMega(); });
38}
39document.addEventListener('keydown', function (e) {
40if (e.key === 'Escape' && !megaMenu.hidden) {
41closeMega();
42}
43});
44document.addEventListener('click', function (e) {
45if (megaMenu.hidden) return;
46if (!megaMenu.contains(e.target) && !megaToggle.contains(e.target)) {
47closeMega(false);
48}
49});
50megaMenu.addEventListener('click', function (e) {
51var link = e.target.closest('a');
52if (link && link.getAttribute('href')) {
53closeMega(false);
54}
55});
56megaMenu.addEventListener('keydown', function (e) {
57if (e.key !== 'Tab' || megaMenu.hidden) return;
58var focusables = megaMenu.querySelectorAll('a[href], button:not([disabled])');
59if (!focusables.length) return;
60var first = focusables[0];
61var last  = focusables[focusables.length - 1];
62if (e.shiftKey && document.activeElement === first) {
63e.preventDefault(); last.focus();
64} else if (!e.shiftKey && document.activeElement === last) {
65e.preventDefault(); first.focus();
66}
67});
68}
69var roi = document.getElementById('pdRoiCalculator');
70if (roi) {
71var cfg = {};
72Object.keys(roi.dataset).forEach(function (k) {
73if (k.indexOf('pd') === 0) {
74var key = k.substring(2).replace(/^[A-Z]/, function (c) { return c.toLowerCase(); })
75.replace(/([A-Z])/g, function (c) { return '_' + c.toLowerCase(); });
76var v = parseFloat(roi.dataset[k]);
77cfg[key] = isNaN(v) ? roi.dataset[k] : v;
78}
79});
80var fmt = function (n) {
81if (n < 0) n = 0;
82return n.toLocaleString('de-DE', { minimumFractionDigits: 0, maximumFractionDigits: 0 }) + ' €';
83};
84var getVal = function (key) {
85var el = roi.querySelector('[data-roi-input="' + key + '"]');
86if (!el) return 0;
87if (el.tagName === 'SELECT') return el.value;
88var n = parseFloat(el.value);
89return isNaN(n) ? 0 : n;
90};
91var setOut = function (key, value) {
92roi.querySelectorAll('[data-roi-out="' + key + '"]').forEach(function (el) {
93el.textContent = value;
94});
95};
96var isPillarActive = function (name) {
97var cb = roi.querySelector('[data-roi-pillar="' + name + '"]');
98return cb && cb.checked;
99};
100var toggleSection = function (name, active) {
101var sec = roi.querySelector('[data-roi-section="' + name + '"]');
102if (sec) sec.hidden = !active;
103};
104var renderBreakdown = function (rows) {
105var container = roi.querySelector('[data-roi-out="breakdown"]');
106if (!container) return;
107if (!rows.length) {
108container.innerHTML = '<p style="text-align:center;color:var(--ink-500);padding:1rem;">Wähle mindestens eine Säule aus, um deine Kosten zu sehen.</p>';
109return;
110}
111container.innerHTML = rows.map(function (r) {
112return '<div class="roi-breakdown-row">'
113+ '<div class="roi-breakdown-label">' + r.label + '</div>'
114+ '<div class="roi-breakdown-detail">' + r.detail + '</div>'
115+ '<div class="roi-breakdown-amount">' + fmt(r.amount) + '</div>'
116+ '</div>';
117}).join('');
118};
119var calc = function () {
120var sg = isPillarActive('stadtgutscheine');
121var tk = isPillarActive('tickets');
122var gb = isPillarActive('gutscheinbuecher');
123var cp = isPillarActive('coupons');
124toggleSection('stadtgutscheine', sg);
125toggleSection('tickets', tk);
126toggleSection('gutscheinbuecher', gb);
127toggleSection('coupons', cp);
128var bundleActive = sg && tk && gb;
129var bundlePct = cfg.bundle_discount_pct || 10;
130var bundleFactor = bundleActive ? (1 - bundlePct / 100) : 1;
131var bundleSuffix = bundleActive ? ' (inkl. ' + bundlePct + ' % Bündel-Rabatt)' : '';
132var pdYear = 0;
133var rows = [];
134if (sg) {
135var sgVol = getVal('stadtgutscheine_volume');
136var sgSetup = cfg.stadtgutscheine_setup_pd;
137var sgLaufend = sgVol * 12 * cfg.stadtgutscheine_pct_pd / 100 * bundleFactor;
138var sgPd = sgSetup + sgLaufend;
139pdYear += sgPd;
140rows.push({
141label: 'Stadtgutscheine',
142detail: fmt(sgSetup) + ' Setup einmalig + ' + cfg.stadtgutscheine_pct_pd + ' % von ' + fmt(sgVol) + '/Mt' + bundleSuffix,
143amount: sgPd
144});
145}
146if (tk) {
147var tkCount = getVal('tickets_count');
148var tkPd = tkCount * 12 * cfg.tickets_per_ticket_pd * bundleFactor;
149pdYear += tkPd;
150rows.push({
151label: 'Online-Ticketing',
152detail: '0 € Setup + ' + cfg.tickets_per_ticket_pd.toString().replace('.', ',') + ' € × ' + tkCount + ' Tickets × 12' + bundleSuffix,
153amount: tkPd
154});
155}
156if (gb) {
157var gbVol = getVal('gutscheinbuecher_volume');
158var gbSetup = cfg.gutscheinbuecher_setup_pd;
159var gbProvision = gbVol * cfg.gutscheinbuecher_provision_pd / 100 * bundleFactor;
160var gbPd = gbSetup + gbProvision;
161pdYear += gbPd;
162rows.push({
163label: 'Gutscheinbücher',
164detail: fmt(gbSetup) + ' Setup einmalig + ' + cfg.gutscheinbuecher_provision_pd + ' % von ' + fmt(gbVol) + ' Buchverkauf/Jahr' + bundleSuffix,
165amount: gbPd
166});
167}
168if (cp) {
169var cpTier = getVal('coupons_tier') || 'basic';
170var monthlyPrice = cfg['coupons_' + cpTier + '_price'] || 9.90;
171var cpPd = monthlyPrice * 12;
172pdYear += cpPd;
173var tierLabel = cpTier.charAt(0).toUpperCase() + cpTier.slice(1);
174rows.push({
175label: 'Coupons (' + tierLabel + ')',
176detail: monthlyPrice.toString().replace('.', ',') + ' €/Mt × 12',
177amount: cpPd
178});
179}
180renderBreakdown(rows);
181setOut('pd_year', rows.length ? fmt(pdYear) : '—');
182var note = roi.querySelector('[data-roi-out="bundle_note"]');
183if (note) note.hidden = !bundleActive;
184};
185roi.querySelectorAll('input, select').forEach(function (el) {
186el.addEventListener('input', calc);
187el.addEventListener('change', calc);
188});
189document.querySelectorAll('[data-roi-preset]').forEach(function (btn) {
190btn.addEventListener('click', function () {
191try {
192var preset = JSON.parse(btn.getAttribute('data-roi-preset'));
193roi.querySelectorAll('[data-roi-pillar]').forEach(function (cb) { cb.checked = false; });
194(preset.pillars || []).forEach(function (p) {
195var cb = roi.querySelector('[data-roi-pillar="' + p + '"]');
196if (cb) cb.checked = true;
197});
198Object.keys(preset).forEach(function (k) {
199if (k === 'pillars') return;
200var el = roi.querySelector('[data-roi-input="' + k + '"]');
201if (el) el.value = preset[k];
202});
203calc();
204var resEl = roi.querySelector('.roi-breakdown');
205if (resEl) resEl.scrollIntoView({ behavior: 'smooth', block: 'center' });
206} catch (e) {  }
207});
208});
209calc();
210}
211var gallery = document.getElementById('gallery');
212if (gallery) {
213var galImgs = gallery.querySelectorAll('img');
214var galIdx = 0;
215var setGalSlide = function (i) {
216var N = galImgs.length;
217galIdx = (i + N) % N;
218galImgs.forEach(function (img, n) {
219var rel = (n - galIdx + N) % N;
220img.classList.remove('s-active','s-next','s-far','s-prev','s-prev-far','s-hidden');
221if      (rel === 0)        img.classList.add('s-active');
222else if (rel === 1)        img.classList.add('s-next');
223else if (rel === 2)        img.classList.add('s-far');
224else if (rel === N - 1)    img.classList.add('s-prev');
225else if (rel === N - 2)    img.classList.add('s-prev-far');
226else                       img.classList.add('s-hidden');
227img.setAttribute('aria-hidden', rel !== 0 ? 'true' : 'false');
228});
229};
230if (galImgs.length) setGalSlide(0);
231var galTimer;
232var startGalTimer = function () {
233galTimer = setInterval(function () { setGalSlide(galIdx + 1); }, 3200);
234};
235var restartGalTimer = function () { clearInterval(galTimer); startGalTimer(); };
236var prevBtn = document.getElementById('gal-prev');
237var nextBtn = document.getElementById('gal-next');
238if (prevBtn) prevBtn.addEventListener('click', function () { setGalSlide(galIdx - 1); restartGalTimer(); });
239if (nextBtn) nextBtn.addEventListener('click', function () { setGalSlide(galIdx + 1); restartGalTimer(); });
240if (galImgs.length && !window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
241startGalTimer();
242}
243}
244if ('IntersectionObserver' in window) {
245var io = new IntersectionObserver(function (entries) {
246entries.forEach(function (e) {
247if (e.isIntersecting) {
248e.target.classList.add('in');
249io.unobserve(e.target);
250}
251});
252}, { threshold: 0.12 });
253document.querySelectorAll('.reveal').forEach(function (el) { io.observe(el); });
254} else {
255document.querySelectorAll('.reveal').forEach(function (el) { el.classList.add('in'); });
256}
257function pdFieldError(field, msg) {
258field.setAttribute('aria-invalid', msg ? 'true' : 'false');
259var span = field.id ? document.getElementById(field.id + '-error') : null;
260if (span) { span.textContent = msg || ''; }
261}
262var PD_FIELD_HINTS = {
263pd_firma:      'den Namen deines Unternehmens',
264pd_rechtsform: 'die Rechtsform (z. B. GmbH, GbR, Einzelunternehmen)',
265pd_vorname:    'deinen Vornamen',
266pd_nachname:   'deinen Nachnamen',
267pd_strasse:    'Straße und Hausnummer',
268pd_plz:        'die Postleitzahl',
269pd_ort:        'den Ort',
270pd_telefon:    'eine Telefonnummer für Rückfragen',
271pd_email:      'deine E-Mail-Adresse',
272pd_name:       'deinen Namen',
273pd_stadt:      'deine Stadt',
274pd_typ:        'aus, was für ein Anbieter du bist'
275};
276function pdValidationMessage(field) {
277var v = field.validity;
278if (!v || v.valid) { return ''; }
279var hint = PD_FIELD_HINTS[field.name] || 'dieses Feld';
280if (v.valueMissing) {
281return field.tagName === 'SELECT'
282? 'Bitte wähle ' + hint + '.'
283: 'Bitte gib ' + hint + ' an.';
284}
285if (v.typeMismatch && field.type === 'email') {
286return 'Bitte gib eine gültige E-Mail-Adresse ein, z. B. [email protected].';
287}
288return field.validationMessage || 'Bitte prüfe deine Eingabe.';
289}
290var bookingForm = document.querySelector('form.booking');
291if (bookingForm) {
292var bSteps   = Array.prototype.slice.call(bookingForm.querySelectorAll('.booking-step'));
293var bProg    = Array.prototype.slice.call(bookingForm.querySelectorAll('.booking-progress li'));
294var bPrev    = bookingForm.querySelector('[data-prev]');
295var bNext    = bookingForm.querySelector('[data-next]');
296var bNav     = bookingForm.querySelector('.booking-nav');
297var bTotal   = bSteps.length;
298var bCurrent = 1;
299var eur = function (n) {
300return n.toLocaleString('de-DE', { minimumFractionDigits: 2, maximumFractionDigits: 2 }) + ' €';
301};
302var selectedPillars = function () {
303return Array.prototype.slice.call(
304bookingForm.querySelectorAll('input[name="pd_saeule[]"]:checked')
305);
306};
307var couponChecked = function () {
308var c = bookingForm.querySelector('input[name="pd_saeule[]"][value="coupons"]');
309return c && c.checked;
310};
311var couponTier = function () {
312return bookingForm.querySelector('input[name="pd_coupon_tier"]:checked');
313};
314var renderCosts = function () {
315var picks = selectedPillars();
316var keys  = picks.map(function (el) { return el.value; });
317var bundle = keys.indexOf('stadtgutscheine') >= 0
318&& keys.indexOf('tickets') >= 0
319&& keys.indexOf('gutscheinbuecher') >= 0;
320var line = function (label, value) {
321return '<span class="booking-product-line">'
322+ '<span>' + label + '</span><span>' + value + '</span></span>';
323};
324var html = '';
325picks.forEach(function (el) {
326var name  = el.getAttribute('data-label');
327var setup = parseFloat(el.getAttribute('data-setup')) || 0;
328var lines = line('Einmalige Einrichtung', eur(setup) + ' zzgl. MwSt');
329if (el.value === 'coupons') {
330var t = couponTier();
331if (t) {
332var m = parseFloat(t.getAttribute('data-monthly')) || 0;
333name += ' — Tarif ' + t.getAttribute('data-label');
334lines += line('Monatliche Gebühr', eur(m) + ' zzgl. MwSt');
335}
336} else {
337var v = el.getAttribute('data-variabel');
338if (v) {
339if (bundle) { v += ' (inkl. 10 % Bündel-Rabatt)'; }
340lines += line('Laufende Gebühr', v);
341}
342}
343html += '<div class="booking-product">'
344+ '<span class="booking-product-name">' + name + '</span>'
345+ lines + '</div>';
346});
347if (picks.length) {
348if (bundle) {
349html += '<p class="booking-product-note">Der 10-%-Bündel-Rabatt auf die '
350+ 'laufenden Gebühren von Stadtgutscheinen, Tickets und Gutscheinbüchern '
351+ 'ist oben je Modul berücksichtigt. Lokale Coupons sind ausgenommen.</p>';
352}
353} else {
354html = '<p class="booking-empty">Noch kein Modul gewählt.</p>';
355}
356var costList = bookingForm.querySelector('[data-cost-list]');
357if (costList) { costList.innerHTML = html; }
358var summary = bookingForm.querySelector('[data-summary]');
359if (summary) {
360summary.innerHTML = picks.length
361? '<h3>Deine Buchung — Modul für Modul</h3>' + html
362: html;
363}
364};
365var syncStep2 = function () {
366var hasCoupons = couponChecked();
367var tierBox = bookingForm.querySelector('[data-needs="coupons"]');
368var emptyBox = bookingForm.querySelector('[data-needs="not-coupons"]');
369if (tierBox)  tierBox.hidden  = !hasCoupons;
370if (emptyBox) emptyBox.hidden = hasCoupons;
371};
372var showError = function (key, show) {
373var el = bookingForm.querySelector('[data-error="' + key + '"]');
374if (el) el.hidden = !show;
375};
376var focusFirstInvalid = function () {
377var bad = bSteps[2].querySelector('[aria-invalid="true"]');
378if (bad) { bad.focus(); }
379};
380var validateStep = function (n) {
381if (n === 1) {
382var ok = selectedPillars().length > 0;
383showError('saeule', !ok);
384return ok;
385}
386if (n === 3) {
387var fields = bSteps[2].querySelectorAll('input, select, textarea');
388var firstInvalid = null;
389for (var i = 0; i < fields.length; i++) {
390var f = fields[i];
391if (f.checkValidity()) {
392pdFieldError(f, '');
393} else {
394pdFieldError(f, pdValidationMessage(f));
395if (!firstInvalid) { firstInvalid = f; }
396}
397}
398return !firstInvalid;
399}
400if (n === 4) {
401var agb = bookingForm.querySelector('input[name="pd_agb"]');
402var ds  = bookingForm.querySelector('input[name="pd_datenschutz"]');
403var ok2 = agb && agb.checked && ds && ds.checked;
404showError('consent', !ok2);
405return ok2;
406}
407return true;
408};
409var showStep = function (n, skipScroll) {
410bCurrent = n;
411bSteps.forEach(function (s) {
412s.hidden = parseInt(s.getAttribute('data-step'), 10) !== n;
413});
414bProg.forEach(function (p) {
415var pn = parseInt(p.getAttribute('data-step'), 10);
416p.classList.toggle('is-active', pn === n);
417p.classList.toggle('is-done', pn < n);
418});
419bPrev.hidden = n === 1;
420bNext.hidden = n === bTotal;
421if (n === 2) syncStep2();
422if (n === 2 || n === 4) renderCosts();
423if (!skipScroll) {
424var panel = bookingForm.querySelector('.booking-step[data-step="' + n + '"]');
425if (panel) panel.scrollIntoView({ behavior: 'smooth', block: 'start' });
426}
427};
428bNext.addEventListener('click', function () {
429if (!validateStep(bCurrent)) {
430if (bCurrent === 3) { focusFirstInvalid(); }
431return;
432}
433if (bCurrent < bTotal) showStep(bCurrent + 1);
434});
435bPrev.addEventListener('click', function () {
436if (bCurrent > 1) showStep(bCurrent - 1);
437});
438bookingForm.addEventListener('change', function (e) {
439if (e.target.name === 'pd_saeule[]' || e.target.name === 'pd_coupon_tier') {
440renderCosts();
441}
442});
443bookingForm.addEventListener('submit', function (e) {
444if (!validateStep(1)) { e.preventDefault(); showStep(1); return; }
445if (!validateStep(3)) { e.preventDefault(); showStep(3); focusFirstInvalid(); return; }
446if (!validateStep(4)) { e.preventDefault(); showStep(4); return; }
447});
448Array.prototype.forEach.call(
449bSteps[2].querySelectorAll('input, select, textarea'),
450function (field) {
451var clear = function () {
452if (field.validity.valid) { pdFieldError(field, ''); }
453};
454field.addEventListener('input', clear);
455field.addEventListener('change', clear);
456}
457);
458if (bNav) bNav.hidden = false;
459showStep(1, true);
460}
461var leadForm = document.querySelector('form.lead-form');
462if (leadForm) {
463Array.prototype.forEach.call(
464leadForm.querySelectorAll('input[id], select[id], textarea[id]'),
465function (field) {
466field.addEventListener('invalid', function (e) {
467e.preventDefault();
468pdFieldError(field, pdValidationMessage(field));
469});
470var clear = function () {
471if (field.validity.valid) { pdFieldError(field, ''); }
472};
473field.addEventListener('input', clear);
474field.addEventListener('change', clear);
475}
476);
477}
478var leadStatus = document.querySelector('.lead-status');
479if (leadStatus && typeof leadStatus.focus === 'function') {
480leadStatus.focus();
481}
482})();

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.