|
12 | 12 | </a> |
13 | 13 | </li> |
14 | 14 | <template v-if="!isEmpty"> |
15 | | - <li class="page-item" v-if="showLeftDot" @click.prevent="pageHandler(1)"> |
| 15 | + <li class="page-item" v-if="start > 3" @click.prevent="pageHandler(1)"> |
16 | 16 | <a class="page-link" href=""> 1 </a> |
17 | 17 | </li> |
18 | | - <li class="page-item disabled" v-if="showLeftDot"> |
19 | | - <a class="page-link" href="">...</a> |
| 18 | + <li class="page-item disabled" v-if="start > 3"> |
| 19 | + <a class="page-link" href="">…</a> |
20 | 20 | </li> |
21 | 21 | <li class="page-item" v-for="index in range" :key="index" v-bind:class="{ active: (index == page)}" @click.prevent="pageHandler(index)"> |
22 | 22 | <a class="page-link" href="">{{index}}</a> |
23 | 23 | </li> |
24 | | - <li class="page-item disabled" v-if="showRightDot"> |
25 | | - <a class="page-link" href="">...</a> |
| 24 | + <li class="page-item disabled" v-if="end < totalPages - 2"> |
| 25 | + <a class="page-link" href="">…</a> |
26 | 26 | </li> |
27 | | - <li class="page-item" v-if="showRightDot" @click.prevent="pageHandler(totalPages)"> |
| 27 | + <li class="page-item" v-if="end < totalPages - 2" @click.prevent="pageHandler(totalPages)"> |
28 | 28 | <a class="page-link" href=""> {{totalPages}} </a> |
29 | 29 | </li> |
30 | 30 | </template> |
31 | 31 |
|
32 | 32 | <template v-else> |
33 | 33 | <li class="page-item disabled"> |
34 | | - <a class="page-link" href="">...</a> |
| 34 | + <a class="page-link" href="">…</a> |
35 | 35 | </li> |
36 | 36 | </template> |
37 | 37 | <li :class="{'disabled' : disableNextButton}" class="page-item" @click.prevent="pageHandler(page+1)"> |
|
58 | 58 | <!-- Number of rows per page ends here --> |
59 | 59 |
|
60 | 60 | <div class="input-group col-sm-2"> |
61 | | - <input type="number" class="form-control" :min="start" :max="totalPages" placeholder="Go to page" @keyup.enter="gotoPage" v-model.number="go_to_page"> |
| 61 | + <input type="number" class="form-control" min="1" step="1" :max="totalPages" placeholder="Go to page" @keyup.enter="gotoPage" v-model.number="go_to_page"> |
62 | 62 | </div> |
63 | 63 | </ul> |
64 | 64 | </nav> |
|
103 | 103 | } |
104 | 104 | }, |
105 | 105 | mounted() { |
106 | | - this.end = (this.page + (this.paginationLimit - 1)); |
| 106 | + this.calculatePageRange(true); |
107 | 107 | }, |
108 | 108 | methods: { |
109 | 109 | gotoPage() { |
110 | | - if (this.go_to_page === "") { |
| 110 | + if (this.go_to_page === "" || !this.isPositiveInteger(this.go_to_page)) { |
111 | 111 | return; |
112 | 112 | } |
113 | | - let go_to_page = this.go_to_page; |
114 | | - if (go_to_page >= 1 && go_to_page <= this.totalPages) { |
115 | | - this.pageHandler(go_to_page) |
116 | | - if (!includes(this.range,go_to_page)) { |
117 | | - if (this.totalPages - go_to_page < this.num_of_visibile_pagination_buttons) { |
118 | | - this.end = this.totalPages; |
119 | | - this.start = this.end - (this.num_of_visibile_pagination_buttons-1);; |
120 | | - } else { |
121 | | - this.start = go_to_page; |
122 | | - this.end = go_to_page + (this.num_of_visibile_pagination_buttons-1); |
123 | | - } |
124 | | - } |
125 | | -
|
126 | | - } else { |
127 | | - console.log("invalid page number"); |
128 | | - } |
| 113 | +
|
| 114 | + //Handle the new page |
| 115 | + this.pageHandler(this.go_to_page) |
129 | 116 | }, |
130 | 117 | pageHandler(index) { |
131 | 118 | if (index >= 1 && index <= this.totalPages) { |
|
135 | 122 | perPageHandler(option) { |
136 | 123 | this.$emit('update:per_page', option); |
137 | 124 | }, |
| 125 | + calculatePageRange(force = false) { |
| 126 | + //Skip calculating if all pages can be shown |
| 127 | + if (this.totalPages <= this.num_of_visibile_pagination_buttons) { |
| 128 | + this.start = 1; |
| 129 | + this.end = this.totalPages; |
| 130 | + return; |
| 131 | + } |
| 132 | +
|
| 133 | + //Skip recalculating if the previous and next pages are already visible |
| 134 | + if (!force && |
| 135 | + (includes(this.range, this.page - 1) || this.page == 1) && |
| 136 | + (includes(this.range, this.page + 1) || this.page == this.totalPages) |
| 137 | + ) { return; } |
| 138 | +
|
| 139 | + //Current page is the start page minus one |
| 140 | + this.start = (this.page == 1) ? 1 : this.page - 1; |
| 141 | +
|
| 142 | + //Reserved entries: firstpage, ellipsis (2x), prev. page, last page, current page |
| 143 | + this.end = this.start + this.num_of_visibile_pagination_buttons - 5; |
| 144 | +
|
| 145 | + //If the user navigates on page one or two, we set start to one (ellipsis pointless) |
| 146 | + //and can potentially shift up end |
| 147 | + if (this.start <= 3) { |
| 148 | + this.end += 3 - this.start; |
| 149 | + this.start = 1; |
| 150 | + } |
| 151 | +
|
| 152 | + //If the user navigates on the last two pages or out of bounds, we can shift down start |
| 153 | + //This will also handle end overflow, substract 2 for ellipsis and last page |
| 154 | + if (this.end >= this.totalPages - 2) { |
| 155 | + this.start -= this.end - (this.totalPages - 2); |
| 156 | + this.end = this.totalPages; |
| 157 | + } |
| 158 | +
|
| 159 | + //Handle start underflow |
| 160 | + this.start = Math.max(this.start, 1); |
| 161 | + }, |
| 162 | + isPositiveInteger(str) { |
| 163 | + return /^\+?(0|[1-9]\d*)$/.test(str); |
| 164 | + } |
138 | 165 | }, |
139 | 166 | components: { |
140 | 167 | }, |
141 | 168 | computed: { |
142 | | - showLeftDot() { |
143 | | - return !(includes(this.range, 1)); |
144 | | - }, |
145 | | - showRightDot() { |
146 | | - return !(this.totalPages - this.end <= 0); |
147 | | - }, |
148 | 169 | totalPages() { |
149 | 170 | return Math.ceil(this.total / this.per_page); |
150 | 171 | }, |
|
155 | 176 | return this.page == this.end; |
156 | 177 | }, |
157 | 178 | range() { |
158 | | - return range(this.start, (this.end + 1)); |
159 | | - }, |
160 | | - paginationLimit() { |
161 | | - if (this.totalPages < this.num_of_visibile_pagination_buttons) { |
162 | | - return this.totalPages; |
163 | | - } else { |
164 | | - return this.num_of_visibile_pagination_buttons; |
165 | | - } |
| 179 | + return range(this.start, this.end + 1); |
166 | 180 | }, |
167 | 181 | isEmpty() { |
168 | 182 | return this.total == 0; |
|
171 | 185 | }, |
172 | 186 | watch: { |
173 | 187 | page(newVal, oldVal) { |
174 | | - if (newVal == this.totalPages) { |
175 | | - this.start = newVal - (this.paginationLimit - 1); |
176 | | - this.end = newVal; |
177 | | - } else if (newVal == 1) { |
178 | | - this.start = newVal; |
179 | | - this.end = newVal + (this.paginationLimit - 1); |
180 | | - } else { |
181 | | - if (newVal > oldVal) { |
182 | | - if (this.end - newVal < 1) { |
183 | | - this.start += 1; |
184 | | - this.end += 1; |
185 | | - } |
186 | | - } else { |
187 | | - if (this.start - newVal >= 0) { |
188 | | - this.start -= 1; |
189 | | - this.end -= 1; |
190 | | - } |
191 | | - } |
192 | | -
|
193 | | - } |
| 188 | + this.calculatePageRange(); |
194 | 189 | }, |
195 | 190 | rowCount(newVal, oldVal) { |
196 | | - if (this.page == this.totalPages) { |
197 | | - this.start = this.page - (this.paginationLimit - 1); |
198 | | - this.end = this.page; |
199 | | - } else if (this.page == 1) { |
200 | | - this.start = this.page; |
201 | | - this.end = this.page + (this.paginationLimit - 1); |
202 | | - } |
| 191 | + this.calculatePageRange(); |
203 | 192 | }, |
204 | 193 | totalPages(newVal, oldVal) { |
205 | | - if (this.page == this.totalPages) { |
206 | | - this.start = this.page - (this.paginationLimit - 1); |
207 | | - this.end = this.page; |
208 | | - } else if (this.page == 1) { |
209 | | - this.start = this.page; |
210 | | - this.end = this.page + (this.paginationLimit - 1); |
211 | | - } |
| 194 | + this.calculatePageRange(); |
212 | 195 | }, |
213 | 196 | } |
214 | 197 | } |
|
0 commit comments