Merge pull request #88 from ThomasRubini/js-refactor

[Client] Refactor JavaScript
This commit is contained in:
Audric V 2023-03-10 11:13:29 +01:00 committed by GitHub
commit 86bcfefaac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 318 additions and 284 deletions

View File

@ -1,3 +1,11 @@
/**
* Make a request to the given endpoint of the API with the given body.
*
* @param {String} endpoint the endpoint on which make an API request
* @param {Object} body an object to send in the API request (this object can be omitted)
* @returns a Promise, which resolves when the server can be reached and responds without an error
* and rejects otherwise
*/
async function makeAPIRequest(endpoint, body) { async function makeAPIRequest(endpoint, body) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const fetchOptions = { const fetchOptions = {
@ -7,7 +15,6 @@ async function makeAPIRequest(endpoint, body) {
fetch("/api/v1/" + endpoint, fetchOptions).then(response => { fetch("/api/v1/" + endpoint, fetchOptions).then(response => {
const responseCode = response.status; const responseCode = response.status;
console.log(responseCode);
if (responseCode >= 500) { if (responseCode >= 500) {
reject("Error " + responseCode + " when fetching " + endpoint); reject("Error " + responseCode + " when fetching " + endpoint);
alert("Une réponse invalide du serveur a été obtenue, veuillez réessayer ultérieurement."); alert("Une réponse invalide du serveur a été obtenue, veuillez réessayer ultérieurement.");

View File

@ -1,77 +1,94 @@
const intro_image_path = "/static/images/entrée-manoir.png"; const INTRO_IMAGE_PATH = "/static/images/entrée-manoir.png";
const interrogation_image_path = "/static/images/salle-interrogation.png"; const INTERROGATION_IMAGE_PATH = "/static/images/salle-interrogation.png";
const results_image_path = "/static/images/salle-resultats.png"; const RESULTS_IMAGE_PATH = "/static/images/salle-resultats.png";
const NPC_REACTION_PATH = "/api/v1/getNpcReaction?npcid=";
const NPC_IMAGE_PATH = "/api/v1/getNpcImage?npcid=";
var npcs_ids = []; let npcsIds = [];
var gamedata = {}; let gameData = {};
var currentNpc = null; let currentNpc = null;
var username = null; let username = null;
function show(className) {
document.getElementsByClassName(className)[0].classList.remove("hidden");
}
function hide(className) {
document.getElementsByClassName(className)[0].classList.add("hidden");
}
/*
* Set the current game background to the first element with the current_background CSS class.
*/
function setGameBackground(backgroundPath) { function setGameBackground(backgroundPath) {
document.getElementsByClassName("current_background")[0].style.backgroundImage = 'url("' + backgroundPath +'")'; document.querySelector(".current_background").style.backgroundImage = 'url("' + backgroundPath + '")';
} }
function setListenerToIntroductionNextBtn() { /**
document.getElementById("introduction_next_btn").addEventListener("click", showInterogationViewFromIntroduction); * Set listeners to introduction and interrogation navigation buttons.
} */
function setIntroductionAndInterrogationListeners() {
function setListenerToInterrogationSuspectPreviousBtn() { document.getElementById("introduction_next_btn")
document.getElementById("interrogation_suspect_previous_btn").addEventListener("click", goBackToInterogation); .addEventListener("click", showInterrogationViewFromIntroduction);
} document.getElementById("interrogation_suspect_previous_btn")
.addEventListener("click", goBackToInterrogation);
function setListenerToInterrogationNextBtn() { document.getElementById("interrogation_next_btn")
document.getElementById("interrogation_next_btn").addEventListener("click", showEmotionAndCulpritChoicesView); .addEventListener("click", showEmotionAndCulpritChoicesView);
} }
/**
* Set listeners to questions buttons.
*/
function setQuestionButtonsListeners() { function setQuestionButtonsListeners() {
document.getElementById("QA_0").addEventListener("click", askTypeZeroQuestion); document.getElementById("QA_0")
document.getElementById("QA_1").addEventListener("click", askTypeOneQuestion); .addEventListener("click", askTypeZeroQuestion);
document.getElementById("QA_1")
.addEventListener("click", askTypeOneQuestion);
} }
function removeQuestionButtonsListeners() { /**
document.getElementById("QA_0").removeEventListener("click", askTypeZeroQuestion); * Unset listeners to questions buttons.
document.getElementById("QA_1").removeEventListener("click", askTypeOneQuestion); */
function unsetQuestionButtonsListeners() {
document.getElementById("QA_0")
.removeEventListener("click", askTypeZeroQuestion);
document.getElementById("QA_1")
.removeEventListener("click", askTypeOneQuestion);
} }
function goBackToInterogation() { /**
hide("interrogation_suspect"); * Go back to interrogation view, by hiding the interrogation suspect view.
show("interrogation"); */
function goBackToInterrogation() {
hideFirstClassElement("interrogation_suspect");
showFirstClassElement("interrogation");
} }
function showInterogationViewFromIntroduction() { /**
hide("introduction"); * Show the interrogation view from the introduction one and hide the interrogation one.
show("interrogation"); */
setGameBackground(interrogation_image_path); function showInterrogationViewFromIntroduction() {
hideFirstClassElement("introduction");
showFirstClassElement("interrogation");
setGameBackground(INTERROGATION_IMAGE_PATH);
} }
/**
* Show the emotion and culprit choices view and hide the interrogation one.
*/
function showEmotionAndCulpritChoicesView() { function showEmotionAndCulpritChoicesView() {
hide("interrogation"); hideFirstClassElement("interrogation");
show("emotion_and_culprit_choices"); showFirstClassElement("emotion_and_culprit_choices");
} }
function getNpcLocationAndPartner(npcid) { function getNpcLocationAndPartner(npcid) {
data = {}; const data = {};
npcid = parseInt(npcid); const npcidInt = parseInt(npcid);
for (const room in gamedata["rooms"]) { for (const room in gameData["rooms"]) {
if (gamedata["rooms"][room]["npcs"].includes(npcid)) { if (gameData["rooms"][room]["npcs"].includes(npcidInt)) {
data["room"] = gamedata["rooms"][room]["name"]; data["room"] = gameData["rooms"][room]["name"];
if (gamedata["rooms"][room]["npcs"].length === 1) { if (gameData["rooms"][room]["npcs"].length === 1) {
do { do {
const random = Math.floor(Math.random() * npcs_ids.length); const random = Math.floor(Math.random() * npcsIds.length);
data["partner"] = npcs_ids[random]; data["partner"] = npcsIds[random];
} while (data["partner"] === npcid); } while (data["partner"] === npcidInt);
} else { } else {
data["partner"] = gamedata["rooms"][room]["npcs"][gamedata["rooms"][room]["npcs"][1] === npcid ? 0 : 1]; data["partner"] = gameData["rooms"][room]["npcs"]
[gameData["rooms"][room]["npcs"][1] === npcidInt ? 0 : 1];
} }
} }
} }
@ -81,21 +98,24 @@ function getNpcLocationAndPartner(npcid) {
function disableCulpritButtons(culprit_choices_element, selected_suspect) { function disableCulpritButtons(culprit_choices_element, selected_suspect) {
let childrenCulpritChoicesElement = culprit_choices_element.children; let childrenCulpritChoicesElement = culprit_choices_element.children;
for (let index = 0; index < childrenCulpritChoicesElement.length; index++) { for (let index = 0; index < childrenCulpritChoicesElement.length; index++) {
let child = childrenCulpritChoicesElement[index]; let child = childrenCulpritChoicesElement[index];
if (selected_suspect != child) { if (selected_suspect != child) {
child.getElementsByClassName("culprit_btn")[0].classList.add("hidden"); child.querySelector(".culprit_btn").classList.add("hidden");
} else { } else {
child.getElementsByClassName("culprit_unchecked_icon")[0].classList.add("hidden"); child.querySelector(".culprit_unchecked_icon").classList.add("hidden");
child.getElementsByClassName("culprit_checked_icon")[0].classList.remove("hidden"); child.querySelector(".culprit_checked_icon").classList.remove("hidden");
child.getElementsByClassName("culprit_btn")[0].classList.add("culprit_btn_checked"); child.querySelector(".culprit_btn").classList.add("culprit_btn_checked");
} }
} }
} }
function getCulprit() { function getCulprit() {
culprit = null; let culprit = null;
Object.values(gamedata["rooms"]).forEach(element => {
Object.values(gameData["rooms"]).forEach(element => {
if (element['npcs'].length === 1) { if (element['npcs'].length === 1) {
culprit = element['npcs'][0]; culprit = element['npcs'][0];
return; return;
@ -106,198 +126,223 @@ function getCulprit() {
} }
async function askTypeOneQuestion() { async function askTypeOneQuestion() {
removeQuestionButtonsListeners(); askQuestion(npcLocationAndPartner => gameData["npcs"][currentNpc]["QA_1"].replace(
partnerId = getNpcLocationAndPartner(currentNpc)["partner"]; "{NPC}", gameData["npcs"][npcLocationAndPartner["partner"]]["name"]));
anwser = gamedata["npcs"][currentNpc]["QA_1"];
anwser = anwser.replace("{NPC}",gamedata["npcs"][partnerId]["name"]);
document.getElementsByClassName("suspect_answer")[0].textContent = anwser;
show("question_answer");
document.getElementById("currentNpcPicure").src = "/api/v1//getNpcReaction?npcid="+currentNpc;
// Sleep for 5 sec
await new Promise(r => setTimeout(r, 2000));
document.getElementById("currentNpcPicure").src = "/api/v1/getNpcImage?npcid="+currentNpc;
hide("question_answer");
document.getElementsByClassName("suspect_answer")[0].textContent = "";
setQuestionButtonsListeners();
} }
async function askTypeZeroQuestion() { async function askTypeZeroQuestion() {
removeQuestionButtonsListeners(); askQuestion(npcLocationAndPartner => gameData["npcs"][currentNpc]["QA_0"].replace(
room = getNpcLocationAndPartner(currentNpc)["room"]; "{SALLE}", npcLocationAndPartner["room"]));
anwser = gamedata["npcs"][currentNpc]["QA_0"]; }
anwser = anwser.replace("{SALLE}",room);
document.getElementsByClassName("suspect_answer")[0].textContent = anwser; async function askQuestion(buildAnswer) {
show("question_answer"); unsetQuestionButtonsListeners();
document.getElementById("currentNpcPicure").src = "/api/v1//getNpcReaction?npcid="+currentNpc;
// Sleep for 5 sec document.querySelector(".suspect_answer").textContent = buildAnswer(
await new Promise(r => setTimeout(r, 5000)); getNpcLocationAndPartner(currentNpc));
document.getElementById("currentNpcPicure").src = "/api/v1/getNpcImage?npcid="+currentNpc;
hide("question_answer"); showFirstClassElement("question_answer");
document.getElementsByClassName("suspect_answer")[0].textContent = "";
document.getElementById("currentNpcPicure").src = NPC_REACTION_PATH + currentNpc;
//TODO: change this code which produces strange behaviors
// Sleep for 4 sec
await new Promise(r => setTimeout(r, 4000));
document.getElementById("currentNpcPicure").src = NPC_REACTION_PATH + currentNpc;
hideFirstClassElement("question_answer");
document.querySelector(".suspect_answer").textContent = "";
setQuestionButtonsListeners(); setQuestionButtonsListeners();
} }
async function sendAnswers() { async function sendAnswers() {
selects = document.getElementsByClassName("suspect_emotion_chooser"); const selections = document.getElementsByClassName("suspect_emotion_chooser");
let playerResponses = {};
for (let index = 0; index < selects.length; index++) { const playerResponses = {};
select = selects[index];
for (let index = 0; index < selections.length; index++) {
select = selections[index];
playerResponses[select.id] = select.value; playerResponses[select.id] = select.value;
} }
data = {}; const data = {};
data["responses"] = JSON.stringify(playerResponses); data["responses"] = JSON.stringify(playerResponses);
return await makeAPIRequest("submitAnswers", data); return await makeAPIRequest("submitAnswers", data);
} }
function renderAnswerSelectionPanel() { function renderAnswerSelectionPanel() {
npcs_ids.forEach(element => { npcsIds.forEach(element => {
let suspect = document.createElement("div"); const suspect = document.createElement("div");
suspect.classList.add("suspect"); suspect.classList.add("suspect");
suspect_emotion_chooser = document.createElement("select"); const suspectEmotionChooser = document.createElement("select");
suspect_emotion_chooser.classList.add("suspect_emotion_chooser") suspectEmotionChooser.classList.add("suspect_emotion_chooser")
suspect_emotion_chooser.setAttribute("id", element); suspectEmotionChooser.setAttribute("id", element);
gamedata["traits"].forEach(trait =>{
let option = document.createElement("option"); gameData["traits"].forEach(trait => {
const option = document.createElement("option");
option.value = trait; option.value = trait;
option.text = trait; option.text = trait;
suspect_emotion_chooser.appendChild(option); suspectEmotionChooser.appendChild(option);
}); });
suspect.appendChild(suspect_emotion_chooser); suspect.appendChild(suspectEmotionChooser);
let img = document.createElement('img'); const img = document.createElement('img');
img.classList.add("suspect_picture"); img.classList.add("suspect_picture");
img.src = "/api/v1/getNpcImage?npcid=" + element; img.src = NPC_IMAGE_PATH + element;
suspect.appendChild(img); suspect.appendChild(img);
let button = document.getElementById("culpritButton"); const button = document.createElement("button");
let button_clone = button.cloneNode(true); button.classList.add("culprit_btn", "action_button");
let culprit_choices = document.getElementById("culprits_choices"); button.innerHTML = '<svg class="culprit_checked_icon hidden culprit_icon" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 48 48"><path d="M18.9 36.75 6.65 24.5l3.3-3.3 8.95 9L38 11.1l3.3 3.25Z"></path></svg><svg class="culprit_unchecked_icon culprit_icon" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 48 48"><path d="M12.45 38.7 9.3 35.55 20.85 24 9.3 12.5l3.15-3.2L24 20.8 35.55 9.3l3.15 3.2L27.2 24l11.5 11.55-3.15 3.15L24 27.2Z"></svg><p class="culprit_btn_text">Couplable</p>';
button_clone.addEventListener("click", () => { const culpritChoices = document.getElementById("culprits_choices");
disableCulpritButtons(culprit_choices, suspect);
button.addEventListener("click", () => {
disableCulpritButtons(culpritChoices, suspect);
sendAnswers(); sendAnswers();
}); });
button_clone.removeAttribute("id"); suspect.appendChild(button);
button_clone.classList.remove("hidden"); culpritChoices.appendChild(suspect);
suspect.appendChild(button_clone);
culprit_choices.appendChild(suspect);
}); });
} }
function renderInterogation() { function renderInterrogation() {
document.getElementById("QA_0").textContent = gamedata["questions"]["QA_0"], document.getElementById("QA_0").textContent = gameData["questions"]["QA_0"];
document.getElementById("QA_1").textContent = gamedata["questions"]["QA_1"], document.getElementById("QA_1").textContent = gameData["questions"]["QA_1"];
npcs_ids.forEach(element => {
let suspect = document.createElement("div"); const interrogationSuspects = document.getElementById("interrogation_suspects");
npcsIds.forEach(element => {
const suspect = document.createElement("div");
suspect.classList.add("suspect"); suspect.classList.add("suspect");
let img = document.createElement('img'); const img = document.createElement('img');
img.classList.add("suspect_picture"); img.classList.add("suspect_picture");
img.src = "/api/v1/getNpcImage?npcid=" + element; img.src = NPC_IMAGE_PATH + element;
suspect.appendChild(img); suspect.appendChild(img);
let button = document.getElementById("interogationButton"); const button = document.createElement("button");
let button_clone = button.cloneNode(true); button.classList.add("ask_button", "action_button");
button_clone.classList.remove("hidden"); button.textContent = "Interroger";
button_clone.addEventListener("click", () => { button.addEventListener("click", () => {
// TODO remove this listener when we know the questions has already been asked; // TODO remove this listener when we know the questions has already been asked;
currentNpc = element currentNpc = element;
document.getElementById("currentNpcPicure").src = "/api/v1/getNpcImage?npcid="+element; document.getElementById("currentNpcPicure").src = NPC_IMAGE_PATH + element;
hide("interrogation"); hideFirstClassElement("interrogation");
show("interrogation_suspect"); showFirstClassElement("interrogation_suspect");
}); });
suspect.appendChild(button_clone); suspect.appendChild(button);
document.getElementById("interrogation_suspects").appendChild(suspect); interrogationSuspects.appendChild(suspect);
}); });
} }
function initSock(){ function initSock() {
socket = io({ const socket = io({
auth : { auth : {
game_id: gamedata["game_id"] game_id: gameData["game_id"]
} }
}); });
socket.on("connect", () => { socket.on("connect", () => {
console.log("Connected !") console.log("Connected to the server!");
}) });
//TODO Send and receive userprogress when they have sent their responses //TODO Send and receive userprogress when they have sent their responses
socket.on("gameprogress", (username) => { socket.on("gameprogress", username => {
console.log(username); console.log(username);
}); });
socket.on("gamefinished", (finalResults) => { socket.on("gamefinished", finalResults => {
hide("emotion_and_culprit_choices"); hideFirstClassElement("emotion_and_culprit_choices");
document.getElementsByClassName("reveal_score")[0].textContent = Object.values(finalResults["player"][username]).filter(x => x == true).length + "/5"; document.querySelector(".reveal_score").textContent =
for (const player in finalResults["player"]){ Object.values(finalResults["player"][username])
.filter(x => x == true).length + " / 5";
const playerListElement = document.querySelector(".players_list");
for (const player in finalResults["player"]) {
if (player === username) { if (player === username) {
continue; continue;
} }
let playerNode = document.createElement("h3"); const playerNode = document.createElement("h3");
playerNode.classList.add("player_name_and_score"); playerNode.classList.add("player_name_and_score");
let playerResultArray = Object.values(finalResults["player"][player]); const playerResultArray = Object.values(finalResults["player"][player]);
playerNode.textContent = "" + player + " : " + playerResultArray.filter(x => x == true).length; playerNode.textContent = "" + player + " : "
+ playerResultArray.filter(x => x == true).length;
document.getElementsByClassName("players_list")[0].appendChild(playerNode); playerListElement.appendChild(playerNode);
} }
culprit = getCulprit(); const culprit = getCulprit();
document.getElementsByClassName("reveal_culprit_title")[0].textContent += " " + gamedata["npcs"][culprit]["name"]; const culpritName = gameData["npcs"][culprit]["name"];
document.getElementById("culprit").src = "/api/v1/getNpcImage?npcid="+culprit; document.querySelector(".reveal_culprit_title").textContent += " " + culpritName;
show("results_game"); const culpritElement = document.getElementById("culprit");
setGameBackground(results_image_path); culpritElement.src = NPC_IMAGE_PATH + culprit;
culpritElement.setAttribute("alt", "Image du ou de la coupable, " + culpritName);
npcs_ids.filter(x => x != culprit).forEach(npcid =>{ showFirstClassElement("results_game");
let suspect = document.createElement("div"); setGameBackground(RESULTS_IMAGE_PATH);
suspect.classList.add("summary_suspect");
let img = document.createElement("img")
img.src = "/api/v1/getNpcImage?npcid=" + npcid;
suspect.appendChild(img)
let emotionTitle = document.createElement("h2"); const suspectListElement = document.querySelector(".suspects_list");
emotionTitle.classList.add("explain_suspect_emotion_title");
emotionTitle.textContent = "Ce suspect était " + finalResults["npcs"][npcid]["reaction"];
suspect.appendChild(emotionTitle);
let emotionDesc = document.createElement("p"); npcsIds.filter(x => x != culprit)
emotionDesc.classList.add("explain_suspect_emotion_description"); .forEach(npcid => {
emotionDesc.textContent = "Qui se caractérise par " + finalResults["npcs"][npcid]["description"]; const suspect = document.createElement("div");
suspect.appendChild(emotionDesc) suspect.classList.add("summary_suspect");
document.getElementsByClassName("suspects_list")[0].appendChild(suspect) const img = document.createElement("img");
}) img.src = NPC_IMAGE_PATH + npcid;
suspect.appendChild(img);
const emotionTitle = document.createElement("h2");
emotionTitle.classList.add("explain_suspect_emotion_title");
emotionTitle.textContent = "Ce suspect était "
+ finalResults["npcs"][npcid]["reaction"] + ".";
suspect.appendChild(emotionTitle);
const emotionDesc = document.createElement("p");
emotionDesc.classList.add("explain_suspect_emotion_description");
emotionDesc.textContent = "Cette émotion se caractérise par "
+ finalResults["npcs"][npcid]["description"];
suspect.appendChild(emotionDesc);
suspectListElement.appendChild(suspect);
});
}); });
} }
async function setGameData() { async function setGameData() {
data = {}; const response = await makeAPIRequest("getGameData");
response = await makeAPIRequest("getGameData"); gameData = response["gamedata"];
gamedata = response["gamedata"];
username = response["username"]; username = response["username"];
npcs_ids = Object.keys(gamedata["npcs"]).sort((a, b) => 0.5 - Math.random()) npcsIds = Object.keys(gameData["npcs"]).sort(() => 0.5 - Math.random());
} }
/**
* Initialize the game, by setting the game data, initializing the socket, rendering the answer
* selection panel, rendering the interrogation view, setting questions buttons listeners,
* setting introduction and interrogation listeners, showing the introduction view and setting the
* introduction image as the game background.
*/
async function initGame() { async function initGame() {
await setGameData(); await setGameData();
initSock(); initSock();
renderAnswerSelectionPanel(); renderAnswerSelectionPanel();
renderInterogation(); renderInterrogation();
setQuestionButtonsListeners() setQuestionButtonsListeners()
setListenerToInterrogationSuspectPreviousBtn() setIntroductionAndInterrogationListeners();
setListenerToIntroductionNextBtn() showFirstClassElement("introduction");
setListenerToInterrogationNextBtn(); setGameBackground(INTRO_IMAGE_PATH);
show("introduction");
setGameBackground(intro_image_path);
} }
initGame(); initGame();

View File

@ -11,7 +11,7 @@
* </p> * </p>
*/ */
function detectIEBrowsers() { function detectIEBrowsers() {
let browserName = window.navigator.userAgent; const browserName = window.navigator.userAgent;
if (browserName.indexOf("MSIE") != -1 || browserName.indexOf("Trident") != -1) { if (browserName.indexOf("MSIE") != -1 || browserName.indexOf("Trident") != -1) {
showUnsupportedBrowserMessage("Il semblerait que vous utilisez Internet Explorer, un navigateur non supporté. Veuillez utiliser un autre navigateur récent tel que Firefox."); showUnsupportedBrowserMessage("Il semblerait que vous utilisez Internet Explorer, un navigateur non supporté. Veuillez utiliser un autre navigateur récent tel que Firefox.");
} }
@ -43,10 +43,10 @@ function checkWebSocketAvailability() {
function createTemporaryCookieThenDeleteIt() { function createTemporaryCookieThenDeleteIt() {
try { try {
// Create a temporary cookie // Create a temporary cookie
document.cookie = "cookietest=1; path=/"; document.cookie = "cookietest=1; SameSite=Strict; Path=/";
let cookieTestResult = document.cookie.indexOf("cookietest=") !== -1; const cookieTestResult = document.cookie.indexOf("cookietest=") !== -1;
// Delete the temporary cookie // Delete the temporary cookie
document.cookie = "cookietest=1; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/"; document.cookie = "cookietest=1; SameSite=Strict; Expires=Thu, 01-Jan-1970 00:00:01 GMT; Path=/";
return cookieTestResult; return cookieTestResult;
} catch (e) { } catch (e) {
return false; return false;
@ -80,7 +80,7 @@ function checkCookiesAvailability() {
*/ */
function showUnsupportedBrowserMessage(messageText) { function showUnsupportedBrowserMessage(messageText) {
showAlertDialog(document.getElementById("unsupported_browser_dialog")); showAlertDialog(document.getElementById("unsupported_browser_dialog"));
let unsupportedBrowserMessageElement = document.getElementsByClassName("unsupported_browser_msg")[0]; const unsupportedBrowserMessageElement = document.querySelector(".unsupported_browser_msg");
unsupportedBrowserMessageElement.textContent = messageText; unsupportedBrowserMessageElement.textContent = messageText;
unsupportedBrowserMessageElement.classList.add("unsupported_show"); unsupportedBrowserMessageElement.classList.add("unsupported_show");
} }
@ -97,7 +97,25 @@ function showUnsupportedBrowserMessage(messageText) {
*/ */
function showAlertDialog(element) { function showAlertDialog(element) {
element.classList.add("alert_dialog_show"); element.classList.add("alert_dialog_show");
document.getElementsByClassName("alert_dialog_background")[0].style.display = "block"; document.querySelector(".alert_dialog_background").style.display = "block";
}
/**
* Show the first element with the given CSS class, by removing the hidden CSS class on it.
*
* @param {String} className the CSS class on which showing the first element found
*/
function showFirstClassElement(className) {
document.querySelector("." + className).classList.remove("hidden");
}
/**
* Hide the first element with the given CSS class, by adding the hidden CSS class on it.
*
* @param {String} className the CSS class on which hiding the first element found
*/
function hideFirstClassElement(className) {
document.querySelector("." + className).classList.add("hidden");
} }
// Execution of main functions // Execution of main functions

View File

@ -13,26 +13,29 @@ function displayInvalidRoundsCountErrorMessage(invalidRoundsCountMessageElement)
* Get the room code and display the room code element. * Get the room code and display the room code element.
*/ */
function displayRoomCode() { function displayRoomCode() {
let roomCode = getRoomCode(); const roomCodeElement = document.querySelector(".room_code");
let roomCodeElement = document.getElementsByClassName("room_code")[0]; const roomCode = getRoomCode();
roomCodeElement.textContent = roomCode; roomCodeElement.textContent = roomCode;
roomCodeElement.setAttribute("href", "/lobby/" + roomCode); roomCodeElement.setAttribute("href", "/lobby/" + roomCode);
document.getElementsByClassName("room_code_text")[0].classList.remove("hidden");
showFirstClassElement("room_code_text");
} }
/** /**
* Display the players list element. * Display the players list element.
*/ */
function displayPlayerList() { function displayPlayerList() {
response = makeAPIRequest("getGameMembers"); const response = makeAPIRequest("getGameMembers");
response.then((value) =>{
player_list = document.getElementsByClassName("player_names")[0];
value["members"].forEach(username => {
player_list.appendChild(document.createTextNode(username+"\n"));
});
response.then(value => {
const playerList = document.querySelector(".player_names");
value["members"].forEach(username => {
playerList.appendChild(document.createTextNode(username + "\n"));
});
}); });
document.getElementsByClassName("players_list")[0].classList.remove("hidden");
showFirstClassElement("players_list");
} }
/** /**
@ -40,29 +43,14 @@ function displayPlayerList() {
* multi_player_mode_choices element. * multi_player_mode_choices element.
*/ */
function displayMultiPlayerModeChoices() { function displayMultiPlayerModeChoices() {
document.getElementsByClassName("multi_player_mode_choices")[0].classList.remove("hidden"); showFirstClassElement("multi_player_mode_choices");
} }
/** /**
* Display the room view, by removing the hidden CSS class on the first room_view element. * Display the room view, by removing the hidden CSS class on the first room_view element.
*/ */
function displayRoomView() { function displayRoomView() {
document.getElementsByClassName("room_view")[0].classList.remove("hidden"); showFirstClassElement("room_view");
}
/**
* Display the join room view, by removing the hidden CSS class on the first join_room_view
* element.
*/
function displayJoinRoomView() {
document.getElementsByClassName("join_room_view")[0].classList.remove("hidden");
}
/**
* Hide the join room view, by removing the hidden CSS class on the first join_room_view element.
*/
function hideJoinRoomView() {
document.getElementsByClassName("join_room_view")[0].classList.add("hidden");
} }
/** /**
@ -70,8 +58,7 @@ function hideJoinRoomView() {
* multi_player_mode_waiting_for_host element. * multi_player_mode_waiting_for_host element.
*/ */
function displayWaitingForHostMessage() { function displayWaitingForHostMessage() {
document.getElementsByClassName("multi_player_mode_waiting_for_host")[0].classList showFirstClassElement("multi_player_mode_waiting_for_host");
.remove("hidden");
} }
/** /**
@ -85,39 +72,25 @@ function displayWaitingForHostMessage() {
* @param {boolean} errorMessage the error message to show * @param {boolean} errorMessage the error message to show
*/ */
function displayInvalidNickNameErrorMessage(errorMessage) { function displayInvalidNickNameErrorMessage(errorMessage) {
let gameStartFailedElement = document.getElementsByClassName("game_start_failed")[0]; let gameStartFailedElement = document.querySelector(".game_start_failed");
gameStartFailedElement.textContent = errorMessage; gameStartFailedElement.textContent = errorMessage;
gameStartFailedElement.classList.remove("hidden"); gameStartFailedElement.classList.remove("hidden");
} }
/**
* Hide an error message on the first game_start_failed CSS element.
*
* <p>
* The element will be hidden by removing the hidden CSS class on the element.
* </p>
*/
function hideInvalidNickNameErrorMessage() {
document.getElementsByClassName("game_start_failed")[0].classList.add("hidden");
}
/**
* Hide the invalid rounds count message element, by adding the hidden CSS class.
*
* @param {Element} invalidRoundsCountMessageElement the invalid rounds counts message
*/
function hideInvalidRoundsCountErrorMessage(invalidRoundsCountMessageElement) {
invalidRoundsCountMessageElement.classList.add("hidden");
}
// Start game functions // Start game functions
/**
* Start a game in the history mode.
*/
function startHistoryGame() { function startHistoryGame() {
makeAPIRequest("startGame"); makeAPIRequest("startGame");
} }
/**
* Start a game in the challenge mode.
*/
function startChallengeGame() { function startChallengeGame() {
let roundsCount = getChallengeModeRoundsCount(); const roundsCount = getChallengeModeRoundsCount();
if (roundsCount == -1) { if (roundsCount == -1) {
return; return;
} }
@ -133,17 +106,20 @@ function joinRoom() {
return; return;
} }
hideInvalidNickNameErrorMessage(); hideFirstClassElement("game_start_failed");
displayWaitingForHostMessage(); displayWaitingForHostMessage();
data = {}
const data = {};
data["username"] = document.getElementById("game_username").value; data["username"] = document.getElementById("game_username").value;
data["game_id"] = getRoomCode(); data["game_id"] = getRoomCode();
response = makeAPIRequest("joinGame",data);
response.then((value)=>{ const response = makeAPIRequest("joinGame", data);
response.then(() => {
displayRoomView(); displayRoomView();
displayPlayerList(); displayPlayerList();
initSock(); initSock();
hideJoinRoomView(); hideFirstClassElement("join_room_view");
}) })
} }
@ -159,12 +135,8 @@ function joinRoom() {
* </p> * </p>
*/ */
function copyCode() { function copyCode() {
// Get the room code from the displayed text to avoid an extra API call const roomCode = getRoomCode();
let roomCode = getRoomCode();
console.log(roomCode);
if (roomCode == "") {
alert("Veuillez patientez, le code d'équipe est en cours de génération.");
}
copyTextToClipboard(window.location.protocol + "//" + window.location.hostname + ":" copyTextToClipboard(window.location.protocol + "//" + window.location.hostname + ":"
+ window.location.port + "/lobby/" + roomCode); + window.location.port + "/lobby/" + roomCode);
} }
@ -179,8 +151,10 @@ function copyCode() {
* </p> * </p>
*/ */
function setListenersToGameButtons() { function setListenersToGameButtons() {
document.getElementById("multi_player_history_start_button").addEventListener("click", startHistoryGame); document.getElementById("multi_player_history_start_button")
document.getElementById("multi_player_challenge_start_button").addEventListener("click", startChallengeGame); .addEventListener("click", startHistoryGame);
document.getElementById("multi_player_challenge_start_button")
.addEventListener("click", startChallengeGame);
} }
/** /**
@ -214,8 +188,10 @@ function setListenerToCopyCodeButton() {
* </p> * </p>
*/ */
function unsetListenersToButtons() { function unsetListenersToButtons() {
document.getElementById("multi_player_history_start_button").removeEventListener("click", startHistoryGame); document.getElementById("multi_player_history_start_button")
document.getElementById("multi_player_challenge_start_button").removeEventListener("click", startChallengeGame); .removeEventListener("click", startHistoryGame);
document.getElementById("multi_player_challenge_start_button")
.removeEventListener("click", startChallengeGame);
} }
/** /**
@ -245,12 +221,12 @@ function unsetListenerToCopyCodeButton() {
// Utility functions // Utility functions
async function isRoomOwner() { async function isRoomOwner() {
response = await makeAPIRequest("isOwner"); const response = await makeAPIRequest("isOwner");
return response["owner"]; return response["owner"];
} }
async function hasJoinedRoom() { async function hasJoinedRoom() {
response = await makeAPIRequest("hasJoined"); const response = await makeAPIRequest("hasJoined");
return response["joined"]; return response["joined"];
} }
@ -262,21 +238,23 @@ async function hasJoinedRoom() {
* </p> * </p>
* *
* <p> * <p>
* This function uses the Clipboard API. In the case it is not supported by the browser used, a JavaScript alert is shown.. * This function uses the Clipboard API. In the case it is not supported by the browser used, a JavaScript alert is shown.
* </p> * </p>
* *
* @param {string}} textToCopy the text to copy to the clipboard * @param {string} textToCopy the text to copy to the clipboard
*/ */
function copyTextToClipboard(textToCopy) { function copyTextToClipboard(textToCopy) {
if (!navigator.clipboard) { if (!navigator.clipboard) {
alert("Votre navigateur ne supporte pas l'API Clipboard. Veuillez copier le texte en ouvrant le menu contextuel de votre navigateur sur le lien et sélectionner l'option pour copier le lien."); alert("Votre navigateur ne supporte pas l'API Clipboard. Veuillez copier le texte en ouvrant le menu contextuel de votre navigateur sur le lien et sélectionner l'option pour copier le lien.");
return; return;
} }
navigator.clipboard.writeText(textToCopy).then(() => {
alert("Lien copié avec succès dans le presse-papiers."); navigator.clipboard.writeText(textToCopy)
}, () => { .then(() => {
alert("Impossible de copier le lien. Vérifiez si vous avez donné la permission d'accès au presse-papiers pour le site de Thruth Inquiry dans les paramètres de votre navigateur."); alert("Lien copié avec succès dans le presse-papiers.");
}); }, () => {
alert("Impossible de copier le lien. Vérifiez si vous avez donné la permission d'accès au presse-papiers pour le site de Thruth Inquiry dans les paramètres de votre navigateur.");
});
} }
/** /**
@ -308,7 +286,8 @@ function isNickNameInvalid() {
*/ */
function getChallengeModeRoundsCount() { function getChallengeModeRoundsCount() {
let roundsCountText = document.getElementById("rounds_count").value; let roundsCountText = document.getElementById("rounds_count").value;
let errorElement = document.getElementsByClassName("multi_player_challenge_mode_invalid_input")[0]; let errorElement = document.querySelector(".multi_player_challenge_mode_invalid_input");
if (!/^\d+$/.test(roundsCountText)) { if (!/^\d+$/.test(roundsCountText)) {
displayInvalidRoundsCountErrorMessage(errorElement); displayInvalidRoundsCountErrorMessage(errorElement);
return -1; return -1;
@ -320,7 +299,7 @@ function getChallengeModeRoundsCount() {
return -1; return -1;
} }
hideInvalidRoundsCountErrorMessage(errorElement); errorElement.classList.add("hidden");
return roundsCountNumber; return roundsCountNumber;
} }
@ -330,27 +309,27 @@ function getChallengeModeRoundsCount() {
* @returns the code of the room * @returns the code of the room
*/ */
function getRoomCode() { function getRoomCode() {
gameid = document.getElementById("game_id").value; return document.getElementById("game_id").value;
return gameid;
} }
function initSock(){ function initSock() {
socket = io({ const socket = io({
auth:{ auth: {
game_id: gameid game_id: getRoomCode()
} }
}); });
socket.on("connect", () => { socket.on("connect", () => {
console.log("Connected !") console.log("Connected to the server!");
}) })
socket.on("gamestart",()=>{ socket.on("gamestart", () => {
window.location.href = "/multi"; window.location.href = "/multi";
}) })
socket.on("playersjoin", (username) => {
player_list = document.getElementsByClassName("player_names")[0]; socket.on("playersjoin", username => {
player_list.appendChild(document.createTextNode(username+"\n")); document.querySelector(".player_names")
.appendChild(document.createTextNode(username + "\n"));
}); });
} }
@ -359,7 +338,7 @@ function initSock(){
/** /**
* Initialize the lobby page. * Initialize the lobby page.
* *
* p> * <p>
* If the player has joined the room, the room view will be shown. In the case the player is the * If the player has joined the room, the room view will be shown. In the case the player is the
* owner of the room, the room code and the multi player mode choice will be shown and the * owner of the room, the room code and the multi player mode choice will be shown and the
* listeners to the game buttons will be done. * listeners to the game buttons will be done.
@ -371,12 +350,10 @@ function initSock(){
* </p> * </p>
*/ */
async function initLobby() { async function initLobby() {
gameid = getRoomCode();
if (await hasJoinedRoom()) { if (await hasJoinedRoom()) {
initSock(); initSock();
displayRoomView(); displayRoomView();
if (await isRoomOwner()) { if (await isRoomOwner()) {
displayRoomCode(); displayRoomCode();
displayMultiPlayerModeChoices(); displayMultiPlayerModeChoices();
@ -388,9 +365,9 @@ async function initLobby() {
displayPlayerList(); displayPlayerList();
} else { } else {
displayJoinRoomView(); showFirstClassElement("join_room_view");
setListenerToJoinRoomButton(); setListenerToJoinRoomButton();
} }
} }
initLobby(); initLobby();

View File

@ -80,7 +80,7 @@
</div> </div>
<div class="reveal_culprit"> <div class="reveal_culprit">
<h2 class="reveal_culprit_title">Le coupable était ...</h2> <h2 class="reveal_culprit_title">Le coupable était ...</h2>
<img class="suspect_picture" id="culprit" src="/static/images/suspect_example.png" alt="Example" draggable="false"> <img class="suspect_picture" id="culprit" draggable="false">
</div> </div>
</div> </div>
<div class="summary"> <div class="summary">
@ -115,19 +115,6 @@
</div> </div>
</div> </div>
</noscript> </noscript>
<!-- buttons to clone in js-->
<button class="ask_button action_button hidden" id="interogationButton">Interroger</button>
<!-- Add culprit_btn_checked class when a choice is checked -->
<!-- Only one button can be checked at a time, so when one is checked, the previous one, if applicable, is unchecked -->
<button class="culprit_btn action_button hidden", id="culpritButton">
<svg class="culprit_checked_icon hidden culprit_icon" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 48 48">
<path d="M18.9 36.75 6.65 24.5l3.3-3.3 8.95 9L38 11.1l3.3 3.25Z"></path>
</svg>
<svg class="culprit_unchecked_icon culprit_icon" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 48 48">
<path d="M12.45 38.7 9.3 35.55 20.85 24 9.3 12.5l3.15-3.2L24 20.8 35.55 9.3l3.15 3.2L27.2 24l11.5 11.55-3.15 3.15L24 27.2Z">
</svg>
<p class="culprit_btn_text">Couplable</p>
</button>
<script src="/static/js/socket.io_v4.4.1/socket.io.min.js"></script> <script src="/static/js/socket.io_v4.4.1/socket.io.min.js"></script>
<script src="/static/js/api.js"></script> <script src="/static/js/api.js"></script>
<script src="/static/js/game_common.js"></script> <script src="/static/js/game_common.js"></script>