myid: "", //our ID, always set
oppid: "", //opponent ID in case of HH game
gameId: "", //useful if opponent started other human games after we disconnected
- myname: getCookie("username","anonymous"),
+ myname: localStorage["username"] || "anonymous",
oppName: "anonymous", //opponent name, revealed after a game (if provided)
chats: [], //chat messages after human game
oppConnected: false,
fenStart: "",
incheck: [],
pgnTxt: "",
- hints: (getCookie("hints") === "1" ? true : false),
- color: getCookie("color", "lichess"), //lichess, chesscom or chesstempo
+ hints: (!localStorage["hints"] ? true : localStorage["hints"] === "1"),
+ color: localStorage["color"] || "lichess", //lichess, chesscom or chesstempo
// sound level: 0 = no sound, 1 = sound only on newgame, 2 = always
- sound: parseInt(getCookie("sound", "2")),
+ sound: parseInt(localStorage["sound"] || "2"),
// Web worker to play computer moves without freezing interface:
compWorker: new Worker('/javascripts/playCompMove.js'),
timeStart: undefined, //time when computer starts thinking
},
render(h) {
const [sizeX,sizeY] = [V.size.x,V.size.y];
- const smallScreen = (window.innerWidth <= 420);
// Precompute hints squares to facilitate rendering
let hintSquares = doubleArray(sizeX, sizeY, false);
this.possibleMoves.forEach(m => { hintSquares[m.end.x][m.end.y] = true; });
attrs: { "aria-label": 'New online game' },
'class': {
"tooltip": true,
- "bottom": true, //display below
+ "play": true,
"seek": this.seek,
"playing": this.mode == "human",
- "small": smallScreen,
+ "spaceright": true,
},
},
[h('i', { 'class': { "material-icons": true } }, "accessibility")])
attrs: { "aria-label": 'New game VS computer' },
'class': {
"tooltip":true,
- "bottom": true,
+ "play": true,
"playing": this.mode == "computer",
- "small": smallScreen,
+ "spaceright": true,
},
},
[h('i', { 'class': { "material-icons": true } }, "computer")])
attrs: { "aria-label": 'New IRL game' },
'class': {
"tooltip":true,
- "bottom": true,
+ "play": true,
"playing": this.mode == "friend",
- "small": smallScreen,
+ "spaceright": true,
},
},
[h('i', { 'class': { "material-icons": true } }, "people")])
? parseFloat(window.getComputedStyle(square00).width.slice(0,-2))
: 0;
const settingsBtnElt = document.getElementById("settingsBtn");
- const indicWidth = !!settingsBtnElt //-2 for border:
- ? parseFloat(window.getComputedStyle(settingsBtnElt).height.slice(0,-2)) - 2
- : (smallScreen ? 31 : 37);
+ const settingsStyle = !!settingsBtnElt
+ ? window.getComputedStyle(settingsBtnElt)
+ : {width:"46px", height:"26px"};
+ const [indicWidth,indicHeight] = //[44,24];
+ [
+ // NOTE: -2 for border
+ parseFloat(settingsStyle.width.slice(0,-2)) - 2,
+ parseFloat(settingsStyle.height.slice(0,-2)) - 2
+ ];
+ let aboveBoardElts = [];
if (["chat","human"].includes(this.mode))
{
const connectedIndic = h(
'div',
{
"class": {
- "topindicator": true,
"indic-left": true,
"connected": this.oppConnected,
"disconnected": !this.oppConnected,
},
style: {
"width": indicWidth + "px",
- "height": indicWidth + "px",
+ "height": indicHeight + "px",
},
}
);
- elementArray.push(connectedIndic);
+ aboveBoardElts.push(connectedIndic);
}
if (this.mode == "chat")
{
},
'class': {
"tooltip": true,
- "topindicator": true,
+ "play": true,
+ "above-board": true,
"indic-left": true,
- "settings-btn": !smallScreen,
- "settings-btn-small": smallScreen,
},
},
[h('i', { 'class': { "material-icons": true } }, "chat")]
);
- elementArray.push(chatButton);
+ aboveBoardElts.push(chatButton);
}
else if (this.mode == "computer")
{
},
'class': {
"tooltip": true,
- "topindicator": true,
+ "play": true,
+ "above-board": true,
"indic-left": true,
- "settings-btn": !smallScreen,
- "settings-btn-small": smallScreen,
},
},
[h('i', { 'class': { "material-icons": true } }, "clear")]
);
- elementArray.push(clearButton);
+ aboveBoardElts.push(clearButton);
}
const turnIndic = h(
'div',
{
"class": {
- "topindicator": true,
"indic-right": true,
"white-turn": this.vr.turn=="w",
"black-turn": this.vr.turn=="b",
},
style: {
"width": indicWidth + "px",
- "height": indicWidth + "px",
+ "height": indicHeight + "px",
},
}
);
- elementArray.push(turnIndic);
+ aboveBoardElts.push(turnIndic);
const settingsBtn = h(
'button',
{
},
'class': {
"tooltip": true,
- "topindicator": true,
+ "play": true,
+ "above-board": true,
"indic-right": true,
- "settings-btn": !smallScreen,
- "settings-btn-small": smallScreen,
},
},
[h('i', { 'class': { "material-icons": true } }, "settings")]
);
- elementArray.push(settingsBtn);
+ aboveBoardElts.push(settingsBtn);
+ elementArray.push(
+ h('div',
+ { "class": { "aboveboard-wrapper": true } },
+ aboveBoardElts
+ )
+ );
if (this.mode == "problem")
{
// Show problem instructions
attrs: { "src": '/images/pieces/' +
VariantRules.getPpath(m.appear[0].c+m.appear[0].p) + '.svg' },
'class': { 'choice-piece': true },
- on: { "click": e => { this.play(m); this.choices=[]; } },
+ on: {
+ "click": e => { this.play(m); this.choices=[]; },
+ // NOTE: add 'touchstart' event to fix a problem on smartphones
+ "touchstart": e => { this.play(m); this.choices=[]; },
+ },
})
]
);
(!["idle","chat"].includes(this.mode) || this.cursor==this.vr.moves.length);
const gameDiv = h('div',
{
- 'class': { 'game': true },
+ 'class': {
+ 'game': true,
+ 'clearer': true,
+ },
},
[_.range(sizeX).map(i => {
let ci = (this.mycolor=='w' ? i : sizeX-i-1);
attrs: { "aria-label": 'Resign' },
'class': {
"tooltip":true,
- "bottom": true,
- "small": smallScreen,
+ "play": true,
},
},
[h('i', { 'class': { "material-icons": true } }, "flag")])
on: { click: e => this.undo() },
attrs: { "aria-label": 'Undo' },
"class": {
- "small": smallScreen,
- "marginleft": true,
+ "play": true,
+ "spaceleft": true,
},
},
[h('i', { 'class': { "material-icons": true } }, "fast_rewind")]),
{
on: { click: e => this.play() },
attrs: { "aria-label": 'Play' },
- "class": { "small": smallScreen },
+ "class": {
+ "play": true,
+ "spaceleft": true,
+ },
},
[h('i', { 'class': { "material-icons": true } }, "fast_forward")]),
]
on: { click: this.undoInGame },
attrs: { "aria-label": 'Undo' },
"class": {
- "small": smallScreen,
- "marginleft": true,
+ "play": true,
+ "spaceleft": true,
},
},
[h('i', { 'class': { "material-icons": true } }, "undo")]
{
on: { click: () => { this.mycolor = this.vr.getOppCol(this.mycolor) } },
attrs: { "aria-label": 'Flip' },
- "class": { "small": smallScreen },
+ "class": {
+ "play": true,
+ "spaceleft": true,
+ },
},
[h('i', { 'class': { "material-icons": true } }, "cached")]
),
{
myReservePiecesArray.push(h('div',
{
- 'class': {'board':true, ['board'+sizeY]:true},
+ 'class': {'board':true, ['board'+sizeY+'-reserve']:true},
attrs: { id: this.getSquareId({x:sizeX+shiftIdx,y:i}) }
},
[
h('img',
{
- 'class': {"piece":true},
+ 'class': {"piece":true, "reserve":true},
attrs: {
"src": "/images/pieces/" +
this.vr.getReservePpath(this.mycolor,i) + ".svg",
{
oppReservePiecesArray.push(h('div',
{
- 'class': {'board':true, ['board'+sizeY]:true},
+ 'class': {'board':true, ['board'+sizeY+'-reserve']:true},
attrs: { id: this.getSquareId({x:sizeX+(1-shiftIdx),y:i}) }
},
[
h('img',
{
- 'class': {"piece":true},
+ 'class': {"piece":true, "reserve":true},
attrs: {
"src": "/images/pieces/" +
this.vr.getReservePpath(oppCol,i) + ".svg",
];
elementArray = elementArray.concat(modalEog);
}
- // NOTE: this modal could be in Pug view (no usage of Vue functions or variables)
- const modalNewgame = [
- h('input',
- {
- attrs: { "id": "modal-newgame", type: "checkbox" },
- "class": { "modal": true },
- }),
- h('div',
- {
- attrs: { "role": "dialog", "aria-labelledby": "newGameTxt" },
- },
- [
- h('div',
- {
- "class": { "card": true, "smallpad": true },
- },
- [
- h('label',
- {
- attrs: { "id": "close-newgame", "for": "modal-newgame" },
- "class": { "modal-close": true },
- }
- ),
- h('h3',
- {
- attrs: { "id": "newGameTxt" },
- "class": { "section": true },
- domProps: { innerHTML: "New game" },
- }
- ),
- h('p',
- {
- "class": { "section": true },
- domProps: { innerHTML: "Waiting for opponent..." },
- }
- )
- ]
- )
- ]
- )
- ];
- elementArray = elementArray.concat(modalNewgame);
const modalFenEdit = [
h('input',
{
),
h('button',
{
+ attrs: { id: "sendChatBtn"},
on: { click: this.sendChat },
domProps: { innerHTML: "Send" },
}
[
h('h3',
{
+ "class": { clickable: true },
domProps: { innerHTML: "Show solution" },
on: { click: this.toggleShowSolution },
}
h('p',
{
attrs: { id: "fen-string" },
- domProps: { innerHTML: this.vr.getBaseFen() }
+ domProps: { innerHTML: this.vr.getBaseFen() },
+ "class": { "text-center": true },
}
)
]
{
'class': {
"col-sm-12":true,
- "col-md-8":true,
- "col-md-offset-2":true,
- "col-lg-6":true,
- "col-lg-offset-3":true,
+ "col-md-10":true,
+ "col-md-offset-1":true,
+ "col-lg-8":true,
+ "col-lg-offset-2":true,
},
// NOTE: click = mousedown + mouseup
on: {
methods: {
setMyname: function(e) {
this.myname = e.target.value;
- setCookie("username",this.myname);
+ localStorage["username"] = this.myname;
},
trySendChat: function(e) {
if (e.keyCode == 13) //'enter' key
setTimeout(() => { modalBox.checked = false; }, 2000);
},
endGame: function(score) {
- console.log("call " + score + " " + this.mode);
this.score = score;
if (["human","computer"].includes(this.mode))
{
},
toggleHints: function() {
this.hints = !this.hints;
- setCookie("hints", this.hints ? "1" : "0");
+ localStorage["hints"] = (this.hints ? "1" : "0");
},
setColor: function(e) {
this.color = e.target.options[e.target.selectedIndex].value;
- setCookie("color", this.color);
+ localStorage["color"] = this.color;
},
setSound: function(e) {
this.sound = parseInt(e.target.options[e.target.selectedIndex].value);
- setCookie("sound", this.sound);
+ localStorage["sound"] = this.sound;
},
clickGameSeek: function(e) {
this.getRidOfTooltip(e.currentTarget);
const storageVariant = localStorage.getItem("comp-variant");
if (!!storageVariant)
{
- if (storageVariant !== variant)
+ const score = localStorage.getItem("comp-score");
+ if (storageVariant !== variant && score == "*")
{
if (!confirm("Unfinished " + storageVariant +
" computer game will be erased"))
return;
}
}
- else
- {
- const score = localStorage.getItem("comp-score");
- if (score == "*")
- return this.continueGame("computer");
- }
+ else if (score == "*")
+ return this.continueGame("computer");
}
}
this.vr = new VariantRules(fen, []);
// Not programmatic, or animation is over
if (this.mode == "human" && this.vr.turn == this.mycolor)
this.conn.send(JSON.stringify({code:"newmove", move:move, oppid:this.oppid}));
- if (this.sound == 2)
- new Audio("/sounds/chessmove1.mp3").play().catch(err => {});
if (!["idle","chat"].includes(this.mode))
{
// Emergency check, if human game started "at the same time"
return;
this.incheck = this.vr.getCheckSquares(move); //is opponent in check?
this.vr.play(move, "ingame");
+ if (this.sound == 2)
+ new Audio("/sounds/move.mp3").play().catch(err => {});
if (this.mode == "computer")
{
// Send the move to web worker (TODO: including his own moves?!)
if (!!lm)
{
this.vr.undo(lm);
+ if (this.sound == 2)
+ new Audio("/sounds/undo.mp3").play().catch(err => {});
const lmBefore = this.vr.lastMove;
if (!!lmBefore)
{