1 | import { ChangeDetectorRef, Component, ElementRef, EventEmitter, forwardRef, Input, Output, TemplateRef } from '@angular/core';
|
2 | import { NG_VALUE_ACCESSOR } from '@angular/forms';
|
3 | import { PaginationConfig } from './pagination.config';
|
4 | export const PAGINATION_CONTROL_VALUE_ACCESSOR = {
|
5 | provide: NG_VALUE_ACCESSOR,
|
6 | useExisting: forwardRef(() => PaginationComponent),
|
7 | multi: true
|
8 | };
|
9 | export class PaginationComponent {
|
10 | constructor(elementRef, paginationConfig, changeDetection) {
|
11 | this.elementRef = elementRef;
|
12 | this.changeDetection = changeDetection;
|
13 |
|
14 | this.align = true;
|
15 |
|
16 | this.boundaryLinks = false;
|
17 |
|
18 | this.directionLinks = true;
|
19 |
|
20 |
|
21 | this.firstText = 'First';
|
22 |
|
23 | this.previousText = 'Previous';
|
24 |
|
25 | this.nextText = 'Next';
|
26 |
|
27 | this.lastText = 'Last';
|
28 |
|
29 | this.rotate = true;
|
30 |
|
31 |
|
32 | this.pageBtnClass = '';
|
33 |
|
34 | this.disabled = false;
|
35 |
|
36 | this.numPages = new EventEmitter();
|
37 | |
38 |
|
39 |
|
40 | this.pageChanged = new EventEmitter();
|
41 | this.onChange = Function.prototype;
|
42 | this.onTouched = Function.prototype;
|
43 | this.classMap = '';
|
44 | this.inited = false;
|
45 | this._itemsPerPage = 10;
|
46 | this._totalItems = 0;
|
47 | this._totalPages = 0;
|
48 | this._page = 1;
|
49 | this.elementRef = elementRef;
|
50 | if (!this.config) {
|
51 | this.configureOptions(paginationConfig.main);
|
52 | }
|
53 | }
|
54 |
|
55 | get itemsPerPage() {
|
56 | return this._itemsPerPage;
|
57 | }
|
58 | set itemsPerPage(v) {
|
59 | this._itemsPerPage = v;
|
60 | this.totalPages = this.calculateTotalPages();
|
61 | }
|
62 |
|
63 | get totalItems() {
|
64 | return this._totalItems;
|
65 | }
|
66 | set totalItems(v) {
|
67 | this._totalItems = v;
|
68 | this.totalPages = this.calculateTotalPages();
|
69 | }
|
70 | get totalPages() {
|
71 | return this._totalPages;
|
72 | }
|
73 | set totalPages(v) {
|
74 | this._totalPages = v;
|
75 | this.numPages.emit(v);
|
76 | if (this.inited) {
|
77 | this.selectPage(this.page);
|
78 | }
|
79 | }
|
80 | get page() {
|
81 | return this._page;
|
82 | }
|
83 | set page(value) {
|
84 | const _previous = this._page;
|
85 | this._page = value > this.totalPages ? this.totalPages : value || 1;
|
86 | this.changeDetection.markForCheck();
|
87 | if (_previous === this._page || typeof _previous === 'undefined') {
|
88 | return;
|
89 | }
|
90 | this.pageChanged.emit({
|
91 | page: this._page,
|
92 | itemsPerPage: this.itemsPerPage
|
93 | });
|
94 | }
|
95 | configureOptions(config) {
|
96 | this.config = Object.assign({}, config);
|
97 | }
|
98 | ngOnInit() {
|
99 | var _a, _b, _c, _d, _e, _f;
|
100 | if (typeof window !== 'undefined') {
|
101 | this.classMap = this.elementRef.nativeElement.getAttribute('class') || '';
|
102 | }
|
103 |
|
104 | if (typeof this.maxSize === 'undefined') {
|
105 | this.maxSize = ((_a = this.config) === null || _a === void 0 ? void 0 : _a.maxSize) || 0;
|
106 | }
|
107 | if (typeof this.rotate === 'undefined') {
|
108 | this.rotate = !!((_b = this.config) === null || _b === void 0 ? void 0 : _b.rotate);
|
109 | }
|
110 | if (typeof this.boundaryLinks === 'undefined') {
|
111 | this.boundaryLinks = !!((_c = this.config) === null || _c === void 0 ? void 0 : _c.boundaryLinks);
|
112 | }
|
113 | if (typeof this.directionLinks === 'undefined') {
|
114 | this.directionLinks = !!((_d = this.config) === null || _d === void 0 ? void 0 : _d.directionLinks);
|
115 | }
|
116 | if (typeof this.pageBtnClass === 'undefined') {
|
117 | this.pageBtnClass = ((_e = this.config) === null || _e === void 0 ? void 0 : _e.pageBtnClass) || '';
|
118 | }
|
119 |
|
120 | if (typeof this.itemsPerPage === 'undefined') {
|
121 | this.itemsPerPage = ((_f = this.config) === null || _f === void 0 ? void 0 : _f.itemsPerPage) || 0;
|
122 | }
|
123 | this.totalPages = this.calculateTotalPages();
|
124 |
|
125 | this.pages = this.getPages(this.page, this.totalPages);
|
126 | this.inited = true;
|
127 | }
|
128 | writeValue(value) {
|
129 | this.page = value;
|
130 | this.pages = this.getPages(this.page, this.totalPages);
|
131 | }
|
132 | getText(key) {
|
133 |
|
134 | return this[`${key}Text`] || this.config[`${key}Text`];
|
135 | }
|
136 | noPrevious() {
|
137 | return this.page === 1;
|
138 | }
|
139 | noNext() {
|
140 | return this.page === this.totalPages;
|
141 | }
|
142 | registerOnChange(fn) {
|
143 | this.onChange = fn;
|
144 | }
|
145 | registerOnTouched(fn) {
|
146 | this.onTouched = fn;
|
147 | }
|
148 | selectPage(page, event) {
|
149 | if (event) {
|
150 | event.preventDefault();
|
151 | }
|
152 | if (!this.disabled) {
|
153 | if (event && event.target) {
|
154 |
|
155 | const target = event.target;
|
156 | target.blur();
|
157 | }
|
158 | this.writeValue(page);
|
159 | this.onChange(this.page);
|
160 | }
|
161 | }
|
162 |
|
163 | makePage(num, text, active) {
|
164 | return { text, number: num, active };
|
165 | }
|
166 | getPages(currentPage, totalPages) {
|
167 | const pages = [];
|
168 |
|
169 | let startPage = 1;
|
170 | let endPage = totalPages;
|
171 | const isMaxSized = typeof this.maxSize !== 'undefined' && this.maxSize < totalPages;
|
172 |
|
173 | if (isMaxSized && this.maxSize) {
|
174 | if (this.rotate) {
|
175 |
|
176 | startPage = Math.max(currentPage - Math.floor(this.maxSize / 2), 1);
|
177 | endPage = startPage + this.maxSize - 1;
|
178 |
|
179 | if (endPage > totalPages) {
|
180 | endPage = totalPages;
|
181 | startPage = endPage - this.maxSize + 1;
|
182 | }
|
183 | }
|
184 | else {
|
185 |
|
186 | startPage =
|
187 | (Math.ceil(currentPage / this.maxSize) - 1) * this.maxSize + 1;
|
188 |
|
189 | endPage = Math.min(startPage + this.maxSize - 1, totalPages);
|
190 | }
|
191 | }
|
192 |
|
193 | for (let num = startPage; num <= endPage; num++) {
|
194 | const page = this.makePage(num, num.toString(), num === currentPage);
|
195 | pages.push(page);
|
196 | }
|
197 |
|
198 | if (isMaxSized && !this.rotate) {
|
199 | if (startPage > 1) {
|
200 | const previousPageSet = this.makePage(startPage - 1, '...', false);
|
201 | pages.unshift(previousPageSet);
|
202 | }
|
203 | if (endPage < totalPages) {
|
204 | const nextPageSet = this.makePage(endPage + 1, '...', false);
|
205 | pages.push(nextPageSet);
|
206 | }
|
207 | }
|
208 | return pages;
|
209 | }
|
210 |
|
211 | calculateTotalPages() {
|
212 | const totalPages = this.itemsPerPage < 1
|
213 | ? 1
|
214 | : Math.ceil(this.totalItems / this.itemsPerPage);
|
215 | return Math.max(totalPages || 0, 1);
|
216 | }
|
217 | }
|
218 | PaginationComponent.decorators = [
|
219 | { type: Component, args: [{
|
220 | selector: 'pagination',
|
221 | template: "<ul class=\"pagination\" [ngClass]=\"classMap\">\n <li class=\"pagination-first page-item\"\n *ngIf=\"boundaryLinks\"\n [class.disabled]=\"noPrevious() || disabled\">\n <a class=\"page-link\" href (click)=\"selectPage(1, $event)\">\n <ng-container [ngTemplateOutlet]=\"customFirstTemplate || defaultFirstTemplate\"\n [ngTemplateOutletContext]=\"{disabled: noPrevious() || disabled, currentPage: page}\">\n </ng-container>\n </a>\n </li>\n\n <li class=\"pagination-prev page-item\"\n *ngIf=\"directionLinks\"\n [class.disabled]=\"noPrevious() || disabled\">\n <a class=\"page-link\" href (click)=\"selectPage(page - 1, $event)\">\n <ng-container [ngTemplateOutlet]=\"customPreviousTemplate || defaultPreviousTemplate\"\n [ngTemplateOutletContext]=\"{disabled: noPrevious() || disabled, currentPage: page}\">\n </ng-container>\n </a>\n </li>\n\n <li *ngFor=\"let pg of pages\"\n [class.active]=\"pg.active\"\n [class.disabled]=\"disabled && !pg.active\"\n class=\"pagination-page page-item\">\n <a class=\"page-link\" href (click)=\"selectPage(pg.number, $event)\">\n <ng-container [ngTemplateOutlet]=\"customPageTemplate || defaultPageTemplate\"\n [ngTemplateOutletContext]=\"{disabled: disabled, $implicit: pg, currentPage: page}\">\n </ng-container>\n </a>\n </li>\n\n <li class=\"pagination-next page-item\"\n *ngIf=\"directionLinks\"\n [class.disabled]=\"noNext() || disabled\">\n <a class=\"page-link\" href (click)=\"selectPage(page + 1, $event)\">\n <ng-container [ngTemplateOutlet]=\"customNextTemplate || defaultNextTemplate\"\n [ngTemplateOutletContext]=\"{disabled: noNext() || disabled, currentPage: page}\">\n </ng-container>\n </a>\n </li>\n\n <li class=\"pagination-last page-item\"\n *ngIf=\"boundaryLinks\"\n [class.disabled]=\"noNext() || disabled\">\n <a class=\"page-link\" href (click)=\"selectPage(totalPages, $event)\">\n <ng-container [ngTemplateOutlet]=\"customLastTemplate || defaultLastTemplate\"\n [ngTemplateOutletContext]=\"{disabled: noNext() || disabled, currentPage: page}\">\n </ng-container>\n </a>\n </li>\n</ul>\n\n<ng-template #defaultPageTemplate let-page>{{ page.text }}</ng-template>\n\n<ng-template #defaultNextTemplate>{{ getText('next') }}</ng-template>\n\n<ng-template #defaultPreviousTemplate>{{ getText('previous') }}</ng-template>\n\n<ng-template #defaultFirstTemplate>{{ getText('first') }}</ng-template>\n\n<ng-template #defaultLastTemplate>{{ getText('last') }}</ng-template>\n",
|
222 | providers: [PAGINATION_CONTROL_VALUE_ACCESSOR]
|
223 | },] }
|
224 | ];
|
225 | PaginationComponent.ctorParameters = () => [
|
226 | { type: ElementRef },
|
227 | { type: PaginationConfig },
|
228 | { type: ChangeDetectorRef }
|
229 | ];
|
230 | PaginationComponent.propDecorators = {
|
231 | align: [{ type: Input }],
|
232 | maxSize: [{ type: Input }],
|
233 | boundaryLinks: [{ type: Input }],
|
234 | directionLinks: [{ type: Input }],
|
235 | firstText: [{ type: Input }],
|
236 | previousText: [{ type: Input }],
|
237 | nextText: [{ type: Input }],
|
238 | lastText: [{ type: Input }],
|
239 | rotate: [{ type: Input }],
|
240 | pageBtnClass: [{ type: Input }],
|
241 | disabled: [{ type: Input }],
|
242 | customPageTemplate: [{ type: Input }],
|
243 | customNextTemplate: [{ type: Input }],
|
244 | customPreviousTemplate: [{ type: Input }],
|
245 | customFirstTemplate: [{ type: Input }],
|
246 | customLastTemplate: [{ type: Input }],
|
247 | numPages: [{ type: Output }],
|
248 | pageChanged: [{ type: Output }],
|
249 | itemsPerPage: [{ type: Input }],
|
250 | totalItems: [{ type: Input }]
|
251 | };
|
252 |
|
\ | No newline at end of file |