1/** 2 * Revocation button widget frontend handler. 3 */ 4var FRMRevocationButtonHandler = function ($scope, $) { 5 var readyClass = 'frymo-revocation-button-js-ready'; 6 var isEditor = $('body').hasClass('elementor-editor-active'); 7 var modalWasOpen = $scope.data('frymo-revocation-modal-open') === true; 8 var $modal = $scope.find('.frymo-revocation-form-modal'); 9 var $button = $scope.find('.frymo-show-revocation-form'); 10 var $form = $scope.find('form.frymo-revocation-form'); 11 var isPopup = $modal.data('display') !== 'inline'; 12 13 if ($scope.hasClass(readyClass)) { 14 if (!isEditor) { 15 return; 16 } 17 18 $button.off('click'); 19 $form.off('submit'); 20 $scope.off('.frymoRevocationCaptcha'); 21 $modal.off('.revocationModal'); 22 $modal.find('.frymo-contact-form-wrapper').off('.revocationModal'); 23 $modal.find('.frymo-contact-form-close').off('.revocationModal'); 24 } 25 26 $scope.addClass(readyClass); 27 28 if (isPopup) { 29 $button.on('click', function (e) { 30 e.preventDefault(); 31 e.stopPropagation(); 32 showModal(); 33 }); 34 } 35 36 function moveModalToBody() { 37 if (!isPopup || !$modal.length || $modal.parent().is('body')) { 38 return; 39 } 40 41 $modal.appendTo(document.body); 42 } 43 44 function showModal() { 45 if (!isPopup) { 46 return; 47 } 48 49 $scope.data('frymo-revocation-modal-open', true); 50 moveModalToBody(); 51 $modal.css({ display: 'flex' }); 52 53 $modal.find('.frymo-contact-form-wrapper').off('.revocationModal').on('click.revocationModal', function (e) { 54 e.stopPropagation(); 55 }); 56 57 $modal.off('.revocationModal').on('click.revocationModal', function (e) { 58 e.stopPropagation(); 59 hideModal(); 60 }); 61 62 $modal.find('.frymo-contact-form-close').off('.revocationModal').on('click.revocationModal', function (e) { 63 e.stopPropagation(); 64 hideModal(); 65 }); 66 } 67 68 function hideModal() { 69 if (!isPopup) { 70 return; 71 } 72 73 $scope.data('frymo-revocation-modal-open', false); 74 $modal.off('.revocationModal'); 75 $modal.find('.frymo-contact-form-wrapper').off('.revocationModal'); 76 $modal.find('.frymo-contact-form-close').off('.revocationModal'); 77 $modal.css({ display: 'none' }); 78 } 79 80 function submitRevocationForm() { 81 $form.addClass('frymo-loading'); 82 $form.find('.frymo-form-field.error').removeClass('error'); 83 $form.find('.field-error-message').text(''); 84 $form.find('.form-messages').empty(); 85 86 var form_fields = {}; 87 $.each($form.serializeArray(), function (index, item) { 88 var $fieldWrap = $form.find('[name="' + item.name + '"]').closest('.frymo-form-field'); 89 if (!$fieldWrap.length) { 90 return; 91 } 92 93 if (form_fields[item.name]) { 94 form_fields[item.name].value += '\n' + item.value; 95 return; 96 } 97 form_fields[item.name] = { 98 value: item.value, 99 type: $fieldWrap.data('type') || '', 100 required: $fieldWrap.data('required') || '' 101 }; 102 }); 103 104 var data = new FormData(); 105 data.append('action', 'frymo_revocation_submit'); 106 107 var nonce = $form.find('[name="frymo_revocation_nonce"]').val(); 108 if (nonce) { 109 data.append('frymo_revocation_nonce', nonce); 110 } 111 112 $.each(['object_post_id', 'template_id', 'element_id', 'page_url'], function (i, hiddenName) { 113 var val = $form.find('[name="' + hiddenName + '"]').val(); 114 if (val) { 115 data.append(hiddenName, val); 116 } 117 }); 118 119 $.each(form_fields, function (fieldName, fieldData) { 120 data.append('form_fields[' + fieldName + '][value]', fieldData.value); 121 data.append('form_fields[' + fieldName + '][type]', fieldData.type || ''); 122 data.append('form_fields[' + fieldName + '][required]', fieldData.required || ''); 123 }); 124 125 if (typeof frymo === 'undefined' || !frymo || !frymo.ajaxurl) { 126 $form.find('.form-messages').append('<div class="error">Form cannot be submitted. Please refresh the page.</div>'); 127 $form.removeClass('frymo-loading'); 128 return; 129 } 130 131 $.ajax({ 132 url: frymo.ajaxurl, 133 method: 'POST', 134 data: data, 135 processData: false, 136 contentType: false 137 }) 138 .always(function () { 139 $form.removeClass('frymo-loading'); 140 }) 141 .fail(function () { 142 $form.find('.form-messages').append('<div class="error">Server error</div>'); 143 }) 144 .done(function (response) { 145 if (!response || typeof response.data !== 'object') { 146 $form.find('.form-messages').append('<div class="error">Invalid response. Please try again.</div>'); 147 return; 148 } 149 150 var messages = response.data.messages || []; 151 $.each(messages, function (index, item) { 152 $form.find('.form-messages').append('<div class="' + item.type + '">' + item.text + '</div>'); 153 if (item.field) { 154 var $field = $form.find('[name="' + item.field + '"]').closest('.frymo-form-field'); 155 $field.addClass('error'); 156 $field.find('.field-error-message').text(item.text); 157 } else if (item.type === 'error' && item.text) { 158 var $mathCaptcha = $form.find('.frymo-math-captcha'); 159 if ($mathCaptcha.length && window.frymoIsCaptchaErrorMessage(item.text)) { 160 $mathCaptcha.addClass('error').find('.field-error-message').text(item.text); 161 regenerateCaptcha($mathCaptcha); 162 } 163 $form.find('.frymo-altcha, .frymo-friendlycaptcha, .frymo-recaptcha-v3').addClass('error').find('.field-error-message').text(item.text); 164 } 165 }); 166 167 if (response.success === true) { 168 $form.addClass('is-success-hide'); 169 $form.find('.frymo-contact-form-submission-content').attr('aria-hidden', 'true').stop(true, true).slide
169Up(250); 170 } 171 }); 172 } 173 174 function regenerateCaptcha($captchaField) { 175 if (isEditor) { 176 return; 177 } 178 179 var $input = $captchaField.find('.frymo-captcha-input'); 180 var $question = $captchaField.find('.frymo-captcha-question'); 181 var $hiddenId = $captchaField.find('input[name="frymo_captcha_id"]'); 182 var $errorMessage = $captchaField.find('.field-error-message'); 183 184 $input.val(''); 185 $errorMessage.text(''); 186 $captchaField.removeClass('error'); 187 $question.text('...'); 188 189 var ajaxUrl = (typeof frymo !== 'undefined' && frymo && frymo.ajaxurl) ? frymo.ajaxurl : ''; 190 if (!ajaxUrl) { 191 $question.text(window.frymoCaptchaString('loadError')); 192 return; 193 } 194 195 $.post(ajaxUrl, { action: 'frymo_regenerate_captcha' }, function (response) { 196 if (response && response.success && response.data && response.data.question !== undefined && response.data.captcha_id !== undefined) { 197 $question.text(response.data.question); 198 $hiddenId.val(response.data.captcha_id); 199 } else { 200 $question.text(window.frymoCaptchaString('loadError')); 201 } 202 }).fail(function () { 203 $question.text(window.frymoCaptchaString('loadError')); 204 }); 205 } 206 207 function initMathCaptcha() { 208 var $captchaFields = $scope.find('.frymo-math-captcha'); 209 if (!$captchaFields.length) { 210 return; 211 } 212 213 if (!isEditor) { 214 $captchaFields.each(function () { 215 regenerateCaptcha($(this)); 216 }); 217 } 218 219 $scope.off('click.frymoRevocationCaptcha', '.frymo-captcha-refresh'); 220 $scope.on('click.frymoRevocationCaptcha', '.frymo-captcha-refresh', function (e) { 221 e.preventDefault(); 222 regenerateCaptcha($(this).closest('.frymo-math-captcha')); 223 }); 224 } 225 226 function initAltcha() { 227 if (isEditor) { 228 return; 229 } 230 231 $scope.find('.frymo-altcha').each(function () { 232 var $wrapper = $(this); 233 var widgetEl = $wrapper[0].querySelector('altcha-widget'); 234 if (!widgetEl) { 235 return; 236 } 237 238 var $tokenInput = $wrapper.find('.altcha-token-input'); 239 240 widgetEl.addEventListener('statechange', function (ev) { 241 if (ev.detail && ev.detail.state === 'verified' && ev.detail.payload) { 242 $tokenInput.val(ev.detail.payload); 243 $wrapper.removeClass('error').find('.field-error-message').text(''); 244 } else if (ev.detail && ev.detail.state === 'error') { 245 $wrapper.addClass('error'); 246 $wrapper.find('.field-error-message').text(window.frymoCaptchaString('verificationFailed')); 247 } else if (ev.detail && ev.detail.state === 'expired') { 248 $tokenInput.val(''); 249 $wrapper.addClass('error'); 250 $wrapper.find('.field-error-message').text(window.frymoCaptchaString('verificationExpired')); 251 } 252 }); 253 254 widgetEl.addEventListener('verified', function (ev) { 255 if (ev.detail && ev.detail.payload) { 256 $tokenInput.val(ev.detail.payload); 257 $wrapper.removeClass('error').find('.field-error-message').text(''); 258 } 259 }); 260 }); 261 } 262 263 function initFriendlyCaptcha() { 264 if (isEditor) { 265 return; 266 } 267 268 $scope.find('.frymo-friendlycaptcha .frc-captcha[data-sitekey]').each(function () { 269 var $widget = $(this); 270 var $tokenInput = $widget.closest('.frymo-friendlycaptcha').find('.frc-captcha-response-input'); 271 272 $widget[0].addEventListener('frc:widget.complete', function (event) { 273 if (event.detail && event.detail.response) { 274 $tokenInput.val(event.detail.response); 275 $widget.closest('.frymo-friendlycaptcha').removeClass('error').find('.field-error-message').text(''); 276 } 277 }); 278 279 $widget[0].addEventListener('frc:widget.error', function () { 280 $widget.closest('.frymo-friendlycaptcha').addClass('error'); 281 }); 282 283 $widget[0].addEventListener('frc:widget.expire', function () { 284 $tokenInput.val(''); 285 $widget.closest('.frymo-friendlycaptcha').find('.field-error-message').text(window.frymoCaptchaString('verificationExpired')); 286 }); 287 }); 288 } 289 290 function validateCaptchaBeforeSubmit() { 291 $form.find('.frymo-math-captcha, .frymo-altcha, .frymo-friendlycaptcha, .frymo-recaptcha-v3').removeClass('error').find('.field-error-message').text(''); 292 293 var $recaptchaV3 = $form.find('.frymo-recaptcha-v3'); 294 var $tokenInput = $recaptchaV3.find('.recaptcha-v3-token-input[data-site-key]'); 295 var needsRecaptchaToken = $tokenInput.length && (!$tokenInput.val() || $tokenInput.val() === 'demo_recaptcha_v3_token'); 296 297 if (needsRecaptchaToken) { 298 if (typeof grecaptcha === 'undefined') { 299 $recaptchaV3.addClass('error').find('.field-error-message').text(window.frymoCaptchaString('recaptchaNotLoaded')); 300 return false;
301 } 302 303 var siteKey = $tokenInput.data('site-key'); 304 grecaptcha.ready(function () { 305 grecaptcha.execute(siteKey, { action: 'submit' }).then(function (token) { 306 $tokenInput.val(token); 307 submitRevocationForm(); 308 }, function () { 309 $recaptchaV3.addClass('error').find('.field-error-message').text(window.frymoCaptchaString('verificationFailed')); 310 }); 311 }); 312 return 'pending'; 313 } 314 315 var $altcha = $form.find('.frymo-altcha'); 316 if ($altcha.length) { 317 var altchaToken = $altcha.find('.altcha-token-input').val(); 318 if (!altchaToken || altchaToken === 'demo_altcha_token') { 319 $altcha.addClass('error').find('.field-error-message').text(window.frymoCaptchaString('waitForVerification')); 320 return false; 321 } 322 } 323 324 var $frc = $form.find('.frymo-friendlycaptcha .frc-captcha[data-sitekey]'); 325 if ($frc.length) { 326 var frcToken = $frc.closest('.frymo-friendlycaptcha').find('.frc-captcha-response-input').val(); 327 if (!frcToken || frcToken === 'demo_frc_token') { 328 $frc.closest('.frymo-friendlycaptcha').addClass('error').find('.field-error-message').text(window.frymoCaptchaString('waitForVerification')); 329 return false; 330 } 331 } 332 333 var $mathCaptcha = $form.find('.frymo-math-captcha'); 334 if ($mathCaptcha.length) { 335 var mathAnswer = $mathCaptcha.find('.frymo-captcha-input').val(); 336 if (!mathAnswer || mathAnswer.trim() === '') { 337 $mathCaptcha.addClass('error').find('.field-error-message').text(window.frymoCaptchaString('solveMathProblem')); 338 return false; 339 } 340 } 341 342 return true; 343 } 344 345 $form.on('submit', function (e) { 346 if (isEditor) { 347 return false; 348 } 349 e.preventDefault(); 350 e.stopPropagation(); 351 352 var captchaResult = validateCaptchaBeforeSubmit(); 353 if (captchaResult === false || captchaResult === 'pending') { 354 return false; 355 } 356 357 submitRevocationForm(); 358 return false; 359 }); 360 361 setTimeout(function () { 362 initMathCaptcha(); 363 initAltcha(); 364 initFriendlyCaptcha(); 365 }, 200); 366 367 if (isEditor) { 368 var elementId = $scope.attr('data-id'); 369 var editorEventNamespace = '.frymoRevocation' + elementId; 370 var modalEditorSections = ['section_settings', 'section_modal_styles']; 371 var messageEditorSections = ['section_messages', 'messages_styles']; 372 373 function shouldKeepModalOpen(sectionName) { 374 return isPopup && (modalWasOpen || (sectionName && (modalEditorSections.indexOf(sectionName) !== -1 || messageEditorSections.indexOf(sectionName) !== -1))); 375 } 376 377 function updateEditorMessagesPreview(sectionName) { 378 var shouldShowMessages = sectionName && messageEditorSections.indexOf(sectionName) !== -1; 379 $form.toggleClass('editor-show-messages', !!shouldShowMessages); 380 } 381 382 var activeSection = elementor.getPanelView().getCurrentPageView().activeSection; 383 updateEditorMessagesPreview(activeSection); 384 if (shouldKeepModalOpen(activeSection)) { 385 showModal(); 386 } 387 388 elementor.channels.editor.off('section:activated' + editorEventNamespace); 389 elementor.channels.editor.on('section:activated' + editorEventNamespace, function (sectionName, editor) { 390 var editedElement = editor.getOption('editedElementView'); 391 if (!editedElement || String(editedElement.model.get('id')) !== String(elementId)) { 392 return; 393 } 394 updateEditorMessagesPreview(sectionName); 395 if (shouldKeepModalOpen(sectionName)) { 396 showModal(); 397 } 398 }); 399 } else if (modalWasOpen) { 400 showModal(); 401 } 402}; 403 404(function ($) { 405 var widgetSelectors = '.elementor-widget-frymo-revocation-button'; 406 407 function bootRevocationButtons($root) { 408 $root.find(widgetSelectors).each(function () { 409 FRMRevocationButtonHandler($(this), $); 410 }); 411 } 412 413 $(window).on('elementor/frontend/init', function () { 414 elementorFrontend.hooks.addAction('frontend/element_ready/frymo-revocation-button.default', FRMRevocationButtonHandler); 415 }); 416 417 $(function () { 418 bootRevocationButtons($(document)); 419 setTimeout(function () { 420 bootRevocationButtons($(document)); 421 }, 500); 422 }); 423})(jQuery);
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.