1/* 2 * Kontaktnà formuláŠâ odeslánà na nový backend /api/contact. 3 * Nahrazuje původnà Contact Form 7 JS (které posÃlalo na WordPress REST API). 4 * Zachovává vzhled a stavové tÅÃdy CF7, aby formuláŠvypadal a choval se 1:1. 5 */ 6(function () { 7 'use strict'; 8 9 var ENDPOINT = '/api/contact'; 10 var EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; 11 12 function ready(fn) { 13 if (document.readyState !== 'loading') fn(); 14 else document.addEventListener('DOMContentLoaded', fn); 15 } 16 17 function clearTips(form) { 18 form.querySelectorAll('.wpcf7-not-valid-tip').forEach(function (t) { t.remove(); }); 19 form.querySelectorAll('.wpcf7-not-valid').forEach(function (el) { 20 el.classList.remove('wpcf7-not-valid'); 21 el.setAttribute('aria-invalid', 'false'); 22 }); 23 } 24 25 function showTip(input, msg) { 26 if (!input) return; 27 input.classList.add('wpcf7-not-valid'); 28 input.setAttribute('aria-invalid', 'true'); 29 var tip = document.createElement('span'); 30 tip.className = 'wpcf7-not-valid-tip'; 31 tip.setAttribute('aria-hidden', 'true'); 32 tip.textContent = msg; 33 (input.closest('.wpcf7-form-control-wrap') || input.parentNode).appendChild(tip); 34 } 35 36 function setStatus(form, state, message) { 37 // state: 'sent' | 'invalid' | 'failed' | 'submitting' | '' 38 form.classList.remove('sent', 'invalid', 'failed', 'submitting', 'init'); 39 if (state) form.classList.add(state); 40 var out = form.querySelector('.wpcf7-response-output'); 41 if (out) { 42 out.textContent = message || ''; 43 out.setAttribute('aria-hidden', message ? 'false' : 'true'); 44 out.style.display = message ? 'block' : ''; 45 } 46 } 47 48 function clientValidate(form) { 49 clearTips(form); 50 var ok = true; 51 var name = form.querySelector('[name="your-name"]'); 52 var email = form.querySelector('[name="your-email"]'); 53 var message = form.querySelector('[name="message"]'); 54 var consent = form.querySelector('[name="consent-1"]'); 55 56 if (name && !name.value.trim()) { showTip(name, 'Please fill out this field.'); ok = false; } 57 if (email && !email.value.trim()) { showTip(email, 'Please fill out this field.'); ok = false; } 58 else if (email && !EMAIL_RE.test(email.value.trim())) { showTip(email, 'The e-mail address is invalid.'); ok = false; } 59 if (message && !message.value.trim()) { 60 showTip(message, 'Please fill out this field.'); ok = false; 61 } 62 if (consent && consent.type === 'checkbox' && !consent.checked) { 63 showTip(consent, 'You must accept the terms.'); ok = false; 64 } 65 return ok; 66 } 67 68 function handle(form) { 69 form.setAttribute('novalidate', 'novalidate'); 70 form.addEventListener('submit', function (e) { 71 e.preventDefault(); 72 e.stopPropagation(); 73 74 if (!clientValidate(form)) { 75 setStatus(form, 'invalid', 'One or more fields have an error. Please check and try again.'); 76 return; 77 } 78 79 var submitBtn = form.querySelector('[type="submit"]'); 80 if (submitBtn) submitBtn.disabled = true; 81 setStatus(form, 'submitting', 'Sendingâ¦'); 82 83 fetch(ENDPOINT, { 84 method: 'POST', 85 headers: { Accept: 'application/json' }, 86 body: new FormData(form), 87 }) 88 .then(function (res) { return res.json().then(function (d) { return { res: res, data: d }; }); }) 89 .then(function (r) { 90 if (r.res.ok && r.data.ok) { 91 setStatus(form, 'sent', r.data.message || 'Thank you for your message!'); 92 form.reset(); 93 } else { 94 if (r.data && r.data.errors) { 95 Object.keys(r.data.errors).forEach(function (field) { 96 showTip(form.querySelector('[name="' + field + '"]'), r.data.errors[field]); 97 }); 98 } 99 setStatus(form, r.res.status === 422 ? 'invalid' : 'failed', 100 (r.data && r.data.message) || 'Something went wrong. Please try again.'); 101 } 102 }) 103 .catch(function () { 104 setStatus(form, 'failed', 'Network error. Please try again later.'); 105 }) 106 .finally(function () { 107 if (submitBtn) submitBtn.disabled = false;
108 }); 109 }); 110 } 111 112 ready(function () { 113 document.querySelectorAll('form.wpcf7-form').forEach(handle); 114 }); 115})();
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.