diff --git a/ReCaptchaFrontendUi/view/frontend/web/js/nonInlineReCaptchaRenderer.js b/ReCaptchaFrontendUi/view/frontend/web/js/nonInlineReCaptchaRenderer.js new file mode 100644 index 00000000..ab622f45 --- /dev/null +++ b/ReCaptchaFrontendUi/view/frontend/web/js/nonInlineReCaptchaRenderer.js @@ -0,0 +1,56 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +/* global grecaptcha */ +define([ + 'jquery' +], function ($) { + 'use strict'; + + var reCaptchaEntities = [], + initialized = false, + rendererRecaptchaId = 'recaptcha-invisible', + rendererReCaptcha = null; + + return { + /** + * Add reCaptcha entity to checklist. + * + * @param {jQuery} reCaptchaEntity + * @param {Object} parameters + */ + add: function (reCaptchaEntity, parameters) { + if (!initialized) { + this.init(); + grecaptcha.render(rendererRecaptchaId, parameters); + setInterval(this.resolveVisibility, 100); + initialized = true; + } + + reCaptchaEntities.push(reCaptchaEntity); + }, + + /** + * Show additional reCaptcha instance if any other should be visible, otherwise hide it. + */ + resolveVisibility: function () { + reCaptchaEntities.some(function (entity) { + return entity.is(':visible') && + // 900 is some magic z-index value of modal popups. + (entity.closest('[data-role=\'modal\']').length === 0 || entity.zIndex() > 900); + }) ? rendererReCaptcha.show() : rendererReCaptcha.hide(); + }, + + /** + * Initialize additional reCaptcha instance. + */ + init: function () { + rendererReCaptcha = $('
', { + 'id': rendererRecaptchaId + }); + $('body').append(rendererReCaptcha); + } + }; +}); diff --git a/ReCaptchaFrontendUi/view/frontend/web/js/reCaptcha.js b/ReCaptchaFrontendUi/view/frontend/web/js/reCaptcha.js index 63688881..ddd627f2 100644 --- a/ReCaptchaFrontendUi/view/frontend/web/js/reCaptcha.js +++ b/ReCaptchaFrontendUi/view/frontend/web/js/reCaptcha.js @@ -3,17 +3,17 @@ * See COPYING.txt for license details. */ -/* eslint-disable no-undef */ -// jscs:disable jsDoc +/* global grecaptcha */ define( [ 'uiComponent', 'jquery', 'ko', + 'underscore', 'Magento_ReCaptchaFrontendUi/js/registry', - 'Magento_ReCaptchaFrontendUi/js/reCaptchaScriptLoader' - ], - function (Component, $, ko, registry, reCaptchaLoader, undefined) { + 'Magento_ReCaptchaFrontendUi/js/reCaptchaScriptLoader', + 'Magento_ReCaptchaFrontendUi/js/nonInlineReCaptchaRenderer' + ], function (Component, $, ko, _, registry, reCaptchaLoader, nonInlineReCaptchaRenderer) { 'use strict'; return Component.extend({ @@ -22,8 +22,10 @@ define( template: 'Magento_ReCaptchaFrontendUi/reCaptcha', reCaptchaId: 'recaptcha' }, - _isApiRegistered: undefined, + /** + * @inheritdoc + */ initialize: function () { this._super(); this._loadApi(); @@ -75,8 +77,7 @@ define( * Initialize reCAPTCHA after first rendering */ initCaptcha: function () { - var me = this, - $parentForm, + var $parentForm, $wrapper, $reCaptcha, widgetId, @@ -102,21 +103,24 @@ define( $reCaptcha.attr('id', this.getReCaptchaId()); $parentForm = $wrapper.parents('form'); - me = this; parameters = _.extend( { 'callback': function (token) { // jscs:ignore jsDoc - me.reCaptchaCallback(token); - me.validateReCaptcha(true); - }, + this.reCaptchaCallback(token); + this.validateReCaptcha(true); + }.bind(this), 'expired-callback': function () { - me.validateReCaptcha(false); - } + this.validateReCaptcha(false); + }.bind(this) }, this.settings.rendering ); + if (parameters.size === 'invisible' && parameters.badge !== 'inline') { + nonInlineReCaptchaRenderer.add($reCaptcha, parameters); + } + // eslint-disable-next-line no-undef widgetId = grecaptcha.render(this.getReCaptchaId(), parameters); this.initParentForm($parentForm, widgetId); @@ -134,18 +138,17 @@ define( * @param {String} widgetId */ initParentForm: function (parentForm, widgetId) { - var me = this, - listeners; + var listeners; if (this.getIsInvisibleRecaptcha() && parentForm.length > 0) { parentForm.submit(function (event) { - if (!me.tokenField.value) { + if (!this.tokenField.value) { // eslint-disable-next-line no-undef grecaptcha.execute(widgetId); event.preventDefault(event); event.stopImmediatePropagation(); } - }); + }.bind(this)); // Move our (last) handler topmost. We need this to avoid submit bindings with ko. listeners = $._data(parentForm[0], 'events').submit; @@ -160,6 +163,11 @@ define( } }, + /** + * Validates reCAPTCHA + * @param {*} state + * @returns {jQuery} + */ validateReCaptcha: function (state) { if (!this.getIsInvisibleRecaptcha()) { return $(document).find('input[type=checkbox].required-captcha').prop('checked', state); @@ -170,14 +178,12 @@ define( * Render reCAPTCHA */ renderReCaptcha: function () { - var me = this; - if (window.grecaptcha && window.grecaptcha.render) { // Check if reCAPTCHA is already loaded - me.initCaptcha(); + this.initCaptcha(); } else { // Wait for reCAPTCHA to be loaded $(window).on('recaptchaapiready', function () { - me.initCaptcha(); - }); + this.initCaptcha(); + }.bind(this)); } }, @@ -189,5 +195,4 @@ define( return this.reCaptchaId; } }); - } -); + }); diff --git a/ReCaptchaNewsletter/etc/adminhtml/system.xml b/ReCaptchaNewsletter/etc/adminhtml/system.xml index f70a2969..ca0109b6 100644 --- a/ReCaptchaNewsletter/etc/adminhtml/system.xml +++ b/ReCaptchaNewsletter/etc/adminhtml/system.xml @@ -12,7 +12,7 @@ - + If enabled, a badge will be displayed in every page. Magento\ReCaptchaAdminUi\Model\OptionSource\Type diff --git a/ReCaptchaNewsletter/view/frontend/layout/default.xml b/ReCaptchaNewsletter/view/frontend/layout/default.xml index 82c684a2..992d56d7 100644 --- a/ReCaptchaNewsletter/view/frontend/layout/default.xml +++ b/ReCaptchaNewsletter/view/frontend/layout/default.xml @@ -17,13 +17,6 @@ ifconfig="recaptcha_frontend/type_for/newsletter"> newsletter - - true - - bottomright - invisible - - diff --git a/ReCaptchaNewsletter/view/frontend/web/css/source/_module.less b/ReCaptchaNewsletter/view/frontend/web/css/source/_module.less new file mode 100644 index 00000000..563319cd --- /dev/null +++ b/ReCaptchaNewsletter/view/frontend/web/css/source/_module.less @@ -0,0 +1,16 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +.block.newsletter { + .field-recaptcha { + .field { + .control { + &:before { + content: none; + } + } + } + } +}