1(function () { 2 var form = document.getElementById('inquire-form'); 3 if (!form) return; 4 5 var fields = [ 6 { id: 'firstName', name: 'first name' }, 7 { id: 'lastName', name: 'last name' }, 8 { id: 'email', name: 'email', email: true }, 9 { id: 'subject', name: 'subject' }, 10 { id: 'message', name: 'message' } 11 ]; 12 13 function fieldWrap(el) { 14 return el.closest('.field') || el.parentElement; 15 } 16 function setState(input, msg) { 17 var wrap = fieldWrap(input); 18 var err = document.getElementById('err-' + input.id); 19 if (err) err.textContent = msg || ''; 20 if (msg) { 21 input.setAttribute('aria-invalid', 'true'); 22 if (wrap) { wrap.classList.add('invalid'); wrap.classList.remove('valid'); } 23 } else { 24 input.removeAttribute('aria-invalid'); 25 if (wrap) { wrap.classList.remove('invalid'); wrap.classList.add('valid'); } 26 } 27 } 28 function validate(input, meta) { 29 var msg = ''; 30 if (input.validity.valueMissing) { 31 msg = 'Please enter your ' + meta.name + '.'; 32 } else if (meta.email && input.validity.typeMismatch) { 33 msg = 'Please enter a valid email address.'; 34 } else if (input.validity.tooShort) { 35 msg = 'Please enter at least ' + input.minLength + ' characters.'; 36 } 37 setState(input, msg); 38 return !msg; 39 } 40 fields.forEach(function (meta) { 41 var el = document.getElementById(meta.id); 42 if (!el) return; 43 el.addEventListener('input', function () { validate(el, meta); }); 44 el.addEventListener('blur', function () { validate(el, meta); }); 45 }); 46 47 // --- NEW: unify location detection (matches the nav logic) --- 48 function detectLocationSlug() { 49 var path = (location.pathname || '').toLowerCase(); 50 if (path.startsWith('/fort-lauderdale')) return 'fort-lauderdale'; 51 if (path.startsWith('/toronto')) return 'toronto'; 52 53 // Fallback: infer from hidden input if present 54 var locInput = form.querySelector('input[name="location"]'); 55 var raw = (locInput && locInput.value || '').toLowerCase(); 56 if (raw.includes('fort')) return 'fort-lauderdale'; 57 if (raw.includes('toronto')) return 'toronto'; 58 59 // Default if truly unknown 60 return 'toronto'; 61 } 62 63 // Optional: keep the hidden input in sync for backend/email context 64 (function syncHiddenInput() { 65 var locInput = form.querySelector('input[name="location"]'); 66 if (!locInput) return; 67 var slug = detectLocationSlug(); 68 locInput.value = (slug === 'fort-lauderdale') ? 'Fort Lauderdale, Florida' : 'Toronto, Canada'; 69 })(); 70 71 form.addEventListener('submit', function (e) { 72 // 1) Client-side validation 73 var firstInvalid = null; 74 fields.forEach(function (meta) { 75 var el = document.getElementById(meta.id); 76 if (!el) return; 77 if (!validate(el, meta) && !firstInvalid) firstInvalid = el; 78 }); 79 if (firstInvalid) { 80 e.preventDefault(); 81 firstInvalid.focus({ preventScroll: false }); 82 return; 83 } 84 85 // 2) Determine location from URL (primary) or hidden input (fallback) 86 var slug = detectLocationSlug(); // "toronto" | "fort-lauderdale" 87 88 var isLocal = location.hostname === 'localhost' || location.hostname === '127.0.0.1'; 89 90 // Base from action (could be "/thank-you" or "/thank-you.html" or location-specific) 91 var base = (form.getAttribute('action') || '/thank-you.html').replace(/\/$/, ''); 92 93 // On localhost, force .html because static server won't apply redirects 94 var baseForEnv = isLocal 95 ? (base.endsWith('.html') ? base : (base + '.html')) 96 : base; 97 98 // Append l=toronto|fort-lauderdale for location-specific copy on TY page 99 var redirectUrl = baseForEnv + (baseForEnv.includes('?') ? '&' : '?') + 'l=' + encodeURIComponent(slug); 100 101 if (isLocal) { 102 // 3) Localhost flow: POST best-effort then redirect 103 e.preventDefault(); 104 var data = new FormData(form); 105 if (!data.has('form-name')) data.append('form-name', form.getAttribute('name')); 106 107 fetch('/', { 108 method: 'POST', 109 headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, 110 body: new URLSearchParams(data).toString() 111 }) 112 .catch(function (err) { 113 console.warn('Local POST failed:', err); 114 }) 115 .finally(function () { 116 window.location.assign(redirectUrl); 117 }); 118 return; 119 } 120 121 // 4) Netlify/Prod: set the action to the tagged URL and let the browser POST normally 122 form.setAttribute('action', redirectUrl); 123 }); 124})();
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.