mirror of
				https://github.com/gohugoio/hugo.git
				synced 2024-05-11 05:54:58 +00:00 
			
		
		
		
	@@ -35,12 +35,17 @@ 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:
 | 
					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 }}`
 | 
					* `{{ range (.Paginator 5).Pages }}`
 | 
				
			||||||
* `{{ $paginator := .Paginate (where .Data.Pages "Type" "post") 5 }}`
 | 
					* `{{ $paginator := .Paginate (where .Data.Pages "Type" "post") 5 }}`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					It is also possible to use the `GroupBy` functions in combination with pagination:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					{{ range (.Paginate (.Data.Pages.GroupByDate "2006")).PageGroups  }}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## 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.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -31,12 +31,29 @@ type Pager struct {
 | 
				
			|||||||
	*paginator
 | 
						*paginator
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type paginatedElement interface {
 | 
				
			||||||
 | 
						Len() int
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (p Pages) Len() int {
 | 
				
			||||||
 | 
						return len(p)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (psg PagesGroup) Len() int {
 | 
				
			||||||
 | 
						l := 0
 | 
				
			||||||
 | 
						for _, pg := range psg {
 | 
				
			||||||
 | 
							l += len(pg.Pages)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return l
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type pagers []*Pager
 | 
					type pagers []*Pager
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var paginatorEmptyPages Pages
 | 
					var paginatorEmptyPages Pages
 | 
				
			||||||
 | 
					var paginatorEmptyPageGroups PagesGroup
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type paginator struct {
 | 
					type paginator struct {
 | 
				
			||||||
	paginatedPages []Pages
 | 
						paginatedElements []paginatedElement
 | 
				
			||||||
	pagers
 | 
						pagers
 | 
				
			||||||
	paginationURLFactory
 | 
						paginationURLFactory
 | 
				
			||||||
	total   int
 | 
						total   int
 | 
				
			||||||
@@ -63,17 +80,71 @@ func (p *Pager) Url() template.HTML {
 | 
				
			|||||||
	return p.URL()
 | 
						return p.URL()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Pages returns the elements on this page.
 | 
					// Pages returns the Pages on this page.
 | 
				
			||||||
 | 
					// Note: If this return a non-empty result, then PageGroups() will return empty.
 | 
				
			||||||
func (p *Pager) Pages() Pages {
 | 
					func (p *Pager) Pages() Pages {
 | 
				
			||||||
	if len(p.paginatedPages) == 0 {
 | 
						if len(p.paginatedElements) == 0 {
 | 
				
			||||||
		return paginatorEmptyPages
 | 
							return paginatorEmptyPages
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return p.paginatedPages[p.PageNumber()-1]
 | 
					
 | 
				
			||||||
 | 
						if pages, ok := p.element().(Pages); ok {
 | 
				
			||||||
 | 
							return pages
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return paginatorEmptyPages
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// PageGroups return Page groups for this page.
 | 
				
			||||||
 | 
					// Note: If this return non-empty result, then Pages() will return empty.
 | 
				
			||||||
 | 
					func (p *Pager) PageGroups() PagesGroup {
 | 
				
			||||||
 | 
						if len(p.paginatedElements) == 0 {
 | 
				
			||||||
 | 
							return paginatorEmptyPageGroups
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if groups, ok := p.element().(PagesGroup); ok {
 | 
				
			||||||
 | 
							return groups
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return paginatorEmptyPageGroups
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (p *Pager) element() paginatedElement {
 | 
				
			||||||
 | 
						if len(p.paginatedElements) == 0 {
 | 
				
			||||||
 | 
							return paginatorEmptyPages
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return p.paginatedElements[p.PageNumber()-1]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// page returns the Page with the given index
 | 
				
			||||||
 | 
					func (p *Pager) page(index int) (*Page, error) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if pages, ok := p.element().(Pages); ok {
 | 
				
			||||||
 | 
							if pages != nil && len(pages) > index {
 | 
				
			||||||
 | 
								return pages[index], nil
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return nil, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// must be PagesGroup
 | 
				
			||||||
 | 
						// this construction looks clumsy, but ...
 | 
				
			||||||
 | 
						// ... it is the difference between 99.5% and 100% test coverage :-)
 | 
				
			||||||
 | 
						groups := p.element().(PagesGroup)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						i := 0
 | 
				
			||||||
 | 
						for _, v := range groups {
 | 
				
			||||||
 | 
							for _, page := range v.Pages {
 | 
				
			||||||
 | 
								if i == index {
 | 
				
			||||||
 | 
									return page, nil
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								i++
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nil, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// NumberOfElements gets the number of elements on this page.
 | 
					// NumberOfElements gets the number of elements on this page.
 | 
				
			||||||
func (p *Pager) NumberOfElements() int {
 | 
					func (p *Pager) NumberOfElements() int {
 | 
				
			||||||
	return len(p.Pages())
 | 
						return p.element().Len()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// HasPrev tests whether there are page(s) before the current.
 | 
					// HasPrev tests whether there are page(s) before the current.
 | 
				
			||||||
@@ -91,7 +162,7 @@ func (p *Pager) Prev() *Pager {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// HasNext tests whether there are page(s) after the current.
 | 
					// HasNext tests whether there are page(s) after the current.
 | 
				
			||||||
func (p *Pager) HasNext() bool {
 | 
					func (p *Pager) HasNext() bool {
 | 
				
			||||||
	return p.PageNumber() < len(p.paginatedPages)
 | 
						return p.PageNumber() < len(p.paginatedElements)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Next returns the pager for the next page.
 | 
					// Next returns the pager for the next page.
 | 
				
			||||||
@@ -124,7 +195,7 @@ func (p *paginator) PageSize() int {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// TotalPages returns the number of pages in the paginator.
 | 
					// TotalPages returns the number of pages in the paginator.
 | 
				
			||||||
func (p *paginator) TotalPages() int {
 | 
					func (p *paginator) TotalPages() int {
 | 
				
			||||||
	return len(p.paginatedPages)
 | 
						return len(p.paginatedElements)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// TotalNumberOfElements returns the number of elements on all pages in this paginator.
 | 
					// TotalNumberOfElements returns the number of elements on all pages in this paginator.
 | 
				
			||||||
@@ -132,8 +203,8 @@ func (p *paginator) TotalNumberOfElements() int {
 | 
				
			|||||||
	return p.total
 | 
						return p.total
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func splitPages(pages Pages, size int) []Pages {
 | 
					func splitPages(pages Pages, size int) []paginatedElement {
 | 
				
			||||||
	var split []Pages
 | 
						var split []paginatedElement
 | 
				
			||||||
	for low, j := 0, len(pages); low < j; low += size {
 | 
						for low, j := 0, len(pages); low < j; low += size {
 | 
				
			||||||
		high := int(math.Min(float64(low+size), float64(len(pages))))
 | 
							high := int(math.Min(float64(low+size), float64(len(pages))))
 | 
				
			||||||
		split = append(split, pages[low:high])
 | 
							split = append(split, pages[low:high])
 | 
				
			||||||
@@ -142,6 +213,44 @@ func splitPages(pages Pages, size int) []Pages {
 | 
				
			|||||||
	return split
 | 
						return split
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func splitPageGroups(pageGroups PagesGroup, size int) []paginatedElement {
 | 
				
			||||||
 | 
						var split []paginatedElement
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						type keyPage struct {
 | 
				
			||||||
 | 
							key  interface{}
 | 
				
			||||||
 | 
							page *Page
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var flattened []keyPage
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, g := range pageGroups {
 | 
				
			||||||
 | 
							for _, p := range g.Pages {
 | 
				
			||||||
 | 
								flattened = append(flattened, keyPage{g.Key, p})
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						numPages := len(flattened)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for low, j := 0, numPages; low < j; low += size {
 | 
				
			||||||
 | 
							high := int(math.Min(float64(low+size), float64(numPages)))
 | 
				
			||||||
 | 
							var pg PagesGroup
 | 
				
			||||||
 | 
							var key interface{} = nil
 | 
				
			||||||
 | 
							var groupIndex = -1
 | 
				
			||||||
 | 
							for k := low; k < high; k++ {
 | 
				
			||||||
 | 
								kp := flattened[k]
 | 
				
			||||||
 | 
								if key == nil || key != kp.key {
 | 
				
			||||||
 | 
									key = kp.key
 | 
				
			||||||
 | 
									pg = append(pg, PageGroup{Key: key})
 | 
				
			||||||
 | 
									groupIndex++
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								pg[groupIndex].Pages = append(pg[groupIndex].Pages, kp.page)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							split = append(split, pg)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return split
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 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(options ...interface{}) (*Pager, error) {
 | 
					func (n *Node) Paginator(options ...interface{}) (*Pager, error) {
 | 
				
			||||||
@@ -264,15 +373,21 @@ func paginatePages(seq interface{}, pagerSize int, section string) (pagers, erro
 | 
				
			|||||||
		return nil, errors.New("'paginate' configuration setting must be positive to paginate")
 | 
							return nil, errors.New("'paginate' configuration setting must be positive to paginate")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pages, err := toPages(seq)
 | 
						section = strings.TrimSuffix(section, ".html")
 | 
				
			||||||
	if err != nil {
 | 
						urlFactory := newPaginationURLFactory(section)
 | 
				
			||||||
		return nil, err
 | 
					
 | 
				
			||||||
 | 
						var paginator *paginator
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if groups, ok := seq.(PagesGroup); ok {
 | 
				
			||||||
 | 
							paginator, _ = newPaginatorFromPageGroups(groups, pagerSize, urlFactory)
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							pages, err := toPages(seq)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return nil, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							paginator, _ = newPaginatorFromPages(pages, pagerSize, urlFactory)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	section = strings.TrimSuffix(section, ".html")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	urlFactory := newPaginationURLFactory(section)
 | 
					 | 
				
			||||||
	paginator, _ := newPaginator(pages, pagerSize, urlFactory)
 | 
					 | 
				
			||||||
	pagers := paginator.Pagers()
 | 
						pagers := paginator.Pagers()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return pagers, nil
 | 
						return pagers, nil
 | 
				
			||||||
@@ -303,6 +418,28 @@ func probablyEqualPageLists(a1 interface{}, a2 interface{}) bool {
 | 
				
			|||||||
		return a1 == a2
 | 
							return a1 == a2
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						t1 := reflect.TypeOf(a1)
 | 
				
			||||||
 | 
						t2 := reflect.TypeOf(a2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if t1 != t2 {
 | 
				
			||||||
 | 
							return false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if g1, ok := a1.(PagesGroup); ok {
 | 
				
			||||||
 | 
							g2 := a2.(PagesGroup)
 | 
				
			||||||
 | 
							if len(g1) != len(g2) {
 | 
				
			||||||
 | 
								return false
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if len(g1) == 0 {
 | 
				
			||||||
 | 
								return true
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if g1.Len() != g2.Len() {
 | 
				
			||||||
 | 
								return false
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return g1[0].Pages[0] == g2[0].Pages[0]
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	p1, err1 := toPages(a1)
 | 
						p1, err1 := toPages(a1)
 | 
				
			||||||
	p2, err2 := toPages(a2)
 | 
						p2, err2 := toPages(a2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -311,10 +448,6 @@ func probablyEqualPageLists(a1 interface{}, a2 interface{}) bool {
 | 
				
			|||||||
		return true
 | 
							return true
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err1 != nil || err2 != nil {
 | 
					 | 
				
			||||||
		return false
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if len(p1) != len(p2) {
 | 
						if len(p1) != len(p2) {
 | 
				
			||||||
		return false
 | 
							return false
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -326,7 +459,7 @@ func probablyEqualPageLists(a1 interface{}, a2 interface{}) bool {
 | 
				
			|||||||
	return p1[0] == p2[0]
 | 
						return p1[0] == p2[0]
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func newPaginator(pages Pages, size int, urlFactory paginationURLFactory) (*paginator, error) {
 | 
					func newPaginatorFromPages(pages Pages, size int, urlFactory paginationURLFactory) (*paginator, error) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if size <= 0 {
 | 
						if size <= 0 {
 | 
				
			||||||
		return nil, errors.New("Paginator size must be positive")
 | 
							return nil, errors.New("Paginator size must be positive")
 | 
				
			||||||
@@ -334,13 +467,28 @@ func newPaginator(pages Pages, size int, urlFactory paginationURLFactory) (*pagi
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	split := splitPages(pages, size)
 | 
						split := splitPages(pages, size)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	p := &paginator{total: len(pages), paginatedPages: split, size: size, paginationURLFactory: urlFactory}
 | 
						return newPaginator(split, len(pages), size, urlFactory)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func newPaginatorFromPageGroups(pageGroups PagesGroup, size int, 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)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func newPaginator(elements []paginatedElement, total, size int, urlFactory paginationURLFactory) (*paginator, error) {
 | 
				
			||||||
 | 
						p := &paginator{total: total, paginatedElements: elements, size: size, paginationURLFactory: urlFactory}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var ps pagers
 | 
						var ps pagers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if len(split) > 0 {
 | 
						if len(elements) > 0 {
 | 
				
			||||||
		ps = make(pagers, len(split))
 | 
							ps = make(pagers, len(elements))
 | 
				
			||||||
		for i := range p.paginatedPages {
 | 
							for i := range p.paginatedElements {
 | 
				
			||||||
			ps[i] = &Pager{number: (i + 1), paginator: p}
 | 
								ps[i] = &Pager{number: (i + 1), paginator: p}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,25 +18,86 @@ func TestSplitPages(t *testing.T) {
 | 
				
			|||||||
	assert.Equal(t, 5, len(chunks))
 | 
						assert.Equal(t, 5, len(chunks))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for i := 0; i < 4; i++ {
 | 
						for i := 0; i < 4; i++ {
 | 
				
			||||||
		assert.Equal(t, 5, len(chunks[i]))
 | 
							assert.Equal(t, 5, chunks[i].Len())
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	lastChunk := chunks[4]
 | 
						lastChunk := chunks[4]
 | 
				
			||||||
	assert.Equal(t, 1, len(lastChunk))
 | 
						assert.Equal(t, 1, lastChunk.Len())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestSplitPageGroups(t *testing.T) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pages := createTestPages(21)
 | 
				
			||||||
 | 
						groups, _ := pages.GroupBy("Weight", "desc")
 | 
				
			||||||
 | 
						chunks := splitPageGroups(groups, 5)
 | 
				
			||||||
 | 
						assert.Equal(t, 5, len(chunks))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						firstChunk := chunks[0]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// alternate weight 5 and 10
 | 
				
			||||||
 | 
						if groups, ok := firstChunk.(PagesGroup); ok {
 | 
				
			||||||
 | 
							assert.Equal(t, 5, groups.Len())
 | 
				
			||||||
 | 
							for _, pg := range groups {
 | 
				
			||||||
 | 
								// first group 10 in weight
 | 
				
			||||||
 | 
								assert.Equal(t, 10, pg.Key)
 | 
				
			||||||
 | 
								for _, p := range pg.Pages {
 | 
				
			||||||
 | 
									assert.True(t, p.FuzzyWordCount%2 == 0) // magic test
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							t.Fatal("Excepted PageGroup")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						lastChunk := chunks[4]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if groups, ok := lastChunk.(PagesGroup); ok {
 | 
				
			||||||
 | 
							assert.Equal(t, 1, groups.Len())
 | 
				
			||||||
 | 
							for _, pg := range groups {
 | 
				
			||||||
 | 
								// last should have 5 in weight
 | 
				
			||||||
 | 
								assert.Equal(t, 5, pg.Key)
 | 
				
			||||||
 | 
								for _, p := range pg.Pages {
 | 
				
			||||||
 | 
									assert.True(t, p.FuzzyWordCount%2 != 0) // magic test
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							t.Fatal("Excepted PageGroup")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestPager(t *testing.T) {
 | 
					func TestPager(t *testing.T) {
 | 
				
			||||||
 | 
					 | 
				
			||||||
	pages := createTestPages(21)
 | 
						pages := createTestPages(21)
 | 
				
			||||||
 | 
						groups, _ := pages.GroupBy("Weight", "desc")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	urlFactory := func(page int) string {
 | 
						urlFactory := func(page int) string {
 | 
				
			||||||
		return fmt.Sprintf("page/%d/", page)
 | 
							return fmt.Sprintf("page/%d/", page)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	_, err := newPaginator(pages, -1, urlFactory)
 | 
						_, err := newPaginatorFromPages(pages, -1, urlFactory)
 | 
				
			||||||
	assert.NotNil(t, err)
 | 
						assert.NotNil(t, err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	paginator, _ := newPaginator(pages, 5, urlFactory)
 | 
						_, err = newPaginatorFromPageGroups(groups, -1, urlFactory)
 | 
				
			||||||
 | 
						assert.NotNil(t, err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pag, err := newPaginatorFromPages(pages, 5, urlFactory)
 | 
				
			||||||
 | 
						assert.Nil(t, err)
 | 
				
			||||||
 | 
						doTestPages(t, pag)
 | 
				
			||||||
 | 
						first := pag.Pagers()[0].First()
 | 
				
			||||||
 | 
						assert.NotEmpty(t, first.Pages())
 | 
				
			||||||
 | 
						assert.Empty(t, first.PageGroups())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pag, err = newPaginatorFromPageGroups(groups, 5, urlFactory)
 | 
				
			||||||
 | 
						assert.Nil(t, err)
 | 
				
			||||||
 | 
						doTestPages(t, pag)
 | 
				
			||||||
 | 
						first = pag.Pagers()[0].First()
 | 
				
			||||||
 | 
						assert.NotEmpty(t, first.PageGroups())
 | 
				
			||||||
 | 
						assert.Empty(t, first.Pages())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func doTestPages(t *testing.T, paginator *paginator) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	paginatorPages := paginator.Pagers()
 | 
						paginatorPages := paginator.Pagers()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	assert.Equal(t, 5, len(paginatorPages))
 | 
						assert.Equal(t, 5, len(paginatorPages))
 | 
				
			||||||
@@ -72,11 +133,29 @@ func TestPager(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func TestPagerNoPages(t *testing.T) {
 | 
					func TestPagerNoPages(t *testing.T) {
 | 
				
			||||||
	pages := createTestPages(0)
 | 
						pages := createTestPages(0)
 | 
				
			||||||
 | 
						groups, _ := pages.GroupBy("Weight", "desc")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	urlFactory := func(page int) string {
 | 
						urlFactory := func(page int) string {
 | 
				
			||||||
		return fmt.Sprintf("page/%d/", page)
 | 
							return fmt.Sprintf("page/%d/", page)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	paginator, _ := newPaginator(pages, 5, urlFactory)
 | 
						paginator, _ := newPaginatorFromPages(pages, 5, urlFactory)
 | 
				
			||||||
 | 
						doTestPagerNoPages(t, paginator)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						first := paginator.Pagers()[0].First()
 | 
				
			||||||
 | 
						assert.Empty(t, first.PageGroups())
 | 
				
			||||||
 | 
						assert.Empty(t, first.Pages())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						paginator, _ = newPaginatorFromPageGroups(groups, 5, urlFactory)
 | 
				
			||||||
 | 
						doTestPagerNoPages(t, paginator)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						first = paginator.Pagers()[0].First()
 | 
				
			||||||
 | 
						assert.Empty(t, first.PageGroups())
 | 
				
			||||||
 | 
						assert.Empty(t, first.Pages())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func doTestPagerNoPages(t *testing.T, paginator *paginator) {
 | 
				
			||||||
	paginatorPages := paginator.Pagers()
 | 
						paginatorPages := paginator.Pagers()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	assert.Equal(t, 1, len(paginatorPages))
 | 
						assert.Equal(t, 1, len(paginatorPages))
 | 
				
			||||||
@@ -91,7 +170,7 @@ func TestPagerNoPages(t *testing.T) {
 | 
				
			|||||||
	assert.False(t, pageOne.HasPrev())
 | 
						assert.False(t, pageOne.HasPrev())
 | 
				
			||||||
	assert.Nil(t, pageOne.Next())
 | 
						assert.Nil(t, pageOne.Next())
 | 
				
			||||||
	assert.Equal(t, 1, len(pageOne.Pagers()))
 | 
						assert.Equal(t, 1, len(pageOne.Pagers()))
 | 
				
			||||||
	assert.Equal(t, 0, len(pageOne.Pages()))
 | 
						assert.Equal(t, 0, pageOne.Pages().Len())
 | 
				
			||||||
	assert.Equal(t, 0, pageOne.NumberOfElements())
 | 
						assert.Equal(t, 0, pageOne.NumberOfElements())
 | 
				
			||||||
	assert.Equal(t, 0, pageOne.TotalNumberOfElements())
 | 
						assert.Equal(t, 0, pageOne.TotalNumberOfElements())
 | 
				
			||||||
	assert.Equal(t, 0, pageOne.TotalPages())
 | 
						assert.Equal(t, 0, pageOne.TotalPages())
 | 
				
			||||||
@@ -250,7 +329,8 @@ func TestPaginateWithNegativePaginate(t *testing.T) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestPaginatePages(t *testing.T) {
 | 
					func TestPaginatePages(t *testing.T) {
 | 
				
			||||||
	for i, seq := range []interface{}{createTestPages(11), WeightedPages{}, PageGroup{}, &Pages{}} {
 | 
						groups, _ := createTestPages(31).GroupBy("Weight", "desc")
 | 
				
			||||||
 | 
						for i, seq := range []interface{}{createTestPages(11), groups, WeightedPages{}, PageGroup{}, &Pages{}} {
 | 
				
			||||||
		v, err := paginatePages(seq, 11, "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)
 | 
				
			||||||
@@ -308,6 +388,10 @@ func TestPaginateFollowedByDifferentPaginateShouldFail(t *testing.T) {
 | 
				
			|||||||
func TestProbablyEqualPageLists(t *testing.T) {
 | 
					func TestProbablyEqualPageLists(t *testing.T) {
 | 
				
			||||||
	fivePages := createTestPages(5)
 | 
						fivePages := createTestPages(5)
 | 
				
			||||||
	zeroPages := createTestPages(0)
 | 
						zeroPages := createTestPages(0)
 | 
				
			||||||
 | 
						zeroPagesByWeight, _ := createTestPages(0).GroupBy("Weight", "asc")
 | 
				
			||||||
 | 
						fivePagesByWeight, _ := createTestPages(5).GroupBy("Weight", "asc")
 | 
				
			||||||
 | 
						ninePagesByWeight, _ := createTestPages(9).GroupBy("Weight", "asc")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for i, this := range []struct {
 | 
						for i, this := range []struct {
 | 
				
			||||||
		v1     interface{}
 | 
							v1     interface{}
 | 
				
			||||||
		v2     interface{}
 | 
							v2     interface{}
 | 
				
			||||||
@@ -320,6 +404,11 @@ func TestProbablyEqualPageLists(t *testing.T) {
 | 
				
			|||||||
		{fivePages, createTestPages(2), false},
 | 
							{fivePages, createTestPages(2), false},
 | 
				
			||||||
		{fivePages, fivePages, true},
 | 
							{fivePages, fivePages, true},
 | 
				
			||||||
		{zeroPages, zeroPages, true},
 | 
							{zeroPages, zeroPages, true},
 | 
				
			||||||
 | 
							{fivePagesByWeight, fivePagesByWeight, true},
 | 
				
			||||||
 | 
							{zeroPagesByWeight, fivePagesByWeight, false},
 | 
				
			||||||
 | 
							{zeroPagesByWeight, zeroPagesByWeight, true},
 | 
				
			||||||
 | 
							{fivePagesByWeight, fivePages, false},
 | 
				
			||||||
 | 
							{fivePagesByWeight, ninePagesByWeight, false},
 | 
				
			||||||
	} {
 | 
						} {
 | 
				
			||||||
		result := probablyEqualPageLists(this.v1, this.v2)
 | 
							result := probablyEqualPageLists(this.v1, this.v2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -330,6 +419,33 @@ func TestProbablyEqualPageLists(t *testing.T) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestPage(t *testing.T) {
 | 
				
			||||||
 | 
						urlFactory := func(page int) string {
 | 
				
			||||||
 | 
							return fmt.Sprintf("page/%d/", page)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fivePages := createTestPages(7)
 | 
				
			||||||
 | 
						fivePagesFuzzyWordCount, _ := createTestPages(7).GroupBy("FuzzyWordCount", "asc")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						p1, _ := newPaginatorFromPages(fivePages, 2, urlFactory)
 | 
				
			||||||
 | 
						p2, _ := newPaginatorFromPageGroups(fivePagesFuzzyWordCount, 2, urlFactory)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						f1 := p1.pagers[0].First()
 | 
				
			||||||
 | 
						f2 := p2.pagers[0].First()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						page11, _ := f1.page(1)
 | 
				
			||||||
 | 
						page1Nil, _ := f1.page(3)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						page21, _ := f2.page(1)
 | 
				
			||||||
 | 
						page2Nil, _ := f2.page(3)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						assert.Equal(t, 1, page11.FuzzyWordCount)
 | 
				
			||||||
 | 
						assert.Nil(t, page1Nil)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						assert.Equal(t, 1, page21.FuzzyWordCount)
 | 
				
			||||||
 | 
						assert.Nil(t, page2Nil)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func createTestPages(num int) Pages {
 | 
					func createTestPages(num int) Pages {
 | 
				
			||||||
	pages := make(Pages, num)
 | 
						pages := make(Pages, num)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -338,14 +454,20 @@ func createTestPages(num int) Pages {
 | 
				
			|||||||
			Node: Node{
 | 
								Node: Node{
 | 
				
			||||||
				URLPath: URLPath{
 | 
									URLPath: URLPath{
 | 
				
			||||||
					Section: "z",
 | 
										Section: "z",
 | 
				
			||||||
					URL:     fmt.Sprintf("http://base/x/y/p%d.html", num),
 | 
										URL:     fmt.Sprintf("http://base/x/y/p%d.html", i),
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
				Site: &SiteInfo{
 | 
									Site: &SiteInfo{
 | 
				
			||||||
					BaseURL: "http://base/",
 | 
										BaseURL: "http://base/",
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			Source: Source{File: *source.NewFile(filepath.FromSlash(fmt.Sprintf("/x/y/p%d.md", num)))},
 | 
								Source: Source{File: *source.NewFile(filepath.FromSlash(fmt.Sprintf("/x/y/p%d.md", i)))},
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							w := 5
 | 
				
			||||||
 | 
							if i%2 == 0 {
 | 
				
			||||||
 | 
								w = 10
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							pages[i].FuzzyWordCount = i
 | 
				
			||||||
 | 
							pages[i].Weight = w
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return pages
 | 
						return pages
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1118,8 +1118,9 @@ func taxonomyRenderer(s *Site, taxes <-chan taxRenderInfo, results chan<- error,
 | 
				
			|||||||
				taxonomyPagerNode, _ := s.newTaxonomyNode(t)
 | 
									taxonomyPagerNode, _ := s.newTaxonomyNode(t)
 | 
				
			||||||
				taxonomyPagerNode.paginator = pager
 | 
									taxonomyPagerNode.paginator = pager
 | 
				
			||||||
				if pager.TotalPages() > 0 {
 | 
									if pager.TotalPages() > 0 {
 | 
				
			||||||
					taxonomyPagerNode.Date = pager.Pages()[0].Date
 | 
										first, _ := pager.page(0)
 | 
				
			||||||
					taxonomyPagerNode.Lastmod = pager.Pages()[0].Lastmod
 | 
										taxonomyPagerNode.Date = first.Date
 | 
				
			||||||
 | 
										taxonomyPagerNode.Lastmod = first.Lastmod
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				pageNumber := i + 1
 | 
									pageNumber := i + 1
 | 
				
			||||||
				htmlBase := fmt.Sprintf("/%s/%s/%d", base, paginatePath, pageNumber)
 | 
									htmlBase := fmt.Sprintf("/%s/%s/%d", base, paginatePath, pageNumber)
 | 
				
			||||||
@@ -1224,8 +1225,9 @@ func (s *Site) RenderSectionLists() error {
 | 
				
			|||||||
				sectionPagerNode := s.newSectionListNode(sectionName, section, data)
 | 
									sectionPagerNode := s.newSectionListNode(sectionName, section, data)
 | 
				
			||||||
				sectionPagerNode.paginator = pager
 | 
									sectionPagerNode.paginator = pager
 | 
				
			||||||
				if pager.TotalPages() > 0 {
 | 
									if pager.TotalPages() > 0 {
 | 
				
			||||||
					sectionPagerNode.Date = pager.Pages()[0].Date
 | 
										first, _ := pager.page(0)
 | 
				
			||||||
					sectionPagerNode.Lastmod = pager.Pages()[0].Lastmod
 | 
										sectionPagerNode.Date = first.Date
 | 
				
			||||||
 | 
										sectionPagerNode.Lastmod = first.Lastmod
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				pageNumber := i + 1
 | 
									pageNumber := i + 1
 | 
				
			||||||
				htmlBase := fmt.Sprintf("/%s/%s/%d", section, paginatePath, pageNumber)
 | 
									htmlBase := fmt.Sprintf("/%s/%s/%d", section, paginatePath, pageNumber)
 | 
				
			||||||
@@ -1283,8 +1285,9 @@ func (s *Site) RenderHomePage() error {
 | 
				
			|||||||
			homePagerNode := s.newHomeNode()
 | 
								homePagerNode := s.newHomeNode()
 | 
				
			||||||
			homePagerNode.paginator = pager
 | 
								homePagerNode.paginator = pager
 | 
				
			||||||
			if pager.TotalPages() > 0 {
 | 
								if pager.TotalPages() > 0 {
 | 
				
			||||||
				homePagerNode.Date = pager.Pages()[0].Date
 | 
									first, _ := pager.page(0)
 | 
				
			||||||
				homePagerNode.Lastmod = pager.Pages()[0].Lastmod
 | 
									homePagerNode.Date = first.Date
 | 
				
			||||||
 | 
									homePagerNode.Lastmod = first.Lastmod
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			pageNumber := i + 1
 | 
								pageNumber := i + 1
 | 
				
			||||||
			htmlBase := fmt.Sprintf("/%s/%d", paginatePath, pageNumber)
 | 
								htmlBase := fmt.Sprintf("/%s/%d", paginatePath, pageNumber)
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user