From 910d631b73cad5ffef1b4461157b704e7e7057d8 Mon Sep 17 00:00:00 2001 From: Benjamin Auder <benjamin.auder@somewhere> Date: Tue, 18 Feb 2020 18:02:44 +0100 Subject: [PATCH] Some more cleaning + fixes --- client/package.json | 4 +- client/src/App.vue | 13 +-- client/src/base_rules.js | 3 +- client/src/components/BaseGame.vue | 24 +++--- client/src/components/ChallengeList.vue | 8 +- client/src/components/Chat.vue | 13 ++- client/src/components/ComputerGame.vue | 9 ++- client/src/components/ContactForm.vue | 13 ++- client/src/components/GameList.vue | 14 +++- client/src/components/Language.vue | 5 +- client/src/components/MoveList.vue | 62 +++++++++++++- client/src/components/Settings.vue | 15 +++- client/src/components/UpsertUser.vue | 42 ++++++++-- client/src/data/userCheck.js | 2 + client/src/store.js | 11 +-- client/src/utils/cookie.js | 8 +- client/src/utils/gameStorage.js | 2 +- client/src/variants/Grand.js | 1 - client/src/variants/Magnetic.js | 6 +- client/src/views/Analyse.vue | 10 ++- client/src/views/Auth.vue | 29 ++----- client/src/views/Game.vue | 51 +++++++++--- client/src/views/Hall.vue | 103 ++++++++++++++++++------ client/src/views/Logout.vue | 37 ++++----- client/src/views/MyGames.vue | 20 +++-- client/src/views/News.vue | 27 +++++-- client/src/views/Problems.vue | 22 ++++- client/src/views/Rules.vue | 34 ++++++-- client/src/views/Variants.vue | 7 +- server/sockets.js | 21 +++-- 30 files changed, 441 insertions(+), 175 deletions(-) diff --git a/client/package.json b/client/package.json index 88feedb9..172b5c4c 100644 --- a/client/package.json +++ b/client/package.json @@ -64,13 +64,13 @@ "flatTernaryExpressions": true } ], - "no-else-return" : [ + "no-else-return": [ 1, { "allowElseIf": false } ], - "semi" : [1, "always"] + "semi": [1, "always"] } }, "postcss": { diff --git a/client/src/App.vue b/client/src/App.vue index 9879e275..9c724e76 100644 --- a/client/src/App.vue +++ b/client/src/App.vue @@ -25,19 +25,22 @@ router-link(to="/problems") | {{ st.tr["Problems"] }} #rightMenu - .clickable(onClick="doClick('modalUser')") + .clickable(onClick="window.doClick('modalUser')") | {{ st.user.id > 0 ? (st.user.name || "@nonymous") : "Login" }} - .clickable(onClick="doClick('modalSettings')") + .clickable(onClick="window.doClick('modalSettings')") | {{ st.tr["Settings"] }} - .clickable#flagContainer(onClick="doClick('modalLang')") - img(v-if="!!st.lang" :src="flagImage") + .clickable#flagContainer(onClick="window.doClick('modalLang')") + img( + v-if="!!st.lang" + :src="flagImage" + ) router-view .row .col-sm-12.col-md-10.col-md-offset-1.col-lg-8.col-lg-offset-2 footer router-link.menuitem(to="/about") {{ st.tr["About"] }} router-link.menuitem(to="/news") {{ st.tr["News"] }} - p.clickable(onClick="doClick('modalContact')") + p.clickable(onClick="window.doClick('modalContact')") | {{ st.tr["Contact"] }} </template> diff --git a/client/src/base_rules.js b/client/src/base_rules.js index 056f4774..42d9bdc8 100644 --- a/client/src/base_rules.js +++ b/client/src/base_rules.js @@ -4,8 +4,8 @@ import { ArrayFun } from "@/utils/array"; import { randInt, shuffle } from "@/utils/alea"; +// class "PiPo": Piece + Position export const PiPo = class PiPo { - //Piece+Position // o: {piece[p], color[c], posX[x], posY[y]} constructor(o) { this.p = o.p; @@ -15,7 +15,6 @@ export const PiPo = class PiPo { } }; -// TODO: for animation, moves should contains "moving" and "fading" maybe... export const Move = class Move { // o: {appear, vanish, [start,] [end,]} // appear,vanish = arrays of PiPo diff --git a/client/src/components/BaseGame.vue b/client/src/components/BaseGame.vue index b2dd4a72..f4603d6b 100644 --- a/client/src/components/BaseGame.vue +++ b/client/src/components/BaseGame.vue @@ -52,7 +52,7 @@ div#baseGame( #downloadDiv(v-if="game.vname!='Dark' || game.score!='*'") a#download(href="#") button(@click="download()") {{ st.tr["Download"] }} PGN - button(onClick="doClick('modalAdjust')") ⤢ + button(onClick="window.doClick('modalAdjust')") ⤢ button( v-if="game.vname!='Dark' && game.mode!='analyze'" @click="analyzePosition()" @@ -169,7 +169,6 @@ export default { }, methods: { focusBg: function() { - // NOTE: small blue border appears... document.getElementById("baseGame").focus(); }, adjustBoard: function() { @@ -259,9 +258,9 @@ export default { this.game.vname + "/?fen=" + this.vr.getFen().replace(/ /g, "_"); + // Open in same tab in live games (against cheating) if (this.game.type == "live") this.$router.push(newUrl); - //open in same tab: against cheating... - else window.open("#" + newUrl); //open in a new tab: more comfortable + else window.open("#" + newUrl); }, download: function() { const content = this.getPgn(); @@ -305,9 +304,6 @@ export default { }, animateMove: function(move, callback) { let startSquare = document.getElementById(getSquareId(move.start)); - // TODO: error "flush nextTick callbacks" when observer reloads page: - // this late check is not a fix! - if (!startSquare) return; let endSquare = document.getElementById(getSquareId(move.end)); let rectStart = startSquare.getBoundingClientRect(); let rectEnd = endSquare.getBoundingClientRect(); @@ -318,9 +314,6 @@ export default { let movingPiece = document.querySelector( "#" + getSquareId(move.start) + " > img.piece" ); - if (!movingPiece) - //TODO: shouldn't happen - return; // HACK for animation (with positive translate, image slides "under background") // Possible improvement: just alter squares on the piece's way... const squares = document.getElementsByClassName("board"); @@ -330,7 +323,7 @@ export default { } movingPiece.style.transform = "translate(" + translation.x + "px," + translation.y + "px)"; - movingPiece.style.transitionDuration = "0.2s"; + movingPiece.style.transitionDuration = "0.25s"; movingPiece.style.zIndex = "3000"; setTimeout(() => { for (let i = 0; i < squares.length; i++) @@ -353,7 +346,8 @@ export default { return; } const doPlayMove = () => { - if (!!receive && this.cursor < this.moves.length - 1) this.gotoEnd(); //required to play the move + // To play a move, cursor must be at the end of the game: + if (!!receive && this.cursor < this.moves.length - 1) this.gotoEnd(); if (navigate) { if (this.cursor == this.moves.length - 1) return; //no more moves move = this.moves[this.cursor + 1]; @@ -433,6 +427,7 @@ export default { <style lang="sass" scoped> [type="checkbox"]#modalEog+div .card min-height: 45px + [type="checkbox"]#modalAdjust+div .card padding: 5px @@ -454,8 +449,10 @@ export default { display: inline-block width: 20% margin: 0 + #turnIndicator text-align: center + #belowControls border-top: 1px solid #2f4f4f text-align: center @@ -467,13 +464,16 @@ export default { & > button border-left: 1px solid #2f4f4f margin: 0 + #boardContainer float: left // TODO: later, maybe, allow movesList of variable width // or e.g. between 250 and 350px (but more complicated) + #movesList width: 280px float: left + @media screen and (max-width: 767px) #movesList width: 100% diff --git a/client/src/components/ChallengeList.vue b/client/src/components/ChallengeList.vue index 92c42f7c..ed490671 100644 --- a/client/src/components/ChallengeList.vue +++ b/client/src/components/ChallengeList.vue @@ -7,7 +7,11 @@ div th {{ st.tr["From"] }} th {{ st.tr["Cadence"] }} tbody - tr(v-for="c in sortedChallenges" :class="{toyou:c.priority==1,fromyou:c.priority==2}" @click="$emit('click-challenge',c)") + tr( + v-for="c in sortedChallenges" + :class="{toyou:c.priority==1,fromyou:c.priority==2}" + @click="$emit('click-challenge',c)" + ) td {{ c.vname }} td {{ c.from.name || "@nonymous" }} td {{ c.cadence }} @@ -47,7 +51,7 @@ export default { </script> <style lang="sass" scoped> -// TODO: understand why the style applied to <tr> element doesn't work +// NOTE: the style applied to <tr> element doesn't work tr.fromyou > td font-style: italic tr.toyou > td diff --git a/client/src/components/Chat.vue b/client/src/components/Chat.vue index 7205f3b7..f1e1fad2 100644 --- a/client/src/components/Chat.vue +++ b/client/src/components/Chat.vue @@ -1,11 +1,17 @@ <template lang="pug"> div - input#inputChat(type="text" :placeholder="st.tr['Chat here']" - @keyup.enter="sendChat()") + input#inputChat( + type="text" + :placeholder="st.tr['Chat here']" + @keyup.enter="sendChat()" + ) button(@click="sendChat()") {{ st.tr["Send"] }} p(v-for="chat in chats.concat(pastChats)") span.name {{ chat.name }} : - span(:class="classObject(chat)" v-html="chat.msg") + span( + :class="classObject(chat)" + v-html="chat.msg" + ) </template> <script> @@ -53,6 +59,7 @@ export default { <style lang="sass" scoped> .name color: #abb2b9 + .my-chatmsg color: #7d3c98 .opp-chatmsg diff --git a/client/src/components/ComputerGame.vue b/client/src/components/ComputerGame.vue index 402bc7fa..4d354713 100644 --- a/client/src/components/ComputerGame.vue +++ b/client/src/components/ComputerGame.vue @@ -1,5 +1,10 @@ <template lang="pug"> -BaseGame(:game="game" :vr="vr" @newmove="processMove" @gameover="gameOver") +BaseGame( + :game="game" + :vr="vr" + @newmove="processMove" + @gameover="gameOver" +) </template> <script> @@ -47,7 +52,7 @@ export default { this.$emit("game-stopped"); //no more moves: mate or stalemate return; //after game ends, no more moves, nothing to do } - if (!Array.isArray(compMove)) compMove = [compMove]; //to deal with MarseilleRules + if (!Array.isArray(compMove)) compMove = [compMove]; //potential multi-move // Small delay for the bot to appear "more human" const delay = Math.max(500 - (Date.now() - this.timeStart), 0); setTimeout(() => { diff --git a/client/src/components/ContactForm.vue b/client/src/components/ContactForm.vue index 9c70a559..9046e0a7 100644 --- a/client/src/components/ContactForm.vue +++ b/client/src/components/ContactForm.vue @@ -1,7 +1,13 @@ <template lang="pug"> div - input#modalContact.modal(type="checkbox" @change="trySetEnterTime($event)") - div(role="dialog" data-checkbox="modalContact") + input#modalContact.modal( + type="checkbox" + @change="trySetEnterTime($event)" + ) + div( + role="dialog" + data-checkbox="modalContact" + ) .card label.modal-close(for="modalContact") form(@submit.prevent="trySendMessage()" @keyup.enter="trySendMessage()") @@ -56,7 +62,6 @@ export default { !confirm(this.st.tr["No subject. Send anyway?"]) ) return; - // Message sending: ajax( "/messages", @@ -81,9 +86,11 @@ export default { [type="checkbox"].modal+div .card max-width: 767px max-height: 100% + textarea#mailContent width: 100% min-height: 100px + #dialog padding: 5px color: blue diff --git a/client/src/components/GameList.vue b/client/src/components/GameList.vue index 7125fde8..77aa83e5 100644 --- a/client/src/components/GameList.vue +++ b/client/src/components/GameList.vue @@ -8,12 +8,18 @@ div th(v-if="showCadence") {{ st.tr["Cadence"] }} th {{ st.tr["Result"] }} tbody - tr(v-for="g in sortedGames" @click="$emit('show-game',g)" - :class="{'my-turn': g.myTurn}") + tr( + v-for="g in sortedGames" + @click="$emit('show-game',g)" + :class="{'my-turn': g.myTurn}" + ) td {{ g.vname }} td {{ player_s(g) }} td(v-if="showCadence") {{ g.cadence }} - td(:class="{finished: g.score!='*'}" @click="deleteGame(g,$event)") + td( + :class="{finished: g.score!='*'}" + @click="deleteGame(g,$event)" + ) | {{ g.score }} </template> @@ -107,7 +113,7 @@ export default { </script> <style lang="sass" scoped> -// TODO: understand why the style applied to <tr> element doesn't work +// NOTE: the style applied to <tr> element doesn't work tr.my-turn > td background-color: #fcd785 tr td.finished diff --git a/client/src/components/Language.vue b/client/src/components/Language.vue index bdfd3417..633f89dd 100644 --- a/client/src/components/Language.vue +++ b/client/src/components/Language.vue @@ -7,7 +7,10 @@ div "fr": "Français", }; input#modalLang.modal(type="checkbox") - div(role="dialog" data-checkbox="modalLang") + div( + role="dialog" + data-checkbox="modalLang" + ) .card label.modal-close(for="modalLang") form(@change="setLanguage($event)") diff --git a/client/src/components/MoveList.vue b/client/src/components/MoveList.vue index 29e9a9fe..aa12969a 100644 --- a/client/src/components/MoveList.vue +++ b/client/src/components/MoveList.vue @@ -5,7 +5,7 @@ export default { props: ["moves", "cursor", "score", "message", "firstNum"], watch: { cursor: function(newCursor) { - if (window.innerWidth <= 767) return; //moves list is below: scrolling would hide chessboard + if (window.innerWidth <= 767) return; //scrolling would hide chessboard // Count grouped moves until the cursor (if multi-moves): let groupsCount = -1; let curCol = undefined; @@ -119,6 +119,66 @@ export default { <style lang="sass" scoped> .moves-list min-width: 250px + td.highlight-lm background-color: plum </style> + +<!-- TODO: use template function + multi-moves: much easier +<template lang="pug"> +div + #scoreInfo(v-if="score!='*'") + p {{ score }} + p {{ message }} + table.moves-list + tbody + tr(v-for="moveIdx in evenNumbers") + td {{ firstNum + moveIdx / 2 + 1 }} + td(:class="{'highlight-lm': cursor == moveIdx}" + @click="() => gotoMove(moveIdx)") + | {{ moves[moveIdx].notation }} + td(v-if="moveIdx < moves.length-1" + :class="{'highlight-lm': cursor == moveIdx+1}" + @click="() => gotoMove(moveIdx+1)") + | {{ moves[moveIdx+1].notation }} + // Else: just add an empty cell + td(v-else) +</template> + +<script> +// Component for moves list on the right +export default { + name: 'my-move-list', + props: ["moves","cursor","score","message","firstNum"], + watch: { + cursor: function(newValue) { + if (window.innerWidth <= 767) + return; //moves list is below: scrolling would hide chessboard + if (newValue < 0) + newValue = 0; //avoid rows[-1] => error + // $nextTick to wait for table > tr to be rendered + this.$nextTick( () => { + let rows = document.querySelectorAll('#movesList tr'); + if (rows.length > 0) + { + rows[Math.floor(newValue/2)].scrollIntoView({ + behavior: "auto", + block: "nearest", + }); + } + }); + }, + }, + computed: { + evenNumbers: function() { + return [...Array(this.moves.length).keys()].filter(i => i%2==0); + }, + }, + methods: { + gotoMove: function(index) { + this.$emit("goto-move", index); + }, + }, +}; +</script> +--> diff --git a/client/src/components/Settings.vue b/client/src/components/Settings.vue index e5a9d9c7..117133d1 100644 --- a/client/src/components/Settings.vue +++ b/client/src/components/Settings.vue @@ -1,17 +1,26 @@ <template lang="pug"> div input#modalSettings.modal(type="checkbox") - div(role="dialog" data-checkbox="modalSettings") + div( + role="dialog" + data-checkbox="modalSettings" + ) .card(@change="updateSettings($event)") label.modal-close(for="modalSettings") form fieldset label(for="setHints") {{ st.tr["Show possible moves?"] }} - input#setHints(type="checkbox" v-model="st.settings.hints") + input#setHints( + type="checkbox" + v-model="st.settings.hints" + ) fieldset label(for="setHighlight") | {{ st.tr["Highlight last move and checks?"] }} - input#setHighlight(type="checkbox" v-model="st.settings.highlight") + input#setHighlight( + type="checkbox" + v-model="st.settings.highlight" + ) fieldset label(for="setBcolor") {{ st.tr["Board colors"] }} select#setBcolor(v-model="st.settings.bcolor") diff --git a/client/src/components/UpsertUser.vue b/client/src/components/UpsertUser.vue index 222a8625..eb1b6c22 100644 --- a/client/src/components/UpsertUser.vue +++ b/client/src/components/UpsertUser.vue @@ -1,7 +1,13 @@ <template lang="pug"> div - input#modalUser.modal(type="checkbox" @change="trySetEnterTime($event)") - div(role="dialog" data-checkbox="modalUser") + input#modalUser.modal( + type="checkbox" + @change="trySetEnterTime($event)" + ) + div( + role="dialog" + data-checkbox="modalUser" + ) .card label.modal-close(for="modalUser") h3.section {{ st.tr[stage] }} @@ -9,23 +15,42 @@ div div(v-show="stage!='Login'") fieldset label(for="username") {{ st.tr["User name"] }} - input#username(type="text" v-model="st.user.name") + input#username( + type="text" + v-model="st.user.name" + ) fieldset label(for="useremail") {{ st.tr["Email"] }} - input#useremail(type="email" v-model="st.user.email") + input#useremail( + type="email" + v-model="st.user.email" + ) fieldset label(for="notifyNew") {{ st.tr["Notifications by email"] }} - input#notifyNew(type="checkbox" v-model="st.user.notify") + input#notifyNew( + type="checkbox" + v-model="st.user.notify" + ) div(v-show="stage=='Login'") fieldset label(for="nameOrEmail") {{ st.tr["Name or Email"] }} - input#nameOrEmail(type="text" v-model="nameOrEmail") + input#nameOrEmail( + type="text" + v-model="nameOrEmail" + ) .button-group button(@click="onSubmit()") span {{ st.tr[submitMessage] }} - button(v-if="stage!='Update'" type="button" @click="toggleStage()") + button( + v-if="stage!='Update'" + type="button" + @click="toggleStage()" + ) span {{ st.tr[stage=="Login" ? "Register" : "Login"] }} - button(v-else type="button" @click="doLogout()") + button( + v-else type="button" + @click="doLogout()" + ) span {{ st.tr["Logout"] }} #dialog.text-center {{ st.tr[infoMsg] }} </template> @@ -158,6 +183,7 @@ export default { [type="checkbox"].modal+div .card max-width: 370px max-height: 100% + #dialog padding: 5px color: blue diff --git a/client/src/data/userCheck.js b/client/src/data/userCheck.js index dac8ef6f..745d6d6e 100644 --- a/client/src/data/userCheck.js +++ b/client/src/data/userCheck.js @@ -3,9 +3,11 @@ export function checkNameEmail(o) { if (o.name.length == 0) return "Empty name"; if (!o.name.match(/^[\w]+$/)) return "Bad characters in name"; } + if (typeof o.email === "string") { if (o.email.length == 0) return "Empty email"; if (!o.email.match(/^[\w.+-]+@[\w.+-]+$/)) return "Bad characters in email"; } + return ""; } diff --git a/client/src/store.js b/client/src/store.js index 373aa288..60e01b97 100644 --- a/client/src/store.js +++ b/client/src/store.js @@ -16,9 +16,10 @@ export const store = { this.state.variants = res.variantArray; }); let mysid = localStorage.getItem("mysid"); + // Assign mysid only once (until next time user clear browser data) if (!mysid) { mysid = getRandString(); - localStorage.setItem("mysid", mysid); //done only once (unless user clear browser data) + localStorage.setItem("mysid", mysid); } // Quick user setup using local storage: this.state.user = { @@ -34,18 +35,18 @@ export const store = { this.state.user.id = res.id; const storedId = localStorage.getItem("myid"); if (res.id > 0 && !storedId) - //user cleared localStorage + // User cleared localStorage localStorage.setItem("myid", res.id); else if (res.id == 0 && !!storedId) - //user cleared cookie + // User cleared cookie localStorage.removeItem("myid"); this.state.user.name = res.name; const storedName = localStorage.getItem("myname"); if (!!res.name && !storedName) - //user cleared localStorage + // User cleared localStorage localStorage.setItem("myname", res.name); else if (!res.name && !!storedName) - //user cleared cookie + // User cleared cookie localStorage.removeItem("myname"); this.state.user.email = res.email; this.state.user.notify = res.notify; diff --git a/client/src/utils/cookie.js b/client/src/utils/cookie.js index 78551a29..34802243 100644 --- a/client/src/utils/cookie.js +++ b/client/src/utils/cookie.js @@ -1,14 +1,14 @@ // Source: https://www.quirksmode.org/js/cookies.html export function setCookie(name, value) { - var date = new Date(); + const date = new Date(); date.setTime(date.getTime() + 183 * 24 * 60 * 60 * 1000); //6 months - var expires = "; expires=" + date.toGMTString(); + const expires = "; expires=" + date.toGMTString(); document.cookie = name + "=" + value + expires + "; path=/"; } export function getCookie(name, defaut) { - var nameEQ = name + "="; - var ca = document.cookie.split(";"); + const nameEQ = name + "="; + const ca = document.cookie.split(";"); for (var i = 0; i < ca.length; i++) { var c = ca[i]; while (c.charAt(0) == " ") c = c.substring(1, c.length); diff --git a/client/src/utils/gameStorage.js b/client/src/utils/gameStorage.js index 453388ed..6e9fc818 100644 --- a/client/src/utils/gameStorage.js +++ b/client/src/utils/gameStorage.js @@ -6,7 +6,7 @@ // players: array of sid+id+name, // cadence: string, // increment: integer (seconds), -// mode: string ("live" or "corr") +// type: string ("live" or "corr") // imported: boolean (optional, default false) // // Game (dynamic) state: // fen: string, diff --git a/client/src/variants/Grand.js b/client/src/variants/Grand.js index d28f639f..c4e2eb1d 100644 --- a/client/src/variants/Grand.js +++ b/client/src/variants/Grand.js @@ -316,7 +316,6 @@ export const VariantRules = class GrandRules extends ChessRules { return 2; } - // TODO: this function could be generalized and shared better (how ?!...) static GenRandInitFen() { let pieces = { w: new Array(10), b: new Array(10) }; // Shuffle pieces on first and last rank diff --git a/client/src/variants/Magnetic.js b/client/src/variants/Magnetic.js index 0110c49e..c2201d60 100644 --- a/client/src/variants/Magnetic.js +++ b/client/src/variants/Magnetic.js @@ -20,8 +20,10 @@ export const VariantRules = class MagneticRules extends ChessRules { // Complete a move with magnetic actions // TODO: job is done multiple times for (normal) promotions. applyMagneticLaws(move) { - if (move.appear[0].p == V.KING && move.appear.length == 1) return [move]; //kings are not charged - const aIdx = move.appear[0].p != V.KING ? 0 : 1; //if castling, rook is charged + // Exception: kings are not charged + if (move.appear[0].p == V.KING && move.appear.length == 1) return [move]; + // If castling, rook is charged: + const aIdx = move.appear[0].p != V.KING ? 0 : 1; const [x, y] = [move.appear[aIdx].x, move.appear[aIdx].y]; const color = this.turn; const lastRank = color == "w" ? 0 : 7; diff --git a/client/src/views/Analyse.vue b/client/src/views/Analyse.vue index 5d22306e..7259632c 100644 --- a/client/src/views/Analyse.vue +++ b/client/src/views/Analyse.vue @@ -3,9 +3,15 @@ main .row .col-sm-12 .text-center - input#fen(v-model="curFen" @input="adjustFenSize()") + input#fen( + v-model="curFen" + @input="adjustFenSize()" + ) button(@click="gotoFen()") {{ st.tr["Go"] }} - BaseGame(:game="game" :vr="vr") + BaseGame( + :game="game" + :vr="vr" + ) </template> <script> diff --git a/client/src/views/Auth.vue b/client/src/views/Auth.vue index a44687c1..36e79c89 100644 --- a/client/src/views/Auth.vue +++ b/client/src/views/Auth.vue @@ -2,8 +2,7 @@ main .row .col-sm-12.col-md-10.col-md-offset-1.col-lg-8.col-lg-offset-2 - p(:class="{warn:!!this.errmsg}") - | {{ errmsg || st.tr["Authentication successful!"] }} + p {{ st.tr["Authentication successful!"] }} </template> <script> @@ -13,8 +12,7 @@ export default { name: "my-auth", data: function() { return { - st: store.state, - errmsg: "" + st: store.state }; }, created: function() { @@ -23,25 +21,14 @@ export default { "GET", { token: this.$route.params["token"] }, res => { - if (!res.errmsg) { - //if not already logged in - this.st.user.id = res.id; - this.st.user.name = res.name; - this.st.user.email = res.email; - this.st.user.notify = res.notify; - localStorage["myname"] = res.name; - localStorage["myid"] = res.id; - } else this.errmsg = res.errmsg; + this.st.user.id = res.id; + this.st.user.name = res.name; + this.st.user.email = res.email; + this.st.user.notify = res.notify; + localStorage["myname"] = res.name; + localStorage["myid"] = res.id; } ); } }; </script> - -<style lang="sass" scoped> -.warn - padding: 3px - color: red - background-color: lightgrey - font-weight: bold -</style> diff --git a/client/src/views/Game.vue b/client/src/views/Game.vue index a0e264ed..9a971006 100644 --- a/client/src/views/Game.vue +++ b/client/src/views/Game.vue @@ -1,27 +1,51 @@ <template lang="pug"> main - input#modalChat.modal(type="checkbox" @click="resetChatColor()") - div#chatWrap(role="dialog" data-checkbox="modalChat") + input#modalChat.modal( + type="checkbox" + @click="resetChatColor()" + ) + div#chatWrap( + role="dialog" + data-checkbox="modalChat" + ) #chat.card label.modal-close(for="modalChat") #participants span {{ Object.keys(people).length + " " + st.tr["participant(s):"] }} - span(v-for="p in Object.values(people)" v-if="!!p.name") + span( + v-for="p in Object.values(people)" + v-if="!!p.name" + ) | {{ p.name }} span.anonymous(v-if="Object.values(people).some(p => !p.name)") | + @nonymous - Chat(:players="game.players" :pastChats="game.chats" - :newChat="newChat" @mychat="processChat") + Chat( + :players="game.players" + :pastChats="game.chats" + :newChat="newChat" + @mychat="processChat" + ) .row #aboveBoard.col-sm-12.col-md-9.col-md-offset-3.col-lg-10.col-lg-offset-2 span.variant-cadence {{ game.cadence }} span.variant-name {{ game.vname }} - button#chatBtn(onClick="doClick('modalChat')") Chat + button#chatBtn(onClick="window.doClick('modalChat')") Chat #actions(v-if="game.score=='*'") - button(@click="clickDraw()" :class="{['draw-' + drawOffer]: true}") + button( + @click="clickDraw()" + :class="{['draw-' + drawOffer]: true}" + ) | {{ st.tr["Draw"] }} - button(v-if="!!game.mycolor" @click="abortGame()") {{ st.tr["Abort"] }} - button(v-if="!!game.mycolor" @click="resign()") {{ st.tr["Resign"] }} + button( + v-if="!!game.mycolor" + @click="abortGame()" + ) + | {{ st.tr["Abort"] }} + button( + v-if="!!game.mycolor" + @click="resign()" + ) + | {{ st.tr["Resign"] }} #playersInfo p span.name(:class="{connected: isConnected(0)}") @@ -31,7 +55,12 @@ main span.name(:class="{connected: isConnected(1)}") | {{ game.players[1].name || "@nonymous" }} span.time(v-if="game.score=='*'") {{ virtualClocks[1] }} - BaseGame(:game="game" :vr="vr" @newmove="processMove" @gameover="gameOver") + BaseGame( + :game="game" + :vr="vr" + @newmove="processMove" + @gameover="gameOver" + ) </template> <script> @@ -217,7 +246,6 @@ export default { case "identity": { const user = data.data; if (user.name) { - //otherwise anonymous // If I multi-connect, kill current connexion if no mark (I'm older) if ( this.newConnect[user.sid] && @@ -497,6 +525,7 @@ export default { } } if (game.scoreMsg) game.scoreMsg = this.st.tr[game.scoreMsg]; //stored in english + delete game["moveToPlay"]; //in case of! this.game = Object.assign( {}, game, diff --git a/client/src/views/Hall.vue b/client/src/views/Hall.vue index 190717d0..b4869c9c 100644 --- a/client/src/views/Hall.vue +++ b/client/src/views/Hall.vue @@ -1,20 +1,29 @@ <template lang="pug"> main input#modalInfo.modal(type="checkbox") - div#infoDiv(role="dialog" data-checkbox="modalInfo") + div#infoDiv( + role="dialog" + data-checkbox="modalInfo" + ) .card.text-center label.modal-close(for="modalInfo") p(v-html="infoMessage") input#modalNewgame.modal(type="checkbox") - div#newgameDiv(role="dialog" data-checkbox="modalNewgame") + div#newgameDiv( + role="dialog" + data-checkbox="modalNewgame" + ) .card label#closeNewgame.modal-close(for="modalNewgame") form(@submit.prevent="newChallenge()" @keyup.enter="newChallenge()") fieldset label(for="selectVariant") {{ st.tr["Variant"] }} * select#selectVariant(v-model="newchallenge.vid") - option(v-for="v in st.variants" :value="v.id" - :selected="newchallenge.vid==v.id") + option( + v-for="v in st.variants" + :value="v.id" + :selected="newchallenge.vid==v.id" + ) | {{ v.name }} fieldset label(for="cadence") {{ st.tr["Cadence"] }} * @@ -22,34 +31,61 @@ main button 3+2 button 5+3 button 15+5 - input#cadence(type="text" v-model="newchallenge.cadence" - placeholder="5+0, 1h+30s, 7d+1d ...") + input#cadence( + type="text" + v-model="newchallenge.cadence" + placeholder="5+0, 1h+30s, 7d+1d ..." + ) fieldset(v-if="st.user.id > 0") label(for="selectPlayers") {{ st.tr["Play with?"] }} - input#selectPlayers(type="text" v-model="newchallenge.to") + input#selectPlayers( + type="text" + v-model="newchallenge.to" + ) fieldset(v-if="st.user.id > 0 && newchallenge.to.length > 0") label(for="inputFen") FEN - input#inputFen(type="text" v-model="newchallenge.fen") + input#inputFen( + type="text" + v-model="newchallenge.fen" + ) button(@click="newChallenge()") {{ st.tr["Send challenge"] }} - input#modalPeople.modal(type="checkbox" @click="resetChatColor()") - div#peopleWrap(role="dialog" data-checkbox="modalPeople") + input#modalPeople.modal( + type="checkbox" + @click="resetChatColor()" + ) + div#peopleWrap( + role="dialog" + data-checkbox="modalPeople" + ) .card label.modal-close(for="modalPeople") #people #players - p(v-for="sid in Object.keys(people)" v-if="!!people[sid].name") + p( + v-for="sid in Object.keys(people)" + v-if="!!people[sid].name" + ) span {{ people[sid].name }} - button.player-action(v-if="sid!=st.user.sid || isGamer(sid)" @click="challOrWatch(sid)") + button.player-action( + v-if="sid!=st.user.sid || isGamer(sid)" + @click="challOrWatch(sid)" + ) | {{ getActionLabel(sid) }} p.anonymous @nonymous ({{ anonymousCount }}) #chat - Chat(:newChat="newChat" @mychat="processChat" :pastChats="[]") + Chat( + :newChat="newChat" + @mychat="processChat" + :pastChats="[]" + ) .clearer .row .col-sm-12.col-md-10.col-md-offset-1.col-lg-8.col-lg-offset-2 .button-group - button#peopleBtn(onClick="doClick('modalPeople')") {{ st.tr["Social"] }} - button(onClick="doClick('modalNewgame')") {{ st.tr["New game"] }} + button#peopleBtn(onClick="window.doClick('modalPeople')") + | {{ st.tr["Social"] }} + button(onClick="window.doClick('modalNewgame')") + | {{ st.tr["New game"] }} .row .col-sm-12.col-md-10.col-md-offset-1.col-lg-8.col-lg-offset-2 div#div2 @@ -58,20 +94,34 @@ main | {{ st.tr["Live challenges"] }} button.tabbtn#btnCcorr(@click="setDisplay('c','corr',$event)") | {{ st.tr["Correspondance challenges"] }} - ChallengeList(v-show="cdisplay=='live'" - :challenges="filterChallenges('live')" @click-challenge="clickChallenge") - ChallengeList(v-show="cdisplay=='corr'" - :challenges="filterChallenges('corr')" @click-challenge="clickChallenge") + ChallengeList( + v-show="cdisplay=='live'" + :challenges="filterChallenges('live')" + @click-challenge="clickChallenge" + ) + ChallengeList( + v-show="cdisplay=='corr'" + :challenges="filterChallenges('corr')" + @click-challenge="clickChallenge" + ) div#div3 .button-group button.tabbtn#btnGlive(@click="setDisplay('g','live',$event)") | {{ st.tr["Live games"] }} button.tabbtn#btnGcorr(@click="setDisplay('g','corr',$event)") | {{ st.tr["Correspondance games"] }} - GameList(v-show="gdisplay=='live'" :games="filterGames('live')" - :showBoth="true" @show-game="showGame") - GameList(v-show="gdisplay=='corr'" :games="filterGames('corr')" - :showBoth="true" @show-game="showGame") + GameList( + v-show="gdisplay=='live'" + :games="filterGames('live')" + :showBoth="true" + @show-game="showGame" + ) + GameList( + v-show="gdisplay=='corr'" + :games="filterGames('corr')" + :showBoth="true" + @show-game="showGame" + ) </template> <script> @@ -417,7 +467,6 @@ export default { case "identity": { const user = data.data; if (user.name) { - //otherwise anonymous // If I multi-connect, kill current connexion if no mark (I'm older) if ( this.newConnect[user.sid] && @@ -775,21 +824,27 @@ div#peopleWrap > .card width: 50% position: relative float: left + #chat width: 50% float: left position: relative + @media screen and (max-width: 767px) #players, #chats width: 100% + #chat > .card max-width: 100% margin: 0; border: none; + #players > p margin-left: 5px + .anonymous font-style: italic + button.player-action margin-left: 32px diff --git a/client/src/views/Logout.vue b/client/src/views/Logout.vue index 34dbb49b..62f057c6 100644 --- a/client/src/views/Logout.vue +++ b/client/src/views/Logout.vue @@ -2,8 +2,7 @@ main .row .col-sm-12.col-md-10.col-md-offset-1.col-lg-8.col-lg-offset-2 - p(:class="{warn:!!this.errmsg}") - | {{ errmsg || st.tr["Logout successful!"] }} + p {{ st.tr["Logout successful!"] }} </template> <script> @@ -13,30 +12,22 @@ export default { name: "my-logout", data: function() { return { - st: store.state, - errmsg: "" + st: store.state }; }, created: function() { - // NOTE: this local cleaning would logically happen when we're sure - // that token is erased. But in the case a user clear the cookies, - // it would lead to situations where he cannot ("locally") log out. - // At worst, if token deletion fails the user can erase cookie manually. - this.st.user.id = 0; - this.st.user.name = ""; - this.st.user.email = ""; - this.st.user.notify = false; - localStorage.removeItem("myid"); - localStorage.removeItem("myname"); - ajax("/logout", "GET"); //TODO: listen for errors? + ajax( + "/logout", + "GET", + () => { + this.st.user.id = 0; + this.st.user.name = ""; + this.st.user.email = ""; + this.st.user.notify = false; + localStorage.removeItem("myid"); + localStorage.removeItem("myname"); + } + ); } }; </script> - -<style lang="sass" scoped> -.warn - padding: 3px - color: red - background-color: lightgrey - font-weight: bold -</style> diff --git a/client/src/views/MyGames.vue b/client/src/views/MyGames.vue index 01b5264d..22f804dc 100644 --- a/client/src/views/MyGames.vue +++ b/client/src/views/MyGames.vue @@ -3,12 +3,20 @@ main .row .col-sm-12.col-md-10.col-md-offset-1.col-lg-8.col-lg-offset-2 .button-group - button.tabbtn#liveGames(@click="setDisplay('live',$event)") {{ st.tr["Live games"] }} - button.tabbtn#corrGames(@click="setDisplay('corr',$event)") {{ st.tr["Correspondance games"] }} - GameList(v-show="display=='live'" :games="liveGames" - @show-game="showGame") - GameList(v-show="display=='corr'" :games="corrGames" - @show-game="showGame") + button.tabbtn#liveGames(@click="setDisplay('live',$event)") + | {{ st.tr["Live games"] }} + button.tabbtn#corrGames(@click="setDisplay('corr',$event)") + | {{ st.tr["Correspondance games"] }} + GameList( + v-show="display=='live'" + :games="liveGames" + @show-game="showGame" + ) + GameList( + v-show="display=='corr'" + :games="corrGames" + @show-game="showGame" + ) </template> <script> diff --git a/client/src/views/News.vue b/client/src/views/News.vue index 2686552c..ad0561a6 100644 --- a/client/src/views/News.vue +++ b/client/src/views/News.vue @@ -1,7 +1,10 @@ <template lang="pug"> main input#modalNews.modal(type="checkbox") - div#newnewsDiv(role="dialog" data-checkbox="modalNews") + div#newnewsDiv( + role="dialog" + data-checkbox="modalNews" + ) .card label.modal-close(for="modalNews") textarea#newsContent( @@ -18,13 +21,19 @@ main @click="showModalNews" ) | {{ st.tr["Write news"] }} - .news(v-for="n,idx in newsList" :class="{margintop:idx>0}") + .news( + v-for="n,idx in newsList" + :class="{margintop:idx>0}" + ) span.ndt {{ formatDatetime(n.added) }} div(v-if="devs.includes(st.user.id)") button(@click="editNews(n)") {{ st.tr["Edit"] }} button(@click="deleteNews(n)") {{ st.tr["Delete"] }} p(v-html="parseHtml(n.content)") - button(v-if="hasMore" @click="loadMore()") + button( + v-if="hasMore" + @click="loadMore()" + ) | {{ st.tr["Load more"] }} </template> @@ -142,27 +151,33 @@ export default { [type="checkbox"].modal+div .card max-width: 767px max-height: 100% + textarea#newsContent margin: 0 width: 100% min-height: 200px max-height: 100% + #dialog padding: 5px color: blue + button#writeNews margin-top: 0 margin-bottom: 0 + span.ndt color: darkblue padding: 0 5px 0 var(--universal-margin) -.margintop - margin-top: 25px - border-top: 1px solid grey + .news padding-top: 10px & > div display: inline-block + +.margintop + margin-top: 25px + border-top: 1px solid grey @media screen and (max-width: 767px) .margintop margin-top: 10px diff --git a/client/src/views/Problems.vue b/client/src/views/Problems.vue index a9f9fcb6..e17bead7 100644 --- a/client/src/views/Problems.vue +++ b/client/src/views/Problems.vue @@ -1,7 +1,13 @@ <template lang="pug"> main - input#modalNewprob.modal(type="checkbox" @change="infoMsg=''") - div#newprobDiv(role="dialog" data-checkbox="modalNewprob") + input#modalNewprob.modal( + type="checkbox" + @change="infoMsg=''" + ) + div#newprobDiv( + role="dialog" + data-checkbox="modalNewprob" + ) .card(@keyup.enter="sendProblem()") label#closeNewprob.modal-close(for="modalNewprob") fieldset @@ -93,7 +99,11 @@ main td {{ p.vname }} td {{ firstChars(p.instruction) }} td {{ p.id }} - BaseGame(v-if="showOne" :game="game" :vr="vr") + BaseGame( + v-if="showOne" + :game="game" + :vr="vr" + ) </template> <script> @@ -310,7 +320,7 @@ export default { ); }, editProblem: function(prob) { - if (!prob.diag) this.setDiagram(prob); //possible because V is loaded at this stage + if (!prob.diag) this.setDiagram(prob); //V is loaded at this stage this.copyProblem(prob, this.curproblem); window.doClick("modalNewprob"); }, @@ -330,13 +340,17 @@ export default { [type="checkbox"].modal+div .card max-width: 767px max-height: 100% + #inputFen width: 100% + textarea width: 100% + #diagram margin: 0 auto max-width: 400px + #controls margin: 0 width: 100% diff --git a/client/src/views/Rules.vue b/client/src/views/Rules.vue index 4daebf9d..55564ffd 100644 --- a/client/src/views/Rules.vue +++ b/client/src/views/Rules.vue @@ -4,18 +4,36 @@ main .col-sm-12.col-md-10.col-md-offset-1.col-lg-8.col-lg-offset-2 .button-group button(@click="clickReadRules()") {{ st.tr["Rules"] }} - button(v-show="!gameInProgress" @click="startGame('auto')") + button( + v-show="!gameInProgress" + @click="startGame('auto')" + ) | {{ st.tr["Example game"] }} - button(v-show="!gameInProgress" @click="startGame('versus')") + button( + v-show="!gameInProgress" + @click="startGame('versus')" + ) | {{ st.tr["Practice"] }} - button(v-show="gameInProgress" @click="stopGame()") + button( + v-show="gameInProgress" + @click="stopGame()" + ) | {{ st.tr["Stop game"] }} - button(v-if="display=='rules' && gameInfo.vname!='Dark'" - @click="gotoAnalyze()") + button( + v-if="display=='rules' && gameInfo.vname!='Dark'" + @click="gotoAnalyze()" + ) | {{ st.tr["Analyse"] }} - div(v-show="display=='rules'" v-html="content") - ComputerGame(v-show="display=='computer'" :game-info="gameInfo" - @game-over="stopGame" @game-stopped="gameStopped") + div( + v-show="display=='rules'" + v-html="content" + ) + ComputerGame( + v-show="display=='computer'" + :game-info="gameInfo" + @game-over="stopGame" + @game-stopped="gameStopped" + ) </template> <script> diff --git a/client/src/views/Variants.vue b/client/src/views/Variants.vue index 31061158..014aca68 100644 --- a/client/src/views/Variants.vue +++ b/client/src/views/Variants.vue @@ -2,7 +2,10 @@ main .row .col-sm-12.col-md-10.col-md-offset-1.col-lg-8.col-lg-offset-2 - input#prefixFilter(v-model="curPrefix" :placeholder="st.tr['Prefix?']") + input#prefixFilter( + v-model="curPrefix" + :placeholder="st.tr['Prefix?']" + ) .variant.col-sm-12.col-md-5.col-lg-4( v-for="(v,idx) in filteredVariants" :class="{'col-md-offset-1': idx%2==0, 'col-lg-offset-2': idx%2==0}" @@ -52,10 +55,10 @@ export default { </script> <style lang="sass" scoped> -// TODO: box-shadow or box-sizing ? https://stackoverflow.com/a/13517809 input#prefixFilter display: block margin: 0 auto + .variant box-sizing: border-box border: 1px solid brown diff --git a/server/sockets.js b/server/sockets.js index 3fb7ea2a..1cc47aeb 100644 --- a/server/sockets.js +++ b/server/sockets.js @@ -152,15 +152,22 @@ module.exports = function(wss) { case "askfullgame": { const pg = obj.page || page; //required for askidentity and askgame - const tmpIds = Object.keys(clients[pg][obj.target]); - if (obj.target == sid) //targetting myself + // In cas askfullgame to wrong SID for example, would crash: + if (!!clients[pg][obj.target]) { - const idx_myTmpid = tmpIds.findIndex(x => x == tmpId); - if (idx_myTmpid >= 0) - tmpIds.splice(idx_myTmpid, 1); + const tmpIds = Object.keys(clients[pg][obj.target]); + if (obj.target == sid) //targetting myself + { + const idx_myTmpid = tmpIds.findIndex(x => x == tmpId); + if (idx_myTmpid >= 0) + tmpIds.splice(idx_myTmpid, 1); + } + const tmpId_idx = Math.floor(Math.random() * tmpIds.length); + send( + clients[pg][obj.target][tmpIds[tmpId_idx]], + {code:obj.code, from:[sid,tmpId,page]} + ); } - const tmpId_idx = Math.floor(Math.random() * tmpIds.length); - send(clients[pg][obj.target][tmpIds[tmpId_idx]], {code:obj.code, from:[sid,tmpId,page]}); break; } -- 2.44.0