X-Git-Url: https://git.auder.net/?a=blobdiff_plain;f=client%2Fsrc%2Fviews%2FGame.vue;h=878e7718e8101fea08ce48402a49d79785f3c31b;hb=08ccbb7827e93df14cd3206a57ec5e598afd93f3;hp=6d5a92abec55604c669f25b0fa0c8e078e17c56e;hpb=51336cd2180ca1a56eba7f773abe715d0eb5cddb;p=vchess.git diff --git a/client/src/views/Game.vue b/client/src/views/Game.vue index 6d5a92ab..878e7718 100644 --- a/client/src/views/Game.vue +++ b/client/src/views/Game.vue @@ -84,39 +84,42 @@ main @click="showNextGame()" ) | {{ st.tr["Next_g"] }} - button#chatBtn.tooltip( + button#chatBtn( + :class="btnTooltipClass()" onClick="window.doClick('modalChat')" aria-label="Chat" ) img(src="/images/icons/chat.svg") - #actions(v-show="game.score=='*'") - button.tooltip( + #actions(v-if="game.score=='*'") + button( @click="clickDraw()" - :class="{['draw-' + drawOffer]: true}" + :class="btnTooltipClass('draw')" :aria-label="st.tr['Draw']" ) img(src="/images/icons/draw.svg") - button.tooltip( - v-show="!!game.mycolor" + button( + v-if="!!game.mycolor" + :class="btnTooltipClass()" @click="abortGame()" :aria-label="st.tr['Abort']" ) img(src="/images/icons/abort.svg") - button.tooltip( - v-show="!!game.mycolor" + button( + v-if="!!game.mycolor" + :class="btnTooltipClass()" @click="resign()" :aria-label="st.tr['Resign']" ) img(src="/images/icons/resign.svg") - button.tooltip( - v-show="game.score!='*'" + button( + v-else + :class="btnTooltipClass('rematch')" @click="clickRematch()" - :class="{['rematch-' + rematchOffer]: true}" :aria-label="st.tr['Rematch']" ) img(src="/images/icons/rematch.svg") #playersInfo - p(v-if="isLargeScreen()") + div(v-if="isLargeScreen()") span.name(:class="{connected: isConnected(0)}") | {{ game.players[0].name || "@nonymous" }} span.time( @@ -138,30 +141,24 @@ main span.time-separator(v-if="!!virtualClocks[1][1]") : span.time-right(v-if="!!virtualClocks[1][1]") | {{ virtualClocks[1][1] }} - p(v-else) + div(v-else) span.name(:class="{connected: isConnected(0)}") | {{ game.players[0].name || "@nonymous" }} span.split-names - span.name(:class="{connected: isConnected(1)}") | {{ game.players[1].name || "@nonymous" }} - br - span.time( - v-if="game.score=='*'" - :class="{yourturn: !!vr && vr.turn == 'w'}" - ) - span.time-left {{ virtualClocks[0][0] }} - span.time-separator(v-if="!!virtualClocks[0][1]") : - span.time-right(v-if="!!virtualClocks[0][1]") - | {{ virtualClocks[0][1] }} - span.separator - span.time( - v-if="game.score=='*'" - :class="{yourturn: !!vr && vr.turn == 'b'}" - ) - span.time-left {{ virtualClocks[1][0] }} - span.time-separator(v-if="!!virtualClocks[1][1]") : - span.time-right(v-if="!!virtualClocks[1][1]") - | {{ virtualClocks[1][1] }} + div(v-if="game.score=='*'") + span.time(:class="{yourturn: !!vr && vr.turn == 'w'}") + span.time-left {{ virtualClocks[0][0] }} + span.time-separator(v-if="!!virtualClocks[0][1]") : + span.time-right(v-if="!!virtualClocks[0][1]") + | {{ virtualClocks[0][1] }} + span.separator + span.time(:class="{yourturn: !!vr && vr.turn == 'b'}") + span.time-left {{ virtualClocks[1][0] }} + span.time-separator(v-if="!!virtualClocks[1][1]") : + span.time-right(v-if="!!virtualClocks[1][1]") + | {{ virtualClocks[1][1] }} BaseGame( ref="basegame" :game="game" @@ -270,12 +267,6 @@ export default { .addEventListener("click", processModalClick); } ); - if ("ontouchstart" in window) { - // Disable tooltips on smartphones: - document.querySelectorAll("#aboveBoard .tooltip").forEach(elt => { - elt.classList.remove("tooltip"); - }); - } }, beforeDestroy: function() { this.cleanBeforeDestroy(); @@ -296,11 +287,6 @@ export default { visibilityChange: function() { // TODO: Use document.hidden? https://webplatform.news/issues/2019-03-27 this.focus = (document.visibilityState == "visible"); - if (!this.focus && !!this.rematchOffer) { - this.rematchOffer = ""; - this.send("rematchoffer", { data: false }); - // Do not remove rematch offer from (local) storage - } this.send(this.focus ? "getfocus" : "losefocus"); }, onFocus: function() { @@ -309,14 +295,20 @@ export default { }, onBlur: function() { this.focus = false; - if (!!this.rematchOffer) { - this.rematchOffer = ""; - this.send("rematchoffer", { data: false }); - } this.send("losefocus"); }, isLargeScreen: function() { - return window.innerWidth >= 500; + return window.innerWidth >= 768; + }, + btnTooltipClass: function(thing) { + let append = {}; + if (!!thing) append = { [thing + "-" + this[thing + "Offer"]]: true }; + return ( + Object.assign( + { tooltip: !("ontouchstart" in window) }, + append + ) + ); }, gotoRules: function() { this.$router.push("/variants/" + this.game.vname); @@ -678,7 +670,6 @@ export default { !this.gotLastate && !!this.game.mycolor && this.game.type == "live" && - this.game.score == "*" && this.game.players.some(p => p.sid == user.sid) ) { this.send("asklastate", { target: user.sid }); @@ -816,10 +807,25 @@ export default { } } this.$refs["basegame"].play(movePlus.move, "received"); - this.game.clocks[moveColIdx] = movePlus.clock; - this.processMove( - movePlus.move, - { receiveMyMove: receiveMyMove } + // Freeze time while the move is being play + // (TODO: a callback would be cleaner here) + clearInterval(this.clockUpdate); + this.clockUpdate = null; + const freezeDuration = ["all", "highlight"].includes(V.ShowMoves) + // 250 = length of animation, 500 = delay between sub-moves + ? 250 + 750 * + (Array.isArray(movePlus.move) ? movePlus.move.length - 1 : 0) + // Incomplete information: no move animation + : 0; + setTimeout( + () => { + this.game.clocks[moveColIdx] = movePlus.clock; + this.processMove( + movePlus.move, + { receiveMyMove: receiveMyMove } + ); + }, + freezeDuration ); } } @@ -862,7 +868,7 @@ export default { if (!!this.game.mycolor && this.game.type == "live") { GameStorage.update( this.gameRef, - { rematchOffer: V.GetOppCol(this.game.mycolor) } + { rematchOffer: data.data ? V.GetOppCol(this.game.mycolor) : "" } ); } break; @@ -929,8 +935,8 @@ export default { clock: this.game.clocks[myIdx], // Since we played a move (or abort or resign), // only drawOffer=="sent" is possible - drawSent: this.drawOffer == "sent", - rematchSent: this.rematchOffer == "sent", + drawSent: this.drawOffer == "sent" ? true : undefined, + rematchSent: this.rematchOffer == "sent" ? true : undefined, score: this.game.score != "*" ? this.game.score : undefined, scoreMsg: this.game.score != "*" ? this.game.scoreMsg : undefined, movesCount: L @@ -941,23 +947,47 @@ export default { processLastate: function() { const data = this.lastate; this.lastate = undefined; //security... - const L = this.game.moves.length; - const oppIdx = 1 - ["w", "b"].indexOf(this.game.mycolor); - this.game.clocks[oppIdx] = data.clock; - if (data.movesCount > L) { - // Just got last move from him - this.$refs["basegame"].play(data.lastMove, "received"); - this.processMove(data.lastMove); - } else { - if (!!this.clockUpdate) clearInterval(this.clockUpdate); - this.re_setClocks(); - } - if (data.drawSent) this.drawOffer = "received"; - if (data.rematchSent) this.rematchOffer = "received"; if (!!data.score) { - this.drawOffer = ""; - if (this.game.score == "*") - this.gameOver(data.score, data.scoreMsg); + const oppCol = V.GetOppCol(this.game.mycolor); + if (!!data.rematchSent) { + if (this.game.rematchOffer != oppCol) { + // Opponent sended rematch offer while we were offline: + this.rematchOffer = "received"; + GameStorage.update( + this.gameRef, + { rematchOffer: oppCol } + ); + } + } + else { + if (this.game.rematchOffer == oppCol) { + // Opponent cancelled rematch offer while we were offline: + this.rematchOffer = ""; + GameStorage.update( + this.gameRef, + { rematchOffer: "" } + ); + } + } + } + else { + const L = this.game.moves.length; + const oppIdx = 1 - ["w", "b"].indexOf(this.game.mycolor); + this.game.clocks[oppIdx] = data.clock; + if (data.movesCount > L) { + // Just got last move from him + this.$refs["basegame"].play(data.lastMove, "received"); + this.processMove(data.lastMove); + } else { + if (!!this.clockUpdate) clearInterval(this.clockUpdate); + this.re_setClocks(); + } + if (!!data.drawSent) this.drawOffer = "received"; + if (!!data.score) { + this.drawOffer = ""; + if (this.game.score == "*") + this.gameOver(data.score, data.scoreMsg); + } } }, clickDraw: function() { @@ -1181,8 +1211,9 @@ export default { if ( (game.rematchOffer == "w" && myIdx == 0) || (game.rematchOffer == "b" && myIdx == 1) - ) + ) { this.rematchOffer = "sent"; + } else this.rematchOffer = "received"; } } @@ -1687,10 +1718,14 @@ span.separator span.name font-size: 1.5rem + @media screen and (max-width: 767px) + font-size: 1.2rem padding: 0 3px span.time font-size: 2rem + @media screen and (max-width: 767px) + font-size: 1.5rem display: inline-block .time-left margin-left: 10px