underpost 3.2.5 → 3.2.9
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 +351 -1
- package/CLI-HELP.md +40 -13
- package/Dockerfile +0 -4
- package/README.md +4 -4
- package/bin/build.js +14 -5
- package/bin/deploy.js +570 -1
- package/bin/file.js +6 -0
- package/conf.js +11 -2
- package/jsconfig.json +1 -1
- package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +2 -2
- package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +2 -2
- 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 +24 -15
- package/scripts/k3s-node-setup.sh +2 -2
- package/scripts/nat-iptables.sh +103 -18
- 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/cluster.js +61 -14
- package/src/cli/db.js +47 -2
- package/src/cli/deploy.js +67 -35
- package/src/cli/fs.js +79 -8
- package/src/cli/image.js +43 -1
- package/src/cli/index.js +26 -1
- package/src/cli/release.js +57 -1
- package/src/cli/repository.js +69 -31
- package/src/cli/run.js +415 -36
- 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 +35 -37
- 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 +64 -91
- 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 +96 -228
- 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 +462 -178
- 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 +48 -44
- 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 +163 -27
- 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 +159 -267
- 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 +86 -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/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 +5 -4
- package/src/server/data-query.js +32 -20
- package/src/server/dns.js +22 -0
- package/src/server/ipfs-client.js +232 -91
- package/src/server/process.js +13 -27
- package/src/server/start.js +17 -3
- package/src/server/valkey.js +141 -235
- package/tsconfig.docs.json +15 -0
- package/typedoc.json +29 -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,23 +1,18 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { Css, darkTheme, renderCssAttr, simpleIconsRender, ThemeEvents, Themes } from './Css.js';
|
|
4
|
-
import { buildBadgeToolTipMenuOption, Modal, renderViewTitle } from './Modal.js';
|
|
1
|
+
import { Css, darkTheme, simpleIconsRender, ThemeEvents, Themes } from './Css.js';
|
|
2
|
+
import { Modal, renderViewTitle } from './Modal.js';
|
|
5
3
|
import { listenQueryPathInstance, setQueryPath, closeModalRouteChangeEvent, getProxyPath } from './Router.js';
|
|
6
|
-
import {
|
|
7
|
-
|
|
4
|
+
import { s, sIframe } from './VanillaJs.js';
|
|
8
5
|
// https://mintlify.com/docs/quickstart
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const docData = this.Data.find((d) => d.type === type);
|
|
6
|
+
class Docs {
|
|
7
|
+
static async RenderModal(type) {
|
|
8
|
+
const docData = Docs.Data.find((d) => d.type === type);
|
|
13
9
|
const ModalId = `modal-docs-${docData.type}`;
|
|
14
10
|
const { barConfig } = await Themes[Css.currentTheme]();
|
|
15
11
|
const parentBarMode =
|
|
16
12
|
Modal.Data['modal-docs'] && Modal.Data['modal-docs'].options.barMode
|
|
17
13
|
? Modal.Data['modal-docs'].options.barMode
|
|
18
14
|
: undefined;
|
|
19
|
-
|
|
20
|
-
await Modal.Render({
|
|
15
|
+
await Modal.instance({
|
|
21
16
|
barConfig,
|
|
22
17
|
title: renderViewTitle(docData),
|
|
23
18
|
id: ModalId,
|
|
@@ -51,7 +46,15 @@ const Docs = {
|
|
|
51
46
|
});
|
|
52
47
|
const iframeEl = s(`.iframe-${ModalId}`);
|
|
53
48
|
let swaggerThemeEventKey = null;
|
|
49
|
+
let unbindIframeLayoutSync = null;
|
|
54
50
|
if (iframeEl) {
|
|
51
|
+
const scheduleViewLayoutSync = () => {
|
|
52
|
+
const sync = () => Modal.syncViewLayout();
|
|
53
|
+
sync();
|
|
54
|
+
setTimeout(sync, 0);
|
|
55
|
+
setTimeout(sync, 120);
|
|
56
|
+
setTimeout(sync, 400);
|
|
57
|
+
};
|
|
55
58
|
iframeEl.addEventListener('load', () => {
|
|
56
59
|
try {
|
|
57
60
|
const iframeWin = iframeEl.contentWindow;
|
|
@@ -62,11 +65,34 @@ const Docs = {
|
|
|
62
65
|
} catch (e) {
|
|
63
66
|
// cross-origin or security restriction — safe to ignore
|
|
64
67
|
}
|
|
65
|
-
window.
|
|
68
|
+
// Keep the parent window scroll untouched.
|
|
69
|
+
// These modals are fixed-position; scrolling the parent on iframe navigation
|
|
70
|
+
// shifts Chrome layout calculations and leaves view modals offset by 50px.
|
|
66
71
|
// Bind Shift+K inside the iframe to focus the parent SearchBox (mirrors app-wide shortcut)
|
|
67
72
|
try {
|
|
73
|
+
const iframeWin = iframeEl.contentWindow;
|
|
68
74
|
const iframeDoc = iframeEl.contentDocument || iframeEl.contentWindow?.document;
|
|
69
75
|
if (iframeDoc) {
|
|
76
|
+
if (unbindIframeLayoutSync) unbindIframeLayoutSync();
|
|
77
|
+
const onIframeAnchorClick = (e) => {
|
|
78
|
+
if (e.target && e.target.closest && e.target.closest('a')) {
|
|
79
|
+
scheduleViewLayoutSync();
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
const onIframeHashChange = () => scheduleViewLayoutSync();
|
|
83
|
+
const onIframePopState = () => scheduleViewLayoutSync();
|
|
84
|
+
iframeDoc.addEventListener('click', onIframeAnchorClick, true);
|
|
85
|
+
if (iframeWin) {
|
|
86
|
+
iframeWin.addEventListener('hashchange', onIframeHashChange);
|
|
87
|
+
iframeWin.addEventListener('popstate', onIframePopState);
|
|
88
|
+
}
|
|
89
|
+
unbindIframeLayoutSync = () => {
|
|
90
|
+
iframeDoc.removeEventListener('click', onIframeAnchorClick, true);
|
|
91
|
+
if (iframeWin) {
|
|
92
|
+
iframeWin.removeEventListener('hashchange', onIframeHashChange);
|
|
93
|
+
iframeWin.removeEventListener('popstate', onIframePopState);
|
|
94
|
+
}
|
|
95
|
+
};
|
|
70
96
|
iframeDoc.addEventListener('keydown', (e) => {
|
|
71
97
|
if (e.shiftKey && e.key.toLowerCase() === 'k') {
|
|
72
98
|
e.preventDefault();
|
|
@@ -85,48 +111,30 @@ const Docs = {
|
|
|
85
111
|
} catch (e) {
|
|
86
112
|
// cross-origin or security restriction — safe to ignore
|
|
87
113
|
}
|
|
114
|
+
scheduleViewLayoutSync();
|
|
88
115
|
});
|
|
89
|
-
|
|
90
116
|
if (type === 'src') {
|
|
91
117
|
swaggerThemeEventKey = `jsdocs-iframe-${ModalId}`;
|
|
92
|
-
|
|
93
118
|
const applyJsDocsTheme = (isDark) => {
|
|
94
119
|
try {
|
|
95
|
-
const
|
|
96
|
-
if (!
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
iframeWin.updateTheme(theme);
|
|
101
|
-
} else {
|
|
102
|
-
// Fallback: replicate localUpdateTheme manually
|
|
103
|
-
const iframeDoc = iframeEl.contentDocument || iframeWin.document;
|
|
104
|
-
if (!iframeDoc || !iframeDoc.body) return;
|
|
105
|
-
iframeDoc.body.setAttribute('data-theme', theme);
|
|
106
|
-
iframeDoc.body.classList.remove('dark', 'light');
|
|
107
|
-
iframeDoc.body.classList.add(theme);
|
|
108
|
-
const iconID = isDark ? '#light-theme-icon' : '#dark-theme-icon';
|
|
109
|
-
const svgUses = sIframe(iframeEl, '.theme-svg-use') ? iframeDoc.querySelectorAll('.theme-svg-use') : [];
|
|
110
|
-
svgUses.forEach((svg) => svg.setAttribute('xlink:href', iconID));
|
|
111
|
-
iframeWin.localStorage?.setItem('theme', theme);
|
|
112
|
-
}
|
|
120
|
+
const iframeDoc = iframeEl.contentDocument || iframeEl.contentWindow?.document;
|
|
121
|
+
if (!iframeDoc || !iframeDoc.documentElement) return;
|
|
122
|
+
// TypeDoc built-in theme: data-theme on <html>, stored as 'tsd-theme' in localStorage
|
|
123
|
+
iframeDoc.documentElement.setAttribute('data-theme', isDark ? 'dark' : 'light');
|
|
124
|
+
iframeEl.contentWindow?.localStorage?.setItem('tsd-theme', isDark ? 'dark' : 'light');
|
|
113
125
|
} catch (e) {
|
|
114
126
|
// cross-origin or security restriction — safe to ignore
|
|
115
127
|
}
|
|
116
128
|
};
|
|
117
|
-
|
|
118
129
|
// Apply current theme as soon as the iframe content is ready
|
|
119
130
|
iframeEl.addEventListener('load', () => applyJsDocsTheme(darkTheme));
|
|
120
|
-
|
|
121
131
|
// Keep in sync whenever the parent page theme changes
|
|
122
132
|
ThemeEvents[swaggerThemeEventKey] = () => {
|
|
123
133
|
if (s(`.iframe-${ModalId}`)) applyJsDocsTheme(darkTheme);
|
|
124
134
|
};
|
|
125
135
|
}
|
|
126
|
-
|
|
127
136
|
if (type === 'api') {
|
|
128
137
|
swaggerThemeEventKey = `swagger-iframe-${ModalId}`;
|
|
129
|
-
|
|
130
138
|
const applySwaggerTheme = (isDark) => {
|
|
131
139
|
try {
|
|
132
140
|
const iframeDoc = iframeEl.contentDocument || iframeEl.contentWindow?.document;
|
|
@@ -143,10 +151,8 @@ const Docs = {
|
|
|
143
151
|
// cross-origin or security restriction — safe to ignore
|
|
144
152
|
}
|
|
145
153
|
};
|
|
146
|
-
|
|
147
154
|
// Apply current theme as soon as the iframe content is ready
|
|
148
155
|
iframeEl.addEventListener('load', () => applySwaggerTheme(darkTheme));
|
|
149
|
-
|
|
150
156
|
// Keep in sync whenever the parent page theme changes
|
|
151
157
|
ThemeEvents[swaggerThemeEventKey] = () => {
|
|
152
158
|
if (s(`.iframe-${ModalId}`)) applySwaggerTheme(darkTheme);
|
|
@@ -159,7 +165,6 @@ const Docs = {
|
|
|
159
165
|
const barHeight = barEl ? barEl.offsetHeight : Modal.headerTitleHeight;
|
|
160
166
|
s(`.iframe-${ModalId}`).style.height = `${s(`.${ModalId}`).offsetHeight - barHeight}px`;
|
|
161
167
|
}
|
|
162
|
-
|
|
163
168
|
if (type.match('coverage')) {
|
|
164
169
|
simpleIconsRender(`.doc-icon-coverage`);
|
|
165
170
|
simpleIconsRender(`.doc-icon-coverage-link`);
|
|
@@ -167,11 +172,12 @@ const Docs = {
|
|
|
167
172
|
};
|
|
168
173
|
Modal.Data[ModalId].onObserverListener[ModalId]();
|
|
169
174
|
Modal.Data[ModalId].onCloseListener[ModalId] = () => {
|
|
175
|
+
if (unbindIframeLayoutSync) unbindIframeLayoutSync();
|
|
170
176
|
if (swaggerThemeEventKey) delete ThemeEvents[swaggerThemeEventKey];
|
|
171
177
|
closeModalRouteChangeEvent({ closedId: ModalId });
|
|
172
178
|
};
|
|
173
|
-
}
|
|
174
|
-
Data
|
|
179
|
+
}
|
|
180
|
+
static Data = [
|
|
175
181
|
{
|
|
176
182
|
type: 'repo',
|
|
177
183
|
icon: html`<i class="fab fa-github"></i>`,
|
|
@@ -238,38 +244,36 @@ const Docs = {
|
|
|
238
244
|
if (s(`.doc-icon-coverage-link`)) setTimeout(() => simpleIconsRender(`.doc-icon-coverage-link`));
|
|
239
245
|
},
|
|
240
246
|
},
|
|
241
|
-
]
|
|
242
|
-
Tokens
|
|
243
|
-
|
|
247
|
+
];
|
|
248
|
+
static Tokens = {};
|
|
249
|
+
static async instance(options = {}) {
|
|
244
250
|
const { idModal } = options;
|
|
245
|
-
|
|
251
|
+
Docs.Tokens[idModal] = options;
|
|
246
252
|
setTimeout(() => {
|
|
247
253
|
s(`.btn-docs-src`).onclick = async () => {
|
|
248
254
|
setQueryPath({ path: 'docs', queryPath: 'src' });
|
|
249
|
-
await
|
|
255
|
+
await Docs.RenderModal('src');
|
|
250
256
|
};
|
|
251
257
|
s(`.btn-docs-api`).onclick = async () => {
|
|
252
258
|
setQueryPath({ path: 'docs', queryPath: 'api' });
|
|
253
|
-
await
|
|
259
|
+
await Docs.RenderModal('api');
|
|
254
260
|
};
|
|
255
261
|
s(`.btn-docs-coverage`).onclick = async () => {
|
|
256
262
|
setQueryPath({ path: 'docs', queryPath: 'coverage' });
|
|
257
|
-
await
|
|
263
|
+
await Docs.RenderModal('coverage');
|
|
258
264
|
};
|
|
259
|
-
|
|
260
265
|
s(`.btn-docs-coverage-link`).onclick = () => {
|
|
261
|
-
const docData =
|
|
266
|
+
const docData = Docs.Data.find((d) => d.type === 'coverage-link');
|
|
262
267
|
location.href = docData.url();
|
|
263
268
|
};
|
|
264
269
|
s(`.btn-docs-repo`).onclick = () => {
|
|
265
|
-
const docData =
|
|
270
|
+
const docData = Docs.Data.find((d) => d.type === 'repo');
|
|
266
271
|
location.href = docData.url();
|
|
267
272
|
};
|
|
268
273
|
s(`.btn-docs-demo`).onclick = () => {
|
|
269
|
-
const docData =
|
|
274
|
+
const docData = Docs.Data.find((d) => d.type === 'demo');
|
|
270
275
|
location.href = docData.url();
|
|
271
276
|
};
|
|
272
|
-
|
|
273
277
|
listenQueryPathInstance({
|
|
274
278
|
id: options.idModal,
|
|
275
279
|
routeId: 'docs',
|
|
@@ -283,44 +287,15 @@ const Docs = {
|
|
|
283
287
|
},
|
|
284
288
|
});
|
|
285
289
|
});
|
|
286
|
-
|
|
287
|
-
for (const docData of
|
|
290
|
+
// Register theme events for items that have them (Docs-specific concern)
|
|
291
|
+
for (const docData of Docs.Data) {
|
|
288
292
|
if (docData.themeEvent) {
|
|
289
293
|
ThemeEvents[`doc-icon-${docData.type}`] = docData.themeEvent;
|
|
290
294
|
setTimeout(ThemeEvents[`doc-icon-${docData.type}`]);
|
|
291
295
|
}
|
|
292
|
-
let tabHref, style, labelStyle;
|
|
293
|
-
switch (docData.type) {
|
|
294
|
-
case 'repo':
|
|
295
|
-
case 'coverage-link':
|
|
296
|
-
style = renderCssAttr({ style: { height: '45px' } });
|
|
297
|
-
labelStyle = renderCssAttr({ style: { top: '8px', left: '9px' } });
|
|
298
|
-
break;
|
|
299
|
-
|
|
300
|
-
default:
|
|
301
|
-
break;
|
|
302
|
-
}
|
|
303
|
-
tabHref = docData.url();
|
|
304
|
-
const subMenuIcon =
|
|
305
|
-
options.subMenuIcon && typeof options.subMenuIcon === 'function'
|
|
306
|
-
? options.subMenuIcon(docData.type)
|
|
307
|
-
: docData.icon;
|
|
308
|
-
docMenuRender += html`
|
|
309
|
-
${await BtnIcon.Render({
|
|
310
|
-
class: `in wfa main-btn-menu submenu-btn btn-docs btn-docs-${docData.type}`,
|
|
311
|
-
label: html`<span class="inl menu-btn-icon">${subMenuIcon}</span
|
|
312
|
-
><span class="menu-label-text menu-label-text-docs"> ${docData.text} </span>`,
|
|
313
|
-
tabHref,
|
|
314
|
-
tooltipHtml: await Badge.Render(buildBadgeToolTipMenuOption(docData.text, 'right')),
|
|
315
|
-
useMenuBtn: true,
|
|
316
|
-
})}
|
|
317
|
-
`;
|
|
318
296
|
}
|
|
319
|
-
//
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
htmls('.menu-btn-container-children-docs', docMenuRender);
|
|
323
|
-
|
|
297
|
+
// Build submenu items and populate — submenu system is owned by Modal
|
|
298
|
+
Modal.subMenuPopulate('docs', await Modal.buildSubMenuItemsHtml('docs', Docs.Data, options));
|
|
324
299
|
{
|
|
325
300
|
const docsData = [
|
|
326
301
|
{
|
|
@@ -360,7 +335,6 @@ const Docs = {
|
|
|
360
335
|
description: 'Join our developer community',
|
|
361
336
|
},
|
|
362
337
|
];
|
|
363
|
-
|
|
364
338
|
return html`
|
|
365
339
|
<style>
|
|
366
340
|
.docs-landing {
|
|
@@ -499,7 +473,6 @@ const Docs = {
|
|
|
499
473
|
</div>
|
|
500
474
|
`;
|
|
501
475
|
}
|
|
502
|
-
}
|
|
503
|
-
}
|
|
504
|
-
|
|
476
|
+
}
|
|
477
|
+
}
|
|
505
478
|
export { Docs };
|
|
@@ -5,18 +5,16 @@ import { Input } from './Input.js';
|
|
|
5
5
|
import { ToggleSwitch } from './ToggleSwitch.js';
|
|
6
6
|
import { Translate } from './Translate.js';
|
|
7
7
|
import { s, htmls } from './VanillaJs.js';
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
this.Tokens[id] = {
|
|
8
|
+
class DropDown {
|
|
9
|
+
static Tokens = {};
|
|
10
|
+
static async instance(options) {
|
|
11
|
+
const id = options.id ? options.id : getId(DropDown.Tokens, 'dropdown-');
|
|
12
|
+
DropDown.Tokens[id] = {
|
|
14
13
|
onClickEvents: {},
|
|
15
14
|
lastSelectValue: undefined,
|
|
16
15
|
oncheckvalues: {},
|
|
17
16
|
originData: options.data ? newInstance(options.data) : [],
|
|
18
17
|
};
|
|
19
|
-
|
|
20
18
|
const _renderSelectedBadges = async () => {
|
|
21
19
|
if (options.type !== 'checkbox') return;
|
|
22
20
|
const container = s(`.dropdown-current-${id}`);
|
|
@@ -29,7 +27,7 @@ const DropDown = {
|
|
|
29
27
|
let badgesHtml = '';
|
|
30
28
|
for (const [key, val] of selected) {
|
|
31
29
|
badgesHtml += html`<span class="inl" style="display:inline-flex;align-items:center;margin:2px;">
|
|
32
|
-
${await Badge.
|
|
30
|
+
${await Badge.instance({
|
|
33
31
|
text: html`<i class="fa-solid fa-tag" style="margin-right:3px;font-size:9px;"></i>${val.display}`,
|
|
34
32
|
style: {
|
|
35
33
|
background: darkTheme ? '#335' : '#cde',
|
|
@@ -67,12 +65,11 @@ const DropDown = {
|
|
|
67
65
|
});
|
|
68
66
|
};
|
|
69
67
|
DropDown.Tokens[id]._renderSelectedBadges = _renderSelectedBadges;
|
|
70
|
-
|
|
71
68
|
options.data.push({
|
|
72
69
|
value: 'reset',
|
|
73
|
-
display: html`<i class="fa-solid fa-broom"></i> ${Translate.
|
|
70
|
+
display: html`<i class="fa-solid fa-broom"></i> ${Translate.instance('clear')}`,
|
|
74
71
|
onClick: () => {
|
|
75
|
-
console.log('DropDown onClick',
|
|
72
|
+
console.log('DropDown onClick', DropDown.value);
|
|
76
73
|
if (options && options.resetOnClick) options.resetOnClick();
|
|
77
74
|
if (options && options.type === 'checkbox') {
|
|
78
75
|
DropDown.Tokens[id].oncheckvalues = {};
|
|
@@ -93,92 +90,85 @@ const DropDown = {
|
|
|
93
90
|
}
|
|
94
91
|
}
|
|
95
92
|
}
|
|
96
|
-
} else
|
|
93
|
+
} else DropDown.Tokens[id].value = undefined;
|
|
97
94
|
},
|
|
98
95
|
});
|
|
99
|
-
|
|
100
96
|
if (!(options && options.disableClose))
|
|
101
97
|
options.data.push({
|
|
102
98
|
value: 'close',
|
|
103
|
-
display: html`<i class="fa-solid fa-xmark"></i> ${Translate.
|
|
99
|
+
display: html`<i class="fa-solid fa-xmark"></i> ${Translate.instance('close')}`,
|
|
104
100
|
onClick: function () {
|
|
105
|
-
console.log('DropDown onClick',
|
|
101
|
+
console.log('DropDown onClick', DropDown.value);
|
|
106
102
|
},
|
|
107
103
|
});
|
|
108
|
-
|
|
109
104
|
const switchOptionsPanel = () => {
|
|
110
105
|
if (Array.from(s(`.dropdown-option-${id}`).classList).includes('hide'))
|
|
111
106
|
s(`.dropdown-option-${id}`).classList.remove('hide');
|
|
112
107
|
else s(`.dropdown-option-${id}`).classList.add('hide');
|
|
113
108
|
};
|
|
114
|
-
|
|
115
109
|
const _render = async (data) => {
|
|
116
110
|
let render = '';
|
|
117
111
|
let index = -1;
|
|
118
112
|
for (const optionData of data) {
|
|
119
113
|
index++;
|
|
120
114
|
const i = index;
|
|
121
|
-
const
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
(
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
ToggleSwitch.Tokens[`checkbox-role-${valueDisplay}`]
|
|
140
|
-
|
|
141
|
-
if (optionData.value !== '
|
|
142
|
-
if (
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
this.Tokens[id].onClickEvents[`dropdown-option-${valueDisplay}`] = onclick;
|
|
167
|
-
|
|
168
|
-
s(`.dropdown-option-${id}-${i}`).onclick = onclick;
|
|
169
|
-
});
|
|
115
|
+
const optionValue = typeof optionData.value === 'string' ? optionData.value : `option-${i}`;
|
|
116
|
+
const valueDisplay = optionValue.trim().replaceAll(' ', '-');
|
|
117
|
+
const isGroup = optionData.kind === 'group' || optionData.nonSelectable === true;
|
|
118
|
+
if (!isGroup) {
|
|
119
|
+
setTimeout(() => {
|
|
120
|
+
const onclick = async (e) => {
|
|
121
|
+
if (options && options.lastSelectClass && s(`.dropdown-option-${DropDown.Tokens[id].lastSelectValue}`)) {
|
|
122
|
+
s(`.dropdown-option-${DropDown.Tokens[id].lastSelectValue}`).classList.remove(options.lastSelectClass);
|
|
123
|
+
}
|
|
124
|
+
DropDown.Tokens[id].lastSelectValue = valueDisplay;
|
|
125
|
+
if (options && options.lastSelectClass && s(`.dropdown-option-${DropDown.Tokens[id].lastSelectValue}`)) {
|
|
126
|
+
s(`.dropdown-option-${DropDown.Tokens[id].lastSelectValue}`).classList.add(options.lastSelectClass);
|
|
127
|
+
}
|
|
128
|
+
if (
|
|
129
|
+
!(options && options.disableClose) &&
|
|
130
|
+
(options.type !== 'checkbox' || optionData.value === 'close' || optionData.value === 'reset')
|
|
131
|
+
)
|
|
132
|
+
s(`.dropdown-option-${id}`).classList.add('hide');
|
|
133
|
+
if (options.type === 'checkbox' && ToggleSwitch.Tokens[`checkbox-role-${valueDisplay}`])
|
|
134
|
+
ToggleSwitch.Tokens[`checkbox-role-${valueDisplay}`].click();
|
|
135
|
+
if (optionData.value !== 'close') {
|
|
136
|
+
if (optionData.value !== 'reset') {
|
|
137
|
+
if (options.type === 'checkbox') {
|
|
138
|
+
_renderSelectedBadges();
|
|
139
|
+
} else {
|
|
140
|
+
htmls(`.dropdown-current-${id}`, optionData.display);
|
|
141
|
+
}
|
|
142
|
+
} else htmls(`.dropdown-current-${id}`, '');
|
|
143
|
+
DropDown.Tokens[id].value =
|
|
144
|
+
options.type === 'checkbox'
|
|
145
|
+
? options.serviceProvider
|
|
146
|
+
? Object.values(DropDown.Tokens[id].oncheckvalues).map((v) => v.data)
|
|
147
|
+
: data.filter((d) => d.checked).map((d) => d.data)
|
|
148
|
+
: optionData.data;
|
|
149
|
+
console.warn('current value dropdown id:' + id, DropDown.Tokens[id].value);
|
|
150
|
+
s(`.${id}`).value = DropDown.Tokens[id].value;
|
|
151
|
+
optionData.onClick(e);
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
DropDown.Tokens[id].onClickEvents[`dropdown-option-${id}-${i}`] = onclick;
|
|
155
|
+
DropDown.Tokens[id].onClickEvents[`dropdown-option-${id}-${valueDisplay}`] = onclick;
|
|
156
|
+
DropDown.Tokens[id].onClickEvents[`dropdown-option-${valueDisplay}`] = onclick;
|
|
157
|
+
s(`.dropdown-option-${id}-${i}`).onclick = onclick;
|
|
158
|
+
});
|
|
159
|
+
}
|
|
170
160
|
render += html`
|
|
171
161
|
<div
|
|
172
|
-
class="in dropdown-option
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
? '
|
|
162
|
+
class="in dropdown-option ${isGroup
|
|
163
|
+
? `dropdown-option-group dropdown-option-group-${id}`
|
|
164
|
+
: `dropdown-option-${id}-${i} dropdown-option-${id}-${valueDisplay} dropdown-option-${valueDisplay} ${valueDisplay === 'reset' && options && !(options.resetOption === true) ? 'hide' : ''}`}"
|
|
165
|
+
style="${isGroup
|
|
166
|
+
? 'cursor:default;opacity:.8;font-size:11px;letter-spacing:.08em;text-transform:uppercase;padding-top:8px;padding-bottom:6px;'
|
|
177
167
|
: ''}"
|
|
178
168
|
>
|
|
179
|
-
${options.type === 'checkbox' && optionData.value !== 'close' && optionData.value !== 'reset'
|
|
169
|
+
${!isGroup && options.type === 'checkbox' && optionData.value !== 'close' && optionData.value !== 'reset'
|
|
180
170
|
? html`
|
|
181
|
-
${await ToggleSwitch.
|
|
171
|
+
${await ToggleSwitch.instance({
|
|
182
172
|
id: `checkbox-role-${valueDisplay}`,
|
|
183
173
|
type: 'checkbox',
|
|
184
174
|
disabledOnClick: true,
|
|
@@ -205,7 +195,6 @@ const DropDown = {
|
|
|
205
195
|
}
|
|
206
196
|
return { render, index };
|
|
207
197
|
};
|
|
208
|
-
|
|
209
198
|
setTimeout(() => {
|
|
210
199
|
if (options.type === 'checkbox')
|
|
211
200
|
options.data.map((optionData) => {
|
|
@@ -216,21 +205,16 @@ const DropDown = {
|
|
|
216
205
|
const indexValue = options.data.findIndex((t) => t.value === options.value);
|
|
217
206
|
if (indexValue > -1) setTimeout(() => s(`.dropdown-option-${id}-${indexValue}`).click());
|
|
218
207
|
}
|
|
219
|
-
|
|
220
208
|
s(`.dropdown-label-${id}`).onclick = switchOptionsPanel;
|
|
221
209
|
s(`.dropdown-current-${id}`).onclick = switchOptionsPanel;
|
|
222
210
|
if (options && options.open) switchOptionsPanel();
|
|
223
|
-
|
|
224
211
|
if (options.type === 'checkbox') {
|
|
225
212
|
ThemeEvents[`dropdown-badge-${id}`] = () => _renderSelectedBadges();
|
|
226
213
|
}
|
|
227
|
-
|
|
228
214
|
const dropDownSearchHandle = async () => {
|
|
229
215
|
const _data = [];
|
|
230
216
|
if (!s(`.search-box-${id}`)) return;
|
|
231
|
-
|
|
232
217
|
let _value = s(`.search-box-${id}`).value.toLowerCase();
|
|
233
|
-
|
|
234
218
|
for (const objData of options.data) {
|
|
235
219
|
if (
|
|
236
220
|
options.excludeSelected &&
|
|
@@ -249,7 +233,6 @@ const DropDown = {
|
|
|
249
233
|
_data.push(objData);
|
|
250
234
|
}
|
|
251
235
|
}
|
|
252
|
-
|
|
253
236
|
if (_data.length > 0) {
|
|
254
237
|
const { render, index } = await _render(_data);
|
|
255
238
|
htmls(`.${id}-render-container`, render);
|
|
@@ -258,12 +241,11 @@ const DropDown = {
|
|
|
258
241
|
htmls(
|
|
259
242
|
`.${id}-render-container`,
|
|
260
243
|
html` <div class="inl" style="padding: 10px; color: red">
|
|
261
|
-
<i class="fas fa-exclamation-circle"></i> ${Translate.
|
|
244
|
+
<i class="fas fa-exclamation-circle"></i> ${Translate.instance('no-result-found')}
|
|
262
245
|
</div>`,
|
|
263
246
|
);
|
|
264
247
|
}
|
|
265
248
|
};
|
|
266
|
-
|
|
267
249
|
if (options.serviceProvider) {
|
|
268
250
|
let serviceSearchTimeout = null;
|
|
269
251
|
s(`.search-box-${id}`).oninput = () => {
|
|
@@ -295,7 +277,7 @@ const DropDown = {
|
|
|
295
277
|
htmls(
|
|
296
278
|
`.${id}-render-container`,
|
|
297
279
|
html` <div class="inl" style="padding: 10px; color: red">
|
|
298
|
-
<i class="fas fa-exclamation-circle"></i> ${Translate.
|
|
280
|
+
<i class="fas fa-exclamation-circle"></i> ${Translate.instance('no-result-found')}
|
|
299
281
|
</div>`,
|
|
300
282
|
);
|
|
301
283
|
}
|
|
@@ -307,13 +289,10 @@ const DropDown = {
|
|
|
307
289
|
} else {
|
|
308
290
|
s(`.search-box-${id}`).oninput = dropDownSearchHandle;
|
|
309
291
|
}
|
|
310
|
-
|
|
311
292
|
// Not use onblur generate bug on input toggle
|
|
312
293
|
// s(`.search-box-${id}`).onblur = dropDownSearchHandle;
|
|
313
294
|
});
|
|
314
|
-
|
|
315
295
|
const { render, index } = await _render(options.data);
|
|
316
|
-
|
|
317
296
|
return html`
|
|
318
297
|
<div class="inl dropdown-container ${id} ${options?.containerClass ? options.containerClass : ''}">
|
|
319
298
|
<div class="in dropdown-option dropdown-label-${id} ${options && options.disableSelectLabel ? 'hide' : ''}">
|
|
@@ -326,9 +305,9 @@ const DropDown = {
|
|
|
326
305
|
></div>
|
|
327
306
|
<div class="in dropdown-option-${id} hide">
|
|
328
307
|
<div class="in dropdown-option ${options && options.disableSearchBox ? 'hide' : ''}">
|
|
329
|
-
${await Input.
|
|
308
|
+
${await Input.instance({
|
|
330
309
|
id: `search-box-${id}`,
|
|
331
|
-
label: html`<i class="fa-solid fa-magnifying-glass"></i> ${Translate.
|
|
310
|
+
label: html`<i class="fa-solid fa-magnifying-glass"></i> ${Translate.instance('search')}`,
|
|
332
311
|
containerClass: 'in',
|
|
333
312
|
placeholder: true,
|
|
334
313
|
})}
|
|
@@ -337,7 +316,6 @@ const DropDown = {
|
|
|
337
316
|
</div>
|
|
338
317
|
</div>
|
|
339
318
|
`;
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
|
|
319
|
+
}
|
|
320
|
+
}
|
|
343
321
|
export { DropDown };
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
class EventBus {
|
|
2
|
+
constructor() {
|
|
3
|
+
this.target = new EventTarget();
|
|
4
|
+
this.listeners = new Map();
|
|
5
|
+
this.typeKeys = new Map();
|
|
6
|
+
this.bridges = new Map();
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
ensureBridge(type) {
|
|
10
|
+
if (this.bridges.has(type)) return;
|
|
11
|
+
|
|
12
|
+
const bridge = async (event) => {
|
|
13
|
+
const deferred = event._deferred;
|
|
14
|
+
|
|
15
|
+
try {
|
|
16
|
+
const keys = [...(this.typeKeys.get(type) ?? [])];
|
|
17
|
+
for (const key of keys) {
|
|
18
|
+
const entry = this.listeners.get(key);
|
|
19
|
+
if (!entry) continue;
|
|
20
|
+
|
|
21
|
+
await entry.listener(event.detail, event);
|
|
22
|
+
if (entry.once) this.off(key);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
deferred?.resolve();
|
|
26
|
+
} catch (error) {
|
|
27
|
+
deferred?.reject(error);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
this.bridges.set(type, bridge);
|
|
32
|
+
this.target.addEventListener(type, bridge);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
on(type, listener, options = {}) {
|
|
36
|
+
const key = options.key ?? Symbol(type);
|
|
37
|
+
|
|
38
|
+
this.off(key);
|
|
39
|
+
this.ensureBridge(type);
|
|
40
|
+
|
|
41
|
+
const keys = this.typeKeys.get(type) ?? new Set();
|
|
42
|
+
keys.add(key);
|
|
43
|
+
this.typeKeys.set(type, keys);
|
|
44
|
+
|
|
45
|
+
this.listeners.set(key, {
|
|
46
|
+
type,
|
|
47
|
+
listener,
|
|
48
|
+
once: Boolean(options.once),
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
return () => this.off(key);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
off(key) {
|
|
55
|
+
const entry = this.listeners.get(key);
|
|
56
|
+
if (!entry) return false;
|
|
57
|
+
|
|
58
|
+
this.listeners.delete(key);
|
|
59
|
+
const keys = this.typeKeys.get(entry.type);
|
|
60
|
+
if (keys) {
|
|
61
|
+
keys.delete(key);
|
|
62
|
+
if (keys.size === 0) this.typeKeys.delete(entry.type);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
has(key) {
|
|
69
|
+
return this.listeners.has(key);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async emit(type, detail) {
|
|
73
|
+
if (!(this.typeKeys.get(type)?.size > 0)) return;
|
|
74
|
+
|
|
75
|
+
const event = new CustomEvent(type, { detail });
|
|
76
|
+
return await new Promise((resolve, reject) => {
|
|
77
|
+
event._deferred = { resolve, reject };
|
|
78
|
+
this.target.dispatchEvent(event);
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
async emitKey(key, detail) {
|
|
83
|
+
const entry = this.listeners.get(key);
|
|
84
|
+
if (!entry) return;
|
|
85
|
+
|
|
86
|
+
const event = new CustomEvent(entry.type, { detail });
|
|
87
|
+
await entry.listener(detail, event);
|
|
88
|
+
if (entry.once) this.off(key);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export { EventBus };
|