Skip to content

Commit 1b65be1

Browse files
authored
Merge pull request #99 from gobuffalo/development
Development
2 parents 82cd769 + 2205842 commit 1b65be1

File tree

2 files changed

+121
-95
lines changed

2 files changed

+121
-95
lines changed

pagination.go

+113-87
Original file line numberDiff line numberDiff line change
@@ -26,64 +26,111 @@ type Paginator struct {
2626
TotalPages int `json:"total_pages"`
2727
}
2828

29-
func (pagination Paginator) Tag(opts Options) (*Tag, error) {
29+
//TagFromPagination receives a pagination interface{} and attempts to get
30+
//Paginator properties from it before generating the tag.
31+
func (p Paginator) TagFromPagination(pagination interface{}, opts Options) (*Tag, error) {
32+
rv := reflect.ValueOf(pagination)
33+
if rv.Kind() == reflect.Ptr {
34+
rv = rv.Elem()
35+
}
36+
37+
if rv.Kind() != reflect.Struct {
38+
return nil, errors.Errorf("can't build a Paginator from %T", pagination)
39+
}
40+
41+
s := structs.New(rv.Interface())
42+
43+
if f, ok := s.FieldOk("Page"); ok {
44+
p.Page = f.Value().(int)
45+
}
46+
47+
if f, ok := s.FieldOk("PerPage"); ok {
48+
p.PerPage = f.Value().(int)
49+
}
50+
51+
if f, ok := s.FieldOk("Offset"); ok {
52+
p.Offset = f.Value().(int)
53+
}
54+
55+
if f, ok := s.FieldOk("TotalEntriesSize"); ok {
56+
p.TotalEntriesSize = f.Value().(int)
57+
}
58+
59+
if f, ok := s.FieldOk("TotalEntriesSize"); ok {
60+
p.TotalEntriesSize = f.Value().(int)
61+
}
62+
63+
if f, ok := s.FieldOk("CurrentEntriesSize"); ok {
64+
p.CurrentEntriesSize = f.Value().(int)
65+
}
66+
67+
if f, ok := s.FieldOk("TotalPages"); ok {
68+
p.TotalPages = f.Value().(int)
69+
}
70+
71+
return p.Tag(opts)
72+
}
73+
74+
//Tag generates the pagination html Tag
75+
func (p Paginator) Tag(opts Options) (*Tag, error) {
3076
// return an empty div if there is only 1 page
31-
if pagination.TotalPages <= 1 {
77+
if p.TotalPages <= 1 {
3278
return New("div", Options{}), nil
3379
}
3480

3581
path, class, wing := extractBaseOptions(opts)
3682
opts["class"] = strings.Join([]string{class, "pagination"}, " ")
83+
3784
t := New("ul", opts)
3885

3986
barLength := wing*2 + 1
4087
center := wing + 1
4188
loopStart := 1
42-
loopEnd := pagination.TotalPages
89+
loopEnd := p.TotalPages
4390

44-
li, err := pagination.addPrev(opts, path)
91+
li, err := p.addPrev(opts, path)
4592
if err != nil {
4693
return t, errors.WithStack(err)
4794
}
4895
t.Append(li)
4996

50-
if pagination.TotalPages > barLength {
51-
loopEnd = barLength - 2 // range 1 ~ center
52-
if pagination.Page > center { /// range center
53-
loopStart = pagination.Page - wing + 2
97+
if p.TotalPages > barLength {
98+
loopEnd = barLength - 2 // range 1 ~ center
99+
if p.Page > center { /// range center
100+
loopStart = p.Page - wing + 2
54101
loopEnd = loopStart + barLength - 5
55-
li, err := pageLI("1", 1, path, pagination)
102+
li, err := pageLI("1", 1, path, p)
56103
if err != nil {
57104
return t, errors.WithStack(err)
58105
}
59106
t.Append(li)
60107
t.Append(pageLIDummy())
61108
}
62-
if pagination.Page > (pagination.TotalPages - wing - 1) {
63-
loopEnd = pagination.TotalPages
64-
loopStart = pagination.TotalPages - barLength + 3
109+
if p.Page > (p.TotalPages - wing - 1) {
110+
loopEnd = p.TotalPages
111+
loopStart = p.TotalPages - barLength + 3
65112
}
66113
}
67114

68115
for i := loopStart; i <= loopEnd; i++ {
69-
li, err := pageLI(strconv.Itoa(i), i, path, pagination)
116+
li, err := pageLI(strconv.Itoa(i), i, path, p)
70117
if err != nil {
71118
return t, errors.WithStack(err)
72119
}
73120
t.Append(li)
74121
}
75122

76-
if pagination.TotalPages > loopEnd {
123+
if p.TotalPages > loopEnd {
77124
t.Append(pageLIDummy())
78-
label := strconv.Itoa(pagination.TotalPages)
79-
li, err := pageLI(label, pagination.TotalPages, path, pagination)
125+
label := strconv.Itoa(p.TotalPages)
126+
li, err := pageLI(label, p.TotalPages, path, p)
80127
if err != nil {
81128
return t, errors.WithStack(err)
82129
}
83130
t.Append(li)
84131
}
85132

86-
li, err = pagination.addNext(opts, path)
133+
li, err = p.addNext(opts, path)
87134
if err != nil {
88135
return t, errors.WithStack(err)
89136
}
@@ -92,7 +139,21 @@ func (pagination Paginator) Tag(opts Options) (*Tag, error) {
92139
return t, nil
93140
}
94141

95-
func (pagination Paginator) addPrev(opts Options, path string) (*Tag, error) {
142+
//Pagination builds pagination Tag based on a passed pagintation interface
143+
func Pagination(pagination interface{}, opts Options) (*Tag, error) {
144+
if p, ok := pagination.(Paginator); ok {
145+
return p.Tag(opts)
146+
}
147+
148+
p := Paginator{
149+
Page: 1,
150+
PerPage: 20,
151+
}
152+
153+
return p.TagFromPagination(pagination, opts)
154+
}
155+
156+
func (p Paginator) addPrev(opts Options, path string) (*Tag, error) {
96157
showPrev := true
97158

98159
if b, ok := opts["showPrev"].(bool); ok {
@@ -104,17 +165,17 @@ func (pagination Paginator) addPrev(opts Options, path string) (*Tag, error) {
104165
return nil, nil
105166
}
106167

107-
page := pagination.Page - 1
168+
page := p.Page - 1
108169
prevContent := "&laquo;"
109170

110171
if opts["previousContent"] != nil {
111172
prevContent = opts["previousContent"].(string)
112173
}
113174

114-
return pageLI(prevContent, page, path, pagination)
175+
return pageLI(prevContent, page, path, p)
115176
}
116177

117-
func (pagination Paginator) addNext(opts Options, path string) (*Tag, error) {
178+
func (p Paginator) addNext(opts Options, path string) (*Tag, error) {
118179
showNext := true
119180

120181
if b, ok := opts["showNext"].(bool); ok {
@@ -126,14 +187,14 @@ func (pagination Paginator) addNext(opts Options, path string) (*Tag, error) {
126187
return nil, nil
127188
}
128189

129-
page := pagination.Page + 1
190+
page := p.Page + 1
130191
nextContent := "&raquo;"
131192

132193
if opts["nextContent"] != nil {
133194
nextContent = opts["nextContent"].(string)
134195
}
135196

136-
return pageLI(nextContent, page, path, pagination)
197+
return pageLI(nextContent, page, path, p)
137198
}
138199

139200
func extractBaseOptions(opts Options) (string, string, int) {
@@ -158,90 +219,55 @@ func extractBaseOptions(opts Options) (string, string, int) {
158219
return path, class, wing
159220
}
160221

161-
func Pagination(pagination interface{}, opts Options) (*Tag, error) {
162-
if p, ok := pagination.(Paginator); ok {
163-
return p.Tag(opts)
164-
}
165-
rv := reflect.ValueOf(pagination)
166-
if rv.Kind() == reflect.Ptr {
167-
rv = rv.Elem()
168-
}
169-
170-
if rv.Kind() != reflect.Struct {
171-
return nil, errors.Errorf("can't build a Paginator from %T", pagination)
172-
}
173-
174-
s := structs.New(rv.Interface())
175-
176-
p := Paginator{
177-
Page: 1,
178-
PerPage: 20,
179-
}
180-
181-
if f, ok := s.FieldOk("Page"); ok {
182-
p.Page = f.Value().(int)
183-
}
184-
185-
if f, ok := s.FieldOk("PerPage"); ok {
186-
p.PerPage = f.Value().(int)
187-
}
222+
func pageLI(text string, page int, path string, pagination Paginator) (*Tag, error) {
188223

189-
if f, ok := s.FieldOk("Offset"); ok {
190-
p.Offset = f.Value().(int)
224+
lio := Options{
225+
"class": "page-item",
191226
}
192227

193-
if f, ok := s.FieldOk("TotalEntriesSize"); ok {
194-
p.TotalEntriesSize = f.Value().(int)
228+
if page == pagination.Page {
229+
lio["class"] = strings.Join([]string{lio["class"].(string), "active"}, " ")
195230
}
196231

197-
if f, ok := s.FieldOk("TotalEntriesSize"); ok {
198-
p.TotalEntriesSize = f.Value().(int)
232+
li := New("li", lio)
233+
if page == 0 || page > pagination.TotalPages {
234+
li.Options["class"] = strings.Join([]string{lio["class"].(string), "disabled"}, " ")
235+
li.Append(New("span", Options{
236+
"body": text,
237+
"class": "page-link",
238+
}))
239+
return li, nil
199240
}
200241

201-
if f, ok := s.FieldOk("CurrentEntriesSize"); ok {
202-
p.CurrentEntriesSize = f.Value().(int)
242+
url, err := urlFor(path, page)
243+
if err != nil {
244+
return li, errors.WithStack(err)
203245
}
204246

205-
if f, ok := s.FieldOk("TotalPages"); ok {
206-
p.TotalPages = f.Value().(int)
207-
}
247+
li.Append(New("a", Options{
248+
"href": url,
249+
"class": "page-link",
250+
"body": text,
251+
}))
208252

209-
return p.Tag(opts)
253+
return li, nil
210254
}
211255

212-
func pageLI(text string, page int, path string, pagination Paginator) (*Tag, error) {
213-
214-
lio := Options{}
215-
if page == pagination.Page {
216-
lio["class"] = "active"
217-
}
218-
li := New("li", lio)
219-
if page == 0 || page > pagination.TotalPages {
220-
li.Options["class"] = "disabled"
221-
li.Append(New("span", Options{
222-
"body": text,
223-
}))
224-
return li, nil
256+
func urlFor(path string, page int) (string, error) {
257+
u, err := url.Parse(path)
258+
if err != nil {
259+
return "", err
225260
}
226261

227-
u, err := url.Parse(path)
228262
q := u.Query()
229263
q.Set("page", strconv.Itoa(page))
230264
u.RawQuery = q.Encode()
231-
ao := Options{
232-
"href": u.String(),
233-
}
234-
a := New("a", ao)
235-
a.Append(text)
236-
li.Append(a)
237-
if err != nil {
238-
return li, errors.WithStack(err)
239-
}
240-
return li, nil
265+
266+
return u.String(), err
241267
}
242268

243269
func pageLIDummy() *Tag {
244-
li := New("li", Options{"class": "disabled"})
270+
li := New("li", Options{"class": "page-item disabled"})
245271
a := New("a", Options{"body": "..."})
246272
li.Append(a)
247273
return li

pagination_test.go

+8-8
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ func Test_Pagination(t *testing.T) {
1818
})
1919
r.NoError(err)
2020

21-
r.Equal(template.HTML("<ul class=\" pagination\"><li><a href=\"/foo?page=1\">&laquo;</a></li><li><a href=\"/foo?page=1\">1</a></li><li class=\"active\"><a href=\"/foo?page=2\">2</a></li><li><a href=\"/foo?page=3\">3</a></li><li><a href=\"/foo?page=3\">&raquo;</a></li></ul>"), tag.HTML())
21+
r.Equal(template.HTML(`<ul class=" pagination"><li class="page-item"><a class="page-link" href="/foo?page=1">&laquo;</a></li><li class="page-item"><a class="page-link" href="/foo?page=1">1</a></li><li class="page-item active"><a class="page-link" href="/foo?page=2">2</a></li><li class="page-item"><a class="page-link" href="/foo?page=3">3</a></li><li class="page-item"><a class="page-link" href="/foo?page=3">&raquo;</a></li></ul>`), tag.HTML())
2222
}
2323

2424
func Test_Pagination_Page1(t *testing.T) {
@@ -32,7 +32,7 @@ func Test_Pagination_Page1(t *testing.T) {
3232
})
3333
r.NoError(err)
3434

35-
r.Equal(template.HTML("<ul class=\" pagination\"><li class=\"disabled\"><span>&laquo;</span></li><li class=\"active\"><a href=\"/foo?page=1\">1</a></li><li><a href=\"/foo?page=2\">2</a></li><li><a href=\"/foo?page=3\">3</a></li><li><a href=\"/foo?page=2\">&raquo;</a></li></ul>"), tag.HTML())
35+
r.Equal(template.HTML(`<ul class=" pagination"><li class="page-item disabled"><span class="page-link">&laquo;</span></li><li class="page-item active"><a class="page-link" href="/foo?page=1">1</a></li><li class="page-item"><a class="page-link" href="/foo?page=2">2</a></li><li class="page-item"><a class="page-link" href="/foo?page=3">3</a></li><li class="page-item"><a class="page-link" href="/foo?page=2">&raquo;</a></li></ul>`), tag.HTML())
3636
}
3737

3838
func Test_Pagination_Page3(t *testing.T) {
@@ -46,7 +46,7 @@ func Test_Pagination_Page3(t *testing.T) {
4646
})
4747
r.NoError(err)
4848

49-
r.Equal(template.HTML("<ul class=\" pagination\"><li><a href=\"/foo?page=2\">&laquo;</a></li><li><a href=\"/foo?page=1\">1</a></li><li><a href=\"/foo?page=2\">2</a></li><li class=\"active\"><a href=\"/foo?page=3\">3</a></li><li class=\"disabled\"><span>&raquo;</span></li></ul>"), tag.HTML())
49+
r.Equal(template.HTML(`<ul class=" pagination"><li class="page-item"><a class="page-link" href="/foo?page=2">&laquo;</a></li><li class="page-item"><a class="page-link" href="/foo?page=1">1</a></li><li class="page-item"><a class="page-link" href="/foo?page=2">2</a></li><li class="page-item active"><a class="page-link" href="/foo?page=3">3</a></li><li class="page-item disabled"><span class="page-link">&raquo;</span></li></ul>`), tag.HTML())
5050
}
5151

5252
func Test_Pagination_LongPageStart(t *testing.T) {
@@ -60,7 +60,7 @@ func Test_Pagination_LongPageStart(t *testing.T) {
6060
})
6161
r.NoError(err)
6262

63-
r.Equal(template.HTML(`<ul class=" pagination"><li class="disabled"><span>&laquo;</span></li><li class="active"><a href="/foo?page=1">1</a></li><li><a href="/foo?page=2">2</a></li><li><a href="/foo?page=3">3</a></li><li><a href="/foo?page=4">4</a></li><li><a href="/foo?page=5">5</a></li><li><a href="/foo?page=6">6</a></li><li><a href="/foo?page=7">7</a></li><li><a href="/foo?page=8">8</a></li><li><a href="/foo?page=9">9</a></li><li class="disabled"><a>...</a></li><li><a href="/foo?page=29">29</a></li><li><a href="/foo?page=2">&raquo;</a></li></ul>`), tag.HTML())
63+
r.Equal(template.HTML(`<ul class=" pagination"><li class="page-item disabled"><span class="page-link">&laquo;</span></li><li class="page-item active"><a class="page-link" href="/foo?page=1">1</a></li><li class="page-item"><a class="page-link" href="/foo?page=2">2</a></li><li class="page-item"><a class="page-link" href="/foo?page=3">3</a></li><li class="page-item"><a class="page-link" href="/foo?page=4">4</a></li><li class="page-item"><a class="page-link" href="/foo?page=5">5</a></li><li class="page-item"><a class="page-link" href="/foo?page=6">6</a></li><li class="page-item"><a class="page-link" href="/foo?page=7">7</a></li><li class="page-item"><a class="page-link" href="/foo?page=8">8</a></li><li class="page-item"><a class="page-link" href="/foo?page=9">9</a></li><li class="page-item disabled"><a>...</a></li><li class="page-item"><a class="page-link" href="/foo?page=29">29</a></li><li class="page-item"><a class="page-link" href="/foo?page=2">&raquo;</a></li></ul>`), tag.HTML())
6464
}
6565

6666
func Test_Pagination_LongPageStartPoint1(t *testing.T) {
@@ -74,7 +74,7 @@ func Test_Pagination_LongPageStartPoint1(t *testing.T) {
7474
})
7575
r.NoError(err)
7676

77-
r.Equal(template.HTML(`<ul class=" pagination"><li><a href="/foo?page=5">&laquo;</a></li><li><a href="/foo?page=1">1</a></li><li><a href="/foo?page=2">2</a></li><li><a href="/foo?page=3">3</a></li><li><a href="/foo?page=4">4</a></li><li><a href="/foo?page=5">5</a></li><li class="active"><a href="/foo?page=6">6</a></li><li><a href="/foo?page=7">7</a></li><li><a href="/foo?page=8">8</a></li><li><a href="/foo?page=9">9</a></li><li class="disabled"><a>...</a></li><li><a href="/foo?page=29">29</a></li><li><a href="/foo?page=7">&raquo;</a></li></ul>`), tag.HTML())
77+
r.Equal(template.HTML(`<ul class=" pagination"><li class="page-item"><a class="page-link" href="/foo?page=5">&laquo;</a></li><li class="page-item"><a class="page-link" href="/foo?page=1">1</a></li><li class="page-item"><a class="page-link" href="/foo?page=2">2</a></li><li class="page-item"><a class="page-link" href="/foo?page=3">3</a></li><li class="page-item"><a class="page-link" href="/foo?page=4">4</a></li><li class="page-item"><a class="page-link" href="/foo?page=5">5</a></li><li class="page-item active"><a class="page-link" href="/foo?page=6">6</a></li><li class="page-item"><a class="page-link" href="/foo?page=7">7</a></li><li class="page-item"><a class="page-link" href="/foo?page=8">8</a></li><li class="page-item"><a class="page-link" href="/foo?page=9">9</a></li><li class="page-item disabled"><a>...</a></li><li class="page-item"><a class="page-link" href="/foo?page=29">29</a></li><li class="page-item"><a class="page-link" href="/foo?page=7">&raquo;</a></li></ul>`), tag.HTML())
7878
}
7979

8080
func Test_Pagination_LongPagePoint2(t *testing.T) {
@@ -88,7 +88,7 @@ func Test_Pagination_LongPagePoint2(t *testing.T) {
8888
})
8989
r.NoError(err)
9090

91-
r.Equal(template.HTML(`<ul class=" pagination"><li><a href="/foo?page=22">&laquo;</a></li><li><a href="/foo?page=1">1</a></li><li class="disabled"><a>...</a></li><li><a href="/foo?page=20">20</a></li><li><a href="/foo?page=21">21</a></li><li><a href="/foo?page=22">22</a></li><li class="active"><a href="/foo?page=23">23</a></li><li><a href="/foo?page=24">24</a></li><li><a href="/foo?page=25">25</a></li><li><a href="/foo?page=26">26</a></li><li class="disabled"><a>...</a></li><li><a href="/foo?page=29">29</a></li><li><a href="/foo?page=24">&raquo;</a></li></ul>`), tag.HTML())
91+
r.Equal(template.HTML(`<ul class=" pagination"><li class="page-item"><a class="page-link" href="/foo?page=22">&laquo;</a></li><li class="page-item"><a class="page-link" href="/foo?page=1">1</a></li><li class="page-item disabled"><a>...</a></li><li class="page-item"><a class="page-link" href="/foo?page=20">20</a></li><li class="page-item"><a class="page-link" href="/foo?page=21">21</a></li><li class="page-item"><a class="page-link" href="/foo?page=22">22</a></li><li class="page-item active"><a class="page-link" href="/foo?page=23">23</a></li><li class="page-item"><a class="page-link" href="/foo?page=24">24</a></li><li class="page-item"><a class="page-link" href="/foo?page=25">25</a></li><li class="page-item"><a class="page-link" href="/foo?page=26">26</a></li><li class="page-item disabled"><a>...</a></li><li class="page-item"><a class="page-link" href="/foo?page=29">29</a></li><li class="page-item"><a class="page-link" href="/foo?page=24">&raquo;</a></li></ul>`), tag.HTML())
9292
}
9393

9494
func Test_Pagination_LongPageEnd(t *testing.T) {
@@ -102,7 +102,7 @@ func Test_Pagination_LongPageEnd(t *testing.T) {
102102
})
103103
r.NoError(err)
104104

105-
r.Equal(template.HTML(`<ul class=" pagination"><li><a href="/foo?page=23">&laquo;</a></li><li><a href="/foo?page=1">1</a></li><li class="disabled"><a>...</a></li><li><a href="/foo?page=21">21</a></li><li><a href="/foo?page=22">22</a></li><li><a href="/foo?page=23">23</a></li><li class="active"><a href="/foo?page=24">24</a></li><li><a href="/foo?page=25">25</a></li><li><a href="/foo?page=26">26</a></li><li><a href="/foo?page=27">27</a></li><li><a href="/foo?page=28">28</a></li><li><a href="/foo?page=29">29</a></li><li><a href="/foo?page=25">&raquo;</a></li></ul>`), tag.HTML())
105+
r.Equal(template.HTML(`<ul class=" pagination"><li class="page-item"><a class="page-link" href="/foo?page=23">&laquo;</a></li><li class="page-item"><a class="page-link" href="/foo?page=1">1</a></li><li class="page-item disabled"><a>...</a></li><li class="page-item"><a class="page-link" href="/foo?page=21">21</a></li><li class="page-item"><a class="page-link" href="/foo?page=22">22</a></li><li class="page-item"><a class="page-link" href="/foo?page=23">23</a></li><li class="page-item active"><a class="page-link" href="/foo?page=24">24</a></li><li class="page-item"><a class="page-link" href="/foo?page=25">25</a></li><li class="page-item"><a class="page-link" href="/foo?page=26">26</a></li><li class="page-item"><a class="page-link" href="/foo?page=27">27</a></li><li class="page-item"><a class="page-link" href="/foo?page=28">28</a></li><li class="page-item"><a class="page-link" href="/foo?page=29">29</a></li><li class="page-item"><a class="page-link" href="/foo?page=25">&raquo;</a></li></ul>`), tag.HTML())
106106
}
107107

108108
func Test_Pagination_NextPrevContent(t *testing.T) {
@@ -118,5 +118,5 @@ func Test_Pagination_NextPrevContent(t *testing.T) {
118118
})
119119
r.NoError(err)
120120

121-
r.Equal(template.HTML(`<ul class=" pagination" nextContent="Next" previousContent="Previous"><li><a href="/foo?page=1">Previous</a></li><li><a href="/foo?page=1">1</a></li><li class="active"><a href="/foo?page=2">2</a></li><li><a href="/foo?page=3">3</a></li><li><a href="/foo?page=3">Next</a></li></ul>`), tag.HTML())
121+
r.Equal(template.HTML(`<ul class=" pagination" nextContent="Next" previousContent="Previous"><li class="page-item"><a class="page-link" href="/foo?page=1">Previous</a></li><li class="page-item"><a class="page-link" href="/foo?page=1">1</a></li><li class="page-item active"><a class="page-link" href="/foo?page=2">2</a></li><li class="page-item"><a class="page-link" href="/foo?page=3">3</a></li><li class="page-item"><a class="page-link" href="/foo?page=3">Next</a></li></ul>`), tag.HTML())
122122
}

0 commit comments

Comments
 (0)