1/** 2 * reCAPTCHA v3 helper â exposes window.smpGetRecaptchaToken(action). 3 */ 4(function (window) { 5 "use strict"; 6 7 function loadApi() { 8 return new Promise(function (resolve, reject) { 9 if (window.grecaptcha && typeof window.grecaptcha.execute === "function") { 10 window.grecaptcha.ready(function () { 11 resolve(window.grecaptcha); 12 }); 13 return; 14 } 15 var attempts = 0; 16 var timer = setInterval(function () { 17 attempts += 1; 18 if (window.grecaptcha && typeof window.grecaptcha.execute === "function") { 19 clearInterval(timer); 20 window.grecaptcha.ready(function () { 21 resolve(window.grecaptcha); 22 }); 23 } else if (attempts > 50) { 24 clearInterval(timer); 25 reject(new Error("reCAPTCHA failed to load")); 26 } 27 }, 100); 28 }); 29 } 30 31 /** 32 * @param {string} action reCAPTCHA action name 33 * @returns {Promise<string>} 34 */ 35 window.smpGetRecaptchaToken = function (action) { 36 var cfg = window.smpRecaptchaV3 || {}; 37 var siteKey = cfg.siteKey; 38 if (!siteKey) { 39 return Promise.reject(new Error("Missing reCAPTCHA site key")); 40 } 41 return loadApi().then(function (grecaptcha) { 42 return grecaptcha.execute(siteKey, { action: action || "form" }); 43 }); 44 }; 45 46 /** 47 * Ensure a hidden g-recaptcha-response input exists and holds the token. 48 * 49 * @param {HTMLFormElement|JQuery} form 50 * @param {string} token 51 */ 52 window.smpSetRecaptchaTokenOnForm = function (form, token) { 53 var el = form && form.jquery ? form[0] : form; 54 if (!el) { 55 return; 56 } 57 var input = el.querySelector('input[name="g-recaptcha-response"]'); 58 if (!input) { 59 input = document.createElement("input"); 60 input.type = "hidden"; 61 input.name = "g-recaptcha-response"; 62 el.appendChild(input); 63 } 64 input.value = token; 65 }; 66 67 /** 68 * Fallback for directory blocks when smp-form view.js is not on the page. 69 * Overridden by smp-form when present (richer validation). 70 */ 71 if (typeof window.submit_form_with_ajax !== "function") { 72 window.submit_form_with_ajax = function ( 73 selector, 74 successCallback, 75 errorCallback, 76 beforeEverythingCallback 77 ) { 78 var $ = window.jQuery; 79 if (!$) { 80 return; 81 } 82 document.querySelectorAll(selector).forEach(function (formEl) { 83 $(formEl) 84 .off("submit.smpTunobRecaptcha") 85 .on("submit.smpTunobRecaptcha", function (e) { 86 e.preventDefault(); 87 if ( 88 typeof beforeEverythingCallback === "function" && 89 beforeEverythingCallback() === false 90 ) { 91 return; 92 } 93 var run = function () { 94 $.ajax({ 95 url: $(formEl).attr("data-url"), 96 type: $(formEl).attr("data-method") || "POST", 97 data: $(formEl).serialize(), 98 success: function (response) { 99 if (typeof successCallback === "function") { 100 successCallback( 101 $(formEl).attr("data-success-message"), 102 { data: $(formEl).serialize() }, 103 response 104 ); 105 } 106 }, 107 error: function (xhr) { 108 if (typeof errorCallback === "function") { 109 errorCallback(xhr); 110 } 111 }, 112 }); 113 }; 114 var action = formEl.getAttribute("data-recaptcha-action"); 115 if (action && typeof window.smpGetRecaptchaToken === "function") { 116 window 117 .smpGetRecaptchaToken(action) 118 .then(function (token) { 119 window.smpSetRecaptchaTokenOnForm(formEl, token); 120 run(); 121 }) 122 .catch(function () { 123 if (typeof errorCallback === "function") { 124 errorCallback({ status: 400 }); 125 } 126 }); 127 } else { 128 run(); 129 } 130 }); 131 }); 132 }; 133 } 134})(window);
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.