// -- GESTION DU FORMULAIRE PERMETTANT D'AFFICHER ET RÉPONDRE À UN QUIZ /// Il n'est pas nécessaire d'avoir une base de données locale active pour répondre à un quiz. /// Mais si ce n'est pas déjà le cas et que cela semble techniquement possible, on propose au répondant de sauvegarder son résultat. /// Dans ce but son résultat est stocké temporairement. /// Si la base de donnée locale existe déjà, l'enregistrement de son résultat se fait automatiquement dans IndexedDB et ses éventuels précédents résultats sont affichés. // Configurations générales provenant du backend : import { availableLangs, theme } from "../../../config/instance.js"; const lang=availableLangs[0]; // Fonctions : import { checkAllPreviousResults, checkUserAnswers, getResultOutput, resultsOpenDb, saveNewQuiz, saveResult, saveResultTemp, showPreviousResults } from "./tools/answers.js"; import { saveIsReady } from "./tools/clientstorage.js"; import { addElement } from "./tools/dom.js"; import { helloDev } from "./tools/everywhere.js"; import { isEmpty } from "../../../tools/main"; import { loadMatomo } from "./tools/matomo.js"; // Textes : const { wantToSaveResponses, wantToSeaPreviousResults }=require("../../../lang/"+lang+"/answer"); const { localDBConnexionFail, serverError }=require("../../../lang/"+lang+"/general"); // Informations du quiz, utile pour enregistrement dans base de donnée locale : const myForm=document.getElementById("quiz");// quiz const quizInfos= { url: window.location.pathname, GroupId: document.getElementById("groupId").value, QuestionnaireId: document.getElementById("questionnaireId").value, title: myForm.dataset.title }; // Autres éléments du DOM manipulés : const propose2Save=document.getElementById("propose2Save"); const btnSave=document.getElementById("want2Save"); const btnSubmit=document.getElementById("checkResponses"); const divResponse=document.getElementById("response"); // L'url permet de savoir si nous sommes sur un quiz unique ou groupé : let btnShow; if(quizInfos.url.indexOf("/gp/") == -1) btnShow=document.getElementById("showQuestionnaire"); // le quiz est affiché directement pour les groupes let userDB, allPreviousAnswers=[]; const initialise = async () => { try { if(btnShow) btnShow.style.display="inline"; // Le bouton est caché si le JS inactif, car le JS est nécessaire pour la suite... // On vérifie si la navigateur accepte l'utilisation d'IndexedDB : const saveIsPossible=saveIsReady(); if(saveIsPossible) { // On essaye ensuite de se connecter à la base de données (ce qui va la créer si inexistante) : userDB=await resultsOpenDb("myAnswers", 1); if(userDB === undefined) console.error(localDBConnexionFail); else { // Vérifie si l'utilisateur a déjà sauvegardé au moins un résultat (et donc est ok pour les sauvegardes) : allPreviousAnswers=await checkAllPreviousResults(userDB); if(allPreviousAnswers.length !== 0) await showPreviousResults(userDB, quizInfos.QuestionnaireId, quizInfos.GroupId); } } loadMatomo(); } catch(e) { console.error(e); } } initialise(); helloDev(); // Affichage du quiz, quand il est caché par défaut (= l'internaute doit d'abord lire un article Wikipédia). // Déclenche en même temps le chronomètre mesurant la durée de réponse aux questions. const showQuestionnaire = () => { chronoBegin=Date.now(); myForm.style.display="block"; btnShow.style.display="none"; const here=window.location; // window.location à ajouter pour ne pas quitter la page en mode "preview". if(window.location.hash !== "") { window.location.hash="";// ! le "#" reste window.location.assign(here+"questionnaire"); } else window.location.assign(here+"#questionnaire"); } // L'utilisateur demande à voir le quiz : let chronoBegin=0; if(btnShow) { btnShow.addEventListener("click", function(e) { try { e.preventDefault(); showQuestionnaire(); } catch(e) { addElement(divResponse, "p", serverError, "", ["error"]); console.error(e); } }); // Un lien peut être passé pour voir directement le quiz : if(location.hash !== "" && location.hash === "#questionnaire") showQuestionnaire(); } // Dans le cas d'un quiz groupé, le chrono est lancé dès l'affichage : if(quizInfos.GroupId != "0") { chronoBegin=Date.now(); btnSubmit.style.display="block"; } // Traitement de l'envoi de la réponse de l'utilisateur : let answer; myForm.addEventListener("submit", async function(e) { try { e.preventDefault(); btnSubmit.style.display="none"; // seulement une réponse à la fois, SVP :) divResponse.innerHTML=""; // supprime les éventuels messages déjà affichés answer=checkUserAnswers(myForm); answer.duration=Math.round((Date.now()-chronoBegin)/1000); answer.QuestionnaireId=quizInfos.QuestionnaireId; answer.GroupId=quizInfos.GroupId; // Affichage du résultat, suivant les cas : let getOuput=getResultOutput(answer); // S'il y a déjà une réponse dans la bd, c'est que l'utilisateur est ok pour les enregister. if(allPreviousAnswers.length !==0) { const saveResponses=await saveResult(userDB, answer); if(saveResponses) await showPreviousResults(userDB, quizInfos.QuestionnaireId, quizInfos.GroupId); getOuput+="

"+wantToSeaPreviousResults.replace("URL","#explanations"); // Nouveau quiz pour cette personne ? await saveNewQuiz(userDB, quizInfos); } else { // S'il n'a pas encore de données, on stocke temporairement le résultat et propose de l'enregistrer : if(saveResultTemp(answer) && !isEmpty(userDB)) { getOuput+="

"+wantToSaveResponses; propose2Save.style.display="block"; } } addElement(divResponse, "p", getOuput, "", ["info"]); // On redirige vers le résultat : const here=window.location; // window.location à ajouter pour ne pas quitter la page en mode "preview". if(window.location.hash !== "") { window.location.hash=""; // ! le "#" reste window.location.assign(here+"response"); } else window.location.assign(here+"#response"); // + Affichage des textes d'explication pour chaque question const explanations=document.querySelectorAll(".help"); for(let i in explanations) { if(explanations[i].style != undefined) // sinon, la console affiche une erreur "TypeError: explanations[i].style is undefined", bien que tout fonctionne (?) explanations[i].style.display="block"; } } catch(e) { addElement(divResponse, "p", serverError, "", ["error"]); console.error(e); } }) // L'utilisateur demande à sauvegarder son résultat : btnSave.addEventListener("click", async function(e) { try { e.preventDefault(); if(!isEmpty(userDB) && !isEmpty(answer)) // On ne devrait pas me proposer d'enregistrer dans ce cas, mais... { const saveResponses=await saveResult(userDB, answer); if(saveResponses) { // Nouvel enregistrement = actualisation nécessaire de la liste des résultats pour ce quiz : await showPreviousResults(userDB, quizInfos.QuestionnaireId, quizInfos.GroupId); // Nouveau quiz await saveNewQuiz(userDB, quizInfos); // Redirection vers la liste des résultats : const here=window.location; // window.location à ajouter pour ne pas quitter la page en mode "preview". if(window.location.hash !== "") { window.location.hash="";// ! le "#" reste window.location.assign(here+"explanations"); } else window.location.assign(here+"#explanations"); } propose2Save.style.display="none"; } } catch(e) { addElement(divResponse, "p", serverError, "", ["error"]); console.error(e); } });