@vcmap/ui 6.1.0-rc.7 → 6.1.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 (106) hide show
  1. package/build/bundle.js +3 -3
  2. package/config/base.config.json +7 -3
  3. package/config/cluster.config.json +1 -1
  4. package/config/dev.config.json +172 -56
  5. package/config/projects.config.json +2 -1
  6. package/config/vectorTile.config.json +42 -1
  7. package/dist/assets/cesium.js +1 -1
  8. package/dist/assets/{core-52c2ef11.js → core-5ae90f6d.js} +7515 -5451
  9. package/dist/assets/core.js +1 -1
  10. package/dist/assets/ol.js +1 -1
  11. package/dist/assets/{ui-dccb9009.css → ui-e659989f.css} +1 -1
  12. package/dist/assets/{ui-dccb9009.js → ui-e659989f.js} +21736 -20926
  13. package/dist/assets/ui.js +1 -1
  14. package/dist/assets/vue.js +1 -1
  15. package/dist/assets/{vuetify-43a20e18.css → vuetify-cc6a8213.css} +2 -2
  16. package/dist/assets/{vuetify-43a20e18.js → vuetify-cc6a8213.js} +6694 -6593
  17. package/dist/assets/vuetify.js +1 -1
  18. package/index.d.ts +14 -6
  19. package/index.js +14 -5
  20. package/package.json +18 -9
  21. package/plugins/@vcmap-show-case/vector-properties-example/src/LayerSettings.vue +39 -0
  22. package/plugins/@vcmap-show-case/vector-properties-example/src/VectorPropertiesExample.vue +3 -0
  23. package/plugins/@vcmap-show-case/vector-properties-example/src/lib.js +13 -0
  24. package/plugins/@vcmap-show-case/window-tester/src/WindowExample.vue +9 -0
  25. package/plugins/package.json +9 -5
  26. package/src/actions/actionHelper.d.ts +6 -0
  27. package/src/actions/actionHelper.js +30 -2
  28. package/src/actions/deepPickingAction.d.ts +23 -0
  29. package/src/actions/deepPickingAction.js +404 -0
  30. package/src/actions/extentActions.js +20 -6
  31. package/src/actions/flightActions.js +5 -1
  32. package/src/application/VcsApp.vue +33 -21
  33. package/src/application/VcsApp.vue.d.ts +4 -0
  34. package/src/application/VcsAttributionsFooter.vue +1 -0
  35. package/src/application/VcsContainer.vue +1 -0
  36. package/src/application/VcsContainer.vue.d.ts +4 -0
  37. package/src/application/VcsMobileMenuList.vue +34 -41
  38. package/src/application/VcsNavbar.vue +3 -0
  39. package/src/application/VcsNavbarMobile.vue +6 -18
  40. package/src/application/VcsNavbarMobile.vue.d.ts +0 -1
  41. package/src/application/VcsPositionDisplay.vue +1 -0
  42. package/src/callback/activateLayersCallback.js +9 -1
  43. package/src/callback/addModuleCallback.js +2 -1
  44. package/src/components/buttons/VcsActionButtonList.vue +1 -0
  45. package/src/components/form-inputs-controls/VcsSelect.vue +8 -6
  46. package/src/components/icons/+all.d.ts +5 -0
  47. package/src/components/icons/+all.js +14 -0
  48. package/src/components/lists/VcsActionList.vue +1 -0
  49. package/src/components/lists/VcsGroupedList.vue +2 -1
  50. package/src/components/lists/VcsListItemComponent.vue +1 -0
  51. package/src/components/lists/VcsTreeNode.vue +5 -1
  52. package/src/components/lists/VcsTreeview.vue +14 -2
  53. package/src/components/style/{MenuWrapper.vue → StyleMenuWrapper.vue} +2 -1
  54. package/src/components/style/VcsFillMenu.vue +4 -4
  55. package/src/components/style/VcsImageMenu.vue +4 -4
  56. package/src/components/style/VcsStrokeMenu.vue +4 -4
  57. package/src/components/style/VcsTextMenu.vue +4 -4
  58. package/src/contentTree/LayerTree.vue +8 -46
  59. package/src/contentTree/LayerTree.vue.d.ts +1 -3
  60. package/src/contentTree/contentTreeCollection.d.ts +7 -0
  61. package/src/contentTree/contentTreeCollection.js +30 -10
  62. package/src/contentTree/contentTreeItem.d.ts +4 -4
  63. package/src/contentTree/contentTreeItem.js +2 -2
  64. package/src/contentTree/groupContentTreeItem.d.ts +5 -0
  65. package/src/contentTree/groupContentTreeItem.js +1 -1
  66. package/src/contentTree/layerContentTreeItem.js +1 -1
  67. package/src/contentTree/layerGroupContentTreeItem.js +11 -1
  68. package/src/contentTree/nodeContentTreeItem.d.ts +21 -0
  69. package/src/contentTree/nodeContentTreeItem.js +31 -2
  70. package/src/contentTree/wmsChildContentTreeItem.d.ts +56 -0
  71. package/src/contentTree/wmsChildContentTreeItem.js +159 -0
  72. package/src/contentTree/wmsGroupContentTreeItem.d.ts +171 -0
  73. package/src/contentTree/wmsGroupContentTreeItem.js +620 -0
  74. package/src/featureInfo/ClusterFeatureComponent.vue +47 -11
  75. package/src/featureInfo/ClusterFeatureComponent.vue.d.ts +1 -0
  76. package/src/featureInfo/balloonFeatureInfoView.d.ts +3 -0
  77. package/src/featureInfo/balloonFeatureInfoView.js +78 -11
  78. package/src/featureInfo/balloonHelper.js +8 -12
  79. package/src/featureInfo/featureInfo.d.ts +32 -7
  80. package/src/featureInfo/featureInfo.js +193 -91
  81. package/src/i18n/de.d.ts +22 -16
  82. package/src/i18n/de.js +4 -0
  83. package/src/i18n/en.d.ts +22 -16
  84. package/src/i18n/en.js +4 -0
  85. package/src/legend/legendHelper.d.ts +15 -0
  86. package/src/legend/legendHelper.js +28 -3
  87. package/src/manager/toolbox/GroupToolboxComponent.vue +1 -0
  88. package/src/manager/toolbox/SelectToolboxComponent.vue +2 -0
  89. package/src/manager/toolbox/ToolboxManagerComponent.vue +1 -0
  90. package/src/manager/window/windowManager.d.ts +2 -2
  91. package/src/manager/window/windowManager.js +17 -16
  92. package/src/navigation/MapNavigation.vue +3 -1
  93. package/src/navigation/overviewMap.js +1 -1
  94. package/src/notifier/NotifierComponent.vue +1 -0
  95. package/src/search/ResultsComponent.vue +10 -1
  96. package/src/search/SearchComponent.vue +11 -6
  97. package/src/search/search.js +3 -16
  98. package/src/state.d.ts +2 -1
  99. package/src/state.js +2 -1
  100. package/src/uiConfig.d.ts +9 -0
  101. package/src/uiConfig.js +1 -0
  102. package/src/vcsUiApp.js +7 -1
  103. /package/dist/assets/{cesium-6c6aa853.js → cesium-be8a1422.js} +0 -0
  104. /package/dist/assets/{ol-b0589b0c.js → ol-d5f8aba6.js} +0 -0
  105. /package/dist/assets/{vue-f7a0b088.js → vue-3435e55b.js} +0 -0
  106. /package/src/components/style/{MenuWrapper.vue.d.ts → StyleMenuWrapper.vue.d.ts} +0 -0
@@ -0,0 +1,620 @@
1
+ import { markVolatile } from '@vcmap/core';
2
+ import { getLogger } from '@vcsuite/logger';
3
+ import { ref } from 'vue';
4
+ import { parseBoolean } from '@vcsuite/parsers';
5
+ import deepEqual from 'fast-deep-equal';
6
+ import WMSCapabilities from 'ol/format/WMSCapabilities';
7
+ import { StateActionState } from '../actions/stateRefAction.js';
8
+ import { contentTreeClassRegistry } from './contentTreeItem.js';
9
+ import WmsChildContentTreeItem from './wmsChildContentTreeItem.js';
10
+ import VcsObjectContentTreeItem from './vcsObjectContentTreeItem.js';
11
+ import { legendSymbol } from '../legend/legendHelper.js';
12
+
13
+ /**
14
+ * @param {string} rawUrl
15
+ * @param {Record<string, string>} parameters
16
+ * @returns {Promise<Array<WMSEntry>>} The fetched capabilities.
17
+ */
18
+ async function getWMSEntries(rawUrl, parameters) {
19
+ const url = new URL(rawUrl);
20
+ const excludedParameters = [
21
+ 'LAYERS',
22
+ 'TRANSPARENT',
23
+ 'FORMAT',
24
+ 'STYLE',
25
+ 'STYLES',
26
+ ];
27
+ Object.entries(parameters).forEach(([key, value]) => {
28
+ if (!excludedParameters.includes(key)) {
29
+ url.searchParams.set(key, value);
30
+ }
31
+ });
32
+ url.searchParams.set('SERVICE', 'WMS');
33
+ url.searchParams.set('REQUEST', 'GetCapabilities');
34
+
35
+ const res = await fetch(url.toString());
36
+ if (!res.ok) {
37
+ throw new Error(`Failed to fetch capabilities: ${res.statusText}`);
38
+ }
39
+ const xml = await res.text();
40
+ const { Capability } = new WMSCapabilities().read(xml);
41
+ const wmsEntries = Capability.Layer.Layer
42
+ // layer without Name are not requestable, they are just a Group.
43
+ .filter((layer) => layer.Name)
44
+ .map((layer) => {
45
+ const styles =
46
+ layer.Style?.map((style) => {
47
+ return {
48
+ name: style.Name,
49
+ title: style.Title,
50
+ legend: style.LegendURL?.filter(
51
+ (legend) => legend.OnlineResource,
52
+ ).map((legend) => {
53
+ const src = legend.OnlineResource;
54
+ if (legend.size[0] < 25) {
55
+ return {
56
+ type: 'StyleLegendItem',
57
+ colNr: 1,
58
+ rows: [
59
+ {
60
+ type: 'IconLegendRow',
61
+ title: layer.Title,
62
+ image: { src },
63
+ },
64
+ ],
65
+ };
66
+ }
67
+ return {
68
+ type: 'ImageLegendItem',
69
+ src,
70
+ popoutBtn: true,
71
+ };
72
+ }),
73
+ };
74
+ }) ?? [];
75
+ return {
76
+ name: layer.Name,
77
+ active: ref(false),
78
+ activeStyle: ref(''),
79
+ title: layer.Title,
80
+ extent: layer.EX_GeographicBoundingBox,
81
+ styles,
82
+ };
83
+ });
84
+ return wmsEntries;
85
+ }
86
+
87
+ /**
88
+ * @param {import("../vcsUiApp.js").default} app
89
+ * @param {WMSEntry} wmsEntry
90
+ * @param {string} parentName
91
+ * @param {boolean} hideStyleSelector
92
+ * @returns {WmsChildContentTreeItem}
93
+ */
94
+ function createWMSChildContentTreeItem(
95
+ app,
96
+ wmsEntry,
97
+ parentName,
98
+ hideStyleSelector,
99
+ ) {
100
+ const childItem = new WmsChildContentTreeItem(
101
+ {
102
+ name: `${parentName}.${wmsEntry.name.replaceAll('.', '_')}`,
103
+ wmsEntry,
104
+ title: wmsEntry.title,
105
+ hideStyleSelector,
106
+ },
107
+ app,
108
+ );
109
+ markVolatile(childItem);
110
+ return childItem;
111
+ }
112
+
113
+ /**
114
+ * @typedef {import('./contentTreeItem.js').ContentTreeItemOptions &
115
+ * { layerName: string, showWhenNotSupported?: boolean, setWMSLayersExclusive?:boolean, hideStyleSelector?:boolean, allowedWMSLayers?:string[]}} WMSGroupContentTreeItemOptions
116
+ * @property {boolean} showWhenNotSupported - optional flag to show the item even if it is not supported by the activeMap.
117
+ * @property {string} layerName - The name of the WMSLayer to show the children of.
118
+ * @property {boolean} [setWMSLayersExclusive=false] - Whether the WMSlayers are mutually exclusive.
119
+ * @property {boolean} [hideStyleSelector=false] - Whether the layer style can be selected. Will add a StyleSelector action to compatible items if the Layer has more than one style.
120
+ * @property {string[]} allowedWMSLayers - The list of layers to be shown, other available layers will not be shown.
121
+ */
122
+
123
+ /**
124
+ * @typedef {Object} WMSStyleEntry
125
+ * @property {string} name
126
+ * @property {string} title
127
+ * @property {import("../legend/legendHelper.js").LegendItem} legend
128
+ */
129
+
130
+ /**
131
+ * @typedef {Object} WMSEntry
132
+ * @property {string} name
133
+ * @property {import("vue").Ref<boolean>} active
134
+ * @property {import("vue").Ref<string>} activeStyle
135
+ * @property {string} title
136
+ * @property {import("@vcmap/core").Extent} extent
137
+ * @property {Array<WMSStyleEntry>} styles
138
+ */
139
+
140
+ /**
141
+ * A WMSGroupItem, will take over a WMSLayer and request the Capabilities of the layer to show all available
142
+ * layers as child Items. The WMSGroupItem will also set the legend on the Layer based on the Capabilities,
143
+ * if the Layer does not have a legend configured.
144
+ * @extends {VcsObjectContentTreeItem<import("./vcsObjectContentTreeItem.js").VcsObjectContentTreeItemProperties>}
145
+ * @class
146
+ */
147
+ class WMSGroupContentTreeItem extends VcsObjectContentTreeItem {
148
+ static get className() {
149
+ return 'WMSGroupContentTreeItem';
150
+ }
151
+
152
+ /**
153
+ * @param {WMSGroupContentTreeItemOptions} options
154
+ * @param {import("../vcsUiApp.js").default} app
155
+ */
156
+ constructor(options, app) {
157
+ super(options, app);
158
+
159
+ /**
160
+ * @type {string}
161
+ * @private
162
+ */
163
+ this._layerName = options.layerName;
164
+
165
+ /**
166
+ * @type {boolean}
167
+ * @private
168
+ */
169
+ this._showWhenNotSupported = parseBoolean(
170
+ options.showWhenNotSupported,
171
+ false,
172
+ );
173
+
174
+ /**
175
+ * @type {boolean}
176
+ * @private
177
+ */
178
+ this._setWMSLayersExclusive = parseBoolean(
179
+ options.setWMSLayersExclusive,
180
+ false,
181
+ );
182
+ // if WMSLayers should be handled exclusive, the item should handle like a NodeContentTreeItem.
183
+ this.clickable = !this._setWMSLayersExclusive;
184
+
185
+ /**
186
+ * @type {boolean}
187
+ * @private
188
+ */
189
+ this._hideStyleSelector = parseBoolean(options.hideStyleSelector, false);
190
+
191
+ this.state = this._setWMSLayersExclusive
192
+ ? StateActionState.NONE
193
+ : StateActionState.INACTIVE;
194
+
195
+ /**
196
+ * @type {boolean}
197
+ * @private
198
+ */
199
+ this._invalid = false;
200
+
201
+ /**
202
+ * The only allowed layers.
203
+ * @type {Array<string>|undefined}
204
+ * @private
205
+ */
206
+ this._allowedWMSLayers = options.allowedWMSLayers;
207
+
208
+ /**
209
+ * @type {Array<WMSEntry>}
210
+ * @private
211
+ */
212
+ this._availableWMSEntries = [];
213
+
214
+ /**
215
+ * references the current ChildItems, this WMSGroupContentTreeItem manages
216
+ * @type {Array<WmsChildContentTreeItem>}
217
+ * @private
218
+ */
219
+ this._childItems = [];
220
+
221
+ /**
222
+ * @type {Array<Function>}
223
+ * @private
224
+ */
225
+ this._listeners = [];
226
+
227
+ /**
228
+ * this flag is set to true, if the legend is already set, so we do not need to manage the legend
229
+ * @type {boolean}
230
+ * @private
231
+ */
232
+ this._legendSet = false;
233
+
234
+ /**
235
+ * pause the stateChangedListener, if the state is set from the Layer to the WMSGroupContentTreeItem
236
+ * @type {boolean}
237
+ * @private
238
+ */
239
+ this._pauseStateChangedListener = false;
240
+
241
+ this._setup();
242
+ }
243
+
244
+ /**
245
+ * readonly access, do not manipulate the entries directly.
246
+ * @type {Array<WMSEntry>}
247
+ */
248
+ get wmsEntries() {
249
+ return this._availableWMSEntries;
250
+ }
251
+
252
+ /**
253
+ * @type {boolean}
254
+ */
255
+ get disabled() {
256
+ return super.disabled;
257
+ }
258
+
259
+ /**
260
+ * @param {boolean} disabled
261
+ */
262
+ set disabled(disabled) {
263
+ super.disabled = disabled;
264
+ this._childItems.forEach((childItem) => {
265
+ childItem.disabled = this.disabled;
266
+ });
267
+ }
268
+
269
+ /**
270
+ * @type {boolean}
271
+ */
272
+ get visible() {
273
+ return super.visible;
274
+ }
275
+
276
+ /**
277
+ * @param {boolean} visible
278
+ */
279
+ set visible(visible) {
280
+ super.visible = visible;
281
+ this._childItems.forEach((childItem) => {
282
+ childItem.visible = this.visible;
283
+ });
284
+ }
285
+
286
+ /**
287
+ * @type {import("@vcmap/core").WMSLayer|undefined}
288
+ * @private
289
+ */
290
+ get _layer() {
291
+ return this._app.layers.getByKey(this._layerName);
292
+ }
293
+
294
+ _setState() {
295
+ if (this._setWMSLayersExclusive) {
296
+ this.state = StateActionState.NONE;
297
+ } else {
298
+ const activeLayers = this._availableWMSEntries.filter(
299
+ (wmsEntry) => wmsEntry.active.value,
300
+ );
301
+ if (activeLayers.length === this._availableWMSEntries.length) {
302
+ this.state = StateActionState.ACTIVE;
303
+ } else if (activeLayers.length === 0) {
304
+ this.state = StateActionState.INACTIVE;
305
+ } else {
306
+ this.state = StateActionState.INDETERMINATE;
307
+ }
308
+ }
309
+ }
310
+
311
+ /**
312
+ * Sets the Legend on the Layer, based on the active WMSLayers and the active Styles.
313
+ * @private
314
+ */
315
+ _setLegend() {
316
+ if (!this._legendSet) {
317
+ const legend = this._availableWMSEntries
318
+ .filter((wmsEntry) => wmsEntry.active.value)
319
+ .map((wmsEntry) => {
320
+ const activeStyle = wmsEntry.activeStyle.value;
321
+ if (activeStyle === '') {
322
+ return wmsEntry.styles?.[0]?.legend;
323
+ } else {
324
+ return wmsEntry?.styles?.find((style) => style.name === activeStyle)
325
+ ?.legend;
326
+ }
327
+ })
328
+ .flat()
329
+ .filter((l) => l);
330
+ if (legend.length > 0) {
331
+ this._layer[legendSymbol] = legend;
332
+ } else {
333
+ delete this._layer[legendSymbol];
334
+ }
335
+ }
336
+ this._pauseStateChangedListener = true;
337
+ this._layer.stateChanged.raiseEvent(this._layer.state); // triggers Legend update;
338
+ this._pauseStateChangedListener = false;
339
+ }
340
+
341
+ /**
342
+ * sets the State of to the underlying Layer
343
+ * @private
344
+ */
345
+ async _setStateToLayer() {
346
+ this._setState();
347
+ const layersOnLayer = this._layer.getLayers();
348
+ const stylesOnLayer = this._layer.parameters.STYLES?.split(',') ?? [];
349
+ const activeLayers = this._availableWMSEntries.filter(
350
+ (wmsEntry) => wmsEntry.active.value,
351
+ );
352
+ const currentStyles = activeLayers.map(
353
+ (wmsEntry) => wmsEntry.activeStyle.value,
354
+ );
355
+ const currentLayers = activeLayers.map((wmsEntry) => wmsEntry.name);
356
+ this._pauseStateChangedListener = true;
357
+ try {
358
+ if (
359
+ !deepEqual(currentLayers, layersOnLayer) ||
360
+ !deepEqual(stylesOnLayer, currentStyles)
361
+ ) {
362
+ this._layer.parameters.STYLES = currentStyles.join(',');
363
+ await this._layer.setLayers(currentLayers);
364
+ }
365
+ if (currentLayers.length > 0 && !this._layer.active) {
366
+ await this._layer.activate();
367
+ } else if (currentLayers.length === 0) {
368
+ this._layer.deactivate();
369
+ }
370
+ } catch (e) {
371
+ getLogger(this.className).error(
372
+ `An error occured while setting the state to the Layer: $(this._layerName)`,
373
+ e,
374
+ );
375
+ }
376
+ this._pauseStateChangedListener = false;
377
+ this._setLegend();
378
+ }
379
+
380
+ /**
381
+ * this reacts to clickEvents from the ChildItem, and sets internal State correspondingly,
382
+ * and also sets the State to the Layer and the children.
383
+ * @param {WmsChildContentTreeItem} item
384
+ */
385
+ _handleChildClickedEvent(item) {
386
+ if (item.wmsEntry.active.value) {
387
+ item.wmsEntry.active.value = false;
388
+ } else {
389
+ if (this._setWMSLayersExclusive) {
390
+ this._availableWMSEntries.forEach((wmsEntry) => {
391
+ wmsEntry.active.value = false;
392
+ });
393
+ }
394
+ item.wmsEntry.active.value = true;
395
+ }
396
+ this._setStateToLayer();
397
+ }
398
+
399
+ /**
400
+ * @param {WmsChildContentTreeItem} item
401
+ * @param {string} style
402
+ * @private
403
+ */
404
+ _handleStyleSelectedEvent(item, style) {
405
+ item.wmsEntry.activeStyle.value = style;
406
+ this._setStateToLayer();
407
+ }
408
+
409
+ /**
410
+ * @private
411
+ */
412
+ _clear() {
413
+ this._childItems.forEach((childItem) => {
414
+ this._app.contentTree.remove(childItem);
415
+ childItem.destroy();
416
+ });
417
+ this._childItems = [];
418
+ this._listeners.forEach((cb) => {
419
+ cb();
420
+ });
421
+ this._listeners.splice(0);
422
+ this._availableWMSEntries = [];
423
+ this._legendSet = false;
424
+ }
425
+
426
+ /**
427
+ * syncs the State from the Layer to the WMSGroupContentTreeItem
428
+ * @private
429
+ */
430
+ _setStateFromLayer() {
431
+ if (this._layer) {
432
+ if (this._layer.active) {
433
+ const activeWMSLayers = this._layer.getLayers();
434
+ if (this._setWMSLayersExclusive) {
435
+ this._availableWMSEntries.forEach((wmsEntry) => {
436
+ wmsEntry.active.value = false;
437
+ if (activeWMSLayers?.[0] === wmsEntry.name) {
438
+ wmsEntry.active.value = true;
439
+ }
440
+ });
441
+ } else {
442
+ this._availableWMSEntries.forEach((wmsEntry) => {
443
+ wmsEntry.active.value = activeWMSLayers.includes(wmsEntry.name);
444
+ });
445
+ }
446
+ } else {
447
+ this._availableWMSEntries.forEach((wmsEntry) => {
448
+ wmsEntry.active.value = false;
449
+ });
450
+ }
451
+ if (this._layer.parameters.STYLES) {
452
+ const activeWMSLayers = this._layer.getLayers();
453
+ const activeStyles = this._layer.parameters.STYLES.split(',');
454
+ if (activeWMSLayers.length === activeStyles.length) {
455
+ this._availableWMSEntries.forEach((wmsEntry) => {
456
+ if (activeWMSLayers.includes(wmsEntry.name)) {
457
+ const styleIndex = activeWMSLayers.indexOf(wmsEntry.name);
458
+ wmsEntry.activeStyle.value = activeStyles[styleIndex];
459
+ }
460
+ });
461
+ }
462
+ }
463
+ }
464
+ }
465
+
466
+ /**
467
+ * @returns {Promise<void>}
468
+ * @private
469
+ */
470
+ async _setup() {
471
+ this._clear();
472
+ /**
473
+ * Called when a layer is added or removed to reset the item if needed
474
+ * @param {import("@vcmap/core").Layer} layer
475
+ */
476
+ const resetHandler = (layer) => {
477
+ if (layer.name === this._layerName) {
478
+ this._setup();
479
+ }
480
+ };
481
+ if (!this._layer) {
482
+ this.visible = false;
483
+ this._listeners.push(
484
+ this._app.layers.added.addEventListener(resetHandler),
485
+ );
486
+ } else {
487
+ let isSupported = this._layer.isSupported(this._app.maps.activeMap);
488
+ this.visible = isSupported || this._showWhenNotSupported;
489
+ if (this._showWhenNotSupported) {
490
+ this.disabled = !isSupported;
491
+ }
492
+ this.state = StateActionState.LOADING;
493
+ this.setPropertiesFromObject(this._layer);
494
+
495
+ this._listeners.push(
496
+ this._app.layers.removed.addEventListener(resetHandler),
497
+ );
498
+ this._listeners.push(
499
+ this._app.layers.added.addEventListener(resetHandler),
500
+ );
501
+ this._listeners.push(
502
+ this._layer.stateChanged.addEventListener(() => {
503
+ if (!this._pauseStateChangedListener) {
504
+ this._setStateFromLayer();
505
+ this._setState();
506
+ this._setLegend();
507
+ }
508
+ }),
509
+ );
510
+ this._listeners.push(
511
+ this._app.maps.mapActivated.addEventListener(() => {
512
+ isSupported = this._layer.isSupported(this._app.maps.activeMap);
513
+ this.visible =
514
+ (isSupported || this._showWhenNotSupported) && !this._invalid;
515
+ if (this._showWhenNotSupported) {
516
+ this.disabled = !isSupported;
517
+ }
518
+ }),
519
+ );
520
+ try {
521
+ const availableWMSEntries = await getWMSEntries(
522
+ this._layer.url,
523
+ this._layer.parameters,
524
+ );
525
+ this._availableWMSEntries = availableWMSEntries.filter((wmsEntry) => {
526
+ return this._allowedWMSLayers
527
+ ? this._allowedWMSLayers.includes(wmsEntry.name)
528
+ : true;
529
+ });
530
+ const childItems = this._availableWMSEntries.map((wmsEntry) => {
531
+ return createWMSChildContentTreeItem(
532
+ this._app,
533
+ wmsEntry,
534
+ this.name,
535
+ this._hideStyleSelector,
536
+ );
537
+ });
538
+ childItems.forEach((childItem) => {
539
+ this._app.contentTree.add(childItem);
540
+ this._listeners.push(
541
+ childItem.clickedEvent.addEventListener(() => {
542
+ this._handleChildClickedEvent(childItem);
543
+ }),
544
+ childItem.styleSelected.addEventListener((style) => {
545
+ this._handleStyleSelectedEvent(childItem, style);
546
+ }),
547
+ );
548
+ });
549
+ this._childItems = childItems;
550
+ // check if we do have a legend already configured, if yes we set a flag, that we do not need to set the legend.
551
+ if (this._layer.properties.legend) {
552
+ this._legendSet = true;
553
+ }
554
+ // we need to get the Initial State from the Layer, to set the correct State to the children.
555
+ this._setStateFromLayer();
556
+ // the layer State maybe incomplete or does not fit to the wmsGroupContentTreeItem, so we need to set the State to the Layer.
557
+ this._setState();
558
+ this._setLegend();
559
+ } catch (e) {
560
+ this._layer.deactivate();
561
+ this.visible = false;
562
+ this._invalid = true;
563
+ getLogger(this.className).error(
564
+ `An error occured while fetching the ${this._layerName} capabilities:`,
565
+ e,
566
+ );
567
+ }
568
+ }
569
+ }
570
+
571
+ async clicked() {
572
+ await super.clicked();
573
+ if (this.state === StateActionState.NONE || this._setWMSLayersExclusive) {
574
+ return;
575
+ }
576
+ const activeLayers = this._availableWMSEntries.filter(
577
+ (wmsEntry) => wmsEntry.active.value,
578
+ );
579
+ const newState = activeLayers.length !== this._availableWMSEntries.length;
580
+ this._availableWMSEntries.forEach((wmsEntry) => {
581
+ wmsEntry.active.value = newState;
582
+ });
583
+ await this._setStateToLayer();
584
+ }
585
+
586
+ /**
587
+ * @returns {WMSGroupContentTreeItemOptions}
588
+ */
589
+ toJSON() {
590
+ const config = super.toJSON();
591
+ config.layerName = this._layerName;
592
+ if (this._showWhenNotSupported) {
593
+ config.showWhenNotSupported = this._showWhenNotSupported;
594
+ }
595
+ if (this._setWMSLayersExclusive) {
596
+ config.setWMSLayersExclusive = this._setWMSLayersExclusive;
597
+ }
598
+ if (this._hideStyleSelector) {
599
+ config.hideStyleSelector = this._hideStyleSelector;
600
+ }
601
+ if (this._allowedWMSLayers?.length > 0) {
602
+ config.allowedWMSLayers = this._allowedWMSLayers;
603
+ }
604
+ return config;
605
+ }
606
+
607
+ destroy() {
608
+ super.destroy();
609
+ this._listeners.forEach((cb) => {
610
+ cb();
611
+ });
612
+ this._listeners.splice(0);
613
+ }
614
+ }
615
+
616
+ export default WMSGroupContentTreeItem;
617
+ contentTreeClassRegistry.registerClass(
618
+ WMSGroupContentTreeItem.className,
619
+ WMSGroupContentTreeItem,
620
+ );
@@ -1,5 +1,6 @@
1
1
  <script setup>
2
- import { ref, shallowRef, inject, onUnmounted } from 'vue';
2
+ import { ref, shallowRef, inject, onUnmounted, watch } from 'vue';
3
+ import { LayerState } from '@vcmap/core';
3
4
  import VcsGroupedList from '../components/lists/VcsGroupedList.vue';
4
5
 
5
6
  const props = defineProps({
@@ -15,25 +16,60 @@
15
16
  },
16
17
  });
17
18
 
19
+ const emit = defineEmits(['close']);
20
+
18
21
  const app = inject('vcsApp');
19
22
  const open = ref(true);
20
23
  const selected = shallowRef([]);
21
24
 
22
- const selectionListener = app.featureInfo.featureChanged.addEventListener(
23
- (f) => {
24
- if (f === null) {
25
- selected.value = [];
26
- } else {
27
- const item = props.items.find((i) => i.name === f.getId());
28
- if (item) {
29
- selected.value = [item];
30
- }
25
+ const selectCurrentFeature = (f) => {
26
+ if (f == null) {
27
+ selected.value = [];
28
+ } else {
29
+ const item = props.items.find((i) => i.name === f.getId());
30
+ if (item) {
31
+ selected.value = [item];
31
32
  }
33
+ }
34
+ };
35
+ selectCurrentFeature(app.featureInfo.selectedFeature);
36
+
37
+ const selectionListener =
38
+ app.featureInfo.featureChanged.addEventListener(selectCurrentFeature);
39
+
40
+ const items = ref(props.items);
41
+ const groups = ref(props.groups);
42
+
43
+ watch(
44
+ () => props.items,
45
+ (newItems) => {
46
+ items.value = newItems;
47
+ selectCurrentFeature(app.featureInfo.selectedFeature);
32
48
  },
33
49
  );
50
+ watch(
51
+ () => props.groups,
52
+ (newGroups) => {
53
+ groups.value = newGroups;
54
+ },
55
+ );
56
+
57
+ const layerListener = app.layers.stateChanged.addEventListener((layer) => {
58
+ if (
59
+ layer.state === LayerState.INACTIVE &&
60
+ items.value.some((item) => item.group === layer.name)
61
+ ) {
62
+ items.value = items.value.filter((item) => item.group !== layer.name);
63
+ groups.value = groups.value.filter((group) => group.name !== layer.name);
64
+ if (items.value.length === 0) {
65
+ emit('close');
66
+ }
67
+ }
68
+ });
34
69
 
35
70
  onUnmounted(() => {
36
71
  selectionListener();
72
+ layerListener();
37
73
  });
38
74
  </script>
39
75
 
@@ -51,7 +87,7 @@
51
87
  open-all
52
88
  />
53
89
  </template>
54
- <p v-else>{{ $t('featureInfo.cluster.empty') }}</p>
90
+ <p v-else class="ma-2">{{ $t('featureInfo.cluster.empty') }}</p>
55
91
  </div>
56
92
  </template>
57
93
 
@@ -1,4 +1,5 @@
1
1
  declare const _default: import("vue").DefineComponent<{}, {
2
+ $emit: (event: "close", ...args: any[]) => void;
2
3
  $props: {
3
4
  readonly [x: string]: any;
4
5
  };