github.com/astaxie/beego@v1.12.3/utils/pagination/paginator.go (about) 1 // Copyright 2014 beego Author. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package pagination 16 17 import ( 18 "math" 19 "net/http" 20 "net/url" 21 "strconv" 22 ) 23 24 // Paginator within the state of a http request. 25 type Paginator struct { 26 Request *http.Request 27 PerPageNums int 28 MaxPages int 29 30 nums int64 31 pageRange []int 32 pageNums int 33 page int 34 } 35 36 // PageNums Returns the total number of pages. 37 func (p *Paginator) PageNums() int { 38 if p.pageNums != 0 { 39 return p.pageNums 40 } 41 pageNums := math.Ceil(float64(p.nums) / float64(p.PerPageNums)) 42 if p.MaxPages > 0 { 43 pageNums = math.Min(pageNums, float64(p.MaxPages)) 44 } 45 p.pageNums = int(pageNums) 46 return p.pageNums 47 } 48 49 // Nums Returns the total number of items (e.g. from doing SQL count). 50 func (p *Paginator) Nums() int64 { 51 return p.nums 52 } 53 54 // SetNums Sets the total number of items. 55 func (p *Paginator) SetNums(nums interface{}) { 56 p.nums, _ = toInt64(nums) 57 } 58 59 // Page Returns the current page. 60 func (p *Paginator) Page() int { 61 if p.page != 0 { 62 return p.page 63 } 64 if p.Request.Form == nil { 65 p.Request.ParseForm() 66 } 67 p.page, _ = strconv.Atoi(p.Request.Form.Get("p")) 68 if p.page > p.PageNums() { 69 p.page = p.PageNums() 70 } 71 if p.page <= 0 { 72 p.page = 1 73 } 74 return p.page 75 } 76 77 // Pages Returns a list of all pages. 78 // 79 // Usage (in a view template): 80 // 81 // {{range $index, $page := .paginator.Pages}} 82 // <li{{if $.paginator.IsActive .}} class="active"{{end}}> 83 // <a href="{{$.paginator.PageLink $page}}">{{$page}}</a> 84 // </li> 85 // {{end}} 86 func (p *Paginator) Pages() []int { 87 if p.pageRange == nil && p.nums > 0 { 88 var pages []int 89 pageNums := p.PageNums() 90 page := p.Page() 91 switch { 92 case page >= pageNums-4 && pageNums > 9: 93 start := pageNums - 9 + 1 94 pages = make([]int, 9) 95 for i := range pages { 96 pages[i] = start + i 97 } 98 case page >= 5 && pageNums > 9: 99 start := page - 5 + 1 100 pages = make([]int, int(math.Min(9, float64(page+4+1)))) 101 for i := range pages { 102 pages[i] = start + i 103 } 104 default: 105 pages = make([]int, int(math.Min(9, float64(pageNums)))) 106 for i := range pages { 107 pages[i] = i + 1 108 } 109 } 110 p.pageRange = pages 111 } 112 return p.pageRange 113 } 114 115 // PageLink Returns URL for a given page index. 116 func (p *Paginator) PageLink(page int) string { 117 link, _ := url.ParseRequestURI(p.Request.URL.String()) 118 values := link.Query() 119 if page == 1 { 120 values.Del("p") 121 } else { 122 values.Set("p", strconv.Itoa(page)) 123 } 124 link.RawQuery = values.Encode() 125 return link.String() 126 } 127 128 // PageLinkPrev Returns URL to the previous page. 129 func (p *Paginator) PageLinkPrev() (link string) { 130 if p.HasPrev() { 131 link = p.PageLink(p.Page() - 1) 132 } 133 return 134 } 135 136 // PageLinkNext Returns URL to the next page. 137 func (p *Paginator) PageLinkNext() (link string) { 138 if p.HasNext() { 139 link = p.PageLink(p.Page() + 1) 140 } 141 return 142 } 143 144 // PageLinkFirst Returns URL to the first page. 145 func (p *Paginator) PageLinkFirst() (link string) { 146 return p.PageLink(1) 147 } 148 149 // PageLinkLast Returns URL to the last page. 150 func (p *Paginator) PageLinkLast() (link string) { 151 return p.PageLink(p.PageNums()) 152 } 153 154 // HasPrev Returns true if the current page has a predecessor. 155 func (p *Paginator) HasPrev() bool { 156 return p.Page() > 1 157 } 158 159 // HasNext Returns true if the current page has a successor. 160 func (p *Paginator) HasNext() bool { 161 return p.Page() < p.PageNums() 162 } 163 164 // IsActive Returns true if the given page index points to the current page. 165 func (p *Paginator) IsActive(page int) bool { 166 return p.Page() == page 167 } 168 169 // Offset Returns the current offset. 170 func (p *Paginator) Offset() int { 171 return (p.Page() - 1) * p.PerPageNums 172 } 173 174 // HasPages Returns true if there is more than one page. 175 func (p *Paginator) HasPages() bool { 176 return p.PageNums() > 1 177 } 178 179 // NewPaginator Instantiates a paginator struct for the current http request. 180 func NewPaginator(req *http.Request, per int, nums interface{}) *Paginator { 181 p := Paginator{} 182 p.Request = req 183 if per <= 0 { 184 per = 10 185 } 186 p.PerPageNums = per 187 p.SetNums(nums) 188 return &p 189 }