Add Knightrelay1. Some fixes. Move odd 'isAttackedBy_multiple_colors' to Checkered...
[vchess.git] / client / src / views / Problems.vue
index 30d3356..2ea875e 100644 (file)
@@ -2,7 +2,7 @@
 main
   input#modalNewprob.modal(
     type="checkbox"
-    @change="infoMsg=''"
+    @change="fenFocusIfOpened($event)"
   )
   div#newprobDiv(
     role="dialog"
@@ -56,7 +56,7 @@ main
         button.nomargin(@click="gotoPrevNext($event,curproblem,1)")
           | {{ st.tr["Previous"] }}
         button.nomargin(@click="gotoPrevNext($event,curproblem,-1)")
-          | {{ st.tr["Next"] }}
+          | {{ st.tr["Next_p"] }}
       p.oneInstructions.clickable(
         v-html="parseHtml(curproblem.instruction)"
         @click="curproblem.showSolution=!curproblem.showSolution"
@@ -96,10 +96,15 @@ main
           td {{ p.vname }}
           td {{ firstChars(p.instruction) }}
           td {{ p.id }}
+      button#loadMoreBtn(
+        v-if="hasMore"
+        @click="loadMore()"
+      )
+        | {{ st.tr["Load more"] }}
   BaseGame(
+    ref="basegame"
     v-if="showOne"
     :game="game"
-    :vr="vr"
   )
 </template>
 
@@ -136,10 +141,13 @@ export default {
       loadedVar: 0, //corresponding to loaded V
       selectedVar: 0, //to filter problems based on variant
       problems: [],
+      // timestamp of oldest showed problem:
+      cursor: Number.MAX_SAFE_INTEGER,
+      // hasMore == TRUE: a priori there could be more problems to load
+      hasMore: true,
       onlyMines: false,
       showOne: false,
       infoMsg: "",
-      vr: null, //"variant rules" object initialized from FEN
       game: {
         players: [{ name: "Problem" }, { name: "Problem" }],
         mode: "analyze"
@@ -147,38 +155,28 @@ export default {
     };
   },
   created: function() {
-    ajax("/problems", "GET", res => {
-      // Show newest problem first:
-      this.problems = res.problems.sort((p1, p2) => p2.added - p1.added);
-      if (this.st.variants.length > 0)
-        this.problems.forEach(p => this.setVname(p));
-      // Retrieve all problems' authors' names
-      let names = {};
-      this.problems.forEach(p => {
-        if (p.uid != this.st.user.id) names[p.uid] = "";
-        else p.uname = this.st.user.name;
-      });
-      const showOneIfPid = () => {
-        const pid = this.$route.query["id"];
-        if (pid) this.showProblem(this.problems.find(p => p.id == pid));
-      };
-      if (Object.keys(names).length > 0) {
-        ajax("/users", "GET", { ids: Object.keys(names).join(",") }, res2 => {
-          res2.users.forEach(u => {
-            names[u.id] = u.name;
-          });
-          this.problems.forEach(p => {
-            if (!p.uname)
-              p.uname = names[p.uid];
-          });
-          showOneIfPid();
-        });
-      } else showOneIfPid();
-    });
+    ajax(
+      "/problems",
+      "GET",
+      {
+        data: { cursor: this.cursor },
+        success: (res) => {
+          // The returned list is sorted from most recent to oldest
+          this.problems = res.problems;
+          const L = res.problems.length;
+          if (L > 0) this.cursor = res.problems[L - 1].added;
+          else this.hasMore = false;
+          const showOneIfPid = () => {
+            const pid = this.$route.query["id"];
+            if (!!pid) this.showProblem(this.problems.find(p => p.id == pid));
+          };
+          this.decorate(this.problems, showOneIfPid);
+        }
+      }
+    );
   },
   mounted: function() {
-    document
-      .getElementById("newprobDiv")
+    document.getElementById("newprobDiv")
       .addEventListener("click", processModalClick);
   },
   watch: {
@@ -190,14 +188,50 @@ export default {
     },
     $route: function(to) {
       const pid = to.query["id"];
-      if (pid) this.showProblem(this.problems.find(p => p.id == pid));
+      if (!!pid) this.showProblem(this.problems.find(p => p.id == pid));
       else this.showOne = false;
     }
   },
   methods: {
+    fenFocusIfOpened: function(event) {
+      if (event.target.checked) {
+        this.infoMsg = "";
+        document.getElementById("inputFen").focus();
+      }
+    },
     setVname: function(prob) {
       prob.vname = this.st.variants.find(v => v.id == prob.vid).name;
     },
+    // Add vname and user names:
+    decorate: function(problems, callback) {
+      if (this.st.variants.length > 0)
+        problems.forEach(p => this.setVname(p));
+      // Retrieve all problems' authors' names
+      let names = {};
+      problems.forEach(p => {
+        if (p.uid != this.st.user.id) names[p.uid] = "";
+        else p.uname = this.st.user.name;
+      });
+      if (Object.keys(names).length > 0) {
+        ajax(
+          "/users",
+          "GET",
+          {
+            data: { ids: Object.keys(names).join(",") },
+            success: (res2) => {
+              res2.users.forEach(u => {
+                names[u.id] = u.name;
+              });
+              problems.forEach(p => {
+                if (!p.uname)
+                  p.uname = names[p.uid];
+              });
+              if (!!callback) callback();
+            }
+          }
+        );
+      } else if (!!callback) callback();
+    },
     firstChars: function(text) {
       let preparedText = text
         // Replace line jumps and <br> by spaces
@@ -280,13 +314,15 @@ export default {
     showProblem: function(p) {
       this.loadVariant(p.vid, () => {
         // The FEN is already checked at this stage:
-        this.vr = new V(p.fen);
         this.game.vname = p.vname;
-        this.game.mycolor = this.vr.turn; //diagram orientation
+        this.game.mycolor = V.ParseFen(p.fen).turn; //diagram orientation
+        this.game.fenStart = p.fen;
         this.game.fen = p.fen;
-        this.$set(this.game, "fenStart", p.fen);
-        this.copyProblem(p, this.curproblem);
         this.showOne = true;
+        // $nextTick to be sure $refs["basegame"] exists
+        this.$nextTick(() => {
+          this.$refs["basegame"].re_setVariables(this.game); });
+        this.copyProblem(p, this.curproblem);
       });
     },
     gotoPrevNext: function(e, prob, dir) {
@@ -319,22 +355,24 @@ export default {
       ajax(
         "/problems",
         edit ? "PUT" : "POST",
-        { prob: this.curproblem },
-        ret => {
-          if (edit) {
-            let editedP = this.problems.find(p => p.id == this.curproblem.id);
-            this.copyProblem(this.curproblem, editedP);
-            this.showProblem(editedP);
+        {
+          data: { prob: this.curproblem },
+          success: (ret) => {
+            if (edit) {
+              let editedP = this.problems.find(p => p.id == this.curproblem.id);
+              this.copyProblem(this.curproblem, editedP);
+              this.showProblem(editedP);
+            }
+            else {
+              let newProblem = Object.assign({}, this.curproblem);
+              newProblem.id = ret.id;
+              newProblem.uid = this.st.user.id;
+              newProblem.uname = this.st.user.name;
+              this.problems = [newProblem].concat(this.problems);
+            }
+            document.getElementById("modalNewprob").checked = false;
+            this.infoMsg = "";
           }
-          else {
-            let newProblem = Object.assign({}, this.curproblem);
-            newProblem.id = ret.id;
-            newProblem.uid = this.st.user.id;
-            newProblem.uname = this.st.user.name;
-            this.problems = [newProblem].concat(this.problems);
-          }
-          document.getElementById("modalNewprob").checked = false;
-          this.infoMsg = "";
         }
       );
     },
@@ -346,11 +384,35 @@ export default {
     },
     deleteProblem: function(prob) {
       if (confirm(this.st.tr["Are you sure?"])) {
-        ajax("/problems", "DELETE", { id: prob.id }, () => {
-          ArrayFun.remove(this.problems, p => p.id == prob.id);
-          this.backToList();
-        });
+        ajax(
+          "/problems",
+          "DELETE",
+          {
+            data: { id: prob.id },
+            success: () => {
+              ArrayFun.remove(this.problems, p => p.id == prob.id);
+              this.backToList();
+            }
+          }
+        );
       }
+    },
+    loadMore: function() {
+      ajax(
+        "/problems",
+        "GET",
+        {
+          data: { cursor: this.cursor },
+          success: (res) => {
+            const L = res.problems.length;
+            if (L > 0) {
+              this.decorate(res.problems);
+              this.problems = this.problems.concat(res.problems);
+              this.cursor = res.problems[L - 1].added;
+            } else this.hasMore = false;
+          }
+        }
+      );
     }
   }
 };
@@ -374,6 +436,10 @@ textarea
 table#tProblems
   max-height: 100%
 
+button#loadMoreBtn
+  display: block
+  margin: 0 auto
+
 #controls
   margin: 0
   width: 100%