@panoramax/web-viewer 3.2.3-develop-d7e5a16d → 3.2.3-develop-6257391e

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 (221) hide show
  1. package/.gitlab-ci.yml +3 -0
  2. package/CHANGELOG.md +19 -0
  3. package/CODE_OF_CONDUCT.md +1 -1
  4. package/README.md +1 -1
  5. package/build/editor.html +10 -1
  6. package/build/index.css +2 -2
  7. package/build/index.css.map +1 -1
  8. package/build/index.html +1 -1
  9. package/build/index.js +1682 -5
  10. package/build/index.js.map +1 -1
  11. package/build/map.html +1 -1
  12. package/build/viewer.html +10 -1
  13. package/build/widgets.html +1 -0
  14. package/config/jest/mocks.js +172 -0
  15. package/config/paths.js +1 -0
  16. package/config/webpack.config.js +26 -0
  17. package/docs/03_URL_settings.md +3 -11
  18. package/docs/05_Compatibility.md +59 -76
  19. package/docs/09_Develop.md +30 -11
  20. package/docs/90_Releases.md +2 -2
  21. package/docs/images/class_diagram.drawio +28 -28
  22. package/docs/images/class_diagram.jpg +0 -0
  23. package/docs/index.md +112 -0
  24. package/docs/reference/components/core/Basic.md +153 -0
  25. package/docs/reference/components/core/CoverageMap.md +160 -0
  26. package/docs/reference/components/core/Editor.md +172 -0
  27. package/docs/reference/components/core/Viewer.md +288 -0
  28. package/docs/reference/components/layout/CorneredGrid.md +29 -0
  29. package/docs/reference/components/layout/Mini.md +45 -0
  30. package/docs/reference/components/menus/MapBackground.md +32 -0
  31. package/docs/reference/components/menus/MapFilters.md +15 -0
  32. package/docs/reference/components/menus/MapLayers.md +15 -0
  33. package/docs/reference/components/menus/MapLegend.md +15 -0
  34. package/docs/reference/components/menus/PictureLegend.md +15 -0
  35. package/docs/reference/components/menus/PictureMetadata.md +15 -0
  36. package/docs/reference/components/menus/PlayerOptions.md +15 -0
  37. package/docs/reference/components/menus/QualityScoreDoc.md +15 -0
  38. package/docs/reference/components/menus/ReportForm.md +15 -0
  39. package/docs/reference/components/menus/ShareMenu.md +15 -0
  40. package/docs/reference/components/ui/Button.md +39 -0
  41. package/docs/reference/components/ui/ButtonGroup.md +36 -0
  42. package/docs/reference/components/ui/CopyButton.md +35 -0
  43. package/docs/reference/components/ui/Grade.md +32 -0
  44. package/docs/reference/components/ui/LinkButton.md +44 -0
  45. package/docs/reference/components/ui/Loader.md +54 -0
  46. package/docs/reference/components/ui/Map.md +214 -0
  47. package/docs/reference/components/ui/MapMore.md +233 -0
  48. package/docs/reference/components/ui/Photo.md +369 -0
  49. package/docs/reference/components/ui/Popup.md +56 -0
  50. package/docs/reference/components/ui/QualityScore.md +45 -0
  51. package/docs/reference/components/ui/SearchBar.md +63 -0
  52. package/docs/reference/components/ui/TogglableGroup.md +39 -0
  53. package/docs/reference/components/ui/widgets/GeoSearch.md +32 -0
  54. package/docs/reference/components/ui/widgets/Legend.md +32 -0
  55. package/docs/reference/components/ui/widgets/MapFiltersButton.md +33 -0
  56. package/docs/reference/components/ui/widgets/MapLayersButton.md +15 -0
  57. package/docs/reference/components/ui/widgets/Player.md +32 -0
  58. package/docs/reference/components/ui/widgets/Share.md +15 -0
  59. package/docs/reference/components/ui/widgets/Zoom.md +15 -0
  60. package/docs/reference/utils/API.md +311 -0
  61. package/docs/reference/utils/InitParameters.md +67 -0
  62. package/docs/reference/utils/URLHandler.md +102 -0
  63. package/docs/reference.md +73 -0
  64. package/docs/shortcuts.md +11 -0
  65. package/docs/tutorials/aerial_imagery.md +19 -0
  66. package/docs/tutorials/authentication.md +10 -0
  67. package/docs/tutorials/custom_widgets.md +64 -0
  68. package/docs/tutorials/map_style.md +27 -0
  69. package/docs/tutorials/migrate_v4.md +122 -0
  70. package/docs/tutorials/synced_coverage.md +42 -0
  71. package/mkdocs.yml +60 -5
  72. package/package.json +10 -7
  73. package/public/editor.html +21 -29
  74. package/public/index.html +3 -3
  75. package/public/map.html +19 -18
  76. package/public/viewer.html +18 -24
  77. package/public/widgets.html +265 -0
  78. package/scripts/doc.js +77 -0
  79. package/src/components/core/Basic.css +44 -0
  80. package/src/components/core/Basic.js +258 -0
  81. package/src/components/core/CoverageMap.css +9 -0
  82. package/src/components/core/CoverageMap.js +105 -0
  83. package/src/components/core/Editor.css +23 -0
  84. package/src/components/core/Editor.js +354 -0
  85. package/src/components/core/Viewer.css +109 -0
  86. package/src/components/core/Viewer.js +707 -0
  87. package/src/components/core/index.js +11 -0
  88. package/src/components/index.js +13 -0
  89. package/src/components/layout/CorneredGrid.js +109 -0
  90. package/src/components/layout/Mini.js +117 -0
  91. package/src/components/layout/index.js +7 -0
  92. package/src/components/menus/MapBackground.js +106 -0
  93. package/src/components/menus/MapFilters.js +386 -0
  94. package/src/components/menus/MapLayers.js +143 -0
  95. package/src/components/menus/MapLegend.js +54 -0
  96. package/src/components/menus/PictureLegend.js +103 -0
  97. package/src/components/menus/PictureMetadata.js +188 -0
  98. package/src/components/menus/PlayerOptions.js +96 -0
  99. package/src/components/menus/QualityScoreDoc.js +36 -0
  100. package/src/components/menus/ReportForm.js +133 -0
  101. package/src/components/menus/Share.js +228 -0
  102. package/src/components/menus/index.js +15 -0
  103. package/src/components/styles.js +365 -0
  104. package/src/components/ui/Button.js +75 -0
  105. package/src/components/ui/ButtonGroup.css +49 -0
  106. package/src/components/ui/ButtonGroup.js +68 -0
  107. package/src/components/ui/CopyButton.js +71 -0
  108. package/src/components/ui/Grade.js +54 -0
  109. package/src/components/ui/LinkButton.js +68 -0
  110. package/src/components/ui/Loader.js +188 -0
  111. package/src/components/{Map.css → ui/Map.css} +5 -17
  112. package/src/components/{Map.js → ui/Map.js} +114 -138
  113. package/src/components/ui/MapMore.js +324 -0
  114. package/src/components/{Photo.css → ui/Photo.css} +6 -6
  115. package/src/components/{Photo.js → ui/Photo.js} +279 -90
  116. package/src/components/ui/Popup.js +145 -0
  117. package/src/components/ui/QualityScore.js +152 -0
  118. package/src/components/ui/SearchBar.js +363 -0
  119. package/src/components/ui/TogglableGroup.js +162 -0
  120. package/src/components/ui/index.js +20 -0
  121. package/src/components/ui/widgets/GeoSearch.css +21 -0
  122. package/src/components/ui/widgets/GeoSearch.js +139 -0
  123. package/src/components/ui/widgets/Legend.js +51 -0
  124. package/src/components/ui/widgets/MapFiltersButton.js +104 -0
  125. package/src/components/ui/widgets/MapLayersButton.js +79 -0
  126. package/src/components/ui/widgets/Player.css +7 -0
  127. package/src/components/ui/widgets/Player.js +148 -0
  128. package/src/components/ui/widgets/Share.js +30 -0
  129. package/src/components/ui/widgets/Zoom.js +82 -0
  130. package/src/components/ui/widgets/index.js +12 -0
  131. package/src/img/panoramax.svg +13 -0
  132. package/src/img/switch_big.svg +20 -10
  133. package/src/index.js +6 -9
  134. package/src/translations/da.json +1 -1
  135. package/src/translations/de.json +1 -1
  136. package/src/translations/en.json +5 -3
  137. package/src/translations/eo.json +1 -1
  138. package/src/translations/es.json +1 -1
  139. package/src/translations/fr.json +5 -3
  140. package/src/translations/hu.json +1 -1
  141. package/src/translations/it.json +1 -1
  142. package/src/translations/ja.json +1 -1
  143. package/src/translations/nl.json +1 -1
  144. package/src/translations/pl.json +1 -1
  145. package/src/translations/sv.json +1 -1
  146. package/src/translations/zh_Hant.json +1 -1
  147. package/src/utils/API.js +74 -42
  148. package/src/utils/InitParameters.js +354 -0
  149. package/src/utils/URLHandler.js +364 -0
  150. package/src/utils/geocoder.js +116 -0
  151. package/src/utils/{I18n.js → i18n.js} +3 -1
  152. package/src/utils/index.js +11 -0
  153. package/src/utils/{Map.js → map.js} +216 -80
  154. package/src/utils/picture.js +433 -0
  155. package/src/utils/utils.js +315 -0
  156. package/src/utils/widgets.js +93 -0
  157. package/tests/components/ui/CopyButton.test.js +52 -0
  158. package/tests/components/ui/Loader.test.js +54 -0
  159. package/tests/components/{Map.test.js → ui/Map.test.js} +19 -61
  160. package/tests/components/{Photo.test.js → ui/Photo.test.js} +89 -57
  161. package/tests/components/ui/Popup.test.js +24 -0
  162. package/tests/components/ui/QualityScore.test.js +17 -0
  163. package/tests/components/ui/SearchBar.test.js +107 -0
  164. package/tests/components/ui/__snapshots__/CopyButton.test.js.snap +34 -0
  165. package/tests/components/ui/__snapshots__/Loader.test.js.snap +56 -0
  166. package/tests/components/{__snapshots__ → ui/__snapshots__}/Map.test.js.snap +11 -38
  167. package/tests/components/{__snapshots__ → ui/__snapshots__}/Photo.test.js.snap +57 -4
  168. package/tests/components/ui/__snapshots__/Popup.test.js.snap +29 -0
  169. package/tests/components/ui/__snapshots__/QualityScore.test.js.snap +11 -0
  170. package/tests/components/ui/__snapshots__/SearchBar.test.js.snap +65 -0
  171. package/tests/utils/API.test.js +1 -14
  172. package/tests/utils/InitParameters.test.js +485 -0
  173. package/tests/utils/URLHandler.test.js +350 -0
  174. package/tests/utils/__snapshots__/URLHandler.test.js.snap +21 -0
  175. package/tests/utils/__snapshots__/picture.test.js.snap +315 -0
  176. package/tests/utils/__snapshots__/widgets.test.js.snap +19 -0
  177. package/tests/utils/geocoder.test.js +37 -0
  178. package/tests/utils/{I18n.test.js → i18n.test.js} +1 -1
  179. package/tests/utils/map.test.js +67 -0
  180. package/tests/utils/picture.test.js +745 -0
  181. package/tests/utils/utils.test.js +288 -0
  182. package/tests/utils/widgets.test.js +90 -0
  183. package/docs/01_Start.md +0 -149
  184. package/docs/02_Usage.md +0 -831
  185. package/docs/04_Advanced_examples.md +0 -216
  186. package/src/Editor.css +0 -37
  187. package/src/Editor.js +0 -361
  188. package/src/StandaloneMap.js +0 -114
  189. package/src/Viewer.css +0 -203
  190. package/src/Viewer.js +0 -1246
  191. package/src/components/CoreView.css +0 -70
  192. package/src/components/CoreView.js +0 -175
  193. package/src/components/Loader.css +0 -74
  194. package/src/components/Loader.js +0 -120
  195. package/src/utils/Exif.js +0 -193
  196. package/src/utils/Utils.js +0 -631
  197. package/src/utils/Widgets.js +0 -562
  198. package/src/viewer/URLHash.js +0 -469
  199. package/src/viewer/Widgets.css +0 -880
  200. package/src/viewer/Widgets.js +0 -1470
  201. package/tests/Editor.test.js +0 -126
  202. package/tests/StandaloneMap.test.js +0 -45
  203. package/tests/Viewer.test.js +0 -366
  204. package/tests/__snapshots__/Editor.test.js.snap +0 -298
  205. package/tests/__snapshots__/StandaloneMap.test.js.snap +0 -30
  206. package/tests/__snapshots__/Viewer.test.js.snap +0 -195
  207. package/tests/components/CoreView.test.js +0 -92
  208. package/tests/components/Loader.test.js +0 -38
  209. package/tests/components/__snapshots__/Loader.test.js.snap +0 -15
  210. package/tests/utils/Exif.test.js +0 -124
  211. package/tests/utils/Map.test.js +0 -113
  212. package/tests/utils/Utils.test.js +0 -300
  213. package/tests/utils/Widgets.test.js +0 -107
  214. package/tests/utils/__snapshots__/Exif.test.js.snap +0 -43
  215. package/tests/utils/__snapshots__/Utils.test.js.snap +0 -41
  216. package/tests/utils/__snapshots__/Widgets.test.js.snap +0 -44
  217. package/tests/viewer/URLHash.test.js +0 -559
  218. package/tests/viewer/Widgets.test.js +0 -127
  219. package/tests/viewer/__snapshots__/URLHash.test.js.snap +0 -108
  220. package/tests/viewer/__snapshots__/Widgets.test.js.snap +0 -403
  221. /package/tests/utils/__snapshots__/{Map.test.js.snap → geocoder.test.js.snap} +0 -0
@@ -0,0 +1,65 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`_onIconClick resets on clear 1`] = `
4
+ Array [
5
+ Array [],
6
+ ]
7
+ `;
8
+
9
+ exports[`_onIconClick resets on error 1`] = `
10
+ Array [
11
+ Array [],
12
+ ]
13
+ `;
14
+
15
+ exports[`_onResultClick resets on null value 1`] = `
16
+ Array [
17
+ Array [
18
+ CustomEvent {
19
+ "isTrusted": false,
20
+ },
21
+ ],
22
+ ]
23
+ `;
24
+
25
+ exports[`_onResultClick works on classic 1`] = `
26
+ Array [
27
+ Array [
28
+ CustomEvent {
29
+ "isTrusted": false,
30
+ },
31
+ ],
32
+ ]
33
+ `;
34
+
35
+ exports[`_onResultClick works on reduced 1`] = `
36
+ Array [
37
+ Array [
38
+ CustomEvent {
39
+ "isTrusted": false,
40
+ },
41
+ ],
42
+ ]
43
+ `;
44
+
45
+ exports[`_search skips if no searcher fct 1`] = `
46
+ Array [
47
+ Array [
48
+ "No search handler defined",
49
+ ],
50
+ ]
51
+ `;
52
+
53
+ exports[`_search skips if value is empty 1`] = `
54
+ Array [
55
+ Array [],
56
+ ]
57
+ `;
58
+
59
+ exports[`reset works 1`] = `
60
+ Array [
61
+ Array [
62
+ null,
63
+ ],
64
+ ]
65
+ `;
@@ -1,9 +1,7 @@
1
1
  import API from "../../src/utils/API";
2
2
 
3
- jest.mock("maplibre-gl", () => ({
4
- addProtocol: jest.fn(),
5
- }));
6
3
  global.AbortSignal = { timeout: jest.fn() };
4
+ global.console = { log: jest.fn(), info: jest.fn(), warn: jest.fn(), error: jest.fn() };
7
5
 
8
6
  const ENDPOINT = "https://panoramax.ign.fr/api";
9
7
  const VALID_LANDING = {
@@ -96,7 +94,6 @@ describe("onceReady", () => {
96
94
  it("handles API failures", async () => {
97
95
  // Mock landing fetch
98
96
  fetch.mockRejectedValueOnce();
99
- global.console = { error: jest.fn() };
100
97
 
101
98
  const api = new API(ENDPOINT);
102
99
  await expect(api.onceReady()).rejects.toBe("Viewer failed to communicate with API");
@@ -107,8 +104,6 @@ describe("onceReady", () => {
107
104
  });
108
105
 
109
106
  describe("isReady", () => {
110
- global.console = { warn: jest.fn(), error: jest.fn() };
111
-
112
107
  // Randomly fails for no reason
113
108
  it.skip("works if API is ready", async () => {
114
109
  // Mock landing fetch
@@ -136,7 +131,6 @@ describe("isReady", () => {
136
131
 
137
132
  describe("_parseLanding", () => {
138
133
  it("handles overrides for tiles URL", () => {
139
- global.console = { warn: jest.fn() };
140
134
  const api = new API (ENDPOINT, { skipReadLanding: true });
141
135
  api._parseLanding(VALID_LANDING, { tiles: "https://my.custom.tiles/" });
142
136
  expect(api._endpoints.tiles).toBe("https://my.custom.tiles/");
@@ -203,7 +197,6 @@ describe("_loadMapStyles", () => {
203
197
  it("works if no background style set", async() => {
204
198
  const api = new API(ENDPOINT, { skipReadLanding: true });
205
199
  api._parseLanding(VALID_LANDING);
206
- global.console = { warn: jest.fn(), log: jest.fn(), error: jest.fn() };
207
200
  await api._loadMapStyles();
208
201
  expect(api.mapStyle).toMatchSnapshot();
209
202
  });
@@ -211,7 +204,6 @@ describe("_loadMapStyles", () => {
211
204
  it("loads background style from string", async () => {
212
205
  const api = new API(ENDPOINT, { skipReadLanding: true });
213
206
  api._parseLanding(LANDING_NO_PREVIEW);
214
- global.console = { warn: jest.fn(), log: jest.fn(), error: jest.fn() };
215
207
  global.fetch = () => Promise.resolve({ json: () => ({
216
208
  name: "Provider",
217
209
  sources: { provider: {} },
@@ -224,7 +216,6 @@ describe("_loadMapStyles", () => {
224
216
  it("loads background style from json", async () => {
225
217
  const api = new API(ENDPOINT, { skipReadLanding: true });
226
218
  api._parseLanding(LANDING_NO_PREVIEW);
227
- global.console = { warn: jest.fn(), log: jest.fn(), error: jest.fn() };
228
219
  await api._loadMapStyles({
229
220
  name: "Provider",
230
221
  sources: { provider: {} },
@@ -236,7 +227,6 @@ describe("_loadMapStyles", () => {
236
227
  it("handles default user", async () => {
237
228
  const api = new API(ENDPOINT, { skipReadLanding: true });
238
229
  api._parseLanding(VALID_LANDING);
239
- global.console = { warn: jest.fn(), log: jest.fn(), error: jest.fn() };
240
230
  await api._loadMapStyles(undefined, ["geovisio"]);
241
231
  expect(api.mapStyle).toMatchSnapshot();
242
232
  });
@@ -260,7 +250,6 @@ describe("_loadMapStyles", () => {
260
250
  }
261
251
  }
262
252
  });
263
- global.console = { warn: jest.fn(), log: jest.fn(), error: jest.fn() };
264
253
  global.fetch = (url) => {
265
254
  if(url.includes("/users") && url.includes("style.json")) {
266
255
  let user = null;
@@ -415,7 +404,6 @@ describe("getMapStyle", () => {
415
404
  it("fallbacks to /map route if any", async () => {
416
405
  const api = new API(ENDPOINT, { skipReadLanding: true });
417
406
  api._parseLanding(LANDING_NO_PREVIEW);
418
- global.console = { warn: jest.fn(), log: jest.fn(), error: jest.fn() };
419
407
  global.fetch = jest.fn(() => Promise.resolve());
420
408
  const res = await api.getMapStyle();
421
409
  expect(res).toStrictEqual({
@@ -434,7 +422,6 @@ describe("getMapStyle", () => {
434
422
  it("fails if no fallback /map route", async () => {
435
423
  const api = new API(ENDPOINT, { skipReadLanding: true });
436
424
  api._parseLanding(LANDING_NO_PREVIEW);
437
- global.console = { warn: jest.fn(), log: jest.fn(), error: jest.fn() };
438
425
  global.fetch = jest.fn(() => Promise.reject());
439
426
  await expect(async () => await api.getMapStyle()).rejects.toEqual(new Error("API doesn't offer a vector tiles endpoint"));
440
427
  });
@@ -0,0 +1,485 @@
1
+ import {
2
+ default as InitParameters, getMapPositionFromString, xyzParamToPSVPosition, paramsToMapFilters,
3
+ alterPSVState, alterMapState, alterViewerState,
4
+ } from "../../src/utils/InitParameters";
5
+
6
+ describe("InitParameters", () => {
7
+ let componentAttrs;
8
+ let urlParams;
9
+
10
+ beforeEach(() => {
11
+ console.warn = jest.fn();
12
+
13
+ componentAttrs = {
14
+ psv: { transitionDuration: 1000, picturesNavigation: "seq" },
15
+ map: { theme: "age", background: "aerial", center: [0, 0], zoom: 10 },
16
+ focus: "pic",
17
+ picture: "pic1",
18
+ users: "user1,user2",
19
+ geocoder: true,
20
+ widgets: true,
21
+ sequence: true,
22
+ fetchOptions: {},
23
+ style: {},
24
+ lang: "en",
25
+ endpoint: "https://panoramax.testapi.fr",
26
+ };
27
+
28
+ urlParams = {
29
+ map: "15/30/70",
30
+ focus: "map",
31
+ pic: "pic2",
32
+ users: "user3,user4",
33
+ speed: 2000,
34
+ nav: "any",
35
+ theme: "default",
36
+ background: "streets",
37
+ xyz: "1/2/3",
38
+ date_from: "2023-01-01",
39
+ date_to: "2023-12-31",
40
+ pic_type: "type1",
41
+ camera: "cam1",
42
+ pic_score: "high",
43
+ };
44
+ });
45
+
46
+ afterEach(() => jest.clearAllMocks());
47
+
48
+ it("should initialize with componentAttrs and urlParams", () => {
49
+ const initParams = new InitParameters(componentAttrs, urlParams);
50
+
51
+ expect(initParams._parentInit).toEqual({
52
+ map: true,
53
+ users: "user3,user4",
54
+ fetchOptions: {},
55
+ style: {},
56
+ lang: "en",
57
+ endpoint: "https://panoramax.testapi.fr",
58
+ });
59
+ expect(initParams._parentPostInit).toEqual({
60
+ focus: "map",
61
+ picture: "pic2",
62
+ sequence: true,
63
+ geocoder: true,
64
+ widgets: true,
65
+ forceFocus: true,
66
+ });
67
+ expect(initParams._psvInit).toEqual({});
68
+ expect(initParams._psvAny).toEqual({
69
+ transitionDuration: 2000,
70
+ picturesNavigation: "any",
71
+ });
72
+ expect(initParams._psvPostInit).toEqual({ xyz: "1/2/3" });
73
+ expect(initParams._mapInit).toEqual({ raster: undefined });
74
+ expect(initParams._mapAny).toEqual({
75
+ theme: "default",
76
+ background: "streets",
77
+ center: [70, 30],
78
+ zoom: 15,
79
+ pitch: undefined,
80
+ bearing: undefined,
81
+ users: "user3,user4",
82
+ });
83
+ expect(initParams._mapPostInit).toEqual({
84
+ date_from: "2023-01-01",
85
+ date_to: "2023-12-31",
86
+ pic_type: "type1",
87
+ camera: "cam1",
88
+ pic_score: "high",
89
+ });
90
+ });
91
+
92
+ it("should skip URL parameters if disabled by component", () => {
93
+ componentAttrs["url-parameters"] = "false";
94
+ const initParams = new InitParameters(componentAttrs, urlParams);
95
+
96
+ expect(initParams._parentInit).toEqual({
97
+ map: true,
98
+ users: "user1,user2",
99
+ fetchOptions: {},
100
+ style: {},
101
+ lang: "en",
102
+ endpoint: "https://panoramax.testapi.fr",
103
+ });
104
+ expect(initParams._parentPostInit).toEqual({
105
+ focus: "pic",
106
+ picture: "pic1",
107
+ sequence: true,
108
+ geocoder: true,
109
+ widgets: true,
110
+ forceFocus: true,
111
+ });
112
+ });
113
+
114
+ it("should sanitize objects correctly", () => {
115
+ const initParams = new InitParameters(componentAttrs, urlParams);
116
+ const obj = { a: 1, b: undefined, c: 3 };
117
+ const sanitizedObj = initParams._sanitize(obj);
118
+
119
+ expect(sanitizedObj).toEqual({ a: 1, c: 3 });
120
+ });
121
+
122
+ it("should get parent initialization parameters", () => {
123
+ const initParams = new InitParameters(componentAttrs, urlParams);
124
+ const parentInit = initParams.getParentInit();
125
+
126
+ expect(parentInit).toEqual({
127
+ map: true,
128
+ users: "user3,user4",
129
+ fetchOptions: {},
130
+ style: {},
131
+ lang: "en",
132
+ endpoint: "https://panoramax.testapi.fr",
133
+ });
134
+ });
135
+
136
+ it("should get parent post-initialization parameters", () => {
137
+ const initParams = new InitParameters(componentAttrs, urlParams);
138
+ const parentPostInit = initParams.getParentPostInit();
139
+
140
+ expect(parentPostInit).toEqual({
141
+ focus: "map",
142
+ picture: "pic2",
143
+ sequence: true,
144
+ geocoder: true,
145
+ widgets: true,
146
+ forceFocus: true,
147
+ });
148
+ });
149
+
150
+ it("should get PSV initialization parameters", () => {
151
+ const initParams = new InitParameters(componentAttrs, urlParams);
152
+ const psvInit = initParams.getPSVInit();
153
+
154
+ expect(psvInit).toEqual({
155
+ transitionDuration: 2000,
156
+ picturesNavigation: "any",
157
+ });
158
+ });
159
+
160
+ it("should get PSV post-initialization parameters", () => {
161
+ const initParams = new InitParameters(componentAttrs, urlParams);
162
+ const psvPostInit = initParams.getPSVPostInit();
163
+
164
+ expect(psvPostInit).toEqual({
165
+ transitionDuration: 2000,
166
+ picturesNavigation: "any",
167
+ xyz: "1/2/3",
168
+ });
169
+ });
170
+
171
+ it("should get map initialization parameters", () => {
172
+ const initParams = new InitParameters(componentAttrs, urlParams);
173
+ const mapInit = initParams.getMapInit();
174
+
175
+ expect(mapInit).toEqual({
176
+ theme: "default",
177
+ background: "streets",
178
+ center: [70, 30],
179
+ zoom: 15,
180
+ pitch: undefined,
181
+ bearing: undefined,
182
+ users: "user3,user4",
183
+ raster: undefined,
184
+ });
185
+ });
186
+
187
+ it("should get map post-initialization parameters", () => {
188
+ const initParams = new InitParameters(componentAttrs, urlParams);
189
+ const mapPostInit = initParams.getMapPostInit();
190
+
191
+ expect(mapPostInit).toEqual({
192
+ theme: "default",
193
+ background: "streets",
194
+ center: [70, 30],
195
+ zoom: 15,
196
+ pitch: undefined,
197
+ bearing: undefined,
198
+ users: "user3,user4",
199
+ date_from: "2023-01-01",
200
+ date_to: "2023-12-31",
201
+ pic_type: "type1",
202
+ camera: "cam1",
203
+ pic_score: "high",
204
+ });
205
+ });
206
+
207
+ it("should handle invalid focus parameter", () => {
208
+ urlParams.focus = "invalid";
209
+ const initParams = new InitParameters(componentAttrs, urlParams);
210
+ expect(initParams._parentPostInit.focus).toBe("pic");
211
+ expect(console.warn).toHaveBeenCalledWith("Invalid value for parameter focus:", "invalid");
212
+ });
213
+
214
+ it("should handle focus parameter when map is disabled", () => {
215
+ componentAttrs.map = "false";
216
+ urlParams.focus = "map";
217
+ const initParams = new InitParameters(componentAttrs, urlParams);
218
+ expect(initParams._parentPostInit.focus).toBe("pic");
219
+ expect(console.warn).toHaveBeenCalledWith("Parameter focus can't be 'map' as map is disabled");
220
+ });
221
+
222
+ it("should handle background parameter when aerial imagery is not available", () => {
223
+ componentAttrs.map.raster = false;
224
+ urlParams.background = "aerial";
225
+ const initParams = new InitParameters(componentAttrs, urlParams);
226
+ expect(initParams._mapAny.background).toBe("streets");
227
+ expect(console.warn).toHaveBeenCalledWith("Parameter background can't be 'aerial' as no aerial imagery is available");
228
+ });
229
+ });
230
+
231
+ describe("getMapPositionFromString", () => {
232
+ it("works without map", () => {
233
+ expect(getMapPositionFromString("18/-12.5/48.7")).toEqual({ center: [48.7, -12.5], zoom: 18, pitch: 0 });
234
+ });
235
+
236
+ it("works with map", () => {
237
+ const map = {
238
+ dragRotate: { isEnabled: () => true },
239
+ touchZoomRotate: { isEnabled: () => true },
240
+ };
241
+ expect(getMapPositionFromString("18/-12.5/48.7/15/12", map)).toEqual({ center: [48.7, -12.5], zoom: 18, pitch: 12, bearing: 15 });
242
+ });
243
+
244
+ it("nulls if string is invalid", () => {
245
+ expect(getMapPositionFromString("bla/bla/bla")).toBeNull();
246
+ });
247
+ });
248
+
249
+ describe("xyzParamToPSVPosition", () => {
250
+ it("works", () => {
251
+ expect(xyzParamToPSVPosition("18/-12.5/48.7")).toEqual({ x: 18, y: -12.5, z: 48.7 });
252
+ });
253
+
254
+ it("nulls if string is invalid", () => {
255
+ expect(xyzParamToPSVPosition("bla/bla/bla")).toBeNull();
256
+ });
257
+ });
258
+
259
+ describe("paramsToMapFilters", () => {
260
+ it("works", () => {
261
+ const vals = {
262
+ "date_from": "2023-01-01",
263
+ "date_to": "2023-05-05",
264
+ "pic_type": "equirectangular",
265
+ "camera": "sony",
266
+ "whatever": "whenever",
267
+ "theme": "type",
268
+ };
269
+ expect(paramsToMapFilters(vals)).toEqual({
270
+ "minDate": "2023-01-01",
271
+ "maxDate": "2023-05-05",
272
+ "pic_type": "equirectangular",
273
+ "camera": "sony",
274
+ "theme": "type",
275
+ });
276
+ });
277
+ });
278
+
279
+ describe("alterPSVState", () => {
280
+ let psv;
281
+
282
+ beforeEach(() => {
283
+ psv = {
284
+ addEventListener: jest.fn(),
285
+ setXYZ: jest.fn(),
286
+ setTransitionDuration: jest.fn(),
287
+ setPicturesNavigation: jest.fn(),
288
+ };
289
+ });
290
+
291
+ afterEach(() => jest.clearAllMocks());
292
+
293
+ it("should set XYZ position when xyz param is provided", () => {
294
+ const params = { xyz: "1/2/3" };
295
+ alterPSVState(psv, params);
296
+
297
+ expect(psv.addEventListener).toHaveBeenCalledWith("picture-loaded", expect.any(Function), { once: true });
298
+ const listener = psv.addEventListener.mock.calls[0][1];
299
+ listener();
300
+ expect(psv.setXYZ).toHaveBeenCalledWith(1, 2, 3);
301
+ });
302
+
303
+ it("should set transition duration when transitionDuration param is provided", () => {
304
+ const params = { transitionDuration: 1000 };
305
+ alterPSVState(psv, params);
306
+ expect(psv.setTransitionDuration).toHaveBeenCalledWith(1000);
307
+ });
308
+
309
+ it("should set pictures navigation mode when picturesNavigation param is provided", () => {
310
+ const params = { picturesNavigation: "pic" };
311
+ alterPSVState(psv, params);
312
+ expect(psv.setPicturesNavigation).toHaveBeenCalledWith("pic");
313
+ });
314
+
315
+ it("should not set pictures navigation mode when picturesNavigation param is invalid", () => {
316
+ const params = { picturesNavigation: "invalid" };
317
+ alterPSVState(psv, params);
318
+ expect(psv.setPicturesNavigation).not.toHaveBeenCalled();
319
+ });
320
+
321
+ it("should handle multiple params correctly", () => {
322
+ const params = { xyz: "1/2/3", transitionDuration: 1000, picturesNavigation: "seq" };
323
+ alterPSVState(psv, params);
324
+
325
+ expect(psv.addEventListener).toHaveBeenCalledWith("picture-loaded", expect.any(Function), { once: true });
326
+ const listener = psv.addEventListener.mock.calls[0][1];
327
+ listener();
328
+ expect(psv.setXYZ).toHaveBeenCalledWith(1, 2, 3);
329
+ expect(psv.setTransitionDuration).toHaveBeenCalledWith(1000);
330
+ expect(psv.setPicturesNavigation).toHaveBeenCalledWith("seq");
331
+ });
332
+ });
333
+
334
+ describe("alterMapState", () => {
335
+ let map;
336
+
337
+ beforeEach(() => {
338
+ map = {
339
+ jumpTo: jest.fn(),
340
+ setVisibleUsers: jest.fn(),
341
+ setFilters: jest.fn(),
342
+ setBackground: jest.fn(),
343
+ getBearing: jest.fn(),
344
+ dragRotate: {
345
+ isEnabled: jest.fn(),
346
+ },
347
+ };
348
+ });
349
+
350
+ afterEach(() => jest.clearAllMocks());
351
+
352
+ it("should jump to map position when map param is provided", () => {
353
+ const params = { map: "10/20/30" };
354
+ const mapOpts = { center: [30,20], zoom: 10, pitch: 0 };
355
+
356
+ alterMapState(map, params);
357
+ expect(map.jumpTo).toHaveBeenCalledWith(mapOpts);
358
+ });
359
+
360
+ it("should set visible users when users param is provided", () => {
361
+ const params = { users: "user1,user2" };
362
+ alterMapState(map, params);
363
+ expect(map.setVisibleUsers).toHaveBeenCalledWith(["user1", "user2"]);
364
+ });
365
+
366
+ it("should set default visible user when users param is empty", () => {
367
+ const params = { users: "" };
368
+ alterMapState(map, params);
369
+ expect(map.setVisibleUsers).toHaveBeenCalledWith(["geovisio"]);
370
+ });
371
+
372
+ it("should set map filters when params are provided", () => {
373
+ const params = { "date_from": "2024-01-01", "pic_score": "ABC" };
374
+ const filters = { "minDate": "2024-01-01", "qualityscore": [5,4,3] };
375
+
376
+ alterMapState(map, params);
377
+ expect(map.setFilters).toHaveBeenCalledWith(filters);
378
+ });
379
+
380
+ it("should set map background when background param is valid", () => {
381
+ const params = { background: "aerial" };
382
+ alterMapState(map, params);
383
+ expect(map.setBackground).toHaveBeenCalledWith("aerial");
384
+ });
385
+
386
+ it("should not set map background when background param is invalid", () => {
387
+ const params = { background: "invalid" };
388
+ alterMapState(map, params);
389
+ expect(map.setBackground).not.toHaveBeenCalled();
390
+ });
391
+
392
+ it("should handle multiple params correctly", () => {
393
+ const params = {
394
+ map: "15/7/6",
395
+ users: "user1,user2",
396
+ camera: "value1",
397
+ background: "streets",
398
+ };
399
+ const mapOpts = { center: [6, 7], zoom: 15, pitch: 0 };
400
+ const filters = { camera: "value1" };
401
+
402
+ alterMapState(map, params);
403
+ expect(map.jumpTo).toHaveBeenCalledWith(mapOpts);
404
+ expect(map.setVisibleUsers).toHaveBeenCalledWith(["user1", "user2"]);
405
+ expect(map.setFilters).toHaveBeenCalledWith(filters);
406
+ expect(map.setBackground).toHaveBeenCalledWith("streets");
407
+ });
408
+ });
409
+
410
+ describe("alterViewerState", () => {
411
+ let viewer;
412
+
413
+ beforeEach(() => {
414
+ console.warn = jest.fn();
415
+ viewer = {
416
+ psv: {
417
+ addEventListener: jest.fn(),
418
+ },
419
+ select: jest.fn(),
420
+ setPopup: jest.fn(),
421
+ _setFocus: jest.fn(),
422
+ _showPictureMetadata: jest.fn(),
423
+ };
424
+ });
425
+
426
+ afterEach(() => jest.clearAllMocks());
427
+
428
+ it("should select the first picture ID when picture param is provided", () => {
429
+ const params = { picture: "pic1;pic2" };
430
+ alterViewerState(viewer, params);
431
+ expect(viewer.select).toHaveBeenCalledWith(null, "pic1");
432
+ expect(console.warn).toHaveBeenCalledWith("Multiple picture IDs passed in URL, only first one kept");
433
+ });
434
+
435
+ it("should select no picture when picture param is not provided", () => {
436
+ const params = {};
437
+ alterViewerState(viewer, params);
438
+ expect(viewer.select).toHaveBeenCalledWith();
439
+ });
440
+
441
+ it("should show picture metadata when focus is meta and picture is loaded", () => {
442
+ const params = { picture: "pic1", focus: "meta" };
443
+ alterViewerState(viewer, params);
444
+ expect(viewer.psv.addEventListener).toHaveBeenCalledWith("picture-loaded", expect.any(Function), { once: true });
445
+ const listener = viewer.psv.addEventListener.mock.calls[0][1];
446
+ listener();
447
+ expect(viewer._showPictureMetadata).toHaveBeenCalled();
448
+ });
449
+
450
+ it("should set focus to map when focus param is map and map exists", () => {
451
+ const params = { focus: "map", forceFocus: true };
452
+ viewer.map = {};
453
+ alterViewerState(viewer, params);
454
+ expect(viewer.setPopup).toHaveBeenCalledWith(false);
455
+ expect(viewer._setFocus).toHaveBeenCalledWith("map", null, true);
456
+ });
457
+
458
+ it("should set focus to pic when focus param is pic", () => {
459
+ const params = { focus: "pic", forceFocus: true };
460
+ alterViewerState(viewer, params);
461
+ expect(viewer.setPopup).toHaveBeenCalledWith(false);
462
+ expect(viewer._setFocus).toHaveBeenCalledWith("pic", null, true);
463
+ });
464
+
465
+ it("should set focus to pic when focus param is meta", () => {
466
+ const params = { focus: "meta", forceFocus: true };
467
+ alterViewerState(viewer, params);
468
+ expect(viewer._setFocus).toHaveBeenCalledWith("pic", null, true);
469
+ });
470
+
471
+ it("should not set focus when focus param is invalid", () => {
472
+ const params = { focus: "invalid", forceFocus: true };
473
+ alterViewerState(viewer, params);
474
+ expect(viewer._setFocus).not.toHaveBeenCalled();
475
+ });
476
+
477
+ it("should handle multiple params correctly", () => {
478
+ const params = { picture: "pic1", focus: "map", forceFocus: true };
479
+ viewer.map = {};
480
+ alterViewerState(viewer, params);
481
+ expect(viewer.select).toHaveBeenCalledWith(null, "pic1");
482
+ expect(viewer.setPopup).toHaveBeenCalledWith(false);
483
+ expect(viewer._setFocus).toHaveBeenCalledWith("map", null, true);
484
+ });
485
+ });