@cedx/base 0.5.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ReadMe.md +1 -1
- package/lib/Data/PaginatedList.d.ts +35 -0
- package/lib/Data/PaginatedList.d.ts.map +1 -0
- package/lib/Data/PaginatedList.js +28 -0
- package/lib/Data/Pagination.d.ts +74 -0
- package/lib/Data/Pagination.d.ts.map +1 -0
- package/lib/Data/Pagination.js +101 -0
- package/lib/Data/Sort.d.ts +25 -23
- package/lib/Data/Sort.d.ts.map +1 -1
- package/lib/Data/Sort.js +37 -33
- package/lib/{Date.d.ts → DateExtensions.d.ts} +1 -1
- package/lib/DateExtensions.d.ts.map +1 -0
- package/lib/{Html/File.d.ts → FileExtensions.d.ts} +4 -11
- package/lib/FileExtensions.d.ts.map +1 -0
- package/lib/{Html/File.js → FileExtensions.js} +3 -12
- package/lib/{Http → Net/Http}/HttpClient.d.ts +17 -2
- package/lib/Net/Http/HttpClient.d.ts.map +1 -0
- package/lib/{Http → Net/Http}/HttpClient.js +17 -15
- package/lib/Net/Http/HttpMethod.d.ts +46 -0
- package/lib/Net/Http/HttpMethod.d.ts.map +1 -0
- package/lib/Net/Http/HttpMethod.js +41 -0
- package/lib/Net/Http/HttpRequestError.d.ts +33 -0
- package/lib/Net/Http/HttpRequestError.d.ts.map +1 -0
- package/lib/{Http/HttpError.js → Net/Http/HttpRequestError.js} +16 -16
- package/lib/Net/Http/StatusCode.d.ts +122 -0
- package/lib/Net/Http/StatusCode.d.ts.map +1 -0
- package/lib/Net/Http/StatusCode.js +117 -0
- package/lib/Net/Mime/DispositionType.d.ts +18 -0
- package/lib/Net/Mime/DispositionType.d.ts.map +1 -0
- package/lib/Net/Mime/DispositionType.js +13 -0
- package/lib/Net/Mime/MediaType.d.ts +151 -0
- package/lib/Net/Mime/MediaType.d.ts.map +1 -0
- package/lib/Net/Mime/MediaType.js +150 -0
- package/lib/{Number.d.ts → NumberExtensions.d.ts} +1 -1
- package/lib/NumberExtensions.d.ts.map +1 -0
- package/lib/{String.d.ts → StringExtensions.d.ts} +1 -1
- package/lib/StringExtensions.d.ts.map +1 -0
- package/lib/{Html → UI}/AppTheme.d.ts +3 -3
- package/lib/UI/AppTheme.d.ts.map +1 -0
- package/lib/{Html → UI}/AppTheme.js +3 -3
- package/lib/UI/Components/ComponentBase.d.ts +24 -0
- package/lib/UI/Components/ComponentBase.d.ts.map +1 -0
- package/lib/UI/Components/ComponentBase.js +29 -0
- package/lib/UI/{LoadingIndicator.d.ts → Components/LoadingIndicator.d.ts} +1 -2
- package/lib/UI/Components/LoadingIndicator.d.ts.map +1 -0
- package/lib/UI/{MenuActivator.d.ts → Components/MenuActivator.d.ts} +1 -1
- package/lib/UI/Components/MenuActivator.d.ts.map +1 -0
- package/lib/UI/{MenuActivator.js → Components/MenuActivator.js} +1 -1
- package/lib/UI/Components/OfflineIndicator.d.ts.map +1 -0
- package/lib/UI/Components/ThemeDropdown.d.ts +67 -0
- package/lib/UI/Components/ThemeDropdown.d.ts.map +1 -0
- package/lib/UI/Components/ThemeDropdown.js +140 -0
- package/lib/UI/Context.d.ts.map +1 -0
- package/lib/UI/MenuAlignment.d.ts +18 -0
- package/lib/UI/MenuAlignment.d.ts.map +1 -0
- package/lib/UI/MenuAlignment.js +13 -0
- package/lib/{Html → UI}/ViewportScroller.d.ts +1 -1
- package/lib/UI/ViewportScroller.d.ts.map +1 -0
- package/lib/{Html → UI}/ViewportScroller.js +6 -6
- package/package.json +7 -8
- package/src/Client/Data/PaginatedList.ts +47 -0
- package/src/Client/Data/Pagination.ts +136 -0
- package/src/Client/Data/Sort.ts +40 -35
- package/src/Client/Data/tsconfig.json +1 -1
- package/src/Client/{Html/File.ts → FileExtensions.ts} +3 -13
- package/src/Client/{Http → Net/Http}/HttpClient.ts +32 -14
- package/src/Client/Net/Http/HttpMethod.ts +55 -0
- package/src/Client/{Http/HttpError.ts → Net/Http/HttpRequestError.ts} +17 -17
- package/src/Client/Net/Http/StatusCode.ts +150 -0
- package/src/Client/Net/Mime/DispositionType.ts +20 -0
- package/src/Client/Net/Mime/MediaType.ts +185 -0
- package/src/Client/{Abstractions → Net}/tsconfig.json +3 -3
- package/src/Client/{Html → UI}/AppTheme.ts +3 -3
- package/src/Client/UI/Components/ComponentBase.ts +34 -0
- package/src/Client/UI/{LoadingIndicator.ts → Components/LoadingIndicator.ts} +1 -3
- package/src/Client/UI/{MenuActivator.ts → Components/MenuActivator.ts} +1 -1
- package/src/Client/UI/Components/ThemeDropdown.ts +163 -0
- package/src/Client/UI/MenuAlignment.ts +20 -0
- package/src/Client/{Html → UI}/ViewportScroller.ts +6 -6
- package/src/Client/UI/tsconfig.json +2 -3
- package/src/Client/tsconfig.json +1 -4
- package/lib/Abstractions/ILoadingIndicator.d.ts +0 -17
- package/lib/Abstractions/ILoadingIndicator.d.ts.map +0 -1
- package/lib/Abstractions/ILoadingIndicator.js +0 -1
- package/lib/Date.d.ts.map +0 -1
- package/lib/DependencyInjection/Container.d.ts +0 -43
- package/lib/DependencyInjection/Container.d.ts.map +0 -1
- package/lib/DependencyInjection/Container.js +0 -65
- package/lib/Html/AppTheme.d.ts.map +0 -1
- package/lib/Html/Context.d.ts.map +0 -1
- package/lib/Html/File.d.ts.map +0 -1
- package/lib/Html/ViewportScroller.d.ts.map +0 -1
- package/lib/Http/HttpClient.d.ts.map +0 -1
- package/lib/Http/HttpError.d.ts +0 -33
- package/lib/Http/HttpError.d.ts.map +0 -1
- package/lib/Http/StatusCodes.d.ts +0 -114
- package/lib/Http/StatusCodes.d.ts.map +0 -1
- package/lib/Http/StatusCodes.js +0 -109
- package/lib/Number.d.ts.map +0 -1
- package/lib/String.d.ts.map +0 -1
- package/lib/UI/ActionBar.d.ts +0 -25
- package/lib/UI/ActionBar.d.ts.map +0 -1
- package/lib/UI/ActionBar.js +0 -25
- package/lib/UI/LoadingIndicator.d.ts.map +0 -1
- package/lib/UI/MenuActivator.d.ts.map +0 -1
- package/lib/UI/OfflineIndicator.d.ts.map +0 -1
- package/lib/UI/ThemeDropdown.d.ts +0 -34
- package/lib/UI/ThemeDropdown.d.ts.map +0 -1
- package/lib/UI/ThemeDropdown.js +0 -71
- package/src/Client/Abstractions/ILoadingIndicator.ts +0 -16
- package/src/Client/Data/Pagination.new +0 -130
- package/src/Client/DependencyInjection/Container.ts +0 -75
- package/src/Client/DependencyInjection/tsconfig.json +0 -13
- package/src/Client/Html/tsconfig.json +0 -16
- package/src/Client/Http/StatusCodes.ts +0 -140
- package/src/Client/Http/tsconfig.json +0 -16
- package/src/Client/UI/ActionBar.ts +0 -41
- package/src/Client/UI/ThemeDropdown.ts +0 -94
- /package/lib/{Date.js → DateExtensions.js} +0 -0
- /package/lib/{Number.js → NumberExtensions.js} +0 -0
- /package/lib/{String.js → StringExtensions.js} +0 -0
- /package/lib/UI/{LoadingIndicator.js → Components/LoadingIndicator.js} +0 -0
- /package/lib/UI/{OfflineIndicator.d.ts → Components/OfflineIndicator.d.ts} +0 -0
- /package/lib/UI/{OfflineIndicator.js → Components/OfflineIndicator.js} +0 -0
- /package/lib/{Html → UI}/Context.d.ts +0 -0
- /package/lib/{Html → UI}/Context.js +0 -0
- /package/src/Client/{Date.ts → DateExtensions.ts} +0 -0
- /package/src/Client/{Number.ts → NumberExtensions.ts} +0 -0
- /package/src/Client/{String.ts → StringExtensions.ts} +0 -0
- /package/src/Client/UI/{OfflineIndicator.ts → Components/OfflineIndicator.ts} +0 -0
- /package/src/Client/{Html → UI}/Context.ts +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Context.d.ts","sourceRoot":"","sources":["../../src/Client/UI/Context.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,eAAO,MAAM,OAAO;IAEnB;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;IAGH;;OAEG;;EAEF,CAAC;AAEH;;GAEG;AACH,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC,MAAM,OAAO,OAAO,CAAC,CAAC;AAE3D;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAOhD"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Defines the alignment of a dropdown menu.
|
|
3
|
+
*/
|
|
4
|
+
export declare const MenuAlignment: Readonly<{
|
|
5
|
+
/**
|
|
6
|
+
* The dropdown menu is left aligned.
|
|
7
|
+
*/
|
|
8
|
+
Start: "Start";
|
|
9
|
+
/**
|
|
10
|
+
* The dropdown menu is right aligned.
|
|
11
|
+
*/
|
|
12
|
+
End: "End";
|
|
13
|
+
}>;
|
|
14
|
+
/**
|
|
15
|
+
* Defines the alignment of a dropdown menu.
|
|
16
|
+
*/
|
|
17
|
+
export type MenuAlignment = typeof MenuAlignment[keyof typeof MenuAlignment];
|
|
18
|
+
//# sourceMappingURL=MenuAlignment.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MenuAlignment.d.ts","sourceRoot":"","sources":["../../src/Client/UI/MenuAlignment.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,eAAO,MAAM,aAAa;IAEzB;;OAEG;;IAGH;;OAEG;;EAEF,CAAC;AAEH;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,OAAO,aAAa,CAAC,MAAM,OAAO,aAAa,CAAC,CAAC"}
|
|
@@ -23,7 +23,7 @@ export declare class ViewportScroller {
|
|
|
23
23
|
get scrollOffset(): number;
|
|
24
24
|
/**
|
|
25
25
|
* Scrolls to the specified anchor.
|
|
26
|
-
* @param anchor The identifier or name of an
|
|
26
|
+
* @param anchor The identifier or name of an element.
|
|
27
27
|
* @param options Value indicating whether scrolling is instant or animates smoothly.
|
|
28
28
|
*/
|
|
29
29
|
scrollToAnchor(anchor: string, options?: ScrollOptions): void;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ViewportScroller.d.ts","sourceRoot":"","sources":["../../src/Client/UI/ViewportScroller.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,OAAO,CAAC;IAEnC;;OAEG;IACH,QAAQ,EAAE,cAAc,CAAA;CACxB,CAAC,CAAC;AAEH;;GAEG;AACH,qBAAa,gBAAgB;;IAY5B;;;OAGG;gBACS,QAAQ,GAAE,MAAM,OAAqE;IAIjG;;OAEG;IACH,IAAI,YAAY,IAAI,MAAM,CAWzB;IAED;;;;OAIG;IACH,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,IAAI;IAKjE;;;;OAIG;IACH,eAAe,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,GAAE,aAAkB,GAAG,IAAI;IAMpE;;;;;OAKG;IACH,gBAAgB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,IAAI;IAIzE;;;OAGG;IACH,WAAW,CAAC,OAAO,GAAE,aAAkB,GAAG,IAAI;CAG9C"}
|
|
@@ -22,21 +22,21 @@ export class ViewportScroller {
|
|
|
22
22
|
*/
|
|
23
23
|
get scrollOffset() {
|
|
24
24
|
if (this.#scrollOffset < 0) {
|
|
25
|
-
const fontSize = parseInt(getComputedStyle(document.body).fontSize);
|
|
25
|
+
const fontSize = Number.parseInt(getComputedStyle(document.body).fontSize);
|
|
26
26
|
this.#scrollOffset = Number.isNaN(fontSize) ? 0 : fontSize * 2;
|
|
27
|
-
const
|
|
28
|
-
this.#scrollOffset +=
|
|
27
|
+
const navbar = document.body.querySelector(".navbar");
|
|
28
|
+
this.#scrollOffset += (navbar?.offsetHeight ?? 0);
|
|
29
29
|
}
|
|
30
|
-
const actionBar = document.body.querySelector("action-bar");
|
|
30
|
+
const actionBar = document.body.querySelector("action-bar, .action-bar");
|
|
31
31
|
return this.#scrollOffset + (actionBar?.offsetHeight ?? 0);
|
|
32
32
|
}
|
|
33
33
|
/**
|
|
34
34
|
* Scrolls to the specified anchor.
|
|
35
|
-
* @param anchor The identifier or name of an
|
|
35
|
+
* @param anchor The identifier or name of an element.
|
|
36
36
|
* @param options Value indicating whether scrolling is instant or animates smoothly.
|
|
37
37
|
*/
|
|
38
38
|
scrollToAnchor(anchor, options = {}) {
|
|
39
|
-
const element = document.getElementById(anchor) ??
|
|
39
|
+
const element = document.getElementById(anchor) ?? this.#viewport().querySelector(`[name="${anchor}"]`);
|
|
40
40
|
if (element)
|
|
41
41
|
this.scrollToElement(element, options);
|
|
42
42
|
}
|
package/package.json
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"name": "@cedx/base",
|
|
8
8
|
"repository": "cedx/base",
|
|
9
9
|
"type": "module",
|
|
10
|
-
"version": "0.
|
|
10
|
+
"version": "0.7.0",
|
|
11
11
|
"devDependencies": {
|
|
12
12
|
"@playwright/browser-chromium": "^1.54.2",
|
|
13
13
|
"@types/bootstrap": "^5.2.10",
|
|
@@ -16,14 +16,14 @@
|
|
|
16
16
|
"@types/node": "^24.2.1",
|
|
17
17
|
"@types/serve-handler": "^6.1.4",
|
|
18
18
|
"chai": "^5.2.1",
|
|
19
|
-
"esbuild": "^0.25.
|
|
19
|
+
"esbuild": "^0.25.9",
|
|
20
20
|
"globals": "^16.3.0",
|
|
21
21
|
"mocha": "^11.7.1",
|
|
22
22
|
"playwright": "^1.54.2",
|
|
23
23
|
"serve-handler": "^6.1.6",
|
|
24
|
-
"typedoc": "^0.28.
|
|
24
|
+
"typedoc": "^0.28.10",
|
|
25
25
|
"typescript": "^5.9.2",
|
|
26
|
-
"typescript-eslint": "^8.39.
|
|
26
|
+
"typescript-eslint": "^8.39.1"
|
|
27
27
|
},
|
|
28
28
|
"engines": {
|
|
29
29
|
"node": ">=24.0.0"
|
|
@@ -39,9 +39,7 @@
|
|
|
39
39
|
"src/Client/"
|
|
40
40
|
],
|
|
41
41
|
"imports": {
|
|
42
|
-
"#
|
|
43
|
-
"#Base/*.js": "./lib/*.js",
|
|
44
|
-
"#Html/*.js": "./lib/Html/*.js"
|
|
42
|
+
"#Base/*.js": "./lib/*.js"
|
|
45
43
|
},
|
|
46
44
|
"keywords": [
|
|
47
45
|
"belin",
|
|
@@ -50,7 +48,8 @@
|
|
|
50
48
|
"library"
|
|
51
49
|
],
|
|
52
50
|
"peerDependencies": {
|
|
53
|
-
"bootstrap": ">=5.3.0"
|
|
51
|
+
"bootstrap": ">=5.3.0",
|
|
52
|
+
"lit": ">=3.3.0"
|
|
54
53
|
},
|
|
55
54
|
"publishConfig": {
|
|
56
55
|
"access": "public"
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import {Pagination} from "./Pagination.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A list with information relevant to the pagination of its items.
|
|
5
|
+
*/
|
|
6
|
+
export class PaginatedList<T> extends Array<T> {
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* The information relevant to the pagination of the list items.
|
|
10
|
+
*/
|
|
11
|
+
pagination: Pagination;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Creates a new paginated list.
|
|
15
|
+
* @param options An object providing values to initialize this instance.
|
|
16
|
+
*/
|
|
17
|
+
constructor(options: PaginatedListOptions<T> = {}) {
|
|
18
|
+
super();
|
|
19
|
+
for (const item of options.items ?? []) this.push(item);
|
|
20
|
+
this.pagination = options.pagination ?? new Pagination;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Creates an empty paginated list.
|
|
25
|
+
* @param itemsPerPage The number of items per page.
|
|
26
|
+
* @returns An empty paginated list with the specified number of items per page.
|
|
27
|
+
*/
|
|
28
|
+
static empty<T>(itemsPerPage: number): PaginatedList<T> {
|
|
29
|
+
return new this({pagination: new Pagination({itemsPerPage})});
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Defines the options of a {@link PaginatedList} instance.
|
|
35
|
+
*/
|
|
36
|
+
export type PaginatedListOptions<T> = Partial<{
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* The list items.
|
|
40
|
+
*/
|
|
41
|
+
items: T[];
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* The information relevant to the pagination of the list items.
|
|
45
|
+
*/
|
|
46
|
+
pagination: Pagination;
|
|
47
|
+
}>;
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Represents information relevant to the pagination of data items.
|
|
3
|
+
*/
|
|
4
|
+
export class Pagination {
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* The one-based current page number.
|
|
8
|
+
*/
|
|
9
|
+
#currentPageIndex!: number;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* The number of items per page.
|
|
13
|
+
*/
|
|
14
|
+
#itemsPerPage!: number;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* The total number of items.
|
|
18
|
+
*/
|
|
19
|
+
#totalItemCount!: number;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Creates a new pagination.
|
|
23
|
+
* @param options An object providing values to initialize this instance.
|
|
24
|
+
*/
|
|
25
|
+
constructor(options: PaginationOptions = {}) {
|
|
26
|
+
this.currentPageIndex = options.currentPageIndex ?? 1;
|
|
27
|
+
this.itemsPerPage = options.itemsPerPage ?? 25;
|
|
28
|
+
this.totalItemCount = options.totalItemCount ?? 0;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* The one-based current page number.
|
|
33
|
+
*/
|
|
34
|
+
get currentPageIndex(): number {
|
|
35
|
+
return this.#currentPageIndex;
|
|
36
|
+
}
|
|
37
|
+
set currentPageIndex(value: number) {
|
|
38
|
+
this.#currentPageIndex = Math.max(1, value);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Value indicating whether a next page exists.
|
|
43
|
+
*/
|
|
44
|
+
get hasNextPage(): boolean {
|
|
45
|
+
return this.#currentPageIndex < this.lastPageIndex;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Value indicating whether a previous page exists.
|
|
50
|
+
*/
|
|
51
|
+
get hasPreviousPage(): boolean {
|
|
52
|
+
return this.#currentPageIndex > 1;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* The number of items per page.
|
|
57
|
+
*/
|
|
58
|
+
get itemsPerPage(): number {
|
|
59
|
+
return this.#itemsPerPage;
|
|
60
|
+
}
|
|
61
|
+
set itemsPerPage(value: number) {
|
|
62
|
+
this.#itemsPerPage = Math.max(1, Math.min(1000, value));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* The one-based last page number.
|
|
67
|
+
*/
|
|
68
|
+
get lastPageIndex(): number {
|
|
69
|
+
return this.#totalItemCount > 0 ? Math.ceil(this.#totalItemCount / this.#itemsPerPage) : 1;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* The data limit.
|
|
74
|
+
*/
|
|
75
|
+
get limit(): number {
|
|
76
|
+
return this.#itemsPerPage;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* The data offset.
|
|
81
|
+
*/
|
|
82
|
+
get offset(): number {
|
|
83
|
+
return (this.#currentPageIndex - 1) * this.#itemsPerPage;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* The search parameters corresponding to this object.
|
|
88
|
+
*/
|
|
89
|
+
get searchParams(): URLSearchParams {
|
|
90
|
+
return new URLSearchParams({page: this.#currentPageIndex.toString(), perPage: this.#itemsPerPage.toString()});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* The total number of items.
|
|
95
|
+
*/
|
|
96
|
+
get totalItemCount(): number {
|
|
97
|
+
return this.#totalItemCount;
|
|
98
|
+
}
|
|
99
|
+
set totalItemCount(value: number) {
|
|
100
|
+
this.#totalItemCount = Math.max(0, value);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Creates a new pagination from the HTTP headers of the specified response.
|
|
105
|
+
* @param response A server response.
|
|
106
|
+
* @returns The pagination corresponding to the HTTP headers of the specified response.
|
|
107
|
+
*/
|
|
108
|
+
static fromResponse(response: Response): Pagination {
|
|
109
|
+
return new this({
|
|
110
|
+
currentPageIndex: Number(response.headers.get("X-Pagination-Current-Page") ?? "1"),
|
|
111
|
+
itemsPerPage: Number(response.headers.get("X-Pagination-Per-Page") ?? "25"),
|
|
112
|
+
totalItemCount: Number(response.headers.get("X-Pagination-Total-Count") ?? "0")
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Defines the options of a {@link Pagination} instance.
|
|
119
|
+
*/
|
|
120
|
+
export type PaginationOptions = Partial<{
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* The one-based current page number.
|
|
124
|
+
*/
|
|
125
|
+
currentPageIndex: number;
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* The number of items per page.
|
|
129
|
+
*/
|
|
130
|
+
itemsPerPage: number;
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* The total number of items.
|
|
134
|
+
*/
|
|
135
|
+
totalItemCount: number;
|
|
136
|
+
}>;
|
package/src/Client/Data/Sort.ts
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Specifies the order of a
|
|
2
|
+
* Specifies the order of a sort property.
|
|
3
3
|
*/
|
|
4
4
|
export const SortOrder = Object.freeze({
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* The sort is ascending.
|
|
8
8
|
*/
|
|
9
|
-
Ascending: "
|
|
9
|
+
Ascending: "Ascending",
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* The sort is descending.
|
|
13
13
|
*/
|
|
14
|
-
Descending: "
|
|
14
|
+
Descending: "Descending"
|
|
15
15
|
});
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
|
-
* Specifies the order of a
|
|
18
|
+
* Specifies the order of a sort property.
|
|
19
19
|
*/
|
|
20
20
|
export type SortOrder = typeof SortOrder[keyof typeof SortOrder];
|
|
21
21
|
|
|
@@ -30,7 +30,7 @@ export type SortProperty = [string, SortOrder];
|
|
|
30
30
|
export class Sort implements Iterable<SortProperty> {
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
|
-
* The list of
|
|
33
|
+
* The list of sort properties.
|
|
34
34
|
*/
|
|
35
35
|
#properties: SortProperty[];
|
|
36
36
|
|
|
@@ -43,7 +43,14 @@ export class Sort implements Iterable<SortProperty> {
|
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
/**
|
|
46
|
-
* The
|
|
46
|
+
* The list of sort properties.
|
|
47
|
+
*/
|
|
48
|
+
get keys(): string[] {
|
|
49
|
+
return this.#properties.map(item => item[0]);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* The number of properties in this sort.
|
|
47
54
|
*/
|
|
48
55
|
get length(): number {
|
|
49
56
|
return this.#properties.length;
|
|
@@ -73,33 +80,39 @@ export class Sort implements Iterable<SortProperty> {
|
|
|
73
80
|
|
|
74
81
|
/**
|
|
75
82
|
* Returns a new iterator that allows iterating the entries of this sort.
|
|
76
|
-
* @returns An iterator over the
|
|
83
|
+
* @returns An iterator over the sort properties.
|
|
77
84
|
*/
|
|
78
|
-
|
|
79
|
-
|
|
85
|
+
[Symbol.iterator](): Iterator<SortProperty> {
|
|
86
|
+
return this.#properties[Symbol.iterator]();
|
|
80
87
|
}
|
|
81
88
|
|
|
82
89
|
/**
|
|
83
90
|
* Appends the specified property to this sort.
|
|
84
91
|
* @param property The property name.
|
|
85
92
|
* @param order The sort order.
|
|
86
|
-
* @
|
|
93
|
+
* @throws `Error` when an item with the property name already exists.
|
|
87
94
|
*/
|
|
88
|
-
|
|
89
|
-
this.
|
|
95
|
+
add(property: string, order: SortOrder): void {
|
|
96
|
+
if (this.containsKey(property)) throw new Error("An item with the property name has already been added.");
|
|
90
97
|
this.#properties.push([property, order]);
|
|
91
|
-
return this;
|
|
92
98
|
}
|
|
93
99
|
|
|
94
100
|
/**
|
|
95
|
-
* Gets the
|
|
101
|
+
* Gets the sort property at the specified index.
|
|
96
102
|
* @param index The position in this sort.
|
|
97
|
-
* @returns The
|
|
103
|
+
* @returns The sort property at the specified index, or `null` if it doesn't exist.
|
|
98
104
|
*/
|
|
99
105
|
at(index: number): SortProperty|null {
|
|
100
106
|
return this.#properties.at(index) ?? null;
|
|
101
107
|
}
|
|
102
108
|
|
|
109
|
+
/**
|
|
110
|
+
* Removes all properties from this sort.
|
|
111
|
+
*/
|
|
112
|
+
clear(): void {
|
|
113
|
+
this.#properties = [];
|
|
114
|
+
}
|
|
115
|
+
|
|
103
116
|
/**
|
|
104
117
|
* Compares the specified objects, according to the current sort properties.
|
|
105
118
|
* @param x The first object to compare.
|
|
@@ -117,6 +130,15 @@ export class Sort implements Iterable<SortProperty> {
|
|
|
117
130
|
return 0;
|
|
118
131
|
}
|
|
119
132
|
|
|
133
|
+
/**
|
|
134
|
+
* Returns a value indicating whether the specified property exists in this sort.
|
|
135
|
+
* @param property The property name.
|
|
136
|
+
* @returns `true` if the specified property exists in this sort, otherwise `false`.
|
|
137
|
+
*/
|
|
138
|
+
containsKey(property: string): boolean {
|
|
139
|
+
return this.#properties.some(([key]) => key == property);
|
|
140
|
+
}
|
|
141
|
+
|
|
120
142
|
/**
|
|
121
143
|
* Removes the specified property from this sort.
|
|
122
144
|
* @param property The property name.
|
|
@@ -148,15 +170,6 @@ export class Sort implements Iterable<SortProperty> {
|
|
|
148
170
|
}
|
|
149
171
|
}
|
|
150
172
|
|
|
151
|
-
/**
|
|
152
|
-
* Returns a value indicating whether the specified property exists in this sort.
|
|
153
|
-
* @param property The property name.
|
|
154
|
-
* @returns `true` if the specified property exists in this sort, otherwise `false`.
|
|
155
|
-
*/
|
|
156
|
-
has(property: string): boolean {
|
|
157
|
-
return this.#properties.some(([key]) => key == property);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
173
|
/**
|
|
161
174
|
* Gets the index of the specified property in the underlying list.
|
|
162
175
|
* @param property The property name.
|
|
@@ -207,7 +220,8 @@ export class Sort implements Iterable<SortProperty> {
|
|
|
207
220
|
return this;
|
|
208
221
|
}
|
|
209
222
|
|
|
210
|
-
|
|
223
|
+
this.add(property, order);
|
|
224
|
+
return this;
|
|
211
225
|
}
|
|
212
226
|
|
|
213
227
|
/**
|
|
@@ -218,20 +232,11 @@ export class Sort implements Iterable<SortProperty> {
|
|
|
218
232
|
return this.toString();
|
|
219
233
|
}
|
|
220
234
|
|
|
221
|
-
/**
|
|
222
|
-
* Converts this sort to an SQL clause.
|
|
223
|
-
* @param escape A function used to escape the SQL identifiers.
|
|
224
|
-
* @returns The SQL clause corresponding to this object.
|
|
225
|
-
*/
|
|
226
|
-
toSql(escape: (identifier: string) => string = id => id): string {
|
|
227
|
-
return this.#properties.map(([property, order]) => `${escape(property)} ${order}`).join(", ");
|
|
228
|
-
}
|
|
229
|
-
|
|
230
235
|
/**
|
|
231
236
|
* Returns a string representation of this object.
|
|
232
237
|
* @returns The string representation of this object.
|
|
233
238
|
*/
|
|
234
239
|
toString(): string {
|
|
235
|
-
return this.#properties.map(([property, order]) => `${order == SortOrder.Descending ? "-" : ""}${property}`).join();
|
|
240
|
+
return this.#properties.map(([property, order]) => `${order == SortOrder.Descending ? "-" : ""}${property}`).join(",");
|
|
236
241
|
}
|
|
237
242
|
}
|
|
@@ -4,7 +4,7 @@ import {Duration} from "#Base/Duration.js";
|
|
|
4
4
|
* Downloads the specified file.
|
|
5
5
|
* @param file The file to be downloaded.
|
|
6
6
|
*/
|
|
7
|
-
export function
|
|
7
|
+
export function download(file: File): void {
|
|
8
8
|
const url = URL.createObjectURL(file);
|
|
9
9
|
const anchor = document.createElement("a");
|
|
10
10
|
anchor.download = file.name;
|
|
@@ -16,22 +16,12 @@ export function downloadFile(file: File): void {
|
|
|
16
16
|
URL.revokeObjectURL(url);
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
/**
|
|
20
|
-
* Downloads the specified text content.
|
|
21
|
-
* @param text The text content.
|
|
22
|
-
* @param fileName The file name.
|
|
23
|
-
* @param options The optional attributes for the file.
|
|
24
|
-
*/
|
|
25
|
-
export function downloadString(text: string, fileName: string, options: FilePropertyBag = {}): void {
|
|
26
|
-
downloadFile(new File([text], fileName, options));
|
|
27
|
-
}
|
|
28
|
-
|
|
29
19
|
/**
|
|
30
20
|
* Opens the specified file.
|
|
31
21
|
* @param file The file to be opened.
|
|
32
22
|
* @param options Value indicating whether to open the file in a new tab.
|
|
33
23
|
*/
|
|
34
|
-
export function
|
|
24
|
+
export function open(file: File, options: {newTab?: boolean} = {}): void {
|
|
35
25
|
const url = URL.createObjectURL(file);
|
|
36
26
|
if (!options.newTab) {
|
|
37
27
|
location.assign(url);
|
|
@@ -55,7 +45,7 @@ export function openFile(file: File, options: {newTab?: boolean} = {}): void {
|
|
|
55
45
|
* Prints the specified file.
|
|
56
46
|
* @param file The file to be printed.
|
|
57
47
|
*/
|
|
58
|
-
export function
|
|
48
|
+
export function print(file: File): void {
|
|
59
49
|
const url = URL.createObjectURL(file);
|
|
60
50
|
const frame = document.createElement("iframe");
|
|
61
51
|
frame.addEventListener("load", () => frame.contentWindow?.print());
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
1
|
+
import {MediaType} from "../Mime/MediaType.js";
|
|
2
|
+
import {HttpMethod} from "./HttpMethod.js";
|
|
3
|
+
import {HttpRequestError} from "./HttpRequestError.js";
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Performs HTTP requests.
|
|
@@ -9,7 +10,7 @@ export class HttpClient {
|
|
|
9
10
|
/**
|
|
10
11
|
* The base URL of the remote service.
|
|
11
12
|
*/
|
|
12
|
-
readonly
|
|
13
|
+
readonly baseAddress: URL;
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* The function returning the component used as loading indicator.
|
|
@@ -22,8 +23,8 @@ export class HttpClient {
|
|
|
22
23
|
*/
|
|
23
24
|
constructor(options: HttpClientOptions = {}) {
|
|
24
25
|
const url = options.baseUrl ? (options.baseUrl instanceof URL ? options.baseUrl.href : options.baseUrl) : document.baseURI;
|
|
25
|
-
this.
|
|
26
|
-
this.#loadingIndicator = options.loadingIndicator ?? (() => document.body.querySelector("loading-indicator") as ILoadingIndicator|null);
|
|
26
|
+
this.baseAddress = new URL(url.endsWith("/") ? url : `${url}/`);
|
|
27
|
+
this.#loadingIndicator = options.loadingIndicator ?? (() => document.body.querySelector("loading-indicator, .loading-indicator") as ILoadingIndicator|null);
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
/**
|
|
@@ -33,7 +34,7 @@ export class HttpClient {
|
|
|
33
34
|
* @returns The server response.
|
|
34
35
|
*/
|
|
35
36
|
delete(url?: string|URL, options?: RequestInit): Promise<Response> {
|
|
36
|
-
return this.#fetch(
|
|
37
|
+
return this.#fetch(HttpMethod.Delete, url, null, options);
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
/**
|
|
@@ -43,7 +44,7 @@ export class HttpClient {
|
|
|
43
44
|
* @returns The server response.
|
|
44
45
|
*/
|
|
45
46
|
get(url?: string|URL, options?: RequestInit): Promise<Response> {
|
|
46
|
-
return this.#fetch(
|
|
47
|
+
return this.#fetch(HttpMethod.Get, url, null, options);
|
|
47
48
|
}
|
|
48
49
|
|
|
49
50
|
/**
|
|
@@ -54,7 +55,7 @@ export class HttpClient {
|
|
|
54
55
|
* @returns The server response.
|
|
55
56
|
*/
|
|
56
57
|
patch(url?: string|URL, body?: unknown, options?: RequestInit): Promise<Response> {
|
|
57
|
-
return this.#fetch(
|
|
58
|
+
return this.#fetch(HttpMethod.Patch, url, body, options);
|
|
58
59
|
}
|
|
59
60
|
|
|
60
61
|
/**
|
|
@@ -65,7 +66,7 @@ export class HttpClient {
|
|
|
65
66
|
* @returns The server response.
|
|
66
67
|
*/
|
|
67
68
|
post(url?: string|URL, body?: unknown, options?: RequestInit): Promise<Response> {
|
|
68
|
-
return this.#fetch(
|
|
69
|
+
return this.#fetch(HttpMethod.Post, url, body, options);
|
|
69
70
|
}
|
|
70
71
|
|
|
71
72
|
/**
|
|
@@ -76,7 +77,7 @@ export class HttpClient {
|
|
|
76
77
|
* @returns The server response.
|
|
77
78
|
*/
|
|
78
79
|
put(url?: string|URL, body?: unknown, options?: RequestInit): Promise<Response> {
|
|
79
|
-
return this.#fetch(
|
|
80
|
+
return this.#fetch(HttpMethod.Put, url, body, options);
|
|
80
81
|
}
|
|
81
82
|
|
|
82
83
|
/**
|
|
@@ -89,19 +90,19 @@ export class HttpClient {
|
|
|
89
90
|
*/
|
|
90
91
|
async #fetch(method: string, url: string|URL = "", body: unknown = null, options: RequestInit = {}): Promise<Response> {
|
|
91
92
|
const headers = new Headers(options.headers);
|
|
92
|
-
if (!headers.has("
|
|
93
|
+
if (!headers.has("Accept")) headers.set("Accept", MediaType.Application.Json);
|
|
93
94
|
|
|
94
95
|
if (body && !(body instanceof Blob || body instanceof FormData || body instanceof URLSearchParams)) {
|
|
95
96
|
if (typeof body != "string") body = JSON.stringify(body);
|
|
96
|
-
if (!headers.has("
|
|
97
|
+
if (!headers.has("Content-Type")) headers.set("Content-Type", MediaType.Application.Json);
|
|
97
98
|
}
|
|
98
99
|
|
|
99
100
|
const loadingIndicator = this.#loadingIndicator();
|
|
100
101
|
try {
|
|
101
102
|
loadingIndicator?.start();
|
|
102
|
-
const request = new Request(new URL(url, this.
|
|
103
|
+
const request = new Request(new URL(url, this.baseAddress), {...options, method, headers, body} as RequestInit);
|
|
103
104
|
const response = await fetch(request);
|
|
104
|
-
if (!response.ok) throw new
|
|
105
|
+
if (!response.ok) throw new HttpRequestError(response);
|
|
105
106
|
return response;
|
|
106
107
|
}
|
|
107
108
|
finally {
|
|
@@ -125,3 +126,20 @@ export type HttpClientOptions = Partial<{
|
|
|
125
126
|
*/
|
|
126
127
|
loadingIndicator: () => ILoadingIndicator|null;
|
|
127
128
|
}>;
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* A component that shows up when an HTTP request starts, and hides when all concurrent HTTP requests are completed.
|
|
132
|
+
*/
|
|
133
|
+
export interface ILoadingIndicator {
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Starts the loading indicator.
|
|
137
|
+
*/
|
|
138
|
+
start: () => void;
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Stops the loading indicator.
|
|
142
|
+
* @param options Value indicating whether to force the loading indicator to stop.
|
|
143
|
+
*/
|
|
144
|
+
stop: (options?: {force?: boolean}) => void;
|
|
145
|
+
}
|