1/** 2 * FormularhÃ¥ndtering â kontaktformular, selskabsforespørgsel og widget. 3 * 4 * Progressive enhancement: formularerne har rigtige felter med required, 5 * maxlength og korrekte type-attributter, sÃ¥ browseren validerer selv. 6 * Uden JavaScript poster de som almindelig formular; JS giver bare svar 7 * uden at forlade siden. 8 */ 9 10const ENDPOINT = '/api/contact'; 11 12/** Samler felterne til den besked receptionen modtager. */ 13function buildMessage(form) { 14 const fd = new FormData(form); 15 const get = (k) => (fd.get(k) || '').toString().trim(); 16 17 const wishes = fd.getAll('wishes').filter(Boolean); 18 const extras = [ 19 ['Telefon', get('phone')], 20 ['Firma', get('company')], 21 ['Adresse', [get('address'), get('zip'), get('city')].filter(Boolean).join(', ')], 22 ['Dato', get('date')], 23 ['Antal gæster', get('guests')], 24 ['Ãnsker', wishes.join(', ')], 25 ].filter(([, v]) => v); 26 27 const body = get('message'); 28 const head = extras.map(([k, v]) => `${k}: ${v}`).join('\n'); 29 30 return [head, body].filter(Boolean).join('\n\n'); 31} 32 33function wire(form) { 34 const status = form.querySelector('.form__status'); 35 const button = form.querySelector('button[type="submit"]'); 36 if (!status || !button) return; 37 38 const thanks = status.dataset.thanks || 'Tak for din besked.'; 39 const lang = document.documentElement.lang || 'da'; 40 41 form.addEventListener('submit', async (e) => { 42 e.preventDefault(); 43 44 if (!form.reportValidity()) return; 45 46 const original = button.textContent; 47 button.disabled = true; 48 status.textContent = ''; 49 status.removeAttribute('data-state'); 50 51 const fd = new FormData(form); 52 const payload = { 53 name: (fd.get('name') || '').toString().trim(), 54 email: (fd.get('email') || '').toString().trim(), 55 message: buildMessage(form), 56 lang, 57 website: (fd.get('website') || '').toString(), 58 }; 59 60 try { 61 const res = await fetch(ENDPOINT, { 62 method: 'POST', 63 headers: { 'Content-Type': 'application/json' }, 64 body: JSON.stringify(payload), 65 }); 66 67 const data = await res.json().catch(() => ({})); 68 69 if (res.ok && data.ok) { 70 form.reset(); 71 status.textContent = thanks; 72 status.setAttribute('data-state', 'ok'); 73 // Skjul felterne nÃ¥r beskeden er sendt â svaret er det eneste 74 // der er relevant derefter. 75 form.querySelectorAll('fieldset, label, .wishes, .wishes-label, button').forEach((el) => { 76 el.hidden = true; 77 }); 78 } else { 79 status.textContent = data.error || 'Beskeden kunne ikke sendes. Prøv igen, eller ring til os.'; 80 status.setAttribute('data-state', 'error'); 81 } 82 } catch { 83 status.textContent = 'Beskeden kunne ikke sendes. Prøv igen, eller ring til os.'; 84 status.setAttribute('data-state', 'error'); 85 } finally { 86 button.disabled = false; 87 button.textContent = original; 88 } 89 }); 90} 91 92document.querySelectorAll('form#contact-form, form#event-form, form#widget-form').forEach(wire);
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.