fix pagination

This commit is contained in:
Nazar Kanaev 2021-05-31 14:37:45 +01:00
parent 7cfd3b3238
commit 7aeb458ee5
4 changed files with 50 additions and 58 deletions

View File

@ -260,7 +260,7 @@
<div>{{ item.title || 'untitled' }}</div>
</div>
</label>
<button class="btn btn-link btn-block loading my-3" v-if="itemsPage.cur < itemsPage.num"></button>
<button class="btn btn-link btn-block loading my-3" v-if="itemsHasMore"></button>
</div>
<div class="px-3 py-2 border-top text-danger text-break" v-if="feed_errors[current.feed.id]">
{{ feed_errors[current.feed.id] }}

View File

@ -180,7 +180,7 @@ var vm = new Vue({
created: function() {
this.refreshStats()
.then(this.refreshFeeds.bind(this))
.then(this.refreshItems.bind(this))
.then(this.refreshItems.bind(this, false))
api.feeds.list_errors().then(function(errors) {
vm.feed_errors = errors
@ -197,10 +197,7 @@ var vm = new Vue({
'feedNewChoice': [],
'feedNewChoiceSelected': '',
'items': [],
'itemsPage': {
'cur': 1,
'num': 1,
},
'itemsHasMore': true,
'itemSelected': null,
'itemSelectedDetails': null,
'itemSelectedReadability': '',
@ -304,13 +301,13 @@ var vm = new Vue({
},
'filterSelected': function(newVal, oldVal) {
if (oldVal === undefined) return // do nothing, initial setup
api.settings.update({filter: newVal}).then(this.refreshItems.bind(this))
api.settings.update({filter: newVal}).then(this.refreshItems.bind(this, false))
this.itemSelected = null
this.computeStats()
},
'feedSelected': function(newVal, oldVal) {
if (oldVal === undefined) return // do nothing, initial setup
api.settings.update({feed: newVal}).then(this.refreshItems.bind(this))
api.settings.update({feed: newVal}).then(this.refreshItems.bind(this, false))
this.itemSelected = null
if (this.$refs.itemlist) this.$refs.itemlist.scrollTop = 0
},
@ -339,7 +336,7 @@ var vm = new Vue({
}, 500),
'itemSortNewestFirst': function(newVal, oldVal) {
if (oldVal === undefined) return // do nothing, initial setup
api.settings.update({sort_newest_first: newVal}).then(this.refreshItems.bind(this))
api.settings.update({sort_newest_first: newVal}).then(vm.refreshItems.bind(this, false))
},
'feedListWidth': debounce(function(newVal, oldVal) {
if (oldVal === undefined) return // do nothing, initial setup
@ -404,34 +401,34 @@ var vm = new Vue({
vm.feeds = values[1]
})
},
refreshItems: function() {
refreshItems: function(loadMore) {
if (this.feedSelected === null) {
vm.items = []
vm.itemsPage = {'cur': 1, 'num': 1}
return
}
var query = this.getItemsQuery()
if (loadMore) {
query.after = vm.items[vm.items.length-1].id
}
this.loading.items = true
return api.items.list(query).then(function(data) {
if (loadMore) {
vm.items = vm.items.concat(data.list)
} else {
vm.items = data.list
vm.itemsPage = data.page
}
vm.itemsHasMore = data.has_more
vm.loading.items = false
})
},
loadMoreItems: function(event, el) {
if (this.itemsPage.cur >= this.itemsPage.num) return
if (!this.itemsHasMore) return
if (this.loading.items) return
var closeToBottom = (el.scrollHeight - el.scrollTop - el.offsetHeight) < 50
if (closeToBottom) {
this.loading.moreitems = true
var query = this.getItemsQuery()
query.page = this.itemsPage.cur + 1
api.items.list(query).then(function(data) {
vm.items = vm.items.concat(data.list)
vm.itemsPage = data.page
vm.loading.items = false
})
}
if (closeToBottom) this.refreshItems(true)
},
markItemsRead: function() {
var query = this.getItemsQuery()

View File

@ -5,7 +5,6 @@ import (
"encoding/json"
"fmt"
"log"
"math"
"net/http"
"path/filepath"
"reflect"
@ -307,11 +306,8 @@ func (s *Server) handleItem(c *router.Context) {
func (s *Server) handleItemList(c *router.Context) {
if c.Req.Method == "GET" {
perPage := 20
curPage := 1
query := c.Req.URL.Query()
if page, err := c.QueryInt64("page"); err == nil {
curPage = int(page)
}
filter := storage.ItemFilter{}
if folderID, err := c.QueryInt64("folder_id"); err == nil {
filter.FolderID = &folderID
@ -319,6 +315,9 @@ func (s *Server) handleItemList(c *router.Context) {
if feedID, err := c.QueryInt64("feed_id"); err == nil {
filter.FeedID = &feedID
}
if after, err := c.QueryInt64("after"); err == nil {
filter.After = &after
}
if status := query.Get("status"); len(status) != 0 {
statusValue := storage.StatusValues[status]
filter.Status = &statusValue
@ -327,14 +326,16 @@ func (s *Server) handleItemList(c *router.Context) {
filter.Search = &search
}
newestFirst := query.Get("oldest_first") != "true"
items := s.db.ListItems(filter, (curPage-1)*perPage, perPage, newestFirst)
count := s.db.CountItems(filter)
items := s.db.ListItems(filter, perPage+1, newestFirst)
hasMore := false
if len(items) == perPage+1 {
hasMore = true
items = items[:perPage]
}
c.JSON(http.StatusOK, map[string]interface{}{
"page": map[string]int{
"cur": curPage,
"num": int(math.Ceil(float64(count) / float64(perPage))),
},
"list": items,
"has_more": hasMore,
})
} else if c.Req.Method == "PUT" {
filter := storage.MarkFilter{}

View File

@ -61,6 +61,7 @@ type ItemFilter struct {
FeedID *int64
Status *ItemStatus
Search *string
After *int64
}
type MarkFilter struct {
@ -106,7 +107,7 @@ func (s *Storage) CreateItems(items []Item) bool {
return true
}
func listQueryPredicate(filter ItemFilter) (string, []interface{}) {
func listQueryPredicate(filter ItemFilter, newestFirst bool) (string, []interface{}) {
cond := make([]string, 0)
args := make([]interface{}, 0)
if filter.FolderID != nil {
@ -131,6 +132,14 @@ func listQueryPredicate(filter ItemFilter) (string, []interface{}) {
cond = append(cond, "i.search_rowid in (select rowid from search where search match ?)")
args = append(args, strings.Join(terms, " "))
}
if filter.After != nil {
compare := ">"
if newestFirst {
compare = "<"
}
cond = append(cond, fmt.Sprintf("(i.date, i.id) %s (select date, id from items where id = ?)", compare))
args = append(args, *filter.After)
}
predicate := "1"
if len(cond) > 0 {
@ -140,13 +149,13 @@ func listQueryPredicate(filter ItemFilter) (string, []interface{}) {
return predicate, args
}
func (s *Storage) ListItems(filter ItemFilter, offset, limit int, newestFirst bool) []Item {
predicate, args := listQueryPredicate(filter)
func (s *Storage) ListItems(filter ItemFilter, limit int, newestFirst bool) []Item {
predicate, args := listQueryPredicate(filter, newestFirst)
result := make([]Item, 0, 0)
order := "date desc"
order := "date desc, id desc"
if !newestFirst {
order = "date asc"
order = "date asc, id asc"
}
query := fmt.Sprintf(`
@ -157,8 +166,8 @@ func (s *Storage) ListItems(filter ItemFilter, offset, limit int, newestFirst bo
from items i
where %s
order by %s
limit %d offset %d
`, predicate, order, limit, offset)
limit %d
`, predicate, order, limit)
rows, err := s.db.Query(query, args...)
if err != nil {
log.Print(err)
@ -199,28 +208,13 @@ func (s *Storage) GetItem(id int64) *Item {
return i
}
func (s *Storage) CountItems(filter ItemFilter) int64 {
predicate, args := listQueryPredicate(filter)
query := fmt.Sprintf(`
select count(i.id)
from items i
where %s`, predicate)
row := s.db.QueryRow(query, args...)
if row != nil {
var result int64
row.Scan(&result)
return result
}
return 0
}
func (s *Storage) UpdateItemStatus(item_id int64, status ItemStatus) bool {
_, err := s.db.Exec(`update items set status = ? where id = ?`, status, item_id)
return err == nil
}
func (s *Storage) MarkItemsRead(filter MarkFilter) bool {
predicate, args := listQueryPredicate(ItemFilter{FolderID: filter.FolderID, FeedID: filter.FeedID})
predicate, args := listQueryPredicate(ItemFilter{FolderID: filter.FolderID, FeedID: filter.FeedID}, false)
query := fmt.Sprintf(`
update items as i set status = %d
where %s and i.status != %d