From fdd223d9cf55f67b5b78fbfa60f980e5bdb4f3a2 Mon Sep 17 00:00:00 2001 From: Azareal Date: Tue, 4 Jun 2019 15:48:12 +1000 Subject: [PATCH] Rewrite the pagination algorithm so it works properly. Shorten a few bits of JS. Get the topic store methods to call BypassGet instead of duplicating logic. --- common/parser.go | 20 ++++++------ common/template_init.go | 2 +- common/topic_list.go | 2 +- common/topic_store.go | 72 +++++++++++++++++++---------------------- public/global.js | 32 +++++++++--------- routes/account.go | 2 +- routes/forum.go | 2 +- routes/panel/groups.go | 2 +- routes/panel/logs.go | 6 ++-- routes/panel/pages.go | 6 ++-- routes/panel/users.go | 2 +- routes/topic.go | 2 +- 12 files changed, 72 insertions(+), 78 deletions(-) diff --git a/common/parser.go b/common/parser.go index e45c69b4..f73709b1 100644 --- a/common/parser.go +++ b/common/parser.go @@ -1002,18 +1002,20 @@ func CoerceIntString(data string) (res int, length int) { // TODO: Write tests for this // Make sure we reflect changes to this in the JS port in /public/global.js -func Paginate(count int, perPage int, maxPages int) []int { - if count < perPage { - return []int{1} +func Paginate(currentPage int, lastPage int, maxPages int) (out []int) { + diff := lastPage - currentPage + pre := 3 + if diff < 3 { + pre = maxPages - diff } - var page int - var out []int - for current := 0; current < count; current += perPage { + + page := currentPage - pre + if page < 0 { + page = 0 + } + for len(out) < maxPages && page < lastPage { page++ out = append(out, page) - if len(out) >= maxPages { - break - } } return out } diff --git a/common/template_init.go b/common/template_init.go index 4a018778..cfeda353 100644 --- a/common/template_init.go +++ b/common/template_init.go @@ -527,7 +527,7 @@ func compileJSTemplates(wg *sync.WaitGroup, c *tmpl.CTemplateSet, themeName stri itemsPerPage := 25 _, page, lastPage := PageOffset(20, 1, itemsPerPage) - pageList := Paginate(20, itemsPerPage, 5) + pageList := Paginate(page, lastPage, 5) tmpls.AddStd("paginator", "common.Paginator", Paginator{pageList, page, lastPage}) tmpls.AddStd("topic_c_edit_post", "common.TopicCEditPost", TopicCEditPost{ID: 0, Source: "", Ref: ""}) diff --git a/common/topic_list.go b/common/topic_list.go index 42c7cd37..cac2b001 100644 --- a/common/topic_list.go +++ b/common/topic_list.go @@ -365,7 +365,7 @@ func (tList *DefaultTopicList) getList(page int, orderby string, argList []inter topic.LastUser = userList[topic.LastReplyBy] } - pageList := Paginate(topicCount, Config.ItemsPerPage, 5) + pageList := Paginate(page, lastPage, 5) return topicList, Paginator{pageList, page, lastPage}, nil } diff --git a/common/topic_store.go b/common/topic_store.go index 41824fda..6c87cb03 100644 --- a/common/topic_store.go +++ b/common/topic_store.go @@ -66,44 +66,40 @@ func NewDefaultTopicStore(cache TopicCache) (*DefaultTopicStore, error) { }, acc.FirstError() } -func (mts *DefaultTopicStore) DirtyGet(id int) *Topic { - topic, err := mts.cache.Get(id) +func (s *DefaultTopicStore) DirtyGet(id int) *Topic { + topic, err := s.cache.Get(id) if err == nil { return topic } - - topic = &Topic{ID: id} - err = mts.get.QueryRow(id).Scan(&topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.LastReplyBy, &topic.LastReplyAt, &topic.LastReplyID, &topic.IsClosed, &topic.Sticky, &topic.ParentID, &topic.IPAddress, &topic.ViewCount, &topic.PostCount, &topic.LikeCount, &topic.AttachCount, &topic.Poll, &topic.Data) + topic, err = s.BypassGet(id) if err == nil { - topic.Link = BuildTopicURL(NameToSlug(topic.Title), id) - _ = mts.cache.Set(topic) + _ = s.cache.Set(topic) return topic } return BlankTopic() } // TODO: Log weird cache errors? -func (mts *DefaultTopicStore) Get(id int) (topic *Topic, err error) { - topic, err = mts.cache.Get(id) +func (s *DefaultTopicStore) Get(id int) (topic *Topic, err error) { + topic, err = s.cache.Get(id) if err == nil { return topic, nil } - - topic = &Topic{ID: id} - err = mts.get.QueryRow(id).Scan(&topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.LastReplyBy, &topic.LastReplyAt, &topic.LastReplyID, &topic.IsClosed, &topic.Sticky, &topic.ParentID, &topic.IPAddress, &topic.ViewCount, &topic.PostCount, &topic.LikeCount, &topic.AttachCount, &topic.Poll, &topic.Data) + topic, err = s.BypassGet(id) if err == nil { - topic.Link = BuildTopicURL(NameToSlug(topic.Title), id) - _ = mts.cache.Set(topic) + _ = s.cache.Set(topic) } return topic, err } // BypassGet will always bypass the cache and pull the topic directly from the database -func (mts *DefaultTopicStore) BypassGet(id int) (*Topic, error) { - topic := &Topic{ID: id} - err := mts.get.QueryRow(id).Scan(&topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.LastReplyBy, &topic.LastReplyAt, &topic.LastReplyID, &topic.IsClosed, &topic.Sticky, &topic.ParentID, &topic.IPAddress, &topic.ViewCount, &topic.PostCount, &topic.LikeCount, &topic.AttachCount, &topic.Poll, &topic.Data) - topic.Link = BuildTopicURL(NameToSlug(topic.Title), id) - return topic, err +func (s *DefaultTopicStore) BypassGet(id int) (*Topic, error) { + t := &Topic{ID: id} + err := s.get.QueryRow(id).Scan(&t.Title, &t.Content, &t.CreatedBy, &t.CreatedAt, &t.LastReplyBy, &t.LastReplyAt, &t.LastReplyID, &t.IsClosed, &t.Sticky, &t.ParentID, &t.IPAddress, &t.ViewCount, &t.PostCount, &t.LikeCount, &t.AttachCount, &t.Poll, &t.Data) + if err == nil { + t.Link = BuildTopicURL(NameToSlug(t.Title), id) + } + return t, err } // TODO: Avoid duplicating much of this logic from user_store.go @@ -155,14 +151,14 @@ func (s *DefaultTopicStore) BulkGetMap(ids []int) (list map[int]*Topic, err erro defer rows.Close() for rows.Next() { - topic := &Topic{} - err := rows.Scan(&topic.ID, &topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.LastReplyBy, &topic.LastReplyAt, &topic.LastReplyID, &topic.IsClosed, &topic.Sticky, &topic.ParentID, &topic.IPAddress, &topic.ViewCount, &topic.PostCount, &topic.LikeCount, &topic.AttachCount, &topic.Poll, &topic.Data) + t := &Topic{} + err := rows.Scan(&t.ID, &t.Title, &t.Content, &t.CreatedBy, &t.CreatedAt, &t.LastReplyBy, &t.LastReplyAt, &t.LastReplyID, &t.IsClosed, &t.Sticky, &t.ParentID, &t.IPAddress, &t.ViewCount, &t.PostCount, &t.LikeCount, &t.AttachCount, &t.Poll, &t.Data) if err != nil { return list, err } - topic.Link = BuildTopicURL(NameToSlug(topic.Title), topic.ID) - s.cache.Set(topic) - list[topic.ID] = topic + t.Link = BuildTopicURL(NameToSlug(t.Title), t.ID) + s.cache.Set(t) + list[t.ID] = t } err = rows.Err() if err != nil { @@ -187,21 +183,19 @@ func (s *DefaultTopicStore) BulkGetMap(ids []int) (list map[int]*Topic, err erro return list, err } -func (mts *DefaultTopicStore) Reload(id int) error { - topic := &Topic{ID: id} - err := mts.get.QueryRow(id).Scan(&topic.Title, &topic.Content, &topic.CreatedBy, &topic.CreatedAt, &topic.LastReplyBy, &topic.LastReplyAt, &topic.LastReplyID, &topic.IsClosed, &topic.Sticky, &topic.ParentID, &topic.IPAddress, &topic.ViewCount, &topic.PostCount, &topic.LikeCount, &topic.AttachCount, &topic.Poll, &topic.Data) +func (s *DefaultTopicStore) Reload(id int) error { + topic, err := s.BypassGet(id) if err == nil { - topic.Link = BuildTopicURL(NameToSlug(topic.Title), id) - _ = mts.cache.Set(topic) + _ = s.cache.Set(topic) } else { - _ = mts.cache.Remove(id) + _ = s.cache.Remove(id) } TopicListThaw.Thaw() return err } -func (mts *DefaultTopicStore) Exists(id int) bool { - return mts.exists.QueryRow(id).Scan(&id) == nil +func (s *DefaultTopicStore) Exists(id int) bool { + return s.exists.QueryRow(id).Scan(&id) == nil } func (mts *DefaultTopicStore) Create(fid int, topicName string, content string, uid int, ipaddress string) (tid int, err error) { @@ -234,7 +228,7 @@ func (mts *DefaultTopicStore) Create(fid int, topicName string, content string, } // ? - What is this? Do we need it? Should it be in the main store interface? -func (mts *DefaultTopicStore) AddLastTopic(item *Topic, fid int) error { +func (s *DefaultTopicStore) AddLastTopic(item *Topic, fid int) error { // Coming Soon... return nil } @@ -248,15 +242,15 @@ func (s *DefaultTopicStore) Count() (count int) { return count } -func (mts *DefaultTopicStore) SetCache(cache TopicCache) { - mts.cache = cache +func (s *DefaultTopicStore) SetCache(cache TopicCache) { + s.cache = cache } // TODO: We're temporarily doing this so that you can do tcache != nil in getTopicUser. Refactor it. -func (mts *DefaultTopicStore) GetCache() TopicCache { - _, ok := mts.cache.(*NullTopicCache) +func (s *DefaultTopicStore) GetCache() TopicCache { + _, ok := s.cache.(*NullTopicCache) if ok { return nil } - return mts.cache -} + return s.cache +} \ No newline at end of file diff --git a/public/global.js b/public/global.js index bb2cd9c3..b3ee1761 100644 --- a/public/global.js +++ b/public/global.js @@ -386,14 +386,17 @@ function PageOffset(count, page, perPage) { function LastPage(count, perPage) { return (count / perPage) + 1 } -function Paginate(count, perPage, maxPages) { - if(count < perPage) return [1]; - let page = 0; +function Paginate(currentPage, lastPage, maxPages) { + let diff = lastPage - currentPage; + let pre = 3; + if(diff < 3) pre = maxPages - diff; + + let page = currentPage - pre; + if(page < 0) page = 0; let out = []; - for(let current = 0; current < count; current += perPage){ + while(out.length < maxPages && page < lastPage){ page++; out.push(page); - if(out.length >= maxPages) break; } return out; } @@ -405,9 +408,9 @@ function mainInit(){ event.preventDefault(); let moreTopicBlocks = document.getElementsByClassName("more_topic_block_active"); for(let i = 0; i < moreTopicBlocks.length; i++) { - let moreTopicBlock = moreTopicBlocks[i]; - moreTopicBlock.classList.remove("more_topic_block_active"); - moreTopicBlock.classList.add("more_topic_block_initial"); + let block = moreTopicBlocks[i]; + block.classList.remove("more_topic_block_active"); + block.classList.add("more_topic_block_initial"); } $(".ajax_topic_dupe").fadeOut("slow", function(){ $(this).remove(); @@ -437,9 +440,7 @@ function mainInit(){ data: { isJs: 1 }, error: ajaxError, success: function (data, status, xhr) { - if("success" in data) { - if(data["success"] == "1") return; - } + if("success" in data && data["success"] == "1") return; // addNotice("Failed to add a like: {err}") likeButton.classList.add("add_like"); likeButton.classList.remove("remove_like"); @@ -465,11 +466,8 @@ function mainInit(){ let urlParams = new URLSearchParams(window.location.search); let page = urlParams.get('page'); if(page=="") page = 1; - let stopAtPage = lastPage; - if(stopAtPage>5) stopAtPage = 5; - let pageList = []; - for(let i = 0; i < stopAtPage;i++) pageList.push(i+1); + let pageList = Paginate(page,lastPage,5) //$(".pageset").html(Template_paginator({PageList: pageList, Page: page, LastPage: lastPage})); let ok = false; $(".pageset").each(function(){ @@ -804,7 +802,7 @@ function mainInit(){ // This one's for Tempra Conflux // TODO: We might want to use pure JS here - $(".ip_item").each(function(){ + /*$(".ip_item").each(function(){ var ip = this.textContent; if(ip.length > 10){ this.innerHTML = "Show IP"; @@ -813,7 +811,7 @@ function mainInit(){ this.textContent = ip; }; } - }); + });*/ $(".quote_item").click(function(){ event.preventDefault(); diff --git a/routes/account.go b/routes/account.go index 072000de..02f1560d 100644 --- a/routes/account.go +++ b/routes/account.go @@ -724,7 +724,7 @@ func AccountLogins(w http.ResponseWriter, r *http.Request, user c.User, header * return c.InternalError(err, w, r) } - pageList := c.Paginate(logCount, perPage, 5) + pageList := c.Paginate(page, lastPage, 5) pi := c.Account{header, "logins", "account_logins", c.AccountLoginsPage{header, logs, c.Paginator{pageList, page, lastPage}}} return renderTemplate("account", w, r, header, pi) } diff --git a/routes/forum.go b/routes/forum.go index 3dd16c38..fddeee10 100644 --- a/routes/forum.go +++ b/routes/forum.go @@ -122,7 +122,7 @@ func ViewForum(w http.ResponseWriter, r *http.Request, user c.User, header *c.He return nil } - pageList := c.Paginate(forum.TopicCount, c.Config.ItemsPerPage, 5) + pageList := c.Paginate(page, lastPage, 5) pi := c.ForumPage{header, topicList, forum, c.Paginator{pageList, page, lastPage}} tmpl := forum.Tmpl if tmpl == "" { diff --git a/routes/panel/groups.go b/routes/panel/groups.go index d658e591..ecd0209b 100644 --- a/routes/panel/groups.go +++ b/routes/panel/groups.go @@ -57,7 +57,7 @@ func Groups(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError { count++ } - pageList := c.Paginate(basePage.Stats.Groups, perPage, 5) + pageList := c.Paginate(page, lastPage, 5) pi := c.PanelGroupPage{basePage, groupList, c.Paginator{pageList, page, lastPage}} return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage,"","","panel_groups",&pi}) } diff --git a/routes/panel/logs.go b/routes/panel/logs.go index b909b6a5..9d5c3128 100644 --- a/routes/panel/logs.go +++ b/routes/panel/logs.go @@ -32,7 +32,7 @@ func LogsRegs(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError llist[index] = c.PageRegLogItem{log, strings.Replace(strings.TrimSuffix(log.FailureReason, "|"), "|", " | ", -1)} } - pageList := c.Paginate(logCount, perPage, 5) + pageList := c.Paginate(page, lastPage, 5) pi := c.PanelRegLogsPage{basePage, llist, c.Paginator{pageList, page, lastPage}} return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage,"","","panel_reglogs", pi}) } @@ -123,7 +123,7 @@ func LogsMod(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError { llist[index] = c.PageLogItem{Action: template.HTML(action), IPAddress: log.IPAddress, DoneAt: log.DoneAt} } - pageList := c.Paginate(logCount, perPage, 5) + pageList := c.Paginate(page, lastPage, 5) pi := c.PanelLogsPage{basePage, llist, c.Paginator{pageList, page, lastPage}} return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage,"","","panel_modlogs", pi}) } @@ -150,7 +150,7 @@ func LogsAdmin(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError llist[index] = c.PageLogItem{Action: template.HTML(action), IPAddress: log.IPAddress, DoneAt: log.DoneAt} } - pageList := c.Paginate(logCount, perPage, 5) + pageList := c.Paginate(page, lastPage, 5) pi := c.PanelLogsPage{basePage, llist, c.Paginator{pageList, page, lastPage}} return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage,"","","panel_adminlogs", pi}) } diff --git a/routes/panel/pages.go b/routes/panel/pages.go index e1a08ab1..2cce3d65 100644 --- a/routes/panel/pages.go +++ b/routes/panel/pages.go @@ -31,9 +31,9 @@ func Pages(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError { return c.InternalError(err, w, r) } - pageList := c.Paginate(pageCount, perPage, 5) + pageList := c.Paginate(page, lastPage, 5) pi := c.PanelCustomPagesPage{basePage, cPages, c.Paginator{pageList, page, lastPage}} - return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage,"panel_page_list","","panel_pages",&pi}) + return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage, "panel_page_list", "", "panel_pages", &pi}) } func PagesCreateSubmit(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError { @@ -90,7 +90,7 @@ func PagesEdit(w http.ResponseWriter, r *http.Request, user c.User, spid string) } pi := c.PanelCustomPageEditPage{basePage, page} - return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage,"panel_page_edit","","panel_pages_edit",&pi}) + return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage, "panel_page_edit", "", "panel_pages_edit", &pi}) } func PagesEditSubmit(w http.ResponseWriter, r *http.Request, user c.User, spid string) c.RouteError { diff --git a/routes/panel/users.go b/routes/panel/users.go index 5be1b27b..c757c3a4 100644 --- a/routes/panel/users.go +++ b/routes/panel/users.go @@ -23,7 +23,7 @@ func Users(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError { return c.InternalError(err, w, r) } - pageList := c.Paginate(basePage.Stats.Users, perPage, 5) + pageList := c.Paginate(page, lastPage, 5) pi := c.PanelUserPage{basePage, users, c.Paginator{pageList, page, lastPage}} return renderTemplate("panel", w, r, basePage.Header, c.Panel{basePage,"","","panel_users",&pi}) } diff --git a/routes/topic.go b/routes/topic.go index 2864d1ad..08a626fc 100644 --- a/routes/topic.go +++ b/routes/topic.go @@ -126,7 +126,7 @@ func ViewTopic(w http.ResponseWriter, r *http.Request, user c.User, header *c.He // Calculate the offset offset, page, lastPage := c.PageOffset(topic.PostCount, page, c.Config.ItemsPerPage) - pageList := c.Paginate(topic.PostCount, c.Config.ItemsPerPage, 5) + pageList := c.Paginate(page, lastPage, 5) tpage := c.TopicPage{header, nil, topic, forum, poll, c.Paginator{pageList, page, lastPage}} // Get the replies if we have any...