@maplat/ui 0.10.6 → 0.11.1

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 (176) hide show
  1. package/LICENSE +223 -223
  2. package/README.md +128 -91
  3. package/assets/locales/de/translation.json +71 -0
  4. package/{locales → assets/locales}/en/translation.json +70 -64
  5. package/{locales → assets/locales}/ja/translation.json +70 -64
  6. package/{locales → assets/locales}/ko/translation.json +71 -65
  7. package/assets/locales/vi/translation.json +71 -0
  8. package/{locales → assets/locales}/zh/translation.json +71 -65
  9. package/{locales → assets/locales}/zh-TW/translation.json +71 -65
  10. package/assets/parts/attr.png +0 -0
  11. package/assets/parts/border.png +0 -0
  12. package/assets/parts/compass.png +0 -0
  13. package/assets/parts/gps.png +0 -0
  14. package/assets/parts/help.png +0 -0
  15. package/assets/parts/hide_marker.png +0 -0
  16. package/assets/parts/home.png +0 -0
  17. package/assets/parts/marker_list.png +0 -0
  18. package/assets/parts/share.png +0 -0
  19. package/dist/absolute_url.d.ts +1 -0
  20. package/dist/assets/locales/de/translation.json +71 -0
  21. package/dist/assets/locales/en/translation.json +70 -64
  22. package/dist/assets/locales/ja/translation.json +70 -64
  23. package/dist/assets/locales/ko/translation.json +71 -65
  24. package/dist/assets/locales/vi/translation.json +71 -0
  25. package/dist/assets/locales/zh/translation.json +71 -65
  26. package/dist/assets/locales/zh-TW/translation.json +71 -65
  27. package/dist/contextmenu.d.ts +5 -0
  28. package/dist/function.d.ts +2 -0
  29. package/dist/icons.d.ts +7 -0
  30. package/dist/index.d.ts +65 -0
  31. package/dist/maplat-ui.es.js +33551 -0
  32. package/dist/maplat-ui.umd.js +4934 -0
  33. package/dist/maplat_control.d.ts +55 -0
  34. package/dist/pointer_images.d.ts +2 -0
  35. package/dist/swiper_ex.d.ts +2 -0
  36. package/dist/types.d.ts +185 -0
  37. package/dist/ui_init.d.ts +4 -0
  38. package/dist/ui_marker.d.ts +9 -0
  39. package/dist/ui_utils.d.ts +9 -0
  40. package/less/bootstrap.less +7010 -7010
  41. package/less/contextmenu.css +8 -0
  42. package/less/font-awesome.less +51 -31
  43. package/less/iziToast.less +1732 -1732
  44. package/less/maplat-specific.less +1038 -652
  45. package/less/swiper4.css +715 -0
  46. package/less/ui.less +11 -11
  47. package/less/ui_packed.less +10 -10
  48. package/package.json +80 -79
  49. package/src/{absolute_url.js → absolute_url.ts} +1 -1
  50. package/src/contextmenu/base.ts +170 -0
  51. package/src/contextmenu/constants.ts +66 -0
  52. package/src/contextmenu/cssVars.ts +13 -0
  53. package/src/contextmenu/helpers/dom.ts +295 -0
  54. package/src/contextmenu/helpers/mix.ts +120 -0
  55. package/src/contextmenu/html.ts +161 -0
  56. package/src/contextmenu/internal.ts +293 -0
  57. package/src/contextmenu.ts +40 -0
  58. package/src/function.ts +36 -0
  59. package/src/icons.ts +46 -0
  60. package/src/index.ts +521 -0
  61. package/src/maplat_control.ts +629 -0
  62. package/src/pointer_images.ts +101 -0
  63. package/src/{service-worker.js → service-worker/index.ts} +5 -6
  64. package/src/swiper_augment.d.ts +13 -0
  65. package/src/{swiper_ex.js → swiper_ex.ts} +14 -10
  66. package/src/types.d.ts +31 -0
  67. package/src/types.ts +202 -0
  68. package/src/ui_init.ts +1175 -0
  69. package/src/ui_marker.ts +376 -0
  70. package/src/ui_utils.ts +87 -0
  71. package/dist/assets/fonts/a8c0074cf70b152b56105e6c4b227bd8.woff +0 -0
  72. package/dist/assets/fonts/cfeff2e898a64ebe7e6b5ec078b174c3.woff +0 -0
  73. package/dist/assets/images/09c3ce5a86d600e24f8e85de3a019853.png +0 -0
  74. package/dist/assets/images/0beac2cb41dfab43ddfd9df80b32b85d.png +0 -0
  75. package/dist/assets/images/1354b4f40dd58bb0f2a4871cb4ff81d8.png +0 -0
  76. package/dist/assets/images/2a61e310e46b50b5f8ddd5e905ba9db9.png +0 -0
  77. package/dist/assets/images/3131423d782cd3ea89a81247065e7f9d.png +0 -0
  78. package/dist/assets/images/41b2cf0fa604d3f196ca52337d238219.jpg +0 -0
  79. package/dist/assets/images/558bc7e8b9b6c5f41a7141cddb8cdb5e.png +0 -0
  80. package/dist/assets/images/56f7003805ed02f8a21199947651db2e.png +0 -0
  81. package/dist/assets/images/5ba349e3596aca094c41c56966b45dc7.png +0 -0
  82. package/dist/assets/images/6111b8076a2cf81c73f0e46f41a3af60.png +0 -0
  83. package/dist/assets/images/6345ee67d554fbfbf484ba4035ad19d9.jpg +0 -0
  84. package/dist/assets/images/649fce122b354de2ac725ba5f2661955.png +0 -0
  85. package/dist/assets/images/6a580287dea82c2fb9b214321a375145.png +0 -0
  86. package/dist/assets/images/6c5dba7f7d76e74c3a8c7c5b1c3fc544.png +0 -0
  87. package/dist/assets/images/6e1f2f2f6fed3c5cddeb925e7ae75aba.png +0 -0
  88. package/dist/assets/images/799a0177b0dc540682fa4a2e349a8f4f.png +0 -0
  89. package/dist/assets/images/7bef6f357e921c43f4f800cfcb757872.png +0 -0
  90. package/dist/assets/images/7d9d643a903df6f57b8b7386316021e5.png +0 -0
  91. package/dist/assets/images/7df82bae917b68159f84998182f2fdc6.png +0 -0
  92. package/dist/assets/images/8e5d0335f6598b8d874ba23ea9fb295f.png +0 -0
  93. package/dist/assets/images/90c32e751366be22777f3fe40a53fe06.png +0 -0
  94. package/dist/assets/images/9247459937b9c882303962e42bd8d989.png +0 -0
  95. package/dist/assets/images/927c34e7b9b2f95c82ba477993117eaf.png +0 -0
  96. package/dist/assets/images/95e9ca8285131f8ccb6da5052093173c.png +0 -0
  97. package/dist/assets/images/9a243e0cb0fc43e2a016d5d3aaa330d5.png +0 -0
  98. package/dist/assets/images/9ac6d81f417d6a5626b7c8d5a087c32b.png +0 -0
  99. package/dist/assets/images/9d3a01c866095b8b3e8e63f9cf11dd51.png +0 -0
  100. package/dist/assets/images/9df733bcb29a746cb16b47eedea9fc3a.png +0 -0
  101. package/dist/assets/images/acc6eab0ba9c470ae20fb4b74135e865.png +0 -0
  102. package/dist/assets/images/b9ae27f0a01228380dff76a33b605707.jpg +0 -0
  103. package/dist/assets/images/ba48b220f61a6e1028f1854326f43acd.png +0 -0
  104. package/dist/assets/images/bf67cc860289b85c0402a4d4f890a3bd.png +0 -0
  105. package/dist/assets/images/c49f2344772e33256ba24d64b59b20d1.png +0 -0
  106. package/dist/assets/images/ca6b77b234b18e7bb9b1ccda774da286.png +0 -0
  107. package/dist/assets/images/cd213169df16398b0017450e31788d73.png +0 -0
  108. package/dist/assets/images/f101a0974972eeab41189185a5c5b225.png +0 -0
  109. package/dist/assets/images/f115726e6249018905cca51653e1262c.png +0 -0
  110. package/dist/assets/images/f7acb820d978ab2dd69e8bf695c574d1.png +0 -0
  111. package/dist/assets/images/ffea4dd10bf2506aa1e0cd4c61426b42.png +0 -0
  112. package/dist/assets/maplat.css +0 -19
  113. package/dist/assets/maplat.css.map +0 -1
  114. package/dist/assets/maplat.js +0 -3
  115. package/dist/assets/maplat.js.LICENSE.txt +0 -43
  116. package/dist/assets/maplat.js.map +0 -1
  117. package/dist/index.html +0 -125
  118. package/dist/service-worker.js +0 -3
  119. package/dist/service-worker.js.LICENSE.txt +0 -1
  120. package/dist/service-worker.js.map +0 -1
  121. package/fonts/clarenbd-webfont.woff +0 -0
  122. package/fonts/fontawesome-webfont.woff +0 -0
  123. package/legacy/bootstrap-native.js +0 -1935
  124. package/legacy/detect-element-resize.js +0 -153
  125. package/legacy/iziToast.js +0 -1301
  126. package/legacy/page.js +0 -1153
  127. package/legacy/qrcode.js +0 -616
  128. package/legacy/sprintf.js +0 -285
  129. package/less/font-face.less +0 -11
  130. package/less/font-face_packed.less +0 -11
  131. package/parts/attr.png +0 -0
  132. package/parts/blue_marker.png +0 -0
  133. package/parts/bluedot.png +0 -0
  134. package/parts/bluedot_small.png +0 -0
  135. package/parts/bluedot_transparent.png +0 -0
  136. package/parts/border.png +0 -0
  137. package/parts/compass.png +0 -0
  138. package/parts/defaultpin.png +0 -0
  139. package/parts/defaultpin_selected.png +0 -0
  140. package/parts/gps.png +0 -0
  141. package/parts/gsi.jpg +0 -0
  142. package/parts/gsi_ortho.jpg +0 -0
  143. package/parts/help.png +0 -0
  144. package/parts/hide_marker.png +0 -0
  145. package/parts/home.png +0 -0
  146. package/parts/osm.jpg +0 -0
  147. package/parts/red_marker.png +0 -0
  148. package/parts/redcircle.png +0 -0
  149. package/parts/share.png +0 -0
  150. package/src/contextmenu.js +0 -29
  151. package/src/freeze_locales.js +0 -337
  152. package/src/function.js +0 -22
  153. package/src/index.js +0 -1778
  154. package/src/index_packed.js +0 -8
  155. package/src/maplat_control.js +0 -808
  156. package/src/pointer_images.js +0 -81
  157. /package/{parts → assets/parts}/Maplat.png +0 -0
  158. /package/{parts → assets/parts}/all_right_reserved.png +0 -0
  159. /package/{parts → assets/parts}/basemap.png +0 -0
  160. /package/{parts → assets/parts}/cc0.png +0 -0
  161. /package/{parts → assets/parts}/cc_by-nc-nd.png +0 -0
  162. /package/{parts → assets/parts}/cc_by-nc-sa.png +0 -0
  163. /package/{parts → assets/parts}/cc_by-nc.png +0 -0
  164. /package/{parts → assets/parts}/cc_by-nd.png +0 -0
  165. /package/{parts → assets/parts}/cc_by-sa.png +0 -0
  166. /package/{parts → assets/parts}/cc_by.png +0 -0
  167. /package/{parts → assets/parts}/favicon.png +0 -0
  168. /package/{parts → assets/parts}/fullscreen.png +0 -0
  169. /package/{parts → assets/parts}/loading.png +0 -0
  170. /package/{parts → assets/parts}/loading_image.png +0 -0
  171. /package/{parts → assets/parts}/minus.png +0 -0
  172. /package/{parts → assets/parts}/no_image.png +0 -0
  173. /package/{parts → assets/parts}/overlay.png +0 -0
  174. /package/{parts → assets/parts}/pd.png +0 -0
  175. /package/{parts → assets/parts}/plus.png +0 -0
  176. /package/{parts → assets/parts}/slider.png +0 -0
package/src/ui_init.ts ADDED
@@ -0,0 +1,1175 @@
1
+ import { MaplatApp as Core, createElement } from "@maplat/core";
2
+ import * as bsn from "bootstrap.native";
3
+ import pointer from "./pointer_images";
4
+ import { Swiper } from "./swiper_ex";
5
+ import { Navigation, Pagination } from "swiper";
6
+ import "swiper/swiper-bundle.css";
7
+ import {
8
+ SliderNew,
9
+ Copyright,
10
+ CompassRotate,
11
+ Zoom,
12
+ SetGPS,
13
+ GoHome,
14
+ Maplat,
15
+ Share,
16
+ Border,
17
+ HideMarker,
18
+ MarkerList
19
+ } from "./maplat_control";
20
+ import ContextMenu from "./contextmenu";
21
+ import Weiwudi from "@c4h/weiwudi";
22
+ import absoluteUrl from "./absolute_url";
23
+ import * as QRCode from "qrcode";
24
+ import { ellips, isBasemap } from "./ui_utils";
25
+
26
+ import { poiWebControl } from "./ui_marker";
27
+
28
+ import type { MaplatUi } from "./index";
29
+ import type { MaplatAppOption } from "./types";
30
+
31
+ Swiper.use([Navigation, Pagination]);
32
+
33
+ export const META_KEYS = [
34
+ "title",
35
+ "officialTitle",
36
+ "author",
37
+ "epoch",
38
+ "createdAt",
39
+ "era",
40
+ "contributor",
41
+ "mapper",
42
+ "license",
43
+ "dataLicense",
44
+ "attr",
45
+ "dataAttr",
46
+ "reference",
47
+ "description"
48
+ ];
49
+
50
+ export async function uiInit(ui: MaplatUi, appOption: MaplatAppOption) {
51
+ appOption.translateUI = true;
52
+ ui.core = new Core(appOption);
53
+ if (appOption.icon) {
54
+ (pointer as Record<string, string>)["defaultpin.png"] = appOption.icon;
55
+ }
56
+
57
+ if (appOption.restore) {
58
+ ui.setShowBorder(appOption.restore.showBorder || false);
59
+ if (appOption.restore.hideMarker) {
60
+ ui.core!.waitReady.then(() => {
61
+ ui.setHideMarker(appOption.restore!.hideMarker);
62
+ });
63
+ }
64
+ if (appOption.restore.openedMarker) {
65
+ console.log(appOption.restore.openedMarker);
66
+ ui.core!.waitReady.then(() => {
67
+ console.log(`Timeout ${appOption.restore!.openedMarker} `);
68
+ ui.handleMarkerActionById(appOption.restore!.openedMarker!);
69
+ });
70
+ }
71
+ } else if (appOption.restoreSession) {
72
+ const lastEpoch = parseInt(
73
+ String(localStorage.getItem("epoch") || "0"),
74
+ 10
75
+ );
76
+ const currentTime = Math.floor(new Date().getTime() / 1000);
77
+ if (lastEpoch && currentTime - lastEpoch < 3600) {
78
+ ui.setShowBorder(
79
+ !!parseInt(String(localStorage.getItem("showBorder") || "0"), 10)
80
+ );
81
+ }
82
+ if (ui.core!.initialRestore.hideMarker) {
83
+ ui.core!.waitReady.then(() => {
84
+ ui.setHideMarker(true);
85
+ });
86
+ }
87
+ } else {
88
+ ui.setShowBorder(false);
89
+ }
90
+
91
+ const enableSplash = !ui.core!.initialRestore.mapID;
92
+ const restoreTransparency =
93
+ ui.core!.initialRestore.transparency ||
94
+ (appOption.restore ? appOption.restore.transparency : undefined);
95
+ const enableOutOfMap = !appOption.presentationMode;
96
+
97
+ ui.enablePoiHtmlNoScroll = appOption.enablePoiHtmlNoScroll || false;
98
+ if (appOption.enableShare) {
99
+ ui.core!.mapDivDocument!.classList.add("enable_share");
100
+ ui.enableShare = true;
101
+ }
102
+ if (appOption.enableHideMarker) {
103
+ ui.core!.mapDivDocument!.classList.add("enable_hide_marker");
104
+ ui.enableHideMarker = true;
105
+ }
106
+ if (appOption.enableBorder) {
107
+ ui.core!.mapDivDocument!.classList.add("enable_border");
108
+ ui.enableBorder = true;
109
+ }
110
+ if (appOption.enableMarkerList) {
111
+ ui.core!.mapDivDocument!.classList.add("enable_marker_list");
112
+ ui.enableMarkerList = true;
113
+ }
114
+ if (appOption.disableNoimage) {
115
+ ui.disableNoimage = true;
116
+ }
117
+ if (appOption.stateUrl) {
118
+ ui.core!.mapDivDocument!.classList.add("state_url");
119
+ }
120
+ if (appOption.alwaysGpsOn) {
121
+ ui.alwaysGpsOn = true;
122
+ }
123
+ if (ui.core!.enableCache) {
124
+ ui.core!.mapDivDocument!.classList.add("enable_cache");
125
+ }
126
+ if ("ontouchstart" in window) {
127
+ ui.core!.mapDivDocument!.classList.add("ol-touch");
128
+ ui.isTouch = true;
129
+ }
130
+ if (appOption.mobileIF) {
131
+ appOption.debug = true;
132
+ }
133
+ if (appOption.appEnvelope) {
134
+ ui.appEnvelope = true;
135
+ }
136
+
137
+ // Inject Custom Toast Styles
138
+ const style = document.createElement("style");
139
+ style.innerHTML = `
140
+ .custom-toast {
141
+ visibility: hidden;
142
+ min-width: 250px;
143
+ margin-left: -125px;
144
+ background-color: #333;
145
+ color: #fff;
146
+ text-align: center;
147
+ border-radius: 2px;
148
+ padding: 16px;
149
+ position: fixed;
150
+ z-index: 9999;
151
+ left: 50%;
152
+ bottom: 30px;
153
+ font-size: 17px;
154
+ opacity: 0;
155
+ transition: opacity 0.3s;
156
+ }
157
+ .custom-toast.show {
158
+ visibility: visible;
159
+ opacity: 1;
160
+ }
161
+ `;
162
+ document.head.appendChild(style);
163
+
164
+ let pwaManifest = appOption.pwaManifest;
165
+ let pwaWorker = appOption.pwaWorker;
166
+ let pwaScope = appOption.pwaScope;
167
+
168
+ // Inject FontAwesome CDN for reliable icons (REMOVED)
169
+ // Icons: Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0)
170
+
171
+ // Add UI HTML Element
172
+ let newElems = createElement(`<d c="ol-control map-title"><s></s></d>
173
+ <d c="swiper-container ol-control base-swiper prevent-default-ui">
174
+ <d c="swiper-wrapper"> </d>
175
+ <d c="swiper-button-next base-next swiper-button-white"> </d>
176
+ <d c="swiper-button-prev base-prev swiper-button-white"> </d>
177
+ </d>
178
+ <d c="swiper-container ol-control overlay-swiper prevent-default-ui">
179
+ <d c="swiper-wrapper"> </d>
180
+ <d c="swiper-button-next overlay-next swiper-button-white"> </d>
181
+ <d c="swiper-button-prev overlay-prev swiper-button-white"> </d>
182
+ </d> `);
183
+ for (let i = newElems.length - 1; i >= 0; i--) {
184
+ ui.core!.mapDivDocument!.insertBefore(
185
+ newElems[i],
186
+ ui.core!.mapDivDocument!.firstChild
187
+ );
188
+ }
189
+
190
+ // Delegated event listener for share buttons
191
+ ui.core!.mapDivDocument!.addEventListener("click", (evt: Event) => {
192
+ const target = evt.target as HTMLElement;
193
+ const btn = target.closest(".share");
194
+ if (!btn) return;
195
+
196
+ console.log("Share button clicked:", btn);
197
+ const cmd = btn.getAttribute("data");
198
+ if (!cmd) return;
199
+ const cmds = cmd.split("_");
200
+ const uri = ui.getShareUrl(cmds[1] || "app");
201
+
202
+ console.log("Share URI:", uri);
203
+
204
+ if (cmds[0] === "cp") {
205
+ const bodyElm = document.querySelector("body")!;
206
+ const message = ui.core!.t ? ui.core!.t("app.copy_toast") : "URL Copied";
207
+ if (navigator.clipboard) {
208
+ navigator.clipboard.writeText(uri).then(() => {
209
+ ui.showToast(message, btn as HTMLElement);
210
+ });
211
+ } else {
212
+ const copyFrom = document.createElement("textarea");
213
+ copyFrom.textContent = uri;
214
+ bodyElm.appendChild(copyFrom);
215
+ copyFrom.select();
216
+ document.execCommand("copy");
217
+ bodyElm.removeChild(copyFrom);
218
+ ui.showToast(message, btn as HTMLElement);
219
+ }
220
+ } else if (cmds[0] === "tw") {
221
+ const text = document.title;
222
+ const twuri = `https://twitter.com/intent/tweet?url=${encodeURIComponent(uri)}&text=${encodeURIComponent(text)}&hashtags=Maplat`;
223
+ window.open(twuri, "_blank");
224
+ } else if (cmds[0] === "fb") {
225
+ const fburi = `https://www.facebook.com/sharer/sharer.php?u=${encodeURIComponent(uri)}&display=popup&ref=plugin&src=like&kid_directed_site=0`;
226
+ window.open(
227
+ fburi,
228
+ "_blank",
229
+ "width=650,height=450,menubar=no,toolbar=no,scrollbars=yes"
230
+ );
231
+ }
232
+ });
233
+
234
+ const prevDefs = ui.core!.mapDivDocument!.querySelectorAll(
235
+ ".prevent-default-ui"
236
+ );
237
+ for (let i = 0; i < prevDefs.length; i++) {
238
+ const target = prevDefs[i];
239
+ target.addEventListener("touchstart", (evt: Event) => {
240
+ evt.preventDefault();
241
+ });
242
+ }
243
+
244
+ newElems = createElement(`<d c="modal modalBase" tabindex="-1" role="dialog"
245
+ aria-labelledby="staticModalLabel" aria-hidden="true" data-show="true" data-keyboard="false"
246
+ data-backdrop="static">
247
+ <d c="modal-dialog">
248
+ <d c="modal-content">
249
+ <d c="modal-header">
250
+ <button type="button" c="close" data-dismiss="modal">
251
+ <s aria-hidden="true">&#215;</s><s c="sr-only" din="html.close"></s>
252
+ </button>
253
+ <h4 c="modal-title">
254
+
255
+ <s c="modal_title"></s>
256
+ <s c="modal_load_title"></s>
257
+ <s c="modal_gpsW_title" din="html.acquiring_gps"></s>
258
+ <s c="modal_help_title" din="html.help_title"></s>
259
+ <s c="modal_share_title" din="html.share_title"></s>
260
+ <s c="modal_marker_list_title" din="html.marker_list_title"></s>
261
+
262
+ </h4>
263
+ </d>
264
+ <d c="modal-body">
265
+
266
+ <d c="modal_help_content">
267
+ <d c="help_content">
268
+ <s dinh="html.help_using_maplat"></s>
269
+ <p c="col-xs-12 help_img"><img src="${pointer["fullscreen.png"]}"></p>
270
+ <h4 din="html.help_operation_title"></h4>
271
+ <p dinh="html.help_operation_content" c="recipient"></p>
272
+ <h4 din="html.help_selection_title"></h4>
273
+ <p dinh="html.help_selection_content" c="recipient"></p>
274
+ <h4 din="html.help_gps_title"></h4>
275
+ <p dinh="html.help_gps_content" c="recipient"></p>
276
+ <h4 din="html.help_poi_title"></h4>
277
+ <p dinh="html.help_poi_content" c="recipient"></p>
278
+ <h4 din="html.help_etc_title"></h4>
279
+ <ul>
280
+ <li dinh="html.help_etc_attr" c="recipient"></li>
281
+ <li dinh="html.help_etc_help" c="recipient"></li>
282
+ <s c="share_help"><li dinh="html.help_share_help" c="recipient"></li></s>
283
+ <s c="border_help"><li dinh="html.help_etc_border" c="recipient"></li></s>
284
+ <s c="hide_marker_help"><li dinh="html.help_etc_hide_marker" c="recipient"></li></s>
285
+ <s c="marker_list_help"><li dinh="html.help_etc_marker_list" c="recipient"></li></s>
286
+ <li dinh="html.help_etc_slider" c="recipient"></li>
287
+ </ul>
288
+ <p><a href="https://www.maplat.jp/" target="_blank">Maplat</a>
289
+ © 2015- Kohei Otsuka, Code for History</p>
290
+ </d>
291
+ </d>
292
+
293
+ <d c="modal_poi_content">
294
+ <d c="poi_web_div"></d>
295
+ <d c="modal_share_poi"></d>
296
+ <p><img src="" height="0px" width="0px"></p>
297
+ </d>
298
+
299
+ <d c="modal_share_content">
300
+ <h4 din="html.share_app_title"></h4>
301
+ <d id="___maplat_app_toast_${ui.html_id_seed}"></d>
302
+ <d c="recipient row">
303
+ <d c="form-group col-xs-4 text-center"><button title="Copy to clipboard" class="share btn btn-light" data="cp_app"><svg style="width:14px;height:14px;vertical-align:text-bottom;" viewBox="0 0 512 512"><path fill="currentColor" d="M224 0c-35.3 0-64 28.7-64 64V96H96c-35.3 0-64 28.7-64 64V448c0 35.3 28.7 64 64 64H288c35.3 0 64-28.7 64-64V384h64c35.3 0 64-28.7 64-64V64c0-35.3-28.7-64-64-64H224zM288 384H96V160H224c0-17.7 14.3-32 32-32h64V256c0 17.7 14.3 32 32 32h96V384H288z"/></svg>&nbsp;<small din="html.share_copy"></small></button></d>
304
+ <d c="form-group col-xs-4 text-center"><button title="Twitter" class="share btn btn-light" data="tw_app"><svg style="width:14px;height:14px;vertical-align:text-bottom;" viewBox="0 0 512 512"><path fill="currentColor" d="M389.2 48h70.6L305.6 224.2 487 464H345L233.7 318.6 106.5 464H35.8L200.7 275.5 26.8 48H172.4L272.9 180.9 389.2 48zM364.4 421.8h39.1L151.1 88h-42L364.4 421.8z"/></svg>&nbsp;<small>Twitter</small></button></d>
305
+ <d c="form-group col-xs-4 text-center"><button title="Facebook" class="share btn btn-light" data="fb_app"><svg style="width:14px;height:14px;vertical-align:text-bottom;" viewBox="0 0 512 512"><path fill="currentColor" d="M504 256C504 119 393 8 256 8S8 119 8 256c0 121.3 87.1 222.4 203 240.5V327.9h-61v-71.9h61V203c0-60.8 35.8-93.7 89.2-93.7 25.5 0 50.4 1.8 56.1 2.6v62.4h-35.4c-29.5 0-37.4 18.2-37.4 42.1v59.6h68.9l-11 71.9h-57.9V496.5C416.9 478.4 504 377.3 504 256z"/></svg>&nbsp;<small>Facebook</small></button></d>
306
+ </d>
307
+ <d c="qr_app center-block" style="width:128px;"></d>
308
+ <d c="modal_share_state">
309
+ <h4 din="html.share_state_title"></h4>
310
+ <d id="___maplat_view_toast_${ui.html_id_seed}"></d>
311
+ <d c="recipient row">
312
+ <d c="form-group col-xs-4 text-center"><button title="Copy to clipboard" c="share btn btn-light" data="cp_view"><svg style="width:14px;height:14px;vertical-align:text-bottom;" viewBox="0 0 512 512"><path fill="currentColor" d="M224 0c-35.3 0-64 28.7-64 64V96H96c-35.3 0-64 28.7-64 64V448c0 35.3 28.7 64 64 64H288c35.3 0 64-28.7 64-64V384h64c35.3 0 64-28.7 64-64V64c0-35.3-28.7-64-64-64H224zM288 384H96V160H224c0-17.7 14.3-32 32-32h64V256c0 17.7 14.3 32 32 32h96V384H288z"/></svg>&nbsp;<small din="html.share_copy"></small></button></d>
313
+ <d c="form-group col-xs-4 text-center"><button title="Twitter" c="share btn btn-light" data="tw_view"><svg style="width:14px;height:14px;vertical-align:text-bottom;" viewBox="0 0 512 512"><path fill="currentColor" d="M389.2 48h70.6L305.6 224.2 487 464H345L233.7 318.6 106.5 464H35.8L200.7 275.5 26.8 48H172.4L272.9 180.9 389.2 48zM364.4 421.8h39.1L151.1 88h-42L364.4 421.8z"/></svg>&nbsp;<small>Twitter</small></button></d>
314
+ <d c="form-group col-xs-4 text-center"><button title="Facebook" c="share btn btn-light" data="fb_view"><svg style="width:14px;height:14px;vertical-align:text-bottom;" viewBox="0 0 512 512"><path fill="currentColor" d="M504 256C504 119 393 8 256 8S8 119 8 256c0 121.3 87.1 222.4 203 240.5V327.9h-61v-71.9h61V203c0-60.8 35.8-93.7 89.2-93.7 25.5 0 50.4 1.8 56.1 2.6v62.4h-35.4c-29.5 0-37.4 18.2-37.4 42.1v59.6h68.9l-11 71.9h-57.9V496.5C416.9 478.4 504 377.3 504 256z"/></svg>&nbsp;<small>Facebook</small></button></d>
315
+ </d>
316
+ <d c="qr_view center-block" style="width:128px;"></d>
317
+ </d>
318
+ <p><img src="" height="0px" width="0px"></p>
319
+ </d>
320
+
321
+ <d c="modal_map_content">
322
+ ${META_KEYS.map(key => {
323
+ if (key == "title" || key == "officialTitle") return "";
324
+ return `<d c="recipients ${key}_div"><dl c="dl-horizontal">
325
+ <dt din="html.${key}"></dt>
326
+ <dd c="${key}_dd"></dd>
327
+ </dl></d> `;
328
+ }).join("")}
329
+ <d c="recipients modal_cache_content"><dl c="dl-horizontal">
330
+ <dt din="html.cache_handle"></dt>
331
+ <dd><s c="cache_size"></s></dd>
332
+ <dt></dt>
333
+ <dd><s c="pull-right"><button c="cache_fetch btn btn-default" href="#" din="html.cache_fetch"></button>
334
+ <button c="cache_delete btn btn-default" href="#" din="html.cache_delete"></button></s></dd>
335
+ </dl></d>
336
+ </d>
337
+
338
+ <d c="modal_load_content">
339
+ <p c="recipient"><img src="${pointer["loading.png"]}"><s din="html.app_loading_body"></s></p>
340
+ <d c="splash_div hide row"><p c="col-xs-12 poi_img"><img c="splash_img" src=""></p></d>
341
+ <p><img src="" height="0px" width="0px"></p>
342
+ </d>
343
+
344
+ <d c="modal_marker_list_content">
345
+ <ul c="list-group"></ul>
346
+ </d>
347
+
348
+ <p c="modal_gpsD_content" c="recipient"></p>
349
+ <p c="modal_gpsW_content" c="recipient"></p>
350
+
351
+ </d>
352
+ </d>
353
+ </d>
354
+ </d> `);
355
+ for (let i = newElems.length - 1; i >= 0; i--) {
356
+ ui.core!.mapDivDocument!.insertBefore(
357
+ newElems[i],
358
+ ui.core!.mapDivDocument!.firstChild
359
+ );
360
+ }
361
+
362
+ // PWA
363
+ if (pwaManifest) {
364
+ if (pwaManifest === true) {
365
+ pwaManifest = `./pwa/${ui.core!.appid}_manifest.json`;
366
+ }
367
+ if (!pwaWorker) {
368
+ pwaWorker = "./service-worker.js";
369
+ }
370
+ if (!pwaScope) {
371
+ pwaScope = "./";
372
+ }
373
+
374
+ const head = document.querySelector("head");
375
+ if (head) {
376
+ if (!head.querySelector('link[rel="manifest"]')) {
377
+ head.appendChild(
378
+ createElement(`<link rel="manifest" href="${pwaManifest}">`)[0]
379
+ );
380
+ }
381
+ }
382
+ try {
383
+ Weiwudi.registerSW(pwaWorker, { scope: pwaScope });
384
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
385
+ } catch (_e) {} // eslint-disable-line no-empty
386
+
387
+ if (head && !head.querySelector('link[rel="apple-touch-icon"]')) {
388
+ const xhr = new XMLHttpRequest();
389
+ xhr.open("GET", pwaManifest, true);
390
+ xhr.responseType = "json";
391
+
392
+ xhr.onload = function (_e: ProgressEvent) {
393
+ let value = this.response;
394
+ if (!value) return;
395
+ if (typeof value != "object") value = JSON.parse(value);
396
+
397
+ if (value.icons) {
398
+ for (let i = 0; i < value.icons.length; i++) {
399
+ const src = absoluteUrl(pwaManifest as string, value.icons[i].src);
400
+ const sizes = value.icons[i].sizes;
401
+ const tag = `<link rel="apple-touch-icon" sizes="${sizes}" href="${src}">`;
402
+ head.appendChild(createElement(tag)[0]);
403
+ }
404
+ }
405
+ };
406
+ xhr.send();
407
+ }
408
+ }
409
+
410
+ ui.core!.addEventListener("uiPrepare", (_evt: unknown) => {
411
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
412
+ const imageExtractor = function (text: any) {
413
+ const regexp = /\$\{([a-zA-Z0-9_\.\/\-]+)\}/g; // eslint-disable-line no-useless-escape
414
+ let ret = text;
415
+ let match;
416
+ while ((match = regexp.exec(text)) != null) {
417
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
418
+ ret = ret.replace(match[0], (pointer as any)[match[1]]);
419
+ }
420
+ return ret;
421
+ };
422
+ let i18nTargets =
423
+ ui.core!.mapDivDocument!.querySelectorAll("[data-i18n], [din]");
424
+ for (let i = 0; i < i18nTargets.length; i++) {
425
+ const target = i18nTargets[i];
426
+ const key =
427
+ target.getAttribute("data-i18n") || target.getAttribute("din");
428
+ (target as HTMLElement).innerText = imageExtractor(ui.core!.t(key));
429
+ }
430
+ i18nTargets = ui.core!.mapDivDocument!.querySelectorAll(
431
+ "[data-i18n-html], [dinh]"
432
+ );
433
+ for (let i = 0; i < i18nTargets.length; i++) {
434
+ const target = i18nTargets[i];
435
+ const key =
436
+ target.getAttribute("data-i18n-html") || target.getAttribute("dinh");
437
+ target.innerHTML = imageExtractor(ui.core!.t(key));
438
+ }
439
+ // Explicitly fix app_loading_body with a more robust selector if needed, or re-run translation for it
440
+ const appLoadingBody = ui.core!.mapDivDocument!.querySelector(
441
+ '[data-i18n="html.app_loading_body"], [din="html.app_loading_body"]'
442
+ );
443
+ if (appLoadingBody) {
444
+ (appLoadingBody as HTMLElement).innerHTML = imageExtractor(
445
+ ui.core!.t("html.app_loading_body")
446
+ );
447
+ }
448
+
449
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
450
+ const options: any = {
451
+ reverse: true,
452
+ tipLabel: ui.core!.t("control.trans", { ns: "translation" })
453
+ };
454
+ if (restoreTransparency) {
455
+ options.initialValue = restoreTransparency / 100;
456
+ }
457
+ ui.sliderNew = new SliderNew(options);
458
+ ui.core!.appData!.controls = [
459
+ new Copyright({
460
+ tipLabel: ui.core!.t("control.info", { ns: "translation" })
461
+ }),
462
+ new CompassRotate({
463
+ tipLabel: ui.core!.t("control.compass", { ns: "translation" })
464
+ }),
465
+ new Zoom({
466
+ tipLabel: ui.core!.t("control.zoom", { ns: "translation" })
467
+ }),
468
+ new SetGPS({
469
+ ui,
470
+ tipLabel: ui.core!.t("control.gps", { ns: "translation" })
471
+ }),
472
+ new GoHome({
473
+ tipLabel: ui.core!.t("control.home", { ns: "translation" })
474
+ }),
475
+ ui.sliderNew,
476
+ new Maplat({
477
+ tipLabel: ui.core!.t("control.help", { ns: "translation" })
478
+ })
479
+ ];
480
+ if (ui.enableShare) {
481
+ ui.core!.appData!.controls.push(
482
+ new Share({
483
+ tipLabel: ui.core!.t("control.share", { ns: "translation" })
484
+ })
485
+ );
486
+ }
487
+ if (ui.enableBorder) {
488
+ ui.core!.appData!.controls.push(
489
+ new Border({
490
+ tipLabel: ui.core!.t("control.border", { ns: "translation" })
491
+ })
492
+ );
493
+ }
494
+ if (ui.enableHideMarker) {
495
+ ui.core!.appData!.controls.push(
496
+ new HideMarker({
497
+ tipLabel: ui.core!.t("control.hide_marker", { ns: "translation" })
498
+ })
499
+ );
500
+ }
501
+ if (ui.enableMarkerList) {
502
+ ui.core!.appData!.controls.push(
503
+ new MarkerList({
504
+ tipLabel: ui.core!.t("control.marker_list", { ns: "translation" })
505
+ })
506
+ );
507
+ }
508
+
509
+ // Contextmenu
510
+ ui.contextMenu = new ContextMenu({
511
+ eventType: "__dummy__",
512
+ width: 170,
513
+ defaultItems: false,
514
+ items: []
515
+ });
516
+ ui.core!.appData!.controls.push(ui.contextMenu);
517
+
518
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
519
+ ui.sliderNew.on("propertychange", (evt: any) => {
520
+ if (evt.key === "slidervalue") {
521
+ ui.core!.setTransparency(ui.sliderNew.get(evt.key) * 100);
522
+ ui.updateUrl();
523
+ }
524
+ });
525
+
526
+ if (enableSplash) {
527
+ // Check Splash data
528
+ let splash = false;
529
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
530
+ if ((ui.core!.appData as any).splash) splash = true;
531
+
532
+ const modalElm = ui.core!.mapDivDocument!.querySelector(".modalBase")!;
533
+ const modal = new bsn.Modal(modalElm, { root: ui.core!.mapDivDocument! });
534
+ (
535
+ ui.core!.mapDivDocument!.querySelector(
536
+ ".modal_load_title"
537
+ ) as HTMLElement
538
+ ).innerText = ui.core!.translate(ui.core!.appData!.appName) || "";
539
+ if (splash) {
540
+ ui.core!.mapDivDocument!.querySelector(".splash_img")!
541
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
542
+ .setAttribute("src", `img/${(ui.core!.appData as any).splash}`);
543
+ ui.core!.mapDivDocument!.querySelector(".splash_div")!.classList.remove(
544
+ "hide"
545
+ );
546
+ }
547
+ ui.modalSetting("load");
548
+ modal.show();
549
+
550
+ const fadeTime = splash ? 1000 : 200;
551
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
552
+ ui.splashPromise = new Promise((resolve: any) => {
553
+ setTimeout(() => {
554
+ resolve();
555
+ }, fadeTime);
556
+ });
557
+ }
558
+
559
+ document.querySelector("title")!.innerHTML =
560
+ ui.core!.translate(ui.core!.appName) || "";
561
+ });
562
+
563
+ ui.core!.addEventListener("mapChanged", (evt: unknown) => {
564
+ const map = (evt as CustomEvent).detail;
565
+
566
+ ui.baseSwiper.setSlideMapID(map.mapID);
567
+ ui.overlaySwiper.setSlideMapID(map.mapID);
568
+
569
+ const title = map.officialTitle || map.title || map.label;
570
+ (
571
+ ui.core!.mapDivDocument!.querySelector(".map-title span") as HTMLElement
572
+ ).innerText = ui.core!.translate(title) || "";
573
+
574
+ if (ui.checkOverlayID(map.mapID)) {
575
+ ui.sliderNew.setEnable(true);
576
+ } else {
577
+ ui.sliderNew.setEnable(false);
578
+ }
579
+ const transparency = ui.sliderNew.get("slidervalue") * 100;
580
+ ui.core!.mapObject.setTransparency(transparency);
581
+
582
+ ui.updateEnvelope();
583
+ ui.updateUrl();
584
+ });
585
+
586
+ ui.core!.addEventListener("poi_number", (evt: unknown) => {
587
+ const number = (evt as CustomEvent).detail;
588
+ if (number) {
589
+ ui.core!.mapDivDocument!.classList.remove("no_poi");
590
+ } else {
591
+ ui.core!.mapDivDocument!.classList.add("no_poi");
592
+ }
593
+ });
594
+
595
+ ui.core!.addEventListener("outOfMap", (_evt: unknown) => {
596
+ console.log("Event: outOfMap");
597
+ if (enableOutOfMap) {
598
+ (
599
+ ui.core!.mapDivDocument!.querySelector(".modal_title") as HTMLElement
600
+ ).innerText = ui.core!.t("app.out_of_map") || "";
601
+ (
602
+ ui.core!.mapDivDocument!.querySelector(
603
+ ".modal_gpsD_content"
604
+ ) as HTMLElement
605
+ ).innerText = ui.core!.t("app.out_of_map_area") || "";
606
+ const modalElm = ui.core!.mapDivDocument!.querySelector(".modalBase")!;
607
+ const modal =
608
+ bsn.Modal.getInstance(modalElm) ||
609
+ new bsn.Modal(modalElm, { root: ui.core!.mapDivDocument! });
610
+
611
+ const closeBtns = modalElm.querySelectorAll(
612
+ ".close, .modal-footer button"
613
+ );
614
+ for (let i = 0; i < closeBtns.length; i++) {
615
+ closeBtns[i].addEventListener("click", () => {
616
+ modal.hide();
617
+ });
618
+ }
619
+
620
+ ui.modalSetting("gpsD");
621
+ modal.show();
622
+ }
623
+ });
624
+
625
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
626
+ ui.core!.addEventListener("gps_error", (evt: any) => {
627
+ console.log("GPS Error:", evt);
628
+ const errorMap: Record<string, string> = {
629
+ user_gps_deny: "app.user_gps_deny",
630
+ gps_miss: "app.gps_miss",
631
+ gps_timeout: "app.gps_timeout"
632
+ };
633
+
634
+ if (!ui.core) return;
635
+ (ui.core.mapDivDocument!.querySelector(
636
+ ".modal_title"
637
+ ) as HTMLElement)!.innerText = ui.core.t("app.gps_error") || "";
638
+ (ui.core.mapDivDocument!.querySelector(
639
+ ".modal_gpsD_content"
640
+ ) as HTMLElement)!.innerText =
641
+ ui.core.t(errorMap[evt.detail] || "app.gps_error") || "";
642
+ const modalElm = ui.core.mapDivDocument!.querySelector(".modalBase")!;
643
+ const modal =
644
+ bsn.Modal.getInstance(modalElm) ||
645
+ new bsn.Modal(modalElm, {
646
+ root: ui.core.mapDivDocument
647
+ });
648
+
649
+ const closeBtns = modalElm.querySelectorAll(".close, .modal-footer button");
650
+ for (let i = 0; i < closeBtns.length; i++) {
651
+ closeBtns[i].addEventListener("click", () => {
652
+ modal.hide();
653
+ });
654
+ }
655
+
656
+ ui.modalSetting("gpsD");
657
+ modal.show();
658
+ });
659
+
660
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
661
+ ui.core!.addEventListener("gps_result", (evt: any) => {
662
+ console.log("GPS Result:", evt);
663
+ if (evt.detail && evt.detail.error) {
664
+ const error = evt.detail.error;
665
+ if (error === "gps_off") {
666
+ ui.lastGPSError = undefined;
667
+ return;
668
+ }
669
+
670
+ ui.lastGPSError = error;
671
+ if (ui.alwaysGpsOn && error === "gps_out") return;
672
+
673
+ if (!ui.core) return;
674
+
675
+ const modalElm = ui.core.mapDivDocument!.querySelector(".modalBase")!;
676
+ const modal =
677
+ bsn.Modal.getInstance(modalElm) ||
678
+ new bsn.Modal(modalElm, {
679
+ root: ui.core.mapDivDocument
680
+ });
681
+
682
+ const closeBtns = modalElm.querySelectorAll(
683
+ ".close, .modal-footer button"
684
+ );
685
+ for (let i = 0; i < closeBtns.length; i++) {
686
+ closeBtns[i].addEventListener("click", () => {
687
+ modal.hide();
688
+ });
689
+ }
690
+
691
+ if (error === "gps_out") {
692
+ (ui.core.mapDivDocument!.querySelector(
693
+ ".modal_title"
694
+ ) as HTMLElement)!.innerText = ui.core.t("app.out_of_map") || "";
695
+ (ui.core.mapDivDocument!.querySelector(
696
+ ".modal_gpsD_content"
697
+ ) as HTMLElement)!.innerText = ui.core.t("app.out_of_map_area") || "";
698
+ } else {
699
+ const errorMap: Record<string, string> = {
700
+ user_gps_deny: "app.user_gps_deny",
701
+ gps_miss: "app.gps_miss",
702
+ gps_timeout: "app.gps_timeout"
703
+ };
704
+
705
+ (ui.core.mapDivDocument!.querySelector(
706
+ ".modal_title"
707
+ ) as HTMLElement)!.innerText = ui.core.t("app.gps_error") || "";
708
+ (ui.core.mapDivDocument!.querySelector(
709
+ ".modal_gpsD_content"
710
+ ) as HTMLElement)!.innerText =
711
+ ui.core.t(errorMap[error] || "app.gps_error") || "";
712
+ }
713
+
714
+ ui.modalSetting("gpsD");
715
+ modal.show();
716
+ } else {
717
+ ui.lastGPSError = undefined;
718
+ }
719
+ });
720
+
721
+ ui.core!.addEventListener("sourceLoaded", (evt: unknown) => {
722
+ const sources = (evt as CustomEvent).detail;
723
+ const colors = [
724
+ "maroon",
725
+ "deeppink",
726
+ "indigo",
727
+ "olive",
728
+ "royalblue",
729
+ "red",
730
+ "hotpink",
731
+ "green",
732
+ "yellow",
733
+ "navy",
734
+ "saddlebrown",
735
+ "fuchsia",
736
+ "darkslategray",
737
+ "yellowgreen",
738
+ "blue",
739
+ "mediumvioletred",
740
+ "purple",
741
+ "lime",
742
+ "darkorange",
743
+ "teal",
744
+ "crimson",
745
+ "darkviolet",
746
+ "darkolivegreen",
747
+ "steelblue",
748
+ "aqua"
749
+ ];
750
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
751
+ const appBbox: any[] = [];
752
+ let cIndex = 0;
753
+
754
+ for (let i = 0; i < sources.length; i++) {
755
+ const source = sources[i];
756
+ if (source.envelope) {
757
+ if (ui.appEnvelope) {
758
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
759
+ source.envelope.geometry.coordinates[0].map((xy: any) => {
760
+ if (appBbox.length === 0) {
761
+ appBbox[0] = appBbox[2] = xy[0];
762
+ appBbox[1] = appBbox[3] = xy[1];
763
+ } else {
764
+ if (xy[0] < appBbox[0]) appBbox[0] = xy[0];
765
+ if (xy[0] > appBbox[2]) appBbox[2] = xy[0];
766
+
767
+ if (xy[1] < appBbox[1]) appBbox[1] = xy[1];
768
+ if (xy[1] > appBbox[3]) appBbox[3] = xy[1];
769
+ }
770
+ });
771
+ }
772
+ source.envelopeColor = colors[cIndex];
773
+ cIndex++;
774
+ if (cIndex === colors.length) cIndex = 0;
775
+
776
+ const xys = source.envelope.geometry.coordinates[0];
777
+ source.envelopeAreaIndex = ui.areaIndex(xys);
778
+ }
779
+ }
780
+ if (ui.appEnvelope) console.log(`This app's envelope is: ${appBbox}`);
781
+
782
+ if (ui.splashPromise) {
783
+ ui.splashPromise.then(() => {
784
+ const modalElm = ui.core!.mapDivDocument!.querySelector(".modalBase")!;
785
+ const modal =
786
+ bsn.Modal.getInstance(modalElm) ||
787
+ new bsn.Modal(modalElm, { root: ui.core!.mapDivDocument! });
788
+ ui.modalSetting("load");
789
+ modal.hide();
790
+ });
791
+ }
792
+
793
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
794
+ const baseSources: any[] = [];
795
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
796
+ const overlaySources: any[] = [];
797
+ for (let i = 0; i < sources.length; i++) {
798
+ const source = sources[i];
799
+ if (isBasemap(source)) {
800
+ baseSources.push(source);
801
+ } else {
802
+ overlaySources.push(source);
803
+ }
804
+ }
805
+
806
+ const baseSwiper = (ui.baseSwiper = new Swiper(".base-swiper", {
807
+ slidesPerView: 2,
808
+ spaceBetween: 15,
809
+ breakpoints: {
810
+ 480: {
811
+ slidesPerView: 1.4,
812
+ spaceBetween: 10
813
+ }
814
+ },
815
+ centeredSlides: true,
816
+ threshold: 2,
817
+ preventClicks: true,
818
+ preventClicksPropagation: true,
819
+ observer: true,
820
+ observeParents: true,
821
+ loop: baseSources.length >= 2,
822
+ navigation: {
823
+ nextEl: ".base-next",
824
+ prevEl: ".base-prev"
825
+ }
826
+ }));
827
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
828
+ baseSwiper.on("click", (_e: any) => {
829
+ if (!baseSwiper.clickedSlide) return;
830
+ const slide = baseSwiper.clickedSlide;
831
+ ui.core!.changeMap(slide.getAttribute("data")!);
832
+ delete ui._selectCandidateSources;
833
+ baseSwiper.setSlideIndexAsSelected(
834
+ parseInt(slide.getAttribute("data-swiper-slide-index") || "0", 10)
835
+ );
836
+ });
837
+ if (baseSources.length < 2) {
838
+ ui.core!.mapDivDocument!.querySelector(".base-swiper")!.classList.add(
839
+ "single-map"
840
+ );
841
+ }
842
+
843
+ const overlaySwiper = (ui.overlaySwiper = new Swiper(".overlay-swiper", {
844
+ slidesPerView: 2,
845
+ spaceBetween: 15,
846
+ breakpoints: {
847
+ 480: {
848
+ slidesPerView: 1.4,
849
+ spaceBetween: 10
850
+ }
851
+ },
852
+ centeredSlides: true,
853
+ threshold: 2,
854
+ preventClicks: true,
855
+ preventClicksPropagation: true,
856
+ observer: true,
857
+ observeParents: true,
858
+ loop: overlaySources.length >= 2,
859
+ navigation: {
860
+ nextEl: ".overlay-next",
861
+ prevEl: ".overlay-prev"
862
+ }
863
+ }));
864
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
865
+ overlaySwiper.on("click", (_e: any) => {
866
+ if (!overlaySwiper.clickedSlide) return;
867
+ const slide = overlaySwiper.clickedSlide;
868
+ ui.core!.changeMap(slide.getAttribute("data")!);
869
+ delete ui._selectCandidateSources;
870
+ overlaySwiper.setSlideIndexAsSelected(
871
+ parseInt(slide.getAttribute("data-swiper-slide-index") || "0", 10)
872
+ );
873
+ });
874
+ if (overlaySources.length < 2) {
875
+ ui.core!.mapDivDocument!.querySelector(".overlay-swiper")!.classList.add(
876
+ "single-map"
877
+ );
878
+ }
879
+
880
+ for (let i = 0; i < baseSources.length; i++) {
881
+ const source = baseSources[i];
882
+ const thumbKey = source.thumbnail
883
+ ? source.thumbnail.split("/").pop()
884
+ : "";
885
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
886
+ const thumbUrl = (pointer as any)[thumbKey] || source.thumbnail;
887
+ baseSwiper.appendSlide(
888
+ `<div class="swiper-slide" data="${source.mapID}">` +
889
+ `<img crossorigin="anonymous" src="${
890
+ thumbUrl
891
+ }"><div> ${ui.core!.translate(source.label)}</div> </div> `
892
+ );
893
+ }
894
+ for (let i = 0; i < overlaySources.length; i++) {
895
+ const source = overlaySources[i];
896
+ const colorCss = source.envelope ? ` ${source.envelopeColor}` : "";
897
+ const thumbKey = source.thumbnail
898
+ ? source.thumbnail.split("/").pop()
899
+ : "";
900
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
901
+ const thumbUrl = (pointer as any)[thumbKey] || source.thumbnail;
902
+ overlaySwiper.appendSlide(
903
+ `<div class="swiper-slide${colorCss}" data="${source.mapID}">` +
904
+ `<img crossorigin="anonymous" src="${
905
+ thumbUrl
906
+ }"><div> ${ui.core!.translate(source.label)}</div> </div> `
907
+ );
908
+ }
909
+
910
+ overlaySwiper.on("slideChange", () => {
911
+ ui.updateEnvelope();
912
+ });
913
+
914
+ baseSwiper.slideToLoop(0);
915
+ overlaySwiper.slideToLoop(0);
916
+ ellips(ui.core!.mapDivDocument!);
917
+ });
918
+
919
+ ui.core!.waitReady.then(() => {
920
+ // Capture pointerdown at viewport level to ensure we get pixel before any stopPropagation
921
+
922
+ ui.core!.mapObject.getViewport().addEventListener(
923
+ "pointerdown",
924
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
925
+ (evt: any) => {
926
+ ui.lastClickPixel = ui.core!.mapObject.getEventPixel(evt);
927
+ ui.lastClickCoordinate = ui.core!.mapObject.getCoordinateFromPixel(
928
+ ui.lastClickPixel
929
+ );
930
+ },
931
+ true
932
+ );
933
+ });
934
+
935
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
936
+ ui.core!.addEventListener("clickMarkers", (evt: any) => {
937
+ const data = evt.detail;
938
+ if (data.length === 1) {
939
+ ui.handleMarkerAction(data[0]);
940
+ } else {
941
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
942
+ const list: any[] = [];
943
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
944
+ data.forEach((datum: any) => {
945
+ list.push({
946
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
947
+ icon: datum.icon || (pointer as any)["defaultpin.png"],
948
+ text: ui.core!.translate(datum.name),
949
+ callback: () => {
950
+ ui.handleMarkerAction(datum);
951
+ }
952
+ });
953
+ });
954
+ ui.showContextMenu(list);
955
+ }
956
+ });
957
+
958
+ ui.core!.waitReady.then(() => {
959
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
960
+ ui.core!.mapObject.on("click_control", (evt: any) => {
961
+ const control = evt.control || (evt.frameState && evt.frameState.control);
962
+ const modalElm = ui.core!.mapDivDocument!.querySelector(".modalBase")!;
963
+ const modal = bsn.Modal.getInstance(modalElm) || new bsn.Modal(modalElm);
964
+
965
+ const closeBtns = modalElm.querySelectorAll(
966
+ ".close, .modal-footer button"
967
+ );
968
+ for (let i = 0; i < closeBtns.length; i++) {
969
+ closeBtns[i].addEventListener("click", () => {
970
+ modal.hide();
971
+ });
972
+ }
973
+
974
+ if (control === "help") {
975
+ ui.modalSetting("help");
976
+ modal.show();
977
+ } else if (control === "share") {
978
+ ui.modalSetting("share");
979
+
980
+ const modalBody = modalElm.querySelector(".modal-body") as HTMLElement;
981
+
982
+ const baseUrl = ui.getShareUrl("app");
983
+ const viewUrl = ui.getShareUrl("view");
984
+
985
+ // Generate QR Codes
986
+ const qrAppDiv = modalBody.querySelector(".qr_app") as HTMLElement;
987
+ const qrViewDiv = modalBody.querySelector(".qr_view") as HTMLElement;
988
+
989
+ if (qrAppDiv) {
990
+ QRCode.toCanvas(
991
+ baseUrl,
992
+ { width: 128, margin: 1 },
993
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
994
+ (err: any, canvas: any) => {
995
+ if (!err) {
996
+ qrAppDiv.innerHTML = "";
997
+ qrAppDiv.appendChild(canvas);
998
+ }
999
+ }
1000
+ );
1001
+ }
1002
+ if (qrViewDiv) {
1003
+ QRCode.toCanvas(
1004
+ viewUrl,
1005
+ { width: 128, margin: 1 },
1006
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1007
+ (err: any, canvas: any) => {
1008
+ if (!err) {
1009
+ qrViewDiv.innerHTML = "";
1010
+ qrViewDiv.appendChild(canvas);
1011
+ }
1012
+ }
1013
+ );
1014
+ }
1015
+
1016
+ modal.show();
1017
+ } else if (control === "markerList") {
1018
+ ui.modalSetting("marker_list");
1019
+ modal.show();
1020
+
1021
+ const listRoot = modalElm.querySelector(
1022
+ ".modal_marker_list_content ul.list-group"
1023
+ ) as HTMLElement;
1024
+ listRoot.innerHTML = "";
1025
+
1026
+ const layers = ui.core!.listPoiLayers(false, true);
1027
+
1028
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1029
+ layers.forEach((layer: any) => {
1030
+ // Create Layer Item
1031
+ const layerLi = createElement(`<li class="list-group-item layer">
1032
+ <div class="row layer_row">
1033
+ <div class="layer_label">
1034
+ <span class="dli-chevron"></span>
1035
+ <img src="${layer.icon || pointer["defaultpin.png"]}" class="markerlist"> ${ui.core!.translate(layer.name)}
1036
+ </div>
1037
+ <div class="layer_onoff">
1038
+ <input type="checkbox" class="markerlist" ${layer.hide ? "" : "checked"}>
1039
+ <label class="check"><div></div></label>
1040
+ </div>
1041
+ </div>
1042
+ </li>`)[0] as HTMLElement;
1043
+
1044
+ const checkbox = layerLi.querySelector(
1045
+ "input[type=checkbox]"
1046
+ ) as HTMLInputElement;
1047
+ const label = layerLi.querySelector("label.check") as HTMLElement;
1048
+
1049
+ label.addEventListener("click", e => {
1050
+ e.stopPropagation();
1051
+ if (!checkbox.disabled) {
1052
+ checkbox.checked = !checkbox.checked;
1053
+ checkbox.dispatchEvent(new Event("change"));
1054
+ }
1055
+ });
1056
+
1057
+ checkbox.addEventListener("click", e => e.stopPropagation());
1058
+
1059
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1060
+ checkbox.addEventListener("change", (e: any) => {
1061
+ if (e.target.checked) {
1062
+ ui.core!.showPoiLayer(layer.id);
1063
+ } else {
1064
+ ui.core!.hidePoiLayer(layer.id);
1065
+ }
1066
+ });
1067
+
1068
+ const poiListUl = createElement(
1069
+ `<ul class="list_poiitems_div"></ul>`
1070
+ )[0] as HTMLElement;
1071
+
1072
+ layerLi
1073
+ .querySelector(".layer_label")!
1074
+ .addEventListener("click", () => {
1075
+ poiListUl.classList.toggle("open");
1076
+ });
1077
+
1078
+ listRoot.appendChild(layerLi);
1079
+ listRoot.appendChild(poiListUl);
1080
+
1081
+ if (layer.pois) {
1082
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1083
+ layer.pois.forEach((poi: any) => {
1084
+ const poiLi = createElement(`<li class="list-group-item poi">
1085
+ <div class="row poi_row">
1086
+ <div class="poi_label">
1087
+ <span class="dli-chevron"></span>
1088
+ <img src="${poi.icon || layer.icon || pointer["defaultpin.png"]}" class="markerlist"> ${ui.core!.translate(poi.name)}
1089
+ </div>
1090
+ </div>
1091
+ </li>`)[0] as HTMLElement;
1092
+
1093
+ const poiContentDiv = createElement(
1094
+ `<div class="list_poicontent_div"></div>`
1095
+ )[0] as HTMLElement;
1096
+
1097
+ // let poiImgHide: any;
1098
+
1099
+ poiLi.addEventListener("click", () => {
1100
+ if (!poiContentDiv.classList.contains("open")) {
1101
+ poiContentDiv.classList.add("open");
1102
+
1103
+ poiWebControl(ui, poiContentDiv, poi);
1104
+
1105
+ ui.core!.selectMarker?.(poi.namespaceID);
1106
+ } else {
1107
+ poiContentDiv.classList.remove("open");
1108
+
1109
+ // if (poiImgHide) poiImgHide();
1110
+ poiContentDiv.innerHTML = "";
1111
+ ui.core!.unselectMarker?.();
1112
+ }
1113
+ });
1114
+
1115
+ poiListUl.appendChild(poiLi);
1116
+ poiListUl.appendChild(poiContentDiv);
1117
+ });
1118
+ }
1119
+ });
1120
+ } else if (control === "copyright") {
1121
+ ui.modalSetting("map");
1122
+ const mapData = ui.core!.from!;
1123
+ const modalRoot = ui.core!.mapDivDocument!;
1124
+ const titleEl = modalRoot.querySelector(".modal_map .modal_title");
1125
+ if (titleEl) {
1126
+ const titleVal = mapData.get ? mapData.get("title") : mapData.title;
1127
+ (titleEl as HTMLElement).innerText =
1128
+ ui.core!.translate(titleVal) || "";
1129
+ }
1130
+
1131
+ META_KEYS.forEach(key => {
1132
+ if (key === "title" || key === "officialTitle") return;
1133
+ const val = mapData.get
1134
+ ? mapData.get(key)
1135
+ : // eslint-disable-next-line @typescript-eslint/no-explicit-any
1136
+ (mapData as any)[key];
1137
+ const container = modalRoot.querySelector(`.modal_map .${key}_div`);
1138
+ if (container) {
1139
+ if (val) {
1140
+ (container as HTMLElement).style.display = "block";
1141
+ const contentEl = container.querySelector(`.${key}_dd`);
1142
+ if (contentEl) {
1143
+ if (key === "license" || key === "dataLicense") {
1144
+ const fileName = (val as string)
1145
+ .toLowerCase()
1146
+ .replace(/ /g, "_");
1147
+ (contentEl as HTMLElement).innerHTML =
1148
+ `<img src="assets/parts/${fileName}.png" class="license" />`;
1149
+ } else {
1150
+ (contentEl as HTMLElement).innerHTML =
1151
+ ui.core!.translate(val) || "";
1152
+ }
1153
+ }
1154
+ } else {
1155
+ (container as HTMLElement).style.display = "none";
1156
+ }
1157
+ }
1158
+ });
1159
+ modal.show();
1160
+ } else if (control === "border") {
1161
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1162
+ ui.setShowBorder(!(ui.core!.stateBuffer as any).showBorder);
1163
+ } else if (control === "hideMarker") {
1164
+ const current =
1165
+ ui.core!.mapDivDocument!.classList.contains("hide-marker");
1166
+ ui.setHideMarker(!current);
1167
+ }
1168
+ ui.updateUrl();
1169
+ });
1170
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1171
+ ui.core!.mapObject.on("moveend", (_evt: any) => {
1172
+ ui.updateUrl();
1173
+ });
1174
+ });
1175
+ }