alfresco-ng2-components/lib/core/pagination/pagination.component.ts
Denys Vuika 6f968f7e4a
[AAE-5637] Remove SCSS mixins and use CSS variables (#7250)
* remove default-class mixin and use regular import

* cleanup colors

* remove variables file, fix bugs in animations

* proper ordering of imports, core css vars

* cleanup snackbar and material themes

* tags component

* login component styles

* app login

* toolbar component styles

* breadcrumb styles

* dropdown breadcrumb

* app layout component

* demo shell: files component

* aspect list styles

* content metadata styles

* node selector

* name location cell

* node share dialog

* content type dialog

* folder dialog

* document list

* datatable theme

* pagination theme

* viewer theme

* viewer theme

* user-info theme

* container widget

* dynamic table theme

* form widgets

* form theme

* form renderer

* sidebar menu

* header theme

* info drawer theme

* comment list

* commens and layout container

* sidenav layout

* empty content

* error content

* clipboard theme

* search input

* tooltip card and notification history

* card view theme

* remove unused keys

* add permission dialog

* search and permission dialogs

* version comparison and column themes

* upload drag area and cleanup references

* remove the need for content styles

* insight components

* cleanup insights theme

* process components

* process components

* process cloud themes

* cleanup unsed imports

* cleanup mixins

* update build scripts

* test fixes

* remove fdescribe

* css fixes

* update unit tests
2021-09-29 13:17:05 +01:00

315 lines
8.9 KiB
TypeScript

/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* 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.
*/
import { Component, EventEmitter, Input, OnInit, Output, ViewEncapsulation, OnDestroy, ElementRef, ChangeDetectionStrategy, ChangeDetectorRef, Renderer2 } from '@angular/core';
import { PaginatedComponent } from './paginated-component.interface';
import { PaginationComponentInterface } from './pagination-component.interface';
import { Subject } from 'rxjs';
import { PaginationModel } from '../models/pagination.model';
import { UserPreferencesService, UserPreferenceValues } from '../services/user-preferences.service';
import { takeUntil } from 'rxjs/operators';
import { TranslateService } from '@ngx-translate/core';
export type PaginationAction =
| 'NEXT_PAGE'
| 'PREV_PAGE'
| 'CHANGE_PAGE_SIZE'
| 'CHANGE_PAGE_NUMBER';
@Component({
selector: 'adf-pagination',
host: { 'class': 'adf-pagination' },
templateUrl: './pagination.component.html',
styleUrls: ['./pagination.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
encapsulation: ViewEncapsulation.None
})
export class PaginationComponent implements OnInit, OnDestroy, PaginationComponentInterface {
static DEFAULT_PAGINATION: PaginationModel = {
skipCount: 0,
maxItems: 25,
totalItems: 0,
count: 0,
hasMoreItems: false
};
private _pagination: PaginationModel;
private _isEmpty = true;
private _hasItems = false;
/** Component that provides custom pagination support. */
@Input()
target: PaginatedComponent;
/** An array of page sizes. */
@Input()
supportedPageSizes: number[];
get pagination(): PaginationModel {
return this._pagination;
}
/** Pagination object. */
@Input()
set pagination(value: PaginationModel) {
value = value || PaginationComponent.DEFAULT_PAGINATION;
this._pagination = value;
this._hasItems = value && value.count > 0;
this._isEmpty = !this.hasItems;
// TODO: Angular 10 workaround for HostBinding bug
if (this._isEmpty) {
this.renderer.addClass(this.elementRef.nativeElement, 'adf-pagination__empty');
} else {
this.renderer.removeClass(this.elementRef.nativeElement, 'adf-pagination__empty');
}
this.cdr.detectChanges();
}
/** Emitted when pagination changes in any way. */
@Output()
change = new EventEmitter<PaginationModel>();
/** Emitted when the page number changes. */
@Output()
changePageNumber = new EventEmitter<PaginationModel>();
/** Emitted when the page size changes. */
@Output()
changePageSize = new EventEmitter<PaginationModel>();
/** Emitted when the next page is requested. */
@Output()
nextPage = new EventEmitter<PaginationModel>();
/** Emitted when the previous page is requested. */
@Output()
prevPage = new EventEmitter<PaginationModel>();
private onDestroy$ = new Subject<boolean>();
constructor(
private elementRef: ElementRef,
private renderer: Renderer2,
private cdr: ChangeDetectorRef,
private userPreferencesService: UserPreferencesService,
private translate: TranslateService) {
}
ngOnInit() {
this.userPreferencesService
.select(UserPreferenceValues.PaginationSize)
.pipe(takeUntil(this.onDestroy$))
.subscribe(maxItems => {
this.pagination = {
...PaginationComponent.DEFAULT_PAGINATION,
...this.pagination,
maxItems
};
});
if (!this.supportedPageSizes) {
this.supportedPageSizes = this.userPreferencesService.supportedPageSizes;
}
if (this.target) {
this.target.pagination
.pipe(takeUntil(this.onDestroy$))
.subscribe(pagination => {
if (pagination.count === 0 && !this.isFirstPage) {
this.goPrevious();
}
this.pagination = {
...pagination
};
});
}
if (!this.pagination) {
this.pagination = {
...PaginationComponent.DEFAULT_PAGINATION
};
}
}
get lastPage(): number {
const { maxItems, totalItems } = this.pagination;
return (totalItems && maxItems)
? Math.ceil(totalItems / maxItems)
: 1;
}
get current(): number {
const { maxItems, skipCount } = this.pagination;
return (skipCount && maxItems)
? Math.floor(skipCount / maxItems) + 1
: 1;
}
get isLastPage(): boolean {
if (!this.pagination.totalItems && this.pagination.hasMoreItems) {
return false;
}
return this.current === this.lastPage;
}
get isFirstPage(): boolean {
return this.current === 1;
}
get next(): number {
return this.isLastPage ? this.current : this.current + 1;
}
get previous(): number {
return this.isFirstPage ? 1 : this.current - 1;
}
get hasItems(): boolean {
return this._hasItems;
}
// TODO: not working correctly in Angular 10
// @HostBinding('class.adf-pagination__empty')
get isEmpty(): boolean {
return this._isEmpty;
}
get range(): number[] {
const { skipCount, maxItems, totalItems } = this.pagination;
let start = 0;
if (totalItems || totalItems !== 0) {
start = skipCount + 1;
}
const end = this.isLastPage ? totalItems : skipCount + maxItems;
return [start, end];
}
get pages(): number[] {
return Array(this.lastPage)
.fill('n')
.map((_, index) => (index + 1));
}
get itemRangeText(): string {
const rangeString = this.range.join('-');
let translation = this.translate.instant('CORE.PAGINATION.ITEMS_RANGE', {
range: rangeString,
total: this.pagination.totalItems
});
if (!this.pagination.totalItems) {
translation = translation.substr(0, translation.indexOf(rangeString) + rangeString.length);
}
return translation;
}
goNext() {
if (this.hasItems) {
const maxItems = this.pagination.maxItems;
const skipCount = (this.next - 1) * maxItems;
this.pagination = {
...this.pagination,
skipCount
};
this.handlePaginationEvent('NEXT_PAGE');
}
}
goPrevious() {
if (this.hasItems) {
const maxItems = this.pagination.maxItems;
const skipCount = (this.previous - 1) * maxItems;
this.pagination = {
...this.pagination,
skipCount
};
this.handlePaginationEvent('PREV_PAGE');
}
}
onChangePageNumber(pageNumber: number) {
if (this.hasItems) {
const maxItems = this.pagination.maxItems;
const skipCount = (pageNumber - 1) * maxItems;
this.pagination = {
...this.pagination,
skipCount
};
this.handlePaginationEvent('CHANGE_PAGE_NUMBER');
}
}
onChangePageSize(maxItems: number) {
this.pagination = {
...this.pagination,
skipCount: 0,
maxItems
};
this.userPreferencesService.paginationSize = maxItems;
this.handlePaginationEvent('CHANGE_PAGE_SIZE');
}
ngOnDestroy() {
this.onDestroy$.next(true);
this.onDestroy$.complete();
}
handlePaginationEvent(action: PaginationAction) {
const paginationModel = { ...this.pagination };
if (action === 'NEXT_PAGE') {
this.nextPage.emit(paginationModel);
}
if (action === 'PREV_PAGE') {
this.prevPage.emit(paginationModel);
}
if (action === 'CHANGE_PAGE_NUMBER') {
this.changePageNumber.emit(paginationModel);
}
if (action === 'CHANGE_PAGE_SIZE') {
this.changePageSize.emit(paginationModel);
}
this.change.emit(paginationModel);
if (this.target) {
this.target.updatePagination(paginationModel);
}
}
}