underpost 3.2.4 → 3.2.8
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/.github/workflows/release.cd.yml +1 -2
- package/CHANGELOG.md +268 -1
- package/CLI-HELP.md +26 -13
- package/Dockerfile +0 -4
- package/README.md +3 -3
- package/bin/build.js +13 -3
- package/bin/deploy.js +570 -1
- package/bin/file.js +5 -0
- package/conf.js +11 -2
- package/jsconfig.json +1 -1
- package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +2 -3
- package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +2 -3
- package/manifests/deployment/dd-default-development/deployment.yaml +2 -6
- package/manifests/deployment/dd-test-development/deployment.yaml +136 -66
- package/manifests/deployment/dd-test-development/proxy.yaml +41 -5
- package/package.json +20 -11
- package/src/api/core/core.controller.js +10 -10
- package/src/api/core/core.service.js +10 -10
- package/src/api/default/default.controller.js +10 -10
- package/src/api/default/default.service.js +10 -10
- package/src/api/document/document.controller.js +12 -12
- package/src/api/document/document.model.js +10 -16
- package/src/api/file/file.controller.js +8 -8
- package/src/api/file/file.model.js +10 -10
- package/src/api/file/file.service.js +36 -36
- package/src/api/test/test.controller.js +8 -8
- package/src/api/test/test.service.js +8 -8
- package/src/api/user/guest.service.js +99 -0
- package/src/api/user/user.controller.js +6 -6
- package/src/api/user/user.model.js +8 -13
- package/src/api/user/user.service.js +3 -20
- package/src/cli/deploy.js +33 -30
- package/src/cli/fs.js +62 -5
- package/src/cli/image.js +43 -1
- package/src/cli/index.js +5 -1
- package/src/cli/release.js +58 -2
- package/src/cli/repository.js +35 -3
- package/src/cli/run.js +304 -38
- package/src/cli/ssh.js +1 -1
- package/src/cli/static.js +43 -115
- package/src/client/Default.index.js +21 -33
- package/src/client/components/core/404.js +4 -4
- package/src/client/components/core/500.js +4 -4
- package/src/client/components/core/Account.js +73 -60
- package/src/client/components/core/AgGrid.js +23 -33
- package/src/client/components/core/Alert.js +12 -13
- package/src/client/components/core/AppStore.js +1 -1
- package/src/client/components/core/Auth.js +20 -32
- package/src/client/components/core/Badge.js +7 -13
- package/src/client/components/core/BtnIcon.js +15 -17
- package/src/client/components/core/CalendarCore.js +42 -63
- package/src/client/components/core/Chat.js +13 -15
- package/src/client/components/core/ClientEvents.js +87 -0
- package/src/client/components/core/ColorPaletteElement.js +309 -0
- package/src/client/components/core/Content.js +17 -14
- package/src/client/components/core/Css.js +15 -71
- package/src/client/components/core/CssCore.js +12 -16
- package/src/client/components/core/D3Chart.js +4 -4
- package/src/client/components/core/Docs.js +60 -59
- package/src/client/components/core/DropDown.js +69 -91
- package/src/client/components/core/EventBus.js +92 -0
- package/src/client/components/core/EventsUI.js +14 -17
- package/src/client/components/core/FileExplorer.js +102 -234
- package/src/client/components/core/FullScreen.js +47 -75
- package/src/client/components/core/Input.js +24 -69
- package/src/client/components/core/Keyboard.js +25 -18
- package/src/client/components/core/KeyboardAvoidance.js +145 -0
- package/src/client/components/core/LoadingAnimation.js +25 -31
- package/src/client/components/core/LogIn.js +41 -41
- package/src/client/components/core/LogOut.js +23 -14
- package/src/client/components/core/Modal.js +397 -176
- package/src/client/components/core/NotificationManager.js +14 -18
- package/src/client/components/core/Panel.js +54 -50
- package/src/client/components/core/PanelForm.js +25 -125
- package/src/client/components/core/Polyhedron.js +110 -214
- package/src/client/components/core/PublicProfile.js +39 -32
- package/src/client/components/core/Recover.js +52 -48
- package/src/client/components/core/Responsive.js +88 -32
- package/src/client/components/core/RichText.js +9 -18
- package/src/client/components/core/Router.js +24 -3
- package/src/client/components/core/SearchBox.js +37 -37
- package/src/client/components/core/SignUp.js +39 -30
- package/src/client/components/core/SocketIo.js +31 -2
- package/src/client/components/core/SocketIoHandler.js +6 -6
- package/src/client/components/core/ToggleSwitch.js +8 -20
- package/src/client/components/core/ToolTip.js +5 -17
- package/src/client/components/core/Translate.js +56 -59
- package/src/client/components/core/Validator.js +26 -16
- package/src/client/components/core/Wallet.js +15 -26
- package/src/client/components/core/Worker.js +140 -25
- package/src/client/components/core/windowGetDimensions.js +7 -7
- package/src/client/components/default/{MenuDefault.js → AppShellDefault.js} +87 -87
- package/src/client/components/default/CssDefault.js +12 -12
- package/src/client/components/default/LogInDefault.js +6 -4
- package/src/client/components/default/LogOutDefault.js +6 -4
- package/src/client/components/default/RouterDefault.js +47 -0
- package/src/client/components/default/SettingsDefault.js +4 -4
- package/src/client/components/default/SignUpDefault.js +6 -4
- package/src/client/components/default/TranslateDefault.js +3 -3
- package/src/client/services/core/core.service.js +17 -49
- package/src/client/services/default/default.management.js +139 -242
- package/src/client/services/default/default.service.js +10 -16
- package/src/client/services/document/document.service.js +14 -19
- package/src/client/services/file/file.service.js +8 -13
- package/src/client/services/test/test.service.js +8 -13
- package/src/client/services/user/guest.service.js +79 -0
- package/src/client/services/user/user.management.js +5 -5
- package/src/client/services/user/user.service.js +14 -20
- package/src/client/ssr/body/404.js +3 -3
- package/src/client/ssr/body/500.js +3 -3
- package/src/client/ssr/body/CacheControl.js +5 -2
- package/src/client/ssr/body/DefaultSplashScreen.js +19 -12
- package/src/client/ssr/mailer/DefaultRecoverEmail.js +19 -20
- package/src/client/ssr/mailer/DefaultVerifyEmail.js +15 -16
- package/src/client/ssr/offline/Maintenance.js +12 -11
- package/src/client/ssr/offline/NoNetworkConnection.js +3 -3
- package/src/client/ssr/pages/Test.js +2 -2
- package/src/client/sw/core.sw.js +212 -0
- package/src/index.js +1 -1
- package/src/runtime/express/Dockerfile +4 -4
- package/src/runtime/lampp/Dockerfile +8 -7
- package/src/runtime/wp/Dockerfile +11 -17
- package/src/server/backup.js +1 -2
- package/src/server/client-build-docs.js +45 -46
- package/src/server/client-build.js +334 -60
- package/src/server/client-formatted.js +47 -16
- package/src/server/conf.js +29 -13
- package/src/server/cron.js +6 -8
- package/src/server/dns.js +2 -1
- package/src/server/ipfs-client.js +232 -91
- package/src/server/process.js +13 -27
- package/src/server/start.js +6 -3
- package/src/server/valkey.js +134 -235
- package/tsconfig.docs.json +15 -0
- package/typedoc.json +20 -0
- package/jsdoc.json +0 -52
- package/src/client/components/core/ColorPalette.js +0 -5267
- package/src/client/components/core/JoyStick.js +0 -80
- package/src/client/components/default/RoutesDefault.js +0 -49
- package/src/client/sw/default.sw.js +0 -127
- package/src/client/sw/template.sw.js +0 -84
|
@@ -1,12 +1,22 @@
|
|
|
1
1
|
import { cap, getId } from './CommonJs.js';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
ActiveKey
|
|
5
|
-
Event
|
|
6
|
-
|
|
2
|
+
import { KeyboardEventType, keyboardEvents } from './ClientEvents.js';
|
|
3
|
+
class Keyboard {
|
|
4
|
+
static ActiveKey = {};
|
|
5
|
+
static Event = {};
|
|
6
|
+
static onPressed(listener, options = {}) {
|
|
7
|
+
return keyboardEvents.on(KeyboardEventType.pressed, listener, options);
|
|
8
|
+
}
|
|
9
|
+
static offPressed(key) {
|
|
10
|
+
return keyboardEvents.off(key);
|
|
11
|
+
}
|
|
12
|
+
static hasPressedListener(key) {
|
|
13
|
+
return keyboardEvents.has(key);
|
|
14
|
+
}
|
|
15
|
+
static async instance() {
|
|
7
16
|
const callBackTime = 45;
|
|
8
17
|
window.onkeydown = (e = new KeyboardEvent()) => {
|
|
9
|
-
|
|
18
|
+
Keyboard.ActiveKey[e.key] = true;
|
|
19
|
+
keyboardEvents.emit(KeyboardEventType.pressed, { key: e.key, activeKeys: { ...Keyboard.ActiveKey }, event: e });
|
|
10
20
|
// e.composedPath()
|
|
11
21
|
// if (['Tab'].includes(e.key)) {
|
|
12
22
|
// e.preventDefault();
|
|
@@ -15,24 +25,23 @@ const Keyboard = {
|
|
|
15
25
|
// }
|
|
16
26
|
};
|
|
17
27
|
window.onkeyup = (e = new KeyboardEvent()) => {
|
|
18
|
-
delete
|
|
28
|
+
delete Keyboard.ActiveKey[e.key];
|
|
19
29
|
};
|
|
20
30
|
setInterval(() => {
|
|
21
|
-
Object.keys(
|
|
22
|
-
Object.keys(
|
|
23
|
-
if (activeKey in
|
|
31
|
+
Object.keys(Keyboard.Event).map((key) => {
|
|
32
|
+
Object.keys(Keyboard.ActiveKey).map((activeKey) => {
|
|
33
|
+
if (activeKey in Keyboard.Event[key]) Keyboard.Event[key][activeKey]();
|
|
24
34
|
});
|
|
25
35
|
});
|
|
26
36
|
}, callBackTime);
|
|
27
|
-
}
|
|
28
|
-
instanceMultiPressKeyTokens
|
|
29
|
-
instanceMultiPressKey
|
|
37
|
+
}
|
|
38
|
+
static instanceMultiPressKeyTokens = {};
|
|
39
|
+
static instanceMultiPressKey = (options = { keys: [], id, timePressDelay, eventCallBack: () => {} }) => {
|
|
30
40
|
if (typeof options.keys[0] === 'string') options.keys[0] = [options.keys[0]];
|
|
31
41
|
if (!options.id) options.id = getId(Keyboard.instanceMultiPressKeyTokens, 'key-press-');
|
|
32
42
|
if (!options.timePressDelay) options.timePressDelay = 500;
|
|
33
43
|
const { id, timePressDelay, keys, eventCallBack } = options;
|
|
34
44
|
Keyboard.instanceMultiPressKeyTokens[id] = { ...options };
|
|
35
|
-
|
|
36
45
|
let indexCombined = -1;
|
|
37
46
|
for (const combinedKeys of keys) {
|
|
38
47
|
indexCombined++;
|
|
@@ -58,7 +67,6 @@ const Keyboard = {
|
|
|
58
67
|
}
|
|
59
68
|
},
|
|
60
69
|
};
|
|
61
|
-
|
|
62
70
|
Keyboard.Event[`instanceMultiPressKey-${id}-${privateIndexCombined}`][key] = multiPressKey[key].trigger;
|
|
63
71
|
Keyboard.Event[`instanceMultiPressKey-${id}-${privateIndexCombined}`][key.toLowerCase()] =
|
|
64
72
|
multiPressKey[key].trigger;
|
|
@@ -67,7 +75,6 @@ const Keyboard = {
|
|
|
67
75
|
Keyboard.Event[`instanceMultiPressKey-${id}-${privateIndexCombined}`][cap(key)] = multiPressKey[key].trigger;
|
|
68
76
|
}
|
|
69
77
|
}
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
78
|
+
};
|
|
79
|
+
}
|
|
73
80
|
export { Keyboard };
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mobile virtual keyboard avoidance utility.
|
|
3
|
+
*
|
|
4
|
+
* On mobile browsers, when the software keyboard appears it reduces
|
|
5
|
+
* `window.visualViewport.height`. Without compensation, the keyboard
|
|
6
|
+
* can cover modals and form inputs so the user cannot see what they type.
|
|
7
|
+
*
|
|
8
|
+
* This module attaches to `window.visualViewport` resize/scroll events and
|
|
9
|
+
* translates a target element upward by the amount of space the keyboard has
|
|
10
|
+
* consumed. A debounce is applied so that rapid `resize` events (common on
|
|
11
|
+
* Android) do not cause visual jitter.
|
|
12
|
+
*
|
|
13
|
+
* Usage:
|
|
14
|
+
* ```js
|
|
15
|
+
* import { initKeyboardAvoidance } from './KeyboardAvoidance.js';
|
|
16
|
+
*
|
|
17
|
+
* // Attach when a modal opens:
|
|
18
|
+
* const cleanup = initKeyboardAvoidance(document.querySelector('.my-modal'));
|
|
19
|
+
*
|
|
20
|
+
* // Detach when the modal closes:
|
|
21
|
+
* cleanup();
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* @module src/client/components/core/KeyboardAvoidance.js
|
|
25
|
+
* @namespace KeyboardAvoidanceModule
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Minimum keyboard height in pixels below which we consider the keyboard
|
|
30
|
+
* to be hidden. Values smaller than this are treated as OS chrome
|
|
31
|
+
* (address bar resize, etc.) and ignored.
|
|
32
|
+
*
|
|
33
|
+
* @constant {number}
|
|
34
|
+
* @memberof KeyboardAvoidanceModule
|
|
35
|
+
*/
|
|
36
|
+
const MIN_KEYBOARD_HEIGHT_PX = 50;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Debounce delay in milliseconds applied to the `resize` handler.
|
|
40
|
+
* Prevents excessive style recalculations when the keyboard animates in.
|
|
41
|
+
*
|
|
42
|
+
* @constant {number}
|
|
43
|
+
* @memberof KeyboardAvoidanceModule
|
|
44
|
+
*/
|
|
45
|
+
const DEBOUNCE_MS = 32;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Attaches `visualViewport` listeners to translate `targetEl` when the
|
|
49
|
+
* mobile software keyboard appears.
|
|
50
|
+
*
|
|
51
|
+
* The function is a no-op in environments that do not support the
|
|
52
|
+
* `visualViewport` API (desktop browsers, some older mobile browsers).
|
|
53
|
+
*
|
|
54
|
+
* @param {HTMLElement} targetEl - The element to translate (typically a
|
|
55
|
+
* modal container or form wrapper).
|
|
56
|
+
* @param {object} [options]
|
|
57
|
+
* @param {number} [options.debounceMs=32] - Debounce delay in ms.
|
|
58
|
+
* @param {number} [options.minKeyboardPx=50] - Minimum offset to treat
|
|
59
|
+
* as a real keyboard appearance.
|
|
60
|
+
* @param {string} [options.transitionStyle='transform 0.15s ease-out'] -
|
|
61
|
+
* CSS transition applied to `targetEl` during keyboard animations.
|
|
62
|
+
* @returns {function(): void} Cleanup function — call when the element is
|
|
63
|
+
* unmounted or the modal closes to remove the event listeners.
|
|
64
|
+
*
|
|
65
|
+
* @memberof KeyboardAvoidanceModule
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* // Inside a modal's open() method:
|
|
69
|
+
* this._kbCleanup = initKeyboardAvoidance(this._el);
|
|
70
|
+
*
|
|
71
|
+
* // Inside the modal's close() method:
|
|
72
|
+
* if (this._kbCleanup) { this._kbCleanup(); this._kbCleanup = null; }
|
|
73
|
+
*/
|
|
74
|
+
export function initKeyboardAvoidance(
|
|
75
|
+
targetEl,
|
|
76
|
+
{
|
|
77
|
+
debounceMs = DEBOUNCE_MS,
|
|
78
|
+
minKeyboardPx = MIN_KEYBOARD_HEIGHT_PX,
|
|
79
|
+
transitionStyle = 'transform 0.15s ease-out',
|
|
80
|
+
} = {},
|
|
81
|
+
) {
|
|
82
|
+
// Feature-detect visualViewport. When unavailable, return a no-op cleanup.
|
|
83
|
+
if (!window.visualViewport || !targetEl) return () => {};
|
|
84
|
+
|
|
85
|
+
// Apply transition so movement feels natural.
|
|
86
|
+
const previousTransition = targetEl.style.transition;
|
|
87
|
+
targetEl.style.transition = transitionStyle;
|
|
88
|
+
|
|
89
|
+
let debounceTimer = null;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Computes the vertical offset caused by the software keyboard and
|
|
93
|
+
* applies a CSS translateY correction to `targetEl`.
|
|
94
|
+
*
|
|
95
|
+
* @returns {void}
|
|
96
|
+
* @memberof KeyboardAvoidanceModule
|
|
97
|
+
*/
|
|
98
|
+
const update = () => {
|
|
99
|
+
const offset = window.innerHeight - window.visualViewport.height - window.visualViewport.offsetTop;
|
|
100
|
+
|
|
101
|
+
if (offset > minKeyboardPx) {
|
|
102
|
+
// Keyboard is visible — push the element up.
|
|
103
|
+
targetEl.style.transform = `translateY(-${Math.round(offset)}px)`;
|
|
104
|
+
} else {
|
|
105
|
+
// Keyboard is hidden — restore original position.
|
|
106
|
+
targetEl.style.transform = '';
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Debounced wrapper for `update`.
|
|
112
|
+
* @returns {void}
|
|
113
|
+
*/
|
|
114
|
+
const onViewportChange = () => {
|
|
115
|
+
if (debounceTimer !== null) clearTimeout(debounceTimer);
|
|
116
|
+
debounceTimer = setTimeout(update, debounceMs);
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
window.visualViewport.addEventListener('resize', onViewportChange);
|
|
120
|
+
window.visualViewport.addEventListener('scroll', onViewportChange);
|
|
121
|
+
|
|
122
|
+
// Run once immediately to handle the case where the keyboard was already
|
|
123
|
+
// open when this function was called.
|
|
124
|
+
update();
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Cleanup function. Removes all listeners and restores the element's
|
|
128
|
+
* original styles.
|
|
129
|
+
*
|
|
130
|
+
* @returns {void}
|
|
131
|
+
*/
|
|
132
|
+
return () => {
|
|
133
|
+
if (debounceTimer !== null) {
|
|
134
|
+
clearTimeout(debounceTimer);
|
|
135
|
+
debounceTimer = null;
|
|
136
|
+
}
|
|
137
|
+
window.visualViewport.removeEventListener('resize', onViewportChange);
|
|
138
|
+
window.visualViewport.removeEventListener('scroll', onViewportChange);
|
|
139
|
+
// Restore previous styles.
|
|
140
|
+
targetEl.style.transform = '';
|
|
141
|
+
targetEl.style.transition = previousTransition;
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export default initKeyboardAvoidance;
|
|
@@ -4,17 +4,15 @@ import { darkTheme, renderCssAttr, subThemeManager } from './Css.js';
|
|
|
4
4
|
import { loggerFactory } from './Logger.js';
|
|
5
5
|
import { append, htmls, s } from './VanillaJs.js';
|
|
6
6
|
import { getProxyPath } from './Router.js';
|
|
7
|
-
|
|
8
7
|
const logger = loggerFactory(import.meta);
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
bar: {
|
|
8
|
+
class LoadingAnimation {
|
|
9
|
+
static bar = {
|
|
12
10
|
tokens: {},
|
|
13
11
|
getId: (id) => `bar-progress-${id.slice(1)}`,
|
|
14
12
|
play: async function (container) {
|
|
15
|
-
const id =
|
|
13
|
+
const id = LoadingAnimation.bar.getId(container);
|
|
16
14
|
const idEvent = s4() + s4() + s4();
|
|
17
|
-
|
|
15
|
+
LoadingAnimation.bar.tokens[container] = `${idEvent}`;
|
|
18
16
|
// diagonal-bar-background-animation
|
|
19
17
|
// #6d68ff #790079
|
|
20
18
|
append(
|
|
@@ -39,28 +37,27 @@ const LoadingAnimation = {
|
|
|
39
37
|
{ time: 5000, value: 1 },
|
|
40
38
|
])
|
|
41
39
|
setTimeout(() => {
|
|
42
|
-
if (
|
|
40
|
+
if (LoadingAnimation.bar.tokens[container] === idEvent && s(`.${id}`)) {
|
|
43
41
|
s(`.${id}`).style.left = `-${frame.value}%`;
|
|
44
42
|
// const percentageRender = html`${100 - frame.value}%`;
|
|
45
43
|
}
|
|
46
44
|
}, frame.time);
|
|
47
45
|
},
|
|
48
46
|
stop: function (container) {
|
|
49
|
-
const id =
|
|
50
|
-
delete
|
|
47
|
+
const id = LoadingAnimation.bar.getId(container);
|
|
48
|
+
delete LoadingAnimation.bar.tokens[container];
|
|
51
49
|
if (!s(`.${id}`)) return;
|
|
52
50
|
s(`.${id}`).style.left = '0%';
|
|
53
51
|
s(`.${id}`).style.opacity = 1;
|
|
54
52
|
setTimeout(() => (s(`.${id}`).style.opacity = 0));
|
|
55
53
|
setTimeout(() => s(`.${id}`).remove(), 400);
|
|
56
54
|
},
|
|
57
|
-
}
|
|
58
|
-
spinner
|
|
55
|
+
};
|
|
56
|
+
static spinner = {
|
|
59
57
|
getId: (id) => `spinner-progress-${id.slice(1)}`,
|
|
60
58
|
play: async function (container, spinner, options = { append: '', prepend: '' }) {
|
|
61
59
|
if (!s(container)) return;
|
|
62
|
-
const id =
|
|
63
|
-
|
|
60
|
+
const id = LoadingAnimation.spinner.getId(container);
|
|
64
61
|
let render;
|
|
65
62
|
switch (spinner) {
|
|
66
63
|
case 'dual-ring':
|
|
@@ -71,11 +68,9 @@ const LoadingAnimation = {
|
|
|
71
68
|
render = html`<div class="lds-dual-ring-mini"></div>`;
|
|
72
69
|
break;
|
|
73
70
|
}
|
|
74
|
-
|
|
75
71
|
const style = {
|
|
76
72
|
'text-align': 'center',
|
|
77
73
|
};
|
|
78
|
-
|
|
79
74
|
append(
|
|
80
75
|
container,
|
|
81
76
|
html`
|
|
@@ -93,30 +88,30 @@ const LoadingAnimation = {
|
|
|
93
88
|
if (label) label.classList.add('hide');
|
|
94
89
|
},
|
|
95
90
|
stop: function (container) {
|
|
96
|
-
const id =
|
|
91
|
+
const id = LoadingAnimation.spinner.getId(container);
|
|
97
92
|
if (!s(`.${id}`)) return;
|
|
98
93
|
s(`.${id}`).remove();
|
|
99
94
|
const label = BtnIcon.findLabel(s(container));
|
|
100
95
|
if (label) label.classList.remove('hide');
|
|
101
96
|
},
|
|
102
|
-
}
|
|
103
|
-
img
|
|
97
|
+
};
|
|
98
|
+
static img = {
|
|
104
99
|
tokens: {},
|
|
105
100
|
load: function ({ key, src, classes, style }) {
|
|
106
|
-
|
|
101
|
+
LoadingAnimation.img.tokens[key] = { src, classes, style };
|
|
107
102
|
},
|
|
108
103
|
play: function (container, key) {
|
|
109
104
|
append(
|
|
110
105
|
container,
|
|
111
106
|
html`<img
|
|
112
|
-
${
|
|
113
|
-
${
|
|
114
|
-
src="${getProxyPath()}${
|
|
107
|
+
${LoadingAnimation.img.tokens[key].classes ? `class="${LoadingAnimation.img.tokens[key].classes}"` : ''}
|
|
108
|
+
${LoadingAnimation.img.tokens[key].style ? `style="${LoadingAnimation.img.tokens[key].style}"` : ''}
|
|
109
|
+
src="${getProxyPath()}${LoadingAnimation.img.tokens[key].src}"
|
|
115
110
|
/>`,
|
|
116
111
|
);
|
|
117
112
|
},
|
|
118
|
-
}
|
|
119
|
-
barLevel
|
|
113
|
+
};
|
|
114
|
+
static barLevel = {
|
|
120
115
|
append: () => {
|
|
121
116
|
if (Array.from(sa('.ssr-loading-bar-block')).length >= 5) return;
|
|
122
117
|
s(`.ssr-blink-bar`).classList.remove('ssr-blink-bar');
|
|
@@ -125,17 +120,16 @@ const LoadingAnimation = {
|
|
|
125
120
|
clear: () => {
|
|
126
121
|
htmls('.ssr-loading-bar', html`<div class="ssr-loading-bar-block ssr-blink-bar"></div>`);
|
|
127
122
|
},
|
|
128
|
-
}
|
|
129
|
-
removeSplashScreen
|
|
123
|
+
};
|
|
124
|
+
static removeSplashScreen(backgroundContainer, callBack) {
|
|
130
125
|
if (s(`.clean-cache-container`)) s(`.clean-cache-container`).style.display = 'none';
|
|
131
126
|
if (!backgroundContainer) backgroundContainer = '.ssr-background';
|
|
132
127
|
if (s(backgroundContainer)) {
|
|
133
128
|
s(backgroundContainer).style.display = 'none';
|
|
134
129
|
if (callBack) callBack();
|
|
135
130
|
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
RenderCurrentSrcLoad: function (event) {
|
|
131
|
+
}
|
|
132
|
+
static RenderCurrentSrcLoad(event) {
|
|
139
133
|
if (s(`.ssr-loading-info`)) {
|
|
140
134
|
let nameSrcLoad = event.data.path;
|
|
141
135
|
if (nameSrcLoad) {
|
|
@@ -153,6 +147,6 @@ const LoadingAnimation = {
|
|
|
153
147
|
);
|
|
154
148
|
}
|
|
155
149
|
}
|
|
156
|
-
}
|
|
157
|
-
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
158
152
|
export { LoadingAnimation };
|
|
@@ -7,15 +7,14 @@ import { EventsUI } from './EventsUI.js';
|
|
|
7
7
|
import { Input } from './Input.js';
|
|
8
8
|
import { loggerFactory } from './Logger.js';
|
|
9
9
|
import { NotificationManager } from './NotificationManager.js';
|
|
10
|
+
import { AuthEventType, authLoginEvents } from './ClientEvents.js';
|
|
10
11
|
import { Translate } from './Translate.js';
|
|
11
12
|
import { Validator } from './Validator.js';
|
|
12
13
|
import { htmls, s } from './VanillaJs.js';
|
|
13
14
|
import { WebhookProvider } from './Webhook.js';
|
|
14
|
-
|
|
15
15
|
const logger = loggerFactory(import.meta);
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
Scope: {
|
|
16
|
+
class LogIn {
|
|
17
|
+
static Scope = {
|
|
19
18
|
user: {
|
|
20
19
|
main: {
|
|
21
20
|
model: {
|
|
@@ -23,13 +22,22 @@ const LogIn = {
|
|
|
23
22
|
},
|
|
24
23
|
},
|
|
25
24
|
},
|
|
26
|
-
}
|
|
27
|
-
Event
|
|
28
|
-
|
|
25
|
+
};
|
|
26
|
+
static Event = {};
|
|
27
|
+
static onLogin(listener, options = {}) {
|
|
28
|
+
return authLoginEvents.on(AuthEventType.login, listener, options);
|
|
29
|
+
}
|
|
30
|
+
static offLogin(key) {
|
|
31
|
+
return authLoginEvents.off(key);
|
|
32
|
+
}
|
|
33
|
+
static hasLoginListener(key) {
|
|
34
|
+
return authLoginEvents.has(key);
|
|
35
|
+
}
|
|
36
|
+
static async Trigger(options) {
|
|
29
37
|
const { user } = options;
|
|
30
|
-
if (user)
|
|
31
|
-
|
|
32
|
-
for (const eventKey of Object.keys(
|
|
38
|
+
if (user) LogIn.Scope.user.main.model.user = { ...LogIn.Scope.user.main.model.user, ...user };
|
|
39
|
+
await authLoginEvents.emit(AuthEventType.login, options);
|
|
40
|
+
for (const eventKey of Object.keys(LogIn.Event)) await LogIn.Event[eventKey](options);
|
|
33
41
|
if (!user || user.role === 'guest') return;
|
|
34
42
|
await WebhookProvider.register({ user });
|
|
35
43
|
if (s(`.session`))
|
|
@@ -56,15 +64,14 @@ const LogIn = {
|
|
|
56
64
|
}
|
|
57
65
|
</style>`,
|
|
58
66
|
);
|
|
59
|
-
if (!
|
|
67
|
+
if (!LogIn.Scope.user.main.model.user.profileImage) {
|
|
60
68
|
// Try to load profile image only if profileImageId exists
|
|
61
|
-
if (!
|
|
69
|
+
if (!LogIn.Scope.user.main.model.user.profileImage && user?.profileImageId) {
|
|
62
70
|
try {
|
|
63
71
|
const resultFile = await FileService.get({ id: user.profileImageId });
|
|
64
72
|
if (resultFile && resultFile.status === 'success' && resultFile.data[0]) {
|
|
65
73
|
const imageData = resultFile.data[0];
|
|
66
74
|
let imageSrc = null;
|
|
67
|
-
|
|
68
75
|
try {
|
|
69
76
|
// Handle new metadata-only format
|
|
70
77
|
if (!imageData.data?.data && imageData._id) {
|
|
@@ -76,9 +83,8 @@ const LogIn = {
|
|
|
76
83
|
const imageFile = new File([imageBlob], imageData.name, { type: imageData.mimetype });
|
|
77
84
|
imageSrc = URL.createObjectURL(imageFile);
|
|
78
85
|
}
|
|
79
|
-
|
|
80
86
|
if (imageSrc) {
|
|
81
|
-
|
|
87
|
+
LogIn.Scope.user.main.model.user.profileImage = {
|
|
82
88
|
resultFile,
|
|
83
89
|
imageData,
|
|
84
90
|
imageSrc,
|
|
@@ -97,8 +103,8 @@ const LogIn = {
|
|
|
97
103
|
html`<div class="abs center top-box-profile-img-container">
|
|
98
104
|
<img
|
|
99
105
|
class="abs center top-box-profile-img"
|
|
100
|
-
${
|
|
101
|
-
? `src="${
|
|
106
|
+
${LogIn.Scope.user.main.model.user.profileImage
|
|
107
|
+
? `src="${LogIn.Scope.user.main.model.user.profileImage.imageSrc}"`
|
|
102
108
|
: `src="${getApiBaseUrl({
|
|
103
109
|
id: 'assets/avatar',
|
|
104
110
|
endpoint: 'user',
|
|
@@ -107,15 +113,14 @@ const LogIn = {
|
|
|
107
113
|
</div>`,
|
|
108
114
|
);
|
|
109
115
|
}
|
|
110
|
-
}
|
|
111
|
-
|
|
116
|
+
}
|
|
117
|
+
static async instance() {
|
|
112
118
|
setTimeout(async () => {
|
|
113
119
|
const formData = [
|
|
114
120
|
{ model: 'email', id: `log-in-email`, rules: [{ type: 'isEmpty' }, { type: 'isEmail' }] },
|
|
115
121
|
{ model: 'password', id: `log-in-password`, rules: [{ type: 'isEmpty' }] },
|
|
116
122
|
];
|
|
117
123
|
const validators = await Validator.instance(formData);
|
|
118
|
-
|
|
119
124
|
EventsUI.onClick(`.btn-log-in`, async (e) => {
|
|
120
125
|
e.preventDefault();
|
|
121
126
|
const { errorMessage } = await validators();
|
|
@@ -125,88 +130,83 @@ const LogIn = {
|
|
|
125
130
|
if ('model' in inputData) body[inputData.model] = s(`.${inputData.id}`).value;
|
|
126
131
|
}
|
|
127
132
|
const result = await UserService.post({ id: 'auth', body });
|
|
128
|
-
|
|
129
133
|
if (result.status === 'error' && result.message.match('attempts')) {
|
|
130
134
|
htmls(`.login-attempt-warn-value`, result.message.split(':')[1]);
|
|
131
135
|
s(`.login-attempt-warn-container`).classList.remove('hide');
|
|
132
136
|
} else s(`.login-attempt-warn-container`).classList.add('hide');
|
|
133
|
-
|
|
134
137
|
if (result.status === 'error' && result.message.match('locked')) {
|
|
135
138
|
htmls(`.login-attempt-warn-value0`, result.message.split(':')[1]);
|
|
136
139
|
s(`.login-attempt-warn-container0`).classList.remove('hide');
|
|
137
140
|
} else s(`.login-attempt-warn-container0`).classList.add('hide');
|
|
138
|
-
|
|
139
141
|
if (result.status === 'success') await Auth.sessionIn(result);
|
|
140
142
|
NotificationManager.Push({
|
|
141
|
-
html: result.status === 'success' ? Translate.
|
|
143
|
+
html: result.status === 'success' ? Translate.instance(`${result.status}-user-log-in`) : result.message,
|
|
142
144
|
status: result.status,
|
|
143
145
|
});
|
|
144
146
|
});
|
|
145
147
|
s(`.btn-log-in-forgot-password`).onclick = () => {
|
|
146
148
|
s(`.main-btn-recover`).click();
|
|
147
149
|
};
|
|
148
|
-
|
|
149
150
|
s(`.btn-log-in-i-not-have-account`).onclick = () => {
|
|
150
151
|
s(`.main-btn-sign-up`).click();
|
|
151
152
|
};
|
|
152
153
|
});
|
|
153
154
|
return html`
|
|
154
155
|
<div class="in">
|
|
155
|
-
${await BtnIcon.
|
|
156
|
+
${await BtnIcon.instance({
|
|
156
157
|
class: 'in section-mp form-button btn-log-in-i-not-have-account',
|
|
157
|
-
label: html`<i class="fas fa-user-plus"></i> ${Translate.
|
|
158
|
+
label: html`<i class="fas fa-user-plus"></i> ${Translate.instance(`i-not-have-account`)}
|
|
158
159
|
<br />
|
|
159
|
-
${Translate.
|
|
160
|
+
${Translate.instance(`sign-up`)}`,
|
|
160
161
|
type: 'button',
|
|
161
162
|
})}
|
|
162
163
|
</div>
|
|
163
164
|
<form class="in">
|
|
164
165
|
<div class="in">
|
|
165
|
-
${await Input.
|
|
166
|
+
${await Input.instance({
|
|
166
167
|
id: `log-in-email`,
|
|
167
168
|
type: 'email',
|
|
168
|
-
label: html`<i class="fa-solid fa-envelope"></i> ${Translate.
|
|
169
|
+
label: html`<i class="fa-solid fa-envelope"></i> ${Translate.instance('email')}`,
|
|
169
170
|
containerClass: 'inl section-mp width-mini-box input-container',
|
|
170
171
|
placeholder: true,
|
|
171
172
|
autocomplete: 'email',
|
|
172
173
|
})}
|
|
173
174
|
</div>
|
|
174
175
|
<div class="in">
|
|
175
|
-
${await Input.
|
|
176
|
+
${await Input.instance({
|
|
176
177
|
id: `log-in-password`,
|
|
177
178
|
type: 'password',
|
|
178
179
|
autocomplete: 'new-password',
|
|
179
|
-
label: html`<i class="fa-solid fa-lock"></i> ${Translate.
|
|
180
|
+
label: html`<i class="fa-solid fa-lock"></i> ${Translate.instance('password')}`,
|
|
180
181
|
containerClass: 'inl section-mp width-mini-box input-container',
|
|
181
182
|
placeholder: true,
|
|
182
183
|
})}
|
|
183
184
|
</div>
|
|
184
185
|
<div class="in">
|
|
185
|
-
${await BtnIcon.
|
|
186
|
+
${await BtnIcon.instance({
|
|
186
187
|
class: 'in section-mp form-button btn-log-in-forgot-password',
|
|
187
|
-
label: html`<i class="fas fa-question-circle"></i> ${Translate.
|
|
188
|
+
label: html`<i class="fas fa-question-circle"></i> ${Translate.instance(`forgot-password`)}`,
|
|
188
189
|
type: 'button',
|
|
189
190
|
})}
|
|
190
191
|
</div>
|
|
191
192
|
<div class="in section-mp form-button login-attempt-warn-container hide">
|
|
192
|
-
<i class="fa-solid fa-triangle-exclamation"></i> ${Translate.
|
|
193
|
+
<i class="fa-solid fa-triangle-exclamation"></i> ${Translate.instance('login-attempts-remaining')}
|
|
193
194
|
<span style="color: #ed9d0f" class="login-attempt-warn-value"></span>
|
|
194
195
|
</div>
|
|
195
196
|
<div class="in section-mp form-button login-attempt-warn-container0 hide">
|
|
196
|
-
<i class="fa-solid fa-triangle-exclamation"></i> ${Translate.
|
|
197
|
+
<i class="fa-solid fa-triangle-exclamation"></i> ${Translate.instance('account-locked-try-again-in')}
|
|
197
198
|
<span style="color: #ed9d0f" class="login-attempt-warn-value0"></span>
|
|
198
199
|
</div>
|
|
199
200
|
|
|
200
201
|
<div class="in">
|
|
201
|
-
${await BtnIcon.
|
|
202
|
+
${await BtnIcon.instance({
|
|
202
203
|
class: 'in section-mp form-button btn-log-in',
|
|
203
|
-
label: Translate.
|
|
204
|
+
label: Translate.instance('log-in'),
|
|
204
205
|
type: 'submit',
|
|
205
206
|
})}
|
|
206
207
|
</div>
|
|
207
208
|
</form>
|
|
208
209
|
`;
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
212
|
export { LogIn };
|
|
@@ -1,16 +1,26 @@
|
|
|
1
1
|
import { Auth } from './Auth.js';
|
|
2
2
|
import { BtnIcon } from './BtnIcon.js';
|
|
3
|
+
import { AuthEventType, authLogoutEvents } from './ClientEvents.js';
|
|
3
4
|
import { LogIn } from './LogIn.js';
|
|
4
5
|
import { Translate } from './Translate.js';
|
|
5
6
|
import { htmls, s } from './VanillaJs.js';
|
|
6
7
|
import { WebhookProvider } from './Webhook.js';
|
|
7
8
|
import { NotificationManager } from './NotificationManager.js';
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
class LogOut {
|
|
10
|
+
static Event = {};
|
|
11
|
+
static onLogout(listener, options = {}) {
|
|
12
|
+
return authLogoutEvents.on(AuthEventType.logout, listener, options);
|
|
13
|
+
}
|
|
14
|
+
static offLogout(key) {
|
|
15
|
+
return authLogoutEvents.off(key);
|
|
16
|
+
}
|
|
17
|
+
static hasLogoutListener(key) {
|
|
18
|
+
return authLogoutEvents.has(key);
|
|
19
|
+
}
|
|
20
|
+
static async Trigger(options) {
|
|
12
21
|
await WebhookProvider.unregister();
|
|
13
|
-
|
|
22
|
+
await authLogoutEvents.emit(AuthEventType.logout, options);
|
|
23
|
+
for (const eventKey of Object.keys(LogOut.Event)) await LogOut.Event[eventKey](options);
|
|
14
24
|
if (s(`.session`))
|
|
15
25
|
htmls(
|
|
16
26
|
`.session`,
|
|
@@ -35,29 +45,28 @@ const LogOut = {
|
|
|
35
45
|
}
|
|
36
46
|
</style>`,
|
|
37
47
|
);
|
|
38
|
-
}
|
|
39
|
-
|
|
48
|
+
}
|
|
49
|
+
static async instance() {
|
|
40
50
|
setTimeout(() => {
|
|
41
51
|
s('.btn-log-out').onclick = async (e) => {
|
|
42
52
|
e.preventDefault();
|
|
43
53
|
await Auth.sessionOut();
|
|
44
54
|
NotificationManager.Push({
|
|
45
|
-
html: Translate.
|
|
55
|
+
html: Translate.instance(`success-logout`),
|
|
46
56
|
status: 'success',
|
|
47
57
|
});
|
|
48
58
|
};
|
|
49
59
|
});
|
|
50
|
-
// Translate.
|
|
60
|
+
// Translate.instance('confirm-logout')
|
|
51
61
|
return html` <form class="in">
|
|
52
62
|
<div class="in">
|
|
53
|
-
${await BtnIcon.
|
|
63
|
+
${await BtnIcon.instance({
|
|
54
64
|
class: 'inl section-mp btn-custom btn-log-out',
|
|
55
|
-
label: html`<i class="fa-solid fa-power-off"></i> ${Translate.
|
|
65
|
+
label: html`<i class="fa-solid fa-power-off"></i> ${Translate.instance('log-out')}`,
|
|
56
66
|
type: 'submit',
|
|
57
67
|
})}
|
|
58
68
|
</div>
|
|
59
69
|
</form>`;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
70
|
+
}
|
|
71
|
+
}
|
|
63
72
|
export { LogOut };
|