span.variantName {{ curChallToAccept.vname }}
span {{ curChallToAccept.cadence }}
span {{ st.tr["with"] + " " + curChallToAccept.from.name }}
- .diagram(v-html="tchallDiag")
- .button-group#buttonsTchall
+ .diagram(
+ v-if="!!curChallToAccept.fen"
+ v-html="tchallDiag"
+ )
+ .button-group#buttonsTchall(:style="tchallButtonsMargin()")
button.acceptBtn(@click="decisionChallenge(true)")
span {{ st.tr["Accept challenge?"] }}
button.refuseBtn(@click="decisionChallenge(false)")
)
| {{ st.tr["Observe"] }}
button.player-action(
- v-else-if="st.user.id > 0 && sid != st.user.sid"
+ v-else-if="isFocusedOnHall(sid)"
@click="challenge(sid)"
)
| {{ st.tr["Challenge"] }}
.button-group
button#peopleBtn(onClick="window.doClick('modalPeople')")
| {{ st.tr["Who's there?"] }}
- button(onClick="window.doClick('modalNewgame')")
+ button(@click="showNewchallengeForm()")
| {{ st.tr["New game"] }}
.row
.col-sm-12.col-md-10.col-md-offset-1.col-lg-8.col-lg-offset-2
if (this.st.variants.length > 0 && this.newchallenge.vid > 0)
this.loadNewchallVariant();
const my = this.st.user;
- this.$set(this.people, my.sid, { id: my.id, name: my.name, pages: ["/"] });
+ this.$set(
+ this.people,
+ my.sid,
+ {
+ id: my.id,
+ name: my.name,
+ pages: [{ path: "/", focus: true }]
+ }
+ );
// Ask server for current corr games (all but mines)
ajax(
"/games",
this.conn.onclose = this.socketCloseListener;
},
mounted: function() {
+ document.addEventListener('visibilitychange', this.visibilityChange);
["peopleWrap", "infoDiv", "newgameDiv"].forEach(eltName => {
let elt = document.getElementById(eltName);
elt.addEventListener("click", processModalClick);
this.setDisplay("g", showGtype);
},
beforeDestroy: function() {
+ document.removeEventListener('visibilitychange', this.visibilityChange);
this.send("disconnect");
},
methods: {
- // Helpers:
+ visibilityChange: function() {
+ // TODO: Use document.hidden? https://webplatform.news/issues/2019-03-27
+ this.send(
+ document.visibilityState == "visible"
+ ? "getfocus"
+ : "losefocus"
+ );
+ },
+ partialResetNewchallenge: function() {
+ // Reset potential target and custom FEN:
+ this.newchallenge.to = "";
+ this.newchallenge.fen = "";
+ this.newchallenge.diag = "";
+ },
+ showNewchallengeForm: function() {
+ this.partialResetNewchallenge();
+ window.doClick("modalNewgame");
+ },
+ tchallButtonsMargin: function() {
+ if (!!this.curChallToAccept.fen) return { "margin-top": "10px" };
+ return {};
+ },
cadenceFocusIfOpened: function() {
if (event.target.checked)
document.getElementById("cadence").focus();
else elt.nextElementSibling.classList.remove("active");
},
isGamer: function(sid) {
- return this.people[sid].pages.some(p => p.indexOf("/game/") >= 0);
+ return this.people[sid].pages
+ .some(p => p.focus && p.path.indexOf("/game/") >= 0);
+ },
+ isFocusedOnHall: function(sid) {
+ return (
+ // This is meant to challenge people, thus the next 2 conditions:
+ this.st.user.id > 0 &&
+ sid != this.st.user.sid &&
+ this.people[sid].pages.some(p => p.path == "/" && p.focus)
+ );
},
challenge: function(sid) {
- // Available, in Hall (only)
+ this.partialResetNewchallenge();
+ // Available, in Hall
this.newchallenge.to = this.people[sid].name;
document.getElementById("modalPeople").checked = false;
window.doClick("modalNewgame");
// In some game, maybe playing maybe not: show a random one
let gids = [];
this.people[sid].pages.forEach(p => {
- const matchGid = p.match(/[a-zA-Z0-9]+$/);
- if (!!matchGid) gids.push(matchGid[0]);
+ if (p.focus) {
+ const matchGid = p.path.match(/[a-zA-Z0-9]+$/);
+ if (!!matchGid) gids.push(matchGid[0]);
+ }
});
const gid = gids[Math.floor(Math.random() * gids.length)];
const game = this.games.find(g => g.id == gid);
this.send("askidentity", { target: s.sid, page: page });
identityAsked[s.sid] = true;
}
- if (!this.people[s.sid])
+ if (!this.people[s.sid]) {
// Do not set name or id: identity unknown yet
- this.$set(this.people, s.sid, { pages: [page] });
- else if (this.people[s.sid].pages.indexOf(page) < 0)
- this.people[s.sid].pages.push(page);
+ this.people[s.sid] = { pages: [{path: page, focus: true}] };
+ }
+ else if (!(this.people[s.sid].pages.find(p => p.path == page)))
+ this.people[s.sid].pages.push({ path: page, focus: true });
if (!s.page)
// Peer is in Hall
this.send("askchallenge", { target: s.sid });
case "connect":
case "gconnect": {
const page = data.page || "/";
- // NOTE: player could have been polled earlier, but might have logged in then
- // So it's a good idea to ask identity if he was anonymous.
- // But only ask game / challenge if currently disconnected.
+ // Only ask game / challenge if first connexion:
if (!this.people[data.from]) {
- this.$set(this.people, data.from, { pages: [page] });
+ this.people[data.from] = { pages: [{ path: page, focus: true }] };
if (data.code == "connect")
this.send("askchallenge", { target: data.from });
else this.send("askgame", { target: data.from, page: page });
} else {
// Append page if not already in list
- if (this.people[data.from].pages.indexOf(page) < 0)
- this.people[data.from].pages.push(page);
+ if (!(this.people[data.from].pages.find(p => p.path == page)))
+ this.people[data.from].pages.push({ path: page, focus: true });
}
if (!this.people[data.from].name && this.people[data.from].id !== 0) {
// Identity not known yet
}
}
const page = data.page || "/";
- ArrayFun.remove(this.people[data.from].pages, p => p == page);
+ ArrayFun.remove(this.people[data.from].pages, p => p.path == page);
if (this.people[data.from].pages.length == 0)
this.$delete(this.people, data.from);
break;
}
+ case "getfocus":
+ // If user reload a page, focus may arrive earlier than connect
+ if (!!this.people[data.from]) {
+ this.people[data.from].pages
+ .find(p => p.path == data.page).focus = true;
+ this.$forceUpdate(); //TODO: shouldn't be required
+ }
+ break;
+ case "losefocus":
+ if (!!this.people[data.from]) {
+ this.people[data.from].pages
+ .find(p => p.path == data.page).focus = false;
+ this.$forceUpdate(); //TODO: shouldn't be required
+ }
+ break;
case "killed":
// I logged in elsewhere:
this.conn = null;
}
case "identity": {
const user = data.data;
- this.$set(this.people, user.sid, {
- id: user.id,
- name: user.name,
- pages: this.people[user.sid].pages
- });
+ let player = this.people[user.sid];
+ // player.pages is already set
+ player.id = user.id;
+ player.name = user.name;
+ // TODO: this.$set(people, ...) fails. So forceUpdate.
+ // But this shouldn't be like that!
+ this.$forceUpdate();
// If I multi-connect, kill current connexion if no mark (I'm older)
if (this.newConnect[user.sid]) {
if (
}
case "game": //individual request
case "newgame": {
- // NOTE: it may be live or correspondance
const game = data.data;
- // Ignore games where I play (corr games)
+ // Ignore games where I play (will go in MyGames page)
if (game.players.every(p =>
p.sid != this.st.user.sid || p.id != this.st.user.id))
{
break;
}
case "startgame": {
- // New game just started: data contain all information
+ // New game just started, I'm involved
const gameInfo = data.data;
if (this.classifyObject(gameInfo) == "live")
this.startNewGame(gameInfo);
"#/game/" +
gameInfo.id +
"</a>";
- let modalBox = document.getElementById("modalInfo");
- modalBox.checked = true;
+ document.getElementById("modalInfo").checked = true;
}
break;
}
position: parsedFen.position,
orientation: c.mycolor
});
- this.curChallToAccept = c;
- document.getElementById("modalAccept").checked = true;
- }
- else {
- if (!confirm(this.st.tr["Accept challenge?"]))
- c.accepted = false;
- this.finishProcessingChallenge(c);
}
+ this.curChallToAccept = c;
+ document.getElementById("modalAccept").checked = true;
}
- else
- this.finishProcessingChallenge(c);
+ else this.finishProcessingChallenge(c);
}
else {
// My challenge
const notifyNewgame = () => {
const oppsid = this.getOppsid(c);
if (!!oppsid)
- //opponent is online
+ // Opponent is online
this.send("startgame", { data: gameInfo, target: oppsid });
- // Send game info (only if live) to everyone except me in this tab
- this.send("newgame", { data: gameInfo });
+ // Send game info (only if live) to everyone except me and opponent
+ // TODO: this double message send could be avoided.
+ this.send("newgame", { data: gameInfo, oppsid: oppsid });
};
if (c.type == "live") {
notifyNewgame();
this.startNewGame(gameInfo);
- } //corr: game only on server
- else {
+ } else {
+ // corr: game only on server
ajax(
"/games",
"POST",
},
// NOTE: for live games only (corr games start on the server)
startNewGame: function(gameInfo) {
- const game = Object.assign({}, gameInfo, {
- // (other) Game infos: constant
- fenStart: gameInfo.fen,
- vname: this.getVname(gameInfo.vid),
- created: Date.now(),
- // Game state (including FEN): will be updated
- moves: [],
- clocks: [-1, -1], //-1 = unstarted
- initime: [0, 0], //initialized later
- score: "*"
- });
- GameStorage.add(game, (err) => {
- // If an error occurred, game is not added: abort
- if (!err) {
- if (this.st.settings.sound)
- new Audio("/sounds/newgame.flac").play().catch(() => {});
- this.$router.push("/game/" + gameInfo.id);
+ const game = Object.assign(
+ {},
+ gameInfo,
+ {
+ // (other) Game infos: constant
+ fenStart: gameInfo.fen,
+ vname: this.getVname(gameInfo.vid),
+ created: Date.now(),
+ // Game state (including FEN): will be updated
+ moves: [],
+ clocks: [-1, -1], //-1 = unstarted
+ initime: [0, 0], //initialized later
+ score: "*"
}
- });
+ );
+ setTimeout(
+ () => {
+ GameStorage.add(game, (err) => {
+ // If an error occurred, game is not added: a tab already
+ // added the game and (if focused) is redirected toward it.
+ // If no error and the tab is hidden: do not show anything.
+ if (!err && !document.hidden) {
+ if (this.st.settings.sound)
+ new Audio("/sounds/newgame.flac").play().catch(() => {});
+ this.$router.push("/game/" + gameInfo.id);
+ }
+ });
+ },
+ document.hidden ? 500 + 1000 * Math.random() : 0
+ );
}
}
};
background-color: red
#buttonsTchall
- margin-top: 10px
+ // margin-top set dynamically (depends if diagram showed or not)
& > button > span
width: 100%
text-align: center