From 41c80bb63b85b2696d3925c10784c3d7bb5d2aa3 Mon Sep 17 00:00:00 2001
From: Benjamin Auder <benjamin.auder@somewhere>
Date: Sat, 1 Feb 2020 23:51:25 +0100
Subject: [PATCH] TODO: fix draw logic

---
 client/src/components/BaseGame.vue | 36 +++++++++++++-----------------
 client/src/components/Board.vue    |  2 +-
 client/src/components/Chat.vue     |  2 --
 client/src/components/GameList.vue | 10 ++++-----
 client/src/components/Language.vue |  2 +-
 client/src/components/MoveList.vue |  8 +++++++
 client/src/components/Settings.vue |  2 +-
 client/src/views/Game.vue          | 31 ++++++++++++-------------
 client/src/views/Hall.vue          | 21 ++++++++++++-----
 client/src/views/MyGames.vue       |  4 ----
 client/src/views/Rules.vue         |  4 ++--
 client/src/views/Variants.vue      |  3 +--
 server/models/Game.js              |  4 +---
 server/sockets.js                  | 11 ++++++---
 14 files changed, 73 insertions(+), 67 deletions(-)

diff --git a/client/src/components/BaseGame.vue b/client/src/components/BaseGame.vue
index 2bf1fbdb..595f9aa3 100644
--- a/client/src/components/BaseGame.vue
+++ b/client/src/components/BaseGame.vue
@@ -26,8 +26,7 @@ div#baseGame(tabindex=-1 @click="() => focusBg()"
       MoveList(v-if="showMoves" :score="game.score" :message="game.scoreMsg"
         :firstNum="firstMoveNumber" :moves="moves" :cursor="cursor"
         @goto-move="gotoMove")
-  // TODO: clearer required ?!
-  .clearer
+    .clearer
 </template>
 
 <script>
@@ -94,7 +93,7 @@ export default {
   },
   methods: {
     focusBg: function() {
-      // TODO: small blue border appears...
+      // NOTE: small blue border appears...
       document.getElementById("baseGame").focus();
     },
     handleKeys: function(e) {
@@ -120,10 +119,14 @@ export default {
       }
     },
     handleScroll: function(e) {
-      if (e.deltaY < 0)
-        this.undo();
-      else if (e.deltaY > 0)
-        this.play();
+      if (this.game.mode == "analyze" || this.game.score != "*")
+      {
+        e.preventDefault();
+        if (e.deltaY < 0)
+          this.undo();
+        else if (e.deltaY > 0)
+          this.play();
+      }
     },
     re_setVariables: function() {
       this.endgameMessage = "";
@@ -350,7 +353,7 @@ export default {
 };
 </script>
 
-<style lang="sass">
+<style lang="sass" scoped>
 #baseGame
   width: 100%
 
@@ -360,11 +363,6 @@ export default {
 
 #modal-eog+div .card
   overflow: hidden
-@media screen and (min-width: 768px)
-  #controls
-    width: 400px
-    margin-left: auto
-    margin-right: auto
 #controls
   margin-top: 10px
   margin-left: auto
@@ -373,12 +371,17 @@ export default {
     display: inline-block
     width: 20%
     margin: 0
+@media screen and (min-width: 768px)
+  #controls
+    max-width: 400px
 #pgnDiv
   text-align: center
   margin-left: auto
   margin-right: auto
 #boardContainer
   float: left
+// TODO: later, maybe, allow movesList of variable width
+// or e.g. between 250 and 350px (but more complicated)
 #movesList
   width: 280px
   float: left
@@ -387,11 +390,4 @@ export default {
     width: 100%
     float: none
     clear: both
-    table
-      tr
-        display: flex
-        margin: 0
-        padding: 0
-        td
-          text-align: left
 </style>
diff --git a/client/src/components/Board.vue b/client/src/components/Board.vue
index 25da6f14..1b7fd6bc 100644
--- a/client/src/components/Board.vue
+++ b/client/src/components/Board.vue
@@ -363,7 +363,7 @@ export default {
 };
 </script>
 
-<style lang="sass">
+<style lang="sass" scoped>
 .game.reserve-div
   margin-bottom: 18px
 
diff --git a/client/src/components/Chat.vue b/client/src/components/Chat.vue
index cbfb8059..18ce6fa9 100644
--- a/client/src/components/Chat.vue
+++ b/client/src/components/Chat.vue
@@ -68,6 +68,4 @@ export default {
   color: grey
 .opp-chatmsg
   color: black
-#chat
-  max-width: 100%
 </style>
diff --git a/client/src/components/GameList.vue b/client/src/components/GameList.vue
index 4233a01b..5ab61cc3 100644
--- a/client/src/components/GameList.vue
+++ b/client/src/components/GameList.vue
@@ -50,7 +50,7 @@ export default {
               priority++;
           }
         }
-        return Object.assign({}, g, {priority: priority, myTurn: priority==2});
+        return Object.assign({}, g, {priority: priority, myTurn: priority==3});
       });
       return augmentedGames.sort((g1,g2) => { return g2.priority - g1.priority; });
     },
@@ -58,8 +58,8 @@ export default {
 };
 </script>
 
-<style scoped lang="sass">
-.my-turn
-  // TODO: the style doesn't work... why?
-  background-color: orange
+<style lang="sass" scoped>
+// TODO: understand why the style applied to <tr> element doesn't work
+tr.my-turn > td
+  background-color: #fcd785
 </style>
diff --git a/client/src/components/Language.vue b/client/src/components/Language.vue
index ac4faa79..c701e590 100644
--- a/client/src/components/Language.vue
+++ b/client/src/components/Language.vue
@@ -29,7 +29,7 @@ export default {
     };
   },
   mounted: function() {
-    // TODO: better style would be in pug directly, but how?
+    // NOTE: better style would be in pug directly, but how?
     document.querySelectorAll("#langSelect > option").forEach(opt => {
       if (opt.value == this.st.lang)
         opt.selected = true;
diff --git a/client/src/components/MoveList.vue b/client/src/components/MoveList.vue
index 1209dd99..28d0d009 100644
--- a/client/src/components/MoveList.vue
+++ b/client/src/components/MoveList.vue
@@ -58,6 +58,14 @@ export default {
 <style lang="sass" scoped>
 .moves-list
   min-width: 250px
+@media screen and (max-width: 767px)
+  .moves-list
+    tr
+      display: flex
+      margin: 0
+      padding: 0
+      td
+        text-align: left
 td.highlight-lm
   background-color: plum
 </style>
diff --git a/client/src/components/Settings.vue b/client/src/components/Settings.vue
index 6034ab45..92b463ef 100644
--- a/client/src/components/Settings.vue
+++ b/client/src/components/Settings.vue
@@ -81,7 +81,7 @@ export default {
         return; //no board on page
       const k = document.getElementById("myRange").value;
       const movesWidth = (window.innerWidth >= 768 ? 280 : 0);
-      const minBoardWidth = 240; //TODO: same
+      const minBoardWidth = 240; //TODO: these 240 and 280 are arbitrary...
       // Value of 0 is board min size; 100 is window.width [- movesWidth]
       const boardSize = minBoardWidth +
         k * (window.innerWidth - (movesWidth+minBoardWidth)) / 100;
diff --git a/client/src/views/Game.vue b/client/src/views/Game.vue
index 30fbc39b..e6cb1e70 100644
--- a/client/src/views/Game.vue
+++ b/client/src/views/Game.vue
@@ -135,6 +135,9 @@ export default {
   methods: {
     // O.1] Ask server for room composition:
     roomInit: function() {
+      // Notify the room only now that I connected, because
+      // messages might be lost otherwise (if game loading is slow)
+      this.st.conn.send(JSON.stringify({code:"connect"}));
       this.st.conn.send(JSON.stringify({code:"pollclients"}));
     },
     isConnected: function(index) {
@@ -182,13 +185,12 @@ export default {
         }
         case "identity":
         {
-          let player = this.people[data.user.sid];
           // NOTE: sometimes player.id fails because player is undefined...
           // Probably because the event was meant for Hall?
-          if (!player)
+          if (!this.people[data.user.sid])
             return;
-          player.id = data.user.id;
-          player.name = data.user.name;
+          this.$set(this.people, data.user.sid,
+            {id: data.user.id, name: data.user.name});
           // Sending last state only for live games: corr games are complete
           if (this.game.type == "live" && this.game.oppsid == data.user.sid)
           {
@@ -225,7 +227,7 @@ export default {
             game:myGame, target:data.from}));
           break;
         case "newmove":
-          this.$set(this.game, "moveToPlay", data.move); //TODO: Vue3...
+          this.$set(this.game, "moveToPlay", data.move);
           break;
         case "lastate": //got opponent infos about last move
         {
@@ -245,10 +247,12 @@ export default {
           this.gameOver("1/2", data.message);
           break;
         case "drawoffer":
-          this.drawOffer = "received"; //TODO: observers don't know who offered draw
+          // NOTE: observers don't know who offered draw
+          this.drawOffer = "received";
           break;
         case "askfullgame":
-          this.st.conn.send(JSON.stringify({code:"fullgame", game:this.game, target:data.from}));
+          this.st.conn.send(JSON.stringify({code:"fullgame",
+            game:this.game, target:data.from}));
           break;
         case "fullgame":
           // Callback "roomInit" to poll clients only after game is loaded
@@ -306,13 +310,7 @@ export default {
         });
         this.gameOver("1/2", message);
       }
-      else if (this.drawOffer == "sent")
-      {
-        this.drawOffer = "";
-        if (this.game.type == "corr")
-          GameStorage.update(this.gameRef.id, {drawOffer: false});
-      }
-      else
+      else if (this.drawOffer == "") //no effect if drawOffer == "sent"
       {
         if (!confirm("Offer draw?"))
           return;
@@ -321,8 +319,7 @@ export default {
           if (sid != this.st.user.sid)
             this.st.conn.send(JSON.stringify({code:"drawoffer", target:sid}));
         });
-        if (this.game.type == "corr")
-          GameStorage.update(this.gameRef.id, {drawOffer: true});
+        GameStorage.update(this.gameRef.id, {drawOffer: true});
       }
     },
     abortGame: function() {
@@ -578,7 +575,7 @@ export default {
 };
 </script>
 
-<style lang="sass">
+<style lang="sass" scoped>
 .connected
   background-color: lightgreen
 
diff --git a/client/src/views/Hall.vue b/client/src/views/Hall.vue
index 7b42854d..2df03e6e 100644
--- a/client/src/views/Hall.vue
+++ b/client/src/views/Hall.vue
@@ -49,10 +49,11 @@ main
             button(@click="pdisplay='players'") Players
             button(@click="pdisplay='chat'") Chat
           #players(v-show="pdisplay=='players'")
-            p.text-center(v-for="p in uniquePlayers")
+            p(v-for="p in uniquePlayers")
               span(:class="{anonymous: !!p.count}")
                 | {{ (p.name || '@nonymous') + (!!p.count ? " ("+p.count+")" : "") }}
-              button.player-action(v-if="!p.count" @click="challOrWatch(p,$event)")
+              button.player-action(v-if="!p.count && p.name != st.user.name"
+                  @click="challOrWatch(p,$event)")
                 | {{ whatPlayerDoes(p) }}
           #chat(v-show="pdisplay=='chat'")
             Chat(:players="[]")
@@ -233,8 +234,11 @@ export default {
       return (!!variant ? variant.name : "");
     },
     whatPlayerDoes: function(p) {
-      if (this.games.some(g => g.players.some(pl => pl.sid == p.sid)))
+      if (this.games.some(g => g.type == "live"
+        && g.players.some(pl => pl.sid == p.sid)))
+      {
         return "Playing";
+      }
       return "Challenge"; //player is available
     },
     sendSomethingTo: function(to, code, obj, warnDisconnected) {
@@ -428,7 +432,7 @@ export default {
         case "Playing":
           // NOTE: this search for game was already done for rendering
           this.showGame(this.games.find(
-            g => g.players.some(pl => pl.sid == p.sid)));
+            g => g.type=="live" && g.players.some(pl => pl.sid == p.sid)));
           break;
       };
     },
@@ -620,7 +624,7 @@ export default {
 };
 </script>
 
-<style lang="sass">
+<style lang="sass" scoped>
 #newGame
   display: block
   margin: 10px auto 5px auto
@@ -628,8 +632,13 @@ export default {
   max-width: 100%
   margin: 0;
   border: none;
+#players > p
+  margin-left: 40%
+@media screen and (max-width: 767px)
+  #players > p
+    margin-left: 5px
 .anonymous
   font-style: italic
 button.player-action
-  margin-left: 20px
+  margin-left: 32px
 </style>
diff --git a/client/src/views/MyGames.vue b/client/src/views/MyGames.vue
index 60792542..a8d9e127 100644
--- a/client/src/views/MyGames.vue
+++ b/client/src/views/MyGames.vue
@@ -57,7 +57,3 @@ export default {
   },
 };
 </script>
-
-<style scoped lang="sass">
-/* TODO */
-</style>
diff --git a/client/src/views/Rules.vue b/client/src/views/Rules.vue
index e1ef8fef..82a4a40f 100644
--- a/client/src/views/Rules.vue
+++ b/client/src/views/Rules.vue
@@ -111,7 +111,7 @@ export default {
 };
 </script>
 
-<style lang="sass">
+<style lang="sass" scoped>
 //.section-content
 //  *
 //    margin-left: auto
@@ -194,7 +194,7 @@ ul:not(.browser-default) > li
 .dark-square-diag
   background-color: #6f8f57
 
-// TODO: following is duplicated
+// TODO: following is duplicated (Board.vue)
 div.board
   float: left
   height: 0
diff --git a/client/src/views/Variants.vue b/client/src/views/Variants.vue
index 9d0a42d9..69d4e69c 100644
--- a/client/src/views/Variants.vue
+++ b/client/src/views/Variants.vue
@@ -50,8 +50,7 @@ export default {
 };
 </script>
 
-<!-- Add "scoped" attribute to limit CSS to this component only -->
-<style scoped lang="sass">
+<style lang="sass" scoped>
 // TODO: box-shadow or box-sizing ? https://stackoverflow.com/a/13517809
 .variant
   box-sizing: border-box
diff --git a/server/models/Game.js b/server/models/Game.js
index 02e3194b..5e1c7990 100644
--- a/server/models/Game.js
+++ b/server/models/Game.js
@@ -34,8 +34,6 @@ const UserModel = require("./User");
 const GameModel =
 {
   checkGameInfo: function(g) {
-    if (!g.id.toString().match(/^[0-9]+$/))
-      return "Wrong game ID";
     if (!g.vid.toString().match(/^[0-9]+$/))
       return "Wrong variant ID";
     if (!g.vname.match(/^[a-zA-Z0-9]+$/))
@@ -228,7 +226,7 @@ const GameModel =
       {
 			  query =
 	        "INSERT INTO Chats (gid, msg, name, added) VALUES ("
-            + id + ",?,'" + obj.chat.name + "'," + "," + Date.now() + ")";
+            + id + ",?,'" + obj.chat.name + "'," + Date.now() + ")";
         db.run(query, obj.chat.msg);
       }
     });
diff --git a/server/sockets.js b/server/sockets.js
index b31334c1..ef2f07b4 100644
--- a/server/sockets.js
+++ b/server/sockets.js
@@ -31,15 +31,20 @@ module.exports = function(wss) {
         }
       });
     };
-    notifyRoom(query["page"], "connect"); //Hall or Game
-    if (query["page"].indexOf("/game/") >= 0)
-      notifyRoom("/", "connect"); //notify main hall
+    // Wait for "connect" message to notify connection to the room,
+    // because if game loading is slow the message listener might
+    // not be ready too early.
     socket.on("message", objtxt => {
       let obj = JSON.parse(objtxt);
       if (!!obj.target && !clients[obj.target])
         return; //receiver not connected, nothing we can do
       switch (obj.code)
       {
+        case "connect":
+          notifyRoom(query["page"], "connect"); //Hall or Game
+          if (query["page"].indexOf("/game/") >= 0)
+            notifyRoom("/", "connect"); //notify main hall
+          break;
         case "pollclients":
           const curPage = clients[sid].page;
           socket.send(JSON.stringify({code:"pollclients",
-- 
2.44.0