1const menuButton = document.querySelector('.menu'); 2const mobileNav = document.querySelector('.nav nav'); 3 4if (menuButton && mobileNav) { 5 menuButton.setAttribute('aria-expanded', 'false'); 6 7 menuButton.addEventListener('click', () => { 8 const isOpen = mobileNav.classList.toggle('open'); 9 10 menuButton.setAttribute( 11 'aria-expanded', 12 String(isOpen) 13 ); 14 15 menuButton.textContent = isOpen ? 'Ã' : 'â°'; 16 }); 17 18 document.querySelectorAll('.nav a').forEach(link => { 19 link.addEventListener('click', () => { 20 mobileNav.classList.remove('open'); 21 menuButton.setAttribute('aria-expanded', 'false'); 22 menuButton.textContent = 'â°'; 23 }); 24 }); 25} 26 27const yearElement = document.getElementById('year'); 28 29if (yearElement) { 30 yearElement.textContent = new Date().getFullYear(); 31} 32 33const orderForm = document.getElementById('orderForm'); 34const submitButton = document.getElementById('submit-button'); 35const formStatus = document.getElementById('form-status'); 36 37const FORM_ENDPOINT = 38 'https://ultrafibre-worker.jerry-882.workers.dev/'; 39 40if (!orderForm || !submitButton || !formStatus) { 41 console.error('Order form elements could not be found:', { 42 orderForm, 43 submitButton, 44 formStatus 45 }); 46} else { 47 orderForm.addEventListener('submit', async event => { 48 event.preventDefault(); 49 50 clearFormStatus(); 51 52 if (!orderForm.reportValidity()) { 53 return; 54 } 55 56 const turnstileToken = 57 orderForm.querySelector( 58 '[name="cf-turnstile-response"]' 59 )?.value; 60 61 if (!turnstileToken) { 62 showFormStatus( 63 'Please complete the security verification.', 64 'error' 65 ); 66 67 return; 68 } 69 70 const formData = new FormData(orderForm); 71 72 const payload = { 73 firstName: formData.get('FirstName') || '', 74 lastName: formData.get('LastName') || '', 75 email: formData.get('Email') || '', 76 phone: formData.get('Phone') || '', 77 addressLine1: formData.get('AddressLine1') || '', 78 town: formData.get('Town') || '', 79 postcode: formData.get('Postcode') || '', 80 plan: formData.get('Plan') || '', 81 message: formData.get('Notes') || '', 82 website: formData.get('website') || '', 83 turnstileToken 84 }; 85 86 setSubmitting(true); 87 88 try { 89 const response = await fetch(FORM_ENDPOINT, { 90 method: 'POST', 91 headers: { 92 'Content-Type': 'application/json' 93 }, 94 body: JSON.stringify(payload) 95 }); 96 97 let result; 98 99 try { 100 result = await response.json(); 101 } catch { 102 result = { 103 success: false, 104 message: 'An unexpected response was received.' 105 }; 106 } 107 108 if (!response.ok || !result.success) { 109 throw new Error( 110 result.message || 111 'Your order could not be submitted.' 112 ); 113 } 114 115 orderForm.reset(); 116 117 if (window.turnstile) { 118 window.turnstile.reset(); 119 } 120 121 showFormStatus( 122 result.message || 123 'Thank you. Your order has been received.', 124 'success' 125 ); 126 } catch (error) { 127 console.error('Form submission failed:', error); 128 129 showFormStatus( 130 error.message || 131 'Submission failed. Please contact us directly.', 132 'error' 133 ); 134 135 if (window.turnstile) { 136 window.turnstile.reset(); 137 } 138 } finally { 139 setSubmitting(false); 140 } 141 }); 142} 143 144function setSubmitting(isSubmitting) { 145 if (!submitButton) { 146 return; 147 } 148 149 submitButton.disabled = isSubmitting; 150 submitButton.textContent = isSubmitting 151 ? 'SENDING...' 152 : 'SUBMIT ORDER'; 153} 154 155function showFormStatus(message, type) { 156 if (!formStatus) { 157 return; 158 } 159 160 formStatus.textContent = message; 161 formStatus.className = 162 `full status form-status--${type}`; 163} 164 165function clearFormStatus() { 166 if (!formStatus) { 167 return; 168 } 169 170 formStatus.textContent = ''; 171 formStatus.className = 'full status'; 172} 173 174if ('IntersectionObserver' in window) { 175 const revealObserver = new IntersectionObserver( 176 entries => { 177 entries.forEach(entry => { 178 if (entry.isIntersecting) { 179 entry.target.classList.add('is-visible'); 180 revealObserver.unobserve(entry.target); 181 } 182 }); 183 }, 184 { 185 threshold: 0.12 186 } 187 ); 188 189 document 190 .querySelectorAll('.reveal') 191 .forEach(section => { 192 revealObserver.observe(section); 193 }); 194} else { 195 document 196 .querySelectorAll('.reveal') 197 .forEach(section => { 198 section.classList.add('is-visible'); 199 }); 200}
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.