WikiLerni/front/public/src/quiz.js

207 lines
8.1 KiB
JavaScript

// -- 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+="<br><br>"+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+="<br><br>"+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);
}
});