mirror of
https://github.com/gohugoio/hugo.git
synced 2024-11-21 20:46:30 -05:00
parent
06d704f243
commit
bec22f8981
3 changed files with 106 additions and 20 deletions
|
@ -17,7 +17,7 @@ Hugo supports pagination for the home page, sections and taxonomies. It's built
|
||||||
|
|
||||||
Pagination can be configured in the site configuration (e.g. `config.toml`):
|
Pagination can be configured in the site configuration (e.g. `config.toml`):
|
||||||
|
|
||||||
* `Paginate` (default `10`)
|
* `Paginate` (default `10`) (this setting can be overridden in the template)
|
||||||
* `PaginatePath` (default `page`)
|
* `PaginatePath` (default `page`)
|
||||||
|
|
||||||
Setting `Paginate` to a positive value will split the list pages for the home page, sections and taxonomies into chunks of that size. But note that the generation of the pagination pages for sections, taxonomies and home page is *lazy* --- the pages will not be created if not referenced by a `.Paginator` (see below).
|
Setting `Paginate` to a positive value will split the list pages for the home page, sections and taxonomies into chunks of that size. But note that the generation of the pagination pages for sections, taxonomies and home page is *lazy* --- the pages will not be created if not referenced by a `.Paginator` (see below).
|
||||||
|
@ -35,6 +35,12 @@ There are two ways to configure and use a `.Paginator`:
|
||||||
|
|
||||||
For a given **Node**, it's one of the options above. The `.Paginator` is static and cannot change once created.
|
For a given **Node**, it's one of the options above. The `.Paginator` is static and cannot change once created.
|
||||||
|
|
||||||
|
|
||||||
|
The global page size setting (`Paginate`) can be overridden by providing a positive integer as the last argument. The examples below will give five items per page:
|
||||||
|
|
||||||
|
* `{{ range (.Paginator 5).Pages }}`
|
||||||
|
* `{{ $paginator := .Paginate (where .Data.Pages "Type" "post") 5 }}`
|
||||||
|
|
||||||
## Build the navigation
|
## Build the navigation
|
||||||
|
|
||||||
The `.Paginator` contains enough information to build a paginator interface.
|
The `.Paginator` contains enough information to build a paginator interface.
|
||||||
|
|
|
@ -16,6 +16,7 @@ package hugolib
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/spf13/cast"
|
||||||
"github.com/spf13/hugo/helpers"
|
"github.com/spf13/hugo/helpers"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
"html/template"
|
"html/template"
|
||||||
|
@ -139,7 +140,13 @@ func splitPages(pages Pages, size int) []Pages {
|
||||||
|
|
||||||
// Paginator gets this Node's paginator if it's already created.
|
// Paginator gets this Node's paginator if it's already created.
|
||||||
// If it's not, one will be created with all pages in Data["Pages"].
|
// If it's not, one will be created with all pages in Data["Pages"].
|
||||||
func (n *Node) Paginator() (*pager, error) {
|
func (n *Node) Paginator(options ...interface{}) (*pager, error) {
|
||||||
|
|
||||||
|
pagerSize, err := resolvePagerSize(options...)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
var initError error
|
var initError error
|
||||||
|
|
||||||
|
@ -148,7 +155,7 @@ func (n *Node) Paginator() (*pager, error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
pagers, err := paginatePages(n.Data["Pages"], n.URL)
|
pagers, err := paginatePages(n.Data["Pages"], pagerSize, n.URL)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
initError = err
|
initError = err
|
||||||
|
@ -170,19 +177,25 @@ func (n *Node) Paginator() (*pager, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Paginator on Page isn't supported, calling this yields an error.
|
// Paginator on Page isn't supported, calling this yields an error.
|
||||||
func (p *Page) Paginator() (*pager, error) {
|
func (p *Page) Paginator(options ...interface{}) (*pager, error) {
|
||||||
return nil, errors.New("Paginators not supported for content pages.")
|
return nil, errors.New("Paginators not supported for content pages.")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Paginate on Page isn't supported, calling this yields an error.
|
// Paginate on Page isn't supported, calling this yields an error.
|
||||||
func (p *Page) Paginate(seq interface{}) (*pager, error) {
|
func (p *Page) Paginate(seq interface{}, options ...interface{}) (*pager, error) {
|
||||||
return nil, errors.New("Paginators not supported for content pages.")
|
return nil, errors.New("Paginators not supported for content pages.")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Paginate gets this Node's paginator if it's already created.
|
// Paginate gets this Node's paginator if it's already created.
|
||||||
// If it's not, one will be created with the qiven sequence.
|
// If it's not, one will be created with the qiven sequence.
|
||||||
// Note that repeated calls will return the same result, even if the sequence is different.
|
// Note that repeated calls will return the same result, even if the sequence is different.
|
||||||
func (n *Node) Paginate(seq interface{}) (*pager, error) {
|
func (n *Node) Paginate(seq interface{}, options ...interface{}) (*pager, error) {
|
||||||
|
|
||||||
|
pagerSize, err := resolvePagerSize(options...)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
var initError error
|
var initError error
|
||||||
|
|
||||||
|
@ -190,7 +203,7 @@ func (n *Node) Paginate(seq interface{}) (*pager, error) {
|
||||||
if n.paginator != nil {
|
if n.paginator != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
pagers, err := paginatePages(seq, n.URL)
|
pagers, err := paginatePages(seq, pagerSize, n.URL)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
initError = err
|
initError = err
|
||||||
|
@ -211,12 +224,30 @@ func (n *Node) Paginate(seq interface{}) (*pager, error) {
|
||||||
return n.paginator, nil
|
return n.paginator, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func paginatePages(seq interface{}, section string) (pagers, error) {
|
func resolvePagerSize(options ...interface{}) (int, error) {
|
||||||
paginateSize := viper.GetInt("paginate")
|
if len(options) == 0 {
|
||||||
|
return viper.GetInt("paginate"), nil
|
||||||
|
}
|
||||||
|
|
||||||
if paginateSize <= 0 {
|
if len(options) > 1 {
|
||||||
|
return -1, errors.New("too many arguments, 'pager size' is currently the only option")
|
||||||
|
}
|
||||||
|
|
||||||
|
pas, err := cast.ToIntE(options[0])
|
||||||
|
|
||||||
|
if err != nil || pas <= 0 {
|
||||||
|
return -1, errors.New(("'pager size' must be a positive integer"))
|
||||||
|
}
|
||||||
|
|
||||||
|
return pas, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func paginatePages(seq interface{}, pagerSize int, section string) (pagers, error) {
|
||||||
|
|
||||||
|
if pagerSize <= 0 {
|
||||||
return nil, errors.New("'paginate' configuration setting must be positive to paginate")
|
return nil, errors.New("'paginate' configuration setting must be positive to paginate")
|
||||||
}
|
}
|
||||||
|
|
||||||
var pages Pages
|
var pages Pages
|
||||||
switch seq.(type) {
|
switch seq.(type) {
|
||||||
case Pages:
|
case Pages:
|
||||||
|
@ -232,7 +263,7 @@ func paginatePages(seq interface{}, section string) (pagers, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
urlFactory := newPaginationURLFactory(section)
|
urlFactory := newPaginationURLFactory(section)
|
||||||
paginator, _ := newPaginator(pages, paginateSize, urlFactory)
|
paginator, _ := newPaginator(pages, pagerSize, urlFactory)
|
||||||
pagers := paginator.Pagers()
|
pagers := paginator.Pagers()
|
||||||
|
|
||||||
return pagers, nil
|
return pagers, nil
|
||||||
|
|
|
@ -44,6 +44,7 @@ func TestPager(t *testing.T) {
|
||||||
|
|
||||||
first := paginatorPages[0]
|
first := paginatorPages[0]
|
||||||
assert.Equal(t, "page/1/", first.URL())
|
assert.Equal(t, "page/1/", first.URL())
|
||||||
|
assert.Equal(t, first.URL(), first.Url())
|
||||||
assert.Equal(t, first, first.First())
|
assert.Equal(t, first, first.First())
|
||||||
assert.True(t, first.HasNext())
|
assert.True(t, first.HasNext())
|
||||||
assert.Equal(t, paginatorPages[1], first.Next())
|
assert.Equal(t, paginatorPages[1], first.Next())
|
||||||
|
@ -110,14 +111,32 @@ func TestPaginationURLFactory(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPaginator(t *testing.T) {
|
func TestPaginator(t *testing.T) {
|
||||||
viper.Set("paginate", 5)
|
for _, useViper := range []bool{false, true} {
|
||||||
|
doTestPaginator(t, useViper)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func doTestPaginator(t *testing.T, useViper bool) {
|
||||||
|
pagerSize := 5
|
||||||
|
if useViper {
|
||||||
|
viper.Set("paginate", pagerSize)
|
||||||
|
} else {
|
||||||
|
viper.Set("paginate", -1)
|
||||||
|
}
|
||||||
pages := createTestPages(12)
|
pages := createTestPages(12)
|
||||||
s := &Site{}
|
s := &Site{}
|
||||||
n1 := s.newHomeNode()
|
n1 := s.newHomeNode()
|
||||||
n2 := s.newHomeNode()
|
n2 := s.newHomeNode()
|
||||||
n1.Data["Pages"] = pages
|
n1.Data["Pages"] = pages
|
||||||
|
|
||||||
paginator1, err := n1.Paginator()
|
var paginator1 *pager
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if useViper {
|
||||||
|
paginator1, err = n1.Paginator()
|
||||||
|
} else {
|
||||||
|
paginator1, err = n1.Paginator(pagerSize)
|
||||||
|
}
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.NotNil(t, paginator1)
|
assert.NotNil(t, paginator1)
|
||||||
|
@ -146,13 +165,33 @@ func TestPaginatorWithNegativePaginate(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPaginate(t *testing.T) {
|
func TestPaginate(t *testing.T) {
|
||||||
viper.Set("paginate", 5)
|
for _, useViper := range []bool{false, true} {
|
||||||
|
doTestPaginate(t, useViper)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func doTestPaginate(t *testing.T, useViper bool) {
|
||||||
|
|
||||||
|
pagerSize := 5
|
||||||
|
if useViper {
|
||||||
|
viper.Set("paginate", pagerSize)
|
||||||
|
} else {
|
||||||
|
viper.Set("paginate", -1)
|
||||||
|
}
|
||||||
|
|
||||||
pages := createTestPages(6)
|
pages := createTestPages(6)
|
||||||
s := &Site{}
|
s := &Site{}
|
||||||
n1 := s.newHomeNode()
|
n1 := s.newHomeNode()
|
||||||
n2 := s.newHomeNode()
|
n2 := s.newHomeNode()
|
||||||
|
|
||||||
paginator1, err := n1.Paginate(pages)
|
var paginator1 *pager
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if useViper {
|
||||||
|
paginator1, err = n1.Paginate(pages)
|
||||||
|
} else {
|
||||||
|
paginator1, err = n1.Paginate(pages, pagerSize)
|
||||||
|
}
|
||||||
|
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.NotNil(t, paginator1)
|
assert.NotNil(t, paginator1)
|
||||||
|
@ -172,6 +211,17 @@ func TestPaginate(t *testing.T) {
|
||||||
assert.NotNil(t, err)
|
assert.NotNil(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestInvalidOptions(t *testing.T) {
|
||||||
|
s := &Site{}
|
||||||
|
n1 := s.newHomeNode()
|
||||||
|
_, err := n1.Paginate(createTestPages(1), 1, 2)
|
||||||
|
assert.NotNil(t, err)
|
||||||
|
_, err = n1.Paginator(1, 2)
|
||||||
|
assert.NotNil(t, err)
|
||||||
|
_, err = n1.Paginator(-1)
|
||||||
|
assert.NotNil(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
func TestPaginateWithNegativePaginate(t *testing.T) {
|
func TestPaginateWithNegativePaginate(t *testing.T) {
|
||||||
viper.Set("paginate", -1)
|
viper.Set("paginate", -1)
|
||||||
s := &Site{}
|
s := &Site{}
|
||||||
|
@ -180,13 +230,12 @@ func TestPaginateWithNegativePaginate(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPaginatePages(t *testing.T) {
|
func TestPaginatePages(t *testing.T) {
|
||||||
viper.Set("paginate", 11)
|
|
||||||
for i, seq := range []interface{}{createTestPages(11), WeightedPages{}, PageGroup{}, &Pages{}} {
|
for i, seq := range []interface{}{createTestPages(11), WeightedPages{}, PageGroup{}, &Pages{}} {
|
||||||
v, err := paginatePages(seq, "t")
|
v, err := paginatePages(seq, 11, "t")
|
||||||
assert.NotNil(t, v, "Val %d", i)
|
assert.NotNil(t, v, "Val %d", i)
|
||||||
assert.Nil(t, err, "Err %d", i)
|
assert.Nil(t, err, "Err %d", i)
|
||||||
}
|
}
|
||||||
_, err := paginatePages(Site{}, "t")
|
_, err := paginatePages(Site{}, 11, "t")
|
||||||
assert.NotNil(t, err)
|
assert.NotNil(t, err)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue