From: Benjamin Auder Date: Wed, 16 Jan 2019 17:37:13 +0000 (+0100) Subject: Almost finished components drafts X-Git-Url: https://git.auder.net/doc/html/pieces/current/common.css?a=commitdiff_plain;h=214dfe16b01836fb19291ebf209bb7035993bafe;p=vchess.git Almost finished components drafts --- diff --git a/public/javascripts/components/TODO_FIND_NAME_gameList.js b/public/javascripts/components/TODO_FIND_NAME_gameList.js new file mode 100644 index 00000000..bd0dde10 --- /dev/null +++ b/public/javascripts/components/TODO_FIND_NAME_gameList.js @@ -0,0 +1,5 @@ +// TODO: variable "display" at "corr", "imported" or "local" (e.g. ...) +//My games : (tabs) +//mes parties corr en cours +//mes parties (toutes) terminées (possibilité de supprimer) +//parties importées diff --git a/public/javascripts/components/challengeList.js b/public/javascripts/components/challengeList.js index bc2ebd03..66e809e1 100644 --- a/public/javascripts/components/challengeList.js +++ b/public/javascripts/components/challengeList.js @@ -1,2 +1,31 @@ -//TODO (avec newGame button ?!) -// ou challengeSummary organisé dans room... +Vue.component("my-challenge-list", { + props: ["challenges"], + computed: { + showVariant: function() { + this.challenges.length > 0 && !!this.challenges[0].variant; + }, + showNbPlayers: function() { + this.challenges.length > 0 && !!this.challenges[0].nbPlayers; + }, + }, + template: ` + + + + + + + + + + + + + + + +
VariantFromToCadenceNumber of players
{{ c.variant }}{{ c.from.name }} + {{ p.name }} + {{ c.mainTime }} + {{ c.increment }}{{ c.nbPlayers }}
+ `, +}); diff --git a/public/javascripts/components/chat.js b/public/javascripts/components/chat.js index 5dce3077..b9bc7986 100644 --- a/public/javascripts/components/chat.js +++ b/public/javascripts/components/chat.js @@ -1,100 +1,67 @@ // TODO: myname, opppnents (optional, different style), people // --> also show messages like "X offers draw ?" (probably not) - - -myname: localStorage["username"] || "anonymous", - oppName: "anonymous", //opponent name, revealed after a game (if provided) +// myname: localStorage["username"] || "anonymous", +Vue.component("my-chat", { + props: ["conn","myname","opponents","people"], + data: function() { + return { chats: [], //chat messages after human game - - - - let chatEltsArray = - [ - h('label', - { - attrs: { "id": "close-chat", "for": "modal-chat" }, - "class": { "modal-close": true }, - } - ), - h('h3', - { - attrs: { "id": "titleChat" }, - "class": { "section": true }, - domProps: { innerHTML: translations["Chat with "] + this.oppName }, - } - ) - ]; - for (let chat of this.chats) - { - chatEltsArray.push( - h('p', - { - "class": { - "my-chatmsg": chat.author==this.myid, - "opp-chatmsg": chat.author==this.oppid, - }, - domProps: { innerHTML: chat.msg } - } - ) - ); - } - chatEltsArray = chatEltsArray.concat([ - h('input', - { - attrs: { - "id": "input-chat", - type: "text", - placeholder: translations["Type here"], - }, - on: { keyup: this.trySendChat }, //if key is 'enter' - } - ), - h('button', - { - attrs: { id: "sendChatBtn"}, - on: { click: this.sendChat }, - domProps: { innerHTML: translations["Send"] }, - } - ) - ]); - const modalChat = [ - h('input', - { - attrs: { "id": "modal-chat", type: "checkbox" }, - "class": { "modal": true }, - }), - h('div', - { - attrs: { "role": "dialog", "aria-labelledby": "titleChat" }, - }, - [ - h('div', - { - "class": { "card": true, "smallpad": true }, - }, - chatEltsArray - ) - ] - ) - ]; - elementArray = elementArray.concat(modalChat); - - + }; + }, + // TODO: Chat modal sur petit écran, dans la page pour grand écran + template: ` +
+ +
+
+ +

+ {{ translate("Chat with ") }} + {{ o.name }} +

+

o.id == chat.uid)"} + > + {{ chat.msg }} +

+ + +
+
+
+ `, + created: function() { + const socketMessageListener = msg => { + const data = JSON.parse(msg.data); + switch (data.code) + { case "newchat": - // Receive new chat + // TODO: new chat just arrived: data contain all informations + // (uid, name, message; no need for timestamp, we can use local time here) this.chats.push({msg:data.msg, author:this.oppid}); break; - case "oppname": - // Receive opponent's name - this.oppName = data.name; + // TODO: distinguish these (dis)connect events from their analogs in game.js + // TODO: implement and harmonize: opponents and people are arrays, not objects ?! + case "connect": + this.players.push({name:data.name, id:data.uid}); break; - - - // TODO: complete this component - trySendChat: function(e) { - if (e.keyCode == 13) //'enter' key - this.sendChat(); - }, + case "disconnect": + const pIdx = this.players.findIndex(p => p.id == data.uid); + this.players.splice(pIdx); + break; + } + }; + const socketCloseListener = () => { + this.conn.addEventListener('message', socketMessageListener); + this.conn.addEventListener('close', socketCloseListener); + }; + this.conn.onmessage = socketMessageListener; + this.conn.onclose = socketCloseListener; + }, + methods: { + // TODO: complete this component sendChat: function() { let chatInput = document.getElementById("input-chat"); const chatTxt = chatInput.value; @@ -103,8 +70,8 @@ myname: localStorage["username"] || "anonymous", this.conn.send(JSON.stringify({ code:"newchat", oppid: this.oppid, msg: chatTxt})); }, - startChat: function(e) { - this.getRidOfTooltip(e.currentTarget); - document.getElementById("modal-chat").checked = true; - }, - +// startChat: function(e) { +// document.getElementById("modal-chat").checked = true; +// }, + }, +}); diff --git a/public/javascripts/components/game.js b/public/javascripts/components/game.js index dd9cfe4b..ef385592 100644 --- a/public/javascripts/components/game.js +++ b/public/javascripts/components/game.js @@ -128,6 +128,13 @@ Vue.component('my-game', { this.vr = new VariantRules(this.fen); this.fenStart = this.fen; } + // TODO: if I'm one of the players in game, then: + // Send ping to server (answer pong if opponent is connected) + if (true && !!this.conn) + { + this.conn.send(JSON.stringify({ + code:"ping",oppid:this.oppid,gameId:this.gameId})); + } // TODO: also handle "draw accepted" (use opponents array?) // --> must give this info also when sending lastState... // and, if all players agree then OK draw (end game ...etc) diff --git a/public/javascripts/components/gameList.js b/public/javascripts/components/gameList.js index 371c89b9..fcbb39a2 100644 --- a/public/javascripts/components/gameList.js +++ b/public/javascripts/components/gameList.js @@ -1,5 +1,24 @@ -// TODO -//My games : (tabs) -//mes parties corr en cours -//mes parties (toutes) terminées (possibilité de supprimer) -//parties importées +Vue.component("my-game-list", { + props: ["games"], + computed: { + showResult: function() { + this.games.length > 0 && this.games[0].score != "*"; + }, + }, + template: ` + + + + + + + + + + +
Players namesCadence +
+ {{ p.name }} + {{ g.mainTime }} + {{ g.increment }}{{ g.score }}
+ `, +}); diff --git a/public/javascripts/components/gameSummary.js b/public/javascripts/components/gameSummary.js deleted file mode 100644 index 8ad1dfb5..00000000 --- a/public/javascripts/components/gameSummary.js +++ /dev/null @@ -1 +0,0 @@ -//TODO diff --git a/public/javascripts/components/playerList.js b/public/javascripts/components/playerList.js deleted file mode 100644 index 8ad1dfb5..00000000 --- a/public/javascripts/components/playerList.js +++ /dev/null @@ -1 +0,0 @@ -//TODO diff --git a/public/javascripts/components/room.js b/public/javascripts/components/room.js index d3dda053..47370fb2 100644 --- a/public/javascripts/components/room.js +++ b/public/javascripts/components/room.js @@ -1,30 +1,23 @@ -// TODO: main playing hall, chat + online players + current challenges + button "new game" -/* -input#modal-newgame.modal(type="checkbox") -div(role="dialog" aria-labelledby="newGameTxt") - .card.smallpad.small-modal - label#close-newgame.modal-close(for="modal-newgame") - h3#newGameTxt= translations["New game"] - p= translations["Waiting for opponent..."] -*/ +// main playing hall: chat + online players + current challenges + button "new game" // TODO: my-challenge-list, gérant clicks sur challenges, affichage, réception/émission des infos sur challenges ; de même, my-player-list // TODO: si on est en train de jouer une partie, le notifier aux nouveaux connectés /* -Players + challenges : == "room" home of variant (surligner si nouveau défi perso et pas affichage courant) -joueurs en ligne (dte), -Nouvelle partie + défis en temps réel + parties en cours (milieu, tabs), -chat général (gauche, activé ou non (bool global storage)). +TODO: surligner si nouveau défi perso et pas affichage courant (cadences base + incrément, corr == incr >= 1jour ou base >= 7j) ---> correspondance: stocker sur serveur lastMove + peerId + color + movesCount + gameId + variant + timeleft -quand je poste un lastMove corr, supprimer mon ancien lastMove le cas échéant (tlm l'a eu) -fin de partie corr: garder maxi nbPlayers lastMove sur serveur, pendant 7 jours (arbitraire) +--> correspondance: stocker sur serveur lastMove + uid + color + movesCount + gameId + variant + timeleft +fin de partie corr: supprimer partie du serveur au bout de 7 jours (arbitraire) +main time should be positive (no 0+2 & cie...) */ // TODO: au moins l'échange des coups en P2P ? +// TODO: objet game, objet challenge ? et player ? Vue.component('my-room', { props: ["conn","settings"], data: { - remoteGames: [], + gdisplay: "live", + liveGames: [], corrGames: [], + players: [], //online players + challenges: [], //live challenges }, // Modal new game, and then sub-components template: ` @@ -39,36 +32,64 @@ Vue.component('my-room', {

TODO: cadence, adversaire (pre-filled if click on name)

-

Note: leave FEN blank for random

+

cadence 2m+12s ou 7d+1d (m,s ou d,d) --> main, increment

+

Note: leave FEN blank for random; FEN only for targeted challenge

- + +
+
- - // TODO: also corr games (of pther players) - // presentation ? table ?! - - +
+
+ {{ p.name }} +
+
+
+ +
+ + + +
`, created: function() { - // TODO: ask server for current corr games (all but mines) + // TODO: ask server for current corr games (all but mines: names, ID, time control) const socketMessageListener = msg => { const data = JSON.parse(msg.data); switch (data.code) { - // TODO: also receive remote games summaries (update) + case "newgame": + // TODO: new game just started: data contain all informations + // (id, players, time control, fenStart ...) + break; + // TODO: also receive live games summaries (update) // (just players names, time control, and ID + player ID) - case "newgame": //challenge accepted + case "acceptchallenge": // oppid: opponent socket ID (or DB id if registered) - this.newGame("human", data.fen, data.color, data.oppid, data.gameid); + if (true) //TODO: if challenge is full + this.newGame(data.challenge, data.user); //user.id et user.name + break; + case "withdrawchallenge": + // TODO + break; + case "cancelchallenge": + // TODO + break; + // TODO: distinguish these (dis)connect events from their analogs in game.js + case "connect": + this.players.push({name:data.name, id:data.uid}); + break; + case "disconnect": + const pIdx = this.players.findIndex(p => p.id == data.uid); + this.players.splice(pIdx); break; } }; @@ -80,74 +101,49 @@ Vue.component('my-room', { this.conn.onclose = socketCloseListener; }, methods: { - clickGameSeek: function(e) { - if (this.mode == "human" && this.score == "*") - return; //no newgame while playing - if (this.seek) + showGame: function(game) { + let hash = "#game?id=" + game.id; + if (!!game.uid) + hash += "&uid=" + game.uid; + location.hash = hash; + }, + challenge: function(player) { + this.conn.send(JSON.stringify({code:"sendchallenge", oppid:p.id, + user:{name:user.name,id:user.id})); + }, + clickChallenge: function(challenge) { + const index = this.challenges.findIndex(c => c.id == challenge.id); + const toIdx = challenge.to.findIndex(p => p.id == user.id); + const me = {name:user.name,id:user.id}; + if (toIdx >= 0) { - this.conn.send(JSON.stringify({code:"cancelnewgame"})); - this.seek = false; + // It's a multiplayer challenge I accepted: withdraw + this.conn.send(JSON.stringify({code:"withdrawchallenge", + cid:challenge.id, user:me})); + this.challenges.to.splice(toIdx, 1); } - else - this.newGame("human"); - }, - newGame: function(mode, fenInit, color, oppId, gameId) { - const fen = fenInit || VariantRules.GenRandInitFen(); - console.log(fen); //DEBUG - if (mode=="human" && !oppId) + else if (challenge.from.id == user.id) //it's my challenge: cancel it { - const storageVariant = localStorage.getItem("variant"); - if (!!storageVariant && storageVariant !== variant.name - && localStorage["score"] == "*") - { - return alert(translations["Finish your "] + - storageVariant + translations[" game first!"]); - } - // Send game request and wait.. - try { - this.conn.send(JSON.stringify({code:"newgame", fen:fen, gameid: getRandString() })); - } catch (INVALID_STATE_ERR) { - return; //nothing achieved - } - this.seek = true; - let modalBox = document.getElementById("modal-newgame"); - modalBox.checked = true; - setTimeout(() => { modalBox.checked = false; }, 2000); - return; + this.conn.send(JSON.stringify({code:"cancelchallenge", cid:challenge.id})); + this.challenges.splice(index, 1); } - this.vr = new VariantRules(fen, []); - this.score = "*"; - this.pgnTxt = ""; //redundant with this.score = "*", but cleaner - this.mode = mode; - this.incheck = []; - this.fenStart = V.ParseFen(fen).position; //this is enough - if (mode=="human") + else //accept a challenge { - // Opponent found! - this.gameId = gameId; - this.oppid = oppId; - this.oppConnected = true; - this.mycolor = color; - this.seek = false; - if (this.sound >= 1) - new Audio("/sounds/newgame.mp3").play().catch(err => {}); - document.getElementById("modal-newgame").checked = false; + this.conn.send(JSON.stringify({code:"acceptchallenge", + cid:challenge.id, user:me})); + this.challenges[index].to.push(me); } - this.setStorage(); //store game state in case of interruptions }, - continueGame: function() { - this.oppid = localStorage.getItem("oppid"); - this.mycolor = localStorage.getItem("mycolor"); - const moves = JSON.parse(localStorage.getItem("moves")); - const fen = localStorage.getItem("fen"); - const score = localStorage.getItem("score"); //always "*" ?! - this.fenStart = localStorage.getItem("fenStart"); - this.vr = new VariantRules(fen); - this.incheck = this.vr.getCheckSquares(this.vr.turn); - this.gameId = localStorage.getItem("gameId"); - // Send ping to server (answer pong if opponent is connected) - this.conn.send(JSON.stringify({ - code:"ping",oppid:this.oppid,gameId:this.gameId})); + // user: last person to accept the challenge + newGame: function(chall, user) { + const fen = chall.fen || VariantRules.GenRandInitFen(); + const game = {}; //TODO: fen, players, time ... + //setStorage(game); //TODO + game.players.forEach(p => { + this.conn.send(JSON.stringify({code:"newgame", oppid:p.id, game:game}); + }); + if (this.settings.sound >= 1) + new Audio("/sounds/newgame.mp3").play().catch(err => {}); }, }, }); diff --git a/views/index.pug b/views/index.pug index 377aef94..51df9235 100644 --- a/views/index.pug +++ b/views/index.pug @@ -37,6 +37,7 @@ block content .row(v-show="display=='games'") .col-sm-12.col-md-10.col-md-offset-1.col-lg-8.col-lg-offset-2 p TODO: load from server, show timeControl + players + link "play" + p Also tab for current challenges + button "new game" block javascripts script. diff --git a/views/variant.pug b/views/variant.pug index 5ea6c463..a3b00899 100644 --- a/views/variant.pug +++ b/views/variant.pug @@ -29,7 +29,7 @@ block content include userMenu .row my-room(v-show="display=='room'") - //my-game-list(v-show="display=='gameList'") + my-TODO_FIND_NAME_game-list(v-show="display=='gameList'") my-rules(v-show="display=='rules'" :settings="settings") //my-problems(v-show="display=='problems'" :query-hash="queryHash") my-game(v-show="display=='game'" :game-id="gameid" :conn="conn" @@ -50,7 +50,8 @@ block javascripts const V = VariantRules; //because this variable is often used const variant = !{JSON.stringify(variant)}; script(src="/javascripts/components/room.js") - //script(src="/javascripts/components/gameList.js") + script(src="/javascripts/components/gameList.js") + script(src="/javascripts/components/TODO_FIND_NAME_gameList.js") script(src="/javascripts/components/rules.js") script(src="/javascripts/components/board.js") //script(src="/javascripts/components/problemPreview.js")