summaryrefslogtreecommitdiffstats
path: root/hugolib/pagination.go
diff options
context:
space:
mode:
authorbep <bjorn.erik.pedersen@gmail.com>2015-03-31 21:33:24 +0100
committerbep <bjorn.erik.pedersen@gmail.com>2015-03-31 22:33:17 +0200
commitbec4bdae992841f011239dac8c685e13470a90f3 (patch)
tree416c00cd413a5a3109005cdf76e813ce16363216 /hugolib/pagination.go
parentbec22f8981c251f88594689c65ad7b8822fe1b09 (diff)
Return error on wrong use of the Paginator
`Paginate`now returns error when 1) `.Paginate` is called after `.Paginator` 2) `.Paginate` is repeatedly called with different arguments This should help remove some confusion. This commit also introduces DistinctErrorLogger, to prevent spamming the log for duplicate rendering errors from the pagers. Fixes #993
Diffstat (limited to 'hugolib/pagination.go')
-rw-r--r--hugolib/pagination.go76
1 files changed, 65 insertions, 11 deletions
diff --git a/hugolib/pagination.go b/hugolib/pagination.go
index 650a355cf..f5380a337 100644
--- a/hugolib/pagination.go
+++ b/hugolib/pagination.go
@@ -22,6 +22,7 @@ import (
"html/template"
"math"
"path"
+ "reflect"
)
type pager struct {
@@ -37,8 +38,10 @@ type paginator struct {
paginatedPages []Pages
pagers
paginationURLFactory
- total int
- size int
+ total int
+ size int
+ source interface{}
+ options []interface{}
}
type paginationURLFactory func(int) string
@@ -164,6 +167,8 @@ func (n *Node) Paginator(options ...interface{}) (*pager, error) {
if len(pagers) > 0 {
// the rest of the nodes will be created later
n.paginator = pagers[0]
+ n.paginator.source = "paginator"
+ n.paginator.options = options
n.Site.addToPaginationPageCount(uint64(n.paginator.TotalPages()))
}
@@ -212,6 +217,8 @@ func (n *Node) Paginate(seq interface{}, options ...interface{}) (*pager, error)
if len(pagers) > 0 {
// the rest of the nodes will be created later
n.paginator = pagers[0]
+ n.paginator.source = seq
+ n.paginator.options = options
n.Site.addToPaginationPageCount(uint64(n.paginator.TotalPages()))
}
@@ -221,6 +228,14 @@ func (n *Node) Paginate(seq interface{}, options ...interface{}) (*pager, error)
return nil, initError
}
+ if n.paginator.source == "paginator" {
+ return nil, errors.New("a Paginator was previously built for this Node without filters; look for earlier .Paginator usage")
+ } else {
+ if !reflect.DeepEqual(options, n.paginator.options) || !probablyEqualPageLists(n.paginator.source, seq) {
+ return nil, errors.New("invoked multiple times with different arguments")
+ }
+ }
+
return n.paginator, nil
}
@@ -248,25 +263,64 @@ func paginatePages(seq interface{}, pagerSize int, section string) (pagers, erro
return nil, errors.New("'paginate' configuration setting must be positive to paginate")
}
- var pages Pages
+ pages, err := toPages(seq)
+ if err != nil {
+ return nil, err
+ }
+
+ urlFactory := newPaginationURLFactory(section)
+ paginator, _ := newPaginator(pages, pagerSize, urlFactory)
+ pagers := paginator.Pagers()
+
+ return pagers, nil
+}
+
+func toPages(seq interface{}) (Pages, error) {
switch seq.(type) {
case Pages:
- pages = seq.(Pages)
+ return seq.(Pages), nil
case *Pages:
- pages = *(seq.(*Pages))
+ return *(seq.(*Pages)), nil
case WeightedPages:
- pages = (seq.(WeightedPages)).Pages()
+ return (seq.(WeightedPages)).Pages(), nil
case PageGroup:
- pages = (seq.(PageGroup)).Pages
+ return (seq.(PageGroup)).Pages, nil
default:
return nil, errors.New(fmt.Sprintf("unsupported type in paginate, got %T", seq))
}
+}
- urlFactory := newPaginationURLFactory(section)
- paginator, _ := newPaginator(pages, pagerSize, urlFactory)
- pagers := paginator.Pagers()
+// probablyEqual checks page lists for probable equality.
+// It may return false positives.
+// The motivation behind this is to avoid potential costly reflect.DeepEqual
+// when "probably" is good enough.
+func probablyEqualPageLists(a1 interface{}, a2 interface{}) bool {
- return pagers, nil
+ if a1 == nil || a2 == nil {
+ return a1 == a2
+ }
+
+ p1, err1 := toPages(a1)
+ p2, err2 := toPages(a2)
+
+ // probably the same wrong type
+ if err1 != nil && err2 != nil {
+ return true
+ }
+
+ if err1 != nil || err2 != nil {
+ return false
+ }
+
+ if len(p1) != len(p2) {
+ return false
+ }
+
+ if len(p1) == 0 {
+ return true
+ }
+
+ return p1[0] == p2[0]
}
func newPaginator(pages Pages, size int, urlFactory paginationURLFactory) (*paginator, error) {