1document.addEventListener("scroll", function () { 2 var scrollTop = window.scrollY; 3 var docHeight = document.body.scrollHeight - window.innerHeight; 4 var scrollPercent = (scrollTop / docHeight) * 100; 5 6 if (scrollPercent > 25 && !window.scroll25) { 7 fbq('trackCustom', 'Scroll25'); 8 window.scroll25 = true; 9 } 10 11 if (scrollPercent > 50 && !window.scroll50) { 12 fbq('trackCustom', 'Scroll50'); 13 window.scroll50 = true; 14 } 15 16 if (scrollPercent > 75 && !window.scroll75) { 17 fbq('trackCustom', 'Scroll75'); 18 window.scroll75 = true; 19 } 20 21 if (scrollPercent > 90 && !window.scroll90) { 22 fbq('trackCustom', 'Scroll90'); 23 window.scroll90 = true; 24 } 25}); 26 27document.querySelectorAll('[data-target=".3ymodal"]').forEach(el => { 28 el.addEventListener('click', function () { 29 fbq('trackCustom', 'ApplyClick'); 30 }); 31}); 32 33document.getElementById('cvtform').addEventListener('submit', function (e) { 34 e.preventDefault(); 35 36 let isValid = true; 37 38 function clearErrors() { 39 document.querySelectorAll('.error').forEach(el => el.textContent = ''); 40 document.querySelectorAll('.invalid').forEach(el => el.classList.remove('invalid')); 41 } 42 43 function setError(id, message) { 44 const input = document.getElementById(id); 45 const errorDiv = document.getElementById(id + '_error'); 46 if (input) input.classList.add('invalid'); 47 if (errorDiv) errorDiv.textContent = message; 48 isValid = false; 49 } 50 51 function validateRadioGroup(name, errorId, message) { 52 const radios = document.querySelectorAll(`input[name="${name}"]`); 53 const checked = Array.from(radios).some(r => r.checked); 54 if (!checked) { 55 document.getElementById(errorId).textContent = message; 56 isValid = false; 57 } 58 } 59 60 clearErrors(); 61 62 // Text fields 63 if (!first_name.value.trim()) { 64 setError('first_name', 'First name is required.'); 65 } 66 67 if (!last_name.value.trim()) { 68 setError('last_name', 'Last name is required.'); 69 } 70 71 const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; 72 if (!email.value.trim()) { 73 setError('email', 'Email is required.'); 74 } else if (!emailPattern.test(email.value)) { 75 setError('email', 'Please enter a valid email address.'); 76 } 77 78 // GDPR 79 if (!gdpr_consent.checked) { 80 document.getElementById('gdpr_error').textContent = 'You must consent before submitting.'; 81 isValid = false; 82 } 83 84 // Radio groups 85 validateRadioGroup('description', 'description_error', 'Please select an option.'); 86 validateRadioGroup('teaching_status', 'teaching_status_error', 'Please select an option.'); 87 validateRadioGroup('interest_reason', 'interest_reason_error', 'Please select an option.'); 88 validateRadioGroup('long_term_education', 'long_term_education_error', 'Please select an option.'); 89 validateRadioGroup('start_timeline', 'start_timeline_error', 'Please select an option.'); 90 91 if (isValid) { 92 const formData = new FormData(this); 93 94 formData.append("action", "add_to_mailchimp"); 95 formData.append("security", mailchimp_ajax.nonce); 96 97 fetch(mailchimp_ajax.ajax_url, { 98 method: "POST", 99 body: formData 100 }) 101 .then(res => res.json()) 102 .then(data => { 103 if (data.success) { 104 fbq('track', 'Lead'); 105 106 if (data.data.qualified) { 107 window.open(data.data.forward, '_blank'); 108 } 109 110 document.getElementById('cvtform').style.display = "none"; 111 const rm = document.getElementById("response-message"); 112 rm.style.display = "block"; 113 rm.querySelector("#message").innerHTML = data.data.message; 114 } else { 115 document.getElementById("response-error").innerText = data.data; 116 } 117 }) 118 .catch(err => { 119 console.error(err); 120 }); 121 } 122});
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.