-
-
Notifications
You must be signed in to change notification settings - Fork 75
/
paginate.ts
118 lines (94 loc) 路 2.68 KB
/
paginate.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import { merge } from "../core/utils.ts";
import type { Site } from "../core.ts";
/** The options for the paginate helper */
export interface PaginateOptions {
/** The number of elements per page */
size: number;
/** The function to generate the url of the pages */
url: (page: number) => string;
}
export type Paginator = (
results: unknown[],
userOptions?: Partial<PaginateOptions>,
) => Generator<PaginateResult, void, unknown>;
/** The paginate result */
export interface PaginateResult {
/** The page url */
url: string;
/** The page elements */
results: unknown[];
/** The pagination info */
pagination: {
/** The current page number */
page: number;
/** The total number of pages */
totalPages: number;
/** The total number of elements */
totalResults: number;
/** The url of the previous page */
previous: string | null;
/** The url of the next page */
next: string | null;
};
}
export interface Options {
/** The helper name */
name: string;
/** The default pagination options */
options: PaginateOptions;
}
export const defaults: Options = {
name: "paginate",
options: {
size: 10,
url: () => "",
},
};
/** Register the plugin to enable the `paginate` helper */
export default function (userOptions?: Partial<Options>) {
const options = merge(defaults, userOptions);
return (site: Site) => {
if (!userOptions?.options?.url) {
const ext = site.options.prettyUrls ? "/index.html" : ".html";
options.options.url = (page: number) => `./page-${page}${ext}`;
}
// Register the helper
site.data(options.name, createPaginator(options.options));
};
}
/** Create a paginator function */
export function createPaginator(defaults: PaginateOptions): Paginator {
return function* paginate(
results: unknown[],
userOptions: Partial<PaginateOptions> = {},
) {
const options = merge(defaults, userOptions);
const totalResults = results.length;
const totalPages = Math.ceil(results.length / options.size);
let page = 1;
let data = createPageData(page);
for (const result of results) {
data.results.push(result);
if (data.results.length >= options.size) {
yield data;
data = createPageData(++page);
}
}
if (data.results.length) {
yield data;
}
function createPageData(page: number): PaginateResult {
return {
url: options.url(page),
results: [],
pagination: {
page,
totalPages,
totalResults,
previous: page > 1 ? options.url(page - 1) : null,
next: totalPages > page ? options.url(page + 1) : null,
},
};
}
};
}