1(function () { 2 'use strict'; 3 4 // Wird per wp_localize_script von PHP gesetzt 5 var cfg = window.innoNewsletter || {}; 6 var strings = cfg.strings || {}; 7 var endpoint = cfg.endpoint || '/api/newsletter/'; 8 var loggedIn = !!cfg.loggedIn; 9 10 var TRIGGER_SELECTOR = 'a[href^="#inno-newsletter:"]'; 11 var modalEl = null; 12 var lastFocus = null; 13 var pendingKey = null; 14 var currentStep = 1; // 1 = nur E-Mail (Prüfung), 2 = Name (Registrierung) 15 16 function t(key, fallback) { 17 return strings[key] || fallback; 18 } 19 20 function parseKey(href) { 21 var m = /^#inno-newsletter:([a-z_]+)$/.exec(href || ''); 22 return m ? m[1] : null; 23 } 24 25 function toast(message, isError) { 26 var el = document.createElement('div'); 27 el.className = 'inno-newsletter-toast' + (isError ? ' is-error' : ''); 28 el.textContent = message; 29 document.body.appendChild(el); 30 // force reflow to enable transition 31 // eslint-disable-next-line no-unused-expressions 32 el.offsetHeight; 33 el.classList.add('is-visible'); 34 setTimeout(function () { 35 el.classList.remove('is-visible'); 36 setTimeout(function () { el.remove(); }, 300); 37 }, 4200); 38 } 39 40 function postForm(method, data) { 41 var body = new URLSearchParams(); 42 Object.keys(data).forEach(function (k) { 43 if (data[k] !== undefined && data[k] !== null) { 44 body.append(k, data[k]); 45 } 46 }); 47 return fetch(endpoint + method, { 48 method: 'POST', 49 credentials: 'include', 50 headers: { 51 'Accept': 'application/json', 52 'Content-Type': 'application/x-www-form-urlencoded', 53 'Pragma': 'no-cache', 54 'Cache-Control': 'no-cache' 55 }, 56 body: body.toString() 57 }).then(function (res) { 58 return res.json().then(function (json) { return { ok: res.ok, status: res.status, json: json }; }); 59 }); 60 } 61 62 function subscribeLoggedIn(key) { 63 var trigger = document.querySelector(TRIGGER_SELECTOR + '[data-current="1"]'); 64 if (trigger) trigger.setAttribute('aria-busy', 'true'); 65 postForm('subscribe', { key: key }).then(function (r) { 66 if (r.ok && r.json && r.json.success) { 67 openSuccessModal( 68 t('success_title', 'Vielen Dank!'), 69 t('subscribed_success', 'Du bist jetzt für den Newsletter angemeldet.') 70 ); 71 } else { 72 toast(t('subscribed_error', 'Anmeldung fehlgeschlagen. Bitte später erneut versuchen.'), true); 73 } 74 }).catch(function () { 75 toast(t('network_error', 'Netzwerkfehler. Bitte später erneut versuchen.'), true); 76 }).finally(function () { 77 if (trigger) trigger.removeAttribute('aria-busy'); 78 }); 79 } 80 81 function openSuccessModal(title, text) { 82 var m = buildModal(); 83 var form = m.querySelector('.inno-newsletter-form'); 84 var success = m.querySelector('.inno-newsletter-success'); 85 var lead = m.querySelector('.inno-newsletter-lead'); 86 var titleEl = m.querySelector('#inno-newsletter-title'); 87 form.hidden = true; 88 if (lead) lead.hidden = true; 89 if (titleEl) titleEl.hidden = true; 90 success.hidden = false; 91 success.querySelector('h4').textContent = title; 92 success.querySelector('p').textContent = text; 93 m.classList.add('is-open', 'is-success-only'); 94 document.body.classList.add('inno-newsletter-locked'); 95 lastFocus = document.activeElement; 96 var closeBtn = success.querySelector('.inno-newsletter-close-success'); 97 if (closeBtn) closeBtn.focus(); 98 } 99 100 function buildModal() { 101 if (modalEl) return modalEl; 102 103 var overlay = document.createElement('div'); 104 overlay.className = 'inno-newsletter-overlay'; 105 overlay.setAttribute('role', 'dialog'); 106 overlay.setAttribute('aria-modal', 'true'); 107 overlay.setAttribute('aria-labelledby', 'inno-newsletter-title'); 108 overlay.innerHTML = '' 109 + '<div class="inno-newsletter-modal">' 110 + ' <button type="button" class="inno-newsletter-close" aria-label="' + t('close', 'SchlieÃen') + '">×</button>' 111 + ' <h3 id="inno-newsletter-title">' + t('modal_title', 'Newsletter abonnieren') + '</h3>' 112 + ' <p class="inno-newsletter-lead">' + t('modal_lead', 'Trage deine E-Mail-Adresse ein, um den Newsletter zu erhalten.') + '</p>' 113 + ' <form class="inno-newsletter-form" novalidate>' 114 + ' <div class="inno-newsletter-step inno-newsletter-step1">' 115 + ' <div class="inno-newsletter-row">' 116 + ' <label>'
117 + ' <span>' + t('field_email', 'E-Mail') + ' *</span>' 118 + ' <input name="email" type="email" required autocomplete="email" />' 119 + ' </label>' 120 + ' </div>' 121 + ' </div>' 122 + ' <div class="inno-newsletter-step inno-newsletter-step2" hidden>' 123 + ' <p class="inno-newsletter-step2-lead"></p>' 124 + ' <div class="inno-newsletter-row">' 125 + ' <label>' 126 + ' <span>' + t('field_gender', 'Anrede') + '</span>' 127 + ' <select name="gender">' 128 + ' <option value="">â</option>' 129 + ' <option value="w">' + t('gender_w', 'Frau') + '</option>' 130 + ' <option value="m">' + t('gender_m', 'Herr') + '</option>' 131 + ' <option value="u">' + t('gender_u', 'Divers') + '</option>' 132 + ' </select>' 133 + ' </label>' 134 + ' </div>' 135 + ' <div class="inno-newsletter-row inno-newsletter-row--split">' 136 + ' <label>' 137 + ' <span>' + t('field_firstname', 'Vorname') + ' *</span>' 138 + ' <input name="firstname" type="text" autocomplete="given-name" />' 139 + ' </label>' 140 + ' <label>' 141 + ' <span>' + t('field_lastname', 'Nachname') + ' *</span>' 142 + ' <input name="lastname" type="text" autocomplete="family-name" />' 143 + ' </label>' 144 + ' </div>' 145 + ' </div>' 146 + ' <div class="inno-newsletter-error" aria-live="polite" hidden></div>' 147 + ' <button type="submit" class="inno-newsletter-submit">' + t('next', 'Weiter') + '</button>' 148 + ' <p class="inno-newsletter-hint">' + t('login_hint', 'Bereits Kunde? Logge dich oben rechts ein, dann genügt ein Klick.') + '</p>' 149 + ' </form>' 150 + ' <div class="inno-newsletter-success" hidden>' 151 + ' <h4>' + t('success_title', 'Vielen Dank!') + '</h4>' 152 + ' <p>' + t('success_text', 'Du hast den Newsletter erfolgreich abonniert.') + '</p>' 153 + ' <button type="button" class="inno-newsletter-submit inno-newsletter-close-success">' + t('success_close', 'SchlieÃen') + '</button>' 154 + ' </div>' 155 + '</div>'; 156 157 document.body.appendChild(overlay); 158 modalEl = overlay; 159 160 overlay.addEventListener('click', function (e) { 161 if (e.target === overlay) closeModal(); 162 }); 163 overlay.querySelector('.inno-newsletter-close').addEventListener('click', closeModal); 164 overlay.querySelector('.inno-newsletter-close-success').addEventListener('click', closeModal); 165 overlay.querySelector('.inno-newsletter-form').addEventListener('submit', onSubmit); 166 167 document.addEventListener('keydown', function (e) { 168 if (e.key === 'Escape' && modalEl && modalEl.classList.contains('is-open')) closeModal(); 169 }); 170 171 return overlay; 172 } 173 174 function openModal(key) { 175 pendingKey = key; 176 var m = buildModal(); 177 m.classList.add('is-open'); 178 document.body.classList.add('inno-newsletter-locked'); 179 lastFocus = document.activeElement; 180 resetForm(); 181 var firstInput = m.querySelector('input[name="email"]'); 182 if (firstInput) firstInput.focus(); 183 } 184 185 function closeModal() { 186 if (!modalEl) return; 187 modalEl.classList.remove('is-open', 'is-success-only'); 188 document.body.classList.remove('inno-newsletter-locked'); 189 pendingKey = null; 190 if (lastFocus && typeof lastFocus.focus === 'function') lastFocus.focus(); 191 } 192 193 function resetForm() { 194 if (!modalEl) return; 195 var form = modalEl.querySelector('.inno-newsletter-form'); 196 var success = modalEl.querySelector('.inno-newsletter-success'); 197 var err = modalEl.querySelector('.inno-newsletter-error'); 198 var lead = modalEl.querySelector('.inno-newsletter-lead'); 199 var titleEl = modalEl.querySelector('#inno-newsletter-title'); 200 form.hidden = false;
201 success.hidden = true; 202 err.hidden = true; 203 err.textContent = ''; 204 if (lead) lead.hidden = false; 205 if (titleEl) titleEl.hidden = false; 206 form.reset(); 207 currentStep = 1; 208 modalEl.querySelector('.inno-newsletter-step1').hidden = false; 209 modalEl.querySelector('.inno-newsletter-step2').hidden = true; 210 var submit = form.querySelector('.inno-newsletter-submit'); 211 submit.disabled = false; 212 submit.textContent = t('next', 'Weiter'); 213 } 214 215 function onSubmit(e) { 216 e.preventDefault(); 217 var form = e.currentTarget; 218 var err = modalEl.querySelector('.inno-newsletter-error'); 219 err.hidden = true; 220 if (currentStep === 1) { 221 stepCheck(form, err); 222 } else { 223 stepRegister(form, err); 224 } 225 } 226 227 // Schritt 1: nur E-Mail prüfen. Existiert ein Account â Login-Maske, 228 // sonst Schritt 2 (Name) einblenden. 229 function stepCheck(form, err) { 230 var email = (new FormData(form).get('email') || '').toString().trim(); 231 if (!/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(email)) { 232 err.textContent = t('error_invalid', 'Bitte gib eine gültige E-Mail-Adresse ein.'); 233 err.hidden = false; 234 return; 235 } 236 var submit = form.querySelector('.inno-newsletter-submit'); 237 submit.disabled = true; 238 submit.textContent = t('checking', 'Wird geprüftâ¦'); 239 240 postForm('check', { email: email }).then(function (r) { 241 if (r.ok && r.json && r.json.success) { 242 if (r.json.exists) {
243 // Bestehender Account â zur Login-Maske / den Einstellungen. 244 err.textContent = t('error_email_exists', 'Diese E-Mail ist bereits bei uns registriert. Wir leiten dich zu deinen Newsletter-Einstellungen weiterâ¦'); 245 err.hidden = false; 246 if (r.json.manage_url) { 247 setTimeout(function () { window.location.href = r.json.manage_url; }, 1800); 248 return; 249 } 250 } else { 251 // Neuer Kontakt â Name abfragen. 252 showStep2(form, email); 253 return; 254 } 255 } else { 256 err.textContent = t('error_generic', 'Anmeldung fehlgeschlagen. Bitte später erneut versuchen.'); 257 err.hidden = false; 258 } 259 submit.disabled = false; 260 submit.textContent = t('next', 'Weiter'); 261 }).catch(function () { 262 err.textContent = t('network_error', 'Netzwerkfehler. Bitte später erneut versuchen.'); 263 err.hidden = false; 264 submit.disabled = false; 265 submit.textContent = t('next', 'Weiter'); 266 }); 267 } 268 269 function showStep2(form, email) { 270 currentStep = 2; 271 modalEl.querySelector('.inno-newsletter-step1').hidden = true; 272 var step2 = modalEl.querySelector('.inno-newsletter-step2'); 273 var lead = step2.querySelector('.inno-newsletter-step2-lead'); 274 if (lead) lead.textContent = t('step2_lead_prefix', 'Schön, dass du dabei bist! Für ') + email + t('step2_lead_suffix', ' brauchen wir noch deinen Namen.'); 275 step2.hidden = false; 276 var submit = form.querySelector('.inno-newsletter-submit'); 277 submit.disabled = false; 278 submit.textContent = t('submit', 'Newsletter abonnieren'); 279 var fn = form.querySelector('input[name="firstname"]'); 280 if (fn) fn.focus(); 281 } 282 283 // Schritt 2: Name + Registrierung (Double-Opt-In). 284 function stepRegister(form, err) { 285 var fd = new FormData(form); 286 var firstname = (fd.get('firstname') || '').toString().trim(); 287 var lastname = (fd.get('lastname') || '').toString().trim(); 288 var email = (fd.get('email') || '').toString().trim(); 289 var gender = (fd.get('gender') || '').toString().trim(); 290 291 if (firstname.length === 0 || lastname.length === 0) { 292 err.textContent = t('error_invalid_names', 'Bitte fülle Vorname und Nachname aus.'); 293 err.hidden = false; 294 return; 295 } 296 297 var submit = form.querySelector('.inno-newsletter-submit'); 298 submit.disabled = true; 299 submit.textContent = t('submitting', 'Wird gesendetâ¦'); 300 301 postForm('register', { 302 firstname: firstname, 303 lastname: lastname, 304 email: email, 305 gender: gender, 306 key: pendingKey || '' 307 }).then(function (r) { 308 if (r.ok && r.json && r.json.success) { 309 // Double-Opt-In: Kontakt angelegt, Bestätigungsmail ist unterwegs. 310 var success = modalEl.querySelector('.inno-newsletter-success'); 311 var h4 = success.querySelector('h4'); 312 var p = success.querySelector('p'); 313 if (h4) h4.textContent = t('optin_title', 'Fast geschafft!'); 314 if (p) p.textContent = t('optin_text', 'Wir haben dir eine E-Mail geschickt. Bitte bestätige darin deine Anmeldung, dann erhältst du den Newsletter.'); 315 form.hidden = true; 316 success.hidden = false; 317 return; 318 } 319 // Race: zwischen Schritt 1 und 2 doch schon registriert. 320 if (r.json && r.json.error === 'email_exists') { 321 err.textContent = t('error_email_exists', 'Diese E-Mail ist bereits bei uns registriert. Wir leiten dich zu deinen Newsletter-Einstellungen weiterâ¦'); 322 err.hidden = false; 323 if (r.json.manage_url) { 324 setTimeout(function () { window.location.href = r.json.manage_url; }, 1800); 325 return; 326 } 327 } 328 var msg = t('error_generic', 'Anmeldung fehlgeschlagen. Bitte später erneut versuchen.');
329 if (r.json && r.json.error === 'invalid_input') msg = t('error_invalid_names', 'Bitte fülle Vorname und Nachname aus.'); 330 err.textContent = msg; 331 err.hidden = false; 332 submit.disabled = false; 333 submit.textContent = t('submit', 'Newsletter abonnieren'); 334 }).catch(function () { 335 err.textContent = t('network_error', 'Netzwerkfehler. Bitte später erneut versuchen.'); 336 err.hidden = false; 337 submit.disabled = false; 338 submit.textContent = t('submit', 'Newsletter abonnieren'); 339 }); 340 } 341 342 function onTriggerClick(e) { 343 var a = e.currentTarget; 344 var key = parseKey(a.getAttribute('href')); 345 if (!key) return; 346 e.preventDefault(); 347 if (loggedIn) { 348 a.setAttribute('data-current', '1'); 349 subscribeLoggedIn(key); 350 setTimeout(function () { a.removeAttribute('data-current'); }, 50); 351 } else { 352 openModal(key); 353 } 354 } 355 356 function attach() { 357 var links = document.querySelectorAll(TRIGGER_SELECTOR); 358 links.forEach(function (a) { 359 if (a.dataset.innoNewsletterBound) return; 360 a.dataset.innoNewsletterBound = '1'; 361 a.addEventListener('click', onTriggerClick); 362 }); 363 } 364 365 // -- Settings-Page (#inno-newsletter-settings) ----------------------------- 366 function initSettingsPage() { 367 var root = document.getElementById('inno-newsletter-settings'); 368 if (!root) return; 369 370 var email = root.getAttribute('data-email'); 371 var guid = root.getAttribute('data-guid'); 372 var type = root.getAttribute('data-type'); // optional: aus Mail-Link 373 var newsletterId = root.getAttribute('data-newsletter-id'); // optional: aus Mail-Link 374 var newsletters = {}; 375 try { newsletters = JSON.parse(root.getAttribute('data-newsletters') || '{}'); } catch (e) {} 376 var onLabel = root.getAttribute('data-on') || 'Subscribed'; 377 var offLabel = root.getAttribute('data-off') || 'Not subscribed'; 378 // labels = key -> Anzeigename (für Bestätigungs-/Abmelde-Texte). 379 var labels = {}; 380 Object.keys(newsletters).forEach(function (k) { labels[k] = newsletters[k].name; }); 381 382 var statusEl = root.querySelector('.inno-ns-status'); 383 var loadingEl = root.querySelector('.inno-ns-loading'); 384 var form = root.querySelector('.inno-ns-form'); 385 var boxes = root.querySelector('.inno-ns-cards'); 386 var errEl = root.querySelector('.inno-ns-error'); 387 var savedEl = root.querySelector('.inno-ns-saved'); 388 var confirmEl = root.querySelector('.inno-ns-confirm'); 389 var confirmTextEl = root.querySelector('.inno-ns-confirm-text'); 390 var confirmYesBtn = root.querySelector('.inno-ns-confirm-yes'); 391 var confirmNoBtn = root.querySelector('.inno-ns-confirm-no'); 392 393 function showStatus(message, isError) { 394 statusEl.textContent = message; 395 statusEl.classList.toggle('is-error', !!isError); 396 statusEl.hidden = false; 397 } 398 399 function renderCheckboxes(flags) { 400 boxes.innerHTML = ''; 401 Object.keys(newsletters).forEach(function (key) { 402 var n = newsletters[key] || {}; 403 var id = 'inno-ns-' + key; 404 var checked = !!(flags && flags[key]); 405 406 var card = document.createElement('label'); 407 card.className = 'inno-ns-card' + (checked ? ' is-active' : ''); 408 card.setAttribute('for', id); 409 410 // Logo bzw. Text-Badge als Fallback 411 var media = document.createElement('div'); 412 media.className = 'inno-ns-card-media'; 413 if (n.logo) { 414 var img = document.createElement('img'); 415 img.src = n.logo; 416 img.alt = n.name || key; 417 img.loading = 'lazy'; 418 media.appendChild(img); 419 } else { 420 var badge = document.createElement('span'); 421 badge.className = 'inno-ns-card-badge'; 422 badge.textContent = n.name || key; 423 media.appendChild(badge); 424 } 425 card.appendChild(media); 426 427 // Textblock 428 var body = document.createElement('div'); 429 body.className = 'inno-ns-card-body'; 430 var nameEl = document.createElement('span'); 431 nameEl.className = 'inno-ns-card-name'; 432 nameEl.textContent = n.name || key; 433 body.appendChild(nameEl); 434 if (n.tagline) { 435 var tag = document.createElement('strong'); 436 tag.className = 'inno-ns-card-tagline'; 437 tag.textContent = n.tagline; 438 body.appendChild(tag); 439 } 440 if (n.description) { 441 var desc = document.createElement('p'); 442 desc.className = 'inno-ns-card-desc'; 443 desc.textContent = n.description; 444 body.appendChild(desc); 445 } 446 card.appendChild(body); 447 448 // Toggle (Checkbox + Switch + Status-Text) 449 var toggle = document.createElement('div'); 450 toggle.className = 'inno-ns-card-toggle'; 451 var input = document.createElement('input'); 452 input.type = 'checkbox'; 453 input.id = id; 454 input.name = key; 455 input.checked = checked; 456 var sw = document.createElement('span'); 457 sw.className = 'inno-ns-switch'; 458 sw.setAttribute('aria-hidden', 'true'); 459 var state = document.createElement('span'); 460 state.className = 'inno-ns-state'; 461 state.textContent = checked ? onLabel : offLabel; 462 input.addEventListener('change', function () { 463 card.classList.toggle('is-active', input.checked); 464 state.textContent = input.checked ? onLabel : offLabel; 465 }); 466 toggle.appendChild(input); 467 toggle.appendChild(sw); 468 toggle.appendChild(state); 469 card.appendChild(toggle); 470 471 boxes.appendChild(card); 472 }); 473 } 474 475 function loadStatus() { 476 var url = endpoint + 'status?guid=' + encodeURIComponent(guid) + '&email=' + encodeURIComponent(email); 477 return fetch(url, { 478 credentials: 'include', 479 headers: { 'Accept': 'application/json', 'Pragma': 'no-cache', 'Cache-Control': 'no-cache' } 480 }).then(function (res) { 481 return res.json().then(function (json) { return { ok: res.ok, json: json }; }); 482 }); 483 } 484 485 function showForm(flags) { 486 loadingEl.hidden = true; 487 renderCheckboxes(flags || {}); 488 form.hidden = false;
489 } 490 491 // Meldet eine erfolgte Abmeldung zusätzlich ans newsletter-Tool, damit sie in 492 // dessen "Abmeldungen"-Statistik auftaucht. Notwendig, weil Elastic Email für 493 // disable_unsubscribe-Accounts (u.a. congress) diesen Klick nie sieht - ohne 494 // diesen Beacon bliebe die Statistik dort strukturell bei 0 (siehe 495 // newsletter/api/webhook/crm_unsubscribe.php). Rein informativ für die 496 // Statistik: die eigentliche Abmeldung ist mit dem obigen updateMailing-Call 497 // bereits vollzogen, ein Fehlschlag hier wird bewusst ignoriert. 498 function notifyNewsletterToolUnsubscribed() { 499 if (!newsletterId) return; 500 var body = new URLSearchParams(); 501 body.append('guid', guid); 502 body.append('email', email); 503 body.append('newsletter_id', newsletterId); 504 fetch('https://innoform-coaching.de/newsletter/api/webhook/crm_unsubscribe.php', { 505 method: 'POST', 506 headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, 507 body: body.toString() 508 }).catch(function () {}); 509 } 510 511 function doUnsubscribe(typeLabel) { 512 confirmEl.hidden = true; 513 loadingEl.hidden = false; 514 postForm('unsubscribe', { guid: guid, email: email, newsletter_type: type }).then(function (r) { 515 if (r.ok && r.json && r.json.success) { 516 notifyNewsletterToolUnsubscribed(); 517 showStatus(t('unsub_success_prefix', 'Sie haben sich erfolgreich vom ') + typeLabel + t('unsub_success_suffix', ' abgemeldet.')); 518 if (r.json.flags) { 519 showForm(r.json.flags); 520 } else { 521 loadStatusIntoForm(); 522 } 523 } else { 524 showStatus(t('unsub_failed', 'Abmeldung fehlgeschlagen. Bitte prüfe deine Einstellungen unten.'), true); 525 loadStatusIntoForm(); 526 } 527 }).catch(function () { 528 showStatus(t('network_error', 'Netzwerkfehler. Bitte später erneut versuchen.'), true); 529 loadStatusIntoForm(); 530 }); 531 } 532 533 function start() { 534 var typeLabel = labels[type] || type; 535 536 // Mit newsletter_type aus dem Mail-Link: erst auf der Seite bestätigen 537 // lassen (kein Auto-Abmelden â Mail-Scanner folgen Links sonst ungewollt). 538 if (type) { 539 loadingEl.hidden = true; 540 confirmTextEl.textContent = t('confirm_prefix', 'Möchten Sie sich wirklich vom ') + typeLabel + t('confirm_suffix', ' abmelden?'); 541 confirmEl.hidden = false; 542 confirmYesBtn.addEventListener('click', function () { doUnsubscribe(typeLabel); }); 543 confirmNoBtn.addEventListener('click', function () { 544 confirmEl.hidden = true; 545 loadingEl.hidden = false; 546 loadStatusIntoForm(); 547 }); 548 return; 549 } 550 551 loadStatusIntoForm(); 552 } 553 554 function loadStatusIntoForm() { 555 loadStatus().then(function (r) { 556 if (r.ok && r.json && r.json.success) { 557 showForm(r.json.flags); 558 } else { 559 loadingEl.hidden = true; 560 showStatus(t('status_load_failed', 'Aktuelle Einstellungen konnten nicht geladen werden.'), true); 561 } 562 }).catch(function () { 563 loadingEl.hidden = true; 564 showStatus(t('network_error', 'Netzwerkfehler. Bitte später erneut versuchen.'), true); 565 }); 566 } 567 568 form.addEventListener('submit', function (e) { 569 e.preventDefault(); 570 errEl.hidden = true; 571 savedEl.hidden = true; 572 var data = { guid: guid, email: email }; 573 Object.keys(labels).forEach(function (key) { 574 var input = form.querySelector('input[name="' + key + '"]'); 575 data[key] = input && input.checked ? 1 : 0; 576 }); 577 var btn = form.querySelector('.inno-ns-save'); 578 btn.disabled = true; 579 postForm('save', data).then(function (r) { 580 btn.disabled = false;
581 if (r.ok && r.json && r.json.success) { 582 savedEl.hidden = false; 583 } else { 584 errEl.textContent = t('save_failed', 'Speichern fehlgeschlagen. Bitte später erneut versuchen.'); 585 errEl.hidden = false; 586 } 587 }).catch(function () { 588 btn.disabled = false; 589 errEl.textContent = t('network_error', 'Netzwerkfehler. Bitte später erneut versuchen.'); 590 errEl.hidden = false; 591 }); 592 }); 593 594 start(); 595 } 596 597 function onReady() { 598 attach(); 599 initSettingsPage(); 600 } 601 602 if (document.readyState === 'loading') { 603 document.addEventListener('DOMContentLoaded', onReady); 604 } else { 605 onReady(); 606 } 607 608 // Falls Buttons später dynamisch nachgeladen werden, kann der Aufrufer 609 // window.innoNewsletter.refresh() rufen, um sie zu binden. 610 window.innoNewsletter = window.innoNewsletter || {}; 611 window.innoNewsletter.refresh = attach; 612})();
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.