mirror of
https://github.com/nkanaev/yarr.git
synced 2025-05-24 00:33:14 +00:00
fix pagination
This commit is contained in:
parent
7cfd3b3238
commit
7aeb458ee5
@ -260,7 +260,7 @@
|
|||||||
<div>{{ item.title || 'untitled' }}</div>
|
<div>{{ item.title || 'untitled' }}</div>
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</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>
|
||||||
<div class="px-3 py-2 border-top text-danger text-break" v-if="feed_errors[current.feed.id]">
|
<div class="px-3 py-2 border-top text-danger text-break" v-if="feed_errors[current.feed.id]">
|
||||||
{{ feed_errors[current.feed.id] }}
|
{{ feed_errors[current.feed.id] }}
|
||||||
|
@ -180,7 +180,7 @@ var vm = new Vue({
|
|||||||
created: function() {
|
created: function() {
|
||||||
this.refreshStats()
|
this.refreshStats()
|
||||||
.then(this.refreshFeeds.bind(this))
|
.then(this.refreshFeeds.bind(this))
|
||||||
.then(this.refreshItems.bind(this))
|
.then(this.refreshItems.bind(this, false))
|
||||||
|
|
||||||
api.feeds.list_errors().then(function(errors) {
|
api.feeds.list_errors().then(function(errors) {
|
||||||
vm.feed_errors = errors
|
vm.feed_errors = errors
|
||||||
@ -197,10 +197,7 @@ var vm = new Vue({
|
|||||||
'feedNewChoice': [],
|
'feedNewChoice': [],
|
||||||
'feedNewChoiceSelected': '',
|
'feedNewChoiceSelected': '',
|
||||||
'items': [],
|
'items': [],
|
||||||
'itemsPage': {
|
'itemsHasMore': true,
|
||||||
'cur': 1,
|
|
||||||
'num': 1,
|
|
||||||
},
|
|
||||||
'itemSelected': null,
|
'itemSelected': null,
|
||||||
'itemSelectedDetails': null,
|
'itemSelectedDetails': null,
|
||||||
'itemSelectedReadability': '',
|
'itemSelectedReadability': '',
|
||||||
@ -304,13 +301,13 @@ var vm = new Vue({
|
|||||||
},
|
},
|
||||||
'filterSelected': function(newVal, oldVal) {
|
'filterSelected': function(newVal, oldVal) {
|
||||||
if (oldVal === undefined) return // do nothing, initial setup
|
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.itemSelected = null
|
||||||
this.computeStats()
|
this.computeStats()
|
||||||
},
|
},
|
||||||
'feedSelected': function(newVal, oldVal) {
|
'feedSelected': function(newVal, oldVal) {
|
||||||
if (oldVal === undefined) return // do nothing, initial setup
|
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
|
this.itemSelected = null
|
||||||
if (this.$refs.itemlist) this.$refs.itemlist.scrollTop = 0
|
if (this.$refs.itemlist) this.$refs.itemlist.scrollTop = 0
|
||||||
},
|
},
|
||||||
@ -339,7 +336,7 @@ var vm = new Vue({
|
|||||||
}, 500),
|
}, 500),
|
||||||
'itemSortNewestFirst': function(newVal, oldVal) {
|
'itemSortNewestFirst': function(newVal, oldVal) {
|
||||||
if (oldVal === undefined) return // do nothing, initial setup
|
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) {
|
'feedListWidth': debounce(function(newVal, oldVal) {
|
||||||
if (oldVal === undefined) return // do nothing, initial setup
|
if (oldVal === undefined) return // do nothing, initial setup
|
||||||
@ -404,34 +401,34 @@ var vm = new Vue({
|
|||||||
vm.feeds = values[1]
|
vm.feeds = values[1]
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
refreshItems: function() {
|
refreshItems: function(loadMore) {
|
||||||
if (this.feedSelected === null) {
|
if (this.feedSelected === null) {
|
||||||
vm.items = []
|
vm.items = []
|
||||||
vm.itemsPage = {'cur': 1, 'num': 1}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var query = this.getItemsQuery()
|
var query = this.getItemsQuery()
|
||||||
|
if (loadMore) {
|
||||||
|
query.after = vm.items[vm.items.length-1].id
|
||||||
|
}
|
||||||
|
|
||||||
this.loading.items = true
|
this.loading.items = true
|
||||||
return api.items.list(query).then(function(data) {
|
return api.items.list(query).then(function(data) {
|
||||||
vm.items = data.list
|
if (loadMore) {
|
||||||
vm.itemsPage = data.page
|
vm.items = vm.items.concat(data.list)
|
||||||
|
} else {
|
||||||
|
vm.items = data.list
|
||||||
|
}
|
||||||
|
vm.itemsHasMore = data.has_more
|
||||||
vm.loading.items = false
|
vm.loading.items = false
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
loadMoreItems: function(event, el) {
|
loadMoreItems: function(event, el) {
|
||||||
if (this.itemsPage.cur >= this.itemsPage.num) return
|
if (!this.itemsHasMore) return
|
||||||
|
|
||||||
if (this.loading.items) return
|
if (this.loading.items) return
|
||||||
var closeToBottom = (el.scrollHeight - el.scrollTop - el.offsetHeight) < 50
|
var closeToBottom = (el.scrollHeight - el.scrollTop - el.offsetHeight) < 50
|
||||||
if (closeToBottom) {
|
if (closeToBottom) this.refreshItems(true)
|
||||||
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
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
markItemsRead: function() {
|
markItemsRead: function() {
|
||||||
var query = this.getItemsQuery()
|
var query = this.getItemsQuery()
|
||||||
|
@ -5,7 +5,6 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"math"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
@ -307,11 +306,8 @@ func (s *Server) handleItem(c *router.Context) {
|
|||||||
func (s *Server) handleItemList(c *router.Context) {
|
func (s *Server) handleItemList(c *router.Context) {
|
||||||
if c.Req.Method == "GET" {
|
if c.Req.Method == "GET" {
|
||||||
perPage := 20
|
perPage := 20
|
||||||
curPage := 1
|
|
||||||
query := c.Req.URL.Query()
|
query := c.Req.URL.Query()
|
||||||
if page, err := c.QueryInt64("page"); err == nil {
|
|
||||||
curPage = int(page)
|
|
||||||
}
|
|
||||||
filter := storage.ItemFilter{}
|
filter := storage.ItemFilter{}
|
||||||
if folderID, err := c.QueryInt64("folder_id"); err == nil {
|
if folderID, err := c.QueryInt64("folder_id"); err == nil {
|
||||||
filter.FolderID = &folderID
|
filter.FolderID = &folderID
|
||||||
@ -319,6 +315,9 @@ func (s *Server) handleItemList(c *router.Context) {
|
|||||||
if feedID, err := c.QueryInt64("feed_id"); err == nil {
|
if feedID, err := c.QueryInt64("feed_id"); err == nil {
|
||||||
filter.FeedID = &feedID
|
filter.FeedID = &feedID
|
||||||
}
|
}
|
||||||
|
if after, err := c.QueryInt64("after"); err == nil {
|
||||||
|
filter.After = &after
|
||||||
|
}
|
||||||
if status := query.Get("status"); len(status) != 0 {
|
if status := query.Get("status"); len(status) != 0 {
|
||||||
statusValue := storage.StatusValues[status]
|
statusValue := storage.StatusValues[status]
|
||||||
filter.Status = &statusValue
|
filter.Status = &statusValue
|
||||||
@ -327,14 +326,16 @@ func (s *Server) handleItemList(c *router.Context) {
|
|||||||
filter.Search = &search
|
filter.Search = &search
|
||||||
}
|
}
|
||||||
newestFirst := query.Get("oldest_first") != "true"
|
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{}{
|
c.JSON(http.StatusOK, map[string]interface{}{
|
||||||
"page": map[string]int{
|
|
||||||
"cur": curPage,
|
|
||||||
"num": int(math.Ceil(float64(count) / float64(perPage))),
|
|
||||||
},
|
|
||||||
"list": items,
|
"list": items,
|
||||||
|
"has_more": hasMore,
|
||||||
})
|
})
|
||||||
} else if c.Req.Method == "PUT" {
|
} else if c.Req.Method == "PUT" {
|
||||||
filter := storage.MarkFilter{}
|
filter := storage.MarkFilter{}
|
||||||
|
@ -61,6 +61,7 @@ type ItemFilter struct {
|
|||||||
FeedID *int64
|
FeedID *int64
|
||||||
Status *ItemStatus
|
Status *ItemStatus
|
||||||
Search *string
|
Search *string
|
||||||
|
After *int64
|
||||||
}
|
}
|
||||||
|
|
||||||
type MarkFilter struct {
|
type MarkFilter struct {
|
||||||
@ -106,7 +107,7 @@ func (s *Storage) CreateItems(items []Item) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func listQueryPredicate(filter ItemFilter) (string, []interface{}) {
|
func listQueryPredicate(filter ItemFilter, newestFirst bool) (string, []interface{}) {
|
||||||
cond := make([]string, 0)
|
cond := make([]string, 0)
|
||||||
args := make([]interface{}, 0)
|
args := make([]interface{}, 0)
|
||||||
if filter.FolderID != nil {
|
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 ?)")
|
cond = append(cond, "i.search_rowid in (select rowid from search where search match ?)")
|
||||||
args = append(args, strings.Join(terms, " "))
|
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"
|
predicate := "1"
|
||||||
if len(cond) > 0 {
|
if len(cond) > 0 {
|
||||||
@ -140,13 +149,13 @@ func listQueryPredicate(filter ItemFilter) (string, []interface{}) {
|
|||||||
return predicate, args
|
return predicate, args
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Storage) ListItems(filter ItemFilter, offset, limit int, newestFirst bool) []Item {
|
func (s *Storage) ListItems(filter ItemFilter, limit int, newestFirst bool) []Item {
|
||||||
predicate, args := listQueryPredicate(filter)
|
predicate, args := listQueryPredicate(filter, newestFirst)
|
||||||
result := make([]Item, 0, 0)
|
result := make([]Item, 0, 0)
|
||||||
|
|
||||||
order := "date desc"
|
order := "date desc, id desc"
|
||||||
if !newestFirst {
|
if !newestFirst {
|
||||||
order = "date asc"
|
order = "date asc, id asc"
|
||||||
}
|
}
|
||||||
|
|
||||||
query := fmt.Sprintf(`
|
query := fmt.Sprintf(`
|
||||||
@ -157,8 +166,8 @@ func (s *Storage) ListItems(filter ItemFilter, offset, limit int, newestFirst bo
|
|||||||
from items i
|
from items i
|
||||||
where %s
|
where %s
|
||||||
order by %s
|
order by %s
|
||||||
limit %d offset %d
|
limit %d
|
||||||
`, predicate, order, limit, offset)
|
`, predicate, order, limit)
|
||||||
rows, err := s.db.Query(query, args...)
|
rows, err := s.db.Query(query, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Print(err)
|
log.Print(err)
|
||||||
@ -199,28 +208,13 @@ func (s *Storage) GetItem(id int64) *Item {
|
|||||||
return i
|
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 {
|
func (s *Storage) UpdateItemStatus(item_id int64, status ItemStatus) bool {
|
||||||
_, err := s.db.Exec(`update items set status = ? where id = ?`, status, item_id)
|
_, err := s.db.Exec(`update items set status = ? where id = ?`, status, item_id)
|
||||||
return err == nil
|
return err == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Storage) MarkItemsRead(filter MarkFilter) bool {
|
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(`
|
query := fmt.Sprintf(`
|
||||||
update items as i set status = %d
|
update items as i set status = %d
|
||||||
where %s and i.status != %d
|
where %s and i.status != %d
|
||||||
|
Loading…
x
Reference in New Issue
Block a user