@underpostnet/cyberia 3.2.80

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 (821) hide show
  1. package/.dockerignore +14 -0
  2. package/.env.example +144 -0
  3. package/.github/workflows/cyberia-client.cd.yml +40 -0
  4. package/.github/workflows/cyberia-server.cd.yml +40 -0
  5. package/.github/workflows/docker-image.cyberia-client.ci.yml +71 -0
  6. package/.github/workflows/docker-image.cyberia-client.dev.ci.yml +70 -0
  7. package/.github/workflows/docker-image.cyberia-server.ci.yml +71 -0
  8. package/.github/workflows/docker-image.cyberia-server.dev.ci.yml +71 -0
  9. package/.github/workflows/docker-image.engine-cyberia.ci.yml +53 -0
  10. package/.github/workflows/docker-image.engine-cyberia.dev.ci.yml +53 -0
  11. package/.github/workflows/engine-cyberia.cd.yml +157 -0
  12. package/.github/workflows/engine-cyberia.ci.yml +125 -0
  13. package/.github/workflows/ghpkg.ci.yml +160 -0
  14. package/.github/workflows/gitlab.ci.yml +20 -0
  15. package/.github/workflows/hardhat.ci.yml +82 -0
  16. package/.github/workflows/npmpkg.ci.yml +126 -0
  17. package/.github/workflows/publish.ci.yml +87 -0
  18. package/.github/workflows/publish.cyberia.ci.yml +79 -0
  19. package/.github/workflows/pwa-microservices-template-page.cd.yml +65 -0
  20. package/.github/workflows/pwa-microservices-template-test.ci.yml +33 -0
  21. package/.github/workflows/release.cd.yml +46 -0
  22. package/.nycrc +9 -0
  23. package/.prettierignore +12 -0
  24. package/.prettierrc +9 -0
  25. package/.vscode/extensions.json +10 -0
  26. package/.vscode/settings.json +26 -0
  27. package/CHANGELOG.md +2516 -0
  28. package/CLI-HELP.md +1099 -0
  29. package/Dockerfile +161 -0
  30. package/Dockerfile.dev +161 -0
  31. package/Dockerfile.test +165 -0
  32. package/LICENSE +21 -0
  33. package/README.md +259 -0
  34. package/baremetal/commission-workflows.json +211 -0
  35. package/baremetal/packer-workflows.json +24 -0
  36. package/bin/build.js +261 -0
  37. package/bin/build.template.js +33 -0
  38. package/bin/cyberia.js +5627 -0
  39. package/bin/deploy.js +1547 -0
  40. package/bin/index.js +5627 -0
  41. package/bump.config.js +27 -0
  42. package/compose.env +144 -0
  43. package/conf.js +952 -0
  44. package/deployment.yaml +418 -0
  45. package/docker-compose.yml +434 -0
  46. package/examples/static-page/README.md +150 -0
  47. package/examples/static-page/ssr-components/CustomPage.js +554 -0
  48. package/examples/static-page/static-config-example.json +57 -0
  49. package/hardhat/.env.example +31 -0
  50. package/hardhat/contracts/ObjectLayerToken.sol +391 -0
  51. package/hardhat/deployments/.gitkeep +0 -0
  52. package/hardhat/deployments/hardhat-ObjectLayerToken.json +11 -0
  53. package/hardhat/hardhat.config.js +136 -0
  54. package/hardhat/ignition/modules/.gitkeep +0 -0
  55. package/hardhat/ignition/modules/ObjectLayerToken.js +21 -0
  56. package/hardhat/networks/besu-object-layer.network.json +138 -0
  57. package/hardhat/package-lock.json +2871 -0
  58. package/hardhat/package.json +43 -0
  59. package/hardhat/scripts/deployObjectLayerToken.js +98 -0
  60. package/hardhat/test/ObjectLayerToken.js +696 -0
  61. package/hardhat/types/ethers-contracts/ObjectLayerToken.ts +690 -0
  62. package/hardhat/types/ethers-contracts/common.ts +92 -0
  63. package/hardhat/types/ethers-contracts/factories/ObjectLayerToken__factory.ts +1055 -0
  64. package/hardhat/types/ethers-contracts/factories/index.ts +4 -0
  65. package/hardhat/types/ethers-contracts/hardhat.d.ts +47 -0
  66. package/hardhat/types/ethers-contracts/index.ts +6 -0
  67. package/ipfs/configure-ipfs.sh +13 -0
  68. package/jsconfig.json +9 -0
  69. package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +48 -0
  70. package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +48 -0
  71. package/manifests/deployment/adminer/deployment.yaml +32 -0
  72. package/manifests/deployment/adminer/kustomization.yaml +7 -0
  73. package/manifests/deployment/adminer/service.yaml +13 -0
  74. package/manifests/deployment/dd-cyberia-development/deployment.yaml +418 -0
  75. package/manifests/deployment/dd-cyberia-development/grpc-service.yaml +17 -0
  76. package/manifests/deployment/dd-cyberia-development/proxy.yaml +189 -0
  77. package/manifests/deployment/dd-cyberia-development/pv-pvc.yaml +164 -0
  78. package/manifests/deployment/dd-default-development/deployment.yaml +163 -0
  79. package/manifests/deployment/dd-default-development/proxy.yaml +46 -0
  80. package/manifests/deployment/fastapi/backend-deployment.yml +120 -0
  81. package/manifests/deployment/fastapi/backend-service.yml +19 -0
  82. package/manifests/deployment/fastapi/frontend-deployment.yml +54 -0
  83. package/manifests/deployment/fastapi/frontend-service.yml +15 -0
  84. package/manifests/deployment/fastapi/initial_data.sh +8 -0
  85. package/manifests/deployment/kafka/deployment.yaml +67 -0
  86. package/manifests/deployment/mongo-express/deployment.yaml +62 -0
  87. package/manifests/deployment/phpmyadmin/deployment.yaml +54 -0
  88. package/manifests/deployment/playwright/deployment.yaml +52 -0
  89. package/manifests/deployment/spark/spark-pi-py.yaml +20 -0
  90. package/manifests/deployment/tensorflow/tf-gpu-test.yaml +63 -0
  91. package/manifests/envoy-service-nodeport.yaml +22 -0
  92. package/manifests/grafana/deployment.yaml +64 -0
  93. package/manifests/grafana/kustomization.yaml +7 -0
  94. package/manifests/grafana/pvc.yaml +12 -0
  95. package/manifests/grafana/service.yaml +14 -0
  96. package/manifests/grafana/storage-class.yaml +9 -0
  97. package/manifests/ipfs/configmap.yaml +64 -0
  98. package/manifests/ipfs/headless-service.yaml +35 -0
  99. package/manifests/ipfs/kustomization.yaml +8 -0
  100. package/manifests/ipfs/statefulset.yaml +149 -0
  101. package/manifests/ipfs/storage-class.yaml +9 -0
  102. package/manifests/kind-config-dev.yaml +20 -0
  103. package/manifests/kind-config.yaml +12 -0
  104. package/manifests/kubeadm-calico-config.yaml +14 -0
  105. package/manifests/letsencrypt-prod.yaml +14 -0
  106. package/manifests/lxd/lxd-admin-profile.yaml +26 -0
  107. package/manifests/lxd/lxd-preseed.yaml +30 -0
  108. package/manifests/mariadb/kustomization.yaml +9 -0
  109. package/manifests/mariadb/pv.yaml +12 -0
  110. package/manifests/mariadb/pvc.yaml +10 -0
  111. package/manifests/mariadb/service.yaml +10 -0
  112. package/manifests/mariadb/statefulset.yaml +56 -0
  113. package/manifests/mariadb/storage-class.yaml +10 -0
  114. package/manifests/mongodb/headless-service.yaml +10 -0
  115. package/manifests/mongodb/kustomization.yaml +11 -0
  116. package/manifests/mongodb/pv-pvc.yaml +59 -0
  117. package/manifests/mongodb/statefulset.yaml +113 -0
  118. package/manifests/mongodb/storage-class.yaml +9 -0
  119. package/manifests/mongodb-4.4/headless-service.yaml +10 -0
  120. package/manifests/mongodb-4.4/kustomization.yaml +9 -0
  121. package/manifests/mongodb-4.4/mongodb-nodeport.yaml +17 -0
  122. package/manifests/mongodb-4.4/pv-pvc.yaml +19 -0
  123. package/manifests/mongodb-4.4/service-deployment.yaml +61 -0
  124. package/manifests/mongodb-4.4/statefulset.yaml +79 -0
  125. package/manifests/mongodb-4.4/storage-class.yaml +9 -0
  126. package/manifests/mysql/kustomization.yaml +7 -0
  127. package/manifests/mysql/pv-pvc.yaml +27 -0
  128. package/manifests/mysql/statefulset.yaml +55 -0
  129. package/manifests/postgresql/configmap.yaml +9 -0
  130. package/manifests/postgresql/kustomization.yaml +10 -0
  131. package/manifests/postgresql/pv.yaml +15 -0
  132. package/manifests/postgresql/pvc.yaml +13 -0
  133. package/manifests/postgresql/service.yaml +10 -0
  134. package/manifests/postgresql/statefulset.yaml +37 -0
  135. package/manifests/prometheus/deployment.yaml +82 -0
  136. package/manifests/pv-pvc-dd.yaml +34 -0
  137. package/manifests/valkey/kustomization.yaml +7 -0
  138. package/manifests/valkey/service.yaml +10 -0
  139. package/manifests/valkey/statefulset.yaml +37 -0
  140. package/manifests/valkey/valkey-nodeport.yaml +17 -0
  141. package/mongodb/entrypoint.sh +76 -0
  142. package/nginx.conf +128 -0
  143. package/nodemon.json +6 -0
  144. package/package.json +101 -0
  145. package/packer/images/Rocky9Amd64/Makefile +62 -0
  146. package/packer/images/Rocky9Amd64/QUICKSTART.md +113 -0
  147. package/packer/images/Rocky9Amd64/README.md +122 -0
  148. package/packer/images/Rocky9Amd64/http/rocky9.ks.pkrtpl.hcl +114 -0
  149. package/packer/images/Rocky9Amd64/rocky9.pkr.hcl +164 -0
  150. package/packer/images/Rocky9Arm64/Makefile +69 -0
  151. package/packer/images/Rocky9Arm64/README.md +122 -0
  152. package/packer/images/Rocky9Arm64/http/rocky9.ks.pkrtpl.hcl +114 -0
  153. package/packer/images/Rocky9Arm64/rocky9.pkr.hcl +171 -0
  154. package/packer/scripts/fuse-nbd +64 -0
  155. package/packer/scripts/fuse-tar-root +63 -0
  156. package/proxy.yaml +189 -0
  157. package/pv-pvc.yaml +164 -0
  158. package/scripts/device-scan.sh +65 -0
  159. package/scripts/disk-clean.sh +182 -0
  160. package/scripts/disk-devices.sh +13 -0
  161. package/scripts/gen-fqdns.sh +14 -0
  162. package/scripts/gpu-diag.sh +19 -0
  163. package/scripts/ip-info.sh +118 -0
  164. package/scripts/ipxe-setup.sh +200 -0
  165. package/scripts/k3s-node-setup.sh +124 -0
  166. package/scripts/kubeadm-node-setup.sh +317 -0
  167. package/scripts/link-local-underpost-cli.sh +6 -0
  168. package/scripts/lxd-vm-setup.sh +208 -0
  169. package/scripts/maas-nat-firewalld.sh +145 -0
  170. package/scripts/maas-setup.sh +135 -0
  171. package/scripts/maas-upload-boot-resource.sh +183 -0
  172. package/scripts/nat-iptables.sh +111 -0
  173. package/scripts/nvim.sh +91 -0
  174. package/scripts/packer-init-vars-file.sh +40 -0
  175. package/scripts/packer-setup.sh +289 -0
  176. package/scripts/ports-ls.sh +33 -0
  177. package/scripts/quick-tftp.sh +19 -0
  178. package/scripts/rhel-grpc-setup.sh +56 -0
  179. package/scripts/rocky-kickstart.sh +986 -0
  180. package/scripts/rocky-pwa.sh +200 -0
  181. package/scripts/rocky-setup.sh +106 -0
  182. package/scripts/rpmfusion-ffmpeg-setup.sh +32 -0
  183. package/scripts/ssl.sh +170 -0
  184. package/scripts/test-monitor.sh +248 -0
  185. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.controller.js +30 -0
  186. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.model.js +155 -0
  187. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.router.js +39 -0
  188. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.service.js +382 -0
  189. package/src/api/core/core.controller.js +8 -0
  190. package/src/api/core/core.model.js +11 -0
  191. package/src/api/core/core.router.js +23 -0
  192. package/src/api/core/core.service.js +30 -0
  193. package/src/api/crypto/crypto.controller.js +10 -0
  194. package/src/api/crypto/crypto.model.js +23 -0
  195. package/src/api/crypto/crypto.router.js +23 -0
  196. package/src/api/crypto/crypto.service.js +64 -0
  197. package/src/api/cyberia-action/cyberia-action.controller.js +8 -0
  198. package/src/api/cyberia-action/cyberia-action.model.js +79 -0
  199. package/src/api/cyberia-action/cyberia-action.router.js +21 -0
  200. package/src/api/cyberia-action/cyberia-action.service.js +58 -0
  201. package/src/api/cyberia-client-hints/cyberia-client-hints.controller.js +27 -0
  202. package/src/api/cyberia-client-hints/cyberia-client-hints.model.js +100 -0
  203. package/src/api/cyberia-client-hints/cyberia-client-hints.router.js +70 -0
  204. package/src/api/cyberia-client-hints/cyberia-client-hints.service.js +152 -0
  205. package/src/api/cyberia-dialogue/cyberia-dialogue.controller.js +8 -0
  206. package/src/api/cyberia-dialogue/cyberia-dialogue.model.js +36 -0
  207. package/src/api/cyberia-dialogue/cyberia-dialogue.router.js +20 -0
  208. package/src/api/cyberia-dialogue/cyberia-dialogue.service.js +57 -0
  209. package/src/api/cyberia-entity/cyberia-entity.controller.js +6 -0
  210. package/src/api/cyberia-entity/cyberia-entity.model.js +25 -0
  211. package/src/api/cyberia-entity/cyberia-entity.router.js +17 -0
  212. package/src/api/cyberia-entity/cyberia-entity.service.js +42 -0
  213. package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.controller.js +6 -0
  214. package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.model.js +67 -0
  215. package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.router.js +17 -0
  216. package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.service.js +46 -0
  217. package/src/api/cyberia-instance/cyberia-fallback-world.js +337 -0
  218. package/src/api/cyberia-instance/cyberia-instance-boot.service.js +57 -0
  219. package/src/api/cyberia-instance/cyberia-instance-map.service.js +583 -0
  220. package/src/api/cyberia-instance/cyberia-instance.controller.js +42 -0
  221. package/src/api/cyberia-instance/cyberia-instance.model.js +117 -0
  222. package/src/api/cyberia-instance/cyberia-instance.router.js +75 -0
  223. package/src/api/cyberia-instance/cyberia-instance.service.js +190 -0
  224. package/src/api/cyberia-instance/cyberia-portal-connector.js +260 -0
  225. package/src/api/cyberia-instance/cyberia-world-generator.js +618 -0
  226. package/src/api/cyberia-instance-conf/cyberia-instance-conf.controller.js +6 -0
  227. package/src/api/cyberia-instance-conf/cyberia-instance-conf.model.js +200 -0
  228. package/src/api/cyberia-instance-conf/cyberia-instance-conf.router.js +17 -0
  229. package/src/api/cyberia-instance-conf/cyberia-instance-conf.service.js +46 -0
  230. package/src/api/cyberia-map/cyberia-map.controller.js +6 -0
  231. package/src/api/cyberia-map/cyberia-map.model.js +33 -0
  232. package/src/api/cyberia-map/cyberia-map.router.js +19 -0
  233. package/src/api/cyberia-map/cyberia-map.service.js +76 -0
  234. package/src/api/cyberia-quest/cyberia-quest.controller.js +9 -0
  235. package/src/api/cyberia-quest/cyberia-quest.model.js +67 -0
  236. package/src/api/cyberia-quest/cyberia-quest.router.js +26 -0
  237. package/src/api/cyberia-quest/cyberia-quest.service.js +97 -0
  238. package/src/api/cyberia-quest-progress/cyberia-quest-progress.controller.js +6 -0
  239. package/src/api/cyberia-quest-progress/cyberia-quest-progress.model.js +49 -0
  240. package/src/api/cyberia-quest-progress/cyberia-quest-progress.router.js +21 -0
  241. package/src/api/cyberia-quest-progress/cyberia-quest-progress.service.js +42 -0
  242. package/src/api/cyberia-saga/cyberia-saga.controller.js +6 -0
  243. package/src/api/cyberia-saga/cyberia-saga.model.js +59 -0
  244. package/src/api/cyberia-saga/cyberia-saga.router.js +17 -0
  245. package/src/api/cyberia-saga/cyberia-saga.service.js +42 -0
  246. package/src/api/cyberia-server-defaults/cyberia-server-defaults.js +1076 -0
  247. package/src/api/cyberia-skill/cyberia-skill.controller.js +6 -0
  248. package/src/api/cyberia-skill/cyberia-skill.model.js +50 -0
  249. package/src/api/cyberia-skill/cyberia-skill.router.js +17 -0
  250. package/src/api/cyberia-skill/cyberia-skill.service.js +42 -0
  251. package/src/api/default/default.controller.js +6 -0
  252. package/src/api/default/default.model.js +20 -0
  253. package/src/api/default/default.router.js +21 -0
  254. package/src/api/default/default.service.js +42 -0
  255. package/src/api/document/document.controller.js +9 -0
  256. package/src/api/document/document.model.js +95 -0
  257. package/src/api/document/document.router.js +32 -0
  258. package/src/api/document/document.service.js +633 -0
  259. package/src/api/file/file.controller.js +15 -0
  260. package/src/api/file/file.model.js +127 -0
  261. package/src/api/file/file.ref.json +39 -0
  262. package/src/api/file/file.router.js +36 -0
  263. package/src/api/file/file.service.js +499 -0
  264. package/src/api/instance/instance.controller.js +8 -0
  265. package/src/api/instance/instance.model.js +34 -0
  266. package/src/api/instance/instance.router.js +27 -0
  267. package/src/api/instance/instance.service.js +75 -0
  268. package/src/api/ipfs/ipfs.controller.js +8 -0
  269. package/src/api/ipfs/ipfs.model.js +77 -0
  270. package/src/api/ipfs/ipfs.router.js +26 -0
  271. package/src/api/ipfs/ipfs.service.js +145 -0
  272. package/src/api/object-layer/object-layer.controller.js +18 -0
  273. package/src/api/object-layer/object-layer.model.js +200 -0
  274. package/src/api/object-layer/object-layer.router.js +729 -0
  275. package/src/api/object-layer/object-layer.service.js +894 -0
  276. package/src/api/object-layer-render-frames/object-layer-render-frames.controller.js +6 -0
  277. package/src/api/object-layer-render-frames/object-layer-render-frames.model.js +93 -0
  278. package/src/api/object-layer-render-frames/object-layer-render-frames.router.js +17 -0
  279. package/src/api/object-layer-render-frames/object-layer-render-frames.service.js +46 -0
  280. package/src/api/test/test.controller.js +14 -0
  281. package/src/api/test/test.model.js +14 -0
  282. package/src/api/test/test.router.js +23 -0
  283. package/src/api/test/test.service.js +35 -0
  284. package/src/api/types.js +24 -0
  285. package/src/api/user/guest.service.js +100 -0
  286. package/src/api/user/postman_collection.json +216 -0
  287. package/src/api/user/user.build.js +16 -0
  288. package/src/api/user/user.controller.js +35 -0
  289. package/src/api/user/user.model.js +142 -0
  290. package/src/api/user/user.router.js +367 -0
  291. package/src/api/user/user.service.js +582 -0
  292. package/src/api.js +23 -0
  293. package/src/cli/baremetal.js +3947 -0
  294. package/src/cli/cloud-init.js +673 -0
  295. package/src/cli/cluster.js +1395 -0
  296. package/src/cli/db.js +1533 -0
  297. package/src/cli/deploy.js +1542 -0
  298. package/src/cli/docker-compose.js +802 -0
  299. package/src/cli/env.js +177 -0
  300. package/src/cli/fs.js +380 -0
  301. package/src/cli/image.js +389 -0
  302. package/src/cli/index.js +1059 -0
  303. package/src/cli/ipfs.js +182 -0
  304. package/src/cli/kickstart.js +271 -0
  305. package/src/cli/kubectl.js +214 -0
  306. package/src/cli/lxd.js +1232 -0
  307. package/src/cli/monitor.js +659 -0
  308. package/src/cli/release.js +595 -0
  309. package/src/cli/repository.js +1969 -0
  310. package/src/cli/run.js +3326 -0
  311. package/src/cli/secrets.js +151 -0
  312. package/src/cli/ssh.js +975 -0
  313. package/src/cli/static.js +653 -0
  314. package/src/cli/system.js +332 -0
  315. package/src/cli/test.js +176 -0
  316. package/src/client/Cryptokoyn.index.js +30 -0
  317. package/src/client/CyberiaPortal.index.js +31 -0
  318. package/src/client/Default.index.js +77 -0
  319. package/src/client/Itemledger.index.js +35 -0
  320. package/src/client/Underpost.index.js +31 -0
  321. package/src/client/components/core/404.js +20 -0
  322. package/src/client/components/core/500.js +20 -0
  323. package/src/client/components/core/Account.js +630 -0
  324. package/src/client/components/core/AgGrid.js +238 -0
  325. package/src/client/components/core/Alert.js +76 -0
  326. package/src/client/components/core/AppStore.js +69 -0
  327. package/src/client/components/core/Auth.js +353 -0
  328. package/src/client/components/core/Badge.js +26 -0
  329. package/src/client/components/core/Blockchain.js +41 -0
  330. package/src/client/components/core/Blog.js +9 -0
  331. package/src/client/components/core/BtnIcon.js +109 -0
  332. package/src/client/components/core/CalendarCore.js +437 -0
  333. package/src/client/components/core/Chat.js +62 -0
  334. package/src/client/components/core/ClientEvents.js +163 -0
  335. package/src/client/components/core/ColorPaletteElement.js +309 -0
  336. package/src/client/components/core/CommonJs.js +1014 -0
  337. package/src/client/components/core/Content.js +349 -0
  338. package/src/client/components/core/Css.js +1134 -0
  339. package/src/client/components/core/CssCore.js +881 -0
  340. package/src/client/components/core/D3Chart.js +44 -0
  341. package/src/client/components/core/Docs.js +478 -0
  342. package/src/client/components/core/DropDown.js +321 -0
  343. package/src/client/components/core/EventBus.js +96 -0
  344. package/src/client/components/core/EventsUI.js +130 -0
  345. package/src/client/components/core/FileExplorer.js +1406 -0
  346. package/src/client/components/core/FullScreen.js +201 -0
  347. package/src/client/components/core/Input.js +537 -0
  348. package/src/client/components/core/Keyboard.js +80 -0
  349. package/src/client/components/core/KeyboardAvoidance.js +145 -0
  350. package/src/client/components/core/LoadingAnimation.js +152 -0
  351. package/src/client/components/core/LogIn.js +212 -0
  352. package/src/client/components/core/LogOut.js +72 -0
  353. package/src/client/components/core/Logger.js +22 -0
  354. package/src/client/components/core/Modal.js +2956 -0
  355. package/src/client/components/core/NotificationManager.js +80 -0
  356. package/src/client/components/core/Pagination.js +252 -0
  357. package/src/client/components/core/Panel.js +1308 -0
  358. package/src/client/components/core/PanelForm.js +915 -0
  359. package/src/client/components/core/Polyhedron.js +947 -0
  360. package/src/client/components/core/PublicProfile.js +895 -0
  361. package/src/client/components/core/Recover.js +211 -0
  362. package/src/client/components/core/Responsive.js +146 -0
  363. package/src/client/components/core/RichText.js +33 -0
  364. package/src/client/components/core/Router.js +523 -0
  365. package/src/client/components/core/Scroll.js +76 -0
  366. package/src/client/components/core/SearchBox.js +1007 -0
  367. package/src/client/components/core/SignUp.js +153 -0
  368. package/src/client/components/core/SocketIo.js +163 -0
  369. package/src/client/components/core/SocketIoHandler.js +75 -0
  370. package/src/client/components/core/Stream.js +161 -0
  371. package/src/client/components/core/ToggleSwitch.js +89 -0
  372. package/src/client/components/core/ToolTip.js +78 -0
  373. package/src/client/components/core/Translate.js +694 -0
  374. package/src/client/components/core/Validator.js +140 -0
  375. package/src/client/components/core/VanillaJs.js +485 -0
  376. package/src/client/components/core/Wallet.js +95 -0
  377. package/src/client/components/core/WebComponent.js +44 -0
  378. package/src/client/components/core/Webhook.js +58 -0
  379. package/src/client/components/core/Worker.js +313 -0
  380. package/src/client/components/core/windowGetDimensions.js +269 -0
  381. package/src/client/components/cryptokoyn/AppShellCryptokoyn.js +352 -0
  382. package/src/client/components/cryptokoyn/AppStoreCryptokoyn.js +5 -0
  383. package/src/client/components/cryptokoyn/CssCryptokoyn.js +212 -0
  384. package/src/client/components/cryptokoyn/LogInCryptokoyn.js +16 -0
  385. package/src/client/components/cryptokoyn/LogOutCryptokoyn.js +12 -0
  386. package/src/client/components/cryptokoyn/RouterCryptokoyn.js +37 -0
  387. package/src/client/components/cryptokoyn/SettingsCryptokoyn.js +16 -0
  388. package/src/client/components/cryptokoyn/SignUpCryptokoyn.js +11 -0
  389. package/src/client/components/cryptokoyn/SocketIoCryptokoyn.js +6 -0
  390. package/src/client/components/cyberia/ActionEngineCyberia.js +1867 -0
  391. package/src/client/components/cyberia/EntityEngineCyberia.js +585 -0
  392. package/src/client/components/cyberia/InstanceEngineCyberia.js +1088 -0
  393. package/src/client/components/cyberia/InstanceSelectionView.js +900 -0
  394. package/src/client/components/cyberia/MapEngineCyberia.js +1976 -0
  395. package/src/client/components/cyberia/ObjectLayerEngine.js +1540 -0
  396. package/src/client/components/cyberia/ObjectLayerEngineModal.js +2420 -0
  397. package/src/client/components/cyberia/ObjectLayerEngineViewer.js +1522 -0
  398. package/src/client/components/cyberia/SharedDefaultsCyberia.js +528 -0
  399. package/src/client/components/cyberia-portal/AppShellCyberiaPortal.js +772 -0
  400. package/src/client/components/cyberia-portal/AppStoreCyberiaPortal.js +5 -0
  401. package/src/client/components/cyberia-portal/CssCyberiaPortal.js +254 -0
  402. package/src/client/components/cyberia-portal/LogInCyberiaPortal.js +21 -0
  403. package/src/client/components/cyberia-portal/LogOutCyberiaPortal.js +16 -0
  404. package/src/client/components/cyberia-portal/MainBodyCyberiaPortal.js +518 -0
  405. package/src/client/components/cyberia-portal/RouterCyberiaPortal.js +72 -0
  406. package/src/client/components/cyberia-portal/SettingsCyberiaPortal.js +16 -0
  407. package/src/client/components/cyberia-portal/SignUpCyberiaPortal.js +13 -0
  408. package/src/client/components/cyberia-portal/SocketIoCyberiaPortal.js +6 -0
  409. package/src/client/components/cyberia-portal/TranslateCyberiaPortal.js +48 -0
  410. package/src/client/components/default/AppShellDefault.js +765 -0
  411. package/src/client/components/default/AppStoreDefault.js +5 -0
  412. package/src/client/components/default/CommonDefault.js +29 -0
  413. package/src/client/components/default/CssDefault.js +27 -0
  414. package/src/client/components/default/LogInDefault.js +16 -0
  415. package/src/client/components/default/LogOutDefault.js +12 -0
  416. package/src/client/components/default/RouterDefault.js +47 -0
  417. package/src/client/components/default/SettingsDefault.js +16 -0
  418. package/src/client/components/default/SignUpDefault.js +11 -0
  419. package/src/client/components/default/SocketIoDefault.js +6 -0
  420. package/src/client/components/default/TranslateDefault.js +7 -0
  421. package/src/client/components/itemledger/AppShellItemledger.js +353 -0
  422. package/src/client/components/itemledger/AppStoreItemledger.js +5 -0
  423. package/src/client/components/itemledger/CssItemledger.js +212 -0
  424. package/src/client/components/itemledger/LogInItemledger.js +17 -0
  425. package/src/client/components/itemledger/LogOutItemledger.js +12 -0
  426. package/src/client/components/itemledger/RouterItemledger.js +38 -0
  427. package/src/client/components/itemledger/SettingsItemledger.js +16 -0
  428. package/src/client/components/itemledger/SignUpItemledger.js +11 -0
  429. package/src/client/components/itemledger/SocketIoItemledger.js +6 -0
  430. package/src/client/components/itemledger/TranslateItemledger.js +7 -0
  431. package/src/client/components/underpost/AppShellUnderpost.js +691 -0
  432. package/src/client/components/underpost/AppStoreUnderpost.js +5 -0
  433. package/src/client/components/underpost/CssUnderpost.js +281 -0
  434. package/src/client/components/underpost/CyberpunkBloggerUnderpost.js +879 -0
  435. package/src/client/components/underpost/DocumentSearchProvider.js +448 -0
  436. package/src/client/components/underpost/LabGalleryUnderpost.js +79 -0
  437. package/src/client/components/underpost/LogInUnderpost.js +25 -0
  438. package/src/client/components/underpost/LogOutUnderpost.js +17 -0
  439. package/src/client/components/underpost/RouterUnderpost.js +45 -0
  440. package/src/client/components/underpost/SettingsUnderpost.js +16 -0
  441. package/src/client/components/underpost/SignUpUnderpost.js +11 -0
  442. package/src/client/components/underpost/SocketIoUnderpost.js +6 -0
  443. package/src/client/components/underpost/TranslateUnderpost.js +10 -0
  444. package/src/client/public/cryptokoyn/assets/banner/koyn-social.png +0 -0
  445. package/src/client/public/cryptokoyn/assets/logo/base-icon.png +0 -0
  446. package/src/client/public/cryptokoyn/assets/logo/cryptokoyn.png +0 -0
  447. package/src/client/public/cryptokoyn/assets/splash/android-chrome-144x144.png +0 -0
  448. package/src/client/public/cryptokoyn/assets/splash/android-chrome-192x192.png +0 -0
  449. package/src/client/public/cryptokoyn/assets/splash/android-chrome-256x256.png +0 -0
  450. package/src/client/public/cryptokoyn/assets/splash/android-chrome-36x36.png +0 -0
  451. package/src/client/public/cryptokoyn/assets/splash/android-chrome-48x48.png +0 -0
  452. package/src/client/public/cryptokoyn/assets/splash/android-chrome-72x72.png +0 -0
  453. package/src/client/public/cryptokoyn/assets/splash/android-chrome-96x96.png +0 -0
  454. package/src/client/public/cryptokoyn/assets/splash/apple-touch-icon-114x114-precomposed.png +0 -0
  455. package/src/client/public/cryptokoyn/assets/splash/apple-touch-icon-114x114.png +0 -0
  456. package/src/client/public/cryptokoyn/assets/splash/apple-touch-icon-120x120-precomposed.png +0 -0
  457. package/src/client/public/cryptokoyn/assets/splash/apple-touch-icon-120x120.png +0 -0
  458. package/src/client/public/cryptokoyn/assets/splash/apple-touch-icon-144x144-precomposed.png +0 -0
  459. package/src/client/public/cryptokoyn/assets/splash/apple-touch-icon-144x144.png +0 -0
  460. package/src/client/public/cryptokoyn/assets/splash/apple-touch-icon-152x152-precomposed.png +0 -0
  461. package/src/client/public/cryptokoyn/assets/splash/apple-touch-icon-152x152.png +0 -0
  462. package/src/client/public/cryptokoyn/assets/splash/apple-touch-icon-180x180-precomposed.png +0 -0
  463. package/src/client/public/cryptokoyn/assets/splash/apple-touch-icon-180x180.png +0 -0
  464. package/src/client/public/cryptokoyn/assets/splash/apple-touch-icon-57x57-precomposed.png +0 -0
  465. package/src/client/public/cryptokoyn/assets/splash/apple-touch-icon-57x57.png +0 -0
  466. package/src/client/public/cryptokoyn/assets/splash/apple-touch-icon-60x60-precomposed.png +0 -0
  467. package/src/client/public/cryptokoyn/assets/splash/apple-touch-icon-60x60.png +0 -0
  468. package/src/client/public/cryptokoyn/assets/splash/apple-touch-icon-72x72-precomposed.png +0 -0
  469. package/src/client/public/cryptokoyn/assets/splash/apple-touch-icon-72x72.png +0 -0
  470. package/src/client/public/cryptokoyn/assets/splash/apple-touch-icon-76x76-precomposed.png +0 -0
  471. package/src/client/public/cryptokoyn/assets/splash/apple-touch-icon-76x76.png +0 -0
  472. package/src/client/public/cryptokoyn/assets/splash/apple-touch-icon-precomposed.png +0 -0
  473. package/src/client/public/cryptokoyn/assets/splash/apple-touch-icon.png +0 -0
  474. package/src/client/public/cryptokoyn/assets/splash/favicon-16x16.png +0 -0
  475. package/src/client/public/cryptokoyn/assets/splash/favicon-32x32.png +0 -0
  476. package/src/client/public/cryptokoyn/assets/splash/mstile-144x144.png +0 -0
  477. package/src/client/public/cryptokoyn/assets/splash/mstile-150x150.png +0 -0
  478. package/src/client/public/cryptokoyn/assets/splash/mstile-310x150.png +0 -0
  479. package/src/client/public/cryptokoyn/assets/splash/mstile-310x310.png +0 -0
  480. package/src/client/public/cryptokoyn/assets/splash/mstile-70x70.png +0 -0
  481. package/src/client/public/cryptokoyn/assets/splash/safari-pinned-tab.svg +42 -0
  482. package/src/client/public/cryptokoyn/browserconfig.xml +12 -0
  483. package/src/client/public/cryptokoyn/favicon.ico +0 -0
  484. package/src/client/public/cryptokoyn/microdata.json +85 -0
  485. package/src/client/public/cryptokoyn/site.webmanifest +57 -0
  486. package/src/client/public/cryptokoyn/sitemap +148 -0
  487. package/src/client/public/cyberia-docs/ACTION-SYSTEM.md +307 -0
  488. package/src/client/public/cyberia-docs/ARCHITECTURE.md +309 -0
  489. package/src/client/public/cyberia-docs/CYBERIA-CLI.md +204 -0
  490. package/src/client/public/cyberia-docs/CYBERIA-CLIENT.md +341 -0
  491. package/src/client/public/cyberia-docs/CYBERIA-LORE.md +84 -0
  492. package/src/client/public/cyberia-docs/CYBERIA-SAGA.md +394 -0
  493. package/src/client/public/cyberia-docs/CYBERIA-SERVER.md +294 -0
  494. package/src/client/public/cyberia-docs/CYBERIA.md +259 -0
  495. package/src/client/public/cyberia-docs/ENTITY-PROFILE.md +242 -0
  496. package/src/client/public/cyberia-docs/HARDHAT-MODULE.md +300 -0
  497. package/src/client/public/cyberia-docs/OFF-CHAIN-ECONOMY.md +309 -0
  498. package/src/client/public/cyberia-docs/QUEST-SYSTEM.md +228 -0
  499. package/src/client/public/cyberia-docs/ROADMAP.md +240 -0
  500. package/src/client/public/cyberia-docs/UNDERPOST-PLATFORM.md +106 -0
  501. package/src/client/public/cyberia-docs/WHITE-PAPER.md +740 -0
  502. package/src/client/public/default/android-chrome-144x144.png +0 -0
  503. package/src/client/public/default/android-chrome-192x192.png +0 -0
  504. package/src/client/public/default/android-chrome-256x256.png +0 -0
  505. package/src/client/public/default/android-chrome-36x36.png +0 -0
  506. package/src/client/public/default/android-chrome-384x384.png +0 -0
  507. package/src/client/public/default/android-chrome-48x48.png +0 -0
  508. package/src/client/public/default/android-chrome-512x512.png +0 -0
  509. package/src/client/public/default/android-chrome-72x72.png +0 -0
  510. package/src/client/public/default/android-chrome-96x96.png +0 -0
  511. package/src/client/public/default/apple-touch-icon-1024x1024.png +0 -0
  512. package/src/client/public/default/apple-touch-icon-114x114-precomposed.png +0 -0
  513. package/src/client/public/default/apple-touch-icon-114x114.png +0 -0
  514. package/src/client/public/default/apple-touch-icon-120x120-precomposed.png +0 -0
  515. package/src/client/public/default/apple-touch-icon-120x120.png +0 -0
  516. package/src/client/public/default/apple-touch-icon-144x144-precomposed.png +0 -0
  517. package/src/client/public/default/apple-touch-icon-144x144.png +0 -0
  518. package/src/client/public/default/apple-touch-icon-152x152-precomposed.png +0 -0
  519. package/src/client/public/default/apple-touch-icon-152x152.png +0 -0
  520. package/src/client/public/default/apple-touch-icon-167x167.png +0 -0
  521. package/src/client/public/default/apple-touch-icon-180x180-precomposed.png +0 -0
  522. package/src/client/public/default/apple-touch-icon-180x180.png +0 -0
  523. package/src/client/public/default/apple-touch-icon-57x57-precomposed.png +0 -0
  524. package/src/client/public/default/apple-touch-icon-57x57.png +0 -0
  525. package/src/client/public/default/apple-touch-icon-60x60-precomposed.png +0 -0
  526. package/src/client/public/default/apple-touch-icon-60x60.png +0 -0
  527. package/src/client/public/default/apple-touch-icon-72x72-precomposed.png +0 -0
  528. package/src/client/public/default/apple-touch-icon-72x72.png +0 -0
  529. package/src/client/public/default/apple-touch-icon-76x76-precomposed.png +0 -0
  530. package/src/client/public/default/apple-touch-icon-76x76.png +0 -0
  531. package/src/client/public/default/apple-touch-icon-precomposed.png +0 -0
  532. package/src/client/public/default/apple-touch-icon.png +0 -0
  533. package/src/client/public/default/apple-touch-startup-image-1125x2436.png +0 -0
  534. package/src/client/public/default/apple-touch-startup-image-1136x640.png +0 -0
  535. package/src/client/public/default/apple-touch-startup-image-1170x2532.png +0 -0
  536. package/src/client/public/default/apple-touch-startup-image-1179x2556.png +0 -0
  537. package/src/client/public/default/apple-touch-startup-image-1242x2208.png +0 -0
  538. package/src/client/public/default/apple-touch-startup-image-1242x2688.png +0 -0
  539. package/src/client/public/default/apple-touch-startup-image-1284x2778.png +0 -0
  540. package/src/client/public/default/apple-touch-startup-image-1290x2796.png +0 -0
  541. package/src/client/public/default/apple-touch-startup-image-1334x750.png +0 -0
  542. package/src/client/public/default/apple-touch-startup-image-1488x2266.png +0 -0
  543. package/src/client/public/default/apple-touch-startup-image-1536x2048.png +0 -0
  544. package/src/client/public/default/apple-touch-startup-image-1620x2160.png +0 -0
  545. package/src/client/public/default/apple-touch-startup-image-1640x2160.png +0 -0
  546. package/src/client/public/default/apple-touch-startup-image-1668x2224.png +0 -0
  547. package/src/client/public/default/apple-touch-startup-image-1668x2388.png +0 -0
  548. package/src/client/public/default/apple-touch-startup-image-1792x828.png +0 -0
  549. package/src/client/public/default/apple-touch-startup-image-2048x1536.png +0 -0
  550. package/src/client/public/default/apple-touch-startup-image-2048x2732.png +0 -0
  551. package/src/client/public/default/apple-touch-startup-image-2160x1620.png +0 -0
  552. package/src/client/public/default/apple-touch-startup-image-2160x1640.png +0 -0
  553. package/src/client/public/default/apple-touch-startup-image-2208x1242.png +0 -0
  554. package/src/client/public/default/apple-touch-startup-image-2224x1668.png +0 -0
  555. package/src/client/public/default/apple-touch-startup-image-2266x1488.png +0 -0
  556. package/src/client/public/default/apple-touch-startup-image-2388x1668.png +0 -0
  557. package/src/client/public/default/apple-touch-startup-image-2436x1125.png +0 -0
  558. package/src/client/public/default/apple-touch-startup-image-2532x1170.png +0 -0
  559. package/src/client/public/default/apple-touch-startup-image-2556x1179.png +0 -0
  560. package/src/client/public/default/apple-touch-startup-image-2688x1242.png +0 -0
  561. package/src/client/public/default/apple-touch-startup-image-2732x2048.png +0 -0
  562. package/src/client/public/default/apple-touch-startup-image-2778x1284.png +0 -0
  563. package/src/client/public/default/apple-touch-startup-image-2796x1290.png +0 -0
  564. package/src/client/public/default/apple-touch-startup-image-640x1136.png +0 -0
  565. package/src/client/public/default/apple-touch-startup-image-750x1334.png +0 -0
  566. package/src/client/public/default/apple-touch-startup-image-828x1792.png +0 -0
  567. package/src/client/public/default/assets/background/dark.jpg +0 -0
  568. package/src/client/public/default/assets/background/dark.svg +557 -0
  569. package/src/client/public/default/assets/background/white.jpg +0 -0
  570. package/src/client/public/default/assets/background/white0-min.jpg +0 -0
  571. package/src/client/public/default/assets/background/white0.jpg +0 -0
  572. package/src/client/public/default/assets/logo/base-icon.png +0 -0
  573. package/src/client/public/default/assets/logo/underpost.gif +0 -0
  574. package/src/client/public/default/assets/mailer/api-user-check.png +0 -0
  575. package/src/client/public/default/assets/mailer/api-user-default-avatar.png +0 -0
  576. package/src/client/public/default/assets/mailer/api-user-invalid-token.png +0 -0
  577. package/src/client/public/default/assets/mailer/api-user-recover.png +0 -0
  578. package/src/client/public/default/browserconfig.xml +12 -0
  579. package/src/client/public/default/favicon-16x16.png +0 -0
  580. package/src/client/public/default/favicon-32x32.png +0 -0
  581. package/src/client/public/default/favicon-48x48.png +0 -0
  582. package/src/client/public/default/favicon.ico +0 -0
  583. package/src/client/public/default/manifest.webmanifest +69 -0
  584. package/src/client/public/default/mstile-144x144.png +0 -0
  585. package/src/client/public/default/mstile-150x150.png +0 -0
  586. package/src/client/public/default/mstile-310x150.png +0 -0
  587. package/src/client/public/default/mstile-310x310.png +0 -0
  588. package/src/client/public/default/mstile-70x70.png +0 -0
  589. package/src/client/public/default/safari-pinned-tab.svg +24 -0
  590. package/src/client/public/default/site.webmanifest +69 -0
  591. package/src/client/public/default/sitemap +148 -0
  592. package/src/client/public/default/yandex-browser-50x50.png +0 -0
  593. package/src/client/public/default/yandex-browser-manifest.json +9 -0
  594. package/src/client/public/doc/favicon.ico +0 -0
  595. package/src/client/public/doc/sitemap +148 -0
  596. package/src/client/public/itemledger/android-chrome-144x144.png +0 -0
  597. package/src/client/public/itemledger/android-chrome-192x192.png +0 -0
  598. package/src/client/public/itemledger/android-chrome-256x256.png +0 -0
  599. package/src/client/public/itemledger/android-chrome-36x36.png +0 -0
  600. package/src/client/public/itemledger/android-chrome-384x384.png +0 -0
  601. package/src/client/public/itemledger/android-chrome-48x48.png +0 -0
  602. package/src/client/public/itemledger/android-chrome-512x512.png +0 -0
  603. package/src/client/public/itemledger/android-chrome-72x72.png +0 -0
  604. package/src/client/public/itemledger/android-chrome-96x96.png +0 -0
  605. package/src/client/public/itemledger/apple-touch-icon-1024x1024.png +0 -0
  606. package/src/client/public/itemledger/apple-touch-icon-114x114.png +0 -0
  607. package/src/client/public/itemledger/apple-touch-icon-120x120.png +0 -0
  608. package/src/client/public/itemledger/apple-touch-icon-144x144.png +0 -0
  609. package/src/client/public/itemledger/apple-touch-icon-152x152.png +0 -0
  610. package/src/client/public/itemledger/apple-touch-icon-167x167.png +0 -0
  611. package/src/client/public/itemledger/apple-touch-icon-180x180.png +0 -0
  612. package/src/client/public/itemledger/apple-touch-icon-57x57.png +0 -0
  613. package/src/client/public/itemledger/apple-touch-icon-60x60.png +0 -0
  614. package/src/client/public/itemledger/apple-touch-icon-72x72.png +0 -0
  615. package/src/client/public/itemledger/apple-touch-icon-76x76.png +0 -0
  616. package/src/client/public/itemledger/apple-touch-icon-precomposed.png +0 -0
  617. package/src/client/public/itemledger/apple-touch-icon.png +0 -0
  618. package/src/client/public/itemledger/apple-touch-startup-image-1125x2436.png +0 -0
  619. package/src/client/public/itemledger/apple-touch-startup-image-1136x640.png +0 -0
  620. package/src/client/public/itemledger/apple-touch-startup-image-1170x2532.png +0 -0
  621. package/src/client/public/itemledger/apple-touch-startup-image-1179x2556.png +0 -0
  622. package/src/client/public/itemledger/apple-touch-startup-image-1242x2208.png +0 -0
  623. package/src/client/public/itemledger/apple-touch-startup-image-1242x2688.png +0 -0
  624. package/src/client/public/itemledger/apple-touch-startup-image-1284x2778.png +0 -0
  625. package/src/client/public/itemledger/apple-touch-startup-image-1290x2796.png +0 -0
  626. package/src/client/public/itemledger/apple-touch-startup-image-1334x750.png +0 -0
  627. package/src/client/public/itemledger/apple-touch-startup-image-1488x2266.png +0 -0
  628. package/src/client/public/itemledger/apple-touch-startup-image-1536x2048.png +0 -0
  629. package/src/client/public/itemledger/apple-touch-startup-image-1620x2160.png +0 -0
  630. package/src/client/public/itemledger/apple-touch-startup-image-1640x2160.png +0 -0
  631. package/src/client/public/itemledger/apple-touch-startup-image-1668x2224.png +0 -0
  632. package/src/client/public/itemledger/apple-touch-startup-image-1668x2388.png +0 -0
  633. package/src/client/public/itemledger/apple-touch-startup-image-1792x828.png +0 -0
  634. package/src/client/public/itemledger/apple-touch-startup-image-2048x1536.png +0 -0
  635. package/src/client/public/itemledger/apple-touch-startup-image-2048x2732.png +0 -0
  636. package/src/client/public/itemledger/apple-touch-startup-image-2160x1620.png +0 -0
  637. package/src/client/public/itemledger/apple-touch-startup-image-2160x1640.png +0 -0
  638. package/src/client/public/itemledger/apple-touch-startup-image-2208x1242.png +0 -0
  639. package/src/client/public/itemledger/apple-touch-startup-image-2224x1668.png +0 -0
  640. package/src/client/public/itemledger/apple-touch-startup-image-2266x1488.png +0 -0
  641. package/src/client/public/itemledger/apple-touch-startup-image-2388x1668.png +0 -0
  642. package/src/client/public/itemledger/apple-touch-startup-image-2436x1125.png +0 -0
  643. package/src/client/public/itemledger/apple-touch-startup-image-2532x1170.png +0 -0
  644. package/src/client/public/itemledger/apple-touch-startup-image-2556x1179.png +0 -0
  645. package/src/client/public/itemledger/apple-touch-startup-image-2688x1242.png +0 -0
  646. package/src/client/public/itemledger/apple-touch-startup-image-2732x2048.png +0 -0
  647. package/src/client/public/itemledger/apple-touch-startup-image-2778x1284.png +0 -0
  648. package/src/client/public/itemledger/apple-touch-startup-image-2796x1290.png +0 -0
  649. package/src/client/public/itemledger/apple-touch-startup-image-640x1136.png +0 -0
  650. package/src/client/public/itemledger/apple-touch-startup-image-750x1334.png +0 -0
  651. package/src/client/public/itemledger/apple-touch-startup-image-828x1792.png +0 -0
  652. package/src/client/public/itemledger/assets/logo/base-icon.png +0 -0
  653. package/src/client/public/itemledger/browserconfig.xml +12 -0
  654. package/src/client/public/itemledger/favicon-16x16.png +0 -0
  655. package/src/client/public/itemledger/favicon-32x32.png +0 -0
  656. package/src/client/public/itemledger/favicon-48x48.png +0 -0
  657. package/src/client/public/itemledger/favicon.ico +0 -0
  658. package/src/client/public/itemledger/manifest.webmanifest +69 -0
  659. package/src/client/public/itemledger/microdata.json +71 -0
  660. package/src/client/public/itemledger/mstile-144x144.png +0 -0
  661. package/src/client/public/itemledger/mstile-150x150.png +0 -0
  662. package/src/client/public/itemledger/mstile-310x150.png +0 -0
  663. package/src/client/public/itemledger/mstile-310x310.png +0 -0
  664. package/src/client/public/itemledger/mstile-70x70.png +0 -0
  665. package/src/client/public/itemledger/sitemap +148 -0
  666. package/src/client/public/itemledger/yandex-browser-50x50.png +0 -0
  667. package/src/client/public/itemledger/yandex-browser-manifest.json +9 -0
  668. package/src/client/public/test/favicon.ico +0 -0
  669. package/src/client/public/test/sitemap +148 -0
  670. package/src/client/services/atlas-sprite-sheet/atlas-sprite-sheet.service.js +137 -0
  671. package/src/client/services/core/core.service.js +309 -0
  672. package/src/client/services/crypto/crypto.service.js +68 -0
  673. package/src/client/services/cyberia-action/cyberia-action.service.js +99 -0
  674. package/src/client/services/cyberia-client-hints/cyberia-client-hints.service.js +99 -0
  675. package/src/client/services/cyberia-dialogue/cyberia-dialogue.service.js +99 -0
  676. package/src/client/services/cyberia-entity/cyberia-entity.management.js +57 -0
  677. package/src/client/services/cyberia-entity/cyberia-entity.service.js +99 -0
  678. package/src/client/services/cyberia-entity-type-default/cyberia-entity-type-default.service.js +99 -0
  679. package/src/client/services/cyberia-instance/cyberia-instance.management.js +194 -0
  680. package/src/client/services/cyberia-instance/cyberia-instance.service.js +137 -0
  681. package/src/client/services/cyberia-instance-conf/cyberia-instance-conf.service.js +99 -0
  682. package/src/client/services/cyberia-map/cyberia-map.management.js +193 -0
  683. package/src/client/services/cyberia-map/cyberia-map.service.js +120 -0
  684. package/src/client/services/cyberia-quest/cyberia-quest.service.js +99 -0
  685. package/src/client/services/cyberia-quest-progress/cyberia-quest-progress.service.js +99 -0
  686. package/src/client/services/cyberia-saga/cyberia-saga.service.js +99 -0
  687. package/src/client/services/cyberia-skill/cyberia-skill.service.js +99 -0
  688. package/src/client/services/default/default.management.js +1015 -0
  689. package/src/client/services/default/default.service.js +99 -0
  690. package/src/client/services/document/document.service.js +134 -0
  691. package/src/client/services/file/file.service.js +94 -0
  692. package/src/client/services/instance/instance.management.js +78 -0
  693. package/src/client/services/instance/instance.service.js +107 -0
  694. package/src/client/services/ipfs/ipfs.service.js +118 -0
  695. package/src/client/services/object-layer/object-layer.management.js +414 -0
  696. package/src/client/services/object-layer/object-layer.service.js +208 -0
  697. package/src/client/services/object-layer-render-frames/object-layer-render-frames.service.js +99 -0
  698. package/src/client/services/test/test.service.js +68 -0
  699. package/src/client/services/user/guest.service.js +86 -0
  700. package/src/client/services/user/user.management.js +51 -0
  701. package/src/client/services/user/user.service.js +106 -0
  702. package/src/client/ssr/RootDocument.js +237 -0
  703. package/src/client/ssr/body/404.js +77 -0
  704. package/src/client/ssr/body/500.js +76 -0
  705. package/src/client/ssr/body/CacheControl.js +117 -0
  706. package/src/client/ssr/body/CyberiaDefaultSplashScreen.js +97 -0
  707. package/src/client/ssr/body/DefaultSplashScreen.js +97 -0
  708. package/src/client/ssr/body/SwaggerDarkMode.js +285 -0
  709. package/src/client/ssr/body/UnderpostDefaultSplashScreen.js +90 -0
  710. package/src/client/ssr/head/CryptokoynScripts.js +4 -0
  711. package/src/client/ssr/head/Css.js +241 -0
  712. package/src/client/ssr/head/CyberiaPortalScripts.js +6 -0
  713. package/src/client/ssr/head/DefaultScripts.js +6 -0
  714. package/src/client/ssr/head/ItemledgerScripts.js +4 -0
  715. package/src/client/ssr/head/Microdata.js +11 -0
  716. package/src/client/ssr/head/Production.js +1 -0
  717. package/src/client/ssr/head/Pwa.js +146 -0
  718. package/src/client/ssr/head/PwaItemledger.js +197 -0
  719. package/src/client/ssr/head/Seo.js +15 -0
  720. package/src/client/ssr/head/UnderpostScripts.js +6 -0
  721. package/src/client/ssr/mailer/DefaultRecoverEmail.js +20 -0
  722. package/src/client/ssr/mailer/DefaultVerifyEmail.js +16 -0
  723. package/src/client/ssr/views/Cyberia404.js +328 -0
  724. package/src/client/ssr/views/CyberiaServerMetrics.js +1070 -0
  725. package/src/client/ssr/views/Maintenance.js +64 -0
  726. package/src/client/ssr/views/NoNetworkConnection.js +68 -0
  727. package/src/client/ssr/views/Test.js +199 -0
  728. package/src/client/sw/core.sw.js +274 -0
  729. package/src/client-builder/client-build-docs.js +493 -0
  730. package/src/client-builder/client-build-live.js +100 -0
  731. package/src/client-builder/client-build.js +1092 -0
  732. package/src/client-builder/client-dev-server.js +88 -0
  733. package/src/client-builder/client-formatted.js +170 -0
  734. package/src/client-builder/client-icons.js +108 -0
  735. package/src/client-builder/ssr.js +124 -0
  736. package/src/client.build.js +17 -0
  737. package/src/client.dev.js +21 -0
  738. package/src/db/DataBaseProvider.js +213 -0
  739. package/src/db/mariadb/MariaDB.js +72 -0
  740. package/src/db/mongo/MongoBootstrap.js +657 -0
  741. package/src/db/mongo/MongooseDB.js +199 -0
  742. package/src/grpc/cyberia/grpc-server.js +162 -0
  743. package/src/index.js +357 -0
  744. package/src/mailer/EmailRender.js +116 -0
  745. package/src/mailer/MailerProvider.js +213 -0
  746. package/src/projects/cyberia/atlas-sprite-sheet-generator.js +413 -0
  747. package/src/projects/cyberia/besu-genesis-generator.js +1630 -0
  748. package/src/projects/cyberia/catalog-cyberia.js +90 -0
  749. package/src/projects/cyberia/gemini-client.js +175 -0
  750. package/src/projects/cyberia/generate-saga.js +2137 -0
  751. package/src/projects/cyberia/hot-reload-trigger.js +163 -0
  752. package/src/projects/cyberia/instance-data.js +719 -0
  753. package/src/projects/cyberia/ipfs-client.js +599 -0
  754. package/src/projects/cyberia/map-preview-generator.js +304 -0
  755. package/src/projects/cyberia/object-layer.js +978 -0
  756. package/src/projects/cyberia/semantic-layer-generator-floor.js +319 -0
  757. package/src/projects/cyberia/semantic-layer-generator-resource.js +259 -0
  758. package/src/projects/cyberia/semantic-layer-generator-skin.js +1164 -0
  759. package/src/projects/cyberia/semantic-layer-generator.js +753 -0
  760. package/src/projects/cyberia/shape-generator.js +1060 -0
  761. package/src/projects/underpost/catalog-underpost.js +60 -0
  762. package/src/proxy.js +19 -0
  763. package/src/runtime/cyberia-client/Dockerfile +49 -0
  764. package/src/runtime/cyberia-client/Dockerfile.dev +75 -0
  765. package/src/runtime/cyberia-server/Dockerfile +43 -0
  766. package/src/runtime/cyberia-server/Dockerfile.dev +56 -0
  767. package/src/runtime/engine-cyberia/Dockerfile +161 -0
  768. package/src/runtime/engine-cyberia/Dockerfile.dev +161 -0
  769. package/src/runtime/engine-cyberia/Dockerfile.test +165 -0
  770. package/src/runtime/engine-cyberia/compose.env +144 -0
  771. package/src/runtime/engine-cyberia/docker-compose.yml +434 -0
  772. package/src/runtime/engine-cyberia/ipfs/configure-ipfs.sh +13 -0
  773. package/src/runtime/engine-cyberia/mongodb/entrypoint.sh +76 -0
  774. package/src/runtime/engine-cyberia/nginx.conf +128 -0
  775. package/src/runtime/express/Dockerfile +45 -0
  776. package/src/runtime/express/Express.js +285 -0
  777. package/src/runtime/lampp/Dockerfile +62 -0
  778. package/src/runtime/lampp/Lampp.js +359 -0
  779. package/src/runtime/nginx/Nginx.js +250 -0
  780. package/src/runtime/wp/Dockerfile +62 -0
  781. package/src/runtime/wp/Wp.js +642 -0
  782. package/src/server/auth.js +713 -0
  783. package/src/server/backup.js +102 -0
  784. package/src/server/catalog.js +72 -0
  785. package/src/server/conf.js +2316 -0
  786. package/src/server/cron.js +476 -0
  787. package/src/server/crypto.js +210 -0
  788. package/src/server/data-query.js +461 -0
  789. package/src/server/dns.js +553 -0
  790. package/src/server/downloader.js +73 -0
  791. package/src/server/logger.js +229 -0
  792. package/src/server/middlewares.js +152 -0
  793. package/src/server/peer.js +75 -0
  794. package/src/server/process.js +299 -0
  795. package/src/server/proxy.js +139 -0
  796. package/src/server/runtime-status.js +252 -0
  797. package/src/server/runtime.js +183 -0
  798. package/src/server/start.js +272 -0
  799. package/src/server/tls.js +254 -0
  800. package/src/server/valkey.js +201 -0
  801. package/src/server.js +25 -0
  802. package/src/ws/IoInterface.js +129 -0
  803. package/src/ws/IoServer.js +68 -0
  804. package/src/ws/core/channels/core.ws.chat.js +68 -0
  805. package/src/ws/core/channels/core.ws.mailer.js +116 -0
  806. package/src/ws/core/channels/core.ws.stream.js +90 -0
  807. package/src/ws/core/core.ws.connection.js +41 -0
  808. package/src/ws/core/core.ws.emit.js +37 -0
  809. package/src/ws/core/core.ws.server.js +44 -0
  810. package/src/ws/default/channels/default.ws.main.js +57 -0
  811. package/src/ws/default/default.ws.connection.js +35 -0
  812. package/src/ws/default/default.ws.emit.js +14 -0
  813. package/src/ws/default/default.ws.server.js +39 -0
  814. package/test/api.test.js +53 -0
  815. package/test/crypto.test.js +117 -0
  816. package/test/cyberia-instance-conf-defaults.test.js +140 -0
  817. package/test/deploy-monitor.test.js +267 -0
  818. package/test/shape-generator.test.js +463 -0
  819. package/tsconfig.docs.json +15 -0
  820. package/typedoc.dd-cyberia.json +31 -0
  821. package/typedoc.json +31 -0
@@ -0,0 +1,2956 @@
1
+ import { getId, newInstance, s4 } from './CommonJs.js';
2
+ import { Draggable } from '@neodrag/vanilla';
3
+ import { append, s, prepend, htmls, sa, getAllChildNodes, isActiveElement } from './VanillaJs.js';
4
+ import { BtnIcon } from './BtnIcon.js';
5
+ import { Responsive } from './Responsive.js';
6
+ import { loggerFactory } from './Logger.js';
7
+ import {
8
+ Css,
9
+ ThemeEvents,
10
+ Themes,
11
+ ThemesScope,
12
+ darkTheme,
13
+ renderStyleTag,
14
+ renderStatus,
15
+ renderCssAttr,
16
+ } from './Css.js';
17
+ import {
18
+ setDocTitle,
19
+ closeModalRouteChangeEvent,
20
+ handleModalViewRoute,
21
+ getProxyPath,
22
+ setPath,
23
+ coreUI,
24
+ sanitizeRoute,
25
+ getQueryParams,
26
+ setRouterReady,
27
+ } from './Router.js';
28
+ import { NotificationManager } from './NotificationManager.js';
29
+ import { EventsUI } from './EventsUI.js';
30
+ import { Translate } from './Translate.js';
31
+ import { Input, isTextInputFocused } from './Input.js';
32
+ import { DropDown } from './DropDown.js';
33
+ import { Keyboard } from './Keyboard.js';
34
+ import { Badge } from './Badge.js';
35
+ import { Worker } from './Worker.js';
36
+ import { Scroll } from './Scroll.js';
37
+ import { windowGetH, windowGetW } from './windowGetDimensions.js';
38
+ import { SearchBox } from './SearchBox.js';
39
+ import { createModalEvents } from './ClientEvents.js';
40
+
41
+ const logger = loggerFactory(import.meta, { trace: true });
42
+
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 = {};
131
+
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(
202
+ options = {
203
+ id: '',
204
+ barConfig: {},
205
+ title: '',
206
+ html: '',
207
+ handleType: 'bar',
208
+ mode: '',
209
+ RouterInstance: {},
210
+ disableTools: [],
211
+ observer: false,
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: [],
225
+ },
226
+ ) {
227
+ const originHeightBottomBar = 50;
228
+ const originHeightTopBar = 50;
229
+ options.heightBottomBar = 0;
230
+ options.heightTopBar = 100;
231
+ if (options && options.barMode && options.barMode === 'top-bottom-bar') {
232
+ options.heightTopBar = 50;
233
+ options.heightBottomBar = 50;
234
+ }
235
+ let width = 300;
236
+ let height = 400;
237
+ let top = options.style?.top ? options.style.top : 0;
238
+ let left = options.style?.left ? options.style.left : 0;
239
+ let transition = `opacity 0.3s, box-shadow 0.3s, bottom 0.3s`;
240
+ const originSlideMenuWidth = 320;
241
+ const collapseSlideMenuWidth = 50;
242
+ let slideMenuWidth = originSlideMenuWidth;
243
+ const minWidth = width;
244
+ const heightDefaultTopBar = 50;
245
+ const heightDefaultBottomBar = 0;
246
+ const idModal = options.id ? options.id : getId(this.Data, 'modal-');
247
+ const { bus: eventBus, channels: eventChannels } = createModalEvents();
248
+ this.Data[idModal] = {
249
+ options,
250
+ events: eventBus,
251
+ ...eventChannels,
252
+ homeModals: options.homeModals ? options.homeModals : [],
253
+ query: options.query ? `${window.location.search}` : undefined,
254
+ getTop: () => Modal.getModalTop(options, heightDefaultBottomBar),
255
+ getHeight: () => Modal.getModalHeight(options, heightDefaultTopBar, heightDefaultBottomBar),
256
+ getMenuLeftStyle: (ops = { open: false }) =>
257
+ Modal.getModalMenuLeftStyle(options, { originSlideMenuWidth, collapseSlideMenuWidth }, ops),
258
+ center: () => {
259
+ const { top: centeredTop, left: centeredLeft } = Modal.getModalCenter({ width, height });
260
+ top = centeredTop;
261
+ left = centeredLeft;
262
+ },
263
+ ...this.Data[idModal],
264
+ };
265
+
266
+ if (options && 'mode' in options) {
267
+ Modal.Data[idModal][options.mode] = {};
268
+ switch (options.mode) {
269
+ case 'view':
270
+ // if (options && options.slideMenu) s(`.btn-close-${options.slideMenu}`).click();
271
+ options.zIndexSync = true;
272
+
273
+ options.style = { width: '100%', ...options.style, 'min-width': `${minWidth}px` };
274
+
275
+ if (Modal.mobileModal()) {
276
+ options.barConfig.buttons.restore.disabled = true;
277
+ options.barConfig.buttons.minimize.disabled = true;
278
+ options.dragDisabled = true;
279
+ options.style.resize = 'none';
280
+ setTimeout(() => {
281
+ s(`.btn-close-modal-menu`).click();
282
+ });
283
+ }
284
+
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}`);
293
+
294
+ // Handle view mode modal route
295
+ if (options.route) {
296
+ handleModalViewRoute({
297
+ route: options.route,
298
+ RouterInstance: options.RouterInstance,
299
+ });
300
+ }
301
+
302
+ break;
303
+ case 'slide-menu':
304
+ case 'slide-menu-right':
305
+ case 'slide-menu-left':
306
+ (async () => {
307
+ if (!options.slideMenuTopBarBannerFix) {
308
+ options.slideMenuTopBarBannerFix = async () => {
309
+ let style = html``;
310
+ if (options.barMode === 'top-bottom-bar') {
311
+ style = html`<style>
312
+ .default-slide-menu-top-bar-fix-logo-container {
313
+ width: 50px;
314
+ height: 50px;
315
+ }
316
+ .default-slide-menu-top-bar-fix-logo {
317
+ width: 40px;
318
+ height: 40px;
319
+ padding: 5px;
320
+ }
321
+ .default-slide-menu-top-bar-fix-title-container-text {
322
+ font-size: 26px;
323
+ top: 8px;
324
+ color: ${darkTheme ? '#ffffff' : '#000000'};
325
+ }
326
+ </style>`;
327
+ } else {
328
+ style = html`<style>
329
+ .default-slide-menu-top-bar-fix-logo-container {
330
+ width: 100px;
331
+ height: 100px;
332
+ }
333
+ .default-slide-menu-top-bar-fix-logo {
334
+ width: 50px;
335
+ height: 50px;
336
+ padding: 24px;
337
+ }
338
+ .default-slide-menu-top-bar-fix-title-container-text {
339
+ font-size: 30px;
340
+ top: 30px;
341
+ color: ${darkTheme ? '#ffffff' : '#000000'};
342
+ }
343
+ </style>`;
344
+ }
345
+ setTimeout(() => {
346
+ if (s(`.top-bar-app-icon`) && s(`.top-bar-app-icon`).src) {
347
+ s(`.default-slide-menu-top-bar-fix-logo`).src = s(`.top-bar-app-icon`).src;
348
+ if (s(`.top-bar-app-icon`).classList.contains('negative-color'))
349
+ s(`.default-slide-menu-top-bar-fix-logo`).classList.add('negative-color');
350
+ htmls(
351
+ `.default-slide-menu-top-bar-fix-title-container`,
352
+ html`
353
+ <div class="inl default-slide-menu-top-bar-fix-title-container-text">${options.title}</div>
354
+ `,
355
+ );
356
+ } else
357
+ htmls(
358
+ `.default-slide-menu-top-bar-fix-logo-container`,
359
+ html`<div class="abs center">${s(`.action-btn-app-icon-render`).innerHTML}</div>`,
360
+ );
361
+ });
362
+
363
+ return html`${style}
364
+ <div class="in fll default-slide-menu-top-bar-fix-logo-container">
365
+ <img class="default-slide-menu-top-bar-fix-logo in fll" />
366
+ </div>
367
+ <div class="in fll default-slide-menu-top-bar-fix-title-container"></div>`;
368
+ };
369
+ }
370
+ const { barConfig } = options;
371
+ options.style = {
372
+ height: `${windowGetH() - options.heightTopBar - options.heightBottomBar}px`,
373
+ width: `${slideMenuWidth}px`,
374
+ // 'overflow-x': 'hidden',
375
+ // overflow: 'visible', // required for tooltip
376
+ 'z-index': 6,
377
+ resize: 'none',
378
+ top: `${options.heightTopBar ? options.heightTopBar : heightDefaultTopBar}px`,
379
+ };
380
+ const contentIconClass = 'abs center';
381
+ top = 'auto';
382
+ left = Modal.Data[idModal].getMenuLeftStyle();
383
+ transition = '.3s';
384
+ options.dragDisabled = true;
385
+ options.titleClass = 'hide';
386
+ options.disableCenter = true;
387
+
388
+ // barConfig.buttons.maximize.disabled = true;
389
+ // barConfig.buttons.minimize.disabled = true;
390
+ // barConfig.buttons.restore.disabled = true;
391
+ // barConfig.buttons.menu.disabled = true;
392
+ // barConfig.buttons.close.disabled = true;
393
+ options.btnBarModalClass = 'hide';
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
+ );
418
+ barConfig.buttons.menu.onClick = () => {
419
+ Modal.Data[idModal][options.mode].width = slideMenuWidth;
420
+ s(`.btn-menu-${idModal}`).classList.add('hide');
421
+ s(`.btn-close-${idModal}`).classList.remove('hide');
422
+ // s(`.${idModal}`).style.width = `${this.Data[idModal][options.mode].width}px`;
423
+ s(`.html-${idModal}`).style.display = 'block';
424
+ // s(`.title-modal-${idModal}`).style.display = 'block';
425
+ s(`.main-body-btn-ui-menu-menu`).classList.add('hide');
426
+ s(`.main-body-btn-ui-menu-close`).classList.remove('hide');
427
+ if (s(`.btn-bar-center-icon-menu`)) {
428
+ sa(`.btn-bar-center-icon-close`).forEach((el) => el.classList.remove('hide'));
429
+ sa(`.btn-bar-center-icon-menu`).forEach((el) => el.classList.add('hide'));
430
+ }
431
+
432
+ s(`.main-body-btn-container`).style[
433
+ true || (options.mode && options.mode.match('right')) ? 'right' : 'left'
434
+ ] = options.mode && options.mode.match('right') ? `${slideMenuWidth}px` : '0px';
435
+ if (options.mode === 'slide-menu-right') {
436
+ s(`.${idModal}`).style.left = `${windowGetW() - originSlideMenuWidth}px`;
437
+ } else {
438
+ s(`.${idModal}`).style.left = `0px`;
439
+ }
440
+ Responsive.triggerChanged(`slide-menu-${idModal}`);
441
+ };
442
+ barConfig.buttons.close.onClick = () => {
443
+ Modal.Data[idModal][options.mode].width = 0;
444
+ s(`.btn-close-${idModal}`).classList.add('hide');
445
+ s(`.btn-menu-${idModal}`).classList.remove('hide');
446
+ // s(`.${idModal}`).style.width = `${this.Data[idModal][options.mode].width}px`;
447
+ // s(`.html-${idModal}`).style.display = 'none';
448
+ // s(`.title-modal-${idModal}`).style.display = 'none';
449
+ s(`.main-body-btn-ui-menu-close`).classList.add('hide');
450
+ s(`.main-body-btn-ui-menu-menu`).classList.remove('hide');
451
+ if (s(`.btn-bar-center-icon-menu`)) {
452
+ sa(`.btn-bar-center-icon-menu`).forEach((el) => el.classList.remove('hide'));
453
+ sa(`.btn-bar-center-icon-close`).forEach((el) => el.classList.add('hide'));
454
+ }
455
+ s(`.main-body-btn-container`).style[
456
+ true || (options.mode && options.mode.match('right')) ? 'right' : 'left'
457
+ ] = `${0}px`;
458
+ if (options.mode === 'slide-menu-right') {
459
+ s(`.${idModal}`).style.left = `${windowGetW() + originSlideMenuWidth}px`;
460
+ } else {
461
+ s(`.${idModal}`).style.left = `-${originSlideMenuWidth}px`;
462
+ }
463
+ Responsive.triggerChanged(`slide-menu-${idModal}`);
464
+ };
465
+ transition += `, width 0.3s`;
466
+
467
+ setTimeout(() => {
468
+ setTimeout(btnCloseEvent);
469
+ append(
470
+ 'body',
471
+ html`
472
+ <div
473
+ class="abs main-body-btn-container"
474
+ style="top: ${options.heightTopBar + 50}px; z-index: 9; ${true ||
475
+ (options.mode && options.mode.match('right'))
476
+ ? 'right'
477
+ : 'left'}: 0px; width: 50px; height: 150px; transition: .3s"
478
+ >
479
+ <div
480
+ class="abs main-body-btn main-body-btn-ui"
481
+ style="top: 0px; ${true || (options.mode && options.mode.match('right')) ? 'right' : 'left'}: 0px"
482
+ >
483
+ <div class="abs center">
484
+ <i class="fas fa-caret-down main-body-btn-ui-open hide"></i>
485
+ <i class="fas fa-caret-up main-body-btn-ui-close"></i>
486
+ </div>
487
+ </div>
488
+ <div
489
+ class="abs main-body-btn main-body-btn-menu"
490
+ style="top: 50px; ${true || (options.mode && options.mode.match('right'))
491
+ ? 'right'
492
+ : 'left'}: 0px"
493
+ >
494
+ <div class="abs center">
495
+ <i class="fa-solid fa-xmark hide main-body-btn-ui-menu-close"></i>
496
+ <i class="fa-solid fa-bars main-body-btn-ui-menu-menu"></i>
497
+ </div>
498
+ </div>
499
+ <div
500
+ class="abs main-body-btn main-body-btn-bar-custom ${options?.slideMenuTopBarBannerFix
501
+ ? ''
502
+ : 'hide'}"
503
+ style="top: 100px; ${true || (options.mode && options.mode.match('right'))
504
+ ? 'right'
505
+ : 'left'}: 0px"
506
+ >
507
+ <div class="abs center">
508
+ <i class="fa-solid fa-magnifying-glass main-body-btn-ui-bar-custom-open"></i>
509
+ <i class="fa-solid fa-home hide main-body-btn-ui-bar-custom-close"></i>
510
+ </div>
511
+ </div>
512
+ </div>
513
+ `,
514
+ );
515
+
516
+ s(`.main-body-btn-menu`).onclick = () => {
517
+ Modal.actionBtnCenter();
518
+ };
519
+
520
+ s(`.main-body-btn-bar-custom`).onclick = () => {
521
+ if (s(`.main-body-btn-ui-close`).classList.contains('hide')) {
522
+ s(`.main-body-btn-ui`).click();
523
+ }
524
+ if (s(`.main-body-btn-ui-bar-custom-open`).classList.contains('hide')) {
525
+ s(`.main-body-btn-ui-bar-custom-open`).classList.remove('hide');
526
+ s(`.main-body-btn-ui-bar-custom-close`).classList.add('hide');
527
+ s(`.slide-menu-top-bar-fix`).style.top = '0px';
528
+ } else {
529
+ s(`.main-body-btn-ui-bar-custom-open`).classList.add('hide');
530
+ s(`.main-body-btn-ui-bar-custom-close`).classList.remove('hide');
531
+ s(`.slide-menu-top-bar-fix`).style.top = '-100px';
532
+ s(`.top-bar-search-box-container`).click();
533
+ }
534
+ if (Modal.mobileModal()) {
535
+ btnCloseEvent();
536
+ }
537
+ };
538
+
539
+ let _heightTopBar, _heightBottomBar, _topMenu;
540
+ s(`.main-body-btn-ui`).onclick = () => {
541
+ if (s(`.main-body-btn-ui-open`).classList.contains('hide')) {
542
+ s(`.main-body-btn-ui-open`).classList.remove('hide');
543
+ s(`.main-body-btn-ui-close`).classList.add('hide');
544
+ _heightTopBar = newInstance(options.heightTopBar);
545
+ _heightBottomBar = newInstance(options.heightBottomBar);
546
+ _topMenu = newInstance(s(`.modal-menu`).style.top);
547
+ options.heightTopBar = 0;
548
+ options.heightBottomBar = 0;
549
+ s(`.slide-menu-top-bar`).classList.add('hide');
550
+ s(`.bottom-bar`).classList.add('hide');
551
+ s(`.modal-menu`).style.top = '0px';
552
+ s(`.main-body-btn-container`).style.top = '50px';
553
+ s(`.main-body`).style.top = '0px';
554
+ s(`.main-body`).style.height = `${windowGetH()}px`;
555
+ for (const event of Object.keys(Modal.Data[idModal].onBarUiClose))
556
+ Modal.Data[idModal].onBarUiClose[event]();
557
+ } else {
558
+ s(`.main-body-btn-ui-close`).classList.remove('hide');
559
+ s(`.main-body-btn-ui-open`).classList.add('hide');
560
+ options.heightTopBar = _heightTopBar;
561
+ options.heightBottomBar = _heightBottomBar;
562
+ s(`.modal-menu`).style.top = _topMenu;
563
+ s(`.main-body-btn-container`).style.top = `${options.heightTopBar + 50}px`;
564
+ s(`.slide-menu-top-bar`).classList.remove('hide');
565
+ s(`.bottom-bar`).classList.remove('hide');
566
+ s(`.main-body`).style.top = `${options.heightTopBar}px`;
567
+ s(`.main-body`).style.height = `${windowGetH() - options.heightTopBar}px`;
568
+ for (const event of Object.keys(Modal.Data[idModal].onBarUiOpen))
569
+ Modal.Data[idModal].onBarUiOpen[event]();
570
+ }
571
+ Responsive.triggerChanged(`slide-menu-modal-menu`);
572
+ Object.keys(this.Data).map((_idModal) => {
573
+ if (this.Data[_idModal].slideMenu) {
574
+ if (s(`.btn-maximize-${_idModal}`)) s(`.btn-maximize-${_idModal}`).click();
575
+ }
576
+ });
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'}`);
582
+ for (const keyEvent of Object.keys(this.Data[idModal].onExpandUiListener)) {
583
+ this.Data[idModal].onExpandUiListener[keyEvent](
584
+ !s(`.main-body-btn-ui-open`).classList.contains('hide'),
585
+ );
586
+ }
587
+ };
588
+ Modal.setTopBannerLink();
589
+ });
590
+
591
+ const inputSearchBoxId = `top-bar-search-box`;
592
+ append(
593
+ 'body',
594
+ html` <div class="fix modal slide-menu-top-bar">
595
+ <div
596
+ class="fl top-bar ${options.barClass ? options.barClass : ''}"
597
+ style="height: ${originHeightTopBar}px;"
598
+ >
599
+ ${await BtnIcon.instance({
600
+ style: `height: 100%`,
601
+ class: 'in fll main-btn-menu action-bar-box action-btn-close hide',
602
+ label: html` <div class="${contentIconClass} action-btn-close-render">
603
+ <i class="fa-solid fa-xmark"></i>
604
+ </div>`,
605
+ })}
606
+ ${await BtnIcon.instance({
607
+ style: `height: 100%`,
608
+ class: `in fll main-btn-menu action-bar-box action-btn-app-icon ${
609
+ options?.disableTools?.includes('app-icon') ? 'hide' : ''
610
+ }`,
611
+ label: html` <div class="${contentIconClass} action-btn-app-icon-render"></div>`,
612
+ })}
613
+ <form
614
+ class="in fll top-bar-search-box-container hover ${options?.disableTools?.includes('text-box')
615
+ ? 'hide'
616
+ : ''}"
617
+ >
618
+ ${await Input.instance({
619
+ id: inputSearchBoxId,
620
+ autocomplete: 'off',
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')}`,
624
+ placeholderIcon: html`<div
625
+ class="in fll"
626
+ style="width: ${originHeightTopBar}px; height: ${originHeightTopBar}px;"
627
+ >
628
+ <div class="abs center"><i class="fa-solid fa-magnifying-glass"></i></div>
629
+ ${!Modal.mobileModal()
630
+ ? html` <div
631
+ class="inl wfm key-shortcut-container-info"
632
+ style="${renderCssAttr({ style: { top: '10px', left: '60px' } })}"
633
+ >
634
+ ${await Badge.instance({
635
+ id: 'shortcut-key-info-search',
636
+ text: 'Shift',
637
+ classList: 'inl',
638
+ style: { 'z-index': 1 },
639
+ })}
640
+ ${await Badge.instance({
641
+ id: 'shortcut-key-info-search',
642
+ text: '+',
643
+ classList: 'inl',
644
+ style: { 'z-index': 1, background: 'none', color: '#5f5f5f' },
645
+ })}
646
+ ${await Badge.instance({
647
+ id: 'shortcut-key-info-search',
648
+ text: 'k',
649
+ classList: 'inl',
650
+ style: { 'z-index': 1 },
651
+ })}
652
+ </div>`
653
+ : ''}
654
+ </div>`,
655
+ inputClass: 'in fll',
656
+ // containerClass: '',
657
+ })}
658
+ </form>
659
+ <div
660
+ class="abs top-box-profile-container ${options?.disableTools?.includes('profile') ? 'hide' : ''}"
661
+ >
662
+ ${await BtnIcon.instance({
663
+ style: `height: 100%`,
664
+ class: 'in fll session-in-log-in main-btn-menu action-bar-box action-btn-profile-log-in',
665
+ label: html` <div class="${contentIconClass} action-btn-profile-log-in-render"></div>`,
666
+ })}
667
+ ${await BtnIcon.instance({
668
+ style: `height: 100%`,
669
+ class: 'in fll session-in-log-out main-btn-menu action-bar-box action-btn-profile-log-out',
670
+ label: html` <div class="${contentIconClass} action-btn-profile-log-out-render">
671
+ <i class="fas fa-user-plus"></i>
672
+ </div>`,
673
+ })}
674
+ </div>
675
+ </div>
676
+ ${options?.slideMenuTopBarBannerFix
677
+ ? html`<div
678
+ class="abs modal slide-menu-top-bar-fix"
679
+ style="height: ${options.heightTopBar}px; top: 0px"
680
+ >
681
+ <a class="a-link-top-banner fl">
682
+ <div class="inl">${await options.slideMenuTopBarBannerFix()}</div></a
683
+ >
684
+ </div>`
685
+ : ''}
686
+ ${idModal === 'modal-menu' && options.mode !== 'slide-menu-right'
687
+ ? html`<div
688
+ class="abs main-btn-menu-top-container"
689
+ style="bottom: 0px; left: 0px; z-index: 10; height: ${originHeightTopBar}px; width: ${originHeightTopBar}px"
690
+ >
691
+ ${await BtnIcon.instance({
692
+ style: `height: 100%`,
693
+ class: `in fll main-btn-menu-top action-bar-box action-btn-center-top`,
694
+ label: html`<div class="abs center">
695
+ <i class="far fa-square btn-bar-center-icon-square hide"></i>
696
+ <span class="btn-bar-center-icon-close hide">${barConfig.buttons.close.label}</span>
697
+ <span class="btn-bar-center-icon-menu">${barConfig.buttons.menu.label}</span>
698
+ </div>`,
699
+ })}
700
+ </div>
701
+
702
+ <style>
703
+ .a-link-top-banner {
704
+ padding-left: 35px;
705
+ }
706
+ .main-body-btn-bar-custom {
707
+ top: 50px !important;
708
+ }
709
+ .main-body-btn-menu {
710
+ display: none;
711
+ }
712
+ </style>`
713
+ : ''}
714
+ </div>`,
715
+ );
716
+ EventsUI.onClick(`.action-btn-profile-log-in`, () => {
717
+ if (Modal.mobileModal() && s(`.btn-close-search-box-history`)) {
718
+ s(`.btn-close-search-box-history`).click();
719
+ }
720
+ s(`.main-btn-account`).click();
721
+ });
722
+ EventsUI.onClick(`.action-btn-profile-log-out`, () => {
723
+ if (Modal.mobileModal() && s(`.btn-close-search-box-history`)) {
724
+ s(`.btn-close-search-box-history`).click();
725
+ }
726
+ s(`.main-btn-sign-up`).click();
727
+ });
728
+ if (idModal === 'modal-menu' && options.mode !== 'slide-menu-right') {
729
+ EventsUI.onClick(`.action-btn-center-top`, (e) => {
730
+ e.preventDefault();
731
+ Modal.actionBtnCenter();
732
+ });
733
+ }
734
+ s(`.input-info-${inputSearchBoxId}`).style.textAlign = 'left';
735
+ htmls(`.input-info-${inputSearchBoxId}`, '');
736
+ const inputInfoNode = s(`.input-info-${inputSearchBoxId}`).cloneNode(true);
737
+ s(`.input-info-${inputSearchBoxId}`).remove();
738
+ {
739
+ // Inject SearchBox base styles
740
+ SearchBox.injectStyles();
741
+
742
+ const id = 'search-box-history';
743
+ const searchBoxHistoryId = id;
744
+ const formDataInfoNode = [
745
+ {
746
+ model: 'search-box',
747
+ id: inputSearchBoxId,
748
+ rules: [] /*{ type: 'isEmpty' }, { type: 'isEmail' }*/,
749
+ },
750
+ ];
751
+ // Reusable hover/focus controller for search history panel
752
+ let unbindDocSearch = null;
753
+ const hoverFocusCtl = EventsUI.HoverFocusController({
754
+ inputSelector: `.top-bar-search-box-container`,
755
+ panelSelector: `.${id}`,
756
+ activeElementId: inputSearchBoxId,
757
+ onDismiss: () => dismissSearchBox(),
758
+ });
759
+ let currentKeyBoardSearchBoxIndex = 0;
760
+ let results = [];
761
+
762
+ const checkHistoryBoxTitleStatus = () => {
763
+ if (s(`.search-box-result-title`) && s(`.search-box-result-title`).classList) {
764
+ if (!s(`.${inputSearchBoxId}`).value.trim()) {
765
+ s(`.search-box-result-title`).classList.add('hide');
766
+ s(`.search-box-recent-title`).classList.remove('hide');
767
+ } else {
768
+ s(`.search-box-recent-title`).classList.add('hide');
769
+ s(`.search-box-result-title`).classList.remove('hide');
770
+ }
771
+ }
772
+ };
773
+
774
+ const checkShortcutContainerInfoEnabled = () => {
775
+ if (Modal.mobileModal() || !s(`.key-shortcut-container-info`)) return;
776
+ if (!s(`.${inputSearchBoxId}`).value) {
777
+ s(`.key-shortcut-container-info`).classList.remove('hide');
778
+ } else s(`.key-shortcut-container-info`).classList.add('hide');
779
+ };
780
+
781
+ const renderSearchResult = async (results, isRecentHistory = false) => {
782
+ // Check if the search history modal still exists before rendering
783
+ if (!s(`.html-${searchBoxHistoryId}`)) return;
784
+
785
+ htmls(`.html-${searchBoxHistoryId}`, '');
786
+
787
+ // Show/hide clear-all button based on whether showing recent history
788
+ // Use setTimeout to ensure the button is in the DOM after modal renders
789
+ const updateClearAllBtn = () => {
790
+ const clearAllBtn = s(`.btn-search-history-clear-all`);
791
+ if (clearAllBtn) {
792
+ if (isRecentHistory && results.length > 0) {
793
+ clearAllBtn.style.display = 'flex';
794
+ } else {
795
+ clearAllBtn.style.display = 'none';
796
+ }
797
+ }
798
+ };
799
+ // Try immediately and also with a delay to handle timing
800
+ updateClearAllBtn();
801
+ setTimeout(updateClearAllBtn, 50);
802
+
803
+ if (results.length === 0) {
804
+ append(
805
+ `.html-${searchBoxHistoryId}`,
806
+ await BtnIcon.instance({
807
+ label: html`<i class="fas fa-exclamation-circle"></i> ${Translate.instance('no-result-found')}`,
808
+ class: `wfa`,
809
+ style: renderCssAttr({
810
+ style: {
811
+ padding: '3px',
812
+ margin: '2px',
813
+ 'text-align': 'center',
814
+ border: 'none',
815
+ cursor: 'default',
816
+ background: 'none !important',
817
+ },
818
+ }),
819
+ }),
820
+ );
821
+ return;
822
+ }
823
+
824
+ // Use SearchBox component for rendering results
825
+ const searchContext = {
826
+ RouterInstance: Worker.RouterInstance,
827
+ options: options,
828
+ isRecentHistory: isRecentHistory, // Flag for delete button visibility
829
+ onResultClick: () => {
830
+ // Dismiss search box on result click
831
+ if (s(`.${searchBoxHistoryId}`)) {
832
+ Modal.removeModal(searchBoxHistoryId);
833
+ }
834
+ },
835
+ };
836
+
837
+ SearchBox.renderResults(results, `html-${searchBoxHistoryId}`, searchContext);
838
+ };
839
+
840
+ const getResultSearchBox = async (validatorData) => {
841
+ if (!s(`.html-${searchBoxHistoryId}`)) return;
842
+ const { model, id } = validatorData;
843
+
844
+ switch (model) {
845
+ case 'search-box':
846
+ {
847
+ currentKeyBoardSearchBoxIndex = 0;
848
+ results = [];
849
+
850
+ const query = s(`.${id}`) ? s(`.${id}`).value : '';
851
+ const trimmedQuery = query.trim();
852
+
853
+ // Use SearchBox component for extensible search
854
+ const searchContext = {
855
+ RouterInstance: Worker.RouterInstance,
856
+ options: options,
857
+ minQueryLength: options?.minSearchQueryLength || 1, // Allow single character search by default
858
+ onResultClick: () => {
859
+ // Dismiss search box on result click
860
+ if (s(`.${searchBoxHistoryId}`)) {
861
+ Modal.removeModal(searchBoxHistoryId);
862
+ }
863
+ },
864
+ };
865
+
866
+ // Check minimum query length (default: 1 character)
867
+ const minLength = searchContext.minQueryLength;
868
+ if (trimmedQuery.length >= minLength) {
869
+ results = await SearchBox.search(trimmedQuery, searchContext);
870
+ renderSearchResult(results, false); // Search results - no delete buttons
871
+ } else if (trimmedQuery.length === 0) {
872
+ // Show recent results from persistent history when query is empty
873
+ const recentResults = SearchBox.RecentResults.getAll();
874
+ renderSearchResult(recentResults, true); // Recent history - show delete buttons
875
+ } else {
876
+ // Query is too short - show nothing or a hint
877
+ renderSearchResult([], false);
878
+ }
879
+ }
880
+ break;
881
+
882
+ default:
883
+ break;
884
+ }
885
+ };
886
+
887
+ const searchBoxCallBack = async (validatorData) => {
888
+ const isSearchBoxActiveElement = isActiveElement(inputSearchBoxId);
889
+ checkHistoryBoxTitleStatus();
890
+ checkShortcutContainerInfoEnabled();
891
+ if (!isSearchBoxActiveElement && !hoverFocusCtl.shouldStay()) {
892
+ Modal.removeModal(searchBoxHistoryId);
893
+ return;
894
+ }
895
+ setTimeout(() => {
896
+ getResultSearchBox(validatorData);
897
+
898
+ if (
899
+ s(`.slide-menu-top-bar-fix`) &&
900
+ !s(`.main-body-btn-ui-bar-custom-open`).classList.contains('hide')
901
+ ) {
902
+ s(`.main-body-btn-bar-custom`).click();
903
+ }
904
+ });
905
+ };
906
+
907
+ const updateSearchBoxValue = (selector) => {
908
+ if (!selector) {
909
+ // Get the currently active search result item
910
+ const activeItem = s(`.html-${searchBoxHistoryId} .search-result-item.active-search-result`);
911
+ if (activeItem) {
912
+ const titleEl = activeItem.querySelector('.search-result-title');
913
+ if (titleEl && titleEl.textContent) {
914
+ s(`.${inputSearchBoxId}`).value = titleEl.textContent.trim();
915
+ }
916
+ }
917
+ } else if (s(selector)) {
918
+ const titleEl = s(selector).querySelector('.search-result-title');
919
+ if (titleEl && titleEl.textContent) {
920
+ s(`.${inputSearchBoxId}`).value = titleEl.textContent.trim();
921
+ }
922
+ }
923
+ checkHistoryBoxTitleStatus();
924
+ checkShortcutContainerInfoEnabled();
925
+ };
926
+
927
+ const setSearchValue = (selector) => {
928
+ // Get all search result items
929
+ const allItems = sa(`.html-${searchBoxHistoryId} .search-result-item`);
930
+ if (!allItems || allItems.length === 0) return;
931
+
932
+ const activeItem = allItems[currentKeyBoardSearchBoxIndex];
933
+ if (!activeItem) return;
934
+
935
+ const resultId = activeItem.getAttribute('data-result-id');
936
+ const resultType = activeItem.getAttribute('data-result-type');
937
+
938
+ if (resultType === 'route' && results[currentKeyBoardSearchBoxIndex]) {
939
+ const result = results[currentKeyBoardSearchBoxIndex];
940
+ // Track in persistent history
941
+ SearchBox.RecentResults.add(result);
942
+ updateSearchBoxValue();
943
+ if (s(`.main-btn-${resultId}`)) {
944
+ s(`.main-btn-${resultId}`).click();
945
+ }
946
+ } else {
947
+ // Track custom provider result in persistent history
948
+ if (results[currentKeyBoardSearchBoxIndex]) {
949
+ SearchBox.RecentResults.add(results[currentKeyBoardSearchBoxIndex]);
950
+ }
951
+ // Trigger click on custom result
952
+ activeItem.click();
953
+ }
954
+ Modal.removeModal(searchBoxHistoryId);
955
+ };
956
+ let boxHistoryDelayRender = 0;
957
+ const searchBoxHistoryOpen = async () => {
958
+ if (boxHistoryDelayRender) return;
959
+ if (Modal.mobileModal()) {
960
+ btnCloseEvent();
961
+ }
962
+ boxHistoryDelayRender = 1000;
963
+ setTimeout(() => (boxHistoryDelayRender = 0));
964
+ if (!s(`.${searchBoxHistoryId}`)) {
965
+ const { barConfig } = await Themes[Css.currentTheme]();
966
+ barConfig.buttons.maximize.disabled = true;
967
+ barConfig.buttons.minimize.disabled = true;
968
+ barConfig.buttons.restore.disabled = true;
969
+ barConfig.buttons.menu.disabled = true;
970
+ barConfig.buttons.close.disabled = false;
971
+
972
+ await Modal.instance({
973
+ id: searchBoxHistoryId,
974
+ barConfig,
975
+ title: html`<div
976
+ style="display: flex; align-items: center; justify-content: space-between; width: 100%;"
977
+ >
978
+ <div style="display: flex; align-items: center; gap: 8px;">
979
+ <div class="search-box-recent-title">
980
+ ${renderViewTitle({
981
+ icon: html`<i class="fas fa-history mini-title"></i>`,
982
+ text: Translate.instance('recent'),
983
+ })}
984
+ </div>
985
+ <div class="search-box-result-title hide">
986
+ ${renderViewTitle({
987
+ icon: html`<i class="far fa-list-alt mini-title"></i>`,
988
+ text: Translate.instance('results'),
989
+ })}
990
+ </div>
991
+ </div>
992
+ </div>`,
993
+ html: () => html``,
994
+ titleClass: 'mini-title',
995
+ style: {
996
+ resize: 'none',
997
+ 'max-width': '450px',
998
+ height:
999
+ this.mobileModal() && windowGetW() < 445
1000
+ ? `${windowGetH() - originHeightTopBar}px !important`
1001
+ : '300px !important',
1002
+ 'z-index': 7,
1003
+ },
1004
+ class: 'search-history-modal',
1005
+ dragDisabled: true,
1006
+ maximize: true,
1007
+ barMode: options.barMode,
1008
+ });
1009
+
1010
+ // Bind hover/focus and click-outside to dismiss
1011
+ hoverFocusCtl.bind();
1012
+ unbindDocSearch = EventsUI.bindDismissOnDocumentClick({
1013
+ shouldStay: hoverFocusCtl.shouldStay,
1014
+ onDismiss: () => dismissSearchBox(),
1015
+ anchors: [`.top-bar-search-box-container`, `.${id}`],
1016
+ });
1017
+ // Ensure cleanup when modal closes
1018
+ Modal.Data[id].onCloseListener[`unbind-doc-${id}`] = () => unbindDocSearch && unbindDocSearch();
1019
+
1020
+ Modal.MoveTitleToBar(id);
1021
+
1022
+ // Add styles for inline button layout in the search history modal bar
1023
+ const styleId = 'search-history-modal-bar-styles';
1024
+ if (!s(`#${styleId}`)) {
1025
+ const styleTag = document.createElement('style');
1026
+ styleTag.id = styleId;
1027
+ styleTag.textContent = `
1028
+ .search-history-modal .btn-bar-modal-container .bar-default-modal {
1029
+ display: flex;
1030
+ flex-direction: row-reverse;
1031
+ align-items: center;
1032
+ }
1033
+ .search-history-modal .btn-bar-modal-container .btn-modal-default {
1034
+ display: inline-flex;
1035
+ align-items: center;
1036
+ justify-content: center;
1037
+ float: none;
1038
+ }
1039
+ .search-history-modal .html-${searchBoxHistoryId} {
1040
+ overflow-x: hidden;
1041
+ box-sizing: border-box;
1042
+ }
1043
+ .search-history-modal .html-${searchBoxHistoryId} .search-result-item,
1044
+ .search-history-modal .html-${searchBoxHistoryId} .search-result-history-item {
1045
+ box-sizing: border-box;
1046
+ max-width: 100%;
1047
+ }
1048
+ `;
1049
+ document.head.appendChild(styleTag);
1050
+ }
1051
+
1052
+ // Add clear all button to the bar area, before the close button
1053
+ const clearAllBtnHtml = await BtnIcon.instance({
1054
+ class: `btn-search-history-clear-all btn-modal-default btn-modal-default-${searchBoxHistoryId}`,
1055
+ label: html`<i class="fas fa-trash-alt"></i>`,
1056
+ attrs: `title="Clear all recent items"`,
1057
+ style: 'padding: 4px 8px; font-size: 12px; display: none;',
1058
+ });
1059
+
1060
+ // Insert before close button in the bar (with flex row-reverse, inserting after close button places our button to its left visually)
1061
+ const closeBtn = s(`.btn-close-${searchBoxHistoryId}`);
1062
+ if (closeBtn) {
1063
+ closeBtn.insertAdjacentHTML('afterend', clearAllBtnHtml);
1064
+ }
1065
+
1066
+ // Add click handler for clear all history button
1067
+ const clearAllBtn = s(`.btn-search-history-clear-all`);
1068
+ if (clearAllBtn) {
1069
+ clearAllBtn.onclick = (e) => {
1070
+ e.preventDefault();
1071
+ e.stopPropagation();
1072
+ // Clear all history from persistent storage
1073
+ SearchBox.RecentResults.clear();
1074
+ // Re-render to show empty history (with isRecentHistory true to hide button)
1075
+ renderSearchResult([], true);
1076
+ };
1077
+ }
1078
+
1079
+ prepend(`.btn-bar-modal-container-${id}`, html`<div class="hide">${inputInfoNode.outerHTML}</div>`);
1080
+ }
1081
+ };
1082
+
1083
+ s('.top-bar-search-box').oninput = () => {
1084
+ searchBoxHistoryOpen();
1085
+ searchBoxCallBack(formDataInfoNode[0]);
1086
+ };
1087
+ s('.top-bar-search-box').onfocus = () => {
1088
+ searchBoxHistoryOpen();
1089
+ searchBoxCallBack(formDataInfoNode[0]);
1090
+ };
1091
+
1092
+ const dismissSearchBox = () => {
1093
+ if (unbindDocSearch) {
1094
+ try {
1095
+ unbindDocSearch();
1096
+ } catch (e) {}
1097
+ }
1098
+ Modal.removeModal(searchBoxHistoryId);
1099
+ };
1100
+ s('.top-bar-search-box').onblur = () => {
1101
+ hoverFocusCtl.checkDismiss();
1102
+ };
1103
+ EventsUI.onClick(`.top-bar-search-box-container`, () => {
1104
+ if (SearchBox.Data.skipOpen) {
1105
+ SearchBox.Data.skipOpen = false;
1106
+ return;
1107
+ }
1108
+ searchBoxHistoryOpen();
1109
+ searchBoxCallBack(formDataInfoNode[0]);
1110
+ const inputEl = s(`.${inputSearchBoxId}`);
1111
+ if (inputEl && inputEl.focus) inputEl.focus();
1112
+ });
1113
+
1114
+ const timePressDelay = 100;
1115
+ Keyboard.instanceMultiPressKey({
1116
+ id: 'input-search-shortcut-ArrowUp',
1117
+ keys: ['ArrowUp'],
1118
+ eventCallBack: () => {
1119
+ if (s(`.${id}`)) {
1120
+ const allItems = sa(`.html-${searchBoxHistoryId} .search-result-item`);
1121
+ if (!allItems || allItems.length === 0) return;
1122
+
1123
+ // Remove active class from current
1124
+ if (allItems[currentKeyBoardSearchBoxIndex]) {
1125
+ allItems[currentKeyBoardSearchBoxIndex].classList.remove('active-search-result');
1126
+ }
1127
+
1128
+ // Navigate up
1129
+ if (currentKeyBoardSearchBoxIndex > 0) {
1130
+ currentKeyBoardSearchBoxIndex--;
1131
+ } else {
1132
+ currentKeyBoardSearchBoxIndex = allItems.length - 1;
1133
+ }
1134
+
1135
+ // Add active class to new and ensure visibility
1136
+ if (allItems[currentKeyBoardSearchBoxIndex]) {
1137
+ allItems[currentKeyBoardSearchBoxIndex].classList.add('active-search-result');
1138
+ // Use optimized scroll method to ensure item is always visible
1139
+ const container = s(`.html-${searchBoxHistoryId}`);
1140
+ if (container) {
1141
+ SearchBox.scrollIntoViewIfNeeded(allItems[currentKeyBoardSearchBoxIndex], container);
1142
+ }
1143
+ }
1144
+ updateSearchBoxValue();
1145
+ }
1146
+ },
1147
+ timePressDelay,
1148
+ });
1149
+
1150
+ Keyboard.instanceMultiPressKey({
1151
+ id: 'input-search-shortcut-ArrowDown',
1152
+ keys: ['ArrowDown'],
1153
+ eventCallBack: () => {
1154
+ if (s(`.${id}`)) {
1155
+ const allItems = sa(`.html-${searchBoxHistoryId} .search-result-item`);
1156
+ if (!allItems || allItems.length === 0) return;
1157
+
1158
+ // Remove active class from current
1159
+ if (allItems[currentKeyBoardSearchBoxIndex]) {
1160
+ allItems[currentKeyBoardSearchBoxIndex].classList.remove('active-search-result');
1161
+ }
1162
+
1163
+ // Navigate down
1164
+ if (currentKeyBoardSearchBoxIndex < allItems.length - 1) {
1165
+ currentKeyBoardSearchBoxIndex++;
1166
+ } else {
1167
+ currentKeyBoardSearchBoxIndex = 0;
1168
+ }
1169
+
1170
+ // Add active class to new and ensure visibility
1171
+ if (allItems[currentKeyBoardSearchBoxIndex]) {
1172
+ allItems[currentKeyBoardSearchBoxIndex].classList.add('active-search-result');
1173
+ // Use optimized scroll method to ensure item is always visible
1174
+ const container = s(`.html-${searchBoxHistoryId}`);
1175
+ if (container) {
1176
+ SearchBox.scrollIntoViewIfNeeded(allItems[currentKeyBoardSearchBoxIndex], container);
1177
+ }
1178
+ }
1179
+ updateSearchBoxValue();
1180
+ }
1181
+ },
1182
+ timePressDelay,
1183
+ });
1184
+
1185
+ s(`.top-bar-search-box-container`).onsubmit = (e) => {
1186
+ e.preventDefault();
1187
+ setSearchValue();
1188
+ };
1189
+ }
1190
+ setTimeout(async () => {
1191
+ // clone and change position
1192
+
1193
+ // s(`.btn-close-${idModal}`);
1194
+ // s(`.btn-menu-${idModal}`);
1195
+ if (originHeightBottomBar === 0) {
1196
+ const btnCloseNode = s(`.btn-close-${idModal}`).cloneNode(true);
1197
+ s(`.btn-close-${idModal}`).remove();
1198
+ s(`.top-bar`).appendChild(btnCloseNode);
1199
+ s(`.btn-close-${idModal}`).onclick = btnCloseEvent;
1200
+
1201
+ const btnMenuNode = s(`.btn-menu-${idModal}`).cloneNode(true);
1202
+ s(`.btn-menu-${idModal}`).remove();
1203
+ s(`.top-bar`).appendChild(btnMenuNode);
1204
+ s(`.btn-menu-${idModal}`).onclick = btnMenuEvent;
1205
+ }
1206
+
1207
+ // const titleNode = s(`.title-modal-${idModal}`).cloneNode(true);
1208
+ // s(`.title-modal-${idModal}`).remove();
1209
+ // s(`.top-bar`).appendChild(titleNode);
1210
+
1211
+ s(`.slide-menu-top-bar`).style.zIndex = 7;
1212
+
1213
+ // s('body').removeChild(`.${idModal}`);
1214
+ // while (s(`.top-modal`).firstChild) s(`.top-modal`).removeChild(s(`.top-modal`).firstChild);
1215
+
1216
+ {
1217
+ const { barConfig } = await Themes[Css.currentTheme]();
1218
+ barConfig.buttons.maximize.disabled = true;
1219
+ barConfig.buttons.minimize.disabled = true;
1220
+ barConfig.buttons.restore.disabled = true;
1221
+ barConfig.buttons.menu.disabled = true;
1222
+ barConfig.buttons.close.disabled = true;
1223
+ const id = 'main-body';
1224
+ await Modal.instance({
1225
+ id,
1226
+ barConfig,
1227
+ html: options.htmlMainBody ? options.htmlMainBody : () => html``,
1228
+ titleClass: 'hide',
1229
+ style: {
1230
+ // overflow: 'hidden',
1231
+ background: 'none',
1232
+ resize: 'none',
1233
+ 'min-width': `${minWidth}px`,
1234
+ width: '100%',
1235
+ // border: '3px solid red',
1236
+ },
1237
+ dragDisabled: true,
1238
+ maximize: true,
1239
+ slideMenu: 'modal-menu',
1240
+ barMode: options.barMode,
1241
+ observer: true,
1242
+ disableBoxShadow: true,
1243
+ });
1244
+ const maxWidthInputSearchBox = 450;
1245
+ const paddingInputSearchBox = 5;
1246
+ const paddingRightSearchBox = 50;
1247
+ Responsive.onChanged(
1248
+ () => {
1249
+ if (!this.Data[id] || !s(`.${id}`)) return Responsive.offChanged(`view-${id}`);
1250
+ const widthInputSearchBox =
1251
+ windowGetW() > maxWidthInputSearchBox ? maxWidthInputSearchBox : windowGetW();
1252
+ s(`.top-bar-search-box-container`).style.width = `${
1253
+ widthInputSearchBox - originHeightTopBar - paddingRightSearchBox - 1
1254
+ }px`;
1255
+ s(`.top-bar-search-box`).style.width = `${
1256
+ widthInputSearchBox -
1257
+ originHeightTopBar * 2 -
1258
+ paddingRightSearchBox -
1259
+ paddingInputSearchBox * 2 /*padding input*/ -
1260
+ 10 /* right-margin */
1261
+ }px`;
1262
+ s(`.top-bar-search-box`).style.top = `${
1263
+ (originHeightTopBar - s(`.top-bar-search-box`).clientHeight) / 2
1264
+ }px`;
1265
+ if (this.Data[id].slideMenu) s(`.${id}`).style.height = `${Modal.Data[id].getHeight()}px`;
1266
+ },
1267
+ { key: `view-${id}` },
1268
+ );
1269
+ Responsive.triggerChanged(`view-${id}`);
1270
+ Keyboard.instanceMultiPressKey({
1271
+ id: 'input-search-shortcut-k',
1272
+ keys: [
1273
+ ['Shift', 'k'],
1274
+ ['Alt', 'k'],
1275
+ ],
1276
+ eventCallBack: () => {
1277
+ if (isTextInputFocused()) return;
1278
+ if (s(`.top-bar-search-box`)) {
1279
+ if (s(`.main-body-btn-ui-close`).classList.contains('hide')) {
1280
+ s(`.main-body-btn-ui-open`).click();
1281
+ }
1282
+ s(`.top-bar-search-box`).blur();
1283
+ s(`.top-bar-search-box`).focus();
1284
+ s(`.top-bar-search-box`).select();
1285
+ }
1286
+ },
1287
+ });
1288
+ }
1289
+
1290
+ {
1291
+ const { barConfig } = await Themes[Css.currentTheme]();
1292
+ barConfig.buttons.maximize.disabled = true;
1293
+ barConfig.buttons.minimize.disabled = true;
1294
+ barConfig.buttons.restore.disabled = true;
1295
+ barConfig.buttons.menu.disabled = true;
1296
+ barConfig.buttons.close.disabled = true;
1297
+ const id = 'bottom-bar';
1298
+ if (!this.Data[idModal].homeModals) this.Data[idModal].homeModals = [];
1299
+ if (!this.Data[idModal].homeModals.includes(id)) {
1300
+ this.Data[idModal].homeModals.push(id);
1301
+ }
1302
+ const html = async () => html`
1303
+ <style>
1304
+ .top-bar-search-box-container {
1305
+ height: 100%;
1306
+ overflow: hidden;
1307
+ }
1308
+ .bottom-bar {
1309
+ overflow: hidden;
1310
+ }
1311
+ .action-bar-box {
1312
+ margin: 0px;
1313
+ border: none;
1314
+ width: 50px;
1315
+ min-height: 50px;
1316
+ }
1317
+ </style>
1318
+ <div
1319
+ class="fl ${options.barClass ? options.barClass : ''}"
1320
+ style="height: ${originHeightBottomBar}px;"
1321
+ >
1322
+ ${await BtnIcon.instance({
1323
+ style: `height: 100%`,
1324
+ class: `in fl${
1325
+ options.mode === 'slide-menu-right' ? 'r' : 'l'
1326
+ } main-btn-menu action-bar-box action-btn-center ${
1327
+ options?.disableTools?.includes('center') ? 'hide' : ''
1328
+ }`,
1329
+ label: html`
1330
+ <div class="${contentIconClass}">
1331
+ <i class="far fa-square btn-bar-center-icon-square hide"></i>
1332
+ <span class="btn-bar-center-icon-close hide">${barConfig.buttons.close.label}</span>
1333
+ <span class="btn-bar-center-icon-menu">${barConfig.buttons.menu.label}</span>
1334
+ </div>
1335
+ `,
1336
+ })}
1337
+ ${await BtnIcon.instance({
1338
+ style: `height: 100%`,
1339
+ class: `in flr main-btn-menu action-bar-box action-btn-lang ${
1340
+ options?.disableTools?.includes('lang') ? 'hide' : ''
1341
+ }`,
1342
+ label: html` <div class="${contentIconClass} action-btn-lang-render"></div>`,
1343
+ })}
1344
+ ${await BtnIcon.instance({
1345
+ style: `height: 100%`,
1346
+ class: `in flr main-btn-menu action-bar-box action-btn-theme ${
1347
+ options?.disableTools?.includes('theme') ? 'hide' : ''
1348
+ }`,
1349
+ label: html` <div class="${contentIconClass} action-btn-theme-render"></div>`,
1350
+ })}
1351
+ ${await BtnIcon.instance({
1352
+ style: `height: 100%`,
1353
+ class: `in flr main-btn-menu action-bar-box action-btn-home ${
1354
+ options?.disableTools?.includes('navigator') ? 'hide' : ''
1355
+ }`,
1356
+ label: html` <div class="${contentIconClass}"><i class="fas fa-home"></i></div>`,
1357
+ })}
1358
+ ${await BtnIcon.instance({
1359
+ style: `height: 100%`,
1360
+ class: `in flr main-btn-menu action-bar-box action-btn-right ${
1361
+ options?.disableTools?.includes('navigator') ? 'hide' : ''
1362
+ }`,
1363
+ label: html` <div class="${contentIconClass}"><i class="fas fa-chevron-right"></i></div>`,
1364
+ })}
1365
+ ${await BtnIcon.instance({
1366
+ style: `height: 100%`,
1367
+ class: `in flr main-btn-menu action-bar-box action-btn-left ${
1368
+ options?.disableTools?.includes('navigator') ? 'hide' : ''
1369
+ }`,
1370
+ label: html`<div class="${contentIconClass}"><i class="fas fa-chevron-left"></i></div>`,
1371
+ })}
1372
+ </div>
1373
+ `;
1374
+ if (options.heightBottomBar === 0 && options.heightTopBar > 0) {
1375
+ append(`.slide-menu-top-bar`, html` <div class="in ${id}">${await html()}</div>`);
1376
+ } else {
1377
+ await Modal.instance({
1378
+ id,
1379
+ barConfig,
1380
+ html,
1381
+ titleClass: 'hide',
1382
+ style: {
1383
+ resize: 'none',
1384
+ height: `${options.heightBottomBar}px`,
1385
+ 'min-width': `${minWidth}px`,
1386
+ 'z-index': 7,
1387
+ // bottom: '0px !important',
1388
+ width: `${windowGetW()}px`,
1389
+ top: `${Modal.Data['modal-menu'].getTop()}px`,
1390
+ },
1391
+ dragDisabled: true,
1392
+ disableCenter: true,
1393
+ // maximize: true,
1394
+ barMode: options.barMode,
1395
+ });
1396
+ Responsive.onChanged(
1397
+ () => {
1398
+ if (!this.Data[id] || !s(`.${id}`)) return Responsive.offChanged(`view-${id}`);
1399
+ // <div class="in fll right-offset-menu-bottom-bar" style="height: 100%"></div>
1400
+ // s(`.right-offset-menu-bottom-bar`).style.width = `${windowGetW() - slideMenuWidth}px`;
1401
+ s(`.${id}`).style.top = `${Modal.Data['modal-menu'].getTop()}px`;
1402
+ s(`.${id}`).style.width = `${windowGetW()}px`;
1403
+ },
1404
+ { key: `view-${id}` },
1405
+ );
1406
+ // Responsive.Event[`view-${id}`]();
1407
+ }
1408
+ EventsUI.onClick(`.action-btn-left`, (e) => {
1409
+ e.preventDefault();
1410
+ window.history.back();
1411
+ });
1412
+ EventsUI.onClick(`.action-btn-center`, (e) => {
1413
+ e.preventDefault();
1414
+ Modal.actionBtnCenter();
1415
+ });
1416
+ EventsUI.onClick(`.action-btn-right`, (e) => {
1417
+ e.preventDefault();
1418
+ window.history.forward();
1419
+ });
1420
+ EventsUI.onClick(`.action-btn-home`, async () => {
1421
+ await Modal.onHomeRouterEvent();
1422
+ subMenuHandler(Object.keys(options.RouterInstance.Routes()));
1423
+ Object.keys(this.Data[idModal].onHome).map((keyListener) => this.Data[idModal].onHome[keyListener]());
1424
+ });
1425
+ EventsUI.onClick(`.action-btn-app-icon`, () => s(`.action-btn-home`).click());
1426
+ Keyboard.instanceMultiPressKey({
1427
+ id: 'input-shortcut-global-escape',
1428
+ keys: ['Escape'],
1429
+ eventCallBack: () => {
1430
+ if (s(`.btn-close-${this.currentTopModalId}`)) s(`.btn-close-${this.currentTopModalId}`).click();
1431
+ },
1432
+ });
1433
+ }
1434
+
1435
+ {
1436
+ ThemeEvents['action-btn-theme'] = async () => {
1437
+ htmls(
1438
+ `.action-btn-theme-render`,
1439
+ html` ${darkTheme ? html` <i class="fas fa-moon"></i>` : html`<i class="far fa-sun"></i>`}`,
1440
+ );
1441
+ if (s(`.slide-menu-top-bar-fix`)) {
1442
+ htmls(
1443
+ `.slide-menu-top-bar-fix`,
1444
+ html`<a class="a-link-top-banner fl">${await options.slideMenuTopBarBannerFix()}</a>`,
1445
+ );
1446
+ Modal.setTopBannerLink();
1447
+ }
1448
+ };
1449
+ ThemeEvents['action-btn-theme']();
1450
+
1451
+ EventsUI.onClick(`.action-btn-theme`, async () => {
1452
+ const themePair = ThemesScope.find((t) => t.theme === Css.currentTheme).themePair;
1453
+ const theme = themePair ? themePair : ThemesScope.find((t) => t.dark === !darkTheme).theme;
1454
+ if (s(`.dropdown-option-${theme}`))
1455
+ DropDown.Tokens['settings-theme'].onClickEvents[`dropdown-option-${theme}`]();
1456
+ else await Themes[theme]();
1457
+ });
1458
+ if (!(ThemesScope.find((t) => t.dark) && ThemesScope.find((t) => !t.dark))) {
1459
+ s(`.action-btn-theme`).classList.add('hide');
1460
+ }
1461
+ }
1462
+
1463
+ {
1464
+ htmls(`.action-btn-lang-render`, html` ${s('html').lang}`);
1465
+ // old method
1466
+ // EventsUI.onClick(`.action-btn-lang`, () => {
1467
+ // let lang = 'en';
1468
+ // if (s('html').lang === 'en') lang = 'es';
1469
+ // if (s(`.dropdown-option-${lang}`))
1470
+ // DropDown.Tokens['settings-lang'].onClickEvents[`dropdown-option-${lang}`]();
1471
+ // else Translate.renderLang(lang);
1472
+ // });
1473
+
1474
+ // Open lightweight empty modal on language button, with shared dismiss logic
1475
+ EventsUI.onClick(
1476
+ `.action-btn-lang`,
1477
+ async () => {
1478
+ const id = 'action-btn-lang-modal';
1479
+ if (s(`.${id}`)) {
1480
+ return s(`.btn-close-${id}`).click();
1481
+ }
1482
+ const { barConfig } = await Themes[Css.currentTheme]();
1483
+ barConfig.buttons.maximize.disabled = true;
1484
+ barConfig.buttons.minimize.disabled = true;
1485
+ barConfig.buttons.restore.disabled = true;
1486
+ barConfig.buttons.menu.disabled = true;
1487
+ barConfig.buttons.close.disabled = false;
1488
+ await Modal.instance({
1489
+ id,
1490
+ barConfig,
1491
+ title: html`${renderViewTitle({
1492
+ icon: html`<i class="fas fa-language mini-title"></i>`,
1493
+ text: Translate.instance('select lang'),
1494
+ })}`,
1495
+ html: async () => html`${await Translate.RenderSetting('action-drop-modal' + id)}`,
1496
+ titleClass: 'mini-title',
1497
+ style: {
1498
+ resize: 'none',
1499
+ width: '100% !important',
1500
+ height: '350px !important',
1501
+ 'max-width': '350px !important',
1502
+ 'z-index': 7,
1503
+ },
1504
+ dragDisabled: true,
1505
+ maximize: true,
1506
+ barMode: options.barMode,
1507
+ });
1508
+
1509
+ // Move title inside the bar container to align with control buttons
1510
+ Modal.MoveTitleToBar(id);
1511
+
1512
+ // Position the language selection modal relative to the language button
1513
+ Modal.positionRelativeToAnchor({
1514
+ modalSelector: `.${id}`,
1515
+ anchorSelector: '.action-btn-lang',
1516
+ align: 'right',
1517
+ offset: { x: 0, y: 6 },
1518
+ autoVertical: true,
1519
+ });
1520
+
1521
+ // Hover/focus controller uses the button as input anchor
1522
+ const hoverFocusCtl = EventsUI.HoverFocusController({
1523
+ inputSelector: `.action-btn-lang`,
1524
+ panelSelector: `.${id}`,
1525
+ onDismiss: () => Modal.removeModal(id),
1526
+ });
1527
+ hoverFocusCtl.bind();
1528
+ const unbindDoc = EventsUI.bindDismissOnDocumentClick({
1529
+ shouldStay: hoverFocusCtl.shouldStay,
1530
+ onDismiss: () => Modal.removeModal(id),
1531
+ anchors: [`.action-btn-lang`, `.${id}`],
1532
+ });
1533
+ Modal.Data[id].onCloseListener[`unbind-doc-${id}`] = () => unbindDoc();
1534
+ },
1535
+ { context: 'modal', noGate: true, noLoading: true },
1536
+ );
1537
+ }
1538
+
1539
+ {
1540
+ const { barConfig } = await Themes[Css.currentTheme]();
1541
+ barConfig.buttons.maximize.disabled = true;
1542
+ barConfig.buttons.minimize.disabled = true;
1543
+ barConfig.buttons.restore.disabled = true;
1544
+ barConfig.buttons.menu.disabled = true;
1545
+ barConfig.buttons.close.disabled = true;
1546
+ const id = 'main-body-top';
1547
+ await Modal.instance({
1548
+ id,
1549
+ barConfig,
1550
+ html: () => html``,
1551
+ titleClass: 'hide',
1552
+ class: 'hide',
1553
+ style: {
1554
+ // overflow: 'hidden',
1555
+ resize: 'none',
1556
+ 'min-width': `${minWidth}px`,
1557
+ 'z-index': 5,
1558
+ background: `rgba(61, 61, 61, 0.5)`,
1559
+ // border: '3px solid red',
1560
+ },
1561
+ dragDisabled: true,
1562
+ maximize: true,
1563
+ barMode: options.barMode,
1564
+ });
1565
+
1566
+ Responsive.onChanged(
1567
+ () => {
1568
+ if (!this.Data[id] || !s(`.${id}`)) return Responsive.offChanged(`view-${id}`);
1569
+ s(`.${id}`).style.height =
1570
+ s(`.main-body-btn-ui-close`).classList.contains('hide') &&
1571
+ s(`.btn-restore-${id}`).style.display !== 'none'
1572
+ ? `${windowGetH()}px`
1573
+ : `${Modal.Data[id].getHeight()}px`;
1574
+
1575
+ if (
1576
+ s(`.main-body-btn-ui-close`).classList.contains('hide') &&
1577
+ s(`.btn-restore-${id}`).style.display !== 'none'
1578
+ ) {
1579
+ s(`.${id}`).style.top = '0px';
1580
+ } else {
1581
+ s(`.${id}`).style.top = `${options.heightTopBar ? options.heightTopBar : heightDefaultTopBar}px`;
1582
+ }
1583
+ },
1584
+ { key: `view-${id}` },
1585
+ );
1586
+ Responsive.triggerChanged(`view-${id}`);
1587
+
1588
+ s(`.main-body-top`).onclick = () => s(`.btn-close-modal-menu`).click();
1589
+ }
1590
+
1591
+ await NotificationManager.RenderBoard(options);
1592
+
1593
+ const { removeEvent } = Scroll.setEvent('.main-body', async (payload) => {
1594
+ // console.warn('scroll', payload);
1595
+ if (payload.scrollTop > 100) {
1596
+ if (!s(`.main-body-btn-ui-close`).classList.contains('hide')) s(`.main-body-btn-ui-close`).click();
1597
+
1598
+ removeEvent();
1599
+ }
1600
+ });
1601
+ setTimeout(window.onresize);
1602
+ setRouterReady();
1603
+ });
1604
+ })();
1605
+ break;
1606
+
1607
+ case 'dropNotification':
1608
+ (() => {
1609
+ setTimeout(() => {
1610
+ s(`.${idModal}`).style.top = 'auto';
1611
+ s(`.${idModal}`).style.left = 'auto';
1612
+ s(`.${idModal}`).style.height = 'auto';
1613
+ s(`.${idModal}`).style.position = 'absolute';
1614
+ let countDrop = 0;
1615
+ Object.keys(this.Data)
1616
+ .reverse()
1617
+ .map((_idModal) => {
1618
+ if (this.Data[_idModal][options.mode]) {
1619
+ s(`.${_idModal}`).style.bottom = `${countDrop * s(`.${_idModal}`).clientHeight * 1.05}px`;
1620
+ countDrop++;
1621
+ }
1622
+ });
1623
+ });
1624
+ })();
1625
+ break;
1626
+
1627
+ default:
1628
+ break;
1629
+ }
1630
+ }
1631
+
1632
+ if (options.zIndexSync) this.zIndexSync({ idModal });
1633
+
1634
+ if (s(`.${idModal}`)) {
1635
+ for (const event of Object.keys(Modal.Data[idModal].onReloadModalListener))
1636
+ await Modal.Data[idModal].onReloadModalListener[event]();
1637
+
1638
+ s(`.btn-maximize-${idModal}`).click();
1639
+ return;
1640
+ }
1641
+
1642
+ if (idModal !== 'main-body' && options.mode !== 'view' && !options.disableCenter) Modal.Data[idModal].center();
1643
+
1644
+ const render = html` <style class="style-${idModal}">
1645
+ .${idModal} {
1646
+ width: ${width}px;
1647
+ height: ${height}px;
1648
+ top: ${top};
1649
+ left: ${left};
1650
+ overflow: auto; /* resizable required */
1651
+ resize: both; /* resizable required */
1652
+ transition: ${transition};
1653
+ opacity: 0;
1654
+ z-index: 1;
1655
+ }
1656
+ .bar-default-modal-${idModal} {
1657
+ top: 0px;
1658
+ left: 0px;
1659
+ z-index: 3;
1660
+ }
1661
+
1662
+ .modal-html-${idModal} {
1663
+ }
1664
+
1665
+ .btn-modal-default-${idModal} {
1666
+ }
1667
+ .modal-handle-${idModal} {
1668
+ width: 90%;
1669
+ height: 90%;
1670
+ top: 5%;
1671
+ left: 5%;
1672
+ }
1673
+ .sub-menu-title-container-${idModal},
1674
+ .nav-path-container-${idModal} {
1675
+ top: 0px;
1676
+ left: 0px;
1677
+ width: 200px;
1678
+ height: 50px;
1679
+ overflow: hidden;
1680
+ font-size: 20px;
1681
+ cursor: default;
1682
+ }
1683
+ .nav-path-display-${idModal} {
1684
+ font-size: 11px;
1685
+ width: 100%;
1686
+ top: 35px;
1687
+ left: 37px;
1688
+ }
1689
+ .nav-title-display-${idModal} {
1690
+ font-size: 19px;
1691
+ width: 100%;
1692
+ top: 13px;
1693
+ left: 13px;
1694
+ }
1695
+ </style>
1696
+ ${renderStyleTag(`style-${idModal}`, `.${idModal}`, options)}
1697
+ <div
1698
+ class="fix ${options && options.class ? options.class : ''} modal ${options.disableBoxShadow
1699
+ ? ''
1700
+ : 'box-shadow'} ${idModal === 'main-body' ? `${idModal} modal-home` : idModal}"
1701
+ >
1702
+ <div class="abs modal-handle-${idModal}"></div>
1703
+ <div class="in modal-html-${idModal}">
1704
+ <div class="stq bar-default-modal bar-default-modal-${idModal}">
1705
+ <div
1706
+ class="fl btn-bar-modal-container btn-bar-modal-container-${idModal} ${options?.btnBarModalClass
1707
+ ? options.btnBarModalClass
1708
+ : ''}"
1709
+ >
1710
+ <div class="btn-bar-modal-container-render-${idModal}"></div>
1711
+ <div class="in flr bar-default-modal" style="z-index: 1">
1712
+ ${await BtnIcon.instance({
1713
+ class: `btn-minimize-${idModal} btn-modal-default btn-modal-default-${idModal} ${
1714
+ options?.btnContainerClass ? options.btnContainerClass : ''
1715
+ } ${options?.barConfig?.buttons?.minimize?.disabled ? 'hide' : ''}`,
1716
+ label: html`<div class="${options?.btnIconContainerClass ? options.btnIconContainerClass : ''}">
1717
+ ${options?.barConfig?.buttons?.minimize?.label ? options.barConfig.buttons.minimize.label : html`_`}
1718
+ </div>`,
1719
+ })}
1720
+ ${await BtnIcon.instance({
1721
+ class: `btn-restore-${idModal} btn-modal-default btn-modal-default-${idModal} ${
1722
+ options?.btnContainerClass ? options.btnContainerClass : ''
1723
+ } ${options?.barConfig?.buttons?.restore?.disabled ? 'hide' : ''}`,
1724
+ label: html`<div class="${options?.btnIconContainerClass ? options.btnIconContainerClass : ''}">
1725
+ ${options?.barConfig?.buttons?.restore?.label ? options.barConfig.buttons.restore.label : html`□`}
1726
+ </div>`,
1727
+ style: 'display: none',
1728
+ })}
1729
+ ${await BtnIcon.instance({
1730
+ class: `btn-maximize-${idModal} btn-modal-default btn-modal-default-${idModal} ${
1731
+ options?.btnContainerClass ? options.btnContainerClass : ''
1732
+ } ${options?.barConfig?.buttons?.maximize?.disabled ? 'hide' : ''}`,
1733
+ label: html`<div class="${options?.btnIconContainerClass ? options.btnIconContainerClass : ''}">
1734
+ ${options?.barConfig?.buttons?.maximize?.label ? options.barConfig.buttons.maximize.label : html`▢`}
1735
+ </div>`,
1736
+ })}
1737
+ ${await BtnIcon.instance({
1738
+ class: `btn-close-${idModal} btn-modal-default btn-modal-default-${idModal} ${
1739
+ options?.btnContainerClass ? options.btnContainerClass : ''
1740
+ } ${options?.barConfig?.buttons?.close?.disabled ? 'hide' : ''}`,
1741
+ label: html`<div class="${options?.btnIconContainerClass ? options.btnIconContainerClass : ''}">
1742
+ ${options?.barConfig?.buttons?.close?.label ? options.barConfig.buttons.close.label : html`X`}
1743
+ </div>`,
1744
+ })}
1745
+ ${await BtnIcon.instance({
1746
+ class: `btn-menu-${idModal} btn-modal-default btn-modal-default-${idModal} ${
1747
+ options?.btnContainerClass ? options.btnContainerClass : ''
1748
+ } ${options?.barConfig?.buttons?.menu?.disabled ? 'hide' : ''}`,
1749
+ label: html`<div class="${options?.btnIconContainerClass ? options.btnIconContainerClass : ''}">
1750
+ ${options?.barConfig?.buttons?.menu?.label ? options.barConfig.buttons.menu.label : html`≡`}
1751
+ </div>`,
1752
+ })}
1753
+ </div>
1754
+ </div>
1755
+ ${options && options.status
1756
+ ? html` <div class="abs modal-icon-container">${renderStatus(options.status)}</div> `
1757
+ : ''}
1758
+ <div
1759
+ class="inl title-modal-${idModal} ${options && options.titleClass
1760
+ ? options.titleClass
1761
+ : 'title-main-modal'}"
1762
+ >
1763
+ ${options && options.titleRender ? options.titleRender() : options.title ? options.title : ''}
1764
+ </div>
1765
+ </div>
1766
+
1767
+ <div class="in html-${idModal}">
1768
+ ${options.mode && options.mode.match('slide-menu')
1769
+ ? html`<div
1770
+ class="stq modal"
1771
+ style="${renderCssAttr({ style: { height: '50px', 'z-index': 1, top: '0px' } })}"
1772
+ >
1773
+ ${await BtnIcon.instance({
1774
+ style: renderCssAttr({ style: { height: '100%', color: '#5f5f5f' } }),
1775
+ class: `in flr main-btn-menu action-bar-box btn-icon-menu-mode`,
1776
+ label: html` <div class="abs center">
1777
+ <i
1778
+ class="fas fa-caret-right btn-icon-menu-mode-right ${options.mode && options.mode.match('right')
1779
+ ? ''
1780
+ : 'hide'}"
1781
+ ></i
1782
+ ><i
1783
+ class="fas fa-caret-left btn-icon-menu-mode-left ${options.mode && options.mode.match('right')
1784
+ ? 'hide'
1785
+ : ''}"
1786
+ ></i>
1787
+ </div>`,
1788
+ })}
1789
+ ${await BtnIcon.instance({
1790
+ style: renderCssAttr({ style: { height: '100%', color: '#5f5f5f' } }),
1791
+ class: `in flr main-btn-menu action-bar-box btn-icon-menu-back hide`,
1792
+ label: html`<div class="abs center"><i class="fas fa-undo-alt"></i></div>`,
1793
+ })}
1794
+ <div class="abs sub-menu-title-container-${idModal} ac">
1795
+ <div class="abs nav-title-display-${idModal}">
1796
+ <!-- <i class="fas fa-home"></i> ${Translate.instance('home')} -->
1797
+ </div>
1798
+ </div>
1799
+ <div class="abs nav-path-container-${idModal} ahc bold">
1800
+ <div class="abs nav-path-display-${idModal}"><!-- ${location.pathname} --></div>
1801
+ </div>
1802
+ </div>`
1803
+ : ''}
1804
+ ${options && options.html ? (typeof options.html === 'function' ? await options.html() : options.html) : ''}
1805
+ </div>
1806
+ </div>
1807
+ </div>`;
1808
+ const selector = options && options.selector ? options.selector : 'body';
1809
+ if (options) {
1810
+ switch (options.renderType) {
1811
+ case 'prepend':
1812
+ prepend(selector, render);
1813
+ break;
1814
+ default:
1815
+ append(selector, render);
1816
+ break;
1817
+ }
1818
+ } else append(selector, render);
1819
+ let handle = [s(`.bar-default-modal-${idModal}`), s(`.modal-handle-${idModal}`), s(`.modal-html-${idModal}`)];
1820
+ if (options && 'handleType' in options) {
1821
+ switch (options.handleType) {
1822
+ case 'bar':
1823
+ handle = [s(`.bar-default-modal-${idModal}`)];
1824
+
1825
+ break;
1826
+
1827
+ default:
1828
+ break;
1829
+ }
1830
+ }
1831
+ switch (options.mode) {
1832
+ case 'slide-menu':
1833
+ case 'slide-menu-right':
1834
+ case 'slide-menu-left':
1835
+ const backMenuButtonEvent = async () => {
1836
+ // htmls(`.nav-title-display-${'modal-menu'}`, html`<i class="fas fa-home"></i> ${Translate.instance('home')}`);
1837
+ htmls(`.nav-title-display-${'modal-menu'}`, html``);
1838
+ htmls(`.nav-path-display-${idModal}`, '');
1839
+ s(`.btn-icon-menu-back`).classList.add('hide');
1840
+ // sa(`.main-btn-menu`).forEach((el) => {
1841
+ // el.classList.remove('hide');
1842
+ // });
1843
+ };
1844
+ s(`.main-btn-home`).onclick = async () => {
1845
+ // await this.onHomeRouterEvent();
1846
+ s(`.action-btn-home`).click();
1847
+ };
1848
+ EventsUI.onClick(`.btn-icon-menu-back`, backMenuButtonEvent);
1849
+ EventsUI.onClick(`.btn-icon-menu-mode`, () => {
1850
+ if (s(`.btn-icon-menu-mode-right`).classList.contains('hide')) {
1851
+ s(`.btn-icon-menu-mode-right`).classList.remove('hide');
1852
+ s(`.btn-icon-menu-mode-left`).classList.add('hide');
1853
+ } else {
1854
+ s(`.btn-icon-menu-mode-left`).classList.remove('hide');
1855
+ s(`.btn-icon-menu-mode-right`).classList.add('hide');
1856
+ }
1857
+ if (slideMenuWidth === originSlideMenuWidth) {
1858
+ slideMenuWidth = collapseSlideMenuWidth;
1859
+ s(`.${idModal}`).style.width = `${slideMenuWidth}px`;
1860
+ sa(`.menu-label-text`).forEach((el) => el.classList.add('hide'));
1861
+ s(`.main-body-btn-container`).style[
1862
+ true || (options.mode && options.mode.match('right')) ? 'right' : 'left'
1863
+ ] = options.mode && options.mode.match('right') ? `${slideMenuWidth}px` : '0px';
1864
+ sa(`.handle-btn-container`).forEach((el) => el.classList.add('hide'));
1865
+ if (options.onCollapseMenu) options.onCollapseMenu();
1866
+ s(`.sub-menu-title-container-${'modal-menu'}`).classList.add('hide');
1867
+ s(`.nav-path-container-${'modal-menu'}`).classList.add('hide');
1868
+ // Shrink any already-open submenu containers to icon-only width
1869
+ Object.keys(Modal.subMenuBtnClass).forEach((subMenuId) => {
1870
+ const container = s(`.menu-btn-container-children-${subMenuId}`);
1871
+ if (container && container.style.height && container.style.height !== '0px')
1872
+ container.style.width = `${collapseSlideMenuWidth}px`;
1873
+ });
1874
+ Object.keys(this.Data[idModal].onCollapseMenuListener).map((keyListener) =>
1875
+ this.Data[idModal].onCollapseMenuListener[keyListener](),
1876
+ );
1877
+ } else {
1878
+ slideMenuWidth = originSlideMenuWidth;
1879
+ s(`.${idModal}`).style.width = `${slideMenuWidth}px`;
1880
+ sa(`.menu-label-text`).forEach((el) => el.classList.remove('hide'));
1881
+ s(`.main-body-btn-container`).style[
1882
+ true || (options.mode && options.mode.match('right')) ? 'right' : 'left'
1883
+ ] = options.mode && options.mode.match('right') ? `${slideMenuWidth}px` : '0px';
1884
+ sa(`.handle-btn-container`).forEach((el) => el.classList.remove('hide'));
1885
+
1886
+ Modal.menuTextLabelAnimation(idModal);
1887
+
1888
+ if (options.onExtendMenu) options.onExtendMenu();
1889
+ s(`.sub-menu-title-container-${'modal-menu'}`).classList.remove('hide');
1890
+ s(`.nav-path-container-${'modal-menu'}`).classList.remove('hide');
1891
+ // Expand any already-open submenu containers back to full width
1892
+ Object.keys(Modal.subMenuBtnClass).forEach((subMenuId) => {
1893
+ const container = s(`.menu-btn-container-children-${subMenuId}`);
1894
+ if (container && container.style.height && container.style.height !== '0px')
1895
+ container.style.width = `${originSlideMenuWidth}px`;
1896
+ });
1897
+ Object.keys(this.Data[idModal].onExtendMenuListener).map((keyListener) =>
1898
+ this.Data[idModal].onExtendMenuListener[keyListener](),
1899
+ );
1900
+ }
1901
+ Modal.Data[idModal][options.mode].width = slideMenuWidth;
1902
+ Responsive.triggerChanged(`slide-menu-${idModal}`);
1903
+ });
1904
+
1905
+ break;
1906
+
1907
+ default:
1908
+ break;
1909
+ }
1910
+ // Track drag position for consistency
1911
+ let dragPosition = { x: 0, y: 0 };
1912
+
1913
+ // Initialize drag options with proper bounds and smooth transitions
1914
+ let dragOptions = {
1915
+ handle: handle,
1916
+ bounds: {
1917
+ top: 0,
1918
+ left: 0,
1919
+ right: 0,
1920
+ bottom: 0,
1921
+ },
1922
+ preventDefault: true,
1923
+ position: { x: 0, y: 0 },
1924
+ onDragStart: () => {
1925
+ const modal = s(`.${idModal}`);
1926
+ if (!modal) return false; // Prevent drag if modal not found
1927
+
1928
+ // Store current position
1929
+ const computedStyle = window.getComputedStyle(modal);
1930
+ const matrix = new DOMMatrixReadOnly(computedStyle.transform);
1931
+ dragPosition = {
1932
+ x: matrix.m41 || 0,
1933
+ y: matrix.m42 || 0,
1934
+ };
1935
+
1936
+ modal.style.transition = 'none';
1937
+ modal.style.willChange = 'transform';
1938
+ return true; // Allow drag to start
1939
+ },
1940
+ onDrag: (data) => {
1941
+ // Update position based on drag delta
1942
+ dragPosition = { x: data.x, y: data.y };
1943
+ },
1944
+ onDragEnd: () => {
1945
+ const modal = s(`.${idModal}`);
1946
+ if (!modal) return;
1947
+
1948
+ modal.style.willChange = '';
1949
+ modal.style.transition = transition;
1950
+
1951
+ // Update drag instance with current position
1952
+ if (dragInstance) {
1953
+ dragInstance.updateOptions({
1954
+ position: dragPosition,
1955
+ });
1956
+ }
1957
+
1958
+ // Notify listeners
1959
+ Object.keys(this.Data[idModal].onDragEndListener || {}).forEach((keyListener) => {
1960
+ this.Data[idModal].onDragEndListener[keyListener]?.();
1961
+ });
1962
+ },
1963
+ };
1964
+
1965
+ let dragInstance = null;
1966
+
1967
+ // Initialize or update drag instance
1968
+ const setDragInstance = () => {
1969
+ if (options?.dragDisabled) {
1970
+ if (dragInstance) {
1971
+ dragInstance.destroy();
1972
+ dragInstance = null;
1973
+ }
1974
+ return null;
1975
+ }
1976
+
1977
+ const modal = s(`.${idModal}`);
1978
+ if (!modal) {
1979
+ console.warn(`Modal element .${idModal} not found for drag initialization`);
1980
+ return null;
1981
+ }
1982
+
1983
+ // Ensure the modal has position: absolute for proper dragging
1984
+ if (window.getComputedStyle(modal).position !== 'absolute') {
1985
+ modal.style.position = 'absolute';
1986
+ }
1987
+
1988
+ // Clean up existing instance
1989
+ if (dragInstance) {
1990
+ dragInstance.destroy();
1991
+ }
1992
+
1993
+ try {
1994
+ // Create new instance with updated options
1995
+ dragInstance = new Draggable(modal, dragOptions);
1996
+ return dragInstance;
1997
+ } catch (error) {
1998
+ console.error('Failed to initialize draggable:', error);
1999
+ return null;
2000
+ }
2001
+ };
2002
+
2003
+ // Expose method to update drag options
2004
+ this.Data[idModal].setDragInstance = (updateDragOptions) => {
2005
+ if (updateDragOptions) {
2006
+ dragOptions = { ...dragOptions, ...updateDragOptions };
2007
+ }
2008
+ dragInstance = setDragInstance();
2009
+ this.Data[idModal].dragInstance = dragInstance;
2010
+ this.Data[idModal].dragOptions = dragOptions;
2011
+ };
2012
+ // Initialize modal with proper transitions
2013
+ const modal = s(`.${idModal}`);
2014
+ if (modal) {
2015
+ // Initial state
2016
+ modal.style.transition = 'opacity 0.15s ease, transform 0.3s ease';
2017
+ modal.style.opacity = '0';
2018
+
2019
+ // Trigger fade-in after a small delay to allow initial render
2020
+ requestAnimationFrame(() => {
2021
+ if (!modal) return;
2022
+ modal.style.opacity = '1';
2023
+
2024
+ // Set final transition after initial animation completes
2025
+ setTimeout(() => {
2026
+ if (modal) {
2027
+ modal.style.transition = transition;
2028
+
2029
+ // Initialize drag after transitions are set
2030
+ if (!options.dragDisabled) {
2031
+ setDragInstance();
2032
+ if (!options.mode) {
2033
+ dragInstance.updateOptions({
2034
+ position: { x: 0, y: 0 },
2035
+ disabled: false, // Ensure drag is enabled after restore
2036
+ });
2037
+ }
2038
+ }
2039
+ }
2040
+ }, 150);
2041
+ });
2042
+ }
2043
+
2044
+ const btnCloseEvent = () => {
2045
+ Object.keys(this.Data[idModal].onCloseListener).map((keyListener) =>
2046
+ this.Data[idModal].onCloseListener[keyListener](),
2047
+ );
2048
+ if (options && 'barConfig' in options && options.barConfig.buttons.close.onClick)
2049
+ return options.barConfig.buttons.close.onClick();
2050
+ s(`.${idModal}`).style.opacity = '0';
2051
+ if (this.Data[idModal].observer) {
2052
+ this.Data[idModal].observer.disconnect();
2053
+ // this.Data[idModal].observer.unobserve();
2054
+ }
2055
+ setTimeout(() => {
2056
+ if (!s(`.${idModal}`)) return;
2057
+ this.removeModal(idModal);
2058
+ // Handle modal route change
2059
+ closeModalRouteChangeEvent({ closedId: idModal });
2060
+ // history.back();
2061
+ }, 300);
2062
+ };
2063
+ s(`.btn-close-${idModal}`).onclick = btnCloseEvent;
2064
+
2065
+ // Minimize button handler
2066
+ s(`.btn-minimize-${idModal}`).onclick = () => {
2067
+ const modal = s(`.${idModal}`);
2068
+ if (!modal) return;
2069
+
2070
+ if (options.slideMenu) {
2071
+ delete this.Data[idModal].slideMenu;
2072
+ }
2073
+
2074
+ // Keep drag enabled when minimized
2075
+ if (dragInstance) {
2076
+ dragInstance.updateOptions({ disabled: false });
2077
+ }
2078
+
2079
+ // Set up transition
2080
+ modal.style.transition = 'height 0.3s ease, transform 0.3s ease';
2081
+
2082
+ // Update button states
2083
+ s(`.btn-minimize-${idModal}`).style.display = 'none';
2084
+ s(`.btn-maximize-${idModal}`).style.display = null;
2085
+ s(`.btn-restore-${idModal}`).style.display = null;
2086
+
2087
+ // Collapse to header height
2088
+ const header = s(`.bar-default-modal-${idModal}`);
2089
+ if (header) {
2090
+ modal.style.height = `${header.clientHeight}px`;
2091
+ modal.style.overflow = 'hidden';
2092
+ }
2093
+
2094
+ // Restore transition after animation
2095
+ setTimeout(() => {
2096
+ if (modal) {
2097
+ modal.style.transition = transition;
2098
+ }
2099
+ }, 300);
2100
+ };
2101
+ // Restore button handler
2102
+ s(`.btn-restore-${idModal}`).onclick = () => {
2103
+ const modal = s(`.${idModal}`);
2104
+ if (!modal) return;
2105
+
2106
+ if (options.slideMenu) {
2107
+ delete this.Data[idModal].slideMenu;
2108
+ }
2109
+
2110
+ // Re-enable dragging
2111
+ if (dragInstance) {
2112
+ dragInstance.updateOptions({ disabled: false });
2113
+ }
2114
+
2115
+ // Set up transition
2116
+ modal.style.transition = 'all 0.3s ease';
2117
+
2118
+ // Update button states
2119
+ s(`.btn-restore-${idModal}`).style.display = 'none';
2120
+ s(`.btn-minimize-${idModal}`).style.display = null;
2121
+ s(`.btn-maximize-${idModal}`).style.display = null;
2122
+
2123
+ // Restore original dimensions and position
2124
+ this.Data[idModal].center();
2125
+ modal.style.transform = '';
2126
+ modal.style.height = `${height}px`;
2127
+ modal.style.left = left;
2128
+ modal.style.top = top;
2129
+ modal.style.width = `${width}px`;
2130
+ modal.style.overflow = '';
2131
+
2132
+ // Re-enable drag after restore
2133
+ if (dragInstance) {
2134
+ dragInstance.updateOptions({
2135
+ position: { x: 0, y: 0 },
2136
+ disabled: false, // Ensure drag is enabled after restore
2137
+ });
2138
+ }
2139
+ setTimeout(() => (s(`.${idModal}`) ? (s(`.${idModal}`).style.transition = transition) : null), 300);
2140
+ };
2141
+ s(`.btn-maximize-${idModal}`).onclick = () => {
2142
+ const modal = s(`.${idModal}`);
2143
+ if (!modal) return;
2144
+
2145
+ // Disable drag when maximizing
2146
+ if (dragInstance) {
2147
+ dragInstance.updateOptions({ disabled: true });
2148
+ }
2149
+
2150
+ modal.style.transition = '0.3s';
2151
+ setTimeout(() => (modal ? (modal.style.transition = transition) : null), 300);
2152
+
2153
+ s(`.btn-maximize-${idModal}`).style.display = 'none';
2154
+ s(`.btn-restore-${idModal}`).style.display = null;
2155
+ s(`.btn-minimize-${idModal}`).style.display = null;
2156
+ modal.style.transform = null;
2157
+
2158
+ if (options.slideMenu) {
2159
+ const idSlide = this.Data[options.slideMenu]['slide-menu']
2160
+ ? 'slide-menu'
2161
+ : this.Data[options.slideMenu]['slide-menu-right']
2162
+ ? 'slide-menu-right'
2163
+ : 'slide-menu-left';
2164
+ const callBack = () => {
2165
+ s(`.${idModal}`).style.transition = '0.3s';
2166
+ s(`.${idModal}`).style.width = `${windowGetW() - this.Data[options.slideMenu][idSlide].width}px`;
2167
+ s(`.${idModal}`).style.left =
2168
+ idSlide === 'slide-menu-right' ? `0px` : `${this.Data[options.slideMenu][idSlide].width}px`;
2169
+ setTimeout(() => (s(`.${idModal}`) ? (s(`.${idModal}`).style.transition = transition) : null), 300);
2170
+ };
2171
+
2172
+ callBack();
2173
+ this.Data[idModal].slideMenu = {
2174
+ callBack,
2175
+ id: options.slideMenu,
2176
+ };
2177
+ Responsive.onChanged(
2178
+ () => {
2179
+ setTimeout(() => {
2180
+ if (!s(`.${idModal}`) || !s(`.main-body-btn-ui-close`)) return;
2181
+ if (s(`.btn-restore-${idModal}`) && s(`.btn-restore-${idModal}`).style.display !== 'none') {
2182
+ s(`.${idModal}`).style.height = s(`.main-body-btn-ui-close`).classList.contains('hide')
2183
+ ? `${windowGetH()}px`
2184
+ : `${Modal.Data[idModal].getHeight()}px`;
2185
+ }
2186
+ s(`.${idModal}`).style.top = s(`.main-body-btn-ui-close`).classList.contains('hide')
2187
+ ? `0px`
2188
+ : `${options.heightTopBar ? options.heightTopBar : heightDefaultTopBar}px`;
2189
+ });
2190
+ },
2191
+ { key: 'h-ui-hide-' + idModal },
2192
+ );
2193
+ Responsive.triggerChanged('h-ui-hide-' + idModal);
2194
+ } else {
2195
+ Responsive.offChanged('h-ui-hide-' + idModal);
2196
+ s(`.${idModal}`).style.width = '100%';
2197
+ s(`.${idModal}`).style.height = '100%';
2198
+ s(`.${idModal}`).style.top = `${options.heightTopBar ? options.heightTopBar : heightDefaultTopBar}px`;
2199
+ s(`.${idModal}`).style.left = `0px`;
2200
+ }
2201
+ dragInstance = setDragInstance();
2202
+ };
2203
+
2204
+ const btnMenuEvent = () => {
2205
+ Modal.menuTextLabelAnimation(idModal);
2206
+ Object.keys(this.Data[idModal].onMenuListener).map((keyListener) =>
2207
+ this.Data[idModal].onMenuListener[keyListener](),
2208
+ );
2209
+ if (options && 'barConfig' in options && options.barConfig.buttons.menu.onClick)
2210
+ options.barConfig.buttons.menu.onClick();
2211
+ };
2212
+ s(`.btn-menu-${idModal}`).onclick = btnMenuEvent;
2213
+
2214
+ dragInstance = setDragInstance();
2215
+ if (options && options.maximize) s(`.btn-maximize-${idModal}`).click();
2216
+ if (options.observer) {
2217
+ this.Data[idModal].observerCallBack = () => {
2218
+ // logger.info('ResizeObserver', `.${idModal}`, s(`.${idModal}`).offsetWidth, s(`.${idModal}`).offsetHeight);
2219
+ if (this.Data[idModal] && this.Data[idModal].onObserverListener)
2220
+ Object.keys(this.Data[idModal].onObserverListener).map((eventKey) =>
2221
+ this.Data[idModal].onObserverListener[eventKey]({
2222
+ width: s(`.${idModal}`).offsetWidth,
2223
+ height: s(`.${idModal}`).offsetHeight,
2224
+ }),
2225
+ );
2226
+ else console.warn('observer not found', idModal);
2227
+ };
2228
+ this.Data[idModal].observer = new ResizeObserver(this.Data[idModal].observerCallBack);
2229
+ this.Data[idModal].observer.observe(s(`.${idModal}`));
2230
+ setTimeout(this.Data[idModal].observerCallBack);
2231
+ }
2232
+ // cancel: [cancel1, cancel2]
2233
+ s(`.${idModal}`).onclick = () => {
2234
+ this.Data[idModal]?.onClickListener
2235
+ ? Object.keys(this.Data[idModal].onClickListener).map((keyListener) =>
2236
+ this.Data[idModal].onClickListener[keyListener](),
2237
+ )
2238
+ : null;
2239
+ };
2240
+ return {
2241
+ id: idModal,
2242
+ ...this.Data[idModal],
2243
+ };
2244
+ }
2245
+
2246
+ /** @type {Object.<string, object>} */
2247
+ static subMenuBtnClass = {};
2248
+
2249
+ /** Navigate to the home route and close all non-home modals. */
2250
+ static onHomeRouterEvent = async () => {
2251
+ // 1. Get list of modals to close.
2252
+ const modalsToClose = Object.keys(Modal.Data).filter((idModal) => {
2253
+ const modal = Modal.Data[idModal];
2254
+ if (!modal) return false;
2255
+ // Don't close the core UI elements
2256
+
2257
+ if (coreUI.find((id) => idModal.startsWith(id))) {
2258
+ return false;
2259
+ }
2260
+ // Don't close modals that are part of the "home" screen itself
2261
+ const homeModals = Modal.Data['modal-menu']?.homeModals || [];
2262
+ if (homeModals.includes(idModal)) {
2263
+ return false;
2264
+ }
2265
+ return true;
2266
+ });
2267
+
2268
+ // 2. Navigate to home first, creating a new history entry.
2269
+ setPath(`${getProxyPath()}${location.search ?? ''}${location.hash ?? ''}`);
2270
+ setDocTitle();
2271
+
2272
+ // 3. Close the modals without them affecting the URL.
2273
+ for (const id of modalsToClose) {
2274
+ Modal.removeModal(id);
2275
+ }
2276
+
2277
+ // 4. Finally, handle UI cleanup for the slide-menu.
2278
+
2279
+ if (s(`.nav-title-display-modal-menu`)) htmls(`.nav-title-display-modal-menu`, '');
2280
+ if (s(`.nav-path-display-modal-menu`)) htmls(`.nav-path-display-modal-menu`, '');
2281
+ if (s(`.btn-icon-menu-back`)) s(`.btn-icon-menu-back`).classList.add('hide');
2282
+ // sa(`.main-btn-menu`).forEach((el) => {
2283
+ // el.classList.remove('hide');
2284
+ // });
2285
+
2286
+ // And close the slide menu if it's open
2287
+ if (s(`.btn-close-modal-menu`) && !s(`.btn-close-modal-menu`).classList.contains('hide')) {
2288
+ s(`.btn-close-modal-menu`).click();
2289
+ }
2290
+ };
2291
+
2292
+ /** @type {string} */
2293
+ static currentTopModalId = '';
2294
+
2295
+ /**
2296
+ * Synchronise z-index for view modals, promoting the given modal to top.
2297
+ * @param {{ idModal: string }} param0
2298
+ */
2299
+ static zIndexSync({ idModal }) {
2300
+ setTimeout(() => {
2301
+ if (!this.Data[idModal]) return;
2302
+ const cleanTopModal = () => {
2303
+ Object.keys(this.Data).map((_idModal) => {
2304
+ if (this.Data[_idModal].options.zIndexSync && s(`.${_idModal}`)) s(`.${_idModal}`).style.zIndex = '3';
2305
+ });
2306
+ };
2307
+ const setTopModal = () => {
2308
+ if (s(`.${idModal}`)) {
2309
+ this.setTopModalCallback(idModal);
2310
+ } else setTimeout(setTopModal, 100);
2311
+ };
2312
+ cleanTopModal();
2313
+ setTopModal();
2314
+ this.Data[idModal].onClickListener[`${idModal}-z-index`] = () => {
2315
+ if (s(`.${idModal}`) && s(`.${idModal}`).style.zIndex === '3') {
2316
+ if (this.Data[idModal].options.route)
2317
+ setPath(
2318
+ `${getProxyPath()}${this.Data[idModal].options.route}${location.search ?? ''}${location.hash ?? ''}`,
2319
+ );
2320
+ cleanTopModal();
2321
+ setTopModal();
2322
+ }
2323
+ };
2324
+ });
2325
+ }
2326
+
2327
+ /**
2328
+ * @param {string} idModal
2329
+ */
2330
+ static setTopModalCallback(idModal) {
2331
+ s(`.${idModal}`).style.zIndex = '4';
2332
+ this.currentTopModalId = `${idModal}`;
2333
+ }
2334
+
2335
+ /** @returns {boolean} True when the viewport is considered mobile-sized. */
2336
+ static mobileModal = () => windowGetW() < 600 || windowGetH() < 600;
2337
+
2338
+ /**
2339
+ * @param {{ idModal: string, html: string }} param0
2340
+ */
2341
+ static writeHTML = ({ idModal, html }) => htmls(`.html-${idModal}`, html);
2342
+
2343
+ /**
2344
+ * Update an existing modal's content and/or title.
2345
+ * @param {{ idModal: string, html?: string, title?: string }} param0
2346
+ * @returns {Promise<boolean>}
2347
+ */
2348
+ static async updateModal({ idModal, html, title }) {
2349
+ if (!this.Data[idModal] || !s(`.${idModal}`)) {
2350
+ console.warn(`Modal ${idModal} not found for update`);
2351
+ return false;
2352
+ }
2353
+
2354
+ // Update modal content
2355
+ if (html) {
2356
+ this.writeHTML({ idModal, html });
2357
+ }
2358
+
2359
+ // Update modal title if provided
2360
+ if (title) {
2361
+ const titleElement = s(`.${idModal} .modal-title`);
2362
+ if (titleElement) {
2363
+ titleElement.innerHTML = title;
2364
+ }
2365
+ }
2366
+
2367
+ // Trigger reload listeners
2368
+ if (this.Data[idModal].onReloadModalListener) {
2369
+ for (const event of Object.keys(this.Data[idModal].onReloadModalListener)) {
2370
+ await this.Data[idModal].onReloadModalListener[event]();
2371
+ }
2372
+ }
2373
+
2374
+ return true;
2375
+ }
2376
+
2377
+ /** @returns {string|undefined} Id of the first open view-mode modal, or undefined. */
2378
+ static viewModalOpen() {
2379
+ return Object.keys(this.Data).find((idModal) => s(`.${idModal}`) && this.Data[idModal].options.mode === 'view');
2380
+ }
2381
+
2382
+ /**
2383
+ * Remove a modal element and its style tags, and delete its data entry.
2384
+ * @param {string} idModal
2385
+ */
2386
+ static removeModal(idModal) {
2387
+ if (!s(`.${idModal}`)) return;
2388
+ s(`.${idModal}`).remove();
2389
+ sa(`.style-${idModal}`).forEach((element) => {
2390
+ element.remove();
2391
+ });
2392
+ delete this.Data[idModal];
2393
+ }
2394
+
2395
+ /**
2396
+ * Render a confirmation dialog and return a promise resolving to the user's choice.
2397
+ * @param {{ id: string, html: Function, icon?: string, disableBtnCancel?: boolean }} options
2398
+ * @returns {Promise<{ status: 'confirm'|'cancelled' }>}
2399
+ */
2400
+ static async RenderConfirm(options) {
2401
+ const { id } = options;
2402
+ append(
2403
+ 'body',
2404
+ html`
2405
+ <div
2406
+ class="fix background-confirm-modal-${id}"
2407
+ style="${renderCssAttr({
2408
+ style: {
2409
+ 'z-index': '10',
2410
+ background: 'rgba(0,0,0,0.5)',
2411
+ width: '100%',
2412
+ height: '100%',
2413
+ top: '0px',
2414
+ left: '0px',
2415
+ transition: '0.3s',
2416
+ opacity: '1',
2417
+ },
2418
+ })}"
2419
+ ></div>
2420
+ `,
2421
+ );
2422
+ const removeBackgroundConfirmModal = () => {
2423
+ s(`.background-confirm-modal-${id}`).style.opacity = '0';
2424
+ setTimeout(() => {
2425
+ s(`.background-confirm-modal-${id}`).remove();
2426
+ });
2427
+ };
2428
+
2429
+ return new Promise(async (resolve, reject) => {
2430
+ const { barConfig } = await Themes[Css.currentTheme]();
2431
+ barConfig.buttons.maximize.disabled = true;
2432
+ barConfig.buttons.minimize.disabled = true;
2433
+ barConfig.buttons.restore.disabled = true;
2434
+ barConfig.buttons.menu.disabled = true;
2435
+ barConfig.buttons.close.disabled = false;
2436
+ const htmlRender = html`
2437
+ <br />
2438
+ <div class="in section-mp" style="font-size: 40px; text-align: center">
2439
+ ${options.icon ? options.icon : html` <i class="fas fa-question-circle"></i>`}
2440
+ </div>
2441
+ ${await options.html()}
2442
+ <div class="in section-mp">
2443
+ ${await BtnIcon.instance({
2444
+ class: `in section-mp form-button btn-confirm-${id}`,
2445
+ label: Translate.instance('confirm'),
2446
+ type: 'submit',
2447
+ style: `margin: auto`,
2448
+ })}
2449
+ </div>
2450
+ <div class="in section-mp ${options.disableBtnCancel ? 'hide' : ''}">
2451
+ ${await BtnIcon.instance({
2452
+ class: `in section-mp form-button btn-cancel-${id}`,
2453
+ label: Translate.instance('cancel'),
2454
+ type: 'submit',
2455
+ style: `margin: auto`,
2456
+ })}
2457
+ </div>
2458
+ `;
2459
+ await Modal.instance({
2460
+ id,
2461
+ barConfig,
2462
+ titleClass: 'hide',
2463
+ style: {
2464
+ width: '300px',
2465
+ height: '400px',
2466
+ overflow: 'hidden',
2467
+ 'z-index': '11',
2468
+ resize: 'none',
2469
+ },
2470
+ dragDisabled: true,
2471
+ ...options,
2472
+ html: htmlRender,
2473
+ });
2474
+
2475
+ const end = () => {
2476
+ removeBackgroundConfirmModal();
2477
+ Modal.removeModal(id);
2478
+ };
2479
+ barConfig.buttons.close.onClick = () => {
2480
+ end();
2481
+ resolve({ status: 'cancelled' });
2482
+ };
2483
+ s(`.background-confirm-modal-${id}`).onclick = () => {
2484
+ end();
2485
+ resolve({ status: 'cancelled' });
2486
+ };
2487
+ s(`.btn-cancel-${id}`).onclick = () => {
2488
+ end();
2489
+ resolve({ status: 'cancelled' });
2490
+ };
2491
+ s(`.btn-confirm-${id}`).onclick = () => {
2492
+ end();
2493
+ resolve({ status: 'confirm' });
2494
+ };
2495
+ });
2496
+ }
2497
+
2498
+ /** @type {string} */
2499
+ static labelSelectorTopOffsetStartAnimation = `-40px`;
2500
+
2501
+ /** @type {string} */
2502
+ static labelSelectorTopOffsetEndAnimation = `-3px`;
2503
+
2504
+ /**
2505
+ * Animate slide-menu labels into view.
2506
+ * @param {string} idModal - The slide-menu modal id.
2507
+ * @param {string} [subMenuId] - If provided, animate only this sub-menu.
2508
+ */
2509
+ static menuTextLabelAnimation = (idModal, subMenuId) => {
2510
+ if (
2511
+ !s(
2512
+ `.btn-icon-menu-mode-${Modal.Data[idModal].options.mode === 'slide-menu-right' ? 'left' : 'right'}`,
2513
+ ).classList.contains('hide')
2514
+ ) {
2515
+ return;
2516
+ }
2517
+ const btnSelector = `.main-btn-menu`;
2518
+ const labelSelector = `.menu-label-text`;
2519
+
2520
+ const _data = subMenuId
2521
+ ? {
2522
+ [subMenuId]: Modal.subMenuBtnClass[subMenuId],
2523
+ }
2524
+ : { ...Modal.subMenuBtnClass, _: { btnSelector, labelSelector } };
2525
+
2526
+ for (const keyDataBtn of Object.keys(_data)) {
2527
+ const { labelSelector, top } = _data[keyDataBtn];
2528
+ if (top)
2529
+ setTimeout(() => {
2530
+ top();
2531
+ });
2532
+ sa(labelSelector).forEach((el) => {
2533
+ if (!el.classList.contains('hide')) el.classList.add('hide');
2534
+ el.style.transition = null;
2535
+ });
2536
+
2537
+ setTimeout(() => {
2538
+ sa(labelSelector).forEach((el) => {
2539
+ el.classList.remove('hide');
2540
+ el.style.transition = null;
2541
+ });
2542
+ sa(labelSelector).forEach((el) => {
2543
+ el.style.top = Modal.labelSelectorTopOffsetStartAnimation;
2544
+ });
2545
+ }, 300);
2546
+ setTimeout(() => {
2547
+ sa(labelSelector).forEach((el) => {
2548
+ el.style.top = Modal.labelSelectorTopOffsetEndAnimation;
2549
+ });
2550
+ }, 400);
2551
+ }
2552
+ };
2553
+
2554
+ /**
2555
+ * Builds submenu item HTML using the canonical BtnIcon pattern.
2556
+ * Centralises the item-rendering contract so individual submenu owners (e.g. Docs)
2557
+ * only need to supply data — not layout concerns.
2558
+ * @param {string} subMenuId - Submenu identifier (e.g. 'docs')
2559
+ * @param {Array<{type:string, icon:string, text:string, url:function|string}>} items
2560
+ * @param {Object} [options]
2561
+ * @param {function} [options.subMenuIcon] - Optional icon override per item type
2562
+ * @returns {Promise<string>} Rendered HTML string
2563
+ */
2564
+ static buildSubMenuItemsHtml = async (subMenuId, items = [], options = {}) => {
2565
+ let result = '';
2566
+ const _menuMode = Modal.Data['modal-menu']?.options?.mode;
2567
+ const _tooltipSide = options.tooltipSide || (_menuMode === 'slide-menu-right' ? 'right' : 'left');
2568
+ for (const item of items) {
2569
+ const tabHref = typeof item.url === 'function' ? item.url() : item.url || '';
2570
+ const icon =
2571
+ options.subMenuIcon && typeof options.subMenuIcon === 'function' ? options.subMenuIcon(item.type) : item.icon;
2572
+ result += html`${await BtnIcon.instance({
2573
+ class: `in wfa main-btn-menu submenu-btn btn-${subMenuId} btn-${subMenuId}-${item.type}`,
2574
+ label: html`<span class="inl menu-btn-icon">${icon}</span
2575
+ ><span class="menu-label-text menu-label-text-${subMenuId}"> ${item.text} </span>`,
2576
+ tabHref,
2577
+ tooltipHtml: await Badge.instance(buildBadgeToolTipMenuOption(item.text, _tooltipSide)),
2578
+ useMenuBtn: true,
2579
+ })} `;
2580
+ }
2581
+ return result;
2582
+ };
2583
+
2584
+ /**
2585
+ * Injects pre-built submenu item HTML into the submenu container and syncs
2586
+ * the collapse state so labels are hidden when the menu is icon-only.
2587
+ * @param {string} subMenuId
2588
+ * @param {string} itemsHtml
2589
+ */
2590
+ static subMenuPopulate = (subMenuId, itemsHtml) => {
2591
+ htmls(`.menu-btn-container-children-${subMenuId}`, itemsHtml);
2592
+ const _menuMode = Modal.Data['modal-menu']?.options?.mode;
2593
+ const _collapseIndicatorClass =
2594
+ _menuMode === 'slide-menu-right' ? '.btn-icon-menu-mode-left' : '.btn-icon-menu-mode-right';
2595
+ if (s(_collapseIndicatorClass) && !s(_collapseIndicatorClass).classList.contains('hide')) {
2596
+ sa(`.menu-label-text-${subMenuId}`).forEach((el) => el.classList.add('hide'));
2597
+ }
2598
+ };
2599
+
2600
+ // Move modal title element into the bar's render container so it aligns with control buttons
2601
+ /**
2602
+ * Position a modal relative to an anchor element.
2603
+ * @param {object} options - Positioning options
2604
+ * @param {string} options.modalSelector - CSS selector for the modal element
2605
+ * @param {string} options.anchorSelector - CSS selector for the anchor element
2606
+ * @param {object} [options.offset={x: 0, y: 6}] - Offset from anchor
2607
+ * @param {string} [options.align='right'] - Horizontal alignment ('left' or 'right')
2608
+ * @param {boolean} [options.autoVertical=true] - Whether to automatically determine vertical position
2609
+ * @param {boolean} [options.placeAbove] - Force position above/below anchor (overrides autoVertical)
2610
+ */
2611
+ static positionRelativeToAnchor({
2612
+ modalSelector,
2613
+ anchorSelector,
2614
+ offset = { x: 0, y: 6 },
2615
+ align = 'right',
2616
+ autoVertical = true,
2617
+ placeAbove,
2618
+ }) {
2619
+ try {
2620
+ const modal = s(modalSelector);
2621
+ const anchor = s(anchorSelector);
2622
+
2623
+ if (!modal || !anchor || !anchor.getBoundingClientRect) return;
2624
+
2625
+ // First, position the modal near its final position but off-screen
2626
+ const arect = anchor.getBoundingClientRect();
2627
+ const vh = windowGetH();
2628
+ const vw = windowGetW();
2629
+ const safeMargin = 6;
2630
+
2631
+ // Determine vertical position
2632
+ let finalPlaceAbove = placeAbove;
2633
+ if (autoVertical && placeAbove === undefined) {
2634
+ const inBottomBar = anchor.closest && anchor.closest('.bottom-bar');
2635
+ const inTopBar = anchor.closest && anchor.closest('.slide-menu-top-bar');
2636
+
2637
+ if (inBottomBar) finalPlaceAbove = true;
2638
+ else if (inTopBar) finalPlaceAbove = false;
2639
+ else finalPlaceAbove = arect.top > vh / 2; // heuristic fallback
2640
+ }
2641
+
2642
+ // Set initial position (slightly offset from final position)
2643
+ const initialOffset = finalPlaceAbove ? 20 : -20;
2644
+ modal.style.position = 'fixed';
2645
+ modal.style.opacity = '0';
2646
+ modal.style.transition = 'opacity 150ms ease-out, transform 150ms ease-out';
2647
+
2648
+ // Position near the anchor but slightly offset
2649
+ modal.style.top = `${finalPlaceAbove ? arect.top - 40 : arect.bottom + 20}px`;
2650
+ modal.style.left = `${align === 'right' ? arect.right - 200 : arect.left}px`;
2651
+ modal.style.transform = 'translateY(0)';
2652
+
2653
+ // Force reflow to ensure initial styles are applied
2654
+ modal.offsetHeight;
2655
+
2656
+ // Now calculate final position
2657
+ const mrect = modal.getBoundingClientRect();
2658
+
2659
+ // Calculate final top position
2660
+ const top = finalPlaceAbove ? arect.top - mrect.height - offset.y : arect.bottom + offset.y;
2661
+
2662
+ // Calculate final left position based on alignment
2663
+ let left;
2664
+ if (align === 'right') {
2665
+ left = arect.right - mrect.width - offset.x; // align right edges
2666
+ } else {
2667
+ left = arect.left + offset.x; // align left edges
2668
+ }
2669
+
2670
+ // Ensure modal stays within viewport bounds
2671
+ left = Math.max(safeMargin, Math.min(left, vw - mrect.width - safeMargin));
2672
+ const finalTop = Math.max(safeMargin, Math.min(top, vh - mrect.height - safeMargin));
2673
+
2674
+ // Apply final position with smooth transition
2675
+ requestAnimationFrame(() => {
2676
+ modal.style.top = `${Math.round(finalTop)}px`;
2677
+ modal.style.left = `${Math.round(left)}px`;
2678
+ modal.style.opacity = '1';
2679
+ });
2680
+ } catch (e) {
2681
+ console.error('Error positioning modal:', e);
2682
+ }
2683
+ }
2684
+
2685
+ /**
2686
+ * Move the title element inside the bar button container for inline alignment.
2687
+ * @param {string} idModal
2688
+ */
2689
+ static MoveTitleToBar(idModal) {
2690
+ try {
2691
+ const titleEl = s(`.title-modal-${idModal}`);
2692
+ const container = s(`.btn-bar-modal-container-render-${idModal}`);
2693
+ if (!titleEl || !container) return;
2694
+ const titleNode = titleEl.cloneNode(true);
2695
+ titleEl.remove();
2696
+ container.classList.add('in');
2697
+ container.classList.add('fll');
2698
+ container.appendChild(titleNode);
2699
+ } catch (e) {
2700
+ // non-fatal: keep default placement if structure not present
2701
+ }
2702
+ }
2703
+
2704
+ /** Update the top-banner anchor href and bind the home-click handler. */
2705
+ static setTopBannerLink() {
2706
+ if (s(`.a-link-top-banner`)) {
2707
+ s(`.a-link-top-banner`).setAttribute('href', `${location.origin}${getProxyPath()}`);
2708
+ EventsUI.onClick(`.a-link-top-banner`, (e) => {
2709
+ e.preventDefault();
2710
+ s(`.action-btn-home`).click();
2711
+ });
2712
+ }
2713
+ }
2714
+
2715
+ /** @type {number} */
2716
+ static headerTitleHeight = 40;
2717
+
2718
+ /** Toggle the slide-menu open/close via the center action button. */
2719
+ static actionBtnCenter() {
2720
+ if (!s(`.btn-close-modal-menu`).classList.contains('hide')) {
2721
+ return s(`.btn-close-modal-menu`).click();
2722
+ }
2723
+ if (!s(`.btn-menu-modal-menu`).classList.contains('hide')) {
2724
+ return s(`.btn-menu-modal-menu`).click();
2725
+ }
2726
+ }
2727
+
2728
+ /** Hide the top-bar, bottom-bar and slide-menu (full-screen mode). */
2729
+ static cleanUI() {
2730
+ s(`.top-bar`).classList.add('hide');
2731
+ s(`.bottom-bar`).classList.add('hide');
2732
+ s(`.modal-menu`).classList.add('hide');
2733
+ }
2734
+
2735
+ /** Restore the top-bar, bottom-bar and slide-menu after cleanUI. */
2736
+ static restoreUI() {
2737
+ s(`.top-bar`).classList.remove('hide');
2738
+ s(`.bottom-bar`).classList.remove('hide');
2739
+ s(`.modal-menu`).classList.remove('hide');
2740
+ }
2741
+
2742
+ /**
2743
+ * Re-applies canonical top/height layout for maximized slide-menu-backed view modals.
2744
+ * This avoids iframe navigation leaving view containers offset at the top.
2745
+ */
2746
+ static syncViewLayout() {
2747
+ const modalMenuOptions = this.Data['modal-menu']?.options || {};
2748
+ const uiCollapsed = !!s(`.main-body-btn-ui-close`) && s(`.main-body-btn-ui-close`).classList.contains('hide');
2749
+ const topOffset = uiCollapsed ? 0 : modalMenuOptions.heightTopBar ? modalMenuOptions.heightTopBar : 50;
2750
+ const bottomOffset = uiCollapsed ? 0 : modalMenuOptions.heightBottomBar ? modalMenuOptions.heightBottomBar : 0;
2751
+ const height = `${windowGetH() - topOffset - bottomOffset}px`;
2752
+
2753
+ Object.keys(this.Data).forEach((idModal) => {
2754
+ const modalData = this.Data[idModal];
2755
+ const modalEl = s(`.${idModal}`);
2756
+ if (!modalData || !modalEl || !modalData.slideMenu) return;
2757
+ if (s(`.btn-restore-${idModal}`) && s(`.btn-restore-${idModal}`).style.display === 'none') return;
2758
+
2759
+ modalEl.style.position = 'fixed';
2760
+ modalEl.style.translate = '0px 0px';
2761
+ modalEl.style.transform = '';
2762
+ modalEl.style.top = `${topOffset}px`;
2763
+ modalEl.style.height = height;
2764
+ });
2765
+
2766
+ for (const id of coreUI) {
2767
+ const key = `view-${id}`;
2768
+ if (Responsive.hasChangedListener(key)) Responsive.triggerChanged(key);
2769
+ }
2770
+ }
2771
+
2772
+ /** Add missing `alt` attributes to all images for SEO/accessibility. */
2773
+ static RenderSeoSanitizer = async () => {
2774
+ sa('img').forEach((img) => {
2775
+ if (!img.getAttribute('alt')) img.setAttribute('alt', 'image ' + Worker.title + ' ' + s4());
2776
+ });
2777
+ };
2778
+ }
2779
+
2780
+ const renderMenuLabel = ({ img, src, text, icon }) => {
2781
+ if (!img && !src) return html`<span class="inl menu-btn-icon">${icon}</span> ${text}`;
2782
+ const imgSrc = src ? src : `${getProxyPath()}assets/ui-icons/${img}`;
2783
+ return html`<img class="abs center img-btn-square-menu" src="${imgSrc}" />
2784
+ <div class="abs center main-btn-menu-text">${text}</div>`;
2785
+ };
2786
+
2787
+ const renderViewTitle = (
2788
+ options = {
2789
+ icon: '',
2790
+ img: '',
2791
+ text: '',
2792
+ assetFolder: '',
2793
+ 'ui-icon': '',
2794
+ imgClass: '',
2795
+ textClass: '',
2796
+ dim,
2797
+ top,
2798
+ topText: '',
2799
+ },
2800
+ ) => {
2801
+ if (options.dim === undefined) options.dim = 30;
2802
+ const { img, text, icon, dim, top } = options;
2803
+ if (!img && !options['ui-icon']) return html`<span class="view-title-icon">${icon}</span> ${text}`;
2804
+ const imgClass = options.imgClass || 'abs img-btn-square-view-title';
2805
+ const textClass = options.textClass || 'in text-btn-square-view-title';
2806
+ return html`<img
2807
+ class="${imgClass}"
2808
+ style="${renderCssAttr({
2809
+ style: {
2810
+ width: `${dim}px`,
2811
+ height: `${dim}px`,
2812
+ top: top !== undefined ? `${top}px !important` : undefined,
2813
+ },
2814
+ })}"
2815
+ src="${options['ui-icon']
2816
+ ? `${getProxyPath()}assets/${options.assetFolder ? options.assetFolder : 'ui-icons'}/${options['ui-icon']}`
2817
+ : img}"
2818
+ />
2819
+ <div
2820
+ class="${textClass}"
2821
+ style="${renderCssAttr({
2822
+ style: {
2823
+ // 'padding-left': `${20 + dim}px`,
2824
+ ...(options.topText !== undefined ? { top: options.topText + 'px !important' } : {}),
2825
+ },
2826
+ })}"
2827
+ >
2828
+ ${text}
2829
+ </div>`;
2830
+ };
2831
+
2832
+ const buildBadgeToolTipMenuOption = (id, sideKey = 'left') => {
2833
+ const option = {
2834
+ id: `tooltip-content-main-btn-${id}`,
2835
+ text: `${Translate.instance(`${id}`)}`,
2836
+ classList: 'tooltip-menu',
2837
+ style: { top: `-40px` },
2838
+ };
2839
+ switch (sideKey) {
2840
+ case 'left':
2841
+ option.style.left = '60px';
2842
+
2843
+ break;
2844
+
2845
+ case 'right':
2846
+ option.style.right = '60px';
2847
+ break;
2848
+
2849
+ default:
2850
+ break;
2851
+ }
2852
+ return option;
2853
+ };
2854
+
2855
+ const isSubMenuOpen = (subMenuId) => {
2856
+ return s(`.down-arrow-submenu-${subMenuId}`) && s(`.down-arrow-submenu-${subMenuId}`).style.rotate === '180deg';
2857
+ };
2858
+
2859
+ const subMenuRender = async (subMenuId) => {
2860
+ const _hBtn = 51;
2861
+ const menuBtn = s(`.main-btn-${subMenuId}`);
2862
+ const menuContainer = s(`.menu-btn-container-children-${subMenuId}`);
2863
+ const arrow = s(`.down-arrow-submenu-${subMenuId}`);
2864
+
2865
+ if (!menuBtn || !menuContainer || !arrow) return;
2866
+
2867
+ const top = () => {
2868
+ let value = menuBtn.offsetTop + Modal.Data['modal-menu'].options.heightTopBar;
2869
+
2870
+ const isHidden = s('.main-body-btn-ui-open').classList.contains('hide');
2871
+ const isTopBottom = Modal.Data['modal-menu'].options.barMode === 'top-bottom-bar';
2872
+
2873
+ if (!isTopBottom && isHidden) value -= 51;
2874
+ else if (!isHidden) value += 51;
2875
+
2876
+ menuContainer.style.top = `${value}px`;
2877
+ };
2878
+
2879
+ Modal.subMenuBtnClass[subMenuId] = {
2880
+ ...Modal.subMenuBtnClass[subMenuId],
2881
+ btnSelector: `.btn-${subMenuId}`,
2882
+ labelSelector: `.menu-label-text-${subMenuId}`,
2883
+ top,
2884
+ };
2885
+
2886
+ menuBtn.style.transition = '.3s';
2887
+ arrow.style.transition = '.3s';
2888
+
2889
+ if (isSubMenuOpen(subMenuId)) {
2890
+ // Close animation
2891
+ menuContainer.style.overflow = 'hidden';
2892
+ menuContainer.style.height = '0px';
2893
+ arrow.style.rotate = '180deg';
2894
+ setTimeout(() => {
2895
+ menuBtn.style.marginBottom = '0px';
2896
+ arrow.style.rotate = '0deg';
2897
+ });
2898
+ } else {
2899
+ sa(`.menu-label-text-${subMenuId}`).forEach((el) => {
2900
+ if (!el.classList.contains('hide')) el.classList.add('hide');
2901
+ });
2902
+ setTimeout(() => {
2903
+ Modal.menuTextLabelAnimation('modal-menu', subMenuId);
2904
+ });
2905
+ // Open animation — match the current menu width (collapsed = 50px, extended = 320px)
2906
+ const _menuMode = Modal.Data['modal-menu']?.options?.mode;
2907
+ const _collapseIndicatorClass =
2908
+ _menuMode === 'slide-menu-right' ? '.btn-icon-menu-mode-left' : '.btn-icon-menu-mode-right';
2909
+ const _isMenuCollapsed = s(_collapseIndicatorClass) && !s(_collapseIndicatorClass).classList.contains('hide');
2910
+ const _menuContainerWidth = _isMenuCollapsed ? 50 : 320;
2911
+ setTimeout(top, 360);
2912
+ menuContainer.style.width = `${_menuContainerWidth}px`;
2913
+ menuContainer.style.overflow = null;
2914
+ menuContainer.style.height = '0px';
2915
+ menuContainer.style.height = `${_hBtn * 6}px`;
2916
+ arrow.style.rotate = '0deg';
2917
+ setTimeout(() => {
2918
+ menuBtn.style.marginBottom = `${_hBtn * sa(`.menu-label-text-${subMenuId}`).length + 4}px`;
2919
+ arrow.style.rotate = '180deg';
2920
+ });
2921
+ }
2922
+
2923
+ setTimeout(() => {
2924
+ menuBtn.style.transition = null;
2925
+ }, 500);
2926
+ };
2927
+
2928
+ const subMenuHandler = (routes, route) => {
2929
+ route = sanitizeRoute(route);
2930
+ for (let _route of routes) {
2931
+ _route = sanitizeRoute(_route);
2932
+ if (_route !== route) {
2933
+ if (isSubMenuOpen(_route)) subMenuRender(_route);
2934
+ }
2935
+ }
2936
+ setTimeout(() => {
2937
+ let cid = getQueryParams().cid;
2938
+ if (cid && cid.includes(',')) {
2939
+ cid = cid.split(',')[0];
2940
+ }
2941
+ if (s(`.main-sub-btn-active`)) s(`.main-sub-btn-active`).classList.remove('main-sub-btn-active');
2942
+ if (cid && s(`.btn-${route}-${cid}`)) {
2943
+ s(`.btn-${route}-${cid}`).classList.add('main-sub-btn-active');
2944
+ }
2945
+ });
2946
+ };
2947
+
2948
+ export {
2949
+ Modal,
2950
+ renderMenuLabel,
2951
+ renderViewTitle,
2952
+ buildBadgeToolTipMenuOption,
2953
+ subMenuRender,
2954
+ isSubMenuOpen,
2955
+ subMenuHandler,
2956
+ };