diff --git a/frontend/static/css/TournamentPage.css b/frontend/static/css/TournamentPage.css new file mode 100644 index 0000000..d9c826b --- /dev/null +++ b/frontend/static/css/TournamentPage.css @@ -0,0 +1,51 @@ +#tournament-tree { + display:flex; + flex-direction:row; +} + +.round { + display:flex; + flex-direction:column; + justify-content:center; + width:200px; + list-style:none; + padding:0; +} + +.round .spacer{ flex-grow:1; } +.round .spacer:first-child, +.round .spacer:last-child{ flex-grow:.5; } + +.round .game-spacer{ + flex-grow:1; +} + +body{ + font-family:sans-serif; + font-size:small; + padding:10px; + line-height:1.4em; +} + +li.game{ +padding-left:20px; +} + +li.game.winner{ + font-weight:bold; +} +li.game span{ + float:right; + margin-right:5px; +} + +li.game-top{ border-bottom:1px solid #aaa; } + +li.game-spacer{ + border-right:1px solid #aaa; + min-height:40px; +} + +li.game-bottom{ + border-top:1px solid #aaa; +} \ No newline at end of file diff --git a/frontend/static/js/api/Matchmaking.js b/frontend/static/js/api/Matchmaking.js index 7081c5e..b0e2240 100644 --- a/frontend/static/js/api/Matchmaking.js +++ b/frontend/static/js/api/Matchmaking.js @@ -21,14 +21,12 @@ class MatchMaking * @param {Number} mode The number of players in a game * @returns {Promise>} */ - async start(receive_func, disconnect_func, mode, gamemode) + async start(receive_func, disconnect_func, gamemode, mode) { if (!await this.client.isAuthenticated()) return null; - this.gamemode = gamemode - - let url = `${window.location.protocol[4] === 's' ? 'wss' : 'ws'}://${window.location.host}/ws/matchmaking/${mode}`; + let url = `${window.location.protocol[4] === 's' ? 'wss' : 'ws'}://${window.location.host}/ws/matchmaking/${gamemode}/${mode}`; this._socket = new WebSocket(url); @@ -51,10 +49,7 @@ class MatchMaking this.disconnect_func(event); } - /** - * @returns {Promise>} - */ - async stop() + stop() { if (this._socket) this._socket.close(); diff --git a/frontend/static/js/api/tournament/Tournament.js b/frontend/static/js/api/tournament/Tournament.js index e5e4682..2d727ce 100644 --- a/frontend/static/js/api/tournament/Tournament.js +++ b/frontend/static/js/api/tournament/Tournament.js @@ -102,7 +102,7 @@ class Tourmanent return; this.connected = false; this._socket.close(); - this.disconnect_func(event); + this.disconnectHandler(event); } toggle_participation() @@ -112,13 +112,40 @@ class Tourmanent this._socket.send(JSON.stringify({participate: ""})); } + async onParticipantsUpdate(data) + { + oldParticipantList = this.par + + await this.participantsUpdateHandler(); + } + + async onError(data) + { + await this.errorHandler(data); + } + + /** + * + * @param {MessageEvent} event + */ + onReceive(event) + { + const data = JSON.parse(event.data); + + if (data?.detail === "error") + this.onError(data); + else if (data?.detail === "participants_update") + this.onParticipantsUpdate(data); + } + /** * Join the tournament Websocket - * @param {CallableFunction} receive_func - * @param {CallableFunction} disconnect_func + * @param {CallableFunction} errorHandler + * @param {CallableFunction} participantsUpdateHandler + * @param {CallableFunction} disconnectHandler * @returns {?} */ - async join(receive_func, disconnect_func) + async join(participantsUpdateHandler, errorHandler, disconnectHandler) { if (!await this.client.isAuthenticated()) return null; @@ -130,13 +157,11 @@ class Tourmanent this.connected = true; this.isParticipating = false; - this.receive_func = receive_func; - this.disconnect_func = disconnect_func; + this.participantsUpdateHandler = participantsUpdateHandler; + this.errorHandler = errorHandler; + this.disconnectHandler = disconnectHandler; - this._socket.onmessage = function (event) { - const data = JSON.parse(event.data); - receive_func(data); - }; + this._socket.onmessage = this.onReceive.bind(this); this._socket.onclose = this.leave.bind(this); } diff --git a/frontend/static/js/views/MatchMakingView.js b/frontend/static/js/views/MatchMakingView.js index 6ca775e..6c45c43 100644 --- a/frontend/static/js/views/MatchMakingView.js +++ b/frontend/static/js/views/MatchMakingView.js @@ -19,8 +19,7 @@ export default class extends AbstractAuthenticatedView { } else { - let nb_players = this.input.value; - await client.matchmaking.start(this.onreceive.bind(this), this.ondisconnect.bind(this), nb_players, this.gamemode); + await client.matchmaking.start(this.onreceive.bind(this), this.ondisconnect.bind(this), this.gamemode_input.value, this.nb_players_input.value); this.button.innerHTML = lang.get("matchmakingStopSearch"); } @@ -29,6 +28,7 @@ export default class extends AbstractAuthenticatedView { ondisconnect(event) { this.button.innerHTML = lang.get("matchmakingStartSearch"); + clearIds("innerText", ["detail"]); } onreceive(data) @@ -36,9 +36,9 @@ export default class extends AbstractAuthenticatedView { if (data.detail === "game_found") { if (this.gamemode.value == "pong") - navigateTo(`/games/${data.game_id}`); + navigateTo(`/games/${data.gamemode}/${data.game_id}`); else - navigateTo(`/games/${this.gamemode.value}/${data.game_id}`); + navigateTo(`/games/${data.gamemode}/${data.game_id}`); return; } this.display_data(data); @@ -50,59 +50,83 @@ export default class extends AbstractAuthenticatedView { fill_errors(data, "innerText"); } - async postInit() + addEnterEvent() { - this.button = document.getElementById("toggle-search"); - this.input = document.getElementById("nb-players-input"); - this.gamemode = document.getElementById("game-choice"); + console.log(this.nb_players_input, this.gamemode_input); - let container = document.getElementById("nb-players-container"); - let gameChoice = document.getElementById("game-choice"); + [this.nb_players_input, this.gamemode_input].forEach((input) => { - this.button.onclick = this.toggle_search.bind(this); + input.addEventListener('keydown', async ev => { - this.input.addEventListener('keydown', async ev => { + if (ev.key !== 'Enter') + return; - if (ev.key !== 'Enter') - return; - - await this.toggle_search.bind(this); + await this.toggle_search.bind(this); + }); }); + } - gameChoice.addEventListener("change", function() - { - if (this.value === "tictactoe") - { - container.style.display = 'none'; - document.getElementById("nb-players-input").value = 2; - } - else - container.style.display = 'block'; - }) - + addChangeNbPlayersEvent() + { let update = () => { this.button.disabled = (this.input.value < 2 || this.input.value > 4); }; ["change", "oninput"].forEach((event_name) => { - this.input.addEventListener(event_name, update); + this.nb_players_input.addEventListener(event_name, update); }); } + addChangeGameModeEvent() + { + let nb_players_div = document.getElementById("nb-players-div"); + + this.gamemode_input.addEventListener("change", () => { + + if (this.gamemode_input.value === "tictactoe") + { + nb_players_div.style.display = 'none'; + this.nb_players_input.value = 2; + } + else + nb_players_div.style.display = 'block'; + + client.matchmaking.stop(); + }); + } + + addEvents() + { + this.addEnterEvent(); + this.addChangeGameModeEvent(); + this.addChangeNbPlayersEvent(); + } + + async postInit() + { + this.button = document.getElementById("toggle-search"); + this.nb_players_input = document.getElementById("nb-players-input"); + this.gamemode_input = document.getElementById("gamemode-input"); + + this.button.onclick = this.toggle_search.bind(this); + + this.addEvents() + } + async getHtml() { return /* HTML */ `