PageSourceSearch

https://ultrafibre.io/script.js

js ultrafibre.io collected 2026-10-06 02:44:02 UTC 4,537 bytes, 200 lines download raw bytes

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.