// -- 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, il est proposé au répondant de sauvegarder durablement son résultat. /// Dans ce but, son résultat est d'abord 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 } from "../../../config/instance.js"; const lang=availableLangs[0]; // Textes : const { wantToSaveResponses, wantToSeaPreviousResults }=require("../../../lang/"+lang+"/answer"); const { serverError }=require("../../../lang/"+lang+"/general"); // Fonctions : import { addElement } from "./tools/dom.js"; import { helloDev } from "./tools/everywhere.js"; import { isEmpty } from "../../../tools/main"; import { loadMatomo } from "./tools/matomo.js"; // Classe s'occupant du stockage des résultats aux quizs : import { userQuizsResults} from "./tools/userQuizsResults"; // Informations du quiz en cours, utiles pour les enregistrements dans la base de donnée locale : const myForm=document.getElementById("quiz"); const quizInfos= { url: window.location.pathname, GroupId: document.getElementById("groupId").value, QuestionnaireId: document.getElementById("questionnaireId").value, title: myForm.dataset.title, keywords: myForm.dataset.keywords }; // Éléments du DOM manipulés : const btnSave=document.getElementById("want2Save"); const btnSubmit=document.getElementById("checkResponses"); const propose2Save=document.getElementById("propose2Save"); const responseTxt=document.getElementById("response"); let userDB, allPreviousAnswers=[], btnShow, myResults; const initialise = async () => { try { // Pour les quizs uniques (non groupés), un bouton permet à l'utilisateur d'afficher le quiz après avoir lu le contenu Wikipédia proposé, ce qui déclenche le chrono : if(quizInfos.url.indexOf("/gp/") == -1) { btnShow=document.getElementById("showQuestionnaire"); btnShow.style.display="inline"; // Le bouton est caché si le JS est inactif, car le JS est nécessaire pour la suite... } // Instanciation de la classe s'occupant du stockage des résultats aux quizs : myResults=await userQuizsResults.initialise("myResults", 2); // Si la base de données est fonctionnel et que des résultats sont déjà enregistrés, on affiche ceux pour le quiz en cours : if(myResults.allResults.length !== 0) await myResults.showPreviousResultsForId(quizInfos.QuestionnaireId, quizInfos.GroupId); // Statistiques : loadMatomo(); } catch(e) { console.error(e); } } initialise(); helloDev(); // Fonction affichant le quiz, quand il est caché par défaut+ déclenchant 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"); } let chronoBegin; if(btnShow) { btnShow.addEventListener("click", function(e) { try { e.preventDefault(); showQuestionnaire(); } catch(e) { addElement(responseTxt, "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 :) responseTxt.innerHTML=""; // supprime les éventuels messages déjà affichés answer=userQuizsResults.checkUserAnswers(myForm); answer.duration=Math.round((Date.now()-chronoBegin)/1000); answer.QuestionnaireId=quizInfos.QuestionnaireId; answer.GroupId=quizInfos.GroupId; // Enregistrement et affichage du résultat, suivant les cas : let getOuput=userQuizsResults.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(myResults.allResults.length !== 0) { const saveResponses=await myResults.addResult(answer); if(saveResponses) await myResults.showPreviousResultsForId(quizInfos.QuestionnaireId, quizInfos.GroupId); getOuput+="

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

"+wantToSaveResponses; propose2Save.style.display="block"; } } addElement(responseTxt, "p", getOuput, "", ["info"]); // On redirige vers le résultat : const here=window.location; 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(responseTxt, "p", serverError, "", ["error"]); console.error(e); } }); // L'utilisateur demande à sauvegarder son résultat : btnSave.addEventListener("click", async function(e) { try { e.preventDefault(); if(!isEmpty(myResults.dbIsReady) && !isEmpty(answer)) // On ne devrait pas m'avoir proposé d'enregistrer dans ce cas, mais... { const saveResponses=await myResults.addResult(answer); if(saveResponses) { // Nouvel enregistrement = actualisation nécessaire de la liste des résultats pour ce quiz : await myResults.showPreviousResultsForId(quizInfos.QuestionnaireId, quizInfos.GroupId); // Nouveau quiz (ce qui doit être le cas, mais...) : await myResults.saveNewQuiz(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(responseTxt, "p", serverError, "", ["error"]); console.error(e); } });