@cedx/base 0.22.0 → 0.24.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/UI/Components/BackButton.d.ts +6 -1
- package/lib/UI/Components/BackButton.d.ts.map +1 -1
- package/lib/UI/Components/BackButton.js +10 -2
- package/lib/UI/Components/DialogBox.js +5 -5
- package/lib/UI/Components/FullScreenToggler.d.ts +46 -0
- package/lib/UI/Components/FullScreenToggler.d.ts.map +1 -0
- package/lib/UI/Components/FullScreenToggler.js +109 -0
- package/lib/UI/Components/KeyboardAccelerator.js +1 -1
- package/lib/UI/Components/MenuActivator.d.ts +5 -0
- package/lib/UI/Components/MenuActivator.d.ts.map +1 -1
- package/lib/UI/Components/MenuActivator.js +23 -7
- package/lib/UI/Components/ThemeDropdown.js +2 -2
- package/lib/UI/Components/Toast.js +1 -1
- package/package.json +1 -1
- package/src/Client/UI/Components/BackButton.ts +11 -2
- package/src/Client/UI/Components/DialogBox.ts +5 -5
- package/src/Client/UI/Components/FullScreenToggler.ts +127 -0
- package/src/Client/UI/Components/KeyboardAccelerator.ts +1 -1
- package/src/Client/UI/Components/MenuActivator.ts +23 -6
- package/src/Client/UI/Components/ThemeDropdown.ts +2 -2
- package/src/Client/UI/Components/Toast.ts +1 -1
package/ReadMe.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# Cédric Belin's Base
|
|
2
|
-
   
|
|
3
3
|
|
|
4
4
|
Base library by [Cédric Belin](https://cedric-belin.fr), full stack developer,
|
|
5
5
|
implemented in [C#](https://learn.microsoft.com/en-us/dotnet/csharp) and [TypeScript](https://www.typescriptlang.org).
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* A component that moves back
|
|
2
|
+
* A component that moves back in the session history when clicked.
|
|
3
3
|
*/
|
|
4
4
|
export declare class BackButton extends HTMLElement {
|
|
5
5
|
/**
|
|
@@ -11,6 +11,11 @@ export declare class BackButton extends HTMLElement {
|
|
|
11
11
|
*/
|
|
12
12
|
get steps(): number;
|
|
13
13
|
set steps(value: number);
|
|
14
|
+
/**
|
|
15
|
+
* Moves back in the session history.
|
|
16
|
+
* @param event The dispatched event.
|
|
17
|
+
*/
|
|
18
|
+
goBack(event?: Event): void;
|
|
14
19
|
}
|
|
15
20
|
/**
|
|
16
21
|
* Declaration merging.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BackButton.d.ts","sourceRoot":"","sources":["../../../src/Client/UI/Components/BackButton.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,UAAW,SAAQ,WAAW;IAE1C;;OAEG;;IAaH;;OAEG;IACH,IAAI,KAAK,IAAI,MAAM,CAGlB;IACD,IAAI,KAAK,CAAC,KAAK,EAAE,MAAM,EAEtB;
|
|
1
|
+
{"version":3,"file":"BackButton.d.ts","sourceRoot":"","sources":["../../../src/Client/UI/Components/BackButton.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,UAAW,SAAQ,WAAW;IAE1C;;OAEG;;IAaH;;OAEG;IACH,IAAI,KAAK,IAAI,MAAM,CAGlB;IACD,IAAI,KAAK,CAAC,KAAK,EAAE,MAAM,EAEtB;IAED;;;OAGG;IACH,MAAM,CAAC,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI;CAI3B;AAED;;GAEG;AACH,OAAO,CAAC,MAAM,CAAC;IAEd;;OAEG;IACH,UAAU,qBAAqB;QAC9B,aAAa,EAAE,UAAU,CAAC;KAC1B;CACD"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* A component that moves back
|
|
2
|
+
* A component that moves back in the session history when clicked.
|
|
3
3
|
*/
|
|
4
4
|
export class BackButton extends HTMLElement {
|
|
5
5
|
/**
|
|
@@ -7,7 +7,7 @@ export class BackButton extends HTMLElement {
|
|
|
7
7
|
*/
|
|
8
8
|
constructor() {
|
|
9
9
|
super();
|
|
10
|
-
this.addEventListener("click", ()
|
|
10
|
+
this.addEventListener("click", this.goBack.bind(this), { capture: true });
|
|
11
11
|
}
|
|
12
12
|
/**
|
|
13
13
|
* Registers the component.
|
|
@@ -25,4 +25,12 @@ export class BackButton extends HTMLElement {
|
|
|
25
25
|
set steps(value) {
|
|
26
26
|
this.setAttribute("steps", value.toString());
|
|
27
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* Moves back in the session history.
|
|
30
|
+
* @param event The dispatched event.
|
|
31
|
+
*/
|
|
32
|
+
goBack(event) {
|
|
33
|
+
event?.stopPropagation();
|
|
34
|
+
history.go(-this.steps);
|
|
35
|
+
}
|
|
28
36
|
}
|
|
@@ -28,10 +28,10 @@ export class DialogBox extends HTMLElement {
|
|
|
28
28
|
*/
|
|
29
29
|
constructor() {
|
|
30
30
|
super();
|
|
31
|
-
this.firstElementChild.addEventListener("
|
|
32
|
-
this.querySelector(".btn-close").addEventListener("click",
|
|
31
|
+
this.firstElementChild.addEventListener("hide.bs.modal", () => this.#resolve(this.#result));
|
|
32
|
+
this.querySelector(".btn-close").addEventListener("click", this.#close.bind(this));
|
|
33
33
|
for (const button of this.querySelectorAll(".modal-footer button"))
|
|
34
|
-
button.addEventListener("click",
|
|
34
|
+
button.addEventListener("click", this.#close.bind(this));
|
|
35
35
|
}
|
|
36
36
|
/**
|
|
37
37
|
* Registers the component.
|
|
@@ -211,7 +211,7 @@ export class DialogBox extends HTMLElement {
|
|
|
211
211
|
if (message) {
|
|
212
212
|
const footer = message.footer ?? document.createDocumentFragment();
|
|
213
213
|
for (const button of footer.querySelectorAll("button"))
|
|
214
|
-
button.addEventListener("click",
|
|
214
|
+
button.addEventListener("click", this.#close.bind(this));
|
|
215
215
|
this.body = message.body;
|
|
216
216
|
this.caption = message.caption;
|
|
217
217
|
this.footer = footer;
|
|
@@ -228,7 +228,7 @@ export class DialogBox extends HTMLElement {
|
|
|
228
228
|
*/
|
|
229
229
|
#close(event) {
|
|
230
230
|
event.preventDefault();
|
|
231
|
-
this.close(event.
|
|
231
|
+
this.close(event.currentTarget.value);
|
|
232
232
|
}
|
|
233
233
|
/**
|
|
234
234
|
* Updates the title displayed in the header.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A component for toggling an element to full-screen.
|
|
3
|
+
*/
|
|
4
|
+
export declare class FullScreenToggler extends HTMLElement {
|
|
5
|
+
#private;
|
|
6
|
+
/**
|
|
7
|
+
* Creates a new full-screen toggler.
|
|
8
|
+
*/
|
|
9
|
+
constructor();
|
|
10
|
+
/**
|
|
11
|
+
* The CSS selector specifying the target element.
|
|
12
|
+
*/
|
|
13
|
+
get target(): string;
|
|
14
|
+
set target(value: string);
|
|
15
|
+
/**
|
|
16
|
+
* Value indicating whether to prevent the device screen from dimming or locking when in full-screen mode.
|
|
17
|
+
*/
|
|
18
|
+
get wakeLock(): boolean;
|
|
19
|
+
set wakeLock(value: boolean);
|
|
20
|
+
/**
|
|
21
|
+
* Method invoked when this component is connected.
|
|
22
|
+
*/
|
|
23
|
+
connectedCallback(): void;
|
|
24
|
+
/**
|
|
25
|
+
* Method invoked when this component is disconnected.
|
|
26
|
+
*/
|
|
27
|
+
disconnectedCallback(): void;
|
|
28
|
+
/**
|
|
29
|
+
* Toggles the full-screen mode of the associated element.
|
|
30
|
+
* @param event The dispatched event.
|
|
31
|
+
* @returns Resolves when the full-screen mode has been toggled.
|
|
32
|
+
*/
|
|
33
|
+
toggleFullScreen(event?: Event): Promise<void>;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Declaration merging.
|
|
37
|
+
*/
|
|
38
|
+
declare global {
|
|
39
|
+
/**
|
|
40
|
+
* The map of HTML tag names.
|
|
41
|
+
*/
|
|
42
|
+
interface HTMLElementTagNameMap {
|
|
43
|
+
"fullscreen-toggler": FullScreenToggler;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=FullScreenToggler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FullScreenToggler.d.ts","sourceRoot":"","sources":["../../../src/Client/UI/Components/FullScreenToggler.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,iBAAkB,SAAQ,WAAW;;IAYjD;;OAEG;;IAaH;;OAEG;IACH,IAAI,MAAM,IAAI,MAAM,CAGnB;IACD,IAAI,MAAM,CAAC,KAAK,EAAE,MAAM,EAEvB;IAED;;OAEG;IACH,IAAI,QAAQ,IAAI,OAAO,CAEtB;IACD,IAAI,QAAQ,CAAC,KAAK,EAAE,OAAO,EAE1B;IAED;;OAEG;IACH,iBAAiB,IAAI,IAAI;IAMzB;;OAEG;IACH,oBAAoB,IAAI,IAAI;IAK5B;;;;OAIG;IACG,gBAAgB,CAAC,KAAK,CAAC,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC;CAwCpD;AAED;;GAEG;AACH,OAAO,CAAC,MAAM,CAAC;IAEd;;OAEG;IACH,UAAU,qBAAqB;QAC9B,oBAAoB,EAAE,iBAAiB,CAAC;KACxC;CACD"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A component for toggling an element to full-screen.
|
|
3
|
+
*/
|
|
4
|
+
export class FullScreenToggler extends HTMLElement {
|
|
5
|
+
/**
|
|
6
|
+
* The target element.
|
|
7
|
+
*/
|
|
8
|
+
#element = document.body;
|
|
9
|
+
/**
|
|
10
|
+
* The handle to the underlying platform wake lock.
|
|
11
|
+
*/
|
|
12
|
+
#sentinel = null;
|
|
13
|
+
/**
|
|
14
|
+
* Creates a new full-screen toggler.
|
|
15
|
+
*/
|
|
16
|
+
constructor() {
|
|
17
|
+
super();
|
|
18
|
+
this.addEventListener("click", this.toggleFullScreen.bind(this), { capture: true }); // eslint-disable-line @typescript-eslint/no-misused-promises
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Registers the component.
|
|
22
|
+
*/
|
|
23
|
+
static {
|
|
24
|
+
customElements.define("fullscreen-toggler", this);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* The CSS selector specifying the target element.
|
|
28
|
+
*/
|
|
29
|
+
get target() {
|
|
30
|
+
const value = this.getAttribute("target") ?? "";
|
|
31
|
+
return value.trim() || "body";
|
|
32
|
+
}
|
|
33
|
+
set target(value) {
|
|
34
|
+
this.setAttribute("target", value);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Value indicating whether to prevent the device screen from dimming or locking when in full-screen mode.
|
|
38
|
+
*/
|
|
39
|
+
get wakeLock() {
|
|
40
|
+
return this.hasAttribute("wakeLock");
|
|
41
|
+
}
|
|
42
|
+
set wakeLock(value) {
|
|
43
|
+
this.toggleAttribute("target", value);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Method invoked when this component is connected.
|
|
47
|
+
*/
|
|
48
|
+
connectedCallback() {
|
|
49
|
+
document.addEventListener("visibilitychange", this.#onVisibilityChanged);
|
|
50
|
+
this.#element = document.querySelector(this.target) ?? document.body;
|
|
51
|
+
this.#element.addEventListener("fullscreenchange", this.#onFullScreenChanged);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Method invoked when this component is disconnected.
|
|
55
|
+
*/
|
|
56
|
+
disconnectedCallback() {
|
|
57
|
+
document.removeEventListener("visibilitychange", this.#onVisibilityChanged);
|
|
58
|
+
this.#element.removeEventListener("fullscreenchange", this.#onFullScreenChanged);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Toggles the full-screen mode of the associated element.
|
|
62
|
+
* @param event The dispatched event.
|
|
63
|
+
* @returns Resolves when the full-screen mode has been toggled.
|
|
64
|
+
*/
|
|
65
|
+
async toggleFullScreen(event) {
|
|
66
|
+
event?.stopPropagation();
|
|
67
|
+
if (document.fullscreenElement)
|
|
68
|
+
await document.exitFullscreen();
|
|
69
|
+
else
|
|
70
|
+
await this.#element.requestFullscreen();
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Acquires a new wake lock.
|
|
74
|
+
* @returns Resolves when the wake lock has been acquired.
|
|
75
|
+
*/
|
|
76
|
+
async #acquireWakeLock() {
|
|
77
|
+
if (this.#sentinel && !this.#sentinel.released)
|
|
78
|
+
return;
|
|
79
|
+
if (this.wakeLock)
|
|
80
|
+
this.#sentinel = await navigator.wakeLock.request();
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Acquires or releases the wake lock when the document enters or exits the full-screen mode.
|
|
84
|
+
* @param event The dispatched event.
|
|
85
|
+
*/
|
|
86
|
+
#onFullScreenChanged = () => {
|
|
87
|
+
if (document.fullscreenElement)
|
|
88
|
+
void this.#acquireWakeLock();
|
|
89
|
+
else
|
|
90
|
+
void this.#releaseWakeLock();
|
|
91
|
+
};
|
|
92
|
+
/**
|
|
93
|
+
* Eventually acquires a new wake lock when the document visibility has changed.
|
|
94
|
+
* @param event The dispatched event.
|
|
95
|
+
*/
|
|
96
|
+
#onVisibilityChanged = () => {
|
|
97
|
+
if (document.fullscreenElement && !document.hidden)
|
|
98
|
+
void this.#acquireWakeLock();
|
|
99
|
+
};
|
|
100
|
+
/**
|
|
101
|
+
* Releases the acquired wake lock.
|
|
102
|
+
* @returns Resolves when the wake lock has been released.
|
|
103
|
+
*/
|
|
104
|
+
async #releaseWakeLock() {
|
|
105
|
+
if (!this.#sentinel || this.#sentinel.released)
|
|
106
|
+
return;
|
|
107
|
+
await this.#sentinel.release();
|
|
108
|
+
}
|
|
109
|
+
}
|
|
@@ -2,10 +2,15 @@
|
|
|
2
2
|
* A component that activates the items of a menu, based on the current document URL.
|
|
3
3
|
*/
|
|
4
4
|
export declare class MenuActivator extends HTMLElement {
|
|
5
|
+
#private;
|
|
5
6
|
/**
|
|
6
7
|
* Method invoked when this component is connected.
|
|
7
8
|
*/
|
|
8
9
|
connectedCallback(): void;
|
|
10
|
+
/**
|
|
11
|
+
* Method invoked when this component is disconnected.
|
|
12
|
+
*/
|
|
13
|
+
disconnectedCallback(): void;
|
|
9
14
|
}
|
|
10
15
|
/**
|
|
11
16
|
* Declaration merging.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MenuActivator.d.ts","sourceRoot":"","sources":["../../../src/Client/UI/Components/MenuActivator.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,aAAc,SAAQ,WAAW
|
|
1
|
+
{"version":3,"file":"MenuActivator.d.ts","sourceRoot":"","sources":["../../../src/Client/UI/Components/MenuActivator.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,aAAc,SAAQ,WAAW;;IAS7C;;OAEG;IACH,iBAAiB,IAAI,IAAI;IAMzB;;OAEG;IACH,oBAAoB,IAAI,IAAI;CAgB5B;AAED;;GAEG;AACH,OAAO,CAAC,MAAM,CAAC;IAEd;;OAEG;IACH,UAAU,qBAAqB;QAC9B,gBAAgB,EAAE,aAAa,CAAC;KAChC;CACD"}
|
|
@@ -12,12 +12,28 @@ export class MenuActivator extends HTMLElement {
|
|
|
12
12
|
* Method invoked when this component is connected.
|
|
13
13
|
*/
|
|
14
14
|
connectedCallback() {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
15
|
+
this.#update();
|
|
16
|
+
addEventListener("popstate", this.#update);
|
|
17
|
+
document.body.addEventListener("htmx:afterRequest", this.#update);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Method invoked when this component is disconnected.
|
|
21
|
+
*/
|
|
22
|
+
disconnectedCallback() {
|
|
23
|
+
removeEventListener("popstate", this.#update);
|
|
24
|
+
document.body.removeEventListener("htmx:afterRequest", this.#update);
|
|
22
25
|
}
|
|
26
|
+
/**
|
|
27
|
+
* Updates this component.
|
|
28
|
+
* @param event The dispatched event.
|
|
29
|
+
*/
|
|
30
|
+
#update = () => {
|
|
31
|
+
for (const element of this.querySelectorAll(".active"))
|
|
32
|
+
element.classList.remove("active");
|
|
33
|
+
for (const element of this.querySelectorAll("a"))
|
|
34
|
+
if (element.href == location.href) {
|
|
35
|
+
element.classList.add("active");
|
|
36
|
+
element.closest(".dropdown")?.querySelector(".dropdown-toggle")?.classList.add("active");
|
|
37
|
+
}
|
|
38
|
+
};
|
|
23
39
|
}
|
|
@@ -23,7 +23,7 @@ export class ThemeDropdown extends HTMLElement {
|
|
|
23
23
|
constructor() {
|
|
24
24
|
super();
|
|
25
25
|
for (const button of this.querySelectorAll(".dropdown-menu button"))
|
|
26
|
-
button.addEventListener("click",
|
|
26
|
+
button.addEventListener("click", this.#setAppTheme.bind(this));
|
|
27
27
|
}
|
|
28
28
|
/**
|
|
29
29
|
* Registers the component.
|
|
@@ -141,7 +141,7 @@ export class ThemeDropdown extends HTMLElement {
|
|
|
141
141
|
*/
|
|
142
142
|
#setAppTheme(event) {
|
|
143
143
|
event.preventDefault();
|
|
144
|
-
this.appTheme = event.
|
|
144
|
+
this.appTheme = event.currentTarget.dataset.theme;
|
|
145
145
|
this.save();
|
|
146
146
|
}
|
|
147
147
|
/**
|
|
@@ -169,7 +169,7 @@ export class Toast extends HTMLElement {
|
|
|
169
169
|
*/
|
|
170
170
|
connectedCallback() {
|
|
171
171
|
const toast = this.firstElementChild;
|
|
172
|
-
toast.addEventListener("
|
|
172
|
+
toast.addEventListener("hide.bs.toast", () => clearInterval(this.#timer));
|
|
173
173
|
toast.addEventListener("show.bs.toast", () => this.#timer = window.setInterval(() => this.#updateElapsedTime(), 1_000));
|
|
174
174
|
this.#toast = new BootstrapToast(toast);
|
|
175
175
|
if (this.open)
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* A component that moves back
|
|
2
|
+
* A component that moves back in the session history when clicked.
|
|
3
3
|
*/
|
|
4
4
|
export class BackButton extends HTMLElement {
|
|
5
5
|
|
|
@@ -8,7 +8,7 @@ export class BackButton extends HTMLElement {
|
|
|
8
8
|
*/
|
|
9
9
|
constructor() {
|
|
10
10
|
super();
|
|
11
|
-
this.addEventListener("click", ()
|
|
11
|
+
this.addEventListener("click", this.goBack.bind(this), {capture: true});
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
/**
|
|
@@ -28,6 +28,15 @@ export class BackButton extends HTMLElement {
|
|
|
28
28
|
set steps(value: number) {
|
|
29
29
|
this.setAttribute("steps", value.toString());
|
|
30
30
|
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Moves back in the session history.
|
|
34
|
+
* @param event The dispatched event.
|
|
35
|
+
*/
|
|
36
|
+
goBack(event?: Event): void {
|
|
37
|
+
event?.stopPropagation();
|
|
38
|
+
history.go(-this.steps);
|
|
39
|
+
}
|
|
31
40
|
}
|
|
32
41
|
|
|
33
42
|
/**
|
|
@@ -81,9 +81,9 @@ export class DialogBox extends HTMLElement {
|
|
|
81
81
|
*/
|
|
82
82
|
constructor() {
|
|
83
83
|
super();
|
|
84
|
-
this.firstElementChild!.addEventListener("
|
|
85
|
-
this.querySelector(".btn-close")!.addEventListener("click",
|
|
86
|
-
for (const button of this.querySelectorAll(".modal-footer button")) button.addEventListener("click",
|
|
84
|
+
this.firstElementChild!.addEventListener("hide.bs.modal", () => this.#resolve(this.#result));
|
|
85
|
+
this.querySelector(".btn-close")!.addEventListener("click", this.#close.bind(this));
|
|
86
|
+
for (const button of this.querySelectorAll(".modal-footer button")) button.addEventListener("click", this.#close.bind(this));
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
/**
|
|
@@ -267,7 +267,7 @@ export class DialogBox extends HTMLElement {
|
|
|
267
267
|
show(message: IDialogMessage|null = null): Promise<string> {
|
|
268
268
|
if (message) {
|
|
269
269
|
const footer = message.footer ?? document.createDocumentFragment();
|
|
270
|
-
for (const button of footer.querySelectorAll("button")) button.addEventListener("click",
|
|
270
|
+
for (const button of footer.querySelectorAll("button")) button.addEventListener("click", this.#close.bind(this));
|
|
271
271
|
this.body = message.body;
|
|
272
272
|
this.caption = message.caption;
|
|
273
273
|
this.footer = footer;
|
|
@@ -286,7 +286,7 @@ export class DialogBox extends HTMLElement {
|
|
|
286
286
|
*/
|
|
287
287
|
#close(event: Event): void {
|
|
288
288
|
event.preventDefault();
|
|
289
|
-
this.close((event.
|
|
289
|
+
this.close((event.currentTarget as HTMLButtonElement).value);
|
|
290
290
|
}
|
|
291
291
|
|
|
292
292
|
/**
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A component for toggling an element to full-screen.
|
|
3
|
+
*/
|
|
4
|
+
export class FullScreenToggler extends HTMLElement {
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* The target element.
|
|
8
|
+
*/
|
|
9
|
+
#element: Element = document.body;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* The handle to the underlying platform wake lock.
|
|
13
|
+
*/
|
|
14
|
+
#sentinel: WakeLockSentinel|null = null;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Creates a new full-screen toggler.
|
|
18
|
+
*/
|
|
19
|
+
constructor() {
|
|
20
|
+
super();
|
|
21
|
+
this.addEventListener("click", this.toggleFullScreen.bind(this), {capture: true}); // eslint-disable-line @typescript-eslint/no-misused-promises
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Registers the component.
|
|
26
|
+
*/
|
|
27
|
+
static {
|
|
28
|
+
customElements.define("fullscreen-toggler", this);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* The CSS selector specifying the target element.
|
|
33
|
+
*/
|
|
34
|
+
get target(): string {
|
|
35
|
+
const value = this.getAttribute("target") ?? "";
|
|
36
|
+
return value.trim() || "body";
|
|
37
|
+
}
|
|
38
|
+
set target(value: string) {
|
|
39
|
+
this.setAttribute("target", value);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Value indicating whether to prevent the device screen from dimming or locking when in full-screen mode.
|
|
44
|
+
*/
|
|
45
|
+
get wakeLock(): boolean {
|
|
46
|
+
return this.hasAttribute("wakeLock");
|
|
47
|
+
}
|
|
48
|
+
set wakeLock(value: boolean) {
|
|
49
|
+
this.toggleAttribute("target", value);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Method invoked when this component is connected.
|
|
54
|
+
*/
|
|
55
|
+
connectedCallback(): void {
|
|
56
|
+
document.addEventListener("visibilitychange", this.#onVisibilityChanged);
|
|
57
|
+
this.#element = document.querySelector(this.target) ?? document.body;
|
|
58
|
+
this.#element.addEventListener("fullscreenchange", this.#onFullScreenChanged);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Method invoked when this component is disconnected.
|
|
63
|
+
*/
|
|
64
|
+
disconnectedCallback(): void {
|
|
65
|
+
document.removeEventListener("visibilitychange", this.#onVisibilityChanged);
|
|
66
|
+
this.#element.removeEventListener("fullscreenchange", this.#onFullScreenChanged);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Toggles the full-screen mode of the associated element.
|
|
71
|
+
* @param event The dispatched event.
|
|
72
|
+
* @returns Resolves when the full-screen mode has been toggled.
|
|
73
|
+
*/
|
|
74
|
+
async toggleFullScreen(event?: Event): Promise<void> {
|
|
75
|
+
event?.stopPropagation();
|
|
76
|
+
if (document.fullscreenElement) await document.exitFullscreen();
|
|
77
|
+
else await this.#element.requestFullscreen();
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Acquires a new wake lock.
|
|
82
|
+
* @returns Resolves when the wake lock has been acquired.
|
|
83
|
+
*/
|
|
84
|
+
async #acquireWakeLock(): Promise<void> {
|
|
85
|
+
if (this.#sentinel && !this.#sentinel.released) return;
|
|
86
|
+
if (this.wakeLock) this.#sentinel = await navigator.wakeLock.request();
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Acquires or releases the wake lock when the document enters or exits the full-screen mode.
|
|
91
|
+
* @param event The dispatched event.
|
|
92
|
+
*/
|
|
93
|
+
readonly #onFullScreenChanged: (event: Event) => void = () => {
|
|
94
|
+
if (document.fullscreenElement) void this.#acquireWakeLock();
|
|
95
|
+
else void this.#releaseWakeLock();
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Eventually acquires a new wake lock when the document visibility has changed.
|
|
100
|
+
* @param event The dispatched event.
|
|
101
|
+
*/
|
|
102
|
+
readonly #onVisibilityChanged: (event: Event) => void = () => {
|
|
103
|
+
if (document.fullscreenElement && !document.hidden) void this.#acquireWakeLock();
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Releases the acquired wake lock.
|
|
108
|
+
* @returns Resolves when the wake lock has been released.
|
|
109
|
+
*/
|
|
110
|
+
async #releaseWakeLock(): Promise<void> {
|
|
111
|
+
if (!this.#sentinel || this.#sentinel.released) return;
|
|
112
|
+
await this.#sentinel.release();
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Declaration merging.
|
|
118
|
+
*/
|
|
119
|
+
declare global {
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* The map of HTML tag names.
|
|
123
|
+
*/
|
|
124
|
+
interface HTMLElementTagNameMap {
|
|
125
|
+
"fullscreen-toggler": FullScreenToggler;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
@@ -72,7 +72,7 @@ export class KeyboardAccelerator extends HTMLElement {
|
|
|
72
72
|
if (!(modifiers & KeyboardModifiers.Alt) && event.altKey) return;
|
|
73
73
|
if (!(modifiers & KeyboardModifiers.Meta) && event.metaKey) return;
|
|
74
74
|
|
|
75
|
-
event.
|
|
75
|
+
event.stopPropagation();
|
|
76
76
|
(this.firstElementChild as HTMLElement|null)?.click();
|
|
77
77
|
}
|
|
78
78
|
}
|
|
@@ -14,13 +14,30 @@ export class MenuActivator extends HTMLElement {
|
|
|
14
14
|
* Method invoked when this component is connected.
|
|
15
15
|
*/
|
|
16
16
|
connectedCallback(): void {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
anchor.classList.add("active");
|
|
21
|
-
anchor.closest(".dropdown")?.querySelector('[data-bs-toggle="dropdown"]')?.classList.add("active");
|
|
22
|
-
}
|
|
17
|
+
this.#update();
|
|
18
|
+
addEventListener("popstate", this.#update);
|
|
19
|
+
document.body.addEventListener("htmx:afterRequest", this.#update);
|
|
23
20
|
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Method invoked when this component is disconnected.
|
|
24
|
+
*/
|
|
25
|
+
disconnectedCallback(): void {
|
|
26
|
+
removeEventListener("popstate", this.#update);
|
|
27
|
+
document.body.removeEventListener("htmx:afterRequest", this.#update);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Updates this component.
|
|
32
|
+
* @param event The dispatched event.
|
|
33
|
+
*/
|
|
34
|
+
readonly #update: (event?: Event) => void = () => {
|
|
35
|
+
for (const element of this.querySelectorAll(".active")) element.classList.remove("active");
|
|
36
|
+
for (const element of this.querySelectorAll("a")) if (element.href == location.href) {
|
|
37
|
+
element.classList.add("active");
|
|
38
|
+
element.closest(".dropdown")?.querySelector(".dropdown-toggle")?.classList.add("active");
|
|
39
|
+
}
|
|
40
|
+
};
|
|
24
41
|
}
|
|
25
42
|
|
|
26
43
|
/**
|
|
@@ -27,7 +27,7 @@ export class ThemeDropdown extends HTMLElement {
|
|
|
27
27
|
*/
|
|
28
28
|
constructor() {
|
|
29
29
|
super();
|
|
30
|
-
for (const button of this.querySelectorAll(".dropdown-menu button")) button.addEventListener("click",
|
|
30
|
+
for (const button of this.querySelectorAll(".dropdown-menu button")) button.addEventListener("click", this.#setAppTheme.bind(this));
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
/**
|
|
@@ -151,7 +151,7 @@ export class ThemeDropdown extends HTMLElement {
|
|
|
151
151
|
*/
|
|
152
152
|
#setAppTheme(event: Event): void {
|
|
153
153
|
event.preventDefault();
|
|
154
|
-
this.appTheme = (event.
|
|
154
|
+
this.appTheme = (event.currentTarget as HTMLElement).dataset.theme! as AppTheme;
|
|
155
155
|
this.save();
|
|
156
156
|
}
|
|
157
157
|
|
|
@@ -173,7 +173,7 @@ export class Toast extends HTMLElement {
|
|
|
173
173
|
*/
|
|
174
174
|
connectedCallback(): void {
|
|
175
175
|
const toast = this.firstElementChild!;
|
|
176
|
-
toast.addEventListener("
|
|
176
|
+
toast.addEventListener("hide.bs.toast", () => clearInterval(this.#timer));
|
|
177
177
|
toast.addEventListener("show.bs.toast", () => this.#timer = window.setInterval(() => this.#updateElapsedTime(), 1_000));
|
|
178
178
|
|
|
179
179
|
this.#toast = new BootstrapToast(toast);
|