@maplat/ui 0.11.4 → 0.11.5

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.
@@ -1,9 +1,9 @@
1
1
  import { MaplatUi } from './index';
2
2
  import { MarkerData } from './types';
3
- export declare function poiWebControl(ui: MaplatUi, div: HTMLElement, data: MarkerData): undefined;
3
+ export declare function poiWebControl(ui: MaplatUi, div: HTMLElement, data: MarkerData, showShare?: boolean): undefined;
4
4
  export declare function handleMarkerAction(ui: MaplatUi, data: MarkerData): void;
5
5
  export declare function showContextMenu(ui: MaplatUi, list: MarkerData[]): void;
6
6
  export declare function xyToMapIDs(ui: MaplatUi, xy: any, threshold?: number): Promise<any>;
7
7
  export declare function setHideMarker(ui: MaplatUi, flag: boolean): void;
8
8
  export declare function checkOverlayID(ui: MaplatUi, mapID: string): boolean;
9
- export declare function handleMarkerActionById(_ui: MaplatUi, markerId: string): void;
9
+ export declare function handleMarkerActionById(ui: MaplatUi, markerId: string): void;
@@ -87,6 +87,7 @@ li:has(+ .open) .dli-chevron {
87
87
 
88
88
  .modal_cache_content,
89
89
  .modal_share_pos,
90
+ .modal_share_state,
90
91
  .share_help,
91
92
  .border_help,
92
93
  .hide_marker_help,
@@ -95,6 +96,7 @@ li:has(+ .open) .dli-chevron {
95
96
  }
96
97
 
97
98
  &.enable_cache .modal_cache_content,
99
+ &.state_url .modal_share_state,
98
100
  &.state_url .modal_share_pos {
99
101
  display: block;
100
102
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@maplat/ui",
3
- "version": "0.11.4",
3
+ "version": "0.11.5",
4
4
  "description": "Maplat is the cool Historical Map/Illustrated Map Viewer.\nIt can transform each map coordinates with nonlinear but homeomorphic projection and makes possible that the maps can collaborate with GPS/accurate maps, without distorting original maps.",
5
5
  "type": "module",
6
6
  "main": "dist/maplat-ui.umd.js",
@@ -36,7 +36,7 @@
36
36
  "dependencies": {
37
37
  "@c4h/chuci": "0.2.4",
38
38
  "@c4h/weiwudi": "^0.2.0",
39
- "@maplat/core": "0.12.2",
39
+ "@maplat/core": "0.12.3",
40
40
  "@turf/turf": "^7.3.1",
41
41
  "@types/page": "^1.11.9",
42
42
  "bootstrap.native": "^5.1.6",
@@ -62,10 +62,9 @@ export default class Base extends Control {
62
62
  * Remove all elements from the menu.
63
63
  */
64
64
  clear() {
65
- Object.keys(this.Internal.items).forEach(
66
- this.Html.removeMenuEntry,
67
- this.Html
68
- );
65
+ for (const key of Object.keys(this.Internal.items)) {
66
+ this.Html.removeMenuEntry(key);
67
+ }
69
68
  }
70
69
 
71
70
  /**
@@ -33,7 +33,7 @@ export function assert(
33
33
  * @returns Boolean
34
34
  */
35
35
  export function contains(str_test: string, str: string) {
36
- return !!~str.indexOf(str_test);
36
+ return str.includes(str_test);
37
37
  }
38
38
 
39
39
  export function getUniqueId(prefix: string = "id_") {
@@ -100,21 +100,20 @@ export function emptyArray(array: unknown[]) {
100
100
  }
101
101
 
102
102
  export function anyMatchInArray(source: unknown[], target: unknown[]) {
103
- return source.some((each: unknown) => target.indexOf(each) >= 0);
103
+ return source.some((each: unknown) => target.includes(each));
104
104
  }
105
105
 
106
106
  export function everyMatchInArray(arr1: unknown[], arr2: unknown[]) {
107
- return arr2.every((each: unknown) => arr1.indexOf(each) >= 0);
107
+ return arr2.every((each: unknown) => arr1.includes(each));
108
108
  }
109
109
 
110
110
  export function anyItemHasValue(
111
111
  obj: Record<string, unknown>,
112
112
  has: boolean = false
113
113
  ) {
114
- const keys = Object.keys(obj);
115
- keys.forEach(key => {
114
+ for (const key of Object.keys(obj)) {
116
115
  const value = obj[key];
117
116
  if (!isEmpty(typeof value === "string" ? value : null)) has = true;
118
- });
117
+ }
119
118
  return has;
120
119
  }
@@ -97,7 +97,7 @@ export class Html {
97
97
  if (cItem.icon) {
98
98
  if (cItem.classname === "") {
99
99
  cItem.classname = CSS_VARS.icon;
100
- } else if (cItem.classname.indexOf(CSS_VARS.icon) === -1) {
100
+ } else if (!cItem.classname.includes(CSS_VARS.icon)) {
101
101
  cItem.classname += ` ${CSS_VARS.icon}`;
102
102
  }
103
103
  element.setAttribute("style", `background-image:url(${cItem.icon})`);
@@ -102,10 +102,10 @@ export class Internal {
102
102
 
103
103
  getItemsLength() {
104
104
  let count = 0;
105
- Object.keys(this.items).forEach(k => {
106
- if (this.items[k].submenu || this.items[k].separator) return;
105
+ for (const k of Object.keys(this.items)) {
106
+ if (this.items[k].submenu || this.items[k].separator) continue;
107
107
  count++;
108
- });
108
+ }
109
109
  return count;
110
110
  }
111
111
 
package/src/index.ts CHANGED
@@ -75,6 +75,7 @@ export class MaplatUi extends EventTarget {
75
75
  lastClickPixel: Pixel | undefined;
76
76
  lastClickCoordinate: Coordinate | undefined;
77
77
  lastGPSError: string | undefined;
78
+ selectedMarkerNamespaceID: string | undefined;
78
79
 
79
80
  constructor(appOption: MaplatAppOption) {
80
81
  super();
@@ -86,9 +87,6 @@ export class MaplatUi extends EventTarget {
86
87
  page((ctx: any, _next: any) => {
87
88
  let pathes = ctx.canonicalPath.split("#!");
88
89
  let path = pathes.length > 1 ? pathes[1] : pathes[0];
89
- console.log(
90
- `[Debug] Page callback.Canonical: ${ctx.canonicalPath}, Path: ${path} `
91
- );
92
90
 
93
91
  pathes = path.split("?");
94
92
  path = pathes[0];
@@ -107,7 +105,6 @@ export class MaplatUi extends EventTarget {
107
105
  path.split("/").forEach((state: any) => {
108
106
  if (!state) return;
109
107
  const line = state.split(":");
110
- console.log(`[Debug] Parsing state: ${state} `, line);
111
108
  switch (line[0]) {
112
109
  case "s":
113
110
  restore.mapID = line[1];
@@ -159,44 +156,17 @@ export class MaplatUi extends EventTarget {
159
156
  });
160
157
  if (!this.core) {
161
158
  if (restore.mapID) {
162
- console.log(
163
- `[Debug] Init with restore: `,
164
- JSON.parse(JSON.stringify(restore))
165
- );
166
159
  appOption.restore = restore;
167
160
  this.restoring = true;
168
161
  }
169
- const preRot = restore.position
170
- ? restore.position.rotation
171
- : "undefined";
172
- console.log(`[Debug] Before initializer: rotation = ${preRot} `);
173
162
 
174
163
  this.initializer(appOption).then(() => {
175
164
  this.core!.waitReady.then(() => {
176
- // Fix: Manually apply rotation as Core 0.11.1 preserves it but fails to apply it view-side
177
- // if (restore.position && restore.position.rotation !== undefined) {
178
- // console.log(`[Debug] Manually applying rotation: ${ restore.position.rotation } `);
179
- // this.core!.mapObject.getView().setRotation(restore.position.rotation);
180
- // }
181
- // Fix: Verify transparency state before updating URL
182
- if (this.sliderNew) {
183
- // Ensure map transparency matches restore if slider is ready
184
- const currentTrans = this.sliderNew.get("slidervalue") * 100;
185
- console.log(`[Debug] Slider transparency: ${currentTrans} `);
186
- } else {
187
- console.log(`[Debug] Slider not ready yet`);
188
- }
189
-
190
165
  this.restoring = false;
191
- console.log(`[Debug] Calling updateUrl from Init`);
192
166
  this.updateUrl();
193
167
  });
194
168
  });
195
169
  } else if (restore.mapID) {
196
- console.log(
197
- `[Debug] ChangeMap with restore: `,
198
- JSON.parse(JSON.stringify(restore))
199
- );
200
170
  this.restoring = true;
201
171
 
202
172
  this.core!.waitReady.then(() => {
@@ -343,6 +313,11 @@ export class MaplatUi extends EventTarget {
343
313
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
344
314
  path += `/om:${(this.core!.stateBuffer as any).markerList}`;
345
315
 
316
+ // Add selected marker to URL
317
+ if (this.selectedMarkerNamespaceID) {
318
+ path += `/om:${this.selectedMarkerNamespaceID}`;
319
+ }
320
+
346
321
  if (this.pathThatSet !== path) {
347
322
  this.pathThatSet = path;
348
323
  page(`#!${path}`);
@@ -354,7 +329,7 @@ export class MaplatUi extends EventTarget {
354
329
 
355
330
  this.core!.mapObject.resetEnvelope();
356
331
  if (this._selectCandidateSources) {
357
- Object.keys(this._selectCandidateSources).forEach(key => {
332
+ for (const key of Object.keys(this._selectCandidateSources)) {
358
333
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
359
334
  if ((this.core!.mapObject as any).removeEnvelope) {
360
335
  console.log(`[Debug] Removing envelope for ${key}`);
@@ -363,7 +338,7 @@ export class MaplatUi extends EventTarget {
363
338
  this._selectCandidateSources![key]
364
339
  );
365
340
  }
366
- });
341
+ }
367
342
  }
368
343
 
369
344
  this._selectCandidateSources = {};
@@ -45,12 +45,12 @@ function hexRgb(hex: string) {
45
45
 
46
46
  export function setControlSettings(options: Record<string, string>) {
47
47
  control_settings = options;
48
- Object.keys(control_settings).forEach(key => {
48
+ for (const key of Object.keys(control_settings)) {
49
49
  if (delegator[key]) {
50
50
  (pointer as Record<string, string>)[delegator[key]] =
51
51
  control_settings[key];
52
52
  }
53
- });
53
+ }
54
54
  }
55
55
 
56
56
  export class SliderNew extends Control {
package/src/ui_init.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { MaplatApp as Core, createElement } from "@maplat/core";
1
+ import { MaplatApp as Core, createElement, MaplatApp } from "@maplat/core";
2
2
 
3
3
  import pointer from "./pointer_images";
4
4
  import { Swiper } from "./swiper_ex";
@@ -286,14 +286,13 @@ function initSwipers(ui: MaplatUi, sources: any[]) {
286
286
  const baseSources: any[] = [];
287
287
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
288
288
  const overlaySources: any[] = [];
289
- for (let i = 0; i < sources.length; i++) {
290
- const source = sources[i];
289
+ sources.forEach(source => {
291
290
  if (isBasemap(source)) {
292
291
  baseSources.push(source);
293
292
  } else {
294
293
  overlaySources.push(source);
295
294
  }
296
- }
295
+ });
297
296
 
298
297
  const baseSwiper = (ui.baseSwiper = new Swiper(".base-swiper", {
299
298
  slidesPerView: 2,
@@ -369,8 +368,7 @@ function initSwipers(ui: MaplatUi, sources: any[]) {
369
368
  );
370
369
  }
371
370
 
372
- for (let i = 0; i < baseSources.length; i++) {
373
- const source = baseSources[i];
371
+ baseSources.forEach(source => {
374
372
  const thumbKey = source.thumbnail ? source.thumbnail.split("/").pop() : "";
375
373
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
376
374
  const thumbUrl = (pointer as any)[thumbKey] || source.thumbnail;
@@ -380,9 +378,8 @@ function initSwipers(ui: MaplatUi, sources: any[]) {
380
378
  thumbUrl
381
379
  }"><div> ${ui.core!.translate(source.label)}</div> </div> `
382
380
  );
383
- }
384
- for (let i = 0; i < overlaySources.length; i++) {
385
- const source = overlaySources[i];
381
+ });
382
+ overlaySources.forEach(source => {
386
383
  const colorCss = source.envelope ? ` ${source.envelopeColor}` : "";
387
384
  const thumbKey = source.thumbnail ? source.thumbnail.split("/").pop() : "";
388
385
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -393,7 +390,7 @@ function initSwipers(ui: MaplatUi, sources: any[]) {
393
390
  thumbUrl
394
391
  }"><div> ${ui.core!.translate(source.label)}</div> </div> `
395
392
  );
396
- }
393
+ });
397
394
 
398
395
  overlaySwiper.on("slideChange", () => {
399
396
  ui.updateEnvelope();
@@ -502,7 +499,7 @@ function initModalHandlers(ui: MaplatUi, appOption: MaplatAppOption) {
502
499
  // Delegated event listener for share buttons
503
500
  mapDiv.addEventListener("click", (evt: Event) => {
504
501
  const target = evt.target as HTMLElement;
505
- const btn = target.closest(".share");
502
+ const btn = target.closest(".share") || target.closest(".share_button");
506
503
  if (!btn) return;
507
504
 
508
505
  console.log("Share button clicked:", btn);
@@ -540,16 +537,33 @@ function initModalHandlers(ui: MaplatUi, appOption: MaplatAppOption) {
540
537
  "_blank",
541
538
  "width=650,height=450,menubar=no,toolbar=no,scrollbars=yes"
542
539
  );
540
+ } else if (cmds[0] === "qr") {
541
+ const qrDiv =
542
+ mapDiv.querySelector(".qr_view_poi") ||
543
+ mapDiv.querySelector(".qr_view");
544
+
545
+ if (qrDiv) {
546
+ QRCode.toCanvas(
547
+ uri,
548
+ { width: 128, margin: 1 },
549
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
550
+ (err: any, canvas: any) => {
551
+ if (!err) {
552
+ qrDiv.innerHTML = "";
553
+ qrDiv.appendChild(canvas);
554
+ }
555
+ }
556
+ );
557
+ }
543
558
  }
544
559
  });
545
560
 
546
561
  const prevDefs = mapDiv.querySelectorAll(".prevent-default-ui");
547
- for (let i = 0; i < prevDefs.length; i++) {
548
- const target = prevDefs[i];
562
+ prevDefs.forEach(target => {
549
563
  target.addEventListener("touchstart", (evt: Event) => {
550
564
  evt.preventDefault();
551
565
  });
552
- }
566
+ });
553
567
 
554
568
  ui.core!.addEventListener("uiPrepare", (_evt: unknown) => {
555
569
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -565,19 +579,17 @@ function initModalHandlers(ui: MaplatUi, appOption: MaplatAppOption) {
565
579
  };
566
580
 
567
581
  let i18nTargets = mapDiv.querySelectorAll("[data-i18n], [din]");
568
- for (let i = 0; i < i18nTargets.length; i++) {
569
- const target = i18nTargets[i];
582
+ i18nTargets.forEach(target => {
570
583
  const key =
571
584
  target.getAttribute("data-i18n") || target.getAttribute("din");
572
585
  (target as HTMLElement).innerText = imageExtractor(ui.core!.t(key));
573
- }
586
+ });
574
587
  i18nTargets = mapDiv.querySelectorAll("[data-i18n-html], [dinh]");
575
- for (let i = 0; i < i18nTargets.length; i++) {
576
- const target = i18nTargets[i];
588
+ i18nTargets.forEach(target => {
577
589
  const key =
578
590
  target.getAttribute("data-i18n-html") || target.getAttribute("dinh");
579
591
  target.innerHTML = imageExtractor(ui.core!.t(key));
580
- }
592
+ });
581
593
  // Explicitly fix app_loading_body with a more robust selector if needed, or re-run translation for it
582
594
  const appLoadingBody = mapDiv.querySelector(
583
595
  '[data-i18n="html.app_loading_body"], [din="html.app_loading_body"]'
@@ -752,14 +764,45 @@ function initModalHandlers(ui: MaplatUi, appOption: MaplatAppOption) {
752
764
  ui.modalSetting("marker_list");
753
765
  modal.show();
754
766
 
767
+ const listRoot = modalBase.querySelector(
768
+ ".modal_marker_list_content ul.list-group"
769
+ ) as HTMLElement;
770
+
771
+ // Reset all panel states when modal is closed
772
+ const resetPanels = () => {
773
+ // Close all Layer panels
774
+ const allLayerPanels =
775
+ listRoot.querySelectorAll(".list_poiitems_div");
776
+ allLayerPanels.forEach(panel => {
777
+ panel.classList.remove("open");
778
+ });
779
+
780
+ // Close and reset all POI Content panels
781
+ const allPoiContentDivs = listRoot.querySelectorAll(
782
+ ".list_poicontent_div"
783
+ );
784
+ allPoiContentDivs.forEach(contentDiv => {
785
+ contentDiv.classList.remove("open");
786
+ contentDiv.innerHTML = "";
787
+ });
788
+
789
+ // Unselect marker
790
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
791
+ (ui.core as any).unselectMarker?.();
792
+
793
+ // Remove this event listener after execution
794
+ modalBase.removeEventListener("hidden.bs.modal", resetPanels);
795
+ };
796
+
797
+ // Remove old listener if exists and add new one
798
+ modalBase.removeEventListener("hidden.bs.modal", resetPanels);
799
+ modalBase.addEventListener("hidden.bs.modal", resetPanels);
800
+
755
801
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
756
802
  const currentMapID = (ui.core!.from as any).mapID;
757
803
  if (cachedMarkerListMapID === currentMapID) return;
758
804
  cachedMarkerListMapID = currentMapID;
759
805
 
760
- const listRoot = modalBase.querySelector(
761
- ".modal_marker_list_content ul.list-group"
762
- ) as HTMLElement;
763
806
  listRoot.innerHTML = "";
764
807
 
765
808
  const layers = ui.core!.listPoiLayers(false, true);
@@ -811,7 +854,40 @@ function initModalHandlers(ui: MaplatUi, appOption: MaplatAppOption) {
811
854
  layerLi
812
855
  .querySelector(".layer_label")!
813
856
  .addEventListener("click", () => {
814
- poiListUl.classList.toggle("open");
857
+ const isCurrentlyOpen = poiListUl.classList.contains("open");
858
+
859
+ // Close all other Layer panels at the same level
860
+ const allLayerPanels =
861
+ listRoot.querySelectorAll(".list_poiitems_div");
862
+ allLayerPanels.forEach(panel => {
863
+ if (panel !== poiListUl) {
864
+ panel.classList.remove("open");
865
+ // Reset all child POI Content panels
866
+ const poiContentDivs = panel.parentElement!.querySelectorAll(
867
+ ".list_poicontent_div"
868
+ );
869
+ poiContentDivs.forEach(contentDiv => {
870
+ contentDiv.classList.remove("open");
871
+ contentDiv.innerHTML = "";
872
+ });
873
+ }
874
+ });
875
+
876
+ // Toggle current panel
877
+ if (isCurrentlyOpen) {
878
+ poiListUl.classList.remove("open");
879
+ // Reset all child POI Content panels in this Layer
880
+ const poiContentDivs = poiListUl.querySelectorAll(
881
+ ".list_poicontent_div"
882
+ );
883
+ poiContentDivs.forEach(contentDiv => {
884
+ contentDiv.classList.remove("open");
885
+ contentDiv.innerHTML = "";
886
+ });
887
+ (ui.core as MaplatApp).unselectMarker?.();
888
+ } else {
889
+ poiListUl.classList.add("open");
890
+ }
815
891
  });
816
892
 
817
893
  listRoot.appendChild(layerLi);
@@ -836,18 +912,34 @@ function initModalHandlers(ui: MaplatUi, appOption: MaplatAppOption) {
836
912
  // let poiImgHide: any;
837
913
 
838
914
  poiLi.addEventListener("click", () => {
839
- if (!poiContentDiv.classList.contains("open")) {
840
- poiContentDiv.classList.add("open");
841
-
842
- poiWebControl(ui, poiContentDiv, poi);
915
+ const isCurrentlyOpen =
916
+ poiContentDiv.classList.contains("open");
917
+
918
+ // Close all other POI panels at the same level (within the same Layer)
919
+ const allPoiContentDivs = poiListUl.querySelectorAll(
920
+ ".list_poicontent_div"
921
+ );
922
+ allPoiContentDivs.forEach(contentDiv => {
923
+ if (
924
+ contentDiv !== poiContentDiv &&
925
+ contentDiv.classList.contains("open")
926
+ ) {
927
+ contentDiv.classList.remove("open");
928
+ contentDiv.innerHTML = "";
929
+ }
930
+ });
843
931
 
844
- ui.core!.selectMarker?.(poi.namespaceID);
845
- } else {
932
+ // Toggle current panel
933
+ if (isCurrentlyOpen) {
846
934
  poiContentDiv.classList.remove("open");
847
-
848
- // if (poiImgHide) poiImgHide();
849
935
  poiContentDiv.innerHTML = "";
850
- ui.core!.unselectMarker?.();
936
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
937
+ (ui.core as any).unselectMarker?.();
938
+ } else {
939
+ poiContentDiv.classList.add("open");
940
+ poiWebControl(ui, poiContentDiv, poi, false);
941
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
942
+ (ui.core as any).selectMarker?.(poi.namespaceID);
851
943
  }
852
944
  });
853
945
 
@@ -856,7 +948,6 @@ function initModalHandlers(ui: MaplatUi, appOption: MaplatAppOption) {
856
948
  });
857
949
  }
858
950
  });
859
- modal.show();
860
951
  } else if (control === "copyright") {
861
952
  ui.modalSetting("map");
862
953
  const mapData = ui.core!.from!;
@@ -1210,6 +1301,12 @@ function initDom(ui: MaplatUi, appOption: MaplatAppOption) {
1210
1301
 
1211
1302
  <d c="modal_poi_content">
1212
1303
  <d c="poi_web_div"></d>
1304
+ <d c="poi_share_buttons recipient row">
1305
+ <d c="form-group col-xs-4 text-center"><button title="Copy to clipboard" class="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>
1306
+ <d c="form-group col-xs-4 text-center"><button title="Twitter" class="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>
1307
+ <d c="form-group col-xs-4 text-center"><button title="Facebook" class="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>
1308
+ </d>
1309
+ <d c="qr_view_poi center-block" style="width:128px;"></d>
1213
1310
  <d c="modal_share_poi"></d>
1214
1311
  <p><img src="" height="0px" width="0px"></p>
1215
1312
  </d>
@@ -1304,25 +1401,21 @@ function initDom(ui: MaplatUi, appOption: MaplatAppOption) {
1304
1401
  } catch (_e) {} // eslint-disable-line no-empty
1305
1402
 
1306
1403
  if (head && !head.querySelector('link[rel="apple-touch-icon"]')) {
1307
- const xhr = new XMLHttpRequest();
1308
- xhr.open("GET", pwaManifest, true);
1309
- xhr.responseType = "json";
1310
-
1311
- xhr.onload = function (_e: ProgressEvent) {
1312
- let value = this.response;
1313
- if (!value) return;
1314
- if (typeof value != "object") value = JSON.parse(value);
1315
-
1316
- if (value.icons) {
1317
- for (let i = 0; i < value.icons.length; i++) {
1318
- const src = absoluteUrl(pwaManifest as string, value.icons[i].src);
1319
- const sizes = value.icons[i].sizes;
1320
- const tag = `<link rel="apple-touch-icon" sizes="${sizes}" href="${src}">`;
1321
- head.appendChild(createElement(tag)[0]);
1404
+ fetch(pwaManifest)
1405
+ .then(response => response.json())
1406
+ .then(value => {
1407
+ if (value.icons) {
1408
+ value.icons.forEach((icon: { src: string; sizes: string }) => {
1409
+ const src = absoluteUrl(pwaManifest as string, icon.src);
1410
+ const sizes = icon.sizes;
1411
+ const tag = `<link rel="apple-touch-icon" sizes="${sizes}" href="${src}">`;
1412
+ head.appendChild(createElement(tag)[0]);
1413
+ });
1322
1414
  }
1323
- }
1324
- };
1325
- xhr.send();
1415
+ })
1416
+ .catch(err => {
1417
+ console.error("Failed to fetch PWA manifest:", err);
1418
+ });
1326
1419
  }
1327
1420
  }
1328
1421
  }