mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 01:54:15 +00:00

Copied over isNumeric from RxJs 6.x as it was removed from 7.x Build & tests are broken, fixed in subsequent commit
242 lines
10 KiB
TypeScript
242 lines
10 KiB
TypeScript
import { Injectable } from '@angular/core';
|
|
import { Router } from '@angular/router';
|
|
import { RouteService } from '../services/route.service';
|
|
import { PaginationComponentOptions } from '../../shared/pagination/pagination-component-options.model';
|
|
import { combineLatest as observableCombineLatest, Observable } from 'rxjs';
|
|
import { filter, map, take } from 'rxjs/operators';
|
|
import { SortDirection, SortOptions } from '../cache/models/sort-options.model';
|
|
import { hasValue, isEmpty, isNotEmpty } from '../../shared/empty.util';
|
|
import { difference } from '../../shared/object.util';
|
|
import { FindListOptions } from '../data/find-list-options.model';
|
|
import { isNumeric } from '../../shared/numeric.util';
|
|
|
|
@Injectable({
|
|
providedIn: 'root',
|
|
})
|
|
/**
|
|
* Service to manage the pagination of different components
|
|
* The pagination information will be stored in the route based on a paginationID.
|
|
* The following params are used for the different kind of pagination information:
|
|
* - For the page: {paginationID}.p
|
|
* - For the page size: {paginationID}.rpp
|
|
* - For the sort direction: {paginationID}.sd
|
|
* - For the sort field: {paginationID}.sf
|
|
*/
|
|
export class PaginationService {
|
|
|
|
private defaultSortOptions = new SortOptions('id', SortDirection.ASC);
|
|
|
|
private clearParams = {};
|
|
|
|
constructor(protected routeService: RouteService,
|
|
protected router: Router
|
|
) {
|
|
}
|
|
|
|
/**
|
|
* Method to retrieve the current pagination settings for an ID based on the router params and default options
|
|
* @param paginationId - The id to check the pagination for
|
|
* @param defaultPagination - The default pagination values to be used when no route info is present
|
|
* @returns {Observable<PaginationComponentOptions>} Retrieves the current pagination settings based on the router params
|
|
*/
|
|
getCurrentPagination(paginationId: string, defaultPagination: PaginationComponentOptions): Observable<PaginationComponentOptions> {
|
|
const page$ = this.routeService.getQueryParameterValue(`${paginationId}.page`);
|
|
const size$ = this.routeService.getQueryParameterValue(`${paginationId}.rpp`);
|
|
return observableCombineLatest([page$, size$]).pipe(
|
|
map(([page, size]) => {
|
|
return Object.assign(new PaginationComponentOptions(), defaultPagination, {
|
|
currentPage: this.convertToNumeric(page, defaultPagination.currentPage),
|
|
pageSize: this.getBestMatchPageSize(size, defaultPagination)
|
|
});
|
|
})
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Method to retrieve the current sort options for an ID based on the router params and default options
|
|
* @param paginationId - The id to check the sort options for
|
|
* @param defaultSort - The default sort options to be used when no route info is present
|
|
* @param ignoreDefault - Indicate whether the default should be ignored
|
|
* @returns {Observable<SortOptions>} Retrieves the current sort options based on the router params
|
|
*/
|
|
getCurrentSort(paginationId: string, defaultSort: SortOptions, ignoreDefault?: boolean): Observable<SortOptions> {
|
|
if (!ignoreDefault && (isEmpty(defaultSort) || !hasValue(defaultSort))) {
|
|
defaultSort = this.defaultSortOptions;
|
|
}
|
|
const sortDirection$ = this.routeService.getQueryParameterValue(`${paginationId}.sd`);
|
|
const sortField$ = this.routeService.getQueryParameterValue(`${paginationId}.sf`);
|
|
return observableCombineLatest([sortDirection$, sortField$]).pipe(map(([sortDirection, sortField]) => {
|
|
const field = sortField || defaultSort?.field;
|
|
const direction = SortDirection[sortDirection] || defaultSort?.direction;
|
|
return new SortOptions(field, direction);
|
|
})
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Method to retrieve the current find list options for an ID based on the router params and default options
|
|
* @param paginationId - The id to check the find list options for
|
|
* @param defaultFindList - The default find list options to be used when no route info is present
|
|
* @param ignoreDefault - Indicate whether the default should be ignored
|
|
* @returns {Observable<FindListOptions>} Retrieves the current find list options based on the router params
|
|
*/
|
|
getFindListOptions(paginationId: string, defaultFindList: FindListOptions, ignoreDefault?: boolean): Observable<FindListOptions> {
|
|
const paginationComponentOptions = new PaginationComponentOptions();
|
|
paginationComponentOptions.currentPage = defaultFindList.currentPage;
|
|
paginationComponentOptions.pageSize = defaultFindList.elementsPerPage;
|
|
const currentPagination$ = this.getCurrentPagination(paginationId, paginationComponentOptions);
|
|
const currentSortOptions$ = this.getCurrentSort(paginationId, defaultFindList.sort, ignoreDefault);
|
|
|
|
return observableCombineLatest([currentPagination$, currentSortOptions$]).pipe(
|
|
filter(([currentPagination, currentSortOptions]) => hasValue(currentPagination) && hasValue(currentSortOptions)),
|
|
map(([currentPagination, currentSortOptions]) => {
|
|
return Object.assign(new FindListOptions(), defaultFindList, {
|
|
sort: currentSortOptions,
|
|
currentPage: currentPagination.currentPage,
|
|
elementsPerPage: currentPagination.pageSize
|
|
});
|
|
}));
|
|
}
|
|
|
|
/**
|
|
* Reset the current page for the provided pagination ID to 1.
|
|
* @param paginationId - The pagination id for which to reset the page
|
|
*/
|
|
resetPage(paginationId: string) {
|
|
this.updateRoute(paginationId, {page: 1});
|
|
}
|
|
|
|
|
|
/**
|
|
* Update the route with the provided information
|
|
* @param paginationId - The pagination ID for which to update the route with info
|
|
* @param params - The page related params to update in the route
|
|
* @param extraParams - Addition params unrelated to the pagination that need to be added to the route
|
|
* @param retainScrollPosition - Scroll to the pagination component after updating the route instead of the top of the page
|
|
*/
|
|
updateRoute(paginationId: string, params: {
|
|
page?: number
|
|
pageSize?: number
|
|
sortField?: string
|
|
sortDirection?: SortDirection
|
|
}, extraParams?, retainScrollPosition?: boolean) {
|
|
|
|
this.updateRouteWithUrl(paginationId, [], params, extraParams, retainScrollPosition);
|
|
}
|
|
|
|
/**
|
|
* Update the route with the provided information
|
|
* @param paginationId - The pagination ID for which to update the route with info
|
|
* @param url - The url to navigate to
|
|
* @param params - The page related params to update in the route
|
|
* @param extraParams - Addition params unrelated to the pagination that need to be added to the route
|
|
* @param retainScrollPosition - Scroll to the pagination component after updating the route instead of the top of the page
|
|
*/
|
|
updateRouteWithUrl(paginationId: string, url: string[], params: {
|
|
page?: number
|
|
pageSize?: number
|
|
sortField?: string
|
|
sortDirection?: SortDirection
|
|
}, extraParams?, retainScrollPosition?: boolean) {
|
|
this.getCurrentRouting(paginationId).subscribe((currentFindListOptions) => {
|
|
const currentParametersWithIdName = this.getParametersWithIdName(paginationId, currentFindListOptions);
|
|
const parametersWithIdName = this.getParametersWithIdName(paginationId, params);
|
|
if (isNotEmpty(difference(parametersWithIdName, currentParametersWithIdName)) || isNotEmpty(extraParams) || isNotEmpty(this.clearParams)) {
|
|
const queryParams = Object.assign({}, this.clearParams, currentParametersWithIdName,
|
|
parametersWithIdName, extraParams);
|
|
if (retainScrollPosition) {
|
|
this.router.navigate(url, {
|
|
queryParams: queryParams,
|
|
queryParamsHandling: 'merge',
|
|
fragment: `p-${paginationId}`
|
|
});
|
|
} else {
|
|
this.router.navigate(url, {
|
|
queryParams: queryParams,
|
|
queryParamsHandling: 'merge'
|
|
});
|
|
}
|
|
this.clearParams = {};
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Add the params to be cleared to the clearParams variable.
|
|
* When the updateRoute or updateRouteWithUrl these params will be removed from the route pagination
|
|
* @param paginationId - The ID for which to clear the params
|
|
*/
|
|
clearPagination(paginationId: string) {
|
|
const params = {};
|
|
params[`${paginationId}.page`] = null;
|
|
params[`${paginationId}.rpp`] = null;
|
|
params[`${paginationId}.sf`] = null;
|
|
params[`${paginationId}.sd`] = null;
|
|
|
|
Object.assign(this.clearParams, params);
|
|
}
|
|
|
|
/**
|
|
* Retrieve the page parameter for the provided id
|
|
* @param paginationId - The ID for which to retrieve the page param
|
|
*/
|
|
getPageParam(paginationId: string) {
|
|
return `${paginationId}.page`;
|
|
}
|
|
|
|
private getCurrentRouting(paginationId: string) {
|
|
return this.getFindListOptions(paginationId, {}, true).pipe(
|
|
take(1),
|
|
map((findListoptions: FindListOptions) => {
|
|
return {
|
|
page: findListoptions.currentPage,
|
|
pageSize: findListoptions.elementsPerPage,
|
|
sortField: findListoptions.sort.field,
|
|
sortDirection: findListoptions.sort.direction,
|
|
};
|
|
})
|
|
);
|
|
}
|
|
|
|
private getParametersWithIdName(paginationId: string, params: {
|
|
page?: number
|
|
pageSize?: number
|
|
sortField?: string
|
|
sortDirection?: SortDirection
|
|
}) {
|
|
const paramsWithIdName = {};
|
|
if (hasValue(params.page)) {
|
|
paramsWithIdName[`${paginationId}.page`] = `${params.page}`;
|
|
}
|
|
if (hasValue(params.pageSize)) {
|
|
paramsWithIdName[`${paginationId}.rpp`] = `${params.pageSize}`;
|
|
}
|
|
if (hasValue(params.sortField)) {
|
|
paramsWithIdName[`${paginationId}.sf`] = `${params.sortField}`;
|
|
}
|
|
if (hasValue(params.sortDirection)) {
|
|
paramsWithIdName[`${paginationId}.sd`] = `${params.sortDirection}`;
|
|
}
|
|
return paramsWithIdName;
|
|
}
|
|
|
|
private convertToNumeric(param, defaultValue) {
|
|
let result = defaultValue;
|
|
if (isNumeric(param)) {
|
|
result = +param;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
|
|
private getBestMatchPageSize(pageSize: any, defaultPagination: PaginationComponentOptions): number {
|
|
const numberPageSize = this.convertToNumeric(pageSize, defaultPagination.pageSize);
|
|
const differenceList = defaultPagination.pageSizeOptions.map((pageSizeOption) => {
|
|
return Math.abs(pageSizeOption - numberPageSize);
|
|
});
|
|
const minDifference = Math.min.apply(Math, differenceList);
|
|
return defaultPagination.pageSizeOptions[differenceList.indexOf(minDifference)];
|
|
}
|
|
|
|
}
|