/
pagination.go
141 lines (127 loc) · 4.09 KB
/
pagination.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
package utils
import (
"fmt"
"net/url"
"sort"
"strconv"
)
type (
//PaginationConfig - represents configuration Options used by the PaginationInfo Build method
PaginationConfig struct {
ShowFirstPage bool `inject:"config:commerce.pagination.showFirstPage"`
ShowLastPage bool `inject:"config:commerce.pagination.showLastPage"`
//ShowAroundActivePageAmount - amount of pages to show before and after the current page (so a value of2 would show 2 pages before and 2 pages after)
ShowAroundActivePageAmount float64 `inject:"config:commerce.pagination.showAroundActivePageAmount"`
NameSpace string
}
// CurrentResultInfos page information
CurrentResultInfos struct {
ActivePage int
TotalHits int
PageSize int
LastPage int
}
// PaginationInfo meta information
PaginationInfo struct {
NextPage *Page
PreviousPage *Page
TotalHits int
PageNavigation []Page
}
// Page page data
Page struct {
Page int
URL string
IsActive bool
IsSpacer bool
}
// PaginationInfoFactory - used to build a configuration based on configured defaults
PaginationInfoFactory struct {
DefaultConfig *PaginationConfig `inject:""`
}
)
//BuildWith builds a paginationInfo based on the given infos and config
func BuildWith(currentResult CurrentResultInfos, paginationConfig PaginationConfig, urlBase *url.URL) PaginationInfo {
if currentResult.PageSize < 1 {
currentResult.PageSize = 1
}
if currentResult.ActivePage < 1 {
currentResult.ActivePage = 1
}
paginationInfo := PaginationInfo{
TotalHits: currentResult.TotalHits,
}
var pagesToAdd []int
if paginationConfig.ShowFirstPage {
pagesToAdd = append(pagesToAdd, 1)
}
if paginationConfig.ShowLastPage {
pagesToAdd = append(pagesToAdd, currentResult.LastPage)
}
if currentResult.ActivePage > 1 {
paginationInfo.PreviousPage = &Page{
Page: currentResult.ActivePage - 1,
URL: makeURL(urlBase, currentResult.ActivePage-1, paginationConfig.NameSpace),
}
}
if currentResult.ActivePage < currentResult.LastPage {
paginationInfo.NextPage = &Page{
Page: currentResult.ActivePage + 1,
URL: makeURL(urlBase, currentResult.ActivePage+1, paginationConfig.NameSpace),
}
}
pagesToAdd = append(pagesToAdd, currentResult.ActivePage)
showAroundActivePageAmount := int(paginationConfig.ShowAroundActivePageAmount)
for i := currentResult.ActivePage - showAroundActivePageAmount; i <= currentResult.ActivePage+showAroundActivePageAmount; i++ {
if i > 0 && i < currentResult.LastPage {
pagesToAdd = append(pagesToAdd, i)
}
}
if currentResult.ActivePage == 1 && currentResult.LastPage > currentResult.ActivePage+2 {
pagesToAdd = append(pagesToAdd, currentResult.ActivePage+2)
}
if currentResult.ActivePage == currentResult.LastPage && currentResult.LastPage > 2 {
pagesToAdd = append(pagesToAdd, currentResult.ActivePage-2)
}
sort.Ints(pagesToAdd)
previousPageNr := 0
for _, pageNr := range pagesToAdd {
//guard same pages / deduplication
if previousPageNr == pageNr {
continue
}
// add spacer if not subsequent pages
if pageNr > previousPageNr+1 {
paginationInfo.PageNavigation = append(paginationInfo.PageNavigation, Page{
IsSpacer: true,
})
}
page := Page{
Page: pageNr,
IsActive: pageNr == currentResult.ActivePage,
IsSpacer: false,
URL: makeURL(urlBase, pageNr, paginationConfig.NameSpace),
}
paginationInfo.PageNavigation = append(paginationInfo.PageNavigation, page)
previousPageNr = pageNr
}
return paginationInfo
}
//Build Pagination with the default configuration
func (f *PaginationInfoFactory) Build(activePage int, totalHits int, pageSize int, lastPage int, urlBase *url.URL) PaginationInfo {
return BuildWith(CurrentResultInfos{
ActivePage: activePage,
TotalHits: totalHits,
PageSize: pageSize,
LastPage: lastPage,
}, *f.DefaultConfig, urlBase)
}
func makeURL(base *url.URL, page int, namespace string) string {
q := base.Query()
parameterName := "page"
if namespace != "" {
parameterName = fmt.Sprintf("%v.%v", namespace, "page")
}
q.Set(parameterName, strconv.Itoa(page))
return (&url.URL{RawQuery: q.Encode()}).String()
}