1/* ---- reCAPTCHA v3 for multiple forms ---- */ 2(function () 3{ 4 var recaptchaKey = '6Lf6t1slAAAAAIRVDKc1ncTpnksULIq8YNNh7-n4'; // your site key 5 var recaptchaReady = false; 6 7 function loadRecaptchaScript() 8 { 9 if (document.getElementById('recaptcha-v3')) return; // don't double-load 10 11 var script = document.createElement('script'); 12 script.id = 'recaptcha-v3'; 13 script.src = 'https://www.google.com/recaptcha/api.js?render=' + recaptchaKey; 14 script.async = true; 15 script.defer = true; 16 script.onload = function () { 17 recaptchaReady = true; 18 }; 19 20 document.head.appendChild(script); 21 } 22 23 // Attach a submit handler to a single form (idempotent) 24 function attachRecaptchaToForm(form) 25 { 26 if (!form || form.__recaptchaAttached) return; 27 28 form.__recaptchaAttached = true; // mark as attached 29 30 form.addEventListener('submit', function onSubmit(e) 31 { 32 // If we're already in the "token acquired" pass-through, let it submit 33 if (form.dataset.recaptchaSubmitting === '1') 34 { 35 return; 36 } 37 38 // Optional: let the browser validate first (remove if using custom validation) 39 if (!form.checkValidity || form.checkValidity()) 40 { 41 // Ensure grecaptcha is available; if not, load and retry shortly 42 if (!recaptchaReady || typeof grecaptcha === 'undefined') 43 { 44 e.preventDefault(); 45 loadRecaptchaScript(); 46 47 setTimeout(function () 48 { 49 // Re-trigger submit after the script likely loaded 50 if (typeof form.requestSubmit === 'function') 51 { 52 form.requestSubmit(); 53 } 54 55 else 56 { 57 HTMLFormElement.prototype.submit.call(form); 58 } 59 }, 300); 60 return; 61 } 62 63 // We have grecaptcha?get a fresh token before submitting 64 e.preventDefault(); 65 grecaptcha.ready(function () 66 { 67 grecaptcha.execute(recaptchaKey, 68 { 69 action: 'submit' 70 }).then(function (token) 71 { 72 var tokenField = form.querySelector('input[name="token_generate"]'); 73 74 if (!tokenField) 75 { 76 // Create the field if missing 77 tokenField = document.createElement('input'); 78 tokenField.type = 'hidden'; 79 tokenField.name = 'token_generate'; 80 form.appendChild(tokenField); 81 } 82 83 tokenField.value = token; 84 85 // Mark as pass-through so our submit handler doesn't intercept again 86 form.dataset.recaptchaSubmitting = '1'; 87 88 // Bypass event listeners to avoid recursion 89 HTMLFormElement.prototype.submit.call(form); 90 }).catch(function () 91 { 92 alert('Unable to verify reCAPTCHA. Please try again.'); 93 }); 94 }); 95 } 96 97 else 98 { 99 // If invalid, let browser show messages 100 // Some browsers need this to display the native UI 101 if (typeof form.reportValidity === 'function') 102 { 103 form.reportValidity(); 104 } 105 } 106 }); 107 } 108 109 document.addEventListener('DOMContentLoaded', function () 110 { 111 // Load reCAPTCHA a moment after page load 112 setTimeout(loadRecaptchaScript, 200);
113 114 // Attach to all existing forms matching the class 115 Array.prototype.forEach.call( 116 document.querySelectorAll('form.recaptcha-form'), 117 attachRecaptchaToForm 118 ); 119 120 // If forms are added dynamically later, observe and attach automatically 121 var mo = new MutationObserver(function (mutations) 122 { 123 mutations.forEach(function (m) 124 { 125 Array.prototype.forEach.call(m.addedNodes || [], function (node) 126 { 127 if (node && node.nodeType === 1) 128 { 129 if (node.matches && node.matches('form.recaptcha-form')) 130 { 131 attachRecaptchaToForm(node); 132 } 133 134 // Also check inside containers 135 var innerForms = node.querySelectorAll ? node.querySelectorAll('form.recaptcha-form') : []; 136 Array.prototype.forEach.call(innerForms, attachRecaptchaToForm); 137 } 138 }); 139 }); 140 }); 141 142 mo.observe(document.documentElement, 143 { 144 childList: true, 145 subtree: true 146 }); 147 148 // Optional: preload when a form is near viewport (nice for performance) 149 try 150 { 151 var observer = new IntersectionObserver(function (entries, obs) 152 { 153 entries.forEach(function (entry) 154 { 155 if (entry.isIntersecting || entry.intersectionRatio >= 0.1) 156 { 157 loadRecaptchaScript(); 158 obs.unobserve(entry.target); 159 } 160 }); 161 }, 162 { 163 root: null, 164 rootMargin: '0px', 165 threshold: 0.1 166 }); 167 168 document.querySelectorAll('form.recaptcha-form').forEach(function (f) 169 { 170 observer.observe(f); 171 }); 172 173 } 174 175 catch (_) 176 { 177 /* older browsers */ 178 } 179 }); 180})();
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.