1/** 2 * Conditional reCAPTCHA Loader 3 * Only loads reCAPTCHA when a form with g-recaptcha class is visible 4 */ 5 6(function() { 7 'use strict'; 8 9 let recaptchaLoaded = false; 10 let recaptchaLoading = false; 11 12 // Function to load reCAPTCHA script 13 function loadRecaptcha() { 14 if (recaptchaLoaded || recaptchaLoading) { 15 return; 16 } 17 18 recaptchaLoading = true; 19 20 const script = document.createElement('script'); 21 script.src = 'https://www.google.com/recaptcha/api.js'; 22 script.async = true; 23 script.defer = true; 24 25 script.onload = function() { 26 recaptchaLoaded = true; 27 recaptchaLoading = false; 28 console.log('reCAPTCHA loaded successfully'); 29 30 // Re-initialize any existing reCAPTCHA elements 31 if (window.grecaptcha && window.grecaptcha.render) { 32 document.querySelectorAll('.g-recaptcha').forEach(function(element) { 33 if (!element.hasAttribute('data-recaptcha-rendered')) { 34 window.grecaptcha.render(element); 35 } 36 }); 37 } 38 }; 39 40 script.onerror = function() { 41 recaptchaLoading = false; 42 console.error('Failed to load reCAPTCHA'); 43 }; 44 45 document.head.appendChild(script); 46 } 47 48 // Function to check if reCAPTCHA is needed 49 function checkForRecaptcha() { 50 const recaptchaElements = document.querySelectorAll('.g-recaptcha'); 51 52 if (recaptchaElements.length > 0) { 53 // Check if any reCAPTCHA element is visible 54 const visibleElements = Array.from(recaptchaElements).filter(function(element) { 55 const rect = element.getBoundingClientRect(); 56 return rect.width > 0 && rect.height > 0; 57 }); 58 59 if (visibleElements.length > 0 && !recaptchaLoaded && !recaptchaLoading) { 60 loadRecaptcha(); 61 } 62 } 63 } 64 65 // Use Intersection Observer to detect when reCAPTCHA elements come into view 66 if ('IntersectionObserver' in window) { 67 const observer = new IntersectionObserver(function(entries) { 68 entries.forEach(function(entry) { 69 if (entry.isIntersecting && entry.target.classList.contains('g-recaptcha')) { 70 loadRecaptcha(); 71 observer.disconnect(); 72 } 73 }); 74 }, { 75 rootMargin: '50px' // Load when element is 50px away from viewport 76 }); 77 78 // Observe all reCAPTCHA elements 79 document.querySelectorAll('.g-recaptcha').forEach(function(element) { 80 observer.observe(element); 81 }); 82 } else { 83 // Fallback for older browsers 84 let checkInterval; 85 86 function startChecking() { 87 checkInterval = setInterval(function() { 88 checkForRecaptcha(); 89 if (recaptchaLoaded) { 90 clearInterval(checkInterval); 91 } 92 }, 500); 93 } 94 95 // Start checking after DOM is ready 96 if (document.readyState === 'loading') { 97 document.addEventListener('DOMContentLoaded', startChecking); 98 } else { 99 startChecking(); 100 } 101 } 102 103 // Also check when forms are focused (user might be about to submit) 104 document.addEventListener('focusin', function(event) { 105 if (event.target.closest('.g-recaptcha')) { 106 loadRecaptcha(); 107 } 108 }); 109 110 // Check when user scrolls near forms 111 let scrollTimeout; 112 window.addEventListener('scroll', function() { 113 clearTimeout(scrollTimeout); 114 scrollTimeout = setTimeout(function() { 115 checkForRecaptcha(); 116 }, 100); 117 }); 118 119})();
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.