jQuery( document ).ready( function( $ ) { let form = $( '.sailthru-contact-form' ); if( form.length ) { $( form ).on( 'submit', function ( e ) { e.preventDefault(); let form = $( e.target ), action = $( e.target ).find( 'input[name="action"]' ).val() || 'contact'; // Validate form on front-end if ( !validateForm( e.target )) { return; } if ( 'undefined' !== typeof amiSailthruContact.recaptcha ) { if ( !window.amiSailthruReCaptchaInit ) { window.amiSailthruReCaptchaInit = true; let recaptcha_script = document.createElement( 'script' ); recaptcha_script.id = 'sailthru-recaptcha'; recaptcha_script.src = amiSailthruContact.recaptcha.script_src; recaptcha_script.async = true; recaptcha_script.onload = function () { grecaptcha.enterprise.ready( function () { grecaptcha.enterprise.execute( amiSailthruContact.recaptcha.site_key, { action: action } ).then( function ( token ) { submit_form( form, token ); } ); } ); }; document.body.appendChild( recaptcha_script ); } else { grecaptcha.enterprise.ready( function () { grecaptcha.enterprise.execute( amiSailthruContact.recaptcha.site_key, { action: action } ).then( function ( token ) { submit_form( form, token ); } ); } ); } } else { submit_form( form ); } } ); } /** * Submits a form via AJAX request * * @param {Object} form - The form element or selector * @param {boolean} [token=false] - The token to add to the form data * * @return {void} */ function submit_form( form, token = false ) { let submit_form = $( form ), submit = $( submit_form ).find( '.contact-submit' ), messaging = $( submit_form ).parent().find( '.contact__messaging' ), success = $( submit_form ).parent().find( '.contact__success' ), success_message = $( success ).find( '.contact-success' ); $( submit ).prop( 'disabled', true ); $( messaging ).text( amiSailthruContact.messages.process ).removeClass( 'error' ); $( submit_form ).find( 'input.error' ).removeClass( 'error' ).attr('aria-invalid', 'false'); let prepare_form_data = $( submit_form ).serializeArray(), form_data = {}; $.map( prepare_form_data, function( n, i ){ form_data[ n['name'] ] = n['value']; } ); // add token if( token ) { form_data['token'] = token; } $.ajax( { url: amiSailthruContact.endpoint, type: 'POST', data: form_data, dataType: 'json', success: function ( response ) { if( response.success ) { $( submit_form ).hide(); $( messaging ).hide(); $( success ).show() if ( success_message.length ) { success_message.scrollIntoView( { behavior: 'smooth', block: 'center' } ); } } else { $( submit ).prop( 'disabled', false ); $( messaging ).text( amiSailthruContact.messages.default_error ).addClass( 'error' ); } }, error: function( error ) { $( submit ).prop( 'disabled', false ); let errors_data = error.responseJSON; if( 'rest_invalid_param' === errors_data.code || 'rest_missing_callback_param' === errors_data.code ) { let invalid_param = 'rest_invalid_param' === errors_data.code ? Object.keys( errors_data.data.params )[0] : errors_data.data.params[0]; $( messaging ).text( amiSailthruContact.messages[ 'invalid_' + invalid_param ] ).addClass( 'error' ); $( submit_form ).find( 'input[name="' + invalid_param + '"]' ).addClass( 'error' ).attr('aria-invalid', 'true'); } else { $( messaging ).text( amiSailthruContact.messages.default_error ).addClass( 'error' ); } } } ); } /** * Form field validation * * @param field * @returns {boolean} */ function validateField( field ) { let isValid = true; const fieldType = field.type; if ( ( fieldType === 'text' ) || ( fieldType === 'textarea' ) ) { if ( field.value.trim() === '' ) { isValid = false; } } else if ( fieldType === 'email' ) { const emailPattern = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/; if ( !emailPattern.test( field.value ) ) { isValid = false; } } return isValid; } /** * Front-end form validation */ function validateForm( form ) { const messaging = form.parentNode.querySelector( '.contact__messaging' ); let formIsValid = true; let errorMessages = ''; messaging.classList.remove( 'error' ); messaging.innerHTML = ''; form.querySelectorAll( '[aria-required="true"]' ).forEach(field => { if ( validateField( field ) ) { field.classList.remove( 'error' ); field.setAttribute( 'aria-invalid', 'false' ); } else { formIsValid = false; field.classList.add( 'error' ); field.setAttribute( 'aria-invalid', 'true' ); const nextEl = field.nextElementSibling; errorMessages += nextEl?.classList?.contains( 'error-message' ) ? nextEl.textContent + '
' : amiSailthruContact.messages['invalid_field'] + ` ${field?.name}.
`; } }); if ( !formIsValid ) { displayFormMessage().then( () => { messaging.classList.add( 'error' ); messaging.innerHTML = errorMessages; } ); } return formIsValid; } // Display form message with a delay (needed for screen readers) function displayFormMessage() { return new Promise( resolve => setTimeout( resolve, 50 ) ); } } );