1/** 2 * УнивеÑÑалÑнÑй иниÑиализаÑÐ¾Ñ Ð¯Ð½Ð´ÐµÐºÑ SmartCaptcha (невидимаÑ) Ð´Ð»Ñ ÑоÑм 3 * ÐÑполÑзование: добавÑÑе аÑÑибÑÑ data-captcha="true" к лÑбой ÑоÑме 4 * 5 * @version 3.0 (ленивÑй ÑендеÑ: Ð²Ð¸Ð´Ð¶ÐµÑ ÑоздаÑÑÑÑ Ð¿Ñи пеÑвом взаимодейÑÑвии Ñ ÑоÑмой) 6 * 7 * ÐоÑÐµÐ¼Ñ Ð»ÐµÐ½Ð¸Ð²Ð¾: smartCaptcha.render() ÑÑÐ°Ð·Ñ Ð²ÑÑавлÑÐµÑ Ð½Ð° ÑÑÑаниÑÑ Ð´Ð²Ð° iframe 8 * ЯндекÑа, один из коÑоÑÑÑ ÑÑÐ½ÐµÑ React Ñ yastatic.net. 9 */ 10(function () { 11 'use strict'; 12 13 const arCaptchaInstances = new Map(); 14 const arFailedForms = new WeakSet(); 15 let arPendingForms = []; 16 let nCheckInterval = null; 17 18 /** 19 * ÐниÑиализаÑÐ¸Ñ ÐºÐ°Ð¿Ñи Ð´Ð»Ñ ÑоÑÐ¼Ñ 20 * @param {HTMLFormElement} obForm 21 */ 22 function initCaptchaForForm(obForm) { 23 // ÐÐ¸Ð´Ð¶ÐµÑ Ð´Ð»Ñ ÑÑой ÑоÑÐ¼Ñ Ñже Ñоздан 24 if (obForm.captchaAPI) { 25 return; 26 } 27 28 if (arFailedForms.has(obForm)) { 29 return; 30 } 31 32 // ÐÑли API еÑÑ Ð½Ðµ загÑÑжен, оÑкладÑваем иниÑиализаÑÐ¸Ñ 33 if (typeof window.smartCaptcha === 'undefined') { 34 // ÐÑовеÑÑем, не добавлена ли ÑоÑма Ñже 35 if (!arPendingForms.includes(obForm)) { 36 arPendingForms.push(obForm); 37 } 38 startApiWatcher(); 39 return; 40 } 41 42 const sCaptchaId = obForm.id || 'form-' + Math.random().toString(36).substr(2, 9); 43 44 // ÐÑопÑÑкаем, еÑли Ñже иниÑиализиÑована 45 if (arCaptchaInstances.has(sCaptchaId)) { 46 return; 47 } 48 49 const obCaptchaContainer = obForm.querySelector('.smart-captcha'); 50 51 if (!obCaptchaContainer) { 52 console.warn('[Captcha] ÐонÑÐµÐ¹Ð½ÐµÑ .smart-captcha не найден в ÑоÑме', obForm); 53 return; 54 } 55 56 let bCaptchaExecuted = false; 57 let sCurrentToken = ''; 58 let nWidgetId = null; 59 let fnPendingSubmit = null; 60 61 // СоздаÑм Ð²Ð¸Ð´Ð¶ÐµÑ ÐºÐ°Ð¿Ñи 62 try { nWidgetId = window.smartCaptcha.render(obCaptchaContainer, { 63 sitekey: obCaptchaContainer.getAttribute('data-sitekey'), 64 invisible: true, 65 shieldPosition: `bottom-left`, 66 hideShield: true, 67 callback: function (sToken) { 68 bCaptchaExecuted = true; 69 sCurrentToken = sToken; 70 71 // ÐобавлÑем ÑкÑÑÑое поле Ñ Ñокеном 72 let obTokenInput = obForm.querySelector('input[name="smart-token"]'); 73 if (!obTokenInput) { 74 obTokenInput = document.createElement('input'); 75 obTokenInput.type = 'hidden'; 76 obTokenInput.name = 'smart-token'; 77 obForm.appendChild(obTokenInput); 78 } 79 obTokenInput.value = sToken; 80 81 // ÐенеÑиÑÑем ÑобÑÑие 82 obForm.dispatchEvent(new CustomEvent('captchaSuccess', { 83 detail: { token: sToken, formId: sCaptchaId } 84 })); 85 86 // ÐÑполнÑем оÑложеннÑÑ Ð¾ÑпÑавкÑ, еÑли еÑÑÑ 87 if (fnPendingSubmit) { 88 fnPendingSubmit(); 89 fnPendingSubmit = null; 90 } 91 }, 92 'expired-callback': function () { 93 bCaptchaExecuted = false; 94 sCurrentToken = ''; 95 const obTokenInput = obForm.querySelector('input[name="smart-token"]'); 96 if (obTokenInput) { 97 obTokenInput.value = ''; 98 } 99 } 100 }); } catch (e) { 101 console.error('[Captcha] ÐÑибка render() Ð´Ð»Ñ ÑоÑмÑ:', sCaptchaId, e); 102 arFailedForms.add(obForm); 103 return; 104 } 105 106 // Ð¡Ð¾Ñ ÑанÑем API 107 const obCaptchaAPI = { 108 form: obForm, 109 container: obCaptchaContainer, 110 widgetId: nWidgetId, 111 isExecuted: function () { return bCaptchaExecuted; }, 112 getToken: function () { return sCurrentToken; }, 113 reset: function () { 114 bCaptchaExecuted = false;
115 sCurrentToken = ''; 116 fnPendingSubmit = null; 117 const obTokenInput = obForm.querySelector('input[name="smart-token"]'); 118 if (obTokenInput) { 119 obTokenInput.value = ''; 120 } 121 try { 122 if (nWidgetId !== null) { 123 window.smartCaptcha.reset(nWidgetId); 124 } 125 } catch (e) { 126 console.warn('[Captcha] ÐÑибка reset():', e); 127 } 128 }, 129 execute: function (fnCallback) { 130 if (fnCallback) { 131 fnPendingSubmit = fnCallback; 132 } 133 try { 134 window.smartCaptcha.execute(nWidgetId); 135 } catch (e) { 136 console.error('[Captcha] ÐÑибка execute() Ð´Ð»Ñ ÑоÑмÑ:', sCaptchaId, e); 137 fnPendingSubmit = null; 138 if (fnCallback) fnCallback(null); 139 } 140 } 141 }; 142 143 arCaptchaInstances.set(sCaptchaId, obCaptchaAPI); 144 obForm.captchaAPI = obCaptchaAPI; 145 } 146 147 /** 148 * ÐниÑиализаÑÐ¸Ñ Ð²ÑÐµÑ ÑоÑм Ñ ÐºÐ°Ð¿Ñей 149 */ 150 function initAllCaptchaForms() { 151 const arForms = document.querySelectorAll('form[data-captcha="true"]'); 152 arForms.forEach(initCaptchaForForm); 153 } 154 155 /** 156 * ÐбÑабоÑка оÑложеннÑÑ ÑоÑм поÑле загÑÑзки API 157 */ 158 function processPendingForms() { 159 if (arPendingForms.length > 0) { 160 const formsToInit = [...arPendingForms]; // ÐопиÑÑем маÑÑив 161 arPendingForms = []; // ÐÑиÑаем оÑеÑÐµÐ´Ñ 162 formsToInit.forEach(initCaptchaForForm); 163 } 164 } 165 166 /** 167 * Ðжидание загÑÑзки API ЯндекÑа. ÐапÑÑкаеÑÑÑ ÑолÑко когда еÑÑÑ Ð¾ÑложеннÑе ÑоÑмÑ, 168 * Ñо еÑÑÑ Ð¿Ð¾Ð»ÑзоваÑÐµÐ»Ñ Ñже наÑал взаимодейÑÑвие, а captcha.js еÑÑ Ð½Ðµ догÑÑзилÑÑ. 169 */ 170 function startApiWatcher() { 171 if (nCheckInterval !== null) { 172 return; 173 } 174 175 nCheckInterval = setInterval(function () { 176 if (typeof window.smartCaptcha !== 'undefined') { 177 stopApiWatcher(); 178 179 // ÐбÑабаÑÑваем ТÐÐЬÐРоÑложеннÑе ÑоÑмÑ, не вÑе заново 180 processPendingForms(); 181 } 182 }, 100); 183 184 // ÐÑиÑаем инÑеÑвал ÑеÑез 10 ÑекÑнд 185 setTimeout(function () { 186 if (nCheckInterval !== null) { 187 stopApiWatcher(); 188 if (arPendingForms.length > 0) { 189 console.error('[Captcha] API не загÑÑзилÑÑ Ð·Ð° 10 ÑекÑнд'); 190 } 191 } 192 }, 10000); 193 } 194 195 function stopApiWatcher() { 196 clearInterval(nCheckInterval); 197 nCheckInterval = null; 198 } 199 200 /** 201 * ÐеÑвое взаимодейÑÑвие Ñ ÑоÑмой â Ð¼Ð¾Ð¼ÐµÐ½Ñ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ð²Ð¸Ð´Ð¶ÐµÑа 202 * @param {Event} obEvent 203 */ 204 function onFormInteraction(obEvent) { 205 const obTarget = obEvent.target; 206 207 if (!obTarget || typeof obTarget.closest !== 'function') { 208 return; 209 } 210 211 const obForm = obTarget.closest('form[data-captcha="true"]'); 212 213 if (obForm) { 214 initCaptchaForForm(obForm); 215 } 216 } 217 218 document.addEventListener('focusin', onFormInteraction, true); 219 document.addEventListener('pointerdown', onFormInteraction, true); 220 document.addEventListener('click', onFormInteraction, true); 221 document.addEventListener('submit', onFormInteraction, true); 222 223 // ÐлобалÑнÑй API 224 window.YandexCaptchaAPI = { 225 getFormCaptcha: function (formIdOrElement) { 226 const sFormId = typeof formIdOrElement === 'string' 227 ? formIdOrElement 228 : formIdOrElement.id; 229 return arCaptchaInstances.get(sFormId) || null; 230 }, 231 initForm: initCaptchaForForm, 232 reinitAll: initAllCaptchaForms, 233 // ÐÐ»Ñ Ð¾Ñладки 234 debug: { 235 getInstances: () => arCaptchaInstances, 236 getPending: () => arPendingForms 237 } 238 }; 239})();
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.