// Copyright 2014 beego Author. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package pagination import ( "math" "net/http" "net/url" "strconv" ) // Paginator within the state of a http request. type Paginator struct { Request *http.Request PerPageNums int MaxPages int nums int64 pageRange []int pageNums int page int } // PageNums Returns the total number of pages. func (p *Paginator) PageNums() int { if p.pageNums != 0 { return p.pageNums } pageNums := math.Ceil(float64(p.nums) / float64(p.PerPageNums)) if p.MaxPages > 0 { pageNums = math.Min(pageNums, float64(p.MaxPages)) } p.pageNums = int(pageNums) return p.pageNums } // Nums Returns the total number of items (e.g. from doing SQL count). func (p *Paginator) Nums() int64 { return p.nums } // SetNums Sets the total number of items. func (p *Paginator) SetNums(nums interface{}) { p.nums, _ = toInt64(nums) } // Page Returns the current page. func (p *Paginator) Page() int { if p.page != 0 { return p.page } if p.Request.Form == nil { p.Request.ParseForm() } p.page, _ = strconv.Atoi(p.Request.Form.Get("p")) if p.page > p.PageNums() { p.page = p.PageNums() } if p.page <= 0 { p.page = 1 } return p.page } // Pages Returns a list of all pages. // // Usage (in a view template): // // {{range $index, $page := .paginator.Pages}} // // {{$page}} // // {{end}} func (p *Paginator) Pages() []int { if p.pageRange == nil && p.nums > 0 { var pages []int pageNums := p.PageNums() page := p.Page() switch { case page >= pageNums-4 && pageNums > 9: start := pageNums - 9 + 1 pages = make([]int, 9) for i := range pages { pages[i] = start + i } case page >= 5 && pageNums > 9: start := page - 5 + 1 pages = make([]int, int(math.Min(9, float64(page+4+1)))) for i := range pages { pages[i] = start + i } default: pages = make([]int, int(math.Min(9, float64(pageNums)))) for i := range pages { pages[i] = i + 1 } } p.pageRange = pages } return p.pageRange } // PageLink Returns URL for a given page index. func (p *Paginator) PageLink(page int) string { link, _ := url.ParseRequestURI(p.Request.URL.String()) values := link.Query() if page == 1 { values.Del("p") } else { values.Set("p", strconv.Itoa(page)) } link.RawQuery = values.Encode() return link.String() } // PageLinkPrev Returns URL to the previous page. func (p *Paginator) PageLinkPrev() (link string) { if p.HasPrev() { link = p.PageLink(p.Page() - 1) } return } // PageLinkNext Returns URL to the next page. func (p *Paginator) PageLinkNext() (link string) { if p.HasNext() { link = p.PageLink(p.Page() + 1) } return } // PageLinkFirst Returns URL to the first page. func (p *Paginator) PageLinkFirst() (link string) { return p.PageLink(1) } // PageLinkLast Returns URL to the last page. func (p *Paginator) PageLinkLast() (link string) { return p.PageLink(p.PageNums()) } // HasPrev Returns true if the current page has a predecessor. func (p *Paginator) HasPrev() bool { return p.Page() > 1 } // HasNext Returns true if the current page has a successor. func (p *Paginator) HasNext() bool { return p.Page() < p.PageNums() } // IsActive Returns true if the given page index points to the current page. func (p *Paginator) IsActive(page int) bool { return p.Page() == page } // Offset Returns the current offset. func (p *Paginator) Offset() int { return (p.Page() - 1) * p.PerPageNums } // HasPages Returns true if there is more than one page. func (p *Paginator) HasPages() bool { return p.PageNums() > 1 } // NewPaginator Instantiates a paginator struct for the current http request. func NewPaginator(req *http.Request, per int, nums interface{}) *Paginator { p := Paginator{} p.Request = req if per <= 0 { per = 10 } p.PerPageNums = per p.SetNums(nums) return &p }