@vcmap/ui 6.1.0-rc.7 → 6.1.0

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