Fix pronlems edit by admins
[vchess.git] / client / src / views / News.vue
index 8a3de76..37bd3ca 100644 (file)
@@ -1,8 +1,11 @@
 <template lang="pug">
 main
   input#modalNews.modal(type="checkbox")
-  div#newnewsDiv(role="dialog" data-checkbox="modalNews")
-    .card
+  div#newnewsDiv(
+    role="dialog"
+    data-checkbox="modalNews"
+  )
+    .card#writeNews
       label.modal-close(for="modalNews")
       textarea#newsContent(
         v-model="curnews.content"
@@ -13,61 +16,84 @@ main
       #dialog.text-center {{ st.tr[infoMsg] }}
   .row
     .col-sm-12.col-md-10.col-md-offset-1.col-lg-8.col-lg-offset-2
-      button(
-        v-if="devs.includes(st.user.id)"
+      button#writeNewsBtn(
+        v-if="devTeam"
         @click="showModalNews"
       )
         | {{ st.tr["Write news"] }}
-      .news(v-for="n,idx in sortedNewsList" :class="{margintop:idx>0}")
+      .news(
+        v-for="n,idx in newsList"
+        :id="'n' + n.id"
+        :class="{margintop:idx>0}"
+      )
         span.ndt {{ formatDatetime(n.added) }}
-        div(v-if="devs.includes(st.user.id)")
+        .dev-buttons(v-if="devTeam")
           button(@click="editNews(n)") {{ st.tr["Edit"] }}
           button(@click="deleteNews(n)") {{ st.tr["Delete"] }}
-        p(v-html="parseHtml(n.content)")
-      button(v-if="hasMore" @click="loadMore()")
+        button(@click="gotoPrevNext(n, 1)") {{ st.tr["Previous_n"] }}
+        button(@click="gotoPrevNext(n, -1)") {{ st.tr["Next_n"] }}
+        .news-content(v-html="parseHtml(n.content)")
+      button#loadMoreBtn(
+        v-if="hasMore"
+        @click="loadMore()"
+      )
         | {{ st.tr["Load more"] }}
 </template>
 
 <script>
 import { store } from "@/store";
 import { ajax } from "@/utils/ajax";
+import params from "@/parameters";
 import { getDate, getTime } from "@/utils/datetime";
 import { processModalClick } from "@/utils/modalClick";
 export default {
   name: "my-news",
   data: function() {
     return {
-      devs: [1], //for now the only dev is me
       st: store.state,
-      cursor: 0, //ID of last showed news
-      hasMore: true, //a priori there could be more news to load
-      curnews: {id:0, content:""},
+      devTeam: params.devs.include(store.state.user.id),
+      // timestamp of oldest showed news:
+      cursor: Number.MAX_SAFE_INTEGER,
+      // hasMore == TRUE: a priori there could be more news to load
+      hasMore: true,
+      curnews: { id: 0, content: "" },
       newsList: [],
-      infoMsg: "",
+      infoMsg: ""
     };
   },
   created: function() {
-    ajax("/news", "GET", {cursor:this.cursor}, (res) => {
-      this.newsList = res.newsList;
-      const L = res.newsList.length;
-      if (L > 0)
-        this.cursor = res.newsList[L-1].id;
-    });
+    ajax(
+      "/news",
+      "GET",
+      {
+        data: { cursor: this.cursor },
+        success: (res) => {
+          // The returned list is sorted from most recent to oldest
+          this.newsList = res.newsList;
+          const L = res.newsList.length;
+          if (L > 0) this.cursor = res.newsList[L - 1].added;
+          else this.hasMore = false;
+        }
+      }
+    );
   },
   mounted: function() {
-    document.getElementById("newnewsDiv").addEventListener("click", processModalClick);
-  },
-  computed: {
-    sortedNewsList: function() {
-      return this.newsList.sort( (n1,n2) => n1.added - n2.added );
-    },
+    // Mark that I've read the news:
+    localStorage.setItem("newsRead", Date.now());
+    if (this.st.user.id > 0) ajax("/newsread", "PUT");
+    document.getElementById("newsMenu").classList.remove("somenews");
+    document
+      .getElementById("newnewsDiv")
+      .addEventListener("click", processModalClick);
   },
   methods: {
     formatDatetime: function(dt) {
       const dtObj = new Date(dt);
       const timePart = getTime(dtObj);
       // Show minutes but not seconds:
-      return getDate(dtObj) + " " + timePart.substr(0,timePart.lastIndexOf(":"));
+      return (
+        getDate(dtObj) + " " + timePart.substr(0, timePart.lastIndexOf(":"))
+      );
     },
     parseHtml: function(txt) {
       return !txt.match(/<[/a-zA-Z]+>/)
@@ -76,18 +102,22 @@ export default {
     },
     adjustHeight: function() {
       const newsContent = document.getElementById("newsContent");
-      // https://stackoverflow.com/questions/995168/textarea-to-resize-based-on-content-length
+      // https://stackoverflow.com/a/995374
       newsContent.style.height = "1px";
-      newsContent.style.height = (10+newsContent.scrollHeight)+"px";
+      newsContent.style.height = 10 + newsContent.scrollHeight + "px";
     },
     resetCurnews: function() {
       this.curnews.id = 0;
       this.curnews.content = "";
       // No need for added and uid fields: never updated
     },
+    gotoPrevNext: function(n, dir) {
+      document.getElementById("n" + n.id)[
+        (dir < 0 ? "previous" : "next") + "ElementSibling"].scrollIntoView();
+    },
     showModalNews: function() {
       this.resetCurnews();
-      doClick('modalNews');
+      window.doClick("modalNews");
     },
     sendNews: function() {
       const edit = this.curnews.id > 0;
@@ -95,27 +125,25 @@ export default {
       ajax(
         "/news",
         edit ? "PUT" : "POST",
-        {news: this.curnews},
-        (res) => {
-          if (edit)
-          {
-            let n = this.newsList.find(n => n.id == this.curnews.id);
-            if (!!n)
-              n.content = this.curnews.content;
-          }
-          else
-          {
-            const newNews = {
-              content:this.curnews.content,
-              added:Date.now(),
-              uid: this.st.user.id,
-              id: res.id
-            };
-            this.newsList = this.newsList.concat([newNews]);
+        {
+          data: { news: this.curnews },
+          success: (res) => {
+            if (edit) {
+              let n = this.newsList.find(n => n.id == this.curnews.id);
+              if (!!n) n.content = this.curnews.content;
+            } else {
+              const newNews = {
+                content: this.curnews.content,
+                added: Date.now(),
+                uid: this.st.user.id,
+                id: res.id
+              };
+              this.newsList = [newNews].concat(this.newsList);
+            }
+            document.getElementById("modalNews").checked = false;
+            this.infoMsg = "";
+            this.resetCurnews();
           }
-          document.getElementById("modalNews").checked = false;
-          this.infoMsg = "";
-          this.resetCurnews();
         }
       );
     },
@@ -123,59 +151,88 @@ export default {
       this.curnews.content = n.content;
       this.curnews.id = n.id;
       // No need for added and uid fields: never updated
-      doClick('modalNews');
+      window.doClick("modalNews");
     },
     deleteNews: function(n) {
-      if (confirm(this.st.tr["Are you sure?"]))
-      {
+      if (confirm(this.st.tr["Are you sure?"])) {
         this.infoMsg = "Processing... Please wait";
-        ajax("/news", "DELETE", {id:n.id}, () => {
-          const nIdx = this.newsList.findIndex(nw => nw.id == n.id);
-          this.newsList.splice(nIdx, 1);
-          this.infoMsg = "";
-          document.getElementById("modalNews").checked = false;
-        });
+        ajax(
+          "/news",
+          "DELETE",
+          {
+            data: { id: n.id },
+            success: () => {
+              const nIdx = this.newsList.findIndex(nw => nw.id == n.id);
+              this.newsList.splice(nIdx, 1);
+              this.infoMsg = "";
+              document.getElementById("modalNews").checked = false;
+            }
+          }
+        );
       }
     },
     loadMore: function() {
-      ajax("/news", "GET", {cursor:this.cursor}, (res) => {
-        if (res.newsList.length > 0)
+      ajax(
+        "/news",
+        "GET",
         {
-          this.newsList = this.newsList.concat(res.newsList);
-          const L = res.newsList.length;
-          if (L > 0)
-            this.cursor = res.newsList[L-1].id;
+          data: { cursor: this.cursor },
+          success: (res) => {
+            const L = res.newsList.length;
+            if (L > 0) {
+              this.newsList = this.newsList.concat(res.newsList);
+              this.cursor = res.newsList[L - 1].added;
+            } else this.hasMore = false;
+          }
         }
-        else
-          this.hasMore = false;
-      });
-    },
-  },
+      );
+    }
+  }
 };
 </script>
 
-<style lang="sass" scoped>
+<style lang="sass">
 [type="checkbox"].modal+div .card
   max-width: 767px
   max-height: 100%
+
 textarea#newsContent
   margin: 0
   width: 100%
   min-height: 200px
   max-height: 100%
+
 #dialog
   padding: 5px
   color: blue
+
+#writeNews
+  padding-top: 50px
+
+button#writeNewsBtn, button#loadMoreBtn
+  margin-top: 0
+  margin-bottom: 0
+
 span.ndt
   color: darkblue
   padding: 0 5px 0 var(--universal-margin)
-.margintop
-  margin-top: 25px
-  border-top: 1px solid grey
+
 .news
   padding-top: 10px
-  & > div
+  & > .dev-buttons
     display: inline-block
+  & > .news-content
+    margin: var(--universal-margin)
+    & > p
+      margin: 10px 0
+    & > br
+      display: block
+      margin-top: 10px
+      content: " "
+
+.margintop
+  margin-top: 25px
+  border-top: 1px solid grey
 @media screen and (max-width: 767px)
   .margintop
     margin-top: 10px