Created
January 31, 2020 10:06
-
-
Save daveharrisonnet/acbc10b42bad3e4da746fdb5a0648828 to your computer and use it in GitHub Desktop.
Javascript used for a contact form.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
mr = (function (mr, $, window, document){ | |
"use strict"; | |
mr.forms = mr.forms || {}; | |
mr.forms.captcha = {}; | |
mr.forms.captcha.widgets = []; | |
mr.forms.captcha.done = false; | |
mr.forms.documentReady = function($){ | |
mr.forms.captcha.widgets = []; | |
/// Checkbox & Radio Inputs | |
$('.input-checkbox input[type="checkbox"], .input-radio input[type="radio"]').each(function(index){ | |
var input = $(this), | |
label = input.siblings('label'), | |
id = "input-assigned-"+index; | |
if(typeof input.attr('id') === typeof undefined || input.attr('id') === ""){ | |
input.attr('id',id); | |
label.attr('for',id); | |
}else{ | |
id = input.attr('id'); | |
label.attr('for',id); | |
} | |
}); | |
//////////////// Number Inputs | |
$('.input-number__controls > span').off('click.mr').on('click.mr',function(){ | |
var control = jQuery(this), | |
parent = control.closest('.input-number'), | |
input = parent.find('input[type="number"]'), | |
max = input.attr('max'), | |
min = input.attr('min'), | |
step = 1, | |
current = parseInt(input.val(),10); | |
if(parent.is('[data-step]')){ | |
step = parseInt(parent.attr('data-step'),10); | |
} | |
if(control.hasClass('input-number__increase')){ | |
if((current+step) <= max){ | |
input.val(current+step); | |
} | |
}else{ | |
if((current-step) >= min){ | |
input.val(current-step); | |
} | |
} | |
}); | |
//////////////// File Uploads | |
$('.input-file .btn').off('click.mr').on('click.mr',function(){ | |
$(this).siblings('input').trigger('click'); | |
return false; | |
}); | |
//////////////// Handle Form Submit | |
$('form.form-email, form[action*="list-manage.com"], form[action*="createsend.com"]').attr('novalidate', true).off('submit').on('submit', mr.forms.submit); | |
//////////////// Handle Form Submit | |
$(document).on('change, input, paste, keyup', '.attempted-submit .field-error', function(){ | |
$(this).removeClass('field-error'); | |
}); | |
//////////////// Check forms for Google reCaptcha site keys | |
$('form[data-recaptcha-sitekey]:not([data-recaptcha-sitekey=""])').each(function(){ | |
var $thisForm = jQuery(this), | |
$captchaDiv = $thisForm.find('div.recaptcha'), | |
$insertBefore, $column, widgetObject, $script, scriptSrc, widgetColourTheme, widgetSize; | |
widgetColourTheme = $thisForm.attr('data-recaptcha-theme'); | |
widgetColourTheme = typeof widgetColourTheme !== typeof undefined ? widgetColourTheme : ''; | |
widgetSize = $thisForm.attr('data-recaptcha-size'); | |
widgetSize = typeof widgetSize !== typeof undefined ? widgetSize : ''; | |
// Store the site key for later use | |
mr.forms.captcha.sitekey = $thisForm.attr('data-recaptcha-sitekey'); | |
if($captchaDiv.length){ | |
// If a div.recaptcha was already present on this form, do nothing at this stage, | |
// It will be populated with a captcha widget later. | |
}else{ | |
// Create a captcha div and insert it before the submit button. | |
$insertBefore = $thisForm.find('button[type=submit]').closest('[class*="col-"]'); | |
$captchaDiv = jQuery('<div>').addClass('recaptcha'); | |
$column = jQuery('<div>').addClass('col-12').append($captchaDiv); | |
$column.insertBefore($insertBefore); | |
} | |
// Add the widget div to the widgets array | |
widgetObject = { | |
element: $captchaDiv.get(0), | |
parentForm: $thisForm, | |
theme: widgetColourTheme, | |
size: widgetSize, | |
}; | |
mr.forms.captcha.widgets.push(widgetObject); | |
// mr.forms.captcha.done indicates whether the api script has been appended yet. | |
if(mr.forms.captcha.done === false){ | |
if(!jQuery('script[src*="recaptcha/api.js"]').length){ | |
$script = jQuery('<script async defer>'); | |
scriptSrc = 'https://www.google.com/recaptcha/api.js?onload=mrFormsCaptchaInit&render=explicit'; | |
$script.attr('src', scriptSrc); | |
jQuery('body').append($script); | |
mr.forms.captcha.done = true; | |
} | |
}else{ | |
if(typeof grecaptcha !== typeof undefined){ | |
mr.forms.captcha.renderWidgets(); | |
} | |
} | |
}); | |
}; | |
mr.forms.submit = function(e){ | |
// return false so form submits through jQuery rather than reloading page. | |
if (e.preventDefault) e.preventDefault(); | |
else e.returnValue = false; | |
var body = $('body'), | |
thisForm = $(e.target).closest('form'), | |
formAction = typeof thisForm.attr('action') !== typeof undefined ? thisForm.attr('action') : "", | |
submitButton = thisForm.find('button[type="submit"], input[type="submit"]'), | |
error = 0, | |
originalError = thisForm.attr('original-error'), | |
captchaUsed = thisForm.find('div.recaptcha').length ? true:false, | |
successRedirect, formError, formSuccess, errorText, successText; | |
body.find('.form-error, .form-success').remove(); | |
submitButton.attr('data-text', submitButton.text()); | |
errorText = thisForm.attr('data-error') ? thisForm.attr('data-error') : "Please fill all fields correctly"; | |
successText = thisForm.attr('data-success') ? thisForm.attr('data-success') : "Thanks, we'll be in touch shortly"; | |
body.append('<div class="form-error" style="display: none;">' + errorText + '</div>'); | |
body.append('<div class="form-success" style="display: none;">' + successText + '</div>'); | |
formError = body.find('.form-error'); | |
formSuccess = body.find('.form-success'); | |
thisForm.addClass('attempted-submit'); | |
// Do this if the form is intended to be submitted to MailChimp or Campaign Monitor | |
if (formAction.indexOf('createsend.com') !== -1 || formAction.indexOf('list-manage.com') !== -1 ) { | |
console.log('Mail list form signup detected.'); | |
if (typeof originalError !== typeof undefined && originalError !== false) { | |
formError.html(originalError); | |
} | |
// validateFields returns 1 on error; | |
if (mr.forms.validateFields(thisForm) !== 1) { | |
thisForm.removeClass('attempted-submit'); | |
// Hide the error if one was shown | |
formError.fadeOut(200); | |
// Create a new loading spinner in the submit button. | |
submitButton.addClass('btn--loading'); | |
try{ | |
$.ajax({ | |
url: thisForm.attr('action'), | |
crossDomain: true, | |
data: thisForm.serialize(), | |
method: "GET", | |
cache: false, | |
dataType: 'json', | |
contentType: 'application/json; charset=utf-8', | |
success: function(data){ | |
// Request was a success, what was the response? | |
if (data.result !== "success" && data.Status !== 200) { | |
// Got an error from Mail Chimp or Campaign Monitor | |
// Keep the current error text in a data attribute on the form | |
formError.attr('original-error', formError.text()); | |
// Show the error with the returned error text. | |
formError.html(data.msg).stop(true).fadeIn(1000); | |
formSuccess.stop(true).fadeOut(1000); | |
submitButton.removeClass('btn--loading'); | |
} else { | |
// Got success from Mail Chimp or Campaign Monitor | |
submitButton.removeClass('btn--loading'); | |
successRedirect = thisForm.attr('data-success-redirect'); | |
// For some browsers, if empty `successRedirect` is undefined; for others, | |
// `successRedirect` is false. Check for both. | |
if (typeof successRedirect !== typeof undefined && successRedirect !== false && successRedirect !== "") { | |
window.location = successRedirect; | |
}else{ | |
mr.forms.resetForm(thisForm); | |
mr.forms.showFormSuccess(formSuccess, formError, 1000, 5000, 500); | |
} | |
} | |
} | |
}); | |
}catch(err){ | |
// Keep the current error text in a data attribute on the form | |
formError.attr('original-error', formError.text()); | |
// Show the error with the returned error text. | |
formError.html(err.message); | |
mr.forms.showFormError(formSuccess, formError, 1000, 5000, 500); | |
submitButton.removeClass('btn--loading'); | |
} | |
} else { | |
// There was a validation error - show the default form error message | |
mr.forms.showFormError(formSuccess, formError, 1000, 5000, 500); | |
} | |
} else { | |
// If no MailChimp or Campaign Monitor form was detected then this is treated as an email form instead. | |
if (typeof originalError !== typeof undefined && originalError !== false) { | |
formError.text(originalError); | |
} | |
error = mr.forms.validateFields(thisForm); | |
if (error === 1) { | |
mr.forms.showFormError(formSuccess, formError, 1000, 5000, 500); | |
} else { | |
thisForm.removeClass('attempted-submit'); | |
// Hide the error if one was shown | |
formError.fadeOut(200); | |
// Create a new loading spinner in the submit button. | |
submitButton.addClass('btn--loading'); | |
jQuery.ajax({ | |
type: "POST", | |
url: (formAction !== "" ? formAction : ""), | |
data: thisForm.serialize()+"&url="+window.location.href+"&captcha="+captchaUsed, | |
success: function(response) { | |
// Swiftmailer always sends back a number representing number of emails sent. | |
// If this is numeric (not Swift Mailer error text) AND greater than 0 then show success message. | |
submitButton.removeClass('btn--loading'); | |
if ($.isNumeric(response)) { | |
if (parseInt(response,10) > 0) { | |
// For some browsers, if empty 'successRedirect' is undefined; for others, | |
// 'successRedirect' is false. Check for both. | |
successRedirect = thisForm.attr('data-success-redirect'); | |
if (typeof successRedirect !== typeof undefined && successRedirect !== false && successRedirect !== "") { | |
window.location = successRedirect; | |
} | |
mr.forms.resetForm(thisForm); | |
mr.forms.showFormSuccess(formSuccess, formError, 1000, 5000, 500); | |
mr.forms.captcha.resetWidgets(); | |
} | |
} | |
// If error text was returned, put the text in the .form-error div and show it. | |
else { | |
// Keep the current error text in a data attribute on the form | |
formError.attr('original-error', formError.text()); | |
// Show the error with the returned error text. | |
formError.text(response).stop(true).fadeIn(1000); | |
formSuccess.stop(true).fadeOut(1000); | |
} | |
}, | |
error: function(errorObject, errorText, errorHTTP) { | |
// Keep the current error text in a data attribute on the form | |
formError.attr('original-error', formError.text()); | |
// Show the error with the returned error text. | |
formError.text(errorHTTP).stop(true).fadeIn(1000); | |
formSuccess.stop(true).fadeOut(1000); | |
submitButton.removeClass('btn--loading'); | |
} | |
}); | |
} | |
} | |
return false; | |
}; | |
mr.forms.validateFields = function(form) { | |
var body = $(body), | |
error = false, | |
originalErrorMessage, | |
name, | |
thisElement; | |
form = $(form); | |
form.find('.validate-required[type="checkbox"]').each(function() { | |
var checkbox = $(this); | |
if (!$('[name="' + $(this).attr('name') + '"]:checked').length) { | |
error = 1; | |
name = $(this).attr('data-name') || 'check'; | |
checkbox.parent().addClass('field-error'); | |
//body.find('.form-error').text('Please tick at least one ' + name + ' box.'); | |
} | |
}); | |
form.find('.validate-required, .required, [required]').not('input[type="checkbox"]').each(function() { | |
if ($(this).val() === '') { | |
$(this).addClass('field-error'); | |
error = 1; | |
} else { | |
$(this).removeClass('field-error'); | |
} | |
}); | |
form.find('.validate-email, .email, [name*="cm-"][type="email"]').each(function() { | |
if (!(/(.+)@(.+){2,}\.(.+){2,}/.test($(this).val()))) { | |
$(this).addClass('field-error'); | |
error = 1; | |
} else { | |
$(this).removeClass('field-error'); | |
} | |
}); | |
form.find('.validate-number-dash').each(function() { | |
if (!(/^[0-9][0-9-]+[0-9]$/.test($(this).val()))) { | |
$(this).addClass('field-error'); | |
error = 1; | |
} else { | |
$(this).removeClass('field-error'); | |
} | |
}); | |
// Validate recaptcha | |
if(form.find('div.recaptcha').length && typeof form.attr('data-recaptcha-sitekey') !== typeof undefined){ | |
thisElement = $(form.find('div.recaptcha')); | |
if(grecaptcha.getResponse(form.data('recaptchaWidgetID')) !== ""){ | |
thisElement.removeClass('field-error'); | |
}else{ | |
thisElement.addClass('field-error'); | |
error = 1; | |
} | |
} | |
if (!form.find('.field-error').length) { | |
body.find('.form-error').fadeOut(1000); | |
}else{ | |
var firstError = $(form).find('.field-error:first'); | |
if(firstError.length){ | |
$('html, body').stop(true).animate({ | |
scrollTop: (firstError.offset().top - 100) | |
}, 1200, function(){firstError.focus();}); | |
} | |
} | |
return error; | |
}; | |
mr.forms.showFormSuccess = function(formSuccess, formError, fadeOutError, wait, fadeOutSuccess){ | |
formSuccess.stop(true).fadeIn(fadeOutError); | |
formError.stop(true).fadeOut(fadeOutError); | |
setTimeout(function() { | |
formSuccess.stop(true).fadeOut(fadeOutSuccess); | |
}, wait); | |
}; | |
mr.forms.showFormError = function(formSuccess, formError, fadeOutSuccess, wait, fadeOutError){ | |
formError.stop(true).fadeIn(fadeOutSuccess); | |
formSuccess.stop(true).fadeOut(fadeOutSuccess); | |
setTimeout(function() { | |
formError.stop(true).fadeOut(fadeOutError); | |
}, wait); | |
}; | |
// Reset form to empty/default state. | |
mr.forms.resetForm = function(form){ | |
form = $(form); | |
form.get(0).reset(); | |
form.find('.input-radio, .input-checkbox').removeClass('checked'); | |
form.find('[data-default-value]').filter('[type="text"],[type="number"],[type="email"],[type="url"],[type="search"],[type="tel"]').each(function(){ | |
var elem = jQuery(this); | |
elem.val(elem.attr('data-default-value')); | |
}); | |
}; | |
// Defined on the window scope as the recaptcha js api seems not to be able to call function in mr scope | |
window.mrFormsCaptchaInit = function(){ | |
mr.forms.captcha.renderWidgets(); | |
}; | |
mr.forms.captcha.renderWidgets = function(){ | |
mr.forms.captcha.widgets.forEach(function(widget){ | |
if(widget.element.innerHTML.replace(/[\s\xA0]+/g,'') === ''){ | |
widget.id = grecaptcha.render(widget.element, { | |
'sitekey' : mr.forms.captcha.sitekey, | |
'theme' : widget.theme, | |
'size' : widget.size, | |
'callback' : mr.forms.captcha.setHuman | |
}); | |
widget.parentForm.data('recaptchaWidgetID', widget.id); | |
} | |
}); | |
}; | |
mr.forms.captcha.resetWidgets = function(){ | |
mr.forms.captcha.widgets.forEach(function(widget){ | |
grecaptcha.reset(widget.id); | |
}); | |
}; | |
mr.forms.captcha.setHuman = function(){ | |
jQuery('div.recaptcha.field-error').removeClass('field-error'); | |
}; | |
mr.components.documentReadyDeferred.push(mr.forms.documentReady); | |
return mr; | |
}(mr, jQuery, window, document)); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment