swaf/src/Pagination.ts

92 lines
2.2 KiB
TypeScript

import {WrappingError} from "./Utils";
export default class Pagination {
public readonly page: number;
public readonly perPage: number;
public readonly totalCount: number;
public constructor(page: number, perPage: number, totalCount: number) {
if (perPage <= 0) throw new Error('perPage must be >= 1');
if (totalCount < 0) throw new Error('totalCount must be >= 0');
this.page = page;
this.perPage = perPage;
this.totalCount = totalCount;
if (this.page < 1 || this.page > 1 && this.page > this.lastPage) {
throw new PageNotFoundError(this.page);
}
}
public hasPrevious(): boolean {
return this.page > 1;
}
public hasNext(): boolean {
return this.page < this.lastPage;
}
public get lastPage(): number {
return Math.max(Math.ceil(this.totalCount / this.perPage), 1);
}
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;
}
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.`);
}
}