415 lines
12 KiB
JavaScript
415 lines
12 KiB
JavaScript
const LOBBY_IMAGE_PATH = "/static/images/cuisine.jpg";
|
|
|
|
// Display functions
|
|
|
|
/*
|
|
* Set the current game background to the first element with the current_background CSS class.
|
|
*/
|
|
function setGameBackground(backgroundPath) {
|
|
document.querySelector(".current_background").style.backgroundImage = 'url("' + backgroundPath + '")';
|
|
}
|
|
|
|
/**
|
|
* Display the invalid rounds count message element, by removing the hidden CSS class.
|
|
*
|
|
* @param {Element} invalidRoundsCountMessageElement the invalid rounds counts message
|
|
*/
|
|
function displayInvalidRoundsCountErrorMessage(invalidRoundsCountMessageElement) {
|
|
invalidRoundsCountMessageElement.classList.remove("hidden");
|
|
}
|
|
|
|
/**
|
|
* Get the room code and display the room code element.
|
|
*/
|
|
function displayRoomCode() {
|
|
const roomCodeElement = document.querySelector(".room_code");
|
|
const roomCode = getRoomCode();
|
|
|
|
roomCodeElement.textContent = roomCode;
|
|
roomCodeElement.setAttribute("href", "/lobby/" + roomCode);
|
|
|
|
showFirstClassElement("room_code_text");
|
|
}
|
|
|
|
/**
|
|
* Display the players list element.
|
|
*/
|
|
function displayPlayerList() {
|
|
showFirstClassElement("players_list");
|
|
}
|
|
|
|
/**
|
|
* Display the multi player mode choices, by removing the hidden CSS class on the first
|
|
* multi_player_mode_choices element.
|
|
*/
|
|
function displayMultiPlayerModeChoices() {
|
|
showFirstClassElement("multi_player_mode_choices");
|
|
}
|
|
|
|
/**
|
|
* Display the room view, by removing the hidden CSS class on the first room_view element.
|
|
*/
|
|
function displayRoomView() {
|
|
showFirstClassElement("room_view");
|
|
}
|
|
|
|
/**
|
|
* Display the room view, by removing the hidden CSS class on the first
|
|
* multi_player_mode_waiting_for_host element.
|
|
*/
|
|
function displayWaitingForHostMessage() {
|
|
showFirstClassElement("multi_player_mode_waiting_for_host");
|
|
}
|
|
|
|
/**
|
|
* Show an error message on the first game_start_failed CSS element.
|
|
*
|
|
* <p>
|
|
* The current error message text will be replaced by the given message and the element will be
|
|
* shown, by removing the hidden CSS class on the element.
|
|
* </p>
|
|
*
|
|
* @param {string} errorMessage the error message to show
|
|
*/
|
|
function displayInvalidNickNameErrorMessage(errorMessage) {
|
|
let gameStartFailedElement = document.querySelector(".game_start_failed");
|
|
gameStartFailedElement.textContent = errorMessage;
|
|
gameStartFailedElement.classList.remove("hidden");
|
|
}
|
|
|
|
// Start game functions
|
|
|
|
/**
|
|
* Start a game in the history mode.
|
|
*/
|
|
function startHistoryGame(startHistoryGameButton) {
|
|
startHistoryGameButton.target.textContent = "Chargement\u00A0...";
|
|
makeAPIRequest("startGame").then(null, () => {
|
|
startHistoryGameButton.target.textContent = "Jouer";
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Start a game in the challenge mode.
|
|
*/
|
|
function startChallengeGame() {
|
|
const roundsCount = getChallengeModeRoundsCount();
|
|
if (roundsCount == -1) {
|
|
return;
|
|
}
|
|
|
|
alert("Ce mode de jeu n'est malheureusement pas disponible.");
|
|
}
|
|
|
|
function getMembers() {
|
|
const data = {};
|
|
data['game_id'] = getRoomCode();
|
|
|
|
const response = makeAPIRequest("getGameMembers", data);
|
|
response.then(value => {
|
|
for (const playerList of document.getElementsByClassName("player_names")) {
|
|
value["members"].forEach(username => {
|
|
playerList.appendChild(document.createTextNode(username + "\n"));
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
// Join room functions
|
|
|
|
/**
|
|
* This function read the username join an already existing game,
|
|
* to do so it calls the joinGame endpoint with the aftermentioned
|
|
* username as parameter. If the request succeeds the lobby view
|
|
* is displayed.
|
|
*/
|
|
function joinRoom() {
|
|
if (isNickNameInvalid()) {
|
|
displayInvalidNickNameErrorMessage("Le nom saisi n'est pas valide.");
|
|
return;
|
|
}
|
|
|
|
hideFirstClassElement("game_start_failed");
|
|
displayWaitingForHostMessage();
|
|
|
|
const data = {};
|
|
data["username"] = document.getElementById("game_username").value;
|
|
data["game_id"] = getRoomCode();
|
|
|
|
const response = makeAPIRequest("joinGame", data);
|
|
|
|
response.then(() => {
|
|
displayRoomView();
|
|
displayPlayerList();
|
|
hideFirstClassElement("join_room_view");
|
|
})
|
|
}
|
|
|
|
// Room code functions
|
|
|
|
/**
|
|
* Copy the room code to the clipboard.
|
|
*
|
|
* <p>
|
|
* In order to not make an additional API call to get the room code, we use the value from the
|
|
* room code HTML element and generate a HTTP link from this value, copied to the clipboard using
|
|
* {@link copyTextToClipboard}.
|
|
* </p>
|
|
*/
|
|
function copyCode() {
|
|
const roomCode = getRoomCode();
|
|
|
|
copyTextToClipboard(window.location.protocol + "//" + window.location.hostname + ":"
|
|
+ window.location.port + "/lobby/" + roomCode);
|
|
}
|
|
|
|
// Listeners functions
|
|
|
|
/**
|
|
* Set listeners to game buttons.
|
|
*
|
|
* <p>
|
|
* This function adds a click event listener on start game buttons.
|
|
* </p>
|
|
*/
|
|
function setListenersToGameButtons() {
|
|
document.getElementById("multi_player_history_start_button")
|
|
.addEventListener("click", startHistoryGame);
|
|
document.getElementById("multi_player_challenge_start_button")
|
|
.addEventListener("click", startChallengeGame);
|
|
}
|
|
|
|
/**
|
|
* Set listeners to the join room button.
|
|
*
|
|
* <p>
|
|
* This function adds a click event listener on the join room button.
|
|
* </p>
|
|
*/
|
|
function setListenerToJoinRoomButton() {
|
|
document.getElementById("join_game_button").addEventListener("click", joinRoom);
|
|
}
|
|
|
|
/**
|
|
* Set listeners to the copy room code button.
|
|
*
|
|
* <p>
|
|
* This function adds a click event listener on the copy room code button.
|
|
* </p>
|
|
*/
|
|
function setListenerToCopyCodeButton() {
|
|
document.getElementById("invite_friends_button").addEventListener("click", copyCode);
|
|
}
|
|
|
|
/**
|
|
* Unset listeners to game buttons.
|
|
*
|
|
* <p>
|
|
* This function removes the click event listener set with {@link setListenersToGameButtons} on
|
|
* start game buttons.
|
|
* </p>
|
|
*/
|
|
function unsetListenersToButtons() {
|
|
document.getElementById("multi_player_history_start_button")
|
|
.removeEventListener("click", startHistoryGame);
|
|
document.getElementById("multi_player_challenge_start_button")
|
|
.removeEventListener("click", startChallengeGame);
|
|
}
|
|
|
|
/**
|
|
* Unset listeners to the join room button.
|
|
*
|
|
* <p>
|
|
* This function removes the click event listener set with {@link setListenerToJoinRoomButton} on
|
|
* the join room button.
|
|
* </p>
|
|
*/
|
|
function unsetListenerToJoinRoomButton() {
|
|
document.getElementById("join_game_button").removeEventListener("click", joinRoom);
|
|
}
|
|
|
|
/**
|
|
* Unset listeners to the copy room code button.
|
|
*
|
|
* <p>
|
|
* This function removes the click event listener set with {@link setListenerToCopyCodeButton} on
|
|
* the copy room code button.
|
|
* </p>
|
|
*/
|
|
function unsetListenerToCopyCodeButton() {
|
|
document.getElementById("invite_friends_button").removeEventListener("click", copyCode);
|
|
}
|
|
|
|
/**
|
|
* This predicate asks the server is the current player is the owner of the
|
|
* room stored in the session cookie.
|
|
* @returns {boolean} true if the player is the owner of the game, false otherwise
|
|
*/
|
|
async function isRoomOwner() {
|
|
const response = await makeAPIRequest("isOwner");
|
|
return response["owner"];
|
|
}
|
|
|
|
/**
|
|
* This predicate asks the server is the current player has joined the
|
|
* room stored in the session cookie.
|
|
* @returns {boolean} true if the player has joined the game, false otherwise
|
|
*/
|
|
async function hasJoinedRoom() {
|
|
const response = await makeAPIRequest("hasJoined");
|
|
return response["joined"];
|
|
}
|
|
|
|
/**
|
|
* Copy the given text in the clipboard, if the browser allows it.
|
|
*
|
|
* <p>
|
|
* A JavaScript alert is created witn an appropriate message, regardless of whether the copy succeeded.
|
|
* </p>
|
|
*
|
|
* <p>
|
|
* This function uses the Clipboard API. In the case it is not supported by the browser used, a JavaScript alert is shown.
|
|
* </p>
|
|
*
|
|
* @param {string} textToCopy the text to copy to the clipboard
|
|
*/
|
|
function copyTextToClipboard(textToCopy) {
|
|
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.");
|
|
return;
|
|
}
|
|
|
|
navigator.clipboard.writeText(textToCopy)
|
|
.then(() => {
|
|
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.");
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Determine whether a nickname is invalid.
|
|
*
|
|
* <p>
|
|
* A nickname is invalid when it only contains spaces characters or is empty.
|
|
* </p>
|
|
*
|
|
* @returns whether a nickname is invalid
|
|
*/
|
|
function isNickNameInvalid() {
|
|
return document.getElementById("game_username").value.trim() == "";
|
|
}
|
|
|
|
/**
|
|
* Get the rounds count for the challenge mode from the user input.
|
|
*
|
|
* <p>
|
|
* As browsers allow to enter any character on a number imput, we need to validate the user value.
|
|
* A regular expression which checks that every character is a number digit is used.
|
|
* </p>
|
|
*
|
|
* <p>
|
|
* If the user input isn't matched by the regular expression, an error message is shown to the user.
|
|
* </p>
|
|
*
|
|
* @returns the rounds count or -1 if it is invalid
|
|
*/
|
|
function getChallengeModeRoundsCount() {
|
|
let roundsCountText = document.getElementById("rounds_count").value;
|
|
let errorElement = document.querySelector(".multi_player_challenge_mode_invalid_input");
|
|
|
|
if (!/^\d+$/.test(roundsCountText)) {
|
|
displayInvalidRoundsCountErrorMessage(errorElement);
|
|
return -1;
|
|
}
|
|
|
|
let roundsCountNumber = parseInt(roundsCountText);
|
|
if (roundsCountNumber < 5 || roundsCountNumber > 15) {
|
|
displayInvalidRoundsCountErrorMessage(errorElement);
|
|
return -1;
|
|
}
|
|
|
|
errorElement.classList.add("hidden");
|
|
return roundsCountNumber;
|
|
}
|
|
|
|
/**
|
|
* Get the code of the room.
|
|
*
|
|
* @returns the code of the room
|
|
*/
|
|
function getRoomCode() {
|
|
return document.getElementById("game_id").value;
|
|
}
|
|
|
|
/**
|
|
* Initialize the websocket for this page, its primary use is to
|
|
* show in realtime players joining the room and to start the game
|
|
* of every player in the same time when the game owner starts the
|
|
* gane
|
|
*/
|
|
function initSock() {
|
|
const socket = io({
|
|
auth: {
|
|
game_id: getRoomCode()
|
|
}
|
|
});
|
|
|
|
socket.on("connect", () => {
|
|
console.log("Connected to the server!");
|
|
})
|
|
|
|
socket.on("gamestart", async () => {
|
|
if (await hasJoinedRoom()) {
|
|
window.location.href = "/multi";
|
|
}
|
|
})
|
|
|
|
socket.on("playersjoin", username => {
|
|
for (const playerList of document.getElementsByClassName("player_names")) {
|
|
playerList.textContent += username + "\n";
|
|
}
|
|
});
|
|
}
|
|
|
|
// Lobby initialization
|
|
|
|
/**
|
|
* Initialize the lobby page.
|
|
*
|
|
* <p>
|
|
* 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
|
|
* listeners to the game buttons will be done.
|
|
* </p>
|
|
*
|
|
* <p>
|
|
* If the player has not joined the room, the join room view will be shown and a listener to the
|
|
* join room button will be set.
|
|
* </p>
|
|
*/
|
|
async function initLobby() {
|
|
setGameBackground(LOBBY_IMAGE_PATH);
|
|
getMembers();
|
|
initSock();
|
|
if (await hasJoinedRoom()) {
|
|
displayRoomView();
|
|
|
|
if (await isRoomOwner()) {
|
|
displayRoomCode();
|
|
displayMultiPlayerModeChoices();
|
|
setListenersToGameButtons();
|
|
setListenerToCopyCodeButton();
|
|
} else {
|
|
displayWaitingForHostMessage();
|
|
}
|
|
|
|
displayPlayerList();
|
|
} else {
|
|
showFirstClassElement("join_room_view");
|
|
setListenerToJoinRoomButton();
|
|
}
|
|
}
|
|
|
|
initLobby();
|