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
|
@@ -4,20 +4,17 @@ import { Css, darkTheme, renderCssAttr, simpleIconsRender, ThemeEvents, Themes }
|
|
|
4
4
|
import { buildBadgeToolTipMenuOption, Modal, renderViewTitle } from './Modal.js';
|
|
5
5
|
import { listenQueryPathInstance, setQueryPath, closeModalRouteChangeEvent, getProxyPath } from './Router.js';
|
|
6
6
|
import { htmls, s, sIframe } from './VanillaJs.js';
|
|
7
|
-
|
|
8
7
|
// https://mintlify.com/docs/quickstart
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const docData = this.Data.find((d) => d.type === type);
|
|
8
|
+
class Docs {
|
|
9
|
+
static async RenderModal(type) {
|
|
10
|
+
const docData = Docs.Data.find((d) => d.type === type);
|
|
13
11
|
const ModalId = `modal-docs-${docData.type}`;
|
|
14
12
|
const { barConfig } = await Themes[Css.currentTheme]();
|
|
15
13
|
const parentBarMode =
|
|
16
14
|
Modal.Data['modal-docs'] && Modal.Data['modal-docs'].options.barMode
|
|
17
15
|
? Modal.Data['modal-docs'].options.barMode
|
|
18
16
|
: undefined;
|
|
19
|
-
|
|
20
|
-
await Modal.Render({
|
|
17
|
+
await Modal.instance({
|
|
21
18
|
barConfig,
|
|
22
19
|
title: renderViewTitle(docData),
|
|
23
20
|
id: ModalId,
|
|
@@ -51,7 +48,15 @@ const Docs = {
|
|
|
51
48
|
});
|
|
52
49
|
const iframeEl = s(`.iframe-${ModalId}`);
|
|
53
50
|
let swaggerThemeEventKey = null;
|
|
51
|
+
let unbindIframeLayoutSync = null;
|
|
54
52
|
if (iframeEl) {
|
|
53
|
+
const scheduleViewLayoutSync = () => {
|
|
54
|
+
const sync = () => Modal.syncViewLayout();
|
|
55
|
+
sync();
|
|
56
|
+
setTimeout(sync, 0);
|
|
57
|
+
setTimeout(sync, 120);
|
|
58
|
+
setTimeout(sync, 400);
|
|
59
|
+
};
|
|
55
60
|
iframeEl.addEventListener('load', () => {
|
|
56
61
|
try {
|
|
57
62
|
const iframeWin = iframeEl.contentWindow;
|
|
@@ -62,11 +67,34 @@ const Docs = {
|
|
|
62
67
|
} catch (e) {
|
|
63
68
|
// cross-origin or security restriction — safe to ignore
|
|
64
69
|
}
|
|
65
|
-
window.
|
|
70
|
+
// Keep the parent window scroll untouched.
|
|
71
|
+
// These modals are fixed-position; scrolling the parent on iframe navigation
|
|
72
|
+
// shifts Chrome layout calculations and leaves view modals offset by 50px.
|
|
66
73
|
// Bind Shift+K inside the iframe to focus the parent SearchBox (mirrors app-wide shortcut)
|
|
67
74
|
try {
|
|
75
|
+
const iframeWin = iframeEl.contentWindow;
|
|
68
76
|
const iframeDoc = iframeEl.contentDocument || iframeEl.contentWindow?.document;
|
|
69
77
|
if (iframeDoc) {
|
|
78
|
+
if (unbindIframeLayoutSync) unbindIframeLayoutSync();
|
|
79
|
+
const onIframeAnchorClick = (e) => {
|
|
80
|
+
if (e.target && e.target.closest && e.target.closest('a')) {
|
|
81
|
+
scheduleViewLayoutSync();
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
const onIframeHashChange = () => scheduleViewLayoutSync();
|
|
85
|
+
const onIframePopState = () => scheduleViewLayoutSync();
|
|
86
|
+
iframeDoc.addEventListener('click', onIframeAnchorClick, true);
|
|
87
|
+
if (iframeWin) {
|
|
88
|
+
iframeWin.addEventListener('hashchange', onIframeHashChange);
|
|
89
|
+
iframeWin.addEventListener('popstate', onIframePopState);
|
|
90
|
+
}
|
|
91
|
+
unbindIframeLayoutSync = () => {
|
|
92
|
+
iframeDoc.removeEventListener('click', onIframeAnchorClick, true);
|
|
93
|
+
if (iframeWin) {
|
|
94
|
+
iframeWin.removeEventListener('hashchange', onIframeHashChange);
|
|
95
|
+
iframeWin.removeEventListener('popstate', onIframePopState);
|
|
96
|
+
}
|
|
97
|
+
};
|
|
70
98
|
iframeDoc.addEventListener('keydown', (e) => {
|
|
71
99
|
if (e.shiftKey && e.key.toLowerCase() === 'k') {
|
|
72
100
|
e.preventDefault();
|
|
@@ -85,48 +113,30 @@ const Docs = {
|
|
|
85
113
|
} catch (e) {
|
|
86
114
|
// cross-origin or security restriction — safe to ignore
|
|
87
115
|
}
|
|
116
|
+
scheduleViewLayoutSync();
|
|
88
117
|
});
|
|
89
|
-
|
|
90
118
|
if (type === 'src') {
|
|
91
119
|
swaggerThemeEventKey = `jsdocs-iframe-${ModalId}`;
|
|
92
|
-
|
|
93
120
|
const applyJsDocsTheme = (isDark) => {
|
|
94
121
|
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
|
-
}
|
|
122
|
+
const iframeDoc = iframeEl.contentDocument || iframeEl.contentWindow?.document;
|
|
123
|
+
if (!iframeDoc || !iframeDoc.documentElement) return;
|
|
124
|
+
// TypeDoc built-in theme: data-theme on <html>, stored as 'tsd-theme' in localStorage
|
|
125
|
+
iframeDoc.documentElement.setAttribute('data-theme', isDark ? 'dark' : 'light');
|
|
126
|
+
iframeEl.contentWindow?.localStorage?.setItem('tsd-theme', isDark ? 'dark' : 'light');
|
|
113
127
|
} catch (e) {
|
|
114
128
|
// cross-origin or security restriction — safe to ignore
|
|
115
129
|
}
|
|
116
130
|
};
|
|
117
|
-
|
|
118
131
|
// Apply current theme as soon as the iframe content is ready
|
|
119
132
|
iframeEl.addEventListener('load', () => applyJsDocsTheme(darkTheme));
|
|
120
|
-
|
|
121
133
|
// Keep in sync whenever the parent page theme changes
|
|
122
134
|
ThemeEvents[swaggerThemeEventKey] = () => {
|
|
123
135
|
if (s(`.iframe-${ModalId}`)) applyJsDocsTheme(darkTheme);
|
|
124
136
|
};
|
|
125
137
|
}
|
|
126
|
-
|
|
127
138
|
if (type === 'api') {
|
|
128
139
|
swaggerThemeEventKey = `swagger-iframe-${ModalId}`;
|
|
129
|
-
|
|
130
140
|
const applySwaggerTheme = (isDark) => {
|
|
131
141
|
try {
|
|
132
142
|
const iframeDoc = iframeEl.contentDocument || iframeEl.contentWindow?.document;
|
|
@@ -143,10 +153,8 @@ const Docs = {
|
|
|
143
153
|
// cross-origin or security restriction — safe to ignore
|
|
144
154
|
}
|
|
145
155
|
};
|
|
146
|
-
|
|
147
156
|
// Apply current theme as soon as the iframe content is ready
|
|
148
157
|
iframeEl.addEventListener('load', () => applySwaggerTheme(darkTheme));
|
|
149
|
-
|
|
150
158
|
// Keep in sync whenever the parent page theme changes
|
|
151
159
|
ThemeEvents[swaggerThemeEventKey] = () => {
|
|
152
160
|
if (s(`.iframe-${ModalId}`)) applySwaggerTheme(darkTheme);
|
|
@@ -159,7 +167,6 @@ const Docs = {
|
|
|
159
167
|
const barHeight = barEl ? barEl.offsetHeight : Modal.headerTitleHeight;
|
|
160
168
|
s(`.iframe-${ModalId}`).style.height = `${s(`.${ModalId}`).offsetHeight - barHeight}px`;
|
|
161
169
|
}
|
|
162
|
-
|
|
163
170
|
if (type.match('coverage')) {
|
|
164
171
|
simpleIconsRender(`.doc-icon-coverage`);
|
|
165
172
|
simpleIconsRender(`.doc-icon-coverage-link`);
|
|
@@ -167,11 +174,12 @@ const Docs = {
|
|
|
167
174
|
};
|
|
168
175
|
Modal.Data[ModalId].onObserverListener[ModalId]();
|
|
169
176
|
Modal.Data[ModalId].onCloseListener[ModalId] = () => {
|
|
177
|
+
if (unbindIframeLayoutSync) unbindIframeLayoutSync();
|
|
170
178
|
if (swaggerThemeEventKey) delete ThemeEvents[swaggerThemeEventKey];
|
|
171
179
|
closeModalRouteChangeEvent({ closedId: ModalId });
|
|
172
180
|
};
|
|
173
|
-
}
|
|
174
|
-
Data
|
|
181
|
+
}
|
|
182
|
+
static Data = [
|
|
175
183
|
{
|
|
176
184
|
type: 'repo',
|
|
177
185
|
icon: html`<i class="fab fa-github"></i>`,
|
|
@@ -238,38 +246,36 @@ const Docs = {
|
|
|
238
246
|
if (s(`.doc-icon-coverage-link`)) setTimeout(() => simpleIconsRender(`.doc-icon-coverage-link`));
|
|
239
247
|
},
|
|
240
248
|
},
|
|
241
|
-
]
|
|
242
|
-
Tokens
|
|
243
|
-
|
|
249
|
+
];
|
|
250
|
+
static Tokens = {};
|
|
251
|
+
static async instance(options = {}) {
|
|
244
252
|
const { idModal } = options;
|
|
245
|
-
|
|
253
|
+
Docs.Tokens[idModal] = options;
|
|
246
254
|
setTimeout(() => {
|
|
247
255
|
s(`.btn-docs-src`).onclick = async () => {
|
|
248
256
|
setQueryPath({ path: 'docs', queryPath: 'src' });
|
|
249
|
-
await
|
|
257
|
+
await Docs.RenderModal('src');
|
|
250
258
|
};
|
|
251
259
|
s(`.btn-docs-api`).onclick = async () => {
|
|
252
260
|
setQueryPath({ path: 'docs', queryPath: 'api' });
|
|
253
|
-
await
|
|
261
|
+
await Docs.RenderModal('api');
|
|
254
262
|
};
|
|
255
263
|
s(`.btn-docs-coverage`).onclick = async () => {
|
|
256
264
|
setQueryPath({ path: 'docs', queryPath: 'coverage' });
|
|
257
|
-
await
|
|
265
|
+
await Docs.RenderModal('coverage');
|
|
258
266
|
};
|
|
259
|
-
|
|
260
267
|
s(`.btn-docs-coverage-link`).onclick = () => {
|
|
261
|
-
const docData =
|
|
268
|
+
const docData = Docs.Data.find((d) => d.type === 'coverage-link');
|
|
262
269
|
location.href = docData.url();
|
|
263
270
|
};
|
|
264
271
|
s(`.btn-docs-repo`).onclick = () => {
|
|
265
|
-
const docData =
|
|
272
|
+
const docData = Docs.Data.find((d) => d.type === 'repo');
|
|
266
273
|
location.href = docData.url();
|
|
267
274
|
};
|
|
268
275
|
s(`.btn-docs-demo`).onclick = () => {
|
|
269
|
-
const docData =
|
|
276
|
+
const docData = Docs.Data.find((d) => d.type === 'demo');
|
|
270
277
|
location.href = docData.url();
|
|
271
278
|
};
|
|
272
|
-
|
|
273
279
|
listenQueryPathInstance({
|
|
274
280
|
id: options.idModal,
|
|
275
281
|
routeId: 'docs',
|
|
@@ -284,7 +290,7 @@ const Docs = {
|
|
|
284
290
|
});
|
|
285
291
|
});
|
|
286
292
|
let docMenuRender = '';
|
|
287
|
-
for (const docData of
|
|
293
|
+
for (const docData of Docs.Data) {
|
|
288
294
|
if (docData.themeEvent) {
|
|
289
295
|
ThemeEvents[`doc-icon-${docData.type}`] = docData.themeEvent;
|
|
290
296
|
setTimeout(ThemeEvents[`doc-icon-${docData.type}`]);
|
|
@@ -296,7 +302,6 @@ const Docs = {
|
|
|
296
302
|
style = renderCssAttr({ style: { height: '45px' } });
|
|
297
303
|
labelStyle = renderCssAttr({ style: { top: '8px', left: '9px' } });
|
|
298
304
|
break;
|
|
299
|
-
|
|
300
305
|
default:
|
|
301
306
|
break;
|
|
302
307
|
}
|
|
@@ -306,21 +311,19 @@ const Docs = {
|
|
|
306
311
|
? options.subMenuIcon(docData.type)
|
|
307
312
|
: docData.icon;
|
|
308
313
|
docMenuRender += html`
|
|
309
|
-
${await BtnIcon.
|
|
314
|
+
${await BtnIcon.instance({
|
|
310
315
|
class: `in wfa main-btn-menu submenu-btn btn-docs btn-docs-${docData.type}`,
|
|
311
316
|
label: html`<span class="inl menu-btn-icon">${subMenuIcon}</span
|
|
312
317
|
><span class="menu-label-text menu-label-text-docs"> ${docData.text} </span>`,
|
|
313
318
|
tabHref,
|
|
314
|
-
tooltipHtml: await Badge.
|
|
319
|
+
tooltipHtml: await Badge.instance(buildBadgeToolTipMenuOption(docData.text, 'right')),
|
|
315
320
|
useMenuBtn: true,
|
|
316
321
|
})}
|
|
317
322
|
`;
|
|
318
323
|
}
|
|
319
324
|
// s(`.menu-btn-container-children`).classList.remove('hide');
|
|
320
325
|
// htmls(`.nav-path-display-${'modal-menu'}`, location.pathname);
|
|
321
|
-
|
|
322
326
|
htmls('.menu-btn-container-children-docs', docMenuRender);
|
|
323
|
-
|
|
324
327
|
{
|
|
325
328
|
const docsData = [
|
|
326
329
|
{
|
|
@@ -360,7 +363,6 @@ const Docs = {
|
|
|
360
363
|
description: 'Join our developer community',
|
|
361
364
|
},
|
|
362
365
|
];
|
|
363
|
-
|
|
364
366
|
return html`
|
|
365
367
|
<style>
|
|
366
368
|
.docs-landing {
|
|
@@ -499,7 +501,6 @@ const Docs = {
|
|
|
499
501
|
</div>
|
|
500
502
|
`;
|
|
501
503
|
}
|
|
502
|
-
}
|
|
503
|
-
}
|
|
504
|
-
|
|
504
|
+
}
|
|
505
|
+
}
|
|
505
506
|
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 };
|