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 amiSailthruReCaptcha ) {
grecaptcha.enterprise.ready( async () => {
let token = await grecaptcha.enterprise.execute( amiSailthruReCaptcha.site_key, { action: action } );
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));
}
} );