@@ -26,64 +26,111 @@ type Paginator struct {
26
26
TotalPages int `json:"total_pages"`
27
27
}
28
28
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 ) {
30
76
// return an empty div if there is only 1 page
31
- if pagination .TotalPages <= 1 {
77
+ if p .TotalPages <= 1 {
32
78
return New ("div" , Options {}), nil
33
79
}
34
80
35
81
path , class , wing := extractBaseOptions (opts )
36
82
opts ["class" ] = strings .Join ([]string {class , "pagination" }, " " )
83
+
37
84
t := New ("ul" , opts )
38
85
39
86
barLength := wing * 2 + 1
40
87
center := wing + 1
41
88
loopStart := 1
42
- loopEnd := pagination .TotalPages
89
+ loopEnd := p .TotalPages
43
90
44
- li , err := pagination .addPrev (opts , path )
91
+ li , err := p .addPrev (opts , path )
45
92
if err != nil {
46
93
return t , errors .WithStack (err )
47
94
}
48
95
t .Append (li )
49
96
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
54
101
loopEnd = loopStart + barLength - 5
55
- li , err := pageLI ("1" , 1 , path , pagination )
102
+ li , err := pageLI ("1" , 1 , path , p )
56
103
if err != nil {
57
104
return t , errors .WithStack (err )
58
105
}
59
106
t .Append (li )
60
107
t .Append (pageLIDummy ())
61
108
}
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
65
112
}
66
113
}
67
114
68
115
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 )
70
117
if err != nil {
71
118
return t , errors .WithStack (err )
72
119
}
73
120
t .Append (li )
74
121
}
75
122
76
- if pagination .TotalPages > loopEnd {
123
+ if p .TotalPages > loopEnd {
77
124
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 )
80
127
if err != nil {
81
128
return t , errors .WithStack (err )
82
129
}
83
130
t .Append (li )
84
131
}
85
132
86
- li , err = pagination .addNext (opts , path )
133
+ li , err = p .addNext (opts , path )
87
134
if err != nil {
88
135
return t , errors .WithStack (err )
89
136
}
@@ -92,7 +139,21 @@ func (pagination Paginator) Tag(opts Options) (*Tag, error) {
92
139
return t , nil
93
140
}
94
141
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 ) {
96
157
showPrev := true
97
158
98
159
if b , ok := opts ["showPrev" ].(bool ); ok {
@@ -104,17 +165,17 @@ func (pagination Paginator) addPrev(opts Options, path string) (*Tag, error) {
104
165
return nil , nil
105
166
}
106
167
107
- page := pagination .Page - 1
168
+ page := p .Page - 1
108
169
prevContent := "«"
109
170
110
171
if opts ["previousContent" ] != nil {
111
172
prevContent = opts ["previousContent" ].(string )
112
173
}
113
174
114
- return pageLI (prevContent , page , path , pagination )
175
+ return pageLI (prevContent , page , path , p )
115
176
}
116
177
117
- func (pagination Paginator ) addNext (opts Options , path string ) (* Tag , error ) {
178
+ func (p Paginator ) addNext (opts Options , path string ) (* Tag , error ) {
118
179
showNext := true
119
180
120
181
if b , ok := opts ["showNext" ].(bool ); ok {
@@ -126,14 +187,14 @@ func (pagination Paginator) addNext(opts Options, path string) (*Tag, error) {
126
187
return nil , nil
127
188
}
128
189
129
- page := pagination .Page + 1
190
+ page := p .Page + 1
130
191
nextContent := "»"
131
192
132
193
if opts ["nextContent" ] != nil {
133
194
nextContent = opts ["nextContent" ].(string )
134
195
}
135
196
136
- return pageLI (nextContent , page , path , pagination )
197
+ return pageLI (nextContent , page , path , p )
137
198
}
138
199
139
200
func extractBaseOptions (opts Options ) (string , string , int ) {
@@ -158,90 +219,55 @@ func extractBaseOptions(opts Options) (string, string, int) {
158
219
return path , class , wing
159
220
}
160
221
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 ) {
188
223
189
- if f , ok := s . FieldOk ( "Offset" ); ok {
190
- p . Offset = f . Value ().( int )
224
+ lio := Options {
225
+ "class" : "page-item" ,
191
226
}
192
227
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" }, " " )
195
230
}
196
231
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
199
240
}
200
241
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 )
203
245
}
204
246
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
+ }))
208
252
209
- return p . Tag ( opts )
253
+ return li , nil
210
254
}
211
255
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
225
260
}
226
261
227
- u , err := url .Parse (path )
228
262
q := u .Query ()
229
263
q .Set ("page" , strconv .Itoa (page ))
230
264
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
241
267
}
242
268
243
269
func pageLIDummy () * Tag {
244
- li := New ("li" , Options {"class" : "disabled" })
270
+ li := New ("li" , Options {"class" : "page-item disabled" })
245
271
a := New ("a" , Options {"body" : "..." })
246
272
li .Append (a )
247
273
return li
0 commit comments