apostrophe-forms
Version:
Build forms for ApostropheCMS in a simple user interface.
229 lines (187 loc) • 7.46 kB
JavaScript
/* global grecaptcha */
apos.utils.widgetPlayers['apostrophe-forms'] = function (el, data, options) {
var form = el.querySelector('[data-apos-forms-form]');
var recaptchaSlot;
if (form) {
form.addEventListener('submit', submit);
if (form.querySelector('[data-apos-recaptcha-slot]')) {
recaptchaSlot = el.querySelector('[data-apos-recaptcha-slot]');
window.renderCaptchas = renderCaptchas;
addRecaptchaScript();
}
// If there are specified query parameters to capture, see if fields can be
// populated.
if (form.hasAttribute('data-apos-forms-params')) {
setParameterValues();
}
}
function submit(event) {
event.preventDefault();
if (form.querySelector('[data-apos-forms-busy]')) {
return setTimeout(function() {
submit(event);
}, 100);
}
// Deprecated, but IE-compatible, way to make an event
event = document.createEvent('Event');
event.initEvent('apos-forms-validate', true, true);
event.input = {
_id: form.getAttribute('data-apos-forms-form')
};
el.dispatchEvent(event);
if (el.querySelector('[data-apos-forms-error]')) {
return;
}
var recaptchaError = el.querySelector('[data-apos-forms-recaptcha-error]');
var recaptchaId;
if (recaptchaSlot) {
recaptchaId = recaptchaSlot.getAttribute('data-apos-recaptcha-id');
var token = grecaptcha.getResponse(recaptchaId);
if (!token) {
apos.utils.addClass(recaptchaError, 'apos-forms-visible');
apos.utils.emit(document.body, 'apostrophe-forms:submission-missing-recaptcha', {
form: form,
recaptchaSlot: recaptchaSlot
});
return;
}
apos.utils.removeClass(recaptchaError, 'apos-forms-visible');
event.input.recaptcha = token;
}
// For resubmissions
var errorMsg = el.querySelector('[data-apos-forms-submit-error]');
var spinner = el.querySelector('[data-apos-forms-spinner]');
var thankYou = el.querySelector('[data-apos-forms-thank-you]');
apos.utils.removeClass(errorMsg, 'apos-forms-visible');
apos.utils.addClass(spinner, 'apos-forms-visible');
// Convert to arrays old school for IE.
var existingErrorInputs = Array.prototype.slice.call(el.querySelectorAll('.apos-forms-input-error'));
var existingErrorMessages = Array.prototype.slice.call(el.querySelectorAll('[data-apos-input-message].apos-forms-error'));
existingErrorInputs.forEach(function (input) {
apos.utils.removeClass(input, 'apos-forms-input-error');
});
existingErrorMessages.forEach(function (message) {
apos.utils.removeClass(message, 'apos-forms-error');
message.hidden = true;
});
// Capture query parameters.
if (form.hasAttribute('data-apos-forms-params')) {
captureParameters(event);
}
return apos.utils.post('/modules/apostrophe-forms/submit', event.input, function (err, res) {
apos.utils.removeClass(spinner, 'apos-forms-visible');
if (err || (res && (res.status !== 'ok'))) {
apos.utils.emit(document.body, 'apostrophe-forms:submission-failed', {
form: form,
err: err,
res: res
});
apos.utils.addClass(errorMsg, 'apos-forms-visible');
highlightErrors(res);
if (recaptchaId) {
grecaptcha.reset(recaptchaId);
}
} else {
apos.utils.emit(document.body, 'apostrophe-forms:submission-form', {
form: form,
res: res
});
apos.utils.addClass(thankYou, 'apos-forms-visible');
apos.utils.addClass(form, 'apos-forms-hidden');
}
});
}
function highlightErrors(res) {
if (!res || !res.formErrors) {
return;
}
var globalError = el.querySelector('[data-apos-forms-global-error]');
var errors = res.formErrors;
globalError.innerText = '';
errors.forEach(function (error) {
if (error.global) {
globalError.innerText = globalError.innerText + ' ' +
error.errorMessage;
return;
}
var fields = form.querySelectorAll('[name=' + error.field + ']');
fields = Array.prototype.slice.call(fields);
var labelMessage = form.querySelector('[data-apos-input-message=' + error.field + ']');
fields.forEach(function (field) {
apos.utils.addClass(field, 'apos-forms-input-error');
});
apos.utils.addClass(labelMessage, 'apos-forms-error');
labelMessage.innerText = error.errorMessage;
labelMessage.hidden = false;
});
}
function addRecaptchaScript () {
if (document.querySelector('[data-apos-recaptcha-script]')) {
return;
}
var container = document.querySelector('[data-apos-refreshable]') || document.body;
var recaptchaScript = document.createElement('script');
recaptchaScript.src = 'https://www.google.com/recaptcha/api.js?onload=renderCaptchas&render=explicit';
recaptchaScript.setAttribute('data-apos-recaptcha-script', '');
recaptchaScript.setAttribute('async', '');
recaptchaScript.setAttribute('defer', '');
container.appendChild(recaptchaScript);
}
function renderCaptchas () {
var recaptchaSlots = document.querySelectorAll('[data-apos-recaptcha-slot]');
recaptchaSlots = Array.prototype.slice.call(recaptchaSlots);
recaptchaSlots.forEach(function(slot) {
var slotId = grecaptcha.render(
'aposRecaptcha' + slot.getAttribute('data-apos-recaptcha-slot'),
{
sitekey: slot.getAttribute('data-apos-recaptcha-sitekey')
}
);
slot.setAttribute('data-apos-recaptcha-id', slotId);
});
}
function getParameters () {
var queryParams = window.location.search.substring(1).split('&');
var params = {};
queryParams.forEach(function (string) {
var pair = string.split('=');
pair[0] = decodeURIComponent(pair[0]);
params[pair[0]] = decodeURIComponent(pair[1]);
});
return params;
}
function setParameterValues () {
var paramList = form.getAttribute('data-apos-forms-params').split(',');
var params = getParameters();
paramList.forEach(function (param) {
var paramInput = form.querySelector('[name="' + param + '"]');
if (!params[param]) {
return;
}
// If the input is a checkbox, check all in the comma-separated query
// parameter value.
if (paramInput && paramInput.type === 'checkbox') {
params[param].split(',').forEach(function (value) {
var checkbox = form.querySelector('[name="' + param + '"][value="' + value + '"]');
if (checkbox) {
checkbox.checked = true;
}
});
// If the input is a radio, check the matching input.
} else if (paramInput && paramInput.type === 'radio') {
form.querySelector('[name="' + param + '"][value="' + params[param] + '"]').checked = true;
// If the input is a select field, make sure the value is an option.
} else if (paramInput && paramInput.type === 'select') {
if (paramInput.querySelector('option[value="' + params[param] + '"')) {
paramInput.value = params[param];
}
// Otherwise set the input value to the parameter value.
} else if (paramInput) {
paramInput.value = params[param];
}
});
}
function captureParameters (event) {
event.input.queryParams = getParameters();
}
};