underpost 2.8.87 → 2.8.88

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.
Files changed (99) hide show
  1. package/.env.development +35 -3
  2. package/.env.production +39 -4
  3. package/.env.test +35 -3
  4. package/.github/workflows/ghpkg.ci.yml +1 -1
  5. package/.github/workflows/npmpkg.ci.yml +1 -1
  6. package/.github/workflows/pwa-microservices-template-page.cd.yml +6 -5
  7. package/.github/workflows/pwa-microservices-template-test.ci.yml +1 -1
  8. package/.github/workflows/release.cd.yml +3 -3
  9. package/README.md +56 -2
  10. package/bin/build.js +4 -0
  11. package/bin/deploy.js +62 -8
  12. package/bin/file.js +3 -2
  13. package/cli.md +8 -2
  14. package/conf.js +30 -4
  15. package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
  16. package/manifests/deployment/dd-test-development/deployment.yaml +174 -0
  17. package/manifests/deployment/dd-test-development/proxy.yaml +51 -0
  18. package/package.json +6 -5
  19. package/src/api/core/core.router.js +2 -1
  20. package/src/api/default/default.controller.js +6 -1
  21. package/src/api/default/default.router.js +6 -2
  22. package/src/api/default/default.service.js +10 -1
  23. package/src/api/document/document.controller.js +66 -0
  24. package/src/api/document/document.model.js +51 -0
  25. package/src/api/document/document.router.js +24 -0
  26. package/src/api/document/document.service.js +125 -0
  27. package/src/api/file/file.controller.js +15 -1
  28. package/src/api/file/file.router.js +2 -1
  29. package/src/api/test/test.router.js +1 -1
  30. package/src/api/user/postman_collection.json +216 -0
  31. package/src/api/user/user.controller.js +25 -60
  32. package/src/api/user/user.model.js +29 -7
  33. package/src/api/user/user.router.js +9 -3
  34. package/src/api/user/user.service.js +84 -32
  35. package/src/cli/baremetal.js +33 -3
  36. package/src/cli/cloud-init.js +11 -0
  37. package/src/cli/cron.js +0 -1
  38. package/src/cli/deploy.js +46 -23
  39. package/src/cli/index.js +5 -0
  40. package/src/cli/lxd.js +7 -0
  41. package/src/cli/repository.js +42 -6
  42. package/src/cli/run.js +45 -13
  43. package/src/cli/ssh.js +20 -6
  44. package/src/client/Default.index.js +42 -1
  45. package/src/client/components/core/Account.js +10 -2
  46. package/src/client/components/core/AgGrid.js +30 -8
  47. package/src/client/components/core/Auth.js +99 -56
  48. package/src/client/components/core/BtnIcon.js +3 -2
  49. package/src/client/components/core/CalendarCore.js +2 -3
  50. package/src/client/components/core/CommonJs.js +1 -2
  51. package/src/client/components/core/Content.js +15 -12
  52. package/src/client/components/core/Css.js +2 -1
  53. package/src/client/components/core/CssCore.js +6 -1
  54. package/src/client/components/core/Docs.js +5 -5
  55. package/src/client/components/core/FileExplorer.js +3 -3
  56. package/src/client/components/core/Input.js +22 -17
  57. package/src/client/components/core/JoyStick.js +2 -2
  58. package/src/client/components/core/LoadingAnimation.js +2 -2
  59. package/src/client/components/core/LogIn.js +16 -23
  60. package/src/client/components/core/LogOut.js +5 -1
  61. package/src/client/components/core/Logger.js +4 -1
  62. package/src/client/components/core/Modal.js +82 -53
  63. package/src/client/components/core/ObjectLayerEngineModal.js +2 -1
  64. package/src/client/components/core/Pagination.js +207 -0
  65. package/src/client/components/core/Panel.js +10 -10
  66. package/src/client/components/core/PanelForm.js +130 -33
  67. package/src/client/components/core/Recover.js +2 -2
  68. package/src/client/components/core/Router.js +210 -34
  69. package/src/client/components/core/SignUp.js +1 -2
  70. package/src/client/components/core/Stream.js +1 -1
  71. package/src/client/components/core/VanillaJs.js +3 -84
  72. package/src/client/components/core/Worker.js +2 -2
  73. package/src/client/components/default/LogInDefault.js +0 -6
  74. package/src/client/components/default/LogOutDefault.js +0 -16
  75. package/src/client/components/default/MenuDefault.js +97 -44
  76. package/src/client/components/default/RoutesDefault.js +5 -2
  77. package/src/client/services/core/core.service.js +8 -20
  78. package/src/client/services/default/default.management.js +115 -18
  79. package/src/client/services/default/default.service.js +13 -4
  80. package/src/client/services/document/document.service.js +97 -0
  81. package/src/client/services/file/file.service.js +2 -0
  82. package/src/client/services/test/test.service.js +3 -0
  83. package/src/client/services/user/user.management.js +6 -0
  84. package/src/client/services/user/user.service.js +15 -4
  85. package/src/client/ssr/Render.js +1 -1
  86. package/src/client/ssr/head/DefaultScripts.js +3 -0
  87. package/src/client/ssr/head/Seo.js +1 -0
  88. package/src/index.js +24 -2
  89. package/src/runtime/lampp/Lampp.js +89 -2
  90. package/src/runtime/xampp/Xampp.js +48 -1
  91. package/src/server/auth.js +519 -155
  92. package/src/server/backup.js +2 -2
  93. package/src/server/conf.js +66 -8
  94. package/src/server/process.js +2 -1
  95. package/src/server/runtime.js +135 -286
  96. package/src/server/ssl.js +1 -2
  97. package/src/server/ssr.js +85 -0
  98. package/src/server/start.js +2 -2
  99. package/src/server/valkey.js +2 -1
@@ -3,7 +3,8 @@ import { CssCoreDark, CssCoreLight } from './CssCore.js';
3
3
  import { DropDown } from './DropDown.js';
4
4
  import { Modal } from './Modal.js';
5
5
  import { Translate } from './Translate.js';
6
- import { append, getProxyPath, htmls, s, sa } from './VanillaJs.js';
6
+ import { append, htmls, s, sa } from './VanillaJs.js';
7
+ import { getProxyPath } from './Router.js';
7
8
 
8
9
  let ThemesScope = [];
9
10
 
@@ -1,7 +1,8 @@
1
1
  import { AgGrid } from './AgGrid.js';
2
2
  import { borderChar, boxShadow, scrollBarDarkRender, scrollBarLightRender } from './Css.js';
3
3
  import { LoadingAnimation } from './LoadingAnimation.js';
4
- import { append, getProxyPath, s } from './VanillaJs.js';
4
+ import { append, s } from './VanillaJs.js';
5
+ import { getProxyPath } from './Router.js';
5
6
 
6
7
  const CssCommonCore = async () => {
7
8
  if (!s(`.fa-link`))
@@ -214,6 +215,10 @@ const CssCommonCore = async () => {
214
215
  .bar-default-modal {
215
216
  overflow: hidden;
216
217
  }
218
+ .panel-placeholder-bottom {
219
+ height: 100px;
220
+ color: gray;
221
+ }
217
222
  </style>
218
223
  ${boxShadow({ selector: '.account-profile-image' })}
219
224
  <div class="ag-grid-style"></div>`;
@@ -1,12 +1,11 @@
1
1
  import { Badge } from './Badge.js';
2
2
  import { BtnIcon } from './BtnIcon.js';
3
- import { rgbToHex } from './CommonJs.js';
4
- import { Css, darkTheme, dynamicCol, renderCssAttr, simpleIconsRender, ThemeEvents, Themes } from './Css.js';
3
+ import { Css, renderCssAttr, simpleIconsRender, ThemeEvents, Themes } from './Css.js';
5
4
  import { DropDown } from './DropDown.js';
6
5
  import { buildBadgeToolTipMenuOption, Modal, renderMenuLabel, renderViewTitle } from './Modal.js';
7
- import { listenQueryPathInstance, setQueryPath } from './Router.js';
6
+ import { listenQueryPathInstance, setQueryPath, closeModalRouteChangeEvent, getProxyPath } from './Router.js';
8
7
  import { Translate } from './Translate.js';
9
- import { getProxyPath, getQueryParams, htmls, s, sa } from './VanillaJs.js';
8
+ import { htmls, s } from './VanillaJs.js';
10
9
  import Sortable from 'sortablejs';
11
10
 
12
11
  // https://mintlify.com/docs/quickstart
@@ -34,6 +33,7 @@ const Docs = {
34
33
  },
35
34
  maximize: true,
36
35
  mode: 'view',
36
+ route: 'docs',
37
37
  slideMenu: 'modal-menu',
38
38
  observer: true,
39
39
  barMode: 'top-bottom-bar',
@@ -51,7 +51,7 @@ const Docs = {
51
51
  };
52
52
  Modal.Data[ModalId].onObserverListener[ModalId]();
53
53
  Modal.Data[ModalId].onCloseListener[ModalId] = () => {
54
- setQueryPath({ path: 'docs', queryPath: '' });
54
+ closeModalRouteChangeEvent({ closedId: ModalId });
55
55
  };
56
56
  },
57
57
  Data: [
@@ -4,8 +4,7 @@ import { FileService } from '../../services/file/file.service.js';
4
4
  import { AgGrid } from './AgGrid.js';
5
5
  import { Auth } from './Auth.js';
6
6
  import { BtnIcon } from './BtnIcon.js';
7
- import { getSubpaths, timer, uniqueArray } from './CommonJs.js';
8
- import { Content } from './Content.js';
7
+ import { getSubpaths, uniqueArray } from './CommonJs.js';
9
8
  import { darkTheme, renderCssAttr } from './Css.js';
10
9
  import { EventsUI } from './EventsUI.js';
11
10
  import { fileFormDataFactory, Input, InputFile } from './Input.js';
@@ -15,7 +14,8 @@ import { NotificationManager } from './NotificationManager.js';
15
14
  import { RouterEvents } from './Router.js';
16
15
  import { Translate } from './Translate.js';
17
16
  import { Validator } from './Validator.js';
18
- import { copyData, downloadFile, getProxyPath, getQueryParams, s, setPath } from './VanillaJs.js';
17
+ import { copyData, downloadFile, s } from './VanillaJs.js';
18
+ import { getProxyPath, getQueryParams, setPath } from './Router.js';
19
19
 
20
20
  const logger = loggerFactory(import.meta);
21
21
 
@@ -7,7 +7,7 @@ import { loggerFactory } from './Logger.js';
7
7
  import { RichText } from './RichText.js';
8
8
  import { ToggleSwitch } from './ToggleSwitch.js';
9
9
  import { Translate } from './Translate.js';
10
- import { htmls, s } from './VanillaJs.js';
10
+ import { htmls, htmlStrSanitize, s } from './VanillaJs.js';
11
11
  const logger = loggerFactory(import.meta);
12
12
 
13
13
  const fileFormDataFactory = (e, extensions) => {
@@ -61,22 +61,27 @@ const Input = {
61
61
  };
62
62
  });
63
63
 
64
- const inputElement = html` <input
65
- type="${options?.type ? options.type : 'text'}"
66
- class="${options.inputClass ? options.inputClass : 'in wfa'} ${id}"
67
- ${options?.min !== undefined ? `min="${options.min}"` : ''}
68
- ${options?.max !== undefined ? `max="${options.max}"` : ''}
69
- placeholder${options?.placeholder ? `="${options.placeholder}"` : ''}
70
- ${options?.value !== undefined ? `value="${options.value}"` : ''}
71
- ${options?.autocomplete ? `autocomplete="${options.autocomplete}"` : ''}
72
- ${options?.disabled ? `disabled` : ''}
73
- ${options?.name !== undefined ? `name="${options.name}"` : ''}
74
- ${options?.pattern !== undefined ? `pattern="${options.pattern}"` : ''}
75
- ${options?.pattern === undefined && options.type === 'tel' ? `pattern="[0-9]{3}-[0-9]{3}-[0-9]{4}"` : ''}
76
- ${options?.required ? ` required ` : ''}
77
- ${options?.accept ? `accept="${options.accept}"` : ''}
78
- ${options?.multiple ? `multiple="multiple"` : ''}
79
- />
64
+ const labelValue = htmlStrSanitize(options.label) ? htmlStrSanitize(options.label) : id;
65
+
66
+ const inputElement = html` <label for="${id}-name">
67
+ <span class="hide">${labelValue}</span>
68
+ <input
69
+ type="${options?.type ? options.type : 'text'}"
70
+ class="${options.inputClass ? options.inputClass : 'in wfa'} ${id}"
71
+ ${options?.min !== undefined ? `min="${options.min}"` : ''}
72
+ ${options?.max !== undefined ? `max="${options.max}"` : ''}
73
+ placeholder${options?.placeholder ? `="${options.placeholder}"` : ''}
74
+ ${options?.value !== undefined ? `value="${options.value}"` : ''}
75
+ ${options?.autocomplete ? `autocomplete="${options.autocomplete}"` : ''}
76
+ ${options?.disabled ? `disabled` : ''}
77
+ ${options?.name !== undefined ? `name="${options.name}"` : `name='${id}-name'`}
78
+ ${options?.pattern !== undefined ? `pattern="${options.pattern}"` : ''}
79
+ ${options?.pattern === undefined && options.type === 'tel' ? `pattern="[0-9]{3}-[0-9]{3}-[0-9]{4}"` : ''}
80
+ ${options?.required ? ` required ` : ''}
81
+ ${options?.accept ? `accept="${options.accept}"` : ''}
82
+ ${options?.multiple ? `multiple="multiple"` : ''}
83
+ id="${id}-name"
84
+ /></label>
80
85
  <div class="${id}-input-extension input-info input-extension ${options?.extension ? '' : 'hide'}">
81
86
  ${options?.extension ? await options.extension() : ''}
82
87
  </div>`;
@@ -1,7 +1,7 @@
1
1
  import JoystickController from 'joystick-controller';
2
2
  import { getDirection, getId } from './CommonJs.js';
3
- import { loggerFactory } from './Logger.js';
4
- import { append, getProxyPath, s } from './VanillaJs.js';
3
+ import { append, s } from './VanillaJs.js';
4
+ import { getProxyPath } from './Router.js';
5
5
 
6
6
  const logger = loggerFactory(import.meta);
7
7
 
@@ -1,9 +1,9 @@
1
- import { CoreService } from '../../services/core/core.service.js';
2
1
  import { BtnIcon } from './BtnIcon.js';
3
2
  import { s4 } from './CommonJs.js';
4
3
  import { darkTheme, renderCssAttr, subThemeManager } from './Css.js';
5
4
  import { loggerFactory } from './Logger.js';
6
- import { append, getAllChildNodes, getProxyPath, htmls, s, sa } from './VanillaJs.js';
5
+ import { append, htmls, s } from './VanillaJs.js';
6
+ import { getProxyPath } from './Router.js';
7
7
 
8
8
  const logger = loggerFactory(import.meta);
9
9
 
@@ -24,8 +24,9 @@ const LogIn = {
24
24
  Event: {},
25
25
  Trigger: async function (options) {
26
26
  const { user } = options;
27
- await Webhook.register({ user });
28
27
  for (const eventKey of Object.keys(this.Event)) await this.Event[eventKey](options);
28
+ if (!user || user.role === 'guest') return;
29
+ await Webhook.register({ user });
29
30
  if (s(`.session`))
30
31
  htmls(
31
32
  `.session`,
@@ -72,19 +73,18 @@ const LogIn = {
72
73
  imageSrc,
73
74
  };
74
75
  }
76
+ htmls(
77
+ `.action-btn-profile-log-in-render`,
78
+ html`<div class="abs center top-box-profile-img-container">
79
+ <img
80
+ class="abs center top-box-profile-img"
81
+ ${this.Scope.user.main.model.user.profileImage
82
+ ? `src="${this.Scope.user.main.model.user.profileImage.imageSrc}"`
83
+ : ``}
84
+ />
85
+ </div>`,
86
+ );
75
87
  }
76
-
77
- htmls(
78
- `.action-btn-profile-log-in-render`,
79
- html`<div class="abs center top-box-profile-img-container">
80
- <img
81
- class="abs center top-box-profile-img"
82
- ${this.Scope.user.main.model.user.profileImage
83
- ? `src="${this.Scope.user.main.model.user.profileImage.imageSrc}"`
84
- : ``}
85
- />
86
- </div>`,
87
- );
88
88
  },
89
89
  Render: async function () {
90
90
  setTimeout(async () => {
@@ -103,13 +103,7 @@ const LogIn = {
103
103
  if ('model' in inputData) body[inputData.model] = s(`.${inputData.id}`).value;
104
104
  }
105
105
  const result = await UserService.post({ id: 'auth', body });
106
- if (result.status === 'success') {
107
- await Auth.sessionIn(result);
108
- setTimeout(() => {
109
- if (s(`.modal-log-in`)) s(`.btn-close-modal-log-in`).click();
110
- if (s(`.modal-sign-up`)) s(`.btn-close-modal-sign-up`).click();
111
- });
112
- }
106
+
113
107
  if (result.status === 'error' && result.message.match('attempts')) {
114
108
  htmls(`.login-attempt-warn-value`, result.message.split(':')[1]);
115
109
  s(`.login-attempt-warn-container`).classList.remove('hide');
@@ -119,6 +113,8 @@ const LogIn = {
119
113
  htmls(`.login-attempt-warn-value0`, result.message.split(':')[1]);
120
114
  s(`.login-attempt-warn-container0`).classList.remove('hide');
121
115
  } else s(`.login-attempt-warn-container0`).classList.add('hide');
116
+
117
+ if (result.status === 'success') await Auth.sessionIn(result);
122
118
  NotificationManager.Push({
123
119
  html: result.status === 'success' ? Translate.Render(`${result.status}-user-log-in`) : result.message,
124
120
  status: result.status,
@@ -189,9 +185,6 @@ const LogIn = {
189
185
  </form>
190
186
  `;
191
187
  },
192
- cleanMainUser: () => {
193
- LogIn.Scope.user.main.model.user = {};
194
- },
195
188
  };
196
189
 
197
190
  export { LogIn };
@@ -4,11 +4,11 @@ import { LogIn } from './LogIn.js';
4
4
  import { Translate } from './Translate.js';
5
5
  import { htmls, s } from './VanillaJs.js';
6
6
  import { Webhook } from './Webhook.js';
7
+ import { NotificationManager } from './NotificationManager.js';
7
8
 
8
9
  const LogOut = {
9
10
  Event: {},
10
11
  Trigger: async function (options) {
11
- LogIn.cleanMainUser();
12
12
  await Webhook.unregister();
13
13
  for (const eventKey of Object.keys(this.Event)) await this.Event[eventKey](options);
14
14
  if (s(`.session`))
@@ -41,6 +41,10 @@ const LogOut = {
41
41
  s('.btn-log-out').onclick = async (e) => {
42
42
  e.preventDefault();
43
43
  await Auth.sessionOut();
44
+ NotificationManager.Push({
45
+ html: Translate.Render(`success-logout`),
46
+ status: 'success',
47
+ });
44
48
  };
45
49
  });
46
50
  // Translate.Render('confirm-logout')
@@ -1,4 +1,6 @@
1
- const loggerFactory = (meta) => {
1
+ import { getCurrentTrace } from './CommonJs.js';
2
+
3
+ const loggerFactory = (meta, options = { trace: false }) => {
2
4
  meta = meta.url.split('/').pop();
3
5
  const types = ['error', 'warn', 'info', 'debug'];
4
6
  const logger = {
@@ -9,6 +11,7 @@ const loggerFactory = (meta) => {
9
11
  console.info = () => null;
10
12
  console.warn = () => null;
11
13
  }
14
+ if (options.trace === true) args.push(getCurrentTrace().split('Logger.js:23')[1]);
12
15
  return location.hostname === 'localhost'
13
16
  ? console[type](`[${meta}] ${new Date().toISOString()} ${type}:`, ...args)
14
17
  : null;
@@ -1,16 +1,6 @@
1
- import { cap, getId, newInstance } from './CommonJs.js';
1
+ import { getId, newInstance, s4 } from './CommonJs.js';
2
2
  import { Draggable } from '@neodrag/vanilla';
3
- import {
4
- append,
5
- s,
6
- prepend,
7
- setPath,
8
- getProxyPath,
9
- htmls,
10
- sa,
11
- getAllChildNodes,
12
- isActiveElement,
13
- } from './VanillaJs.js';
3
+ import { append, s, prepend, htmls, sa, getAllChildNodes, isActiveElement } from './VanillaJs.js';
14
4
  import { BtnIcon } from './BtnIcon.js';
15
5
  import { Responsive } from './Responsive.js';
16
6
  import { loggerFactory } from './Logger.js';
@@ -24,18 +14,25 @@ import {
24
14
  renderStatus,
25
15
  renderCssAttr,
26
16
  } from './Css.js';
27
- import { setDocTitle, closeModalRouteChangeEvent, handleModalViewRoute } from './Router.js';
17
+ import {
18
+ setDocTitle,
19
+ closeModalRouteChangeEvent,
20
+ handleModalViewRoute,
21
+ getProxyPath,
22
+ setPath,
23
+ coreUI,
24
+ } from './Router.js';
28
25
  import { NotificationManager } from './NotificationManager.js';
29
26
  import { EventsUI } from './EventsUI.js';
30
27
  import { Translate } from './Translate.js';
31
28
  import { Input, isTextInputFocused } from './Input.js';
32
- import { Validator } from './Validator.js';
33
29
  import { DropDown } from './DropDown.js';
34
30
  import { Keyboard } from './Keyboard.js';
35
31
  import { Badge } from './Badge.js';
36
32
  import { Worker } from './Worker.js';
33
+ import { Scroll } from './Scroll.js';
37
34
 
38
- const logger = loggerFactory(import.meta);
35
+ const logger = loggerFactory(import.meta, { trace: true });
39
36
 
40
37
  const Modal = {
41
38
  Data: {},
@@ -91,10 +88,15 @@ const Modal = {
91
88
  homeModals: options.homeModals ? options.homeModals : [],
92
89
  query: options.query ? `${window.location.search}` : undefined,
93
90
  getTop: () => window.innerHeight - (options.heightBottomBar ? options.heightBottomBar : heightDefaultBottomBar),
94
- getHeight: () =>
95
- window.innerHeight -
96
- (options.heightTopBar ? options.heightTopBar : heightDefaultTopBar) -
97
- (options.heightBottomBar ? options.heightBottomBar : heightDefaultBottomBar),
91
+ getHeight: () => {
92
+ return (
93
+ window.innerHeight -
94
+ (s(`.main-body-btn-ui-close`) && !s(`.main-body-btn-ui-close`).classList.contains('hide')
95
+ ? (options.heightTopBar ? options.heightTopBar : heightDefaultTopBar) -
96
+ (options.heightBottomBar ? options.heightBottomBar : heightDefaultBottomBar)
97
+ : 0)
98
+ );
99
+ },
98
100
  };
99
101
 
100
102
  if (idModal !== 'main-body' && options.mode !== 'view') {
@@ -186,9 +188,7 @@ const Modal = {
186
188
  htmls(
187
189
  `.default-slide-menu-top-bar-fix-title-container`,
188
190
  html`
189
- <div class="inl default-slide-menu-top-bar-fix-title-container-text">
190
- ${options.RouterInstance.BannerAppTemplate}
191
- </div>
191
+ <div class="inl default-slide-menu-top-bar-fix-title-container-text">${options.title}</div>
192
192
  `,
193
193
  );
194
194
  } else
@@ -274,6 +274,7 @@ const Modal = {
274
274
  s(`.btn-menu-${idModal}`).classList.remove('hide');
275
275
  s(`.${idModal}`).style.width = `${this.Data[idModal][options.mode].width}px`;
276
276
  s(`.html-${idModal}`).style.display = 'none';
277
+ // s(`.title-modal-${idModal}`).style.display = 'none';
277
278
  setTimeout(() => {
278
279
  s(`.main-body-btn-ui-menu-close`).classList.add('hide');
279
280
  s(`.main-body-btn-ui-menu-menu`).classList.remove('hide');
@@ -281,9 +282,6 @@ const Modal = {
281
282
  s(`.btn-bar-center-icon-menu`).classList.remove('hide');
282
283
  s(`.btn-bar-center-icon-close`).classList.add('hide');
283
284
  }
284
- });
285
- // s(`.title-modal-${idModal}`).style.display = 'none';
286
- setTimeout(() => {
287
285
  s(`.main-body-btn-container`).style[
288
286
  true || (options.mode && options.mode.match('right')) ? 'right' : 'left'
289
287
  ] = `${0}px`;
@@ -375,6 +373,7 @@ const Modal = {
375
373
  s(`.modal-menu`).style.top = '0px';
376
374
  s(`.main-body-btn-container`).style.top = '50px';
377
375
  s(`.main-body`).style.top = '0px';
376
+ s(`.main-body`).style.height = `${window.innerHeight}px`;
378
377
  for (const event of Object.keys(Modal.Data[idModal].onBarUiClose))
379
378
  Modal.Data[idModal].onBarUiClose[event]();
380
379
  } else {
@@ -387,6 +386,7 @@ const Modal = {
387
386
  s(`.slide-menu-top-bar`).classList.remove('hide');
388
387
  s(`.bottom-bar`).classList.remove('hide');
389
388
  s(`.main-body`).style.top = `${options.heightTopBar}px`;
389
+ s(`.main-body`).style.height = `${window.innerHeight - options.heightTopBar}px`;
390
390
  for (const event of Object.keys(Modal.Data[idModal].onBarUiOpen))
391
391
  Modal.Data[idModal].onBarUiOpen[event]();
392
392
  }
@@ -787,8 +787,7 @@ const Modal = {
787
787
  dragDisabled: true,
788
788
  maximize: true,
789
789
  heightBottomBar: 0,
790
- heightTopBar: originHeightTopBar,
791
- barMode: options.barMode,
790
+ heightTopBar: options.heightTopBar,
792
791
  });
793
792
 
794
793
  // Bind hover/focus and click-outside to dismiss
@@ -1300,6 +1299,15 @@ const Modal = {
1300
1299
  }
1301
1300
 
1302
1301
  await NotificationManager.RenderBoard(options);
1302
+
1303
+ const { removeEvent } = Scroll.setEvent('.main-body', async (payload) => {
1304
+ console.warn('scroll', payload);
1305
+ if (payload.scrollTop > 100) {
1306
+ if (!s(`.main-body-btn-ui-close`).classList.contains('hide')) s(`.main-body-btn-ui-close`).click();
1307
+
1308
+ removeEvent();
1309
+ }
1310
+ });
1303
1311
  });
1304
1312
  })();
1305
1313
  break;
@@ -1394,7 +1402,7 @@ const Modal = {
1394
1402
  <div
1395
1403
  class="fix ${options && options.class ? options.class : ''} modal ${options.disableBoxShadow
1396
1404
  ? ''
1397
- : 'box-shadow'} ${idModal}"
1405
+ : 'box-shadow'} ${idModal === 'main-body' ? `${idModal} modal-home` : idModal}"
1398
1406
  >
1399
1407
  <div class="abs modal-handle-${idModal}"></div>
1400
1408
  <div class="in modal-html-${idModal}">
@@ -1535,18 +1543,6 @@ const Modal = {
1535
1543
  s(`.btn-icon-menu-back`).classList.add('hide');
1536
1544
  if (s(`.menu-btn-container-main`)) s(`.menu-btn-container-main`).classList.remove('hide');
1537
1545
  };
1538
- this.onHomeRouterEvent = async () => {
1539
- for (const keyModal of Object.keys(this.Data)) {
1540
- if (
1541
- ![idModal, 'main-body-top', 'main-body'].concat(this.Data[idModal]?.homeModals || []).includes(keyModal)
1542
- )
1543
- if (s(`.btn-close-${keyModal}`)) s(`.btn-close-${keyModal}`).click();
1544
- backMenuButtonEvent();
1545
- }
1546
- if (s(`.btn-close-modal-menu`)) s(`.btn-close-modal-menu`).click();
1547
- setPath(getProxyPath());
1548
- setDocTitle();
1549
- };
1550
1546
  s(`.main-btn-home`).onclick = async () => {
1551
1547
  // await this.onHomeRouterEvent();
1552
1548
  s(`.action-btn-home`).click();
@@ -1767,13 +1763,8 @@ const Modal = {
1767
1763
  if (!s(`.${idModal}`)) return;
1768
1764
  this.removeModal(idModal);
1769
1765
  // Handle modal route change
1770
- if (options.route) {
1771
- closeModalRouteChangeEvent({
1772
- route: options.route,
1773
- RouterInstance: options.RouterInstance,
1774
- homeCid: Modal.homeCid,
1775
- });
1776
- }
1766
+ closeModalRouteChangeEvent({ closedId: idModal });
1767
+ // history.back();
1777
1768
  }, 300);
1778
1769
  };
1779
1770
  s(`.btn-close-${idModal}`).onclick = btnCloseEvent;
@@ -1967,7 +1958,45 @@ const Modal = {
1967
1958
  ...this.Data[idModal],
1968
1959
  };
1969
1960
  },
1970
- onHomeRouterEvent: () => {},
1961
+ onHomeRouterEvent: async () => {
1962
+ // 1. Get list of modals to close.
1963
+ const modalsToClose = Object.keys(Modal.Data).filter((idModal) => {
1964
+ const modal = Modal.Data[idModal];
1965
+ if (!modal) return false;
1966
+ // Don't close the core UI elements
1967
+
1968
+ if (coreUI.find((id) => idModal.startsWith(id))) {
1969
+ return false;
1970
+ }
1971
+ // Don't close modals that are part of the "home" screen itself
1972
+ const homeModals = Modal.Data['modal-menu']?.homeModals || [];
1973
+ if (homeModals.includes(idModal)) {
1974
+ return false;
1975
+ }
1976
+ return true;
1977
+ });
1978
+
1979
+ // 2. Navigate to home first, creating a new history entry.
1980
+ setPath(`${getProxyPath()}${location.search ?? ''}${location.hash ?? ''}`);
1981
+ setDocTitle();
1982
+
1983
+ // 3. Close the modals without them affecting the URL.
1984
+ for (const id of modalsToClose) {
1985
+ Modal.removeModal(id);
1986
+ }
1987
+
1988
+ // 4. Finally, handle UI cleanup for the slide-menu.
1989
+ if (s(`.menu-btn-container-children`)) htmls(`.menu-btn-container-children`, '');
1990
+ if (s(`.nav-title-display-modal-menu`)) htmls(`.nav-title-display-modal-menu`, '');
1991
+ if (s(`.nav-path-display-modal-menu`)) htmls(`.nav-path-display-modal-menu`, '');
1992
+ if (s(`.btn-icon-menu-back`)) s(`.btn-icon-menu-back`).classList.add('hide');
1993
+ if (s(`.menu-btn-container-main`)) s(`.menu-btn-container-main`).classList.remove('hide');
1994
+
1995
+ // And close the slide menu if it's open
1996
+ if (s(`.btn-close-modal-menu`) && !s(`.btn-close-modal-menu`).classList.contains('hide')) {
1997
+ s(`.btn-close-modal-menu`).click();
1998
+ }
1999
+ },
1971
2000
  currentTopModalId: '',
1972
2001
  zIndexSync: function ({ idModal }) {
1973
2002
  setTimeout(() => {
@@ -1996,11 +2025,6 @@ const Modal = {
1996
2025
  setTopModalCallback: function (idModal) {
1997
2026
  s(`.${idModal}`).style.zIndex = '4';
1998
2027
  this.currentTopModalId = `${idModal}`;
1999
- if (
2000
- this.Data[idModal].query &&
2001
- `${location.pathname}${window.location.search}` !== `${location.pathname}${this.Data[idModal].query}`
2002
- )
2003
- setPath(`${location.pathname}${this.Data[idModal].query}`);
2004
2028
  },
2005
2029
  mobileModal: () => window.innerWidth < 600 || window.innerHeight < 600,
2006
2030
  writeHTML: ({ idModal, html }) => htmls(`.html-${idModal}`, html),
@@ -2239,6 +2263,11 @@ const Modal = {
2239
2263
  s(`.bottom-bar`).classList.remove('hide');
2240
2264
  s(`.modal-menu`).classList.remove('hide');
2241
2265
  },
2266
+ RenderSeoSanitizer: async () => {
2267
+ sa('img').forEach((img) => {
2268
+ if (!img.getAttribute('alt')) img.setAttribute('alt', 'image ' + Worker.title + ' ' + s4());
2269
+ });
2270
+ },
2242
2271
  };
2243
2272
 
2244
2273
  const renderMenuLabel = ({ img, text, icon }) => {
@@ -4,7 +4,8 @@ import { borderChar, dynamicCol } from './Css.js';
4
4
  import { DropDown } from './DropDown.js';
5
5
  import { EventsUI } from './EventsUI.js';
6
6
  import { Translate } from './Translate.js';
7
- import { getProxyPath, s, append, hexToRgbA } from './VanillaJs.js';
7
+ import { s, append, hexToRgbA } from './VanillaJs.js';
8
+ import { getProxyPath } from './Router.js';
8
9
  import { s4 } from './CommonJs.js';
9
10
  import { Input } from './Input.js';
10
11
  import { ToggleSwitch } from './ToggleSwitch.js';