Factor some lines (raw loading pug files)
[vchess.git] / client / src / views / Problems.vue
index 270707d..a55126f 100644 (file)
@@ -1,5 +1,15 @@
 <template lang="pug">
 main
+  input#modalRules.modal(type="checkbox")
+  div#rulesDiv(
+    role="dialog"
+    data-checkbox="modalRules"
+  )
+    .card
+      label.modal-close(for="modalRules")
+      a#variantNameInProblems(:href="'/#/variants/'+game.vname")
+        | {{ game.vname }}
+      div(v-html="rulesContent")
   input#modalNewprob.modal(
     type="checkbox"
     @change="fenFocusIfOpened($event)"
@@ -18,6 +28,7 @@ main
         )
           option(
             v-for="v in [emptyVar].concat(st.variants)"
+            v-if="!v.noProblems"
             :value="v.id"
             :selected="curproblem.vid==v.id"
           )
@@ -31,17 +42,19 @@ main
         )
         #diagram(v-html="curproblem.diag")
       fieldset
-        textarea(
+        textarea.instructions-edit(
           :placeholder="st.tr['Instructions']"
+          @input="adjustHeight('instructions')"
           v-model="curproblem.instruction"
         )
-        p(v-html="parseHtml(curproblem.instruction)")
+        .instructions(v-html="parseHtml(curproblem.instruction)")
       fieldset
-        textarea(
+        textarea.solution-edit(
           :placeholder="st.tr['Solution']"
+          @input="adjustHeight('solution')"
           v-model="curproblem.solution"
         )
-        p(v-html="parseHtml(curproblem.solution)")
+        .solution(v-html="parseHtml(curproblem.solution)")
       button(@click="sendProblem()") {{ st.tr["Send"] }}
       #dialog.text-center {{ st.tr[infoMsg] }}
   .row(v-if="showOne")
@@ -53,16 +66,16 @@ main
         span.vname {{ curproblem.vname }}
         span.uname ({{ curproblem.uname }})
         button.marginleft(@click="backToList()") {{ st.tr["Back to list"] }}
-        button.nomargin(@click="gotoPrevNext($event,curproblem,1)")
+        button.nomargin(@click="gotoPrevNext(curproblem,1)")
           | {{ st.tr["Previous_p"] }}
-        button.nomargin(@click="gotoPrevNext($event,curproblem,-1)")
+        button.nomargin(@click="gotoPrevNext(curproblem,-1)")
           | {{ st.tr["Next_p"] }}
-      p.oneInstructions.clickable(
+      .instructions.oneInstructions.clickable(
         v-html="parseHtml(curproblem.instruction)"
         @click="curproblem.showSolution=!curproblem.showSolution"
       )
         | {{ st.tr["Show solution"] }}
-      p(
+      .solution(
         v-show="curproblem.showSolution"
         v-html="parseHtml(curproblem.solution)"
       )
@@ -114,9 +127,11 @@ main
 import { store } from "@/store";
 import { ajax } from "@/utils/ajax";
 import { checkProblem } from "@/data/problemCheck";
-import { getDiagram } from "@/utils/printDiagram";
+import params from "@/parameters";
+import { getDiagram, replaceByDiag } from "@/utils/printDiagram";
 import { processModalClick } from "@/utils/modalClick";
 import { ArrayFun } from "@/utils/array";
+import afterRawLoad from "@/utils/afterRawLoad";
 import BaseGame from "@/components/BaseGame.vue";
 export default {
   name: "my-problems",
@@ -153,7 +168,7 @@ export default {
       onlyMine: false,
       showOne: false,
       infoMsg: "",
-      admins: [1], //hard-coded for now. TODO
+      rulesContent: "",
       game: {
         players: [{ name: "Problem" }, { name: "Problem" }],
         mode: "analyze"
@@ -166,8 +181,10 @@ export default {
     else this.loadMore("others", () => { this.loadMore("mine"); });
   },
   mounted: function() {
-    document.getElementById("newprobDiv")
-      .addEventListener("click", processModalClick);
+    ["rulesDiv","newprobDiv"].forEach(eltName => {
+      document.getElementById(eltName)
+      .addEventListener("click", processModalClick)
+    });
   },
   watch: {
     // st.variants changes only once, at loading from [] to [...]
@@ -196,6 +213,12 @@ export default {
         document.getElementById("inputFen").focus();
       }
     },
+    adjustHeight: function(elt) {
+      // https://stackoverflow.com/a/48460773
+      let t = document.querySelector("." + elt + "-edit");
+      t.style.height = "";
+      t.style.height = (t.scrollHeight + 3) + "px";
+    },
     setVname: function(prob) {
       prob.vname = this.st.variants.find(v => v.id == prob.vid).name;
     },
@@ -267,7 +290,10 @@ export default {
     },
     parseHtml: function(txt) {
       return !txt.match(/<[/a-zA-Z]+>/)
-        ? txt.replace(/\n/g, "<br/>") //no HTML tag
+        ?
+          // No HTML tag
+          txt.replace(/\n\n/g, "<br/><div class='br'></div>")
+             .replace(/\n/g, "<br/>")
         : txt;
     },
     changeVariant: function(prob) {
@@ -288,6 +314,13 @@ export default {
         this.loadedVar = vid;
         cb();
       });
+      this.rulesContent =
+        afterRawLoad(
+          require(
+            "raw-loader!@/translations/rules/" + variant.name + "/" +
+            this.st.lang + ".pug"
+          ).default
+        ).replace(/(fen:)([^:]*):/g, replaceByDiag);
     },
     trySetDiagram: function(prob) {
       // Problem edit: FEN could be wrong or incomplete,
@@ -318,6 +351,7 @@ export default {
           // $nextTick to be sure $refs["basegame"] exists
           this.$nextTick(() => {
             this.$refs["basegame"].re_setVariables(this.game); });
+          this.curproblem.showSolution = false; //in case of
           this.copyProblem(p, this.curproblem);
         });
       };
@@ -346,18 +380,28 @@ export default {
         );
       } else processWhenWeHaveProb();
     },
-    gotoPrevNext: function(e, prob, dir) {
+    gotoPrevNext: function(prob, dir) {
       const mode = (this.onlyMine ? "mine" : "others");
       const problems = this.problems[mode];
       const startIdx = problems.findIndex(p => p.id == prob.id);
       const nextIdx = startIdx + dir;
       if (nextIdx >= 0 && nextIdx < problems.length)
         this.setHrefPid(problems[nextIdx]);
-      else if (this.hasMore[mode]) this.loadMore(mode);
+      else if (this.hasMore[mode]) {
+        this.loadMore(
+          mode,
+          (nbProbs) => {
+            if (nbProbs > 0) this.gotoPrevNext(prob, dir);
+            else alert(this.st.tr["No more problems"]);
+          }
+        );
+      }
       else alert(this.st.tr["No more problems"]);
     },
     prepareNewProblem: function() {
       this.resetCurProb();
+      this.adjustHeight("instructions");
+      this.adjustHeight("solution");
       window.doClick("modalNewprob");
     },
     sendProblem: function() {
@@ -399,12 +443,14 @@ export default {
       );
     },
     canIedit: function(puid) {
-      return this.admins.concat([puid]).includes(this.st.user.id);
+      return params.devs.concat([puid]).includes(this.st.user.id);
     },
     editProblem: function(prob) {
       // prob.diag might correspond to some other problem or be empty:
       this.setDiagram(prob); //V is loaded at this stage
       this.copyProblem(prob, this.curproblem);
+      this.adjustHeight("instructions");
+      this.adjustHeight("solution");
       window.doClick("modalNewprob");
     },
     deleteProblem: function(prob) {
@@ -441,9 +487,16 @@ export default {
               const pids = this.problems[mode].map(p => p.id);
               ArrayFun.remove(res.problems, p => pids.includes(p.id), "all");
               this.decorate(res.problems);
-              this.problems[mode] = this.problems[mode].concat(res.problems);
+              this.problems[mode] =
+                this.problems[mode].concat(res.problems)
+                // TODO: problems are already sorted, would just need to insert
+                // the current individual problem in list; more generally
+                // there is probably only one misclassified problem.
+                // (Unless the user navigated several times by URL to show a
+                // single problem...)
+                .sort((p1, p2) => p2.added - p1.added);
             } else this.hasMore[mode] = false;
-            if (!!cb) cb();
+            if (!!cb) cb(L);
           }
         }
       );
@@ -452,16 +505,43 @@ export default {
 };
 </script>
 
+<style lang="sass">
+@import "@/styles/_board_squares_img.sass"
+@import "@/styles/_rules.sass"
+.instructions, .solution
+  margin: 0 var(--universal-margin)
+  p, ul, ol, pre, table, h3, h4, h5, h6, blockquote
+    margin: var(--universal-margin) 0
+  .br
+    display: block
+    margin: 10px 0
+</style>
+
 <style lang="sass" scoped>
 [type="checkbox"].modal+div .card
   max-width: 767px
   max-height: 100%
 
+#rulesDiv > .card
+  padding: 5px 0
+  max-width: 50%
+  max-height: 100%
+  @media screen and (max-width: 1500px)
+    max-width: 67%
+  @media screen and (max-width: 1024px)
+    max-width: 85%
+  @media screen and (max-width: 767px)
+    max-width: 100%
+
 #inputFen
   width: 100%
 
 textarea
   width: 100%
+  &.instructions-edit
+    min-height: 70px
+  &.solution-edit
+    min-height: 100px
 
 #diagram
   margin: 0 auto
@@ -481,7 +561,7 @@ button#loadMoreBtn
   & > *
     margin: 0
 
-p.oneInstructions
+.oneInstructions
   margin: 0
   padding: 2px 5px
   background-color: lightgreen
@@ -504,4 +584,12 @@ p.oneInstructions
 @media screen and (max-width: 767px)
   #topPage
     text-align: center
+
+a#variantNameInProblems
+  color: var(--card-fore-color)
+  text-align: center
+  font-weight: bold
+  font-size: calc(1rem * var(--heading-ratio))
+  line-height: 1.2
+  margin: calc(1.5 * var(--universal-margin))
 </style>