Browse Source

Improve naviguation

Frédéric Guillot 8 years ago
parent
commit
0e6fc2db1e
3 changed files with 53 additions and 28 deletions
  1. 10 10
      server/static/js.go
  2. 33 9
      server/static/js/app.js
  3. 10 9
      server/ui/controller/entry.go

+ 10 - 10
server/static/js.go

@@ -1,5 +1,5 @@
 // Code generated by go generate; DO NOT EDIT.
-// 2017-12-03 17:25:29.409871548 -0800 PST m=+0.022898473
+// 2017-12-04 20:40:04.511740583 -0800 PST m=+0.012182340
 
 package static
 
@@ -41,30 +41,30 @@ withCallback(callback){this.callback=callback;return this;}
 getCsrfToken(){let element=document.querySelector("meta[name=X-CSRF-Token]");if(element!==null){return element.getAttribute("value");}
 return "";}
 execute(){fetch(new Request(this.url,this.options)).then((response)=>{if(this.callback){this.callback(response);}});}}
-class EntryHandler{static updateEntriesStatus(entryIDs,status){let url=document.body.dataset.entriesStatusUrl;let request=new RequestBuilder(url);request.withBody({entry_ids:entryIDs,status:status});request.execute();}
+class EntryHandler{static updateEntriesStatus(entryIDs,status,callback){let url=document.body.dataset.entriesStatusUrl;let request=new RequestBuilder(url);request.withBody({entry_ids:entryIDs,status:status});request.withCallback(callback);request.execute();}
 static toggleEntryStatus(element){let entryID=parseInt(element.dataset.id,10);let statuses={read:"unread",unread:"read"};for(let currentStatus in statuses){let newStatus=statuses[currentStatus];if(element.classList.contains("item-status-"+currentStatus)){element.classList.remove("item-status-"+currentStatus);element.classList.add("item-status-"+newStatus);this.updateEntriesStatus([entryID],newStatus);break;}}}
+static markEntryAsRead(element){if(element.classList.contains("item-status-unread")){element.classList.remove("item-status-unread");element.classList.add("item-status-read");let entryID=parseInt(element.dataset.id,10);this.updateEntriesStatus([entryID],"read");}}
 static saveEntry(element){if(element.dataset.completed){return;}
 element.innerHTML=element.dataset.labelLoading;let request=new RequestBuilder(element.dataset.saveUrl);request.withCallback(()=>{element.innerHTML=element.dataset.labelDone;element.dataset.completed=true;});request.execute();}}
 class ConfirmHandler{remove(url){let request=new RequestBuilder(url);request.withCallback(()=>window.location.reload());request.execute();}
 handle(event){let questionElement=document.createElement("span");let linkElement=event.target;let containerElement=linkElement.parentNode;linkElement.style.display="none";let yesElement=document.createElement("a");yesElement.href="#";yesElement.appendChild(document.createTextNode(linkElement.dataset.labelYes));yesElement.onclick=(event)=>{event.preventDefault();let loadingElement=document.createElement("span");loadingElement.className="loading";loadingElement.appendChild(document.createTextNode(linkElement.dataset.labelLoading));questionElement.remove();containerElement.appendChild(loadingElement);this.remove(linkElement.dataset.url);};let noElement=document.createElement("a");noElement.href="#";noElement.appendChild(document.createTextNode(linkElement.dataset.labelNo));noElement.onclick=(event)=>{event.preventDefault();linkElement.style.display="inline";questionElement.remove();};questionElement.className="confirm";questionElement.appendChild(document.createTextNode(linkElement.dataset.labelQuestion+" "));questionElement.appendChild(yesElement);questionElement.appendChild(document.createTextNode(", "));questionElement.appendChild(noElement);containerElement.appendChild(questionElement);}}
 class MenuHandler{clickMenuListItem(event){let element=event.target;if(element.tagName==="A"){window.location.href=element.getAttribute("href");}else{window.location.href=element.querySelector("a").getAttribute("href");}}
 toggleMainMenu(){let menu=document.querySelector(".header nav ul");if(DomHelper.isVisible(menu)){menu.style.display="none";}else{menu.style.display="block";}}}
-class NavHandler{markPageAsRead(){let items=DomHelper.getVisibleElements(".items .item");let entryIDs=[];items.forEach((element)=>{element.classList.add("item-status-read");entryIDs.push(parseInt(element.dataset.id,10));});if(entryIDs.length>0){EntryHandler.updateEntriesStatus(entryIDs,"read");}
-this.goToPage("next");}
+class NavHandler{markPageAsRead(){let items=DomHelper.getVisibleElements(".items .item");let entryIDs=[];items.forEach((element)=>{element.classList.add("item-status-read");entryIDs.push(parseInt(element.dataset.id,10));});if(entryIDs.length>0){EntryHandler.updateEntriesStatus(entryIDs,"read",()=>{this.goToPage("next",true);});}}
 saveEntry(){if(this.isListView()){let currentItem=document.querySelector(".current-item");if(currentItem!==null){let saveLink=currentItem.querySelector("a[data-save-entry]");if(saveLink){EntryHandler.saveEntry(saveLink);}}}else{let saveLink=document.querySelector("a[data-save-entry]");if(saveLink){EntryHandler.saveEntry(saveLink);}}}
-toggleEntryStatus(){let currentItem=document.querySelector(".current-item");if(currentItem!==null){EntryHandler.toggleEntryStatus(currentItem);this.goToNextListItem();}}
+toggleEntryStatus(){let currentItem=document.querySelector(".current-item");if(currentItem!==null){this.goToNextListItem();EntryHandler.toggleEntryStatus(currentItem);}}
 openOriginalLink(){let entryLink=document.querySelector(".entry h1 a");if(entryLink!==null){DomHelper.openNewTab(entryLink.getAttribute("href"));return;}
-let currentItemOriginalLink=document.querySelector(".current-item a[data-original-link]");if(currentItemOriginalLink!==null){DomHelper.openNewTab(currentItemOriginalLink.getAttribute("href"));}}
+let currentItemOriginalLink=document.querySelector(".current-item a[data-original-link]");if(currentItemOriginalLink!==null){DomHelper.openNewTab(currentItemOriginalLink.getAttribute("href"));let currentItem=document.querySelector(".current-item");this.goToNextListItem();EntryHandler.markEntryAsRead(currentItem);}}
 openSelectedItem(){let currentItemLink=document.querySelector(".current-item .item-title a");if(currentItemLink!==null){window.location.href=currentItemLink.getAttribute("href");}}
-goToPage(page){let element=document.querySelector("a[data-page="+page+"]");if(element){document.location.href=element.href;}}
+goToPage(page,fallbackSelf){let element=document.querySelector("a[data-page="+page+"]");if(element){document.location.href=element.href;}else if(fallbackSelf){window.location.reload();}}
 goToPrevious(){if(this.isListView()){this.goToPreviousListItem();}else{this.goToPage("previous");}}
 goToNext(){if(this.isListView()){this.goToNextListItem();}else{this.goToPage("next");}}
 goToPreviousListItem(){let items=DomHelper.getVisibleElements(".items .item");if(items.length===0){return;}
 if(document.querySelector(".current-item")===null){items[0].classList.add("current-item");return;}
 for(let i=0;i<items.length;i++){if(items[i].classList.contains("current-item")){items[i].classList.remove("current-item");if(i-1>=0){items[i-1].classList.add("current-item");DomHelper.scrollPageTo(items[i-1]);}
 break;}}}
-goToNextListItem(){let items=DomHelper.getVisibleElements(".items .item");if(items.length===0){return;}
-if(document.querySelector(".current-item")===null){items[0].classList.add("current-item");return;}
+goToNextListItem(){let currentItem=document.querySelector(".current-item");let items=DomHelper.getVisibleElements(".items .item");if(items.length===0){return;}
+if(currentItem===null){items[0].classList.add("current-item");return;}
 for(let i=0;i<items.length;i++){if(items[i].classList.contains("current-item")){items[i].classList.remove("current-item");if(i+1<items.length){items[i+1].classList.add("current-item");DomHelper.scrollPageTo(items[i+1]);}
 break;}}}
 isListView(){return document.querySelector(".items")!==null;}}
@@ -72,5 +72,5 @@ document.addEventListener("DOMContentLoaded",function(){FormHandler.handleSubmit
 }
 
 var JavascriptChecksums = map[string]string{
-	"app": "ce9791d6752f8b09f6163907e5ba01092f76595d6f99d611858216d6533f4655",
+	"app": "7d14f00cb219662aaf59f20080265097eb236999dcc712b83775882970d05803",
 }

+ 33 - 9
server/static/js/app.js

@@ -275,10 +275,11 @@ class RequestBuilder {
 }
 
 class EntryHandler {
-    static updateEntriesStatus(entryIDs, status) {
+    static updateEntriesStatus(entryIDs, status, callback) {
         let url = document.body.dataset.entriesStatusUrl;
         let request = new RequestBuilder(url);
         request.withBody({entry_ids: entryIDs, status: status});
+        request.withCallback(callback);
         request.execute();
     }
 
@@ -299,6 +300,16 @@ class EntryHandler {
         }
     }
 
+    static markEntryAsRead(element) {
+        if (element.classList.contains("item-status-unread")) {
+            element.classList.remove("item-status-unread");
+            element.classList.add("item-status-read");
+
+            let entryID = parseInt(element.dataset.id, 10);
+            this.updateEntriesStatus([entryID], "read");
+        }
+    }
+
     static saveEntry(element) {
         if (element.dataset.completed) {
             return;
@@ -395,10 +406,11 @@ class NavHandler {
         });
 
         if (entryIDs.length > 0) {
-            EntryHandler.updateEntriesStatus(entryIDs, "read");
+            EntryHandler.updateEntriesStatus(entryIDs, "read", () => {
+                // This callback make sure the Ajax request reach the server before we reload the page.
+                this.goToPage("next", true);
+            });
         }
-
-        this.goToPage("next");
     }
 
     saveEntry() {
@@ -421,8 +433,10 @@ class NavHandler {
     toggleEntryStatus() {
         let currentItem = document.querySelector(".current-item");
         if (currentItem !== null) {
-            EntryHandler.toggleEntryStatus(currentItem);
+            // The order is important here,
+            // On the unread page, the read item will be hidden.
             this.goToNextListItem();
+            EntryHandler.toggleEntryStatus(currentItem);
         }
     }
 
@@ -436,6 +450,11 @@ class NavHandler {
         let currentItemOriginalLink = document.querySelector(".current-item a[data-original-link]");
         if (currentItemOriginalLink !== null) {
             DomHelper.openNewTab(currentItemOriginalLink.getAttribute("href"));
+
+            // Move to the next item and if we are on the unread page mark this item as read.
+            let currentItem = document.querySelector(".current-item");
+            this.goToNextListItem();
+            EntryHandler.markEntryAsRead(currentItem);
         }
     }
 
@@ -446,11 +465,17 @@ class NavHandler {
         }
     }
 
-    goToPage(page) {
+    /**
+     * @param {string} page Page to redirect to.
+     * @param {boolean} fallbackSelf Refresh actual page if the page is not found.
+     */
+    goToPage(page, fallbackSelf) {
         let element = document.querySelector("a[data-page=" + page + "]");
 
         if (element) {
             document.location.href = element.href;
+        } else if (fallbackSelf) {
+            window.location.reload();
         }
     }
 
@@ -472,7 +497,6 @@ class NavHandler {
 
     goToPreviousListItem() {
         let items = DomHelper.getVisibleElements(".items .item");
-
         if (items.length === 0) {
             return;
         }
@@ -497,13 +521,13 @@ class NavHandler {
     }
 
     goToNextListItem() {
+        let currentItem = document.querySelector(".current-item");
         let items = DomHelper.getVisibleElements(".items .item");
-
         if (items.length === 0) {
             return;
         }
 
-        if (document.querySelector(".current-item") === null) {
+        if (currentItem === null) {
             items[0].classList.add("current-item");
             return;
         }

+ 10 - 9
server/ui/controller/entry.go

@@ -191,15 +191,6 @@ func (c *Controller) ShowUnreadEntry(ctx *core.Context, request *core.Request, r
 		return
 	}
 
-	if entry.Status == model.EntryStatusUnread {
-		err = c.store.SetEntriesStatus(user.ID, []int64{entry.ID}, model.EntryStatusRead)
-		if err != nil {
-			log.Println(err)
-			response.HTML().ServerError(nil)
-			return
-		}
-	}
-
 	args, err := c.getCommonTemplateArgs(ctx)
 	if err != nil {
 		response.HTML().ServerError(err)
@@ -225,6 +216,16 @@ func (c *Controller) ShowUnreadEntry(ctx *core.Context, request *core.Request, r
 		prevEntryRoute = ctx.Route("unreadEntry", "entryID", prevEntry.ID)
 	}
 
+	// We change the status here, otherwise we cannot get the pagination for unread items.
+	if entry.Status == model.EntryStatusUnread {
+		err = c.store.SetEntriesStatus(user.ID, []int64{entry.ID}, model.EntryStatusRead)
+		if err != nil {
+			log.Println(err)
+			response.HTML().ServerError(nil)
+			return
+		}
+	}
+
 	response.HTML().Render("entry", args.Merge(tplParams{
 		"entry":          entry,
 		"prevEntry":      prevEntry,