cyberia 3.2.5 → 3.2.12

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 (381) hide show
  1. package/.github/workflows/engine-cyberia.cd.yml +8 -2
  2. package/.github/workflows/npmpkg.ci.yml +1 -0
  3. package/.github/workflows/pwa-microservices-template-test.ci.yml +1 -1
  4. package/.github/workflows/release.cd.yml +2 -2
  5. package/.vscode/extensions.json +9 -9
  6. package/.vscode/settings.json +20 -4
  7. package/CHANGELOG.md +563 -1
  8. package/CLI-HELP.md +130 -34
  9. package/Dockerfile +0 -4
  10. package/README.md +194 -607
  11. package/bin/build.js +42 -12
  12. package/bin/build.template.js +187 -0
  13. package/bin/cyberia.js +1367 -281
  14. package/bin/deploy.js +582 -3
  15. package/bin/index.js +1367 -281
  16. package/bump.config.js +26 -0
  17. package/conf.js +195 -111
  18. package/deployment.yaml +6 -222
  19. package/hardhat/package-lock.json +118 -149
  20. package/hardhat/package.json +5 -4
  21. package/jsconfig.json +1 -1
  22. package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +2 -2
  23. package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +2 -2
  24. package/manifests/deployment/dd-cyberia-development/deployment.yaml +6 -222
  25. package/manifests/deployment/dd-cyberia-development/proxy.yaml +10 -118
  26. package/manifests/deployment/dd-default-development/deployment.yaml +2 -6
  27. package/manifests/deployment/dd-test-development/deployment.yaml +138 -66
  28. package/manifests/deployment/dd-test-development/proxy.yaml +41 -5
  29. package/manifests/kind-config-dev.yaml +8 -0
  30. package/manifests/lxd/lxd-admin-profile.yaml +12 -3
  31. package/manifests/mongodb/pv-pvc.yaml +44 -8
  32. package/manifests/mongodb/statefulset.yaml +55 -68
  33. package/manifests/mongodb-4.4/headless-service.yaml +10 -0
  34. package/manifests/mongodb-4.4/kustomization.yaml +3 -1
  35. package/manifests/mongodb-4.4/mongodb-nodeport.yaml +17 -0
  36. package/manifests/mongodb-4.4/pv-pvc.yaml +10 -14
  37. package/manifests/mongodb-4.4/statefulset.yaml +79 -0
  38. package/manifests/mongodb-4.4/storage-class.yaml +9 -0
  39. package/manifests/valkey/statefulset.yaml +1 -1
  40. package/manifests/valkey/valkey-nodeport.yaml +17 -0
  41. package/package.json +45 -24
  42. package/proxy.yaml +10 -118
  43. package/scripts/ipxe-setup.sh +52 -49
  44. package/scripts/k3s-node-setup.sh +83 -48
  45. package/scripts/lxd-vm-setup.sh +193 -8
  46. package/scripts/maas-nat-firewalld.sh +145 -0
  47. package/scripts/nat-iptables.sh +103 -18
  48. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.controller.js +18 -18
  49. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.model.js +7 -14
  50. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.router.js +38 -33
  51. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.service.js +91 -36
  52. package/src/api/core/core.controller.js +10 -10
  53. package/src/api/core/core.router.js +19 -14
  54. package/src/api/core/core.service.js +15 -15
  55. package/src/api/crypto/crypto.controller.js +8 -8
  56. package/src/api/crypto/crypto.router.js +18 -12
  57. package/src/api/crypto/crypto.service.js +11 -11
  58. package/src/api/cyberia-action/cyberia-action.controller.js +74 -0
  59. package/src/api/cyberia-action/cyberia-action.model.js +87 -0
  60. package/src/api/cyberia-action/cyberia-action.router.js +31 -0
  61. package/src/api/cyberia-action/cyberia-action.service.js +42 -0
  62. package/src/api/cyberia-client-hints/cyberia-client-hints.controller.js +74 -0
  63. package/src/api/cyberia-client-hints/cyberia-client-hints.model.js +99 -0
  64. package/src/api/cyberia-client-hints/cyberia-client-hints.router.js +98 -0
  65. package/src/api/cyberia-client-hints/cyberia-client-hints.service.js +152 -0
  66. package/src/api/cyberia-dialogue/cyberia-dialogue.controller.js +13 -13
  67. package/src/api/cyberia-dialogue/cyberia-dialogue.model.js +11 -11
  68. package/src/api/cyberia-dialogue/cyberia-dialogue.router.js +25 -20
  69. package/src/api/cyberia-dialogue/cyberia-dialogue.service.js +22 -22
  70. package/src/api/cyberia-entity/cyberia-entity.controller.js +10 -10
  71. package/src/api/cyberia-entity/cyberia-entity.router.js +22 -18
  72. package/src/api/cyberia-entity/cyberia-entity.service.js +15 -15
  73. package/src/api/cyberia-instance/cyberia-fallback-world.js +83 -198
  74. package/src/api/cyberia-instance/cyberia-instance.controller.js +14 -14
  75. package/src/api/cyberia-instance/cyberia-instance.model.js +3 -0
  76. package/src/api/cyberia-instance/cyberia-instance.router.js +57 -52
  77. package/src/api/cyberia-instance/cyberia-instance.service.js +32 -67
  78. package/src/api/cyberia-instance/cyberia-portal-connector.js +20 -246
  79. package/src/api/cyberia-instance/cyberia-world-generator.js +505 -0
  80. package/src/api/cyberia-instance-conf/cyberia-instance-conf.controller.js +10 -10
  81. package/src/api/cyberia-instance-conf/cyberia-instance-conf.model.js +18 -49
  82. package/src/api/cyberia-instance-conf/cyberia-instance-conf.router.js +22 -18
  83. package/src/api/cyberia-instance-conf/cyberia-instance-conf.service.js +19 -15
  84. package/src/api/cyberia-map/cyberia-map.controller.js +10 -10
  85. package/src/api/cyberia-map/cyberia-map.router.js +35 -30
  86. package/src/api/cyberia-map/cyberia-map.service.js +17 -17
  87. package/src/api/cyberia-quest/cyberia-quest.controller.js +74 -0
  88. package/src/api/cyberia-quest/cyberia-quest.model.js +67 -0
  89. package/src/api/cyberia-quest/cyberia-quest.router.js +31 -0
  90. package/src/api/cyberia-quest/cyberia-quest.service.js +42 -0
  91. package/src/api/cyberia-quest-progress/cyberia-quest-progress.controller.js +74 -0
  92. package/src/api/cyberia-quest-progress/cyberia-quest-progress.model.js +49 -0
  93. package/src/api/cyberia-quest-progress/cyberia-quest-progress.router.js +31 -0
  94. package/src/api/cyberia-quest-progress/cyberia-quest-progress.service.js +42 -0
  95. package/src/api/cyberia-server-defaults/cyberia-server-defaults.js +451 -0
  96. package/src/api/default/default.controller.js +10 -10
  97. package/src/api/default/default.router.js +22 -18
  98. package/src/api/default/default.service.js +15 -15
  99. package/src/api/document/document.controller.js +12 -12
  100. package/src/api/document/document.model.js +10 -16
  101. package/src/api/document/document.router.js +28 -23
  102. package/src/api/document/document.service.js +100 -23
  103. package/src/api/file/file.controller.js +8 -8
  104. package/src/api/file/file.model.js +10 -10
  105. package/src/api/file/file.router.js +19 -13
  106. package/src/api/file/file.service.js +45 -43
  107. package/src/api/instance/instance.controller.js +10 -10
  108. package/src/api/instance/instance.model.js +4 -10
  109. package/src/api/instance/instance.router.js +29 -24
  110. package/src/api/instance/instance.service.js +16 -16
  111. package/src/api/ipfs/ipfs.controller.js +12 -12
  112. package/src/api/ipfs/ipfs.model.js +4 -13
  113. package/src/api/ipfs/ipfs.router.js +21 -16
  114. package/src/api/ipfs/ipfs.service.js +22 -36
  115. package/src/api/object-layer/object-layer.controller.js +12 -12
  116. package/src/api/object-layer/object-layer.model.js +4 -17
  117. package/src/api/object-layer/object-layer.router.js +512 -507
  118. package/src/api/object-layer/object-layer.service.js +29 -26
  119. package/src/api/object-layer-render-frames/object-layer-render-frames.controller.js +10 -10
  120. package/src/api/object-layer-render-frames/object-layer-render-frames.model.js +6 -16
  121. package/src/api/object-layer-render-frames/object-layer-render-frames.router.js +22 -18
  122. package/src/api/object-layer-render-frames/object-layer-render-frames.service.js +19 -15
  123. package/src/api/test/test.controller.js +8 -8
  124. package/src/api/test/test.router.js +17 -12
  125. package/src/api/test/test.service.js +8 -8
  126. package/src/api/types.js +24 -0
  127. package/src/api/user/guest.service.js +100 -0
  128. package/src/api/user/user.controller.js +6 -6
  129. package/src/api/user/user.model.js +8 -13
  130. package/src/api/user/user.router.js +297 -288
  131. package/src/api/user/user.service.js +103 -55
  132. package/src/cli/baremetal.js +132 -101
  133. package/src/cli/cluster.js +732 -217
  134. package/src/cli/db.js +106 -62
  135. package/src/cli/deploy.js +260 -149
  136. package/src/cli/fs.js +90 -9
  137. package/src/cli/image.js +43 -1
  138. package/src/cli/index.js +106 -16
  139. package/src/cli/ipfs.js +4 -6
  140. package/src/cli/kubectl.js +4 -1
  141. package/src/cli/lxd.js +1099 -223
  142. package/src/cli/monitor.js +9 -3
  143. package/src/cli/release.js +336 -86
  144. package/src/cli/repository.js +136 -53
  145. package/src/cli/run.js +599 -76
  146. package/src/cli/secrets.js +11 -2
  147. package/src/cli/ssh.js +1 -1
  148. package/src/cli/static.js +43 -115
  149. package/src/cli/test.js +9 -3
  150. package/src/client/Cryptokoyn.index.js +18 -21
  151. package/src/client/CyberiaPortal.index.js +19 -23
  152. package/src/client/Default.index.js +30 -36
  153. package/src/client/Itemledger.index.js +20 -26
  154. package/src/client/Underpost.index.js +19 -23
  155. package/src/client/components/core/404.js +4 -4
  156. package/src/client/components/core/500.js +4 -4
  157. package/src/client/components/core/Account.js +73 -60
  158. package/src/client/components/core/AgGrid.js +23 -33
  159. package/src/client/components/core/Alert.js +12 -13
  160. package/src/client/components/core/AppStore.js +1 -1
  161. package/src/client/components/core/Auth.js +40 -37
  162. package/src/client/components/core/Badge.js +7 -13
  163. package/src/client/components/core/BtnIcon.js +15 -17
  164. package/src/client/components/core/CalendarCore.js +42 -63
  165. package/src/client/components/core/Chat.js +13 -15
  166. package/src/client/components/core/ClientEvents.js +163 -0
  167. package/src/client/components/core/ColorPaletteElement.js +309 -0
  168. package/src/client/components/core/Content.js +17 -14
  169. package/src/client/components/core/Css.js +15 -71
  170. package/src/client/components/core/CssCore.js +12 -16
  171. package/src/client/components/core/D3Chart.js +4 -4
  172. package/src/client/components/core/Docs.js +64 -91
  173. package/src/client/components/core/DropDown.js +69 -91
  174. package/src/client/components/core/EventBus.js +96 -0
  175. package/src/client/components/core/EventsUI.js +14 -17
  176. package/src/client/components/core/FileExplorer.js +96 -228
  177. package/src/client/components/core/FullScreen.js +47 -75
  178. package/src/client/components/core/Input.js +24 -69
  179. package/src/client/components/core/Keyboard.js +25 -18
  180. package/src/client/components/core/KeyboardAvoidance.js +145 -0
  181. package/src/client/components/core/LoadingAnimation.js +25 -31
  182. package/src/client/components/core/LogIn.js +41 -41
  183. package/src/client/components/core/LogOut.js +23 -14
  184. package/src/client/components/core/Modal.js +544 -219
  185. package/src/client/components/core/NotificationManager.js +14 -18
  186. package/src/client/components/core/Panel.js +54 -50
  187. package/src/client/components/core/PanelForm.js +81 -177
  188. package/src/client/components/core/Polyhedron.js +110 -214
  189. package/src/client/components/core/PublicProfile.js +39 -32
  190. package/src/client/components/core/Recover.js +48 -44
  191. package/src/client/components/core/Responsive.js +88 -32
  192. package/src/client/components/core/RichText.js +9 -18
  193. package/src/client/components/core/Router.js +24 -3
  194. package/src/client/components/core/SearchBox.js +37 -37
  195. package/src/client/components/core/SignUp.js +39 -30
  196. package/src/client/components/core/SocketIo.js +31 -2
  197. package/src/client/components/core/SocketIoHandler.js +6 -6
  198. package/src/client/components/core/ToggleSwitch.js +8 -20
  199. package/src/client/components/core/ToolTip.js +5 -17
  200. package/src/client/components/core/Translate.js +56 -59
  201. package/src/client/components/core/Validator.js +26 -16
  202. package/src/client/components/core/Wallet.js +15 -26
  203. package/src/client/components/core/Worker.js +211 -276
  204. package/src/client/components/core/windowGetDimensions.js +7 -7
  205. package/src/client/components/cryptokoyn/{MenuCryptokoyn.js → AppShellCryptokoyn.js} +57 -57
  206. package/src/client/components/cryptokoyn/CssCryptokoyn.js +15 -15
  207. package/src/client/components/cryptokoyn/LogInCryptokoyn.js +6 -4
  208. package/src/client/components/cryptokoyn/LogOutCryptokoyn.js +6 -4
  209. package/src/client/components/cryptokoyn/RouterCryptokoyn.js +37 -0
  210. package/src/client/components/cryptokoyn/SettingsCryptokoyn.js +4 -4
  211. package/src/client/components/cryptokoyn/SignUpCryptokoyn.js +6 -4
  212. package/src/client/components/cyberia/InstanceEngineCyberia.js +141 -60
  213. package/src/client/components/cyberia/MapEngineCyberia.js +691 -214
  214. package/src/client/components/cyberia/ObjectLayerEngine.js +19 -0
  215. package/src/client/components/cyberia/ObjectLayerEngineModal.js +1204 -94
  216. package/src/client/components/cyberia/ObjectLayerEngineViewer.js +196 -298
  217. package/src/client/components/cyberia/SharedDefaultsCyberia.js +330 -0
  218. package/src/client/components/cyberia-portal/{MenuCyberiaPortal.js → AppShellCyberiaPortal.js} +102 -102
  219. package/src/client/components/cyberia-portal/CssCyberiaPortal.js +15 -15
  220. package/src/client/components/cyberia-portal/LogInCyberiaPortal.js +6 -4
  221. package/src/client/components/cyberia-portal/LogOutCyberiaPortal.js +6 -4
  222. package/src/client/components/cyberia-portal/MainBodyCyberiaPortal.js +4 -4
  223. package/src/client/components/cyberia-portal/RouterCyberiaPortal.js +60 -0
  224. package/src/client/components/cyberia-portal/SettingsCyberiaPortal.js +4 -4
  225. package/src/client/components/cyberia-portal/SignUpCyberiaPortal.js +6 -4
  226. package/src/client/components/cyberia-portal/TranslateCyberiaPortal.js +4 -4
  227. package/src/client/components/default/{MenuDefault.js → AppShellDefault.js} +87 -87
  228. package/src/client/components/default/CssDefault.js +12 -12
  229. package/src/client/components/default/LogInDefault.js +6 -4
  230. package/src/client/components/default/LogOutDefault.js +6 -4
  231. package/src/client/components/default/RouterDefault.js +47 -0
  232. package/src/client/components/default/SettingsDefault.js +4 -4
  233. package/src/client/components/default/SignUpDefault.js +6 -4
  234. package/src/client/components/default/TranslateDefault.js +3 -3
  235. package/src/client/components/itemledger/{MenuItemledger.js → AppShellItemledger.js} +57 -57
  236. package/src/client/components/itemledger/CssItemledger.js +15 -15
  237. package/src/client/components/itemledger/LogInItemledger.js +6 -4
  238. package/src/client/components/itemledger/LogOutItemledger.js +6 -4
  239. package/src/client/components/itemledger/RouterItemledger.js +38 -0
  240. package/src/client/components/itemledger/SettingsItemledger.js +4 -4
  241. package/src/client/components/itemledger/SignUpItemledger.js +6 -4
  242. package/src/client/components/itemledger/TranslateItemledger.js +3 -3
  243. package/src/client/components/underpost/{MenuUnderpost.js → AppShellUnderpost.js} +88 -88
  244. package/src/client/components/underpost/CssUnderpost.js +14 -14
  245. package/src/client/components/underpost/CyberpunkBloggerUnderpost.js +4 -4
  246. package/src/client/components/underpost/DocumentSearchProvider.js +1 -1
  247. package/src/client/components/underpost/LabGalleryUnderpost.js +12 -15
  248. package/src/client/components/underpost/LogInUnderpost.js +6 -4
  249. package/src/client/components/underpost/LogOutUnderpost.js +6 -4
  250. package/src/client/components/underpost/RouterUnderpost.js +45 -0
  251. package/src/client/components/underpost/SettingsUnderpost.js +4 -4
  252. package/src/client/components/underpost/SignUpUnderpost.js +6 -4
  253. package/src/client/components/underpost/TranslateUnderpost.js +4 -4
  254. package/src/client/public/cyberia-docs/ACTION-SYSTEM.md +235 -0
  255. package/src/client/public/cyberia-docs/ARCHITECTURE.md +83 -0
  256. package/src/client/public/cyberia-docs/CYBERIA-CLI.md +204 -0
  257. package/src/client/public/cyberia-docs/CYBERIA-CLIENT.md +291 -0
  258. package/src/client/public/cyberia-docs/CYBERIA-SERVER.md +278 -0
  259. package/src/client/public/cyberia-docs/CYBERIA.md +259 -0
  260. package/src/client/public/cyberia-docs/ENTITY-PROFILE.md +241 -0
  261. package/src/client/public/cyberia-docs/HARDHAT-MODULE.md +300 -0
  262. package/src/client/public/cyberia-docs/OFF-CHAIN-ECONOMY.md +279 -0
  263. package/src/client/public/cyberia-docs/QUEST-SYSTEM.md +206 -0
  264. package/src/client/public/cyberia-docs/ROADMAP.md +240 -0
  265. package/src/client/public/cyberia-docs/UNDERPOST-PLATFORM.md +106 -0
  266. package/src/client/public/cyberia-docs/WHITE-PAPER.md +732 -0
  267. package/src/client/services/atlas-sprite-sheet/atlas-sprite-sheet.service.js +14 -20
  268. package/src/client/services/core/core.service.js +17 -49
  269. package/src/client/services/crypto/crypto.service.js +8 -13
  270. package/src/client/services/cyberia-action/cyberia-action.service.js +99 -0
  271. package/src/client/services/cyberia-client-hints/cyberia-client-hints.service.js +99 -0
  272. package/src/client/services/cyberia-dialogue/cyberia-dialogue.service.js +10 -16
  273. package/src/client/services/cyberia-entity/cyberia-entity.management.js +5 -5
  274. package/src/client/services/cyberia-entity/cyberia-entity.service.js +10 -16
  275. package/src/client/services/cyberia-instance/cyberia-instance.management.js +6 -6
  276. package/src/client/services/cyberia-instance/cyberia-instance.service.js +12 -18
  277. package/src/client/services/cyberia-instance-conf/cyberia-instance-conf.service.js +10 -16
  278. package/src/client/services/cyberia-map/cyberia-map.management.js +6 -6
  279. package/src/client/services/cyberia-map/cyberia-map.service.js +12 -18
  280. package/src/client/services/cyberia-quest/cyberia-quest.service.js +99 -0
  281. package/src/client/services/cyberia-quest-progress/cyberia-quest-progress.service.js +99 -0
  282. package/src/client/services/default/default.management.js +159 -267
  283. package/src/client/services/default/default.service.js +10 -16
  284. package/src/client/services/document/document.service.js +14 -19
  285. package/src/client/services/file/file.service.js +8 -13
  286. package/src/client/services/instance/instance.management.js +5 -5
  287. package/src/client/services/instance/instance.service.js +10 -15
  288. package/src/client/services/ipfs/ipfs.service.js +12 -18
  289. package/src/client/services/object-layer/object-layer.management.js +12 -12
  290. package/src/client/services/object-layer/object-layer.service.js +20 -26
  291. package/src/client/services/object-layer-render-frames/object-layer-render-frames.service.js +10 -16
  292. package/src/client/services/test/test.service.js +8 -13
  293. package/src/client/services/user/guest.service.js +86 -0
  294. package/src/client/services/user/user.management.js +5 -5
  295. package/src/client/services/user/user.service.js +14 -20
  296. package/src/client/ssr/body/404.js +3 -3
  297. package/src/client/ssr/body/500.js +3 -3
  298. package/src/client/ssr/body/CacheControl.js +5 -2
  299. package/src/client/ssr/body/DefaultSplashScreen.js +19 -12
  300. package/src/client/ssr/body/UnderpostDefaultSplashScreen.js +13 -6
  301. package/src/client/ssr/head/PwaItemledger.js +197 -60
  302. package/src/client/ssr/mailer/DefaultRecoverEmail.js +19 -20
  303. package/src/client/ssr/mailer/DefaultVerifyEmail.js +15 -16
  304. package/src/client/ssr/views/CyberiaServerMetrics.js +982 -0
  305. package/src/client/ssr/{offline → views}/Maintenance.js +12 -11
  306. package/src/client/ssr/{offline → views}/NoNetworkConnection.js +3 -3
  307. package/src/client/ssr/{pages → views}/Test.js +2 -2
  308. package/src/client/sw/core.sw.js +274 -0
  309. package/src/db/DataBaseProvider.js +115 -15
  310. package/src/db/mariadb/MariaDB.js +2 -1
  311. package/src/db/mongo/MongoBootstrap.js +657 -0
  312. package/src/db/mongo/MongooseDB.js +129 -21
  313. package/src/grpc/cyberia/grpc-server.js +185 -105
  314. package/src/index.js +1 -1
  315. package/src/runtime/cyberia-client/Dockerfile +101 -0
  316. package/src/runtime/cyberia-client/Dockerfile.dev +82 -0
  317. package/src/runtime/cyberia-server/Dockerfile +62 -0
  318. package/src/runtime/cyberia-server/Dockerfile.dev +71 -0
  319. package/src/runtime/express/Dockerfile +4 -4
  320. package/src/runtime/express/Express.js +2 -2
  321. package/src/runtime/lampp/Dockerfile +8 -7
  322. package/src/runtime/wp/Dockerfile +11 -17
  323. package/src/runtime/wp/Wp.js +8 -5
  324. package/src/server/atlas-sprite-sheet-generator.js +4 -2
  325. package/src/server/auth.js +2 -2
  326. package/src/server/client-build-docs.js +46 -47
  327. package/src/server/client-build.js +371 -132
  328. package/src/server/client-formatted.js +47 -16
  329. package/src/server/conf.js +91 -87
  330. package/src/server/data-query.js +32 -20
  331. package/src/server/dns.js +22 -0
  332. package/src/server/ipfs-client.js +232 -91
  333. package/src/server/object-layer.js +1 -6
  334. package/src/server/process.js +192 -45
  335. package/src/server/proxy.js +9 -2
  336. package/src/server/runtime.js +1 -1
  337. package/src/server/semantic-layer-generator-floor.js +11 -51
  338. package/src/server/semantic-layer-generator-resource.js +259 -0
  339. package/src/server/semantic-layer-generator-skin.js +41 -171
  340. package/src/server/semantic-layer-generator.js +122 -14
  341. package/src/server/shape-generator.js +108 -0
  342. package/src/server/start.js +34 -8
  343. package/src/server/valkey.js +143 -235
  344. package/src/ws/IoInterface.js +16 -16
  345. package/src/ws/core/channels/core.ws.chat.js +11 -11
  346. package/src/ws/core/channels/core.ws.mailer.js +29 -29
  347. package/src/ws/core/channels/core.ws.stream.js +19 -19
  348. package/src/ws/core/core.ws.connection.js +8 -8
  349. package/src/ws/core/core.ws.server.js +6 -5
  350. package/src/ws/default/channels/default.ws.main.js +10 -10
  351. package/src/ws/default/default.ws.connection.js +4 -4
  352. package/src/ws/default/default.ws.server.js +4 -3
  353. package/tsconfig.docs.json +15 -0
  354. package/typedoc.dd-cyberia.json +29 -0
  355. package/typedoc.json +29 -0
  356. package/WHITE-PAPER.md +0 -1540
  357. package/bin/file.js +0 -196
  358. package/bin/vs.js +0 -74
  359. package/bin/zed.js +0 -84
  360. package/hardhat/README.md +0 -531
  361. package/hardhat/WHITE-PAPER.md +0 -1540
  362. package/jsdoc.dd-cyberia.json +0 -68
  363. package/jsdoc.json +0 -68
  364. package/src/api/cyberia-instance-conf/cyberia-instance-conf.defaults.js +0 -413
  365. package/src/api/object-layer/README.md +0 -672
  366. package/src/client/components/core/ColorPalette.js +0 -5267
  367. package/src/client/components/core/JoyStick.js +0 -80
  368. package/src/client/components/cryptokoyn/RoutesCryptokoyn.js +0 -39
  369. package/src/client/components/cyberia-portal/CommonCyberiaPortal.js +0 -223
  370. package/src/client/components/cyberia-portal/RoutesCyberiaPortal.js +0 -62
  371. package/src/client/components/cyberia-portal/ServerCyberiaPortal.js +0 -136
  372. package/src/client/components/default/RoutesDefault.js +0 -49
  373. package/src/client/components/itemledger/RoutesItemledger.js +0 -40
  374. package/src/client/components/underpost/RoutesUnderpost.js +0 -47
  375. package/src/client/ssr/email/DefaultRecoverEmail.js +0 -21
  376. package/src/client/ssr/email/DefaultVerifyEmail.js +0 -17
  377. package/src/client/ssr/pages/CyberiaServerMetrics.js +0 -461
  378. package/src/client/sw/default.sw.js +0 -127
  379. package/src/client/sw/template.sw.js +0 -84
  380. package/src/grpc/cyberia/OFF_CHAIN_ECONOMY.md +0 -305
  381. package/src/grpc/cyberia/README.md +0 -326
@@ -36,24 +36,192 @@ import { Worker } from './Worker.js';
36
36
  import { Scroll } from './Scroll.js';
37
37
  import { windowGetH, windowGetW } from './windowGetDimensions.js';
38
38
  import { SearchBox } from './SearchBox.js';
39
+ import { createModalEvents } from './ClientEvents.js';
39
40
 
40
41
  const logger = loggerFactory(import.meta, { trace: true });
41
42
 
42
- const Modal = {
43
- Data: {},
43
+ /**
44
+ * @typedef {object} ModalBarButton
45
+ * @property {string} [label] - Button label HTML
46
+ * @property {boolean} [disabled] - Whether the button is hidden/disabled
47
+ * @property {Function} [onClick] - Optional click handler override
48
+ */
49
+
50
+ /**
51
+ * @typedef {object} ModalBarConfig
52
+ * @property {{ minimize: ModalBarButton, restore: ModalBarButton, maximize: ModalBarButton, close: ModalBarButton, menu: ModalBarButton }} buttons
53
+ */
54
+
55
+ /**
56
+ * @typedef {object} ModalRenderOptions
57
+ * @property {string} [id=''] - Modal element id/class name. Auto-generated if omitted.
58
+ * @property {ModalBarConfig} [barConfig={}] - Bar button configuration.
59
+ * @property {string} [title=''] - Modal title HTML.
60
+ * @property {string|Function} [html=''] - Modal body HTML or async factory.
61
+ * @property {string} [handleType='bar'] - Drag handle type ('bar' or default full).
62
+ * @property {string} [mode=''] - Layout mode: 'view', 'slide-menu', 'slide-menu-right', 'slide-menu-left', 'dropNotification'.
63
+ * @property {object} [RouterInstance={}] - Router instance for route-aware modals.
64
+ * @property {string[]} [disableTools=[]] - Tool ids to hide ('app-icon', 'text-box', 'profile', 'center', 'lang', 'theme', 'navigator').
65
+ * @property {boolean} [observer=false] - Attach a ResizeObserver to the modal element.
66
+ * @property {boolean} [disableBoxShadow=false] - Remove box shadow from the modal.
67
+ * @property {boolean} [dragDisabled=false] - Disable dragging.
68
+ * @property {boolean} [maximize=false] - Immediately maximize the modal after render.
69
+ * @property {boolean} [disableCenter=false] - Skip auto-centering.
70
+ * @property {object} [style={}] - Inline style overrides applied via renderStyleTag.
71
+ * @property {string} [class=''] - Extra CSS class(es) on the modal wrapper.
72
+ * @property {string} [titleClass=''] - Class for the title element.
73
+ * @property {string} [btnBarModalClass=''] - Class override for the button bar container.
74
+ * @property {string} [btnContainerClass=''] - Class for each bar button.
75
+ * @property {string} [btnIconContainerClass=''] - Class for each bar button inner icon div.
76
+ * @property {string} [barClass=''] - Class for the top/bottom bar flex row.
77
+ * @property {string} [barMode=''] - Bar layout variant ('top-bottom-bar').
78
+ * @property {string} [renderType=''] - Insertion strategy ('prepend' or default append).
79
+ * @property {string} [selector='body'] - Parent selector for insertion.
80
+ * @property {string} [slideMenu=''] - Id of the slide-menu modal this view should attach to.
81
+ * @property {string} [route=''] - URL path segment for view-mode route tracking.
82
+ * @property {string} [status=''] - Status icon descriptor rendered in the bar.
83
+ * @property {boolean} [zIndexSync=false] - Enable z-index management for stacked view modals.
84
+ * @property {boolean} [query=false] - Snapshot the current query string into modal data.
85
+ * @property {string[]} [homeModals=[]] - Modal ids that belong to the home screen (not closed on home nav).
86
+ * @property {Function} [titleRender] - Function returning title HTML (takes priority over title string).
87
+ * @property {Function} [htmlMainBody] - Factory for main-body modal html (slide-menu mode).
88
+ * @property {Function} [slideMenuTopBarBannerFix] - Async factory for top-bar banner content.
89
+ * @property {number} [minSearchQueryLength=1] - Minimum search query length.
90
+ * @property {Function} [onCollapseMenu] - Callback when slide menu collapses.
91
+ * @property {Function} [onExtendMenu] - Callback when slide menu extends.
92
+ */
93
+
94
+ /**
95
+ * @typedef {object} ModalDataEntry
96
+ * @property {ModalRenderOptions} options - Original render options.
97
+ * @property {import('./EventBus.js').EventBus} events - Per-modal event bus backing the listener channels below.
98
+ *
99
+ * The `onX` channels are EventBus-backed proxies that preserve the historical
100
+ * `{ [key]: listener }` map API: assign to register, read+call to invoke a single
101
+ * listener, `delete` to remove, and `Object.keys` to enumerate registered keys.
102
+ * @property {Object.<string, Function>} onCloseListener - Close event listeners keyed by id.
103
+ * @property {Object.<string, Function>} onMenuListener - Menu button event listeners.
104
+ * @property {Object.<string, Function>} onCollapseMenuListener - Collapse menu listeners.
105
+ * @property {Object.<string, Function>} onExtendMenuListener - Extend menu listeners.
106
+ * @property {Object.<string, Function>} onDragEndListener - Drag-end listeners.
107
+ * @property {Object.<string, Function>} onObserverListener - ResizeObserver listeners.
108
+ * @property {Object.<string, Function>} onClickListener - Click listeners.
109
+ * @property {Object.<string, Function>} onExpandUiListener - UI expand/collapse listeners.
110
+ * @property {Object.<string, Function>} onBarUiOpen - Bar UI open listeners.
111
+ * @property {Object.<string, Function>} onBarUiClose - Bar UI close listeners.
112
+ * @property {Object.<string, Function>} onReloadModalListener - Reload listeners.
113
+ * @property {Object.<string, Function>} onHome - Home navigation listeners.
114
+ * @property {string[]} homeModals - Home modal ids.
115
+ * @property {string} [query] - Snapshotted query string.
116
+ * @property {Function} getTop - Returns computed top offset.
117
+ * @property {Function} getHeight - Returns computed modal height.
118
+ * @property {Function} getMenuLeftStyle - Returns slide menu left CSS value.
119
+ * @property {Function} center - Centers the modal in the viewport.
120
+ * @property {object} [slideMenu] - Active slide-menu link data.
121
+ * @property {ResizeObserver} [observer] - Attached ResizeObserver.
122
+ * @property {Function} [observerCallBack] - ResizeObserver callback.
123
+ * @property {Function} [setDragInstance] - Updates drag options and re-creates the Draggable.
124
+ * @property {object} [dragInstance] - Active Draggable instance.
125
+ * @property {object} [dragOptions] - Current drag configuration.
126
+ */
127
+
128
+ class Modal {
129
+ /** @type {Object.<string, ModalDataEntry>} */
130
+ static Data = {};
44
131
 
45
- Render: async function (
132
+ /**
133
+ * Bottom offset of the slide-menu area for the given options.
134
+ * @param {ModalRenderOptions} options
135
+ * @param {number} [heightDefaultBottomBar=0]
136
+ * @returns {number}
137
+ */
138
+ static getModalTop(options, heightDefaultBottomBar = 0) {
139
+ return windowGetH() - (options.heightBottomBar ? options.heightBottomBar : heightDefaultBottomBar);
140
+ }
141
+
142
+ /**
143
+ * Available modal height, accounting for the top/bottom bars when the UI is expanded.
144
+ * @param {ModalRenderOptions} options
145
+ * @param {number} [heightDefaultTopBar=50]
146
+ * @param {number} [heightDefaultBottomBar=0]
147
+ * @returns {number}
148
+ */
149
+ static getModalHeight(options, heightDefaultTopBar = 50, heightDefaultBottomBar = 0) {
150
+ const barsVisible = s(`.main-body-btn-ui-close`) && !s(`.main-body-btn-ui-close`).classList.contains('hide');
151
+ return (
152
+ windowGetH() -
153
+ (barsVisible
154
+ ? (options.heightTopBar ? options.heightTopBar : heightDefaultTopBar) +
155
+ (options.heightBottomBar ? options.heightBottomBar : heightDefaultBottomBar)
156
+ : 0)
157
+ );
158
+ }
159
+
160
+ /**
161
+ * Left CSS value for a slide menu in its open/closed state.
162
+ * @param {ModalRenderOptions} options
163
+ * @param {{ originSlideMenuWidth: number, collapseSlideMenuWidth: number }} widths
164
+ * @param {{ open: boolean }} [ops={ open: false }]
165
+ * @returns {string}
166
+ */
167
+ static getModalMenuLeftStyle(options, { originSlideMenuWidth, collapseSlideMenuWidth }, ops = { open: false }) {
168
+ return `${
169
+ options.mode === 'slide-menu-right'
170
+ ? `${
171
+ windowGetW() +
172
+ (ops?.open
173
+ ? -1 * originSlideMenuWidth +
174
+ (options.mode === 'slide-menu-right' && s(`.btn-icon-menu-mode-right`).classList.contains('hide')
175
+ ? originSlideMenuWidth - collapseSlideMenuWidth
176
+ : 0)
177
+ : originSlideMenuWidth)
178
+ }px`
179
+ : `-${ops?.open ? '0px' : originSlideMenuWidth}px`
180
+ }`;
181
+ }
182
+
183
+ /**
184
+ * Viewport-centered top/left CSS values for a modal of the given size.
185
+ * @param {{ width: number, height: number }} param0
186
+ * @returns {{ top: string, left: string }}
187
+ */
188
+ static getModalCenter({ width, height }) {
189
+ return {
190
+ top: `${windowGetH() / 2 - height / 2}px`,
191
+ left: `${windowGetW() / 2 - width / 2}px`,
192
+ };
193
+ }
194
+
195
+ /**
196
+ * Create or reload a modal. When the modal already exists in the DOM the
197
+ * existing instance is reloaded via its onReloadModalListener callbacks.
198
+ * @param {ModalRenderOptions} options
199
+ * @returns {Promise<ModalDataEntry & { id: string }>}
200
+ */
201
+ static async instance(
46
202
  options = {
47
203
  id: '',
48
204
  barConfig: {},
49
205
  title: '',
50
206
  html: '',
51
207
  handleType: 'bar',
52
- mode: '' /* slide-menu */,
208
+ mode: '',
53
209
  RouterInstance: {},
54
210
  disableTools: [],
55
211
  observer: false,
56
212
  disableBoxShadow: false,
213
+ dragDisabled: false,
214
+ maximize: false,
215
+ disableCenter: false,
216
+ style: {},
217
+ class: '',
218
+ titleClass: '',
219
+ barMode: '',
220
+ route: '',
221
+ slideMenu: '',
222
+ zIndexSync: false,
223
+ query: false,
224
+ homeModals: [],
57
225
  },
58
226
  ) {
59
227
  const originHeightBottomBar = 50;
@@ -76,52 +244,21 @@ const Modal = {
76
244
  const heightDefaultTopBar = 50;
77
245
  const heightDefaultBottomBar = 0;
78
246
  const idModal = options.id ? options.id : getId(this.Data, 'modal-');
247
+ const { bus: eventBus, channels: eventChannels } = createModalEvents();
79
248
  this.Data[idModal] = {
80
249
  options,
81
- onCloseListener: {},
82
- onMenuListener: {},
83
- onCollapseMenuListener: {},
84
- onExtendMenuListener: {},
85
- onDragEndListener: {},
86
- onObserverListener: {},
87
- onClickListener: {},
88
- onExpandUiListener: {},
89
- onBarUiOpen: {},
90
- onBarUiClose: {},
91
- onReloadModalListener: {},
92
- onHome: {},
250
+ events: eventBus,
251
+ ...eventChannels,
93
252
  homeModals: options.homeModals ? options.homeModals : [],
94
253
  query: options.query ? `${window.location.search}` : undefined,
95
- getTop: () => {
96
- const result = windowGetH() - (options.heightBottomBar ? options.heightBottomBar : heightDefaultBottomBar);
97
- return result;
98
- },
99
- getHeight: () => {
100
- return (
101
- windowGetH() -
102
- (s(`.main-body-btn-ui-close`) && !s(`.main-body-btn-ui-close`).classList.contains('hide')
103
- ? (options.heightTopBar ? options.heightTopBar : heightDefaultTopBar) +
104
- (options.heightBottomBar ? options.heightBottomBar : heightDefaultBottomBar)
105
- : 0)
106
- );
107
- },
254
+ getTop: () => Modal.getModalTop(options, heightDefaultBottomBar),
255
+ getHeight: () => Modal.getModalHeight(options, heightDefaultTopBar, heightDefaultBottomBar),
108
256
  getMenuLeftStyle: (ops = { open: false }) =>
109
- `${
110
- options.mode === 'slide-menu-right'
111
- ? `${
112
- windowGetW() +
113
- (ops?.open
114
- ? -1 * originSlideMenuWidth +
115
- (options.mode === 'slide-menu-right' && s(`.btn-icon-menu-mode-right`).classList.contains('hide')
116
- ? originSlideMenuWidth - collapseSlideMenuWidth
117
- : 0)
118
- : originSlideMenuWidth)
119
- }px`
120
- : `-${ops?.open ? '0px' : originSlideMenuWidth}px`
121
- }`,
257
+ Modal.getModalMenuLeftStyle(options, { originSlideMenuWidth, collapseSlideMenuWidth }, ops),
122
258
  center: () => {
123
- top = `${windowGetH() / 2 - height / 2}px`;
124
- left = `${windowGetW() / 2 - width / 2}px`;
259
+ const { top: centeredTop, left: centeredLeft } = Modal.getModalCenter({ width, height });
260
+ top = centeredTop;
261
+ left = centeredLeft;
125
262
  },
126
263
  ...this.Data[idModal],
127
264
  };
@@ -145,11 +282,14 @@ const Modal = {
145
282
  });
146
283
  }
147
284
 
148
- Responsive.Event[`view-${idModal}`] = () => {
149
- if (!this.Data[idModal]) return delete Responsive.Event[`view-${idModal}`];
150
- if (this.Data[idModal].slideMenu) s(`.${idModal}`).style.height = `${this.Data[idModal].getHeight()}px`;
151
- };
152
- Responsive.Event[`view-${idModal}`]();
285
+ Responsive.onChanged(
286
+ () => {
287
+ if (!this.Data[idModal]) return Responsive.offChanged(`view-${idModal}`);
288
+ if (this.Data[idModal].slideMenu) s(`.${idModal}`).style.height = `${this.Data[idModal].getHeight()}px`;
289
+ },
290
+ { key: `view-${idModal}` },
291
+ );
292
+ Responsive.triggerChanged(`view-${idModal}`);
153
293
 
154
294
  // Handle view mode modal route
155
295
  if (options.route) {
@@ -251,23 +391,30 @@ const Modal = {
251
391
  // barConfig.buttons.menu.disabled = true;
252
392
  // barConfig.buttons.close.disabled = true;
253
393
  options.btnBarModalClass = 'hide';
254
- Responsive.Event[`slide-menu-${idModal}`] = () => {
255
- for (const _idModal of Object.keys(this.Data)) {
256
- if (this.Data[_idModal].slideMenu && this.Data[_idModal].slideMenu.id === idModal)
257
- this.Data[_idModal].slideMenu.callBack();
258
- }
259
- s(`.${idModal}`).style.height = `${Modal.Data[idModal].getHeight()}px`;
260
- s(`.${idModal}`).style.left = Modal.Data[idModal].getMenuLeftStyle({
261
- open: s(`.btn-bar-center-icon-menu`).classList.contains('hide') ? true : false,
262
- });
263
- if (s(`.main-body-top`)) {
264
- if (Modal.mobileModal()) {
265
- if (s(`.btn-menu-${idModal}`).classList.contains('hide') && collapseSlideMenuWidth !== slideMenuWidth)
266
- s(`.main-body-top`).classList.remove('hide');
267
- if (s(`.btn-close-${idModal}`).classList.contains('hide')) s(`.main-body-top`).classList.add('hide');
268
- } else if (!s(`.main-body-top`).classList.contains('hide')) s(`.main-body-top`).classList.add('hide');
269
- }
270
- };
394
+ Responsive.onChanged(
395
+ () => {
396
+ for (const _idModal of Object.keys(this.Data)) {
397
+ if (this.Data[_idModal].slideMenu && this.Data[_idModal].slideMenu.id === idModal)
398
+ this.Data[_idModal].slideMenu.callBack();
399
+ }
400
+ s(`.${idModal}`).style.height = `${Modal.Data[idModal].getHeight()}px`;
401
+ s(`.${idModal}`).style.left = Modal.Data[idModal].getMenuLeftStyle({
402
+ open: s(`.btn-bar-center-icon-menu`).classList.contains('hide') ? true : false,
403
+ });
404
+ if (s(`.main-body-top`)) {
405
+ if (Modal.mobileModal()) {
406
+ if (
407
+ s(`.btn-menu-${idModal}`).classList.contains('hide') &&
408
+ collapseSlideMenuWidth !== slideMenuWidth
409
+ )
410
+ s(`.main-body-top`).classList.remove('hide');
411
+ if (s(`.btn-close-${idModal}`).classList.contains('hide'))
412
+ s(`.main-body-top`).classList.add('hide');
413
+ } else if (!s(`.main-body-top`).classList.contains('hide')) s(`.main-body-top`).classList.add('hide');
414
+ }
415
+ },
416
+ { key: `slide-menu-${idModal}` },
417
+ );
271
418
  barConfig.buttons.menu.onClick = () => {
272
419
  Modal.Data[idModal][options.mode].width = slideMenuWidth;
273
420
  s(`.btn-menu-${idModal}`).classList.add('hide');
@@ -290,7 +437,7 @@ const Modal = {
290
437
  } else {
291
438
  s(`.${idModal}`).style.left = `0px`;
292
439
  }
293
- Responsive.Event[`slide-menu-${idModal}`]();
440
+ Responsive.triggerChanged(`slide-menu-${idModal}`);
294
441
  };
295
442
  barConfig.buttons.close.onClick = () => {
296
443
  Modal.Data[idModal][options.mode].width = 0;
@@ -313,7 +460,7 @@ const Modal = {
313
460
  } else {
314
461
  s(`.${idModal}`).style.left = `-${originSlideMenuWidth}px`;
315
462
  }
316
- Responsive.Event[`slide-menu-${idModal}`]();
463
+ Responsive.triggerChanged(`slide-menu-${idModal}`);
317
464
  };
318
465
  transition += `, width 0.3s`;
319
466
 
@@ -421,15 +568,17 @@ const Modal = {
421
568
  for (const event of Object.keys(Modal.Data[idModal].onBarUiOpen))
422
569
  Modal.Data[idModal].onBarUiOpen[event]();
423
570
  }
424
- Responsive.Event[`slide-menu-modal-menu`]();
571
+ Responsive.triggerChanged(`slide-menu-modal-menu`);
425
572
  Object.keys(this.Data).map((_idModal) => {
426
573
  if (this.Data[_idModal].slideMenu) {
427
574
  if (s(`.btn-maximize-${_idModal}`)) s(`.btn-maximize-${_idModal}`).click();
428
575
  }
429
576
  });
430
- Responsive.Event[`view-${'main-body'}`]();
431
- if (Responsive.Event[`view-${'bottom-bar'}`]) Responsive.Event[`view-${'bottom-bar'}`]();
432
- if (Responsive.Event[`view-${'main-body-top'}`]) Responsive.Event[`view-${'main-body-top'}`]();
577
+ Responsive.triggerChanged(`view-${'main-body'}`);
578
+ if (Responsive.hasChangedListener(`view-${'bottom-bar'}`))
579
+ Responsive.triggerChanged(`view-${'bottom-bar'}`);
580
+ if (Responsive.hasChangedListener(`view-${'main-body-top'}`))
581
+ Responsive.triggerChanged(`view-${'main-body-top'}`);
433
582
  for (const keyEvent of Object.keys(this.Data[idModal].onExpandUiListener)) {
434
583
  this.Data[idModal].onExpandUiListener[keyEvent](
435
584
  !s(`.main-body-btn-ui-open`).classList.contains('hide'),
@@ -447,14 +596,14 @@ const Modal = {
447
596
  class="fl top-bar ${options.barClass ? options.barClass : ''}"
448
597
  style="height: ${originHeightTopBar}px;"
449
598
  >
450
- ${await BtnIcon.Render({
599
+ ${await BtnIcon.instance({
451
600
  style: `height: 100%`,
452
601
  class: 'in fll main-btn-menu action-bar-box action-btn-close hide',
453
602
  label: html` <div class="${contentIconClass} action-btn-close-render">
454
603
  <i class="fa-solid fa-xmark"></i>
455
604
  </div>`,
456
605
  })}
457
- ${await BtnIcon.Render({
606
+ ${await BtnIcon.instance({
458
607
  style: `height: 100%`,
459
608
  class: `in fll main-btn-menu action-bar-box action-btn-app-icon ${
460
609
  options?.disableTools?.includes('app-icon') ? 'hide' : ''
@@ -466,10 +615,12 @@ const Modal = {
466
615
  ? 'hide'
467
616
  : ''}"
468
617
  >
469
- ${await Input.Render({
618
+ ${await Input.instance({
470
619
  id: inputSearchBoxId,
471
620
  autocomplete: 'off',
472
- placeholder: Modal.mobileModal() ? Translate.Render('search', '.top-bar-search-box') : undefined, // html`<i class="fa-solid fa-magnifying-glass"></i> ${Translate.Render('search')}`,
621
+ placeholder: Modal.mobileModal()
622
+ ? Translate.instance('search', '.top-bar-search-box')
623
+ : undefined, // html`<i class="fa-solid fa-magnifying-glass"></i> ${Translate.instance('search')}`,
473
624
  placeholderIcon: html`<div
474
625
  class="in fll"
475
626
  style="width: ${originHeightTopBar}px; height: ${originHeightTopBar}px;"
@@ -480,19 +631,19 @@ const Modal = {
480
631
  class="inl wfm key-shortcut-container-info"
481
632
  style="${renderCssAttr({ style: { top: '10px', left: '60px' } })}"
482
633
  >
483
- ${await Badge.Render({
634
+ ${await Badge.instance({
484
635
  id: 'shortcut-key-info-search',
485
636
  text: 'Shift',
486
637
  classList: 'inl',
487
638
  style: { 'z-index': 1 },
488
639
  })}
489
- ${await Badge.Render({
640
+ ${await Badge.instance({
490
641
  id: 'shortcut-key-info-search',
491
642
  text: '+',
492
643
  classList: 'inl',
493
644
  style: { 'z-index': 1, background: 'none', color: '#5f5f5f' },
494
645
  })}
495
- ${await Badge.Render({
646
+ ${await Badge.instance({
496
647
  id: 'shortcut-key-info-search',
497
648
  text: 'k',
498
649
  classList: 'inl',
@@ -508,12 +659,12 @@ const Modal = {
508
659
  <div
509
660
  class="abs top-box-profile-container ${options?.disableTools?.includes('profile') ? 'hide' : ''}"
510
661
  >
511
- ${await BtnIcon.Render({
662
+ ${await BtnIcon.instance({
512
663
  style: `height: 100%`,
513
664
  class: 'in fll session-in-log-in main-btn-menu action-bar-box action-btn-profile-log-in',
514
665
  label: html` <div class="${contentIconClass} action-btn-profile-log-in-render"></div>`,
515
666
  })}
516
- ${await BtnIcon.Render({
667
+ ${await BtnIcon.instance({
517
668
  style: `height: 100%`,
518
669
  class: 'in fll session-in-log-out main-btn-menu action-bar-box action-btn-profile-log-out',
519
670
  label: html` <div class="${contentIconClass} action-btn-profile-log-out-render">
@@ -618,8 +769,8 @@ const Modal = {
618
769
  if (results.length === 0) {
619
770
  append(
620
771
  `.html-${searchBoxHistoryId}`,
621
- await BtnIcon.Render({
622
- label: html`<i class="fas fa-exclamation-circle"></i> ${Translate.Render('no-result-found')}`,
772
+ await BtnIcon.instance({
773
+ label: html`<i class="fas fa-exclamation-circle"></i> ${Translate.instance('no-result-found')}`,
623
774
  class: `wfa`,
624
775
  style: renderCssAttr({
625
776
  style: {
@@ -784,7 +935,7 @@ const Modal = {
784
935
  barConfig.buttons.menu.disabled = true;
785
936
  barConfig.buttons.close.disabled = false;
786
937
 
787
- await Modal.Render({
938
+ await Modal.instance({
788
939
  id: searchBoxHistoryId,
789
940
  barConfig,
790
941
  title: html`<div
@@ -794,13 +945,13 @@ const Modal = {
794
945
  <div class="search-box-recent-title">
795
946
  ${renderViewTitle({
796
947
  icon: html`<i class="fas fa-history mini-title"></i>`,
797
- text: Translate.Render('recent'),
948
+ text: Translate.instance('recent'),
798
949
  })}
799
950
  </div>
800
951
  <div class="search-box-result-title hide">
801
952
  ${renderViewTitle({
802
953
  icon: html`<i class="far fa-list-alt mini-title"></i>`,
803
- text: Translate.Render('results'),
954
+ text: Translate.instance('results'),
804
955
  })}
805
956
  </div>
806
957
  </div>
@@ -865,7 +1016,7 @@ const Modal = {
865
1016
  }
866
1017
 
867
1018
  // Add clear all button to the bar area, before the close button
868
- const clearAllBtnHtml = await BtnIcon.Render({
1019
+ const clearAllBtnHtml = await BtnIcon.instance({
869
1020
  class: `btn-search-history-clear-all btn-modal-default btn-modal-default-${searchBoxHistoryId}`,
870
1021
  label: html`<i class="fas fa-trash-alt"></i>`,
871
1022
  attrs: `title="Clear all recent items"`,
@@ -916,6 +1067,10 @@ const Modal = {
916
1067
  hoverFocusCtl.checkDismiss();
917
1068
  };
918
1069
  EventsUI.onClick(`.top-bar-search-box-container`, () => {
1070
+ if (SearchBox.Data.skipOpen) {
1071
+ SearchBox.Data.skipOpen = false;
1072
+ return;
1073
+ }
919
1074
  searchBoxHistoryOpen();
920
1075
  searchBoxCallBack(formDataInfoNode[0]);
921
1076
  const inputEl = s(`.${inputSearchBoxId}`);
@@ -1032,7 +1187,7 @@ const Modal = {
1032
1187
  barConfig.buttons.menu.disabled = true;
1033
1188
  barConfig.buttons.close.disabled = true;
1034
1189
  const id = 'main-body';
1035
- await Modal.Render({
1190
+ await Modal.instance({
1036
1191
  id,
1037
1192
  barConfig,
1038
1193
  html: options.htmlMainBody ? options.htmlMainBody : () => html``,
@@ -1055,26 +1210,29 @@ const Modal = {
1055
1210
  const maxWidthInputSearchBox = 450;
1056
1211
  const paddingInputSearchBox = 5;
1057
1212
  const paddingRightSearchBox = 50;
1058
- Responsive.Event[`view-${id}`] = () => {
1059
- if (!this.Data[id] || !s(`.${id}`)) return delete Responsive.Event[`view-${id}`];
1060
- const widthInputSearchBox =
1061
- windowGetW() > maxWidthInputSearchBox ? maxWidthInputSearchBox : windowGetW();
1062
- s(`.top-bar-search-box-container`).style.width = `${
1063
- widthInputSearchBox - originHeightTopBar - paddingRightSearchBox - 1
1064
- }px`;
1065
- s(`.top-bar-search-box`).style.width = `${
1066
- widthInputSearchBox -
1067
- originHeightTopBar * 2 -
1068
- paddingRightSearchBox -
1069
- paddingInputSearchBox * 2 /*padding input*/ -
1070
- 10 /* right-margin */
1071
- }px`;
1072
- s(`.top-bar-search-box`).style.top = `${
1073
- (originHeightTopBar - s(`.top-bar-search-box`).clientHeight) / 2
1074
- }px`;
1075
- if (this.Data[id].slideMenu) s(`.${id}`).style.height = `${Modal.Data[id].getHeight()}px`;
1076
- };
1077
- Responsive.Event[`view-${id}`]();
1213
+ Responsive.onChanged(
1214
+ () => {
1215
+ if (!this.Data[id] || !s(`.${id}`)) return Responsive.offChanged(`view-${id}`);
1216
+ const widthInputSearchBox =
1217
+ windowGetW() > maxWidthInputSearchBox ? maxWidthInputSearchBox : windowGetW();
1218
+ s(`.top-bar-search-box-container`).style.width = `${
1219
+ widthInputSearchBox - originHeightTopBar - paddingRightSearchBox - 1
1220
+ }px`;
1221
+ s(`.top-bar-search-box`).style.width = `${
1222
+ widthInputSearchBox -
1223
+ originHeightTopBar * 2 -
1224
+ paddingRightSearchBox -
1225
+ paddingInputSearchBox * 2 /*padding input*/ -
1226
+ 10 /* right-margin */
1227
+ }px`;
1228
+ s(`.top-bar-search-box`).style.top = `${
1229
+ (originHeightTopBar - s(`.top-bar-search-box`).clientHeight) / 2
1230
+ }px`;
1231
+ if (this.Data[id].slideMenu) s(`.${id}`).style.height = `${Modal.Data[id].getHeight()}px`;
1232
+ },
1233
+ { key: `view-${id}` },
1234
+ );
1235
+ Responsive.triggerChanged(`view-${id}`);
1078
1236
  Keyboard.instanceMultiPressKey({
1079
1237
  id: 'input-search-shortcut-k',
1080
1238
  keys: [
@@ -1127,7 +1285,7 @@ const Modal = {
1127
1285
  class="fl ${options.barClass ? options.barClass : ''}"
1128
1286
  style="height: ${originHeightBottomBar}px;"
1129
1287
  >
1130
- ${await BtnIcon.Render({
1288
+ ${await BtnIcon.instance({
1131
1289
  style: `height: 100%`,
1132
1290
  class: `in fl${
1133
1291
  options.mode === 'slide-menu-right' ? 'r' : 'l'
@@ -1142,35 +1300,35 @@ const Modal = {
1142
1300
  </div>
1143
1301
  `,
1144
1302
  })}
1145
- ${await BtnIcon.Render({
1303
+ ${await BtnIcon.instance({
1146
1304
  style: `height: 100%`,
1147
1305
  class: `in flr main-btn-menu action-bar-box action-btn-lang ${
1148
1306
  options?.disableTools?.includes('lang') ? 'hide' : ''
1149
1307
  }`,
1150
1308
  label: html` <div class="${contentIconClass} action-btn-lang-render"></div>`,
1151
1309
  })}
1152
- ${await BtnIcon.Render({
1310
+ ${await BtnIcon.instance({
1153
1311
  style: `height: 100%`,
1154
1312
  class: `in flr main-btn-menu action-bar-box action-btn-theme ${
1155
1313
  options?.disableTools?.includes('theme') ? 'hide' : ''
1156
1314
  }`,
1157
1315
  label: html` <div class="${contentIconClass} action-btn-theme-render"></div>`,
1158
1316
  })}
1159
- ${await BtnIcon.Render({
1317
+ ${await BtnIcon.instance({
1160
1318
  style: `height: 100%`,
1161
1319
  class: `in flr main-btn-menu action-bar-box action-btn-home ${
1162
1320
  options?.disableTools?.includes('navigator') ? 'hide' : ''
1163
1321
  }`,
1164
1322
  label: html` <div class="${contentIconClass}"><i class="fas fa-home"></i></div>`,
1165
1323
  })}
1166
- ${await BtnIcon.Render({
1324
+ ${await BtnIcon.instance({
1167
1325
  style: `height: 100%`,
1168
1326
  class: `in flr main-btn-menu action-bar-box action-btn-right ${
1169
1327
  options?.disableTools?.includes('navigator') ? 'hide' : ''
1170
1328
  }`,
1171
1329
  label: html` <div class="${contentIconClass}"><i class="fas fa-chevron-right"></i></div>`,
1172
1330
  })}
1173
- ${await BtnIcon.Render({
1331
+ ${await BtnIcon.instance({
1174
1332
  style: `height: 100%`,
1175
1333
  class: `in flr main-btn-menu action-bar-box action-btn-left ${
1176
1334
  options?.disableTools?.includes('navigator') ? 'hide' : ''
@@ -1182,7 +1340,7 @@ const Modal = {
1182
1340
  if (options.heightBottomBar === 0 && options.heightTopBar > 0) {
1183
1341
  append(`.slide-menu-top-bar`, html` <div class="in ${id}">${await html()}</div>`);
1184
1342
  } else {
1185
- await Modal.Render({
1343
+ await Modal.instance({
1186
1344
  id,
1187
1345
  barConfig,
1188
1346
  html,
@@ -1201,13 +1359,16 @@ const Modal = {
1201
1359
  // maximize: true,
1202
1360
  barMode: options.barMode,
1203
1361
  });
1204
- Responsive.Event[`view-${id}`] = () => {
1205
- if (!this.Data[id] || !s(`.${id}`)) return delete Responsive.Event[`view-${id}`];
1206
- // <div class="in fll right-offset-menu-bottom-bar" style="height: 100%"></div>
1207
- // s(`.right-offset-menu-bottom-bar`).style.width = `${windowGetW() - slideMenuWidth}px`;
1208
- s(`.${id}`).style.top = `${Modal.Data['modal-menu'].getTop()}px`;
1209
- s(`.${id}`).style.width = `${windowGetW()}px`;
1210
- };
1362
+ Responsive.onChanged(
1363
+ () => {
1364
+ if (!this.Data[id] || !s(`.${id}`)) return Responsive.offChanged(`view-${id}`);
1365
+ // <div class="in fll right-offset-menu-bottom-bar" style="height: 100%"></div>
1366
+ // s(`.right-offset-menu-bottom-bar`).style.width = `${windowGetW() - slideMenuWidth}px`;
1367
+ s(`.${id}`).style.top = `${Modal.Data['modal-menu'].getTop()}px`;
1368
+ s(`.${id}`).style.width = `${windowGetW()}px`;
1369
+ },
1370
+ { key: `view-${id}` },
1371
+ );
1211
1372
  // Responsive.Event[`view-${id}`]();
1212
1373
  }
1213
1374
  EventsUI.onClick(`.action-btn-left`, (e) => {
@@ -1290,12 +1451,12 @@ const Modal = {
1290
1451
  barConfig.buttons.restore.disabled = true;
1291
1452
  barConfig.buttons.menu.disabled = true;
1292
1453
  barConfig.buttons.close.disabled = false;
1293
- await Modal.Render({
1454
+ await Modal.instance({
1294
1455
  id,
1295
1456
  barConfig,
1296
1457
  title: html`${renderViewTitle({
1297
1458
  icon: html`<i class="fas fa-language mini-title"></i>`,
1298
- text: Translate.Render('select lang'),
1459
+ text: Translate.instance('select lang'),
1299
1460
  })}`,
1300
1461
  html: async () => html`${await Translate.RenderSetting('action-drop-modal' + id)}`,
1301
1462
  titleClass: 'mini-title',
@@ -1349,7 +1510,7 @@ const Modal = {
1349
1510
  barConfig.buttons.menu.disabled = true;
1350
1511
  barConfig.buttons.close.disabled = true;
1351
1512
  const id = 'main-body-top';
1352
- await Modal.Render({
1513
+ await Modal.instance({
1353
1514
  id,
1354
1515
  barConfig,
1355
1516
  html: () => html``,
@@ -1368,24 +1529,27 @@ const Modal = {
1368
1529
  barMode: options.barMode,
1369
1530
  });
1370
1531
 
1371
- Responsive.Event[`view-${id}`] = () => {
1372
- if (!this.Data[id] || !s(`.${id}`)) return delete Responsive.Event[`view-${id}`];
1373
- s(`.${id}`).style.height =
1374
- s(`.main-body-btn-ui-close`).classList.contains('hide') &&
1375
- s(`.btn-restore-${id}`).style.display !== 'none'
1376
- ? `${windowGetH()}px`
1377
- : `${Modal.Data[id].getHeight()}px`;
1378
-
1379
- if (
1380
- s(`.main-body-btn-ui-close`).classList.contains('hide') &&
1381
- s(`.btn-restore-${id}`).style.display !== 'none'
1382
- ) {
1383
- s(`.${id}`).style.top = '0px';
1384
- } else {
1385
- s(`.${id}`).style.top = `${options.heightTopBar ? options.heightTopBar : heightDefaultTopBar}px`;
1386
- }
1387
- };
1388
- Responsive.Event[`view-${id}`]();
1532
+ Responsive.onChanged(
1533
+ () => {
1534
+ if (!this.Data[id] || !s(`.${id}`)) return Responsive.offChanged(`view-${id}`);
1535
+ s(`.${id}`).style.height =
1536
+ s(`.main-body-btn-ui-close`).classList.contains('hide') &&
1537
+ s(`.btn-restore-${id}`).style.display !== 'none'
1538
+ ? `${windowGetH()}px`
1539
+ : `${Modal.Data[id].getHeight()}px`;
1540
+
1541
+ if (
1542
+ s(`.main-body-btn-ui-close`).classList.contains('hide') &&
1543
+ s(`.btn-restore-${id}`).style.display !== 'none'
1544
+ ) {
1545
+ s(`.${id}`).style.top = '0px';
1546
+ } else {
1547
+ s(`.${id}`).style.top = `${options.heightTopBar ? options.heightTopBar : heightDefaultTopBar}px`;
1548
+ }
1549
+ },
1550
+ { key: `view-${id}` },
1551
+ );
1552
+ Responsive.triggerChanged(`view-${id}`);
1389
1553
 
1390
1554
  s(`.main-body-top`).onclick = () => s(`.btn-close-modal-menu`).click();
1391
1555
  }
@@ -1511,7 +1675,7 @@ const Modal = {
1511
1675
  >
1512
1676
  <div class="btn-bar-modal-container-render-${idModal}"></div>
1513
1677
  <div class="in flr bar-default-modal" style="z-index: 1">
1514
- ${await BtnIcon.Render({
1678
+ ${await BtnIcon.instance({
1515
1679
  class: `btn-minimize-${idModal} btn-modal-default btn-modal-default-${idModal} ${
1516
1680
  options?.btnContainerClass ? options.btnContainerClass : ''
1517
1681
  } ${options?.barConfig?.buttons?.minimize?.disabled ? 'hide' : ''}`,
@@ -1519,7 +1683,7 @@ const Modal = {
1519
1683
  ${options?.barConfig?.buttons?.minimize?.label ? options.barConfig.buttons.minimize.label : html`_`}
1520
1684
  </div>`,
1521
1685
  })}
1522
- ${await BtnIcon.Render({
1686
+ ${await BtnIcon.instance({
1523
1687
  class: `btn-restore-${idModal} btn-modal-default btn-modal-default-${idModal} ${
1524
1688
  options?.btnContainerClass ? options.btnContainerClass : ''
1525
1689
  } ${options?.barConfig?.buttons?.restore?.disabled ? 'hide' : ''}`,
@@ -1528,7 +1692,7 @@ const Modal = {
1528
1692
  </div>`,
1529
1693
  style: 'display: none',
1530
1694
  })}
1531
- ${await BtnIcon.Render({
1695
+ ${await BtnIcon.instance({
1532
1696
  class: `btn-maximize-${idModal} btn-modal-default btn-modal-default-${idModal} ${
1533
1697
  options?.btnContainerClass ? options.btnContainerClass : ''
1534
1698
  } ${options?.barConfig?.buttons?.maximize?.disabled ? 'hide' : ''}`,
@@ -1536,7 +1700,7 @@ const Modal = {
1536
1700
  ${options?.barConfig?.buttons?.maximize?.label ? options.barConfig.buttons.maximize.label : html`▢`}
1537
1701
  </div>`,
1538
1702
  })}
1539
- ${await BtnIcon.Render({
1703
+ ${await BtnIcon.instance({
1540
1704
  class: `btn-close-${idModal} btn-modal-default btn-modal-default-${idModal} ${
1541
1705
  options?.btnContainerClass ? options.btnContainerClass : ''
1542
1706
  } ${options?.barConfig?.buttons?.close?.disabled ? 'hide' : ''}`,
@@ -1544,7 +1708,7 @@ const Modal = {
1544
1708
  ${options?.barConfig?.buttons?.close?.label ? options.barConfig.buttons.close.label : html`X`}
1545
1709
  </div>`,
1546
1710
  })}
1547
- ${await BtnIcon.Render({
1711
+ ${await BtnIcon.instance({
1548
1712
  class: `btn-menu-${idModal} btn-modal-default btn-modal-default-${idModal} ${
1549
1713
  options?.btnContainerClass ? options.btnContainerClass : ''
1550
1714
  } ${options?.barConfig?.buttons?.menu?.disabled ? 'hide' : ''}`,
@@ -1572,7 +1736,7 @@ const Modal = {
1572
1736
  class="stq modal"
1573
1737
  style="${renderCssAttr({ style: { height: '50px', 'z-index': 1, top: '0px' } })}"
1574
1738
  >
1575
- ${await BtnIcon.Render({
1739
+ ${await BtnIcon.instance({
1576
1740
  style: renderCssAttr({ style: { height: '100%', color: '#5f5f5f' } }),
1577
1741
  class: `in flr main-btn-menu action-bar-box btn-icon-menu-mode`,
1578
1742
  label: html` <div class="abs center">
@@ -1588,14 +1752,14 @@ const Modal = {
1588
1752
  ></i>
1589
1753
  </div>`,
1590
1754
  })}
1591
- ${await BtnIcon.Render({
1755
+ ${await BtnIcon.instance({
1592
1756
  style: renderCssAttr({ style: { height: '100%', color: '#5f5f5f' } }),
1593
1757
  class: `in flr main-btn-menu action-bar-box btn-icon-menu-back hide`,
1594
1758
  label: html`<div class="abs center"><i class="fas fa-undo-alt"></i></div>`,
1595
1759
  })}
1596
1760
  <div class="abs sub-menu-title-container-${idModal} ac">
1597
1761
  <div class="abs nav-title-display-${idModal}">
1598
- <!-- <i class="fas fa-home"></i> ${Translate.Render('home')} -->
1762
+ <!-- <i class="fas fa-home"></i> ${Translate.instance('home')} -->
1599
1763
  </div>
1600
1764
  </div>
1601
1765
  <div class="abs nav-path-container-${idModal} ahc bold">
@@ -1635,7 +1799,7 @@ const Modal = {
1635
1799
  case 'slide-menu-right':
1636
1800
  case 'slide-menu-left':
1637
1801
  const backMenuButtonEvent = async () => {
1638
- // htmls(`.nav-title-display-${'modal-menu'}`, html`<i class="fas fa-home"></i> ${Translate.Render('home')}`);
1802
+ // htmls(`.nav-title-display-${'modal-menu'}`, html`<i class="fas fa-home"></i> ${Translate.instance('home')}`);
1639
1803
  htmls(`.nav-title-display-${'modal-menu'}`, html``);
1640
1804
  htmls(`.nav-path-display-${idModal}`, '');
1641
1805
  s(`.btn-icon-menu-back`).classList.add('hide');
@@ -1667,6 +1831,12 @@ const Modal = {
1667
1831
  if (options.onCollapseMenu) options.onCollapseMenu();
1668
1832
  s(`.sub-menu-title-container-${'modal-menu'}`).classList.add('hide');
1669
1833
  s(`.nav-path-container-${'modal-menu'}`).classList.add('hide');
1834
+ // Shrink any already-open submenu containers to icon-only width
1835
+ Object.keys(Modal.subMenuBtnClass).forEach((subMenuId) => {
1836
+ const container = s(`.menu-btn-container-children-${subMenuId}`);
1837
+ if (container && container.style.height && container.style.height !== '0px')
1838
+ container.style.width = `${collapseSlideMenuWidth}px`;
1839
+ });
1670
1840
  Object.keys(this.Data[idModal].onCollapseMenuListener).map((keyListener) =>
1671
1841
  this.Data[idModal].onCollapseMenuListener[keyListener](),
1672
1842
  );
@@ -1684,12 +1854,18 @@ const Modal = {
1684
1854
  if (options.onExtendMenu) options.onExtendMenu();
1685
1855
  s(`.sub-menu-title-container-${'modal-menu'}`).classList.remove('hide');
1686
1856
  s(`.nav-path-container-${'modal-menu'}`).classList.remove('hide');
1857
+ // Expand any already-open submenu containers back to full width
1858
+ Object.keys(Modal.subMenuBtnClass).forEach((subMenuId) => {
1859
+ const container = s(`.menu-btn-container-children-${subMenuId}`);
1860
+ if (container && container.style.height && container.style.height !== '0px')
1861
+ container.style.width = `${originSlideMenuWidth}px`;
1862
+ });
1687
1863
  Object.keys(this.Data[idModal].onExtendMenuListener).map((keyListener) =>
1688
1864
  this.Data[idModal].onExtendMenuListener[keyListener](),
1689
1865
  );
1690
1866
  }
1691
1867
  Modal.Data[idModal][options.mode].width = slideMenuWidth;
1692
- Responsive.Event[`slide-menu-${idModal}`]();
1868
+ Responsive.triggerChanged(`slide-menu-${idModal}`);
1693
1869
  });
1694
1870
 
1695
1871
  break;
@@ -1964,22 +2140,25 @@ const Modal = {
1964
2140
  callBack,
1965
2141
  id: options.slideMenu,
1966
2142
  };
1967
- Responsive.Event['h-ui-hide-' + idModal] = () => {
1968
- setTimeout(() => {
1969
- if (!s(`.${idModal}`) || !s(`.main-body-btn-ui-close`)) return;
1970
- if (s(`.btn-restore-${idModal}`) && s(`.btn-restore-${idModal}`).style.display !== 'none') {
1971
- s(`.${idModal}`).style.height = s(`.main-body-btn-ui-close`).classList.contains('hide')
1972
- ? `${windowGetH()}px`
1973
- : `${Modal.Data[idModal].getHeight()}px`;
1974
- }
1975
- s(`.${idModal}`).style.top = s(`.main-body-btn-ui-close`).classList.contains('hide')
1976
- ? `0px`
1977
- : `${options.heightTopBar ? options.heightTopBar : heightDefaultTopBar}px`;
1978
- });
1979
- };
1980
- Responsive.Event['h-ui-hide-' + idModal]();
2143
+ Responsive.onChanged(
2144
+ () => {
2145
+ setTimeout(() => {
2146
+ if (!s(`.${idModal}`) || !s(`.main-body-btn-ui-close`)) return;
2147
+ if (s(`.btn-restore-${idModal}`) && s(`.btn-restore-${idModal}`).style.display !== 'none') {
2148
+ s(`.${idModal}`).style.height = s(`.main-body-btn-ui-close`).classList.contains('hide')
2149
+ ? `${windowGetH()}px`
2150
+ : `${Modal.Data[idModal].getHeight()}px`;
2151
+ }
2152
+ s(`.${idModal}`).style.top = s(`.main-body-btn-ui-close`).classList.contains('hide')
2153
+ ? `0px`
2154
+ : `${options.heightTopBar ? options.heightTopBar : heightDefaultTopBar}px`;
2155
+ });
2156
+ },
2157
+ { key: 'h-ui-hide-' + idModal },
2158
+ );
2159
+ Responsive.triggerChanged('h-ui-hide-' + idModal);
1981
2160
  } else {
1982
- delete Responsive.Event['h-ui-hide-' + idModal];
2161
+ Responsive.offChanged('h-ui-hide-' + idModal);
1983
2162
  s(`.${idModal}`).style.width = '100%';
1984
2163
  s(`.${idModal}`).style.height = '100%';
1985
2164
  s(`.${idModal}`).style.top = `${options.heightTopBar ? options.heightTopBar : heightDefaultTopBar}px`;
@@ -2001,7 +2180,6 @@ const Modal = {
2001
2180
  dragInstance = setDragInstance();
2002
2181
  if (options && options.maximize) s(`.btn-maximize-${idModal}`).click();
2003
2182
  if (options.observer) {
2004
- this.Data[idModal].onObserverListener = {};
2005
2183
  this.Data[idModal].observerCallBack = () => {
2006
2184
  // logger.info('ResizeObserver', `.${idModal}`, s(`.${idModal}`).offsetWidth, s(`.${idModal}`).offsetHeight);
2007
2185
  if (this.Data[idModal] && this.Data[idModal].onObserverListener)
@@ -2029,10 +2207,13 @@ const Modal = {
2029
2207
  id: idModal,
2030
2208
  ...this.Data[idModal],
2031
2209
  };
2032
- },
2033
- subMenuBtnClass: {},
2210
+ }
2034
2211
 
2035
- onHomeRouterEvent: async () => {
2212
+ /** @type {Object.<string, object>} */
2213
+ static subMenuBtnClass = {};
2214
+
2215
+ /** Navigate to the home route and close all non-home modals. */
2216
+ static onHomeRouterEvent = async () => {
2036
2217
  // 1. Get list of modals to close.
2037
2218
  const modalsToClose = Object.keys(Modal.Data).filter((idModal) => {
2038
2219
  const modal = Modal.Data[idModal];
@@ -2072,9 +2253,16 @@ const Modal = {
2072
2253
  if (s(`.btn-close-modal-menu`) && !s(`.btn-close-modal-menu`).classList.contains('hide')) {
2073
2254
  s(`.btn-close-modal-menu`).click();
2074
2255
  }
2075
- },
2076
- currentTopModalId: '',
2077
- zIndexSync: function ({ idModal }) {
2256
+ };
2257
+
2258
+ /** @type {string} */
2259
+ static currentTopModalId = '';
2260
+
2261
+ /**
2262
+ * Synchronise z-index for view modals, promoting the given modal to top.
2263
+ * @param {{ idModal: string }} param0
2264
+ */
2265
+ static zIndexSync({ idModal }) {
2078
2266
  setTimeout(() => {
2079
2267
  if (!this.Data[idModal]) return;
2080
2268
  const cleanTopModal = () => {
@@ -2100,14 +2288,30 @@ const Modal = {
2100
2288
  }
2101
2289
  };
2102
2290
  });
2103
- },
2104
- setTopModalCallback: function (idModal) {
2291
+ }
2292
+
2293
+ /**
2294
+ * @param {string} idModal
2295
+ */
2296
+ static setTopModalCallback(idModal) {
2105
2297
  s(`.${idModal}`).style.zIndex = '4';
2106
2298
  this.currentTopModalId = `${idModal}`;
2107
- },
2108
- mobileModal: () => windowGetW() < 600 || windowGetH() < 600,
2109
- writeHTML: ({ idModal, html }) => htmls(`.html-${idModal}`, html),
2110
- updateModal: async function ({ idModal, html, title }) {
2299
+ }
2300
+
2301
+ /** @returns {boolean} True when the viewport is considered mobile-sized. */
2302
+ static mobileModal = () => windowGetW() < 600 || windowGetH() < 600;
2303
+
2304
+ /**
2305
+ * @param {{ idModal: string, html: string }} param0
2306
+ */
2307
+ static writeHTML = ({ idModal, html }) => htmls(`.html-${idModal}`, html);
2308
+
2309
+ /**
2310
+ * Update an existing modal's content and/or title.
2311
+ * @param {{ idModal: string, html?: string, title?: string }} param0
2312
+ * @returns {Promise<boolean>}
2313
+ */
2314
+ static async updateModal({ idModal, html, title }) {
2111
2315
  if (!this.Data[idModal] || !s(`.${idModal}`)) {
2112
2316
  console.warn(`Modal ${idModal} not found for update`);
2113
2317
  return false;
@@ -2134,19 +2338,32 @@ const Modal = {
2134
2338
  }
2135
2339
 
2136
2340
  return true;
2137
- },
2138
- viewModalOpen: function () {
2341
+ }
2342
+
2343
+ /** @returns {string|undefined} Id of the first open view-mode modal, or undefined. */
2344
+ static viewModalOpen() {
2139
2345
  return Object.keys(this.Data).find((idModal) => s(`.${idModal}`) && this.Data[idModal].options.mode === 'view');
2140
- },
2141
- removeModal: function (idModal) {
2346
+ }
2347
+
2348
+ /**
2349
+ * Remove a modal element and its style tags, and delete its data entry.
2350
+ * @param {string} idModal
2351
+ */
2352
+ static removeModal(idModal) {
2142
2353
  if (!s(`.${idModal}`)) return;
2143
2354
  s(`.${idModal}`).remove();
2144
2355
  sa(`.style-${idModal}`).forEach((element) => {
2145
2356
  element.remove();
2146
2357
  });
2147
2358
  delete this.Data[idModal];
2148
- },
2149
- RenderConfirm: async function (options) {
2359
+ }
2360
+
2361
+ /**
2362
+ * Render a confirmation dialog and return a promise resolving to the user's choice.
2363
+ * @param {{ id: string, html: Function, icon?: string, disableBtnCancel?: boolean }} options
2364
+ * @returns {Promise<{ status: 'confirm'|'cancelled' }>}
2365
+ */
2366
+ static async RenderConfirm(options) {
2150
2367
  const { id } = options;
2151
2368
  append(
2152
2369
  'body',
@@ -2189,23 +2406,23 @@ const Modal = {
2189
2406
  </div>
2190
2407
  ${await options.html()}
2191
2408
  <div class="in section-mp">
2192
- ${await BtnIcon.Render({
2409
+ ${await BtnIcon.instance({
2193
2410
  class: `in section-mp form-button btn-confirm-${id}`,
2194
- label: Translate.Render('confirm'),
2411
+ label: Translate.instance('confirm'),
2195
2412
  type: 'submit',
2196
2413
  style: `margin: auto`,
2197
2414
  })}
2198
2415
  </div>
2199
2416
  <div class="in section-mp ${options.disableBtnCancel ? 'hide' : ''}">
2200
- ${await BtnIcon.Render({
2417
+ ${await BtnIcon.instance({
2201
2418
  class: `in section-mp form-button btn-cancel-${id}`,
2202
- label: Translate.Render('cancel'),
2419
+ label: Translate.instance('cancel'),
2203
2420
  type: 'submit',
2204
2421
  style: `margin: auto`,
2205
2422
  })}
2206
2423
  </div>
2207
2424
  `;
2208
- await Modal.Render({
2425
+ await Modal.instance({
2209
2426
  id,
2210
2427
  barConfig,
2211
2428
  titleClass: 'hide',
@@ -2242,10 +2459,20 @@ const Modal = {
2242
2459
  resolve({ status: 'confirm' });
2243
2460
  };
2244
2461
  });
2245
- },
2246
- labelSelectorTopOffsetStartAnimation: `-40px`,
2247
- labelSelectorTopOffsetEndAnimation: `-3px`,
2248
- menuTextLabelAnimation: (idModal, subMenuId) => {
2462
+ }
2463
+
2464
+ /** @type {string} */
2465
+ static labelSelectorTopOffsetStartAnimation = `-40px`;
2466
+
2467
+ /** @type {string} */
2468
+ static labelSelectorTopOffsetEndAnimation = `-3px`;
2469
+
2470
+ /**
2471
+ * Animate slide-menu labels into view.
2472
+ * @param {string} idModal - The slide-menu modal id.
2473
+ * @param {string} [subMenuId] - If provided, animate only this sub-menu.
2474
+ */
2475
+ static menuTextLabelAnimation = (idModal, subMenuId) => {
2249
2476
  if (
2250
2477
  !s(
2251
2478
  `.btn-icon-menu-mode-${Modal.Data[idModal].options.mode === 'slide-menu-right' ? 'left' : 'right'}`,
@@ -2288,19 +2515,66 @@ const Modal = {
2288
2515
  });
2289
2516
  }, 400);
2290
2517
  }
2291
- },
2518
+ };
2519
+
2520
+ /**
2521
+ * Builds submenu item HTML using the canonical BtnIcon pattern.
2522
+ * Centralises the item-rendering contract so individual submenu owners (e.g. Docs)
2523
+ * only need to supply data — not layout concerns.
2524
+ * @param {string} subMenuId - Submenu identifier (e.g. 'docs')
2525
+ * @param {Array<{type:string, icon:string, text:string, url:function|string}>} items
2526
+ * @param {Object} [options]
2527
+ * @param {function} [options.subMenuIcon] - Optional icon override per item type
2528
+ * @returns {Promise<string>} Rendered HTML string
2529
+ */
2530
+ static buildSubMenuItemsHtml = async (subMenuId, items = [], options = {}) => {
2531
+ let result = '';
2532
+ const _menuMode = Modal.Data['modal-menu']?.options?.mode;
2533
+ const _tooltipSide = options.tooltipSide || (_menuMode === 'slide-menu-right' ? 'right' : 'left');
2534
+ for (const item of items) {
2535
+ const tabHref = typeof item.url === 'function' ? item.url() : item.url || '';
2536
+ const icon =
2537
+ options.subMenuIcon && typeof options.subMenuIcon === 'function' ? options.subMenuIcon(item.type) : item.icon;
2538
+ result += html`${await BtnIcon.instance({
2539
+ class: `in wfa main-btn-menu submenu-btn btn-${subMenuId} btn-${subMenuId}-${item.type}`,
2540
+ label: html`<span class="inl menu-btn-icon">${icon}</span
2541
+ ><span class="menu-label-text menu-label-text-${subMenuId}"> ${item.text} </span>`,
2542
+ tabHref,
2543
+ tooltipHtml: await Badge.instance(buildBadgeToolTipMenuOption(item.text, _tooltipSide)),
2544
+ useMenuBtn: true,
2545
+ })} `;
2546
+ }
2547
+ return result;
2548
+ };
2549
+
2550
+ /**
2551
+ * Injects pre-built submenu item HTML into the submenu container and syncs
2552
+ * the collapse state so labels are hidden when the menu is icon-only.
2553
+ * @param {string} subMenuId
2554
+ * @param {string} itemsHtml
2555
+ */
2556
+ static subMenuPopulate = (subMenuId, itemsHtml) => {
2557
+ htmls(`.menu-btn-container-children-${subMenuId}`, itemsHtml);
2558
+ const _menuMode = Modal.Data['modal-menu']?.options?.mode;
2559
+ const _collapseIndicatorClass =
2560
+ _menuMode === 'slide-menu-right' ? '.btn-icon-menu-mode-left' : '.btn-icon-menu-mode-right';
2561
+ if (s(_collapseIndicatorClass) && !s(_collapseIndicatorClass).classList.contains('hide')) {
2562
+ sa(`.menu-label-text-${subMenuId}`).forEach((el) => el.classList.add('hide'));
2563
+ }
2564
+ };
2565
+
2292
2566
  // Move modal title element into the bar's render container so it aligns with control buttons
2293
2567
  /**
2294
- * Position a modal relative to an anchor element
2295
- * @param {Object} options - Positioning options
2568
+ * Position a modal relative to an anchor element.
2569
+ * @param {object} options - Positioning options
2296
2570
  * @param {string} options.modalSelector - CSS selector for the modal element
2297
2571
  * @param {string} options.anchorSelector - CSS selector for the anchor element
2298
- * @param {Object} [options.offset={x: 0, y: 6}] - Offset from anchor
2572
+ * @param {object} [options.offset={x: 0, y: 6}] - Offset from anchor
2299
2573
  * @param {string} [options.align='right'] - Horizontal alignment ('left' or 'right')
2300
2574
  * @param {boolean} [options.autoVertical=true] - Whether to automatically determine vertical position
2301
2575
  * @param {boolean} [options.placeAbove] - Force position above/below anchor (overrides autoVertical)
2302
2576
  */
2303
- positionRelativeToAnchor({
2577
+ static positionRelativeToAnchor({
2304
2578
  modalSelector,
2305
2579
  anchorSelector,
2306
2580
  offset = { x: 0, y: 6 },
@@ -2372,9 +2646,13 @@ const Modal = {
2372
2646
  } catch (e) {
2373
2647
  console.error('Error positioning modal:', e);
2374
2648
  }
2375
- },
2649
+ }
2376
2650
 
2377
- MoveTitleToBar(idModal) {
2651
+ /**
2652
+ * Move the title element inside the bar button container for inline alignment.
2653
+ * @param {string} idModal
2654
+ */
2655
+ static MoveTitleToBar(idModal) {
2378
2656
  try {
2379
2657
  const titleEl = s(`.title-modal-${idModal}`);
2380
2658
  const container = s(`.btn-bar-modal-container-render-${idModal}`);
@@ -2387,8 +2665,10 @@ const Modal = {
2387
2665
  } catch (e) {
2388
2666
  // non-fatal: keep default placement if structure not present
2389
2667
  }
2390
- },
2391
- setTopBannerLink: function () {
2668
+ }
2669
+
2670
+ /** Update the top-banner anchor href and bind the home-click handler. */
2671
+ static setTopBannerLink() {
2392
2672
  if (s(`.a-link-top-banner`)) {
2393
2673
  s(`.a-link-top-banner`).setAttribute('href', `${location.origin}${getProxyPath()}`);
2394
2674
  EventsUI.onClick(`.a-link-top-banner`, (e) => {
@@ -2396,32 +2676,72 @@ const Modal = {
2396
2676
  s(`.action-btn-home`).click();
2397
2677
  });
2398
2678
  }
2399
- },
2400
- headerTitleHeight: 40,
2401
- actionBtnCenter: function () {
2679
+ }
2680
+
2681
+ /** @type {number} */
2682
+ static headerTitleHeight = 40;
2683
+
2684
+ /** Toggle the slide-menu open/close via the center action button. */
2685
+ static actionBtnCenter() {
2402
2686
  if (!s(`.btn-close-modal-menu`).classList.contains('hide')) {
2403
2687
  return s(`.btn-close-modal-menu`).click();
2404
2688
  }
2405
2689
  if (!s(`.btn-menu-modal-menu`).classList.contains('hide')) {
2406
2690
  return s(`.btn-menu-modal-menu`).click();
2407
2691
  }
2408
- },
2409
- cleanUI: function () {
2692
+ }
2693
+
2694
+ /** Hide the top-bar, bottom-bar and slide-menu (full-screen mode). */
2695
+ static cleanUI() {
2410
2696
  s(`.top-bar`).classList.add('hide');
2411
2697
  s(`.bottom-bar`).classList.add('hide');
2412
2698
  s(`.modal-menu`).classList.add('hide');
2413
- },
2414
- restoreUI: function () {
2699
+ }
2700
+
2701
+ /** Restore the top-bar, bottom-bar and slide-menu after cleanUI. */
2702
+ static restoreUI() {
2415
2703
  s(`.top-bar`).classList.remove('hide');
2416
2704
  s(`.bottom-bar`).classList.remove('hide');
2417
2705
  s(`.modal-menu`).classList.remove('hide');
2418
- },
2419
- RenderSeoSanitizer: async () => {
2706
+ }
2707
+
2708
+ /**
2709
+ * Re-applies canonical top/height layout for maximized slide-menu-backed view modals.
2710
+ * This avoids iframe navigation leaving view containers offset at the top.
2711
+ */
2712
+ static syncViewLayout() {
2713
+ const modalMenuOptions = this.Data['modal-menu']?.options || {};
2714
+ const uiCollapsed = !!s(`.main-body-btn-ui-close`) && s(`.main-body-btn-ui-close`).classList.contains('hide');
2715
+ const topOffset = uiCollapsed ? 0 : modalMenuOptions.heightTopBar ? modalMenuOptions.heightTopBar : 50;
2716
+ const bottomOffset = uiCollapsed ? 0 : modalMenuOptions.heightBottomBar ? modalMenuOptions.heightBottomBar : 0;
2717
+ const height = `${windowGetH() - topOffset - bottomOffset}px`;
2718
+
2719
+ Object.keys(this.Data).forEach((idModal) => {
2720
+ const modalData = this.Data[idModal];
2721
+ const modalEl = s(`.${idModal}`);
2722
+ if (!modalData || !modalEl || !modalData.slideMenu) return;
2723
+ if (s(`.btn-restore-${idModal}`) && s(`.btn-restore-${idModal}`).style.display === 'none') return;
2724
+
2725
+ modalEl.style.position = 'fixed';
2726
+ modalEl.style.translate = '0px 0px';
2727
+ modalEl.style.transform = '';
2728
+ modalEl.style.top = `${topOffset}px`;
2729
+ modalEl.style.height = height;
2730
+ });
2731
+
2732
+ for (const id of coreUI) {
2733
+ const key = `view-${id}`;
2734
+ if (Responsive.hasChangedListener(key)) Responsive.triggerChanged(key);
2735
+ }
2736
+ }
2737
+
2738
+ /** Add missing `alt` attributes to all images for SEO/accessibility. */
2739
+ static RenderSeoSanitizer = async () => {
2420
2740
  sa('img').forEach((img) => {
2421
2741
  if (!img.getAttribute('alt')) img.setAttribute('alt', 'image ' + Worker.title + ' ' + s4());
2422
2742
  });
2423
- },
2424
- };
2743
+ };
2744
+ }
2425
2745
 
2426
2746
  const renderMenuLabel = ({ img, src, text, icon }) => {
2427
2747
  if (!img && !src) return html`<span class="inl menu-btn-icon">${icon}</span> ${text}`;
@@ -2478,7 +2798,7 @@ const renderViewTitle = (
2478
2798
  const buildBadgeToolTipMenuOption = (id, sideKey = 'left') => {
2479
2799
  const option = {
2480
2800
  id: `tooltip-content-main-btn-${id}`,
2481
- text: `${Translate.Render(`${id}`)}`,
2801
+ text: `${Translate.instance(`${id}`)}`,
2482
2802
  classList: 'tooltip-menu',
2483
2803
  style: { top: `-40px` },
2484
2804
  };
@@ -2548,9 +2868,14 @@ const subMenuRender = async (subMenuId) => {
2548
2868
  setTimeout(() => {
2549
2869
  Modal.menuTextLabelAnimation('modal-menu', subMenuId);
2550
2870
  });
2551
- // Open animation
2871
+ // Open animation — match the current menu width (collapsed = 50px, extended = 320px)
2872
+ const _menuMode = Modal.Data['modal-menu']?.options?.mode;
2873
+ const _collapseIndicatorClass =
2874
+ _menuMode === 'slide-menu-right' ? '.btn-icon-menu-mode-left' : '.btn-icon-menu-mode-right';
2875
+ const _isMenuCollapsed = s(_collapseIndicatorClass) && !s(_collapseIndicatorClass).classList.contains('hide');
2876
+ const _menuContainerWidth = _isMenuCollapsed ? 50 : 320;
2552
2877
  setTimeout(top, 360);
2553
- menuContainer.style.width = '320px';
2878
+ menuContainer.style.width = `${_menuContainerWidth}px`;
2554
2879
  menuContainer.style.overflow = null;
2555
2880
  menuContainer.style.height = '0px';
2556
2881
  menuContainer.style.height = `${_hBtn * 6}px`;