1window.recaptcha = (function () { 2 let v3Key = null, v2Key = null; 3 4 // containerId -> widgetId 5 const v2Widgets = new Map(); 6 // containerId -> resolver (Promise) 7 const v2Resolvers = new Map(); 8 // containerId -> HTMLElement (slot hijo real donde se renderiza) 9 const v2Slots = new Map(); 10 11 let v2Busy = false; 12 13 function init(siteKeyV3, siteKeyV2) { v3Key = siteKeyV3; v2Key = siteKeyV2; } 14 15 function ensureGreCaptcha() { 16 return new Promise((resolve, reject) => { 17 let tries = 0; 18 (function waitForIt() { 19 tries++; 20 if (window.grecaptcha && typeof grecaptcha.render === "function") return resolve(); 21 if (tries > 120) return reject("grecaptcha no cargó"); 22 setTimeout(waitForIt, 50); 23 })(); 24 }); 25 } 26 27 async function getV3Token(action) { 28 await ensureGreCaptcha(); 29 return await grecaptcha.execute(v3Key, { action }); 30 } 31 32 async function renderV2AndWait(containerId) { 33 await ensureGreCaptcha(); 34 if (v2Busy) return null; 35 v2Busy = true; 36 37 const host = document.getElementById(containerId); 38 if (!host) { v2Busy = false; return null; } 39 host.style.display = 'block'; 40 41 return new Promise((resolve) => { 42 // guardar resolver para poder cancelarlo en hide/dispose 43 v2Resolvers.set(containerId, (tok) => { v2Busy = false; resolve(tok); }); 44 45 let widgetId = v2Widgets.get(containerId); 46 let slot = v2Slots.get(containerId); 47 48 // ¿Necesitamos un slot nuevo? (si no hay widget, no hay slot, o el slot ya no está en el DOM) 49 const needsNewSlot = !widgetId || !slot || !host.contains(slot); 50 51 if (needsNewSlot) { 52 // limpiar host y crear un slot hijo NUEVO 53 try { if (widgetId != null && window.grecaptcha && typeof grecaptcha.reset === "function") { grecaptcha.reset(widgetId); } } catch { } 54 v2Widgets.delete(containerId); 55 56 host.innerHTML = ''; 57 slot = document.createElement('div'); 58 slot.className = 'grecaptcha-slot'; 59 host.appendChild(slot); 60 61 // Render SIEMPRE sobre el SLOT (no sobre el host) 62 widgetId = grecaptcha.render(slot, { 63 sitekey: v2Key, 64 callback: (token) => onV2Solved(containerId, token), 65 "error-callback": () => onV2Error(containerId), 66 "expired-callback": () => onV2Expired(containerId) 67 }); 68 69 v2Widgets.set(containerId, widgetId); 70 v2Slots.set(containerId, slot); 71 } else { 72 // Reutilizamos el widget existente 73 try { grecaptcha.reset(widgetId); } catch { } 74 } 75 }); 76 } 77 78 function onV2Solved(containerId, token) { resolveAndClear(containerId, token); } 79 function onV2Error(containerId) { resolveAndClear(containerId, null); } 80 function onV2Expired(containerId) { resolveAndClear(containerId, null); } 81 82 function resolveAndClear(containerId, value) { 83 const resolver = v2Resolvers.get(containerId); 84 if (resolver) { v2Resolvers.delete(containerId); resolver(value); } 85 } 86 87 // --- utilidades de limpieza --- 88 89 async function resetV2(containerId) { 90 const widgetId = v2Widgets.get(containerId); 91 if (widgetId != null && window.grecaptcha && typeof grecaptcha.reset === "function") { 92 try { grecaptcha.reset(widgetId); } catch { } 93 } 94 const host = document.getElementById(containerId); 95 if (host) { 96 const ta = host.querySelector('textarea[g-recaptcha-response]'); 97 if (ta) ta.value = ''; 98 } 99 } 100 101 async function hideV2(containerId) { 102 // 1) cancelar promesa pendiente y liberar semáforo 103 const resolver = v2Resolvers.get(containerId); 104 if (resolver) { v2Resolvers.delete(containerId); try { resolver(null); } catch { } } 105 v2Busy = false; 106 107 // 2) resetear widget para poder reutilizarlo luego 108 const widgetId = v2Widgets.get(containerId); 109 if (widgetId != null && window.grecaptcha && typeof grecaptcha.reset === "function") { 110 try { grecaptcha.reset(widgetId); } catch { } 111 } 112 113 // 3) ocultar contenedor (NO destruyas el slot) 114 const host = document.getElementById(containerId); 115 if (host) host.style.display = 'none'; 116 } 117 118 async function disposeV2(containerId) { 119 // Si de verdad quieres destruirlo (por ejemplo, abandonas la página) 120 const resolver = v2Resolvers.get(containerId); 121 if (resolver) { v2Resolvers.delete(containerId); try { resolver(null); } catch { } } 122 123 const widgetId = v2Widgets.get(containerId); 124 if (widgetId != null && window.grecaptcha && typeof grecaptcha.reset === "function") { 125 try { grecaptcha.reset(widgetId); } catch { } 126 } 127 v2Widgets.delete(containerId); 128 129 const host = document.getElementById(containerId); 130 if (host) { host.innerHTML = ''; host.style.display = 'none'; } 131 132 v2Slots.delete(containerId); 133 v2Busy = false; 134 } 135 136 async function hideV2(containerId) { 137 // 1) cancelar promesa pendiente y liberar semáforo 138 const resolver = v2Resolvers.get(containerId); 139 if (resolver) { 140 v2Resolvers.delete(containerId); 141 try { resolver("__cancelled__"); } catch { } 142 } 143 v2Busy = false; 144 145 // 2) resetear widget para poder reutilizarlo luego 146 const widgetId = v2Widgets.get(containerId); 147 if (widgetId != null && window.grecaptcha && typeof grecaptcha.reset === "function") { 148 try { grecaptcha.reset(widgetId); } catch { } 149 } 150 151 // 3) ocultar contenedor 152 const host = document.getElementById(containerId); 153 if (host) host.style.display = 'none'; 154 } 155 156 157 return { init, getV3Token, renderV2AndWait, resetV2, hideV2, disposeV2 }; 158 159 160})();
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.