252 lines
9.4 KiB
JavaScript
252 lines
9.4 KiB
JavaScript
document.addEventListener('DOMContentLoaded', (event) => {
|
|
const form = document.querySelector('form');
|
|
const formElements = form.elements;
|
|
|
|
const instructionsModal = new bootstrap.Modal(document.getElementById('instructionsModal'));
|
|
instructionsModal.show();
|
|
|
|
document.getElementById('startModalBtn').addEventListener('click', function() {
|
|
hideNavElementsAndQuestions();
|
|
document.currentQuestion = 0;
|
|
showQuestion('q0');
|
|
setButtonVisiblity('next', true);
|
|
setButtonVisiblity('back', true);
|
|
setNextButtonAvailability();
|
|
});
|
|
|
|
// Load saved form state
|
|
/* loadFormState(formElements);
|
|
|
|
// Save form state on change
|
|
form.addEventListener('change', () => {
|
|
saveFormState(formElements);
|
|
}); */
|
|
|
|
setUpNavigation()
|
|
});
|
|
|
|
function nextQuestion() {
|
|
document.currentQuestion++;
|
|
hideNavElementsAndQuestions();
|
|
showQuestion(`q${document.currentQuestion}`);
|
|
setButtonVisiblity('back', true);
|
|
setButtonVisiblity('next', true);
|
|
if (document.currentQuestion === document.lastQuestion) {
|
|
setButtonVisiblity('next', false);
|
|
setButtonVisiblity('submit', true);
|
|
}
|
|
setNextButtonAvailability();
|
|
}
|
|
|
|
function previousQuestion() {
|
|
if (document.currentQuestion > 0) {
|
|
document.currentQuestion--;
|
|
hideNavElementsAndQuestions();
|
|
showQuestion(`q${document.currentQuestion}`);
|
|
setButtonVisiblity('next', true);
|
|
setButtonVisiblity('submit', false);
|
|
document.nextEnabled = true;
|
|
}
|
|
setButtonVisiblity('back', document.currentQuestion !== 0);
|
|
setNextButtonAvailability();
|
|
}
|
|
|
|
function setUpNavigation() {
|
|
const questions = document.querySelectorAll('.question');
|
|
|
|
document.currentQuestion = 0;
|
|
document.nextEnabled = false;
|
|
document.lastQuestion = questions.length - 1;
|
|
|
|
hideNavElementsAndQuestions();
|
|
showQuestion(`q${document.currentQuestion}`);
|
|
setButtonVisiblity('next', true);
|
|
|
|
|
|
const nextButton = document.getElementById('next');
|
|
const backButton = document.getElementById('back');
|
|
nextButton.addEventListener('click', nextQuestion);
|
|
backButton.addEventListener('click', previousQuestion);
|
|
|
|
setNextButtonAvailability();
|
|
|
|
// check if next button should be enabled on every input, checkbox and radio button bellow class of .question change
|
|
const inputs = document.querySelectorAll('.question input, .question select, .question textarea');
|
|
inputs.forEach(input => {
|
|
input.addEventListener('change',()=> setNextButtonAvailability());
|
|
input.addEventListener('blur', () => setNextButtonAvailability());
|
|
|
|
});
|
|
}
|
|
|
|
async function setNextButtonAvailability() {
|
|
// check if current question is answered
|
|
// and then enable the next button, disable it otherwise
|
|
const currentQuestion = document.getElementById(`q${document.currentQuestion}`);
|
|
const nextButton = document.getElementById('next');
|
|
const submitButton = document.getElementById('submit');
|
|
// check if any input in the current question is checked, or filled in case it is a text input
|
|
let nextEnabled = false;
|
|
if (document.currentQuestion === 0) {
|
|
const name = document.getElementById('name');
|
|
const email = document.getElementById('email');
|
|
const errorDiv = document.getElementById('org-email-error');
|
|
|
|
if (name && email && name.value.trim() && email.value.trim()) {
|
|
nextEnabled = await validateFormFields(nextButton, errorDiv);
|
|
}else{
|
|
nextButton.disabled = true;
|
|
if (errorDiv) errorDiv.textContent = '';
|
|
return
|
|
}
|
|
} else {
|
|
const inputs = currentQuestion.querySelectorAll('input, select, textarea');
|
|
for (let input of inputs) {
|
|
if (input.checkVisibility() === false){
|
|
continue;
|
|
}
|
|
if (input.type === 'checkbox' || input.type === 'radio') {
|
|
if (input.checked) {
|
|
nextEnabled = true;
|
|
break;
|
|
}
|
|
} else {
|
|
if (input.value) {
|
|
nextEnabled = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
nextButton.disabled = !nextEnabled;
|
|
submitButton.disabled = !nextEnabled;
|
|
}
|
|
|
|
function saveFormState(elements) {
|
|
const formState = {};
|
|
for (let element of elements) {
|
|
if (element.name) {
|
|
if (element.type === 'select-multiple') {
|
|
formState[element.name] = Array.from(element.selectedOptions).map(option => option.value);
|
|
} else if (element.type === 'checkbox' || element.type === 'radio') {
|
|
formState[element.name] = element.checked ? element.value : formState[element.name] || null;
|
|
} else {
|
|
formState[element.name] = element.value;
|
|
}
|
|
}
|
|
}
|
|
localStorage.setItem('formState', JSON.stringify(formState));
|
|
}
|
|
|
|
function loadFormState(elements) {
|
|
const formState = JSON.parse(localStorage.getItem('formState'));
|
|
if (formState) {
|
|
for (let element of elements) {
|
|
if (element.name && formState[element.name] !== undefined) {
|
|
if (element.type === 'select-multiple') {
|
|
Array.from(element.options).forEach(option => {
|
|
option.selected = formState[element.name].includes(option.value);
|
|
});
|
|
} else if (element.type === 'checkbox' || element.type === 'radio') {
|
|
element.checked = formState[element.name] === element.value;
|
|
} else {
|
|
element.value = formState[element.name];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function hideNavElementsAndQuestions() {
|
|
const questions = document.querySelectorAll('.question');
|
|
questions.forEach(question => {
|
|
// add bootstrap hidden class to the element
|
|
question.classList.add('d-none');
|
|
});
|
|
const nextButton = document.getElementById('next');
|
|
const backButton = document.getElementById('back');
|
|
const submitButton = document.getElementById('submit');
|
|
nextButton.classList.add('d-none');
|
|
backButton.classList.add('d-none');
|
|
submitButton.classList.add('d-none');
|
|
}
|
|
|
|
function showQuestion(questionId) {
|
|
const question = document.getElementById(questionId);
|
|
question.classList.remove('d-none');
|
|
progressBar();
|
|
}
|
|
|
|
function setButtonVisiblity(buttonId, visible) {
|
|
const button = document.getElementById(buttonId);
|
|
if (visible) {
|
|
button.classList.remove('d-none');
|
|
} else {
|
|
button.classList.add('d-none');
|
|
}
|
|
}
|
|
|
|
async function validateFormFields(nextBtn, errorDiv) {
|
|
const nameInput = document.getElementById('name');
|
|
const emailInput = document.getElementById('email');
|
|
const name = nameInput.value.trim();
|
|
const email = emailInput.value.trim();
|
|
|
|
const resp = await fetch(`/api/validate_form_fields/?name=${name}&email=${email}`);
|
|
const data = await resp.json();
|
|
if (data.errors && (data.errors.name || data.errors.email)) {
|
|
errorDiv.textContent = (data.errors.name || '') + ' ' + (data.errors.email || '');
|
|
nextBtn.disabled = true;
|
|
return false;
|
|
} else {
|
|
errorDiv.textContent = '';
|
|
nextBtn.disabled = false;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
function progressBar() {
|
|
const basic = Array.from(document.querySelectorAll('.basic-section'));
|
|
const advanced = Array.from(document.querySelectorAll('.advanced-section'));
|
|
const basicProgress = document.getElementById('basic-progress');
|
|
const advancedProgress = document.getElementById('advanced-progress');
|
|
const basicBar = document.getElementById('basic-progress-bar');
|
|
const advancedBar = document.getElementById('advanced-progress-bar');
|
|
const basicBarWrap = document.getElementById('basic-progress-bar-wrap');
|
|
const advancedBarWrap = document.getElementById('advanced-progress-bar-wrap');
|
|
|
|
let currentId = `q${document.currentQuestion}`;
|
|
let idxBasic = basic.findIndex(q => q.id === currentId);
|
|
let idxAdvanced = advanced.findIndex(q => q.id === currentId);
|
|
|
|
if (idxBasic !== -1) {
|
|
basicProgress.classList.remove('d-none');
|
|
basicBarWrap.classList.remove('d-none');
|
|
advancedProgress.classList.add('d-none');
|
|
advancedBarWrap.classList.add('d-none');
|
|
if (idxBasic + 1 === basic.length) {
|
|
basicProgress.innerHTML = `<span class="text-success fw-bold">Basic question ✓</span>`;
|
|
basicBarWrap.classList.add('d-none');
|
|
} else {
|
|
basicProgress.innerText = `Question ${idxBasic + 1} / ${basic.length}`;
|
|
}
|
|
let percent = ((idxBasic + 1) / basic.length) * 100;
|
|
basicBar.style.width = percent + "%";
|
|
basicBar.setAttribute('aria-valuenow', percent);
|
|
} else if (idxAdvanced !== -1) {
|
|
advancedProgress.classList.remove('d-none');
|
|
advancedBarWrap.classList.remove('d-none');
|
|
basicBarWrap.classList.add('d-none');
|
|
advancedProgress.innerText = `Advanced Question ${idxAdvanced + 1} / ${advanced.length}`;
|
|
let percent = ((idxAdvanced + 1) / advanced.length) * 100;
|
|
advancedBar.style.width = percent + "%";
|
|
advancedBar.setAttribute('aria-valuenow', percent);
|
|
} else {
|
|
basicProgress.classList.add('d-none');
|
|
advancedProgress.classList.add('d-none');
|
|
basicBarWrap.classList.add('d-none');
|
|
advancedBarWrap.classList.add('d-none');
|
|
}
|
|
} |