2021-03-30 10:20:38 +02:00
|
|
|
import {WrappingError} from "./Utils";
|
2020-04-22 15:52:17 +02:00
|
|
|
|
2021-03-30 10:20:38 +02:00
|
|
|
export default class Pagination {
|
2020-04-22 15:52:17 +02:00
|
|
|
public readonly page: number;
|
|
|
|
public readonly perPage: number;
|
|
|
|
public readonly totalCount: number;
|
|
|
|
|
2021-03-30 10:20:38 +02:00
|
|
|
public constructor(page: number, perPage: number, totalCount: number) {
|
2021-04-22 11:40:27 +02:00
|
|
|
if (perPage <= 0) throw new Error('perPage must be >= 1');
|
|
|
|
if (totalCount < 0) throw new Error('totalCount must be >= 0');
|
|
|
|
|
2020-04-22 15:52:17 +02:00
|
|
|
this.page = page;
|
|
|
|
this.perPage = perPage;
|
|
|
|
this.totalCount = totalCount;
|
2021-03-30 10:20:38 +02:00
|
|
|
|
2021-04-22 11:40:27 +02:00
|
|
|
if (this.page < 1 || this.page > 1 && this.page > this.lastPage) {
|
2021-03-30 10:20:38 +02:00
|
|
|
throw new PageNotFoundError(this.page);
|
|
|
|
}
|
2020-04-22 15:52:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public hasPrevious(): boolean {
|
|
|
|
return this.page > 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
public hasNext(): boolean {
|
2021-03-30 10:20:38 +02:00
|
|
|
return this.page < this.lastPage;
|
|
|
|
}
|
|
|
|
|
|
|
|
public get lastPage(): number {
|
2021-04-22 11:40:27 +02:00
|
|
|
return Math.max(Math.ceil(this.totalCount / this.perPage), 1);
|
2021-03-30 10:20:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public previousPages(contextSize: number): number[] {
|
|
|
|
const pages = [];
|
|
|
|
|
|
|
|
let i = 1;
|
|
|
|
|
|
|
|
// Leftmost context
|
|
|
|
while (i < this.page && i <= contextSize) {
|
|
|
|
pages.push(i);
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ellipsis
|
|
|
|
if (i < this.page - contextSize) {
|
|
|
|
pages.push(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Middle left context
|
|
|
|
i = Math.max(i, this.page - contextSize);
|
|
|
|
while (i < this.page) {
|
|
|
|
pages.push(i);
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return pages;
|
2020-04-22 15:52:17 +02:00
|
|
|
}
|
|
|
|
|
2021-03-30 10:20:38 +02:00
|
|
|
public nextPages(contextSize: number): number[] {
|
|
|
|
const pages = [];
|
|
|
|
|
|
|
|
let i = this.page + 1;
|
|
|
|
// Middle right context
|
|
|
|
while (i <= this.lastPage && i <= this.page + contextSize) {
|
|
|
|
pages.push(i);
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ellipsis
|
|
|
|
if (this.page + contextSize + 1 < this.lastPage - contextSize + 1) {
|
|
|
|
pages.push(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Rightmost context
|
|
|
|
i = Math.max(i, this.lastPage - contextSize + 1);
|
|
|
|
while (i <= this.lastPage) {
|
|
|
|
pages.push(i);
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return pages;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export class PageNotFoundError extends WrappingError {
|
|
|
|
public constructor(
|
|
|
|
public readonly page: number,
|
|
|
|
) {
|
|
|
|
super(`Page ${page} not found.`);
|
|
|
|
}
|
2020-09-25 23:42:15 +02:00
|
|
|
}
|