github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/Unknwon/paginater/paginater.go (about) 1 // Copyright 2015 Unknwon 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"): you may 4 // not use this file except in compliance with the License. You may obtain 5 // 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, WITHOUT 11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 // License for the specific language governing permissions and limitations 13 // under the License. 14 15 // Package paginater is a helper module for custom pagination calculation. 16 package paginater 17 18 // Paginater represents a set of results of pagination calculations. 19 type Paginater struct { 20 total int 21 pagingNum int 22 current int 23 numPages int 24 } 25 26 // New initialize a new pagination calculation and returns a Paginater as result. 27 func New(total, pagingNum, current, numPages int) *Paginater { 28 if pagingNum <= 0 { 29 pagingNum = 1 30 } 31 if current <= 0 { 32 current = 1 33 } 34 p := &Paginater{total, pagingNum, current, numPages} 35 if p.current > p.TotalPages() { 36 p.current = p.TotalPages() 37 } 38 return p 39 } 40 41 // IsFirst returns true if current page is the first page. 42 func (p *Paginater) IsFirst() bool { 43 return p.current == 1 44 } 45 46 // HasPrevious returns true if there is a previous page relative to current page. 47 func (p *Paginater) HasPrevious() bool { 48 return p.current > 1 49 } 50 51 func (p *Paginater) Previous() int { 52 if !p.HasPrevious() { 53 return p.current 54 } 55 return p.current - 1 56 } 57 58 // HasNext returns true if there is a next page relative to current page. 59 func (p *Paginater) HasNext() bool { 60 return p.total > p.current*p.pagingNum 61 } 62 63 func (p *Paginater) Next() int { 64 if !p.HasNext() { 65 return p.current 66 } 67 return p.current + 1 68 } 69 70 // IsLast returns true if current page is the last page. 71 func (p *Paginater) IsLast() bool { 72 if p.total == 0 { 73 return true 74 } 75 return p.total > (p.current-1)*p.pagingNum && !p.HasNext() 76 } 77 78 // Total returns number of total rows. 79 func (p *Paginater) Total() int { 80 return p.total 81 } 82 83 // TotalPage returns number of total pages. 84 func (p *Paginater) TotalPages() int { 85 if p.total == 0 { 86 return 1 87 } 88 if p.total%p.pagingNum == 0 { 89 return p.total / p.pagingNum 90 } 91 return p.total/p.pagingNum + 1 92 } 93 94 // Current returns current page number. 95 func (p *Paginater) Current() int { 96 return p.current 97 } 98 99 // Page presents a page in the paginater. 100 type Page struct { 101 num int 102 isCurrent bool 103 } 104 105 func (p *Page) Num() int { 106 return p.num 107 } 108 109 func (p *Page) IsCurrent() bool { 110 return p.isCurrent 111 } 112 113 func getMiddleIdx(numPages int) int { 114 if numPages%2 == 0 { 115 return numPages / 2 116 } 117 return numPages/2 + 1 118 } 119 120 // Pages returns a list of nearby page numbers relative to current page. 121 // If value is -1 means "..." that more pages are not showing. 122 func (p *Paginater) Pages() []*Page { 123 if p.numPages == 0 { 124 return []*Page{} 125 } else if p.numPages == 1 && p.TotalPages() == 1 { 126 // Only show current page. 127 return []*Page{{1, true}} 128 } 129 130 // Total page number is less or equal. 131 if p.TotalPages() <= p.numPages { 132 pages := make([]*Page, p.TotalPages()) 133 for i := range pages { 134 pages[i] = &Page{i + 1, i+1 == p.current} 135 } 136 return pages 137 } 138 139 numPages := p.numPages 140 maxIdx := numPages - 1 141 offsetIdx := 0 142 hasMoreNext := false 143 144 // Check more previous and next pages. 145 previousNum := getMiddleIdx(p.numPages) - 1 146 if previousNum > p.current-1 { 147 previousNum -= previousNum - (p.current - 1) 148 } 149 nextNum := p.numPages - previousNum - 1 150 if p.current+nextNum > p.TotalPages() { 151 delta := nextNum - (p.TotalPages() - p.current) 152 nextNum -= delta 153 previousNum += delta 154 } 155 156 offsetVal := p.current - previousNum 157 if offsetVal > 1 { 158 numPages++ 159 maxIdx++ 160 offsetIdx = 1 161 } 162 163 if p.current+nextNum < p.TotalPages() { 164 numPages++ 165 hasMoreNext = true 166 } 167 168 pages := make([]*Page, numPages) 169 170 // There are more previous pages. 171 if offsetIdx == 1 { 172 pages[0] = &Page{-1, false} 173 } 174 // There are more next pages. 175 if hasMoreNext { 176 pages[len(pages)-1] = &Page{-1, false} 177 } 178 179 // Check previous pages. 180 for i := 0; i < previousNum; i++ { 181 pages[offsetIdx+i] = &Page{i + offsetVal, false} 182 } 183 184 pages[offsetIdx+previousNum] = &Page{p.current, true} 185 186 // Check next pages. 187 for i := 1; i <= nextNum; i++ { 188 pages[offsetIdx+previousNum+i] = &Page{p.current + i, false} 189 } 190 191 return pages 192 }