UNPKG

11.9 kBJavaScriptView Raw
1import { ChangeDetectorRef, Component, ElementRef, EventEmitter, forwardRef, Input, Output, TemplateRef } from '@angular/core';
2import { NG_VALUE_ACCESSOR } from '@angular/forms';
3import { PaginationConfig } from './pagination.config';
4export const PAGINATION_CONTROL_VALUE_ACCESSOR = {
5 provide: NG_VALUE_ACCESSOR,
6 useExisting: forwardRef(() => PaginationComponent),
7 multi: true
8};
9export class PaginationComponent {
10 constructor(elementRef, paginationConfig, changeDetection) {
11 this.elementRef = elementRef;
12 this.changeDetection = changeDetection;
13 /** if `true` aligns each link to the sides of pager */
14 this.align = true;
15 /** if false first and last buttons will be hidden */
16 this.boundaryLinks = false;
17 /** if false previous and next buttons will be hidden */
18 this.directionLinks = true;
19 // labels
20 /** first button text */
21 this.firstText = 'First';
22 /** previous button text */
23 this.previousText = 'Previous';
24 /** next button text */
25 this.nextText = 'Next';
26 /** last button text */
27 this.lastText = 'Last';
28 /** if true current page will in the middle of pages list */
29 this.rotate = true;
30 // css
31 /** add class to <code><li\></code> */
32 this.pageBtnClass = '';
33 /** if true pagination component will be disabled */
34 this.disabled = false;
35 /** fired when total pages count changes, $event:number equals to total pages count */
36 this.numPages = new EventEmitter();
37 /** fired when page was changed, $event:{page, itemsPerPage} equals to object
38 * with current page index and number of items per page
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 /** maximum number of items per page. If value less than 1 will display all items on one page */
55 get itemsPerPage() {
56 return this._itemsPerPage;
57 }
58 set itemsPerPage(v) {
59 this._itemsPerPage = v;
60 this.totalPages = this.calculateTotalPages();
61 }
62 /** total number of items in all pages */
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 // watch for maxSize
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 // base class
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 // this class
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 // eslint-disable-next-line @typescript-eslint/no-explicit-any
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 // eslint-disable-next-line @typescript-eslint/no-explicit-any
155 const target = event.target;
156 target.blur();
157 }
158 this.writeValue(page);
159 this.onChange(this.page);
160 }
161 }
162 // Create page object used in template
163 makePage(num, text, active) {
164 return { text, number: num, active };
165 }
166 getPages(currentPage, totalPages) {
167 const pages = [];
168 // Default page limits
169 let startPage = 1;
170 let endPage = totalPages;
171 const isMaxSized = typeof this.maxSize !== 'undefined' && this.maxSize < totalPages;
172 // recompute if maxSize
173 if (isMaxSized && this.maxSize) {
174 if (this.rotate) {
175 // Current page is displayed in the middle of the visible ones
176 startPage = Math.max(currentPage - Math.floor(this.maxSize / 2), 1);
177 endPage = startPage + this.maxSize - 1;
178 // Adjust if limit is exceeded
179 if (endPage > totalPages) {
180 endPage = totalPages;
181 startPage = endPage - this.maxSize + 1;
182 }
183 }
184 else {
185 // Visible pages are paginated with maxSize
186 startPage =
187 (Math.ceil(currentPage / this.maxSize) - 1) * this.maxSize + 1;
188 // Adjust last page if limit is exceeded
189 endPage = Math.min(startPage + this.maxSize - 1, totalPages);
190 }
191 }
192 // Add page number links
193 for (let num = startPage; num <= endPage; num++) {
194 const page = this.makePage(num, num.toString(), num === currentPage);
195 pages.push(page);
196 }
197 // Add links to move between page sets
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 // base class
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}
218PaginationComponent.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];
225PaginationComponent.ctorParameters = () => [
226 { type: ElementRef },
227 { type: PaginationConfig },
228 { type: ChangeDetectorRef }
229];
230PaginationComponent.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//# sourceMappingURL=pagination.component.js.map
\No newline at end of file