import { store } from "@/store";
import { GameStorage } from "@/utils/gameStorage";
import { ppt } from "@/utils/datetime";
+import { notify } from "@/utils/notifications";
import { ajax } from "@/utils/ajax";
import { extractTime } from "@/utils/timeControl";
import { getRandString } from "@/utils/alea";
gameRef: "",
nextIds: [],
game: {}, //passed to BaseGame
+ focus: false,
// virtualClocks will be initialized from true game.clocks
virtualClocks: [],
vr: null, //"variant rules" object initialized from FEN
cleanBeforeDestroy: function() {
clearInterval(this.socketCloseListener);
document.removeEventListener('visibilitychange', this.visibilityChange);
+ window.removeEventListener('focus', this.onFocus);
+ window.removeEventListener('blur', this.onBlur);
if (!!this.askLastate) clearInterval(this.askLastate);
if (!!this.retrySendmove) clearInterval(this.retrySendmove);
if (!!this.clockUpdate) clearInterval(this.clockUpdate);
},
visibilityChange: function() {
// TODO: Use document.hidden? https://webplatform.news/issues/2019-03-27
- this.send(
- document.visibilityState == "visible"
- ? "getfocus"
- : "losefocus"
- );
+ 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() {
+ this.focus = true;
+ this.send("getfocus");
+ },
+ onBlur: function() {
+ this.focus = false;
+ if (!!this.rematchOffer) {
+ this.rematchOffer = "";
+ this.send("rematchoffer", { data: false });
+ }
+ this.send("losefocus");
},
participateInChat: function(p) {
return Object.keys(p.tmpIds).some(x => p.tmpIds[x].focus) && !!p.name;
},
atCreation: function() {
document.addEventListener('visibilitychange', this.visibilityChange);
+ window.addEventListener('focus', this.onFocus);
+ window.addEventListener('blur', this.onBlur);
// 0] (Re)Set variables
this.gameRef = this.$route.params["id"];
// next = next corr games IDs to navigate faster (if applicable)
// NOTE: anonymous chats in corr games are not stored on server (TODO?)
if (this.game.type == "corr" && this.st.user.id > 0)
this.updateCorrGame({ chat: chat });
+ else if (this.game.type == "live") {
+ chat.added = Date.now();
+ GameStorage.update(this.gameRef, { chat: chat });
+ }
},
clearChat: function() {
- // Nothing more to do if game is live (chats not recorded)
- if (this.game.type == "corr") {
- if (!!this.game.mycolor) {
+ if (!!this.game.mycolor) {
+ if (this.game.type == "corr") {
ajax(
"/chats",
"DELETE",
{ data: { gid: this.game.id } }
);
+ } else {
+ // Live game
+ GameStorage.update(this.gameRef, { delchat: true });
}
this.$set(this.game, "chats", []);
}
this.send("fullgame", { data: gameToSend, target: data.from });
break;
case "fullgame":
- // Callback "roomInit" to poll clients only after game is loaded
- this.loadVariantThenGame(data.data, this.roomInit);
+ if (!!data.data.empty) {
+ alert(this.st.tr["The game should be in another tab"]);
+ this.$router.go(-1);
+ }
+ else
+ // Callback "roomInit" to poll clients only after game is loaded
+ this.loadVariantThenGame(data.data, this.roomInit);
break;
case "asklastate":
// Sending informative last state if I played a move or score != "*"
} else {
this.gotMoveIdx = movePlus.index;
const receiveMyMove = (movePlus.color == this.game.mycolor);
- if (!receiveMyMove && !!this.game.mycolor)
+ const moveColIdx = ["w", "b"].indexOf(movePlus.color);
+ if (!receiveMyMove && !!this.game.mycolor) {
// Notify opponent that I got the move:
this.send("gotmove", {data: movePlus.index, target: data.from});
+ // And myself if I'm elsewhere:
+ if (!this.focus) {
+ notify(
+ "New move",
+ {
+ body:
+ (this.game.players[moveColIdx].name || "@nonymous") +
+ " just played."
+ }
+ );
+ }
+ }
if (movePlus.cancelDrawOffer) {
// Opponent refuses draw
this.drawOffer = "";
}
}
this.$refs["basegame"].play(movePlus.move, "received", null, true);
- const moveColIdx = ["w", "b"].indexOf(movePlus.color);
this.game.clocks[moveColIdx] = movePlus.clock;
this.processMove(
movePlus.move,
}
break;
}
- case "newchat":
- this.$refs["chatcomp"].newChat(data.data);
+ case "newchat": {
+ let chat = data.data;
+ this.$refs["chatcomp"].newChat(chat);
+ if (this.game.type == "live") {
+ chat.added = Date.now();
+ GameStorage.update(this.gameRef, { chat: chat });
+ }
if (!document.getElementById("modalChat").checked)
document.getElementById("chatBtn").classList.add("somethingnew");
break;
+ }
}
},
updateCorrGame: function(obj, callback) {
return p.sid == this.st.user.sid || p.id == this.st.user.id;
});
const mycolor = [undefined, "w", "b"][myIdx + 1]; //undefined for observers
- if (!game.chats) game.chats = []; //live games don't have chat history
+ // Live games before 26/03/2020 don't have chat history. TODO: remove next line
+ if (!game.chats) game.chats = [];
+ // Sort chat messages from newest to oldest
+ game.chats.sort((c1, c2) => c2.added - c1.added);
if (gtype == "corr") {
// NOTE: clocks in seconds
game.moves.sort((m1, m2) => m1.idx - m2.idx); //in case of
(Date.now() - game.moves[L-1].played) / 1000;
}
}
- // Sort chat messages from newest to oldest
- game.chats.sort((c1, c2) => {
- return c2.added - c1.added;
- });
if (myIdx >= 0 && game.score == "*" && game.chats.length > 0) {
// Did a chat message arrive after my last move?
let dtLastMove = 0;
game.moves = game.moves.map(m => m.squares);
}
if (gtype == "live") {
+ if (
+ game.chats.length > 0 &&
+ (!game.initime || game.initime < game.chats[0].added)
+ ) {
+ document.getElementById("chatBtn").classList.add("somethingnew");
+ }
if (game.clocks[0] < 0) {
// Game is unstarted. clock is ignored until move 2
game.clocks = [tc.mainTime, tc.mainTime];
});
};
// The active tab can update storage immediately
- if (!document.hidden) updateStorage();
+ if (this.focus) updateStorage();
// Small random delay otherwise
else setTimeout(updateStorage, 500 + 1000 * Math.random());
}
};
if (this.game.type == "live") {
GameStorage.update(this.gameRef, scoreObj);
+ // Notify myself locally if I'm elsewhere:
+ if (!this.focus) {
+ notify(
+ "Game over",
+ { body: score + " : " + scoreMsg }
+ );
+ }
if (!!callback) callback();
}
else this.updateCorrGame(scoreObj, callback);