commit 0e922ffa3e84bd0f5d763586f3b24e6e32d7295e
parent 15463f835bbadd6f86158b83cb1499721ae2269f
Author: Shimmy Xu <shimmy.xu@shimmy1996.com>
Date: Tue, 26 Jul 2022 21:23:21 -0500
Add rev parameter to make last page the default
Diffstat:
3 files changed, 68 insertions(+), 46 deletions(-)
diff --git a/hugolib/page__paginator.go b/hugolib/page__paginator.go
@@ -34,6 +34,7 @@ type pagePaginator struct {
type pagePaginatorInit struct {
init sync.Once
current *page.Pager
+ rev bool
}
// reset resets the paginator to allow for a rebuild.
@@ -44,7 +45,7 @@ func (p *pagePaginator) reset() {
func (p *pagePaginator) Paginate(seq any, options ...any) (*page.Pager, error) {
var initErr error
p.init.Do(func() {
- pagerSize, err := page.ResolvePagerSize(p.source.s.Cfg, options...)
+ pagerSize, rev, err := page.ResolvePagerSize(p.source.s.Cfg, options...)
if err != nil {
initErr = err
return
@@ -52,13 +53,14 @@ func (p *pagePaginator) Paginate(seq any, options ...any) (*page.Pager, error) {
pd := p.source.targetPathDescriptor
pd.Type = p.source.outputFormat()
- paginator, err := page.Paginate(pd, seq, pagerSize)
+ paginator, err := page.Paginate(pd, seq, pagerSize, rev)
if err != nil {
initErr = err
return
}
p.current = paginator.Pagers()[0]
+ p.rev = rev
})
if initErr != nil {
@@ -71,7 +73,7 @@ func (p *pagePaginator) Paginate(seq any, options ...any) (*page.Pager, error) {
func (p *pagePaginator) Paginator(options ...any) (*page.Pager, error) {
var initErr error
p.init.Do(func() {
- pagerSize, err := page.ResolvePagerSize(p.source.s.Cfg, options...)
+ pagerSize, rev, err := page.ResolvePagerSize(p.source.s.Cfg, options...)
if err != nil {
initErr = err
return
@@ -94,13 +96,14 @@ func (p *pagePaginator) Paginator(options ...any) (*page.Pager, error) {
pages = p.source.RegularPages()
}
- paginator, err := page.Paginate(pd, pages, pagerSize)
+ paginator, err := page.Paginate(pd, pages, pagerSize, rev)
if err != nil {
initErr = err
return
}
p.current = paginator.Pagers()[0]
+ p.rev = rev
})
if initErr != nil {
diff --git a/hugolib/site_render.go b/hugolib/site_render.go
@@ -193,28 +193,24 @@ func (s *Site) renderPaginator(p *pageState, templ tpl.Template) error {
panic(fmt.Sprintf("invalid paginator state for %q", p.pathOrTitle()))
}
- if f.IsHTML {
- // Write alias for page 1
- d.Addends = fmt.Sprintf("/%s/%d", paginatePath, 1)
- targetPaths := page.CreateTargetPaths(d)
-
- if err := s.writeDestAlias(targetPaths.TargetFilename, p.Permalink(), f, nil); err != nil {
- return err
- }
- }
-
// Render pages for the rest
- for current := p.paginator.current.Next(); current != nil; current = current.Next() {
+ for current := p.paginator.current; current != nil; current = current.Next() {
p.paginator.current = current
d.Addends = fmt.Sprintf("/%s/%d", paginatePath, current.PageNumber())
targetPaths := page.CreateTargetPaths(d)
- if err := s.renderAndWritePage(
- &s.PathSpec.ProcessingStats.PaginatorPages,
- p.Title(),
- targetPaths.TargetFilename, p, templ); err != nil {
- return err
+ if f.IsHTML && current.Prev() == nil {
+ if err := s.writeDestAlias(targetPaths.TargetFilename, p.Permalink(), f, nil); err != nil {
+ return err
+ }
+ } else {
+ if err := s.renderAndWritePage(
+ &s.PathSpec.ProcessingStats.PaginatorPages,
+ p.Title(),
+ targetPaths.TargetFilename, p, templ); err != nil {
+ return err
+ }
}
}
diff --git a/resources/page/pagination.go b/resources/page/pagination.go
@@ -59,9 +59,10 @@ type Paginator struct {
paginationURLFactory
total int
size int
+ rev bool
}
-type paginationURLFactory func(int) string
+type paginationURLFactory func(int, int) string
// PageNumber returns the current page's number in the pager sequence.
func (p *Pager) PageNumber() int {
@@ -70,7 +71,7 @@ func (p *Pager) PageNumber() int {
// URL returns the URL to the current page.
func (p *Pager) URL() template.HTML {
- return template.HTML(p.paginationURLFactory(p.PageNumber()))
+ return template.HTML(p.paginationURLFactory(p.PageNumber(), p.TotalPages()))
}
// Pages returns the Pages on this page.
@@ -141,7 +142,7 @@ func (p *Pager) NumberOfElements() int {
// HasPrev tests whether there are page(s) before the current.
func (p *Pager) HasPrev() bool {
- return p.PageNumber() > 1
+ return (!p.rev && p.PageNumber() > 1) || (p.rev && p.PageNumber() < p.TotalPages())
}
// Prev returns the pager for the previous page.
@@ -149,12 +150,16 @@ func (p *Pager) Prev() *Pager {
if !p.HasPrev() {
return nil
}
- return p.pagers[p.PageNumber()-2]
+ if !p.rev {
+ return p.pagers[p.PageNumber()-2]
+ } else {
+ return p.pagers[p.TotalPages()-1-p.PageNumber()]
+ }
}
// HasNext tests whether there are page(s) after the current.
func (p *Pager) HasNext() bool {
- return p.PageNumber() < len(p.paginatedElements)
+ return (!p.rev && p.PageNumber() < len(p.paginatedElements)) || (p.rev && p.PageNumber() > 1)
}
// Next returns the pager for the next page.
@@ -162,7 +167,11 @@ func (p *Pager) Next() *Pager {
if !p.HasNext() {
return nil
}
- return p.pagers[p.PageNumber()]
+ if !p.rev {
+ return p.pagers[p.PageNumber()]
+ } else {
+ return p.pagers[p.TotalPages()+1-p.PageNumber()]
+ }
}
// First returns the pager for the first page.
@@ -248,30 +257,40 @@ func splitPageGroups(pageGroups PagesGroup, size int) []paginatedElement {
return split
}
-func ResolvePagerSize(cfg config.Provider, options ...any) (int, error) {
+func ResolvePagerSize(cfg config.Provider, options ...any) (int, bool, error) {
if len(options) == 0 {
- return cfg.GetInt("paginate"), nil
+ return cfg.GetInt("paginate"), cfg.GetBool("paginateRev"), nil
}
- if len(options) > 1 {
- return -1, errors.New("too many arguments, 'pager size' is currently the only option")
+ if len(options) > 2 {
+ return -1, false, errors.New("too many arguments, 'pager size' and 'rev' are currently the only options")
}
pas, err := cast.ToIntE(options[0])
if err != nil || pas <= 0 {
- return -1, errors.New(("'pager size' must be a positive integer"))
+ return -1, false, errors.New(("'pager size' must be a positive integer"))
+ }
+
+ if len(options) == 1 {
+ return pas, cfg.GetBool("paginateRev"), nil
}
- return pas, nil
+ rev, err := cast.ToBoolE(options[1])
+
+ if err != nil {
+ return -1, false, errors.New(("'rev' must be a bool"))
+ }
+
+ return pas, rev, nil
}
-func Paginate(td TargetPathDescriptor, seq any, pagerSize int) (*Paginator, error) {
+func Paginate(td TargetPathDescriptor, seq any, pagerSize int, rev bool) (*Paginator, error) {
if pagerSize <= 0 {
return nil, errors.New("'paginate' configuration setting must be positive to paginate")
}
- urlFactory := newPaginationURLFactory(td)
+ urlFactory := newPaginationURLFactory(td, rev)
var paginator *Paginator
@@ -280,13 +299,13 @@ func Paginate(td TargetPathDescriptor, seq any, pagerSize int) (*Paginator, erro
return nil, err
}
if groups != nil {
- paginator, _ = newPaginatorFromPageGroups(groups, pagerSize, urlFactory)
+ paginator, _ = newPaginatorFromPageGroups(groups, pagerSize, rev, urlFactory)
} else {
pages, err := ToPages(seq)
if err != nil {
return nil, err
}
- paginator, _ = newPaginatorFromPages(pages, pagerSize, urlFactory)
+ paginator, _ = newPaginatorFromPages(pages, pagerSize, rev, urlFactory)
}
return paginator, nil
@@ -342,35 +361,39 @@ func probablyEqualPageLists(a1 any, a2 any) bool {
return p1[0] == p2[0]
}
-func newPaginatorFromPages(pages Pages, size int, urlFactory paginationURLFactory) (*Paginator, error) {
+func newPaginatorFromPages(pages Pages, size int, rev bool, urlFactory paginationURLFactory) (*Paginator, error) {
if size <= 0 {
return nil, errors.New("Paginator size must be positive")
}
split := splitPages(pages, size)
- return newPaginator(split, len(pages), size, urlFactory)
+ return newPaginator(split, len(pages), size, rev, urlFactory)
}
-func newPaginatorFromPageGroups(pageGroups PagesGroup, size int, urlFactory paginationURLFactory) (*Paginator, error) {
+func newPaginatorFromPageGroups(pageGroups PagesGroup, size int, rev bool, urlFactory paginationURLFactory) (*Paginator, error) {
if size <= 0 {
return nil, errors.New("Paginator size must be positive")
}
split := splitPageGroups(pageGroups, size)
- return newPaginator(split, pageGroups.Len(), size, urlFactory)
+ return newPaginator(split, pageGroups.Len(), size, rev, urlFactory)
}
-func newPaginator(elements []paginatedElement, total, size int, urlFactory paginationURLFactory) (*Paginator, error) {
- p := &Paginator{total: total, paginatedElements: elements, size: size, paginationURLFactory: urlFactory}
+func newPaginator(elements []paginatedElement, total, size int, rev bool, urlFactory paginationURLFactory) (*Paginator, error) {
+ p := &Paginator{total: total, paginatedElements: elements, size: size, paginationURLFactory: urlFactory, rev: rev}
var ps pagers
if len(elements) > 0 {
ps = make(pagers, len(elements))
for i := range p.paginatedElements {
- ps[i] = &Pager{number: (i + 1), Paginator: p}
+ if !rev {
+ ps[i] = &Pager{number: (i + 1), Paginator: p}
+ } else {
+ ps[len(elements)-1-i] = &Pager{number: (i + 1), Paginator: p}
+ }
}
} else {
ps = make(pagers, 1)
@@ -382,11 +405,11 @@ func newPaginator(elements []paginatedElement, total, size int, urlFactory pagin
return p, nil
}
-func newPaginationURLFactory(d TargetPathDescriptor) paginationURLFactory {
- return func(pageNumber int) string {
+func newPaginationURLFactory(d TargetPathDescriptor, rev bool) paginationURLFactory {
+ return func(pageNumber int, totalPages int) string {
pathDescriptor := d
var rel string
- if pageNumber > 1 {
+ if (!rev && pageNumber > 1) || (rev && pageNumber < totalPages) {
rel = fmt.Sprintf("/%s/%d/", d.PathSpec.PaginatePath, pageNumber)
pathDescriptor.Addends = rel
}