diff --git a/src/other-scripts/recaptcha/index.js b/src/other-scripts/recaptcha/index.js index 037228d729..bbf22871cf 100644 --- a/src/other-scripts/recaptcha/index.js +++ b/src/other-scripts/recaptcha/index.js @@ -80,6 +80,39 @@ function addHiddenField( form ) { } } +/** + * Append a generic error message above the given form. + * + * @param {HTMLElement} form The form element. + * @param {string} message The error message to display. + */ +function addErrorMessage( form, message ) { + const errorText = document.createElement( 'p' ); + errorText.textContent = message; + const container = document.createElement( 'div' ); + container.classList.add( 'newspack-recaptcha-error' ); + container.appendChild( errorText ); + // Newsletters block errors render below the form. + if ( form.parentElement.classList.contains( 'newspack-newsletters-subscribe' ) ) { + form.append( container ); + } else { + container.classList.add( 'newspack-ui__notice', 'newspack-ui__notice--error' ); + form.insertBefore( container, form.firstChild ); + } +} + +/** + * Remove generic error messages from form if present. + * + * @param {HTMLElement} form The form element. + */ +function removeErrorMessages( form ) { + const errors = form.querySelectorAll( '.newspack-recaptcha-error' ); + for ( const error of errors ) { + error.parentElement.removeChild( error ); + } +} + /** * Remove the hidden reCAPTCHA v3 token field from the given form. * @@ -147,6 +180,14 @@ function renderWidget( form, onSuccess = null, onError = null ) { refreshWidget( button ); }; + const errorCallback = ( message ) => { + if ( onError ) { + onError( message ); + } else { + addErrorMessage( form, message ); + } + } + // Render reCAPTCHA widget. See https://developers.google.com/recaptcha/docs/invisible#js_api for API reference. const widgetId = grecaptcha.render( button, { ...options, @@ -158,17 +199,12 @@ function renderWidget( form, onSuccess = null, onError = null ) { refreshWidget( button ); } else { clearInterval( refreshIntervalId ); + button.disabled = true; } const message = retryCount < 3 ? wp.i18n.__( 'There was an error with reCAPTCHA. Please try again.', 'newspack-plugin' ) : wp.i18n.__( 'There was an error with reCAPTCHA. Please reload the page and try again.', 'newspack-plugin' ); - if ( onError ) { - onError( message ); - } else { - // Recaptcha's default error behavior is to alert with the above message. - // eslint-disable-next-line no-alert - alert( message ); - } + errorCallback( message ); }, } ); @@ -177,6 +213,8 @@ function renderWidget( form, onSuccess = null, onError = null ) { button.addEventListener( 'click', e => { e.preventDefault(); + // Empty error messages if present. + removeErrorMessages( form ); // Skip reCAPTCHA verification if the button has a data-skip-recaptcha attribute. if ( button.hasAttribute( 'data-skip-recaptcha' ) ) { successCallback(); diff --git a/src/other-scripts/recaptcha/style.scss b/src/other-scripts/recaptcha/style.scss index 52fdd4451e..b6bfb43f17 100644 --- a/src/other-scripts/recaptcha/style.scss +++ b/src/other-scripts/recaptcha/style.scss @@ -13,3 +13,9 @@ inset: 0 !important; // Prevents an odd side-scroll issue in the registration modal & block. visibility: hidden !important; } + +.newspack-recaptcha-error { + &.newspack-ui__notice--error { + margin-top: 0 !important; + } +}