PageSourceSearch

https://sebastianwalach.com/enquiry.js?v=929466595825

js sebastianwalach.com collected 2026-10-06 13:35:26 UTC 3,326 bytes, 66 lines download raw bytes

1(() => {
2  const track = (event, parameters) => {
3    // Tracking must never turn an accepted enquiry into a visible send failure.
4    try {
5      if (typeof window.gtag === 'function') window.gtag('event', event, parameters);
6    } catch (_) {}
7  };
8  document.addEventListener('click', event => {
9    const link = event.target.closest('a[href]');
10    if (!link) return;
11    if (link.href.startsWith('mailto:')) track('email_click', {contact_method: 'email'});
12    else if (new URL(link.href).hostname === 'www.linkedin.com') track('linkedin_click', {contact_method: 'linkedin'});
13  });
14  const form = document.getElementById('enquiry-form');
15  if (!form) return;
16  const status = document.getElementById('enquiry-status');
17  const button = form.querySelector('[type="submit"]');
18  const endpoint = new URL(form.getAttribute('action'), location.href);
19  let token = '', submissionId = '', busy = false, complete = false;
20  async function prepare() {
21    const response = await fetch(endpoint, {cache: 'no-store', credentials: 'same-origin', headers: {Accept: 'application/json'}});
22    const data = await response.json();
23    if (!response.ok || !data.token) throw new Error('The form is unavailable. Please email [email protected].');
24    token = data.token;
25    submissionId = data.submissionId;
26  }
27  const ready = prepare().catch(() => { status.textContent = 'The form is unavailable right now. You can email me directly above.'; });
28  form.addEventListener('submit', async event => {
29    event.preventDefault();
30    if (busy || complete || !form.reportValidity()) return;
31    busy = true;
32    button.disabled = true;
33    button.textContent = 'Sending…';
34    status.textContent = '';
35    form.setAttribute('aria-busy', 'true');
36    try {
37      await ready;
38      if (!token) await prepare();
39      const payload = new FormData(form);
40      payload.set('token', token);
41      payload.set('submission_id', submissionId);
42      const response = await fetch(endpoint, {method: 'POST', body: payload, credentials: 'same-origin', headers: {Accept: 'application/json'}});
43      const data = await response.json();
44      if (!response.ok || data.success !== true) {
45        if (response.status === 403) {token = ''; await prepare();}
46        throw new Error(data.message || 'Your enquiry could not be sent. Please try again or email me directly.');
47      }
48      complete = true;
49      status.textContent = 'Thanks—your enquiry is on its way. I’ll be in touch by email.';
50      status.classList.add('enquiry-success');
51      button.textContent = 'Enquiry sent ↗';
52      form.querySelectorAll('input, select, textarea').forEach(field => {field.disabled = true;});
53      // Both events belong only to a confirmed success, never load or click.
54      // No names, emails, company names or project text go to tracking.
55      track('generate_lead', {form_id: 'project_enquiry', lead_source: 'website_form'});
56      track('ads_conversion_Submit_lead_form_1', {});
57    } catch (error) {
58      status.textContent = error.message.includes('Failed to fetch') ? 'Your connection was interrupted. Please try again or email me directly.' : error.message;
59      button.disabled = false;
60      button.textContent = 'Send enquiry ↗';
61    } finally {
62      busy = false;
63      form.removeAttribute('aria-busy');
64    }
65  });
66})();

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.