@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,399 @@
1
+ import {
2
+ cartesianToMercator,
3
+ FeatureProviderInteraction,
4
+ getFeatureFromPickObject,
5
+ isProvidedClusterFeature,
6
+ isProvidedFeature,
7
+ markVolatile,
8
+ maxZIndex,
9
+ mercatorProjection,
10
+ mercatorToCartesian,
11
+ moduleIdSymbol,
12
+ originalFeatureSymbol,
13
+ vcsLayerName,
14
+ vectorClusterGroupName,
15
+ VectorLayer,
16
+ VectorStyleItem,
17
+ volatileModuleId,
18
+ } from '@vcmap/core';
19
+ import { Feature } from 'ol';
20
+ import { Point, LineString } from 'ol/geom.js';
21
+ import { Icon } from 'ol/style.js';
22
+ import { Cartesian3, Ray } from '@vcmap-cesium/engine';
23
+ import { watch } from 'vue';
24
+ import { getColorByKey } from '../vuePlugins/vuetify.js';
25
+ import ClusterFeatureComponent from '../featureInfo/ClusterFeatureComponent.vue';
26
+ import { WindowSlot } from '../manager/window/windowManager.js';
27
+ import { vcsAppSymbol } from '../pluginHelper.js';
28
+ import {
29
+ featureInfoViewSymbol,
30
+ getFeatureInfoViewForFeature,
31
+ getGroupedFeatureList,
32
+ } from '../featureInfo/featureInfo.js';
33
+ import { getColoredMapIcon } from '../components/icons/+all.js';
34
+
35
+ const scratchCartesian = new Cartesian3();
36
+ const pickingZOffset = 10.0;
37
+ const iconScale = 1.5;
38
+
39
+ export const deepPickingWindowId = 'deep-picking-window';
40
+
41
+ /**
42
+ * @param {import("@vcmap/ui").VcsUiApp} app
43
+ * @returns {{ layer: import("@vcmap/core").VectorLayer, destroy: () => void }}
44
+ */
45
+ export function setupDeepPickingLayer(app) {
46
+ const layer = new VectorLayer({
47
+ zIndex: maxZIndex,
48
+ projection: mercatorProjection.toJSON(),
49
+ vectorProperties: {
50
+ altitudeMode: 'absolute',
51
+ eyeOffset: [0, 0, -200],
52
+ },
53
+ allowPicking: false,
54
+ });
55
+ markVolatile(layer);
56
+ app.layers.add(layer);
57
+ layer.activate();
58
+
59
+ const style = new VectorStyleItem({
60
+ image: {
61
+ ...getColoredMapIcon(getColorByKey(app, 'primary')),
62
+ scale: iconScale,
63
+ },
64
+ fill: {
65
+ color: 'rgba(237, 237, 237, 0.1)',
66
+ },
67
+ stroke: {
68
+ color: getColorByKey(app, 'primary'),
69
+ width: 5,
70
+ },
71
+ });
72
+ layer.setStyle(style);
73
+
74
+ function setIconColor() {
75
+ const color = getColorByKey(app, 'primary');
76
+ style.stroke?.setColor(color);
77
+ style.image = new Icon({ ...getColoredMapIcon(color), scale: iconScale });
78
+ layer.forceRedraw();
79
+ }
80
+
81
+ const themChangedListener = app.themeChanged.addEventListener(setIconColor);
82
+
83
+ const destroy = () => {
84
+ layer.deactivate();
85
+ app.layers.remove(layer);
86
+ layer.destroy();
87
+ themChangedListener();
88
+ };
89
+
90
+ return { layer, destroy };
91
+ }
92
+
93
+ /**
94
+ * Retrieves features from an OpenLayers map at a given pixel.
95
+ * @param {import("ol/Map.js").OLMap} map
96
+ * @param {[number, number]} pixel
97
+ * @param {number} hitTolerance
98
+ * @param {number} drill
99
+ * @returns {import("ol").Feature[]}
100
+ */
101
+ function getFeaturesFromOlMap(map, pixel, hitTolerance, drill) {
102
+ const features = [];
103
+ let i = 0;
104
+ map.forEachFeatureAtPixel(
105
+ pixel,
106
+ (feat) => {
107
+ if (
108
+ feat &&
109
+ (feat.get('olcs_allowPicking') == null ||
110
+ feat.get('olcs_allowPicking') === true)
111
+ ) {
112
+ const feature = feat[originalFeatureSymbol] || feat;
113
+ if (!feature[vectorClusterGroupName]) {
114
+ features.push(feature);
115
+ }
116
+ }
117
+ i += 1;
118
+ return i >= drill;
119
+ },
120
+ { hitTolerance },
121
+ );
122
+
123
+ return features;
124
+ }
125
+
126
+ /**
127
+ * Retrieves features from a Cesium scene at a given window position.
128
+ * @param {import("@vcmap-cesium/engine").Scene} scene
129
+ * @param {import("@vcmap-cesium/engine").Ray} ray
130
+ * @param {number} hitTolerance
131
+ * @param {number} drill
132
+ * @returns {Promise<{ features: import("@vcmap/core").EventFeature[], minZ: number }>}
133
+ */
134
+ async function getFeaturesFromScene(scene, ray, hitTolerance, drill) {
135
+ const { depthTestAgainstTerrain } = scene.globe;
136
+ scene.globe.depthTestAgainstTerrain = false;
137
+
138
+ let minZ = 0;
139
+ const objects = await scene.drillPickFromRay(
140
+ ray,
141
+ drill,
142
+ undefined,
143
+ hitTolerance,
144
+ );
145
+
146
+ scene.globe.depthTestAgainstTerrain = depthTestAgainstTerrain;
147
+
148
+ const features = objects
149
+ .map(({ object, position }) => {
150
+ let feature;
151
+ if (object) {
152
+ if (position) {
153
+ const z = cartesianToMercator(position)[2];
154
+ minZ = Math.min(minZ, z);
155
+ }
156
+ feature = getFeatureFromPickObject(object);
157
+ if (feature?.[vectorClusterGroupName]) {
158
+ const clusterFeatures = feature.get('features');
159
+ return [...clusterFeatures];
160
+ }
161
+ }
162
+ return feature;
163
+ })
164
+ .filter((f, i, a) => !!f && a.indexOf(f) === i);
165
+ return { features, minZ };
166
+ }
167
+
168
+ /**
169
+ * @param {import("@vcmap/core").InteractionEvent} event
170
+ * @param {number} [hitTolerance=10]
171
+ * @param {number} [drillLimit]
172
+ * @returns {Promise<{ features: import("@vcmap/core").EventFeature[], minZ: number }>}
173
+ */
174
+ async function getDeepPickingFeatures(
175
+ event,
176
+ hitTolerance = 10,
177
+ drillLimit = undefined,
178
+ ) {
179
+ let features = [];
180
+ let minZ = 0;
181
+ if (
182
+ event.map.className === 'OpenlayersMap' ||
183
+ event.map.className === 'ObliqueMap'
184
+ ) {
185
+ features = getFeaturesFromOlMap(
186
+ event.map.olMap,
187
+ [event.windowPosition.x, event.windowPosition.y],
188
+ hitTolerance,
189
+ drillLimit,
190
+ );
191
+ } else if (event.map.className === 'CesiumMap') {
192
+ const cesiumMap = event.map;
193
+ const scene = cesiumMap.getScene();
194
+
195
+ if (!scene) {
196
+ return features;
197
+ }
198
+
199
+ const [x, y, z] = event.position;
200
+ const origin = mercatorToCartesian([
201
+ x,
202
+ y,
203
+ Number.isNaN(z) ? pickingZOffset : z + pickingZOffset,
204
+ ]);
205
+ const direction = Cartesian3.normalize(
206
+ Cartesian3.negate(origin, scratchCartesian),
207
+ scratchCartesian,
208
+ );
209
+ const ray = new Ray(origin, direction);
210
+
211
+ ({ features, minZ } = await getFeaturesFromScene(
212
+ scene,
213
+ ray,
214
+ hitTolerance,
215
+ drillLimit,
216
+ ));
217
+ }
218
+
219
+ if (
220
+ event.feature &&
221
+ !event.feature[isProvidedFeature] && // provided features will be provided again.
222
+ !features.includes(event.feature)
223
+ ) {
224
+ features.unshift(event.feature);
225
+ }
226
+
227
+ return { features, minZ };
228
+ }
229
+
230
+ /**
231
+ * @param {import("@vcmap/core").AbstractInteraction} interaction
232
+ * @param {import("@vcmap/core").InteractionEvent} event
233
+ * @returns {Promise<import("@vcmap/core").EventFeature[]>}
234
+ */
235
+ async function getInteractionFeatures(interaction, event) {
236
+ const pipedEvent = await interaction.pipe({
237
+ ...event,
238
+ feature: undefined,
239
+ });
240
+ const { feature } = pipedEvent;
241
+ if (feature) {
242
+ if (feature[isProvidedClusterFeature]) {
243
+ return feature.get('features');
244
+ }
245
+ return [feature];
246
+ }
247
+ return [];
248
+ }
249
+
250
+ /**
251
+ * @returns {{ collectFeatures: (event: import("@vcmap/core").InteractionEvent) => Promise<{ features: import("@vcmap/core").EventFeature[], minZ: number }>, destroy: () => void}}
252
+ */
253
+ function createCollectFeatures() {
254
+ const featureProviderInteraction = new FeatureProviderInteraction();
255
+ return {
256
+ async collectFeatures(event) {
257
+ const { features: deepPickingFeatures, minZ } =
258
+ await getDeepPickingFeatures(event);
259
+ return {
260
+ features: [
261
+ ...deepPickingFeatures,
262
+ ...(await getInteractionFeatures(featureProviderInteraction, event)),
263
+ ],
264
+ minZ,
265
+ };
266
+ },
267
+ destroy() {
268
+ featureProviderInteraction.destroy();
269
+ },
270
+ };
271
+ }
272
+
273
+ /**
274
+ * @param {import("../vcsUiApp.js").default} app
275
+ * @param {import("ol/Feature").default} f
276
+ * @returns {boolean}
277
+ */
278
+ function featurePredicate(app, f) {
279
+ if (f[featureInfoViewSymbol]) {
280
+ return true;
281
+ }
282
+
283
+ const l = app.layers.getByKey(f[vcsLayerName]);
284
+ if (l?.[moduleIdSymbol] === volatileModuleId) {
285
+ return !!getFeatureInfoViewForFeature(app, f);
286
+ }
287
+
288
+ return !!l;
289
+ }
290
+
291
+ /**
292
+ * @param {import("../vcsUiApp.js").default} app
293
+ * @param {import("@vcmap/core").VectorLayer} layer
294
+ * @param {(event: import("@vcmap/core").InteractionEvent) => Promise<import("@vcmap/core").EventFeature[]>} collectFeatures
295
+ * @param {import("@vcmap/core").InteractionEvent} event
296
+ * @returns {import("./actionHelper.js").VcsAction}
297
+ */
298
+ export function createDeepPickingAction(app, layer, collectFeatures, event) {
299
+ return {
300
+ name: 'featureInfo.deepPicking.title',
301
+ icon: '$vcsInfo',
302
+ async callback() {
303
+ const { features, minZ } = await collectFeatures(event);
304
+ const { items, groups } = getGroupedFeatureList(
305
+ app,
306
+ features.filter((f) => featurePredicate(app, f)),
307
+ event.position,
308
+ );
309
+
310
+ if (app.windowManager.has(deepPickingWindowId)) {
311
+ app.windowManager.remove(deepPickingWindowId);
312
+ }
313
+
314
+ app.windowManager.add(
315
+ {
316
+ id: deepPickingWindowId,
317
+ component: ClusterFeatureComponent,
318
+ props: {
319
+ items,
320
+ groups,
321
+ },
322
+ state: {
323
+ headerTitle: 'featureInfo.deepPicking.headerTitle',
324
+ headerIcon: '$vcsInfo',
325
+ },
326
+ slot: WindowSlot.DYNAMIC_LEFT,
327
+ },
328
+ vcsAppSymbol,
329
+ );
330
+
331
+ const windowListener = app.windowManager.removed.addEventListener(
332
+ ({ id: windowId }) => {
333
+ if (windowId === deepPickingWindowId) {
334
+ layer.removeAllFeatures();
335
+ windowListener();
336
+ }
337
+ },
338
+ );
339
+
340
+ const [x, y, z] = event.position;
341
+ const coordinate = [
342
+ x,
343
+ y,
344
+ Number.isNaN(z) ? pickingZOffset : z + pickingZOffset,
345
+ ];
346
+ const pickFeature = new Feature({
347
+ geometry: new Point(coordinate),
348
+ });
349
+ const rayFeature = new Feature({
350
+ geometry: new LineString([coordinate, [x, y, minZ]]),
351
+ });
352
+ layer.addFeatures([pickFeature, rayFeature]);
353
+ },
354
+ };
355
+ }
356
+
357
+ /**
358
+ * This adds deep picking action to the context menu, if not disabled in uiConfig
359
+ * @param {import("../vcsUiApp.js").default} app
360
+ * @returns {() => void}
361
+ */
362
+ export function setupDeepPicking(app) {
363
+ const { layer, destroy: destroyLayer } = setupDeepPickingLayer(app);
364
+ const { collectFeatures, destroy: destroyCollectFeatures } =
365
+ createCollectFeatures();
366
+
367
+ const handler = async (event) => {
368
+ if (event.windowPosition) {
369
+ return [createDeepPickingAction(app, layer, collectFeatures, event)];
370
+ }
371
+ return [];
372
+ };
373
+
374
+ if (app.uiConfig.enableDeepPicking !== false) {
375
+ app.contextMenuManager.addEventHandler(handler, vcsAppSymbol);
376
+ }
377
+
378
+ const stopWatching = watch(
379
+ () => app.uiConfig.config.enableDeepPicking,
380
+ (value, oldValue) => {
381
+ if (value !== false) {
382
+ if (!(oldValue !== false)) {
383
+ app.contextMenuManager.addEventHandler(handler, vcsAppSymbol);
384
+ }
385
+ } else {
386
+ app.contextMenuManager.removeHandler(handler);
387
+ }
388
+ },
389
+ );
390
+
391
+ return () => {
392
+ stopWatching();
393
+ destroyLayer();
394
+ destroyCollectFeatures();
395
+ layer.deactivate();
396
+ layer.destroy();
397
+ app.layers.remove(layer);
398
+ };
399
+ }
@@ -79,6 +79,7 @@
79
79
  createMapButtonAction,
80
80
  createToggleAction,
81
81
  } from '../actions/actionHelper.js';
82
+ import { setupDeepPicking } from '../actions/deepPickingAction.js';
82
83
  import VcsSettings from './VcsSettings.vue';
83
84
  import { WindowSlot } from '../manager/window/windowManager.js';
84
85
  import CollectionManager from '../manager/collectionManager/CollectionManager.vue';
@@ -814,6 +815,7 @@
814
815
  const destroyDisplayQualityListener = setupUiConfigDisplayQuality(app);
815
816
  const { attributionEntries, attributionAction, destroyAttributions } =
816
817
  setupAttributions(app);
818
+ const destroyDeepPicking = setupDeepPicking(app);
817
819
 
818
820
  let pluginMountedListener;
819
821
  onMounted(() => {
@@ -853,6 +855,7 @@
853
855
  destroyThemingListener();
854
856
  destroyDisplayQualityListener();
855
857
  destroyAttributions();
858
+ destroyDeepPicking();
856
859
  });
857
860
 
858
861
  const { smAndUp, xs } = useDisplay();
@@ -112,6 +112,10 @@ declare const _default: import("vue").DefineComponent<{
112
112
  * - an optional flag whether to activate feature info on startup (default active)
113
113
  */
114
114
  readonly startingFeatureInfo?: boolean | undefined;
115
+ /**
116
+ * - an optional flag whether to enable deep picking via right click context menu (default active)
117
+ */
118
+ readonly enableDeepPicking?: boolean | undefined;
115
119
  /**
116
120
  * - mouse event, when position display is updated. Either 'click' (default) or 'move'.
117
121
  */
@@ -15,6 +15,7 @@
15
15
  </div>
16
16
  <VcsButton
17
17
  class="flex-shrink-0"
18
+ :data-action-name="attributionAction.name"
18
19
  :key="attributionAction.name"
19
20
  :tooltip="attributionAction.title"
20
21
  :icon="attributionAction.icon"
@@ -22,6 +22,7 @@
22
22
  </template>
23
23
  <VcsButton
24
24
  v-if="!smAndUp"
25
+ :data-action-name="attributionAction.name"
25
26
  :key="attributionAction.name"
26
27
  :tooltip="attributionAction.title"
27
28
  icon="mdi-copyright"
@@ -26,6 +26,10 @@ declare const _default: import("vue").DefineComponent<{
26
26
  * - an optional flag whether to activate feature info on startup (default active)
27
27
  */
28
28
  readonly startingFeatureInfo?: boolean | undefined;
29
+ /**
30
+ * - an optional flag whether to enable deep picking via right click context menu (default active)
31
+ */
32
+ readonly enableDeepPicking?: boolean | undefined;
29
33
  /**
30
34
  * - mouse event, when position display is updated. Either 'click' (default) or 'move'.
31
35
  */
@@ -1,5 +1,5 @@
1
1
  <script setup>
2
- import { computed, inject } from 'vue';
2
+ import { inject } from 'vue';
3
3
  import { VDivider, VList, VListItem } from 'vuetify/components';
4
4
  import {
5
5
  ButtonLocation,
@@ -9,56 +9,48 @@
9
9
  import VcsTextPageFooter from './VcsTextPageFooter.vue';
10
10
  import { getDataProtection, getImprint } from './uiConfigHelper.js';
11
11
  import { toolboxComponentId } from '../manager/toolbox/ToolboxManagerComponent.vue';
12
- import { defaultContentTreeComponentId } from '../contentTree/contentTreeCollection.js';
13
- import { legendComponentId } from './VcsApp.vue';
14
12
 
15
13
  const app = inject('vcsApp');
16
14
 
17
- const mobileButtonComponents = computed(() =>
18
- app.navbarManager.componentIds
19
- .map((id) => app.navbarManager.get(id))
20
- .filter((buttonComponent) => {
21
- return buttonComponent[deviceSymbol].mobile;
22
- }),
23
- );
24
-
25
- const getActions = (location) =>
26
- computed(() =>
27
- getActionsByLocation(
28
- mobileButtonComponents.value,
29
- location,
30
- [...app.plugins].map((p) => p.name),
31
- ),
32
- );
15
+ const mobileButtonComponents = app.navbarManager.componentIds
16
+ .map((id) => app.navbarManager.get(id))
17
+ .filter((buttonComponent) => {
18
+ return buttonComponent[deviceSymbol].mobile;
19
+ });
33
20
 
34
21
  // Actions from the content overflow are put in Menu
35
- const defaultContentTreeComponentIdAction = app.navbarManager.get(
36
- defaultContentTreeComponentId,
37
- ).action;
38
- const legendComponentIdAction =
39
- app.navbarManager.get(legendComponentId).action;
40
- const contentOverflowActions = computed(() => {
41
- return getActions(ButtonLocation.CONTENT).value.filter(
42
- (action) =>
43
- action.name !== defaultContentTreeComponentIdAction.name &&
44
- action.name !== legendComponentIdAction.name,
45
- );
46
- });
22
+ const contentOverflowActions = getActionsByLocation(
23
+ mobileButtonComponents,
24
+ ButtonLocation.CONTENT,
25
+ [...app.plugins].map((p) => p.name),
26
+ )?.slice(2);
47
27
 
48
28
  const toolboxToggleAction = app.navbarManager.get(toolboxComponentId).action;
49
29
 
50
- const toolboxOverflowActions = computed(() =>
51
- getActions(ButtonLocation.TOOL).value.filter(
52
- (action) => action.name !== toolboxToggleAction.name,
53
- ),
54
- );
30
+ const toolboxOverflowActions = getActionsByLocation(
31
+ mobileButtonComponents,
32
+ ButtonLocation.TOOL,
33
+ [...app.plugins].map((p) => p.name),
34
+ )?.filter((action) => action.name !== toolboxToggleAction.name);
55
35
 
56
36
  const mobileMenuActions = [
57
- ...getActions(ButtonLocation.MENU).value,
58
- ...getActions(ButtonLocation.SHARE).value,
59
- ...getActions(ButtonLocation.PROJECT).value,
60
- ...toolboxOverflowActions.value,
61
- ...contentOverflowActions.value,
37
+ ...getActionsByLocation(
38
+ mobileButtonComponents,
39
+ ButtonLocation.MENU,
40
+ [...app.plugins].map((p) => p.name),
41
+ ),
42
+ ...getActionsByLocation(
43
+ mobileButtonComponents,
44
+ ButtonLocation.SHARE,
45
+ [...app.plugins].map((p) => p.name),
46
+ ),
47
+ ...getActionsByLocation(
48
+ mobileButtonComponents,
49
+ ButtonLocation.PROJECT,
50
+ [...app.plugins].map((p) => p.name),
51
+ ),
52
+ ...toolboxOverflowActions,
53
+ ...contentOverflowActions,
62
54
  ];
63
55
 
64
56
  const dataProtection = getDataProtection(app.uiConfig?.config);
@@ -70,6 +62,7 @@
70
62
  <div v-for="action in mobileMenuActions" :key="action.name">
71
63
  <v-list-item
72
64
  @click="action.callback()"
65
+ :data-action-name="action.name"
73
66
  :title="$t(action.name)"
74
67
  :prepend-icon="action.icon"
75
68
  >
@@ -85,6 +85,7 @@
85
85
  v-bind="props"
86
86
  tooltip="navbar.share.tooltip"
87
87
  icon="$vcsShare"
88
+ id="vcs-navbar-share-menu-activator"
88
89
  />
89
90
  </template>
90
91
  <VcsActionList
@@ -96,6 +97,7 @@
96
97
  <VcsToolButton
97
98
  class="d-flex"
98
99
  v-if="searchAction"
100
+ :data-action-name="searchAction.name"
99
101
  :key="searchAction.name"
100
102
  :tooltip="searchAction.title"
101
103
  :icon="searchAction.icon"
@@ -108,6 +110,7 @@
108
110
  <VcsToolButton
109
111
  v-bind="props"
110
112
  tooltip="navbar.menu.tooltip"
113
+ id="vcs-navbar-burger-menu-activator"
111
114
  icon="$vcsMenu"
112
115
  />
113
116
  </template>
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <v-toolbar
3
3
  absolute
4
- :density="density"
4
+ density="comfortable"
5
5
  elevation="0"
6
6
  class="px-4 vcs-navbar-mobile"
7
7
  :height="toolbarHeight"
@@ -14,6 +14,7 @@
14
14
  <VcsToolButton
15
15
  v-if="mobileMenuAction"
16
16
  :key="mobileMenuAction.name"
17
+ :data-action-name="mobileMenuAction.name"
17
18
  :tooltip="mobileMenuAction.title"
18
19
  :icon="mobileMenuAction.icon"
19
20
  :active="mobileMenuAction.active"
@@ -22,6 +23,7 @@
22
23
  />
23
24
  <VcsToolButton
24
25
  v-if="searchAction"
26
+ :data-action-name="searchAction.name"
25
27
  :key="searchAction.name"
26
28
  :tooltip="searchAction.title"
27
29
  :icon="searchAction.icon"
@@ -76,7 +78,7 @@
76
78
  </style>
77
79
 
78
80
  <script>
79
- import { inject, computed, onUnmounted, shallowRef } from 'vue';
81
+ import { computed, inject, onUnmounted, shallowRef } from 'vue';
80
82
  import {
81
83
  VCol,
82
84
  VContainer,
@@ -100,8 +102,6 @@
100
102
  import { WindowSlot } from '../manager/window/windowManager.js';
101
103
  import MapsGroupMobileMenu from './MapsGroupMobileMenu.vue';
102
104
  import { toolboxComponentId } from '../manager/toolbox/ToolboxManagerComponent.vue';
103
- import { defaultContentTreeComponentId } from '../contentTree/contentTreeCollection.js';
104
- import { legendComponentId } from './VcsApp.vue';
105
105
 
106
106
  export const mobileMenuListId = 'mobileMenuList';
107
107
 
@@ -148,10 +148,6 @@
148
148
  destroySearchAction();
149
149
  });
150
150
 
151
- const density = computed(() => {
152
- return 'comfortable';
153
- });
154
-
155
151
  const fontSize = useFontSize();
156
152
  const toolbarHeight = computed(() => {
157
153
  return fontSize.value * 3 + 1;
@@ -178,16 +174,9 @@
178
174
  vcsAppSymbol,
179
175
  );
180
176
 
181
- // only show the ContentTree and Legend actions, rest handled in VcsMobileMenuList
177
+ // only show the first two actions, rest handled in VcsMobileMenuList
182
178
  const contentActions = computed(() => {
183
- return getActions(ButtonLocation.CONTENT).value.filter(
184
- (action) =>
185
- action.name ===
186
- app.navbarManager.get(defaultContentTreeComponentId).action
187
- .name ||
188
- action.name ===
189
- app.navbarManager.get(legendComponentId).action.name,
190
- );
179
+ return getActions(ButtonLocation.CONTENT)?.value?.slice(0, 2);
191
180
  });
192
181
 
193
182
  const toolboxToggleAction = shallowRef(
@@ -210,7 +199,6 @@
210
199
  contentActions,
211
200
  toolboxToggleAction,
212
201
  searchAction,
213
- density,
214
202
  toolbarHeight,
215
203
  };
216
204
  },
@@ -37,7 +37,6 @@ declare const _default: import("vue").DefineComponent<{}, {
37
37
  */
38
38
  disabled?: boolean | undefined;
39
39
  } | null>;
40
- density: import("vue").ComputedRef<string>;
41
40
  toolbarHeight: import("vue").ComputedRef<number>;
42
41
  }, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{}>>, {}, {}>;
43
42
  export default _default;
@@ -4,6 +4,7 @@
4
4
  :class="{ active: positionDisplayAction.active }"
5
5
  >
6
6
  <VcsButton
7
+ :data-action-name="positionDisplayAction.name"
7
8
  :tooltip="positionDisplayAction.title"
8
9
  :icon="positionDisplayAction.icon"
9
10
  @click.stop="positionDisplayAction.callback($event)"
@@ -10,6 +10,7 @@
10
10
  class="d-flex"
11
11
  v-for="(btn, index) in buttons"
12
12
  :key="`${btn.name}-${index}`"
13
+ :data-action-name="btn.name"
13
14
  :tooltip="btn.title"
14
15
  :tooltip-position="tooltipPosition"
15
16
  :icon="btn.icon"