X-Git-Url: https://git.auder.net/?a=blobdiff_plain;f=app.js;h=a46ceb39d5ca33499d6814ef7503844d1b44d28f;hb=8a9f61cec20509fd4398169d4ce1da73157d32ab;hp=f89706233b24ef2fb380202f9cc0f59cceb24c7f;hpb=41534b92f0bcfc8ef5f58d8040706a5e7ce088c6;p=xogo.git diff --git a/app.js b/app.js index f897062..a46ceb3 100644 --- a/app.js +++ b/app.js @@ -30,6 +30,22 @@ if (!localStorage.getItem("name")) const sid = localStorage.getItem("sid"); $.getElementById("myName").value = localStorage.getItem("name"); +// "Material" input field name +let inputName = document.getElementById("myName"); +let formField = document.getElementById("ng-name"); +const setActive = (active) => { + if (active) formField.classList.add("form-field--is-active"); + else { + formField.classList.remove("form-field--is-active"); + inputName.value === "" ? + formField.classList.remove("form-field--is-filled") : + formField.classList.add("form-field--is-filled"); + } +}; +inputName.onblur = () => setActive(false); +inputName.onfocus = () => setActive(true); +inputName.focus(); + ///////// // Utils @@ -39,10 +55,24 @@ function setName() { // Turn a "tab" on, and "close" all others function toggleVisible(element) { - for (elt of document.querySelectorAll('body > div')) { + for (elt of document.querySelectorAll('main > div')) { if (elt.id != element) elt.style.display = "none"; else elt.style.display = "block"; } + if (element == "boardContainer") { + // Avoid smartphone scrolling effects (TODO?) + document.querySelector("html").style.overflow = "hidden"; + document.body.style.overflow = "hidden"; + } + else { + document.querySelector("html").style.overflow = "visible"; + document.body.style.overflow = "visible"; + if (element == "newGame") { + // Workaround "superposed texts" effect + inputName.focus(); + inputName.blur(); + } + } } let seek_vname; @@ -74,8 +104,8 @@ function showNewGameForm() { $.getElementById("selectColor").selectedIndex = 0; toggleVisible("newGameForm"); import(`/variants/${vname}/class.js`).then(module => { - const Rules = module.default; - prepareOptions(Rules); + window.V = module.default; + prepareOptions(); }); } } @@ -87,50 +117,68 @@ function toggleStyle(e, word) { } let options; -function prepareOptions(Rules) { +function prepareOptions() { options = {}; - let optHtml = ""; - for (let select of Rules.Options.select) { - optHtml += ` - - ` + + select.options.map(option => { return ` + `; + }).join("") + ` + + + + `; + }).join(""); + optHtml += V.Options.check.map(check => { + return ` +
+ +
`; + }).join(""); + if (V.Options.styles.length >= 1) { + optHtml += '
'; + let i = 0; + const stylesLength = V.Options.styles.length; + while (i < stylesLength) { + optHtml += '
'; + for (let j=i; j${style}`; + } + optHtml += "
"; + i += 4; } - optHtml += ''; - } - for (let check of Rules.Options.check) { - optHtml += ` - - = 1) optHtml += "

"; - for (let style of Rules.Options.styles) { - optHtml += ` - - ${style} - `; - } - if (Rules.Options.styles.length >= 1) optHtml += "

"; $.getElementById("gameOptions").innerHTML = optHtml; } function getGameLink() { const vname = $.getElementById("selectVariant").value; const color = $.getElementById("selectColor").value; - for (const select of $.querySelectorAll("#gameOptions > select")) { + for (const select of $.querySelectorAll("#gameOptions select")) { let value = select.value; if (select.attributes["data-numeric"]) value = parseInt(value, 10); - options[ select.id.split("_")[1] ] = value; + if (value) options[ select.id.split("_")[1] ] = value; + } + for (const check of $.querySelectorAll("#gameOptions input")) { + if (check.checked) options[ check.id.split("_")[1] ] = check.checked; } - for (const check of $.querySelectorAll("#gameOptions > input")) - options[ check.id.split("_")[1] ] = check.checked; send("creategame", { vname: vname, player: { sid: sid, name: localStorage.getItem("name"), color: color }, @@ -143,28 +191,36 @@ const fillGameInfos = (gameInfos, oppIndex) => { .then(res => res.text()) .then(txt => { let htmlContent = ` -

- ${gameInfos.vdisp} - vs. ${gameInfos.players[oppIndex].name} -

-
-

`; - htmlContent += - Object.entries(gameInfos.options).map(opt => { - return ( - '' + - (opt[1] === true ? opt[0] : `${opt[0]}:${opt[1]}`) + - '' - ); - }) - .join(", "); +

+

+ ${gameInfos.vdisp} + vs. ${gameInfos.players[oppIndex].name} +

+
`; + const options = Object.entries(gameInfos.options); + if (options.length > 0) { + htmlContent += '
'; + let i = 0; + while (i < options.length) { + htmlContent += '
'; + for (let j=i; j' + + (opt[1] === true ? opt[0] : `${opt[0]}:${opt[1]}`) + " " + + ''; + } + htmlContent += "
"; + i += 4; + } + htmlContent += "
"; + } htmlContent += ` -

-
-
- ${txt} -
- `; +
${txt}
+
+ +
`; $.getElementById("gameInfos").innerHTML = htmlContent; }); }; @@ -207,7 +263,7 @@ const messageCenter = (msg) => { switch (obj.code) { // Start new game: case "gamestart": { - if (!$.hasFocus()) notifyMe("game"); + if (document.hidden) notifyMe("game"); gid = obj.gid; initializeGame(obj); break; @@ -239,7 +295,10 @@ const messageCenter = (msg) => { break; // Receive opponent's move: case "newmove": - if (!$.hasFocus()) notifyMe("move"); + send("gotmove", {fen: obj.fen, gid: gid}); + if (obj.fen == lastFen) break; //got this move already + lastFen = obj.fen; + if (document.hidden) notifyMe("move"); vr.playReceivedMove(obj.moves, () => { if (vr.getCurrentScore(obj.moves[obj.moves.length-1]) != "*") { localStorage.removeItem("gid"); @@ -248,6 +307,16 @@ const messageCenter = (msg) => { else toggleTurnIndicator(true); }); break; + // The server notifies that it got our move: + case "gotmove": + if (obj.fen == lastFen) { + curMoves = []; + clearTimeout(timeout1); + clearTimeout(timeout2); + clearTimeout(timeout3); + callbackAfterConfirmation(); + } + break; // Opponent stopped game (draw, abort, resign...) case "gameover": toggleVisible("gameStopped"); @@ -314,31 +383,45 @@ function notifyMe(code) { } if (Notification.permission === 'granted') doNotify(); else if (Notification.permission !== 'denied') { - Notification.requestPermission().then((permission) => { + Notification.requestPermission().then(permission => { if (permission === 'granted') doNotify(); }); } } -let curMoves = []; -const afterPlay = (move) => { //pack into one moves array, then send +let curMoves = [], + lastFen, lastMove, + timeout1, timeout2, timeout3; +const callbackAfterConfirmation = () => { + const result = vr.getCurrentScore(lastMove); + if (result != "*") { + setTimeout( () => { + toggleVisible("gameStopped"); + send("gameover", { gid: gid }); + }, 2000); + } +}; +const afterPlay = (move) => { + // Pack into one moves array, then send curMoves.push({ appear: move.appear, vanish: move.vanish, start: move.start, end: move.end }); - if (vr.turn != color) { + lastMove = move; + if (vr.turn != playerColor) { toggleTurnIndicator(false); - send("newmove", { gid: gid, moves: curMoves, fen: vr.getFen() }); - curMoves = []; - const result = vr.getCurrentScore(move); - if (result != "*") { - setTimeout( () => { - toggleVisible("gameStopped"); - send("gameover", { gid: gid }); - }, 2000); - } + lastFen = vr.getFen(); + const sendMove = + () => send("newmove", {gid: gid, moves: curMoves, fen: lastFen}); + // Send move until we obtain confirmation or timeout, then callback + sendMove(); + timeout1 = setTimeout(sendMove, 500); + timeout2 = setTimeout(sendMove, 1500); + timeout3 = setTimeout( + () => alert("The move may be lost :( Please reload"), + 3000); } }; @@ -354,35 +437,45 @@ const conditionalLoadCSS = (vname) => { } }; -let vr, color; +let vr, playerColor; function initializeGame(obj) { const options = obj.options || {}; import(`/variants/${obj.vname}/class.js`).then(module => { - const Rules = module.default; + window.V = module.default; conditionalLoadCSS(obj.vname); - color = (sid == obj.players[0].sid ? "w" : "b"); + playerColor = (sid == obj.players[0].sid ? "w" : "b"); // Init + remove potential extra DOM elements from a previous game: document.getElementById("boardContainer").innerHTML = `
- + + + + +
- + + + + +
`; - vr = new Rules({ + vr = new V({ seed: obj.seed, //may be null if FEN already exists (running game) fen: obj.fen, element: "chessboard", - color: color, + color: playerColor, afterPlay: afterPlay, options: options }); if (!obj.fen) { // Game creation - if (color == "w") send("setfen", {gid: obj.gid, fen: vr.getFen()}); + if (playerColor == "w") send("setfen", {gid: obj.gid, fen: vr.getFen()}); localStorage.setItem("gid", obj.gid); } const select = $.getElementById("selectVariant"); @@ -393,10 +486,10 @@ function initializeGame(obj) { break; } } - fillGameInfos(obj, color == "w" ? 1 : 0); + fillGameInfos(obj, playerColor == "w" ? 1 : 0); if (obj.randvar) toggleVisible("gameInfos"); else toggleVisible("boardContainer"); - toggleTurnIndicator(vr.turn == color); + toggleTurnIndicator(vr.turn == playerColor); }); } @@ -411,7 +504,11 @@ function confirmStopGame() { function toggleGameInfos() { if ($.getElementById("gameInfos").style.display == "none") toggleVisible("gameInfos"); - else toggleVisible("boardContainer"); + else { + toggleVisible("boardContainer"); + // Quickfix for the "vanished piece" bug (move played while on game infos) + vr.setupPieces(); //TODO: understand better + } } $.body.addEventListener("keydown", (e) => {