1/* ============================================================================ 2 lead.js, behaviour for the shared lead-capture form component. 3 The markup lives in each page (component: LeadCaptureForm); its copy lives in 4 src/content/site/forms.json â leadForm. Any [data-open-lead] element opens it; 5 add data-lead-service="Subtitling" to pre-select a service chip. 6 No-ops on pages without the component. 7 ========================================================================= */ 8(function () { 9 var modal = document.getElementById('leadModal'); 10 if (!modal || modal.__leadBound) return; 11 modal.__leadBound = true; 12 13 var form = document.getElementById('leadForm'); 14 var success = document.getElementById('leadSuccess'); 15 var eyebrow = document.getElementById('leadEyebrow'); 16 var chips = Array.prototype.slice.call(modal.querySelectorAll('.lead-chip')); 17 var defaultEyebrow = eyebrow ? eyebrow.textContent : ''; 18 var lastFocus = null; 19 20 var open = function (e) { 21 if (e) e.preventDefault(); 22 lastFocus = document.activeElement; 23 24 // pre-select a service if the trigger requested one 25 var trigger = e && e.currentTarget ? e.currentTarget : null; 26 var preset = trigger ? trigger.getAttribute('data-lead-service') : null; 27 chips.forEach(function (c) { c.classList.remove('active'); }); 28 if (preset) { 29 chips.forEach(function (c) { if (c.dataset.service === preset) c.classList.add('active'); }); 30 if (eyebrow) eyebrow.textContent = '// ' + preset + ' request'; 31 } else if (eyebrow) { 32 eyebrow.textContent = defaultEyebrow; 33 } 34 35 form.hidden = false; success.hidden = true; 36 modal.hidden = false; document.body.style.overflow = 'hidden'; 37 setTimeout(function () { var f = form.querySelector('input[name="name"]'); if (f) f.focus(); }, 60); 38 }; 39 var close = function () { 40 modal.hidden = true; document.body.style.overflow = ''; 41 if (lastFocus && lastFocus.focus) lastFocus.focus(); 42 }; 43 44 document.querySelectorAll('[data-open-lead]').forEach(function (b) { b.addEventListener('click', open); }); 45 modal.querySelectorAll('[data-close-lead]').forEach(function (b) { b.addEventListener('click', close); }); 46 document.addEventListener('keydown', function (e) { if (e.key === 'Escape' && !modal.hidden) close(); }); 47 48 chips.forEach(function (chip) { chip.addEventListener('click', function () { chip.classList.toggle('active'); }); }); 49 50 form.addEventListener('submit', function (e) { 51 e.preventDefault(); 52 var name = form.name.value.trim(); 53 var email = form.email.value.trim(); 54 if (!name) { form.name.focus(); return; } 55 if (!email || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) { form.email.reportValidity(); return; } 56 57 var services = chips.filter(function (c) { return c.classList.contains('active'); }).map(function (c) { return c.dataset.service; }).join(', '); 58 var data = new FormData(form); 59 data.set('form-name', 'lead'); 60 data.set('services', services); 61 62 var btn = form.querySelector('button[type="submit"]'); 63 if (btn) btn.disabled = true; 64 fetch('/', { 65 method: 'POST', 66 headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, 67 body: new URLSearchParams(data).toString() 68 }).then(function (res) { 69 if (!res.ok) throw new Error('HTTP ' + res.status); 70 document.getElementById('leadName').textContent = name.split(' ')[0] || 'there'; 71 document.getElementById('leadEmail').textContent = email; 72 form.hidden = true; success.hidden = false; 73 form.reset(); chips.forEach(function (c) { c.classList.remove('active'); }); 74 }).catch(function () { 75 alert('Something went wrong sending your request. Please try again, or email [email protected].'); 76 }).finally(function () { 77 if (btn) btn.disabled = false; 78 }); 79 }); 80})();
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.