@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
@@ -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)"
@@ -1,3 +1,4 @@
1
+ import { getLogger } from '@vcsuite/logger';
1
2
  import VcsCallback, { callbackClassRegistry } from './vcsCallback.js';
2
3
 
3
4
  /**
@@ -34,7 +35,14 @@ class ActivateLayersCallback extends VcsCallback {
34
35
  this._layerNames
35
36
  .map((n) => this._app.layers.getByKey(n))
36
37
  .filter((l) => l)
37
- .forEach((l) => l.activate());
38
+ .forEach((l) =>
39
+ l.activate().catch((e) => {
40
+ getLogger('ActivateLayersCallback').error(
41
+ `Could not activate layer: ${l.name}`,
42
+ e,
43
+ );
44
+ }),
45
+ );
38
46
  }
39
47
 
40
48
  /**
@@ -36,8 +36,9 @@ class AddModuleCallback extends VcsCallback {
36
36
  createModuleFromObjectOrUrl(this._module)
37
37
  .then((module) => {
38
38
  if (module) {
39
- this._app.addModule(module);
39
+ return this._app.addModule(module);
40
40
  }
41
+ return undefined;
41
42
  })
42
43
  .catch((e) => {
43
44
  getLogger('addModuleCallback').error('Error adding module', e);
@@ -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"
@@ -15,12 +15,14 @@
15
15
  v-model="localModelValue"
16
16
  >
17
17
  <template #selection="{ item, index }">
18
- <span v-if="index === 0" class="text-truncate w-100">
19
- {{ $st(getTitle(item.raw)) }}
20
- </span>
21
- <span v-if="index === 1" class="text-no-wrap">
22
- (+{{ additionalItems }})
23
- </span>
18
+ <slot name="selection" v-bind="{ item, index }">
19
+ <span v-if="index === 0" class="text-truncate w-100">
20
+ {{ $st(getTitle(item.raw)) }}
21
+ </span>
22
+ <span v-if="index === 1" class="text-no-wrap">
23
+ (+{{ additionalItems }})
24
+ </span>
25
+ </slot>
24
26
  </template>
25
27
 
26
28
  <template #append-inner="scope">
@@ -1,3 +1,8 @@
1
+ /**
2
+ * @param {string} color
3
+ * @returns {import("ol/style/Icon").Options}
4
+ */
5
+ export function getColoredMapIcon(color: string): import("ol/style/Icon").Options;
1
6
  export const IconIds: string[];
2
7
  export const IconNames: string[];
3
8
  export default Icons;
@@ -497,3 +497,17 @@ export const IconNames = Object.keys(Icons).map((name) => {
497
497
  return `$${name}`;
498
498
  });
499
499
  export default Icons;
500
+
501
+ /**
502
+ * @param {string} color
503
+ * @returns {import("ol/style/Icon").Options}
504
+ */
505
+ export function getColoredMapIcon(color) {
506
+ return {
507
+ src: `data:image/svg+xml,%3Csvg xmlns:dc='http://purl.org/dc/elements/1.1/' xmlns:cc='http://creativecommons.org/ns%23' xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns%23' xmlns:svg='http://www.w3.org/2000/svg' xmlns='http://www.w3.org/2000/svg' xmlns:sodipodi='http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd' xmlns:inkscape='http://www.inkscape.org/namespaces/inkscape' id='icon_24_poi' width='24' height='23.994' viewBox='0 0 24 23.994' sodipodi:docname='mapIcon.svg'%3E%3Cg id='Gruppe_1972' transform='translate(-571 -609.477)'%3E%3Cpath id='Pfad_773' d='M583,611a8.009,8.009,0,0,0-8,8c0,5.314,6.952,13.32,7.248,13.658a1,1,0,0,0,1.5,0c.3-.338,7.248-8.344,7.248-13.658A8.009,8.009,0,0,0,583,611Zm0,19.444c-2.18-2.685-6-8.09-6-11.444a6,6,0,0,1,12,0C589,622.354,585.18,627.759,583,630.444Z' fill='currentColor' /%3E%3Cpath id='Pfad_774' d='M583,615a4,4,0,1,0,4,4A4,4,0,0,0,583,615Zm0,6a2,2,0,1,1,2-2A2,2,0,0,1,583,621Z' fill='currentColor' /%3E%3C/g%3E%3Cpath fill='${encodeURIComponent(
508
+ color,
509
+ )}' d='M 11.672998,20.526286 C 8.5115524,16.526958 6.4310003,12.714969 6.0702695,10.260963 6.0109099,9.8571482 6.0115821,9.1201807 6.0716855,8.7084104 6.4424582,6.1682348 8.3335069,4.1603103 10.828528,3.6575721 c 1.904966,-0.383844 3.881822,0.1903514 5.289639,1.5364231 0.993092,0.9495349 1.610829,2.1488769 1.810148,3.5144152 0.0601,0.4117703 0.06077,1.1487378 0.0014,1.5525526 -0.357076,2.429138 -2.337816,6.081898 -5.487559,10.119822 -0.224045,0.287223 -0.415188,0.530536 -0.424763,0.540696 -0.0096,0.01016 -0.16456,-0.167678 -0.344411,-0.395195 z m 0.990366,-7.047968 c 0.894914,-0.146674 1.762065,-0.627065 2.349286,-1.301476 0.86707,-0.995812 1.194989,-2.3427819 0.880571,-3.6170541 -0.379849,-1.5394474 -1.596396,-2.6842781 -3.173401,-2.9863277 -0.368703,-0.070619 -1.070937,-0.070619 -1.43964,0 C 9.7056173,5.875042 8.48604,7.0227247 8.1067793,8.5597879 7.8410265,9.6368274 8.0329903,10.787029 8.6317551,11.705317 c 0.5717674,0.876885 1.4205679,1.474277 2.4457369,1.721329 0.47704,0.114961 1.079877,0.134602 1.585872,0.05167 z' id='path1432' /%3E%3C/svg%3E`,
510
+ scale: 1,
511
+ color,
512
+ };
513
+ }
@@ -2,6 +2,7 @@
2
2
  <v-list v-if="actions.length > 0" rounded class="vcs-action-list">
3
3
  <v-list-item
4
4
  v-for="(action, index) in actions"
5
+ :data-action-name="action.name"
5
6
  :key="`${action.name}-${index}`"
6
7
  :class="action.active ? 'text-primary' : ''"
7
8
  :disabled="action.disabled || disabled"
@@ -142,7 +142,7 @@
142
142
  </script>
143
143
 
144
144
  <template>
145
- <div>
145
+ <div class="vcs-grouped-list">
146
146
  <VcsTreeviewSearchbar
147
147
  v-if="searchable"
148
148
  :placeholder="searchbarPlaceholder"
@@ -156,6 +156,7 @@
156
156
  >
157
157
  <vcs-expansion-panel
158
158
  v-for="(group, i) in groups"
159
+ :data-group-name="group.name"
159
160
  :key="i"
160
161
  :value="group.name"
161
162
  :disabled="group.disabled"
@@ -93,6 +93,7 @@
93
93
  :disabled="item.disabled"
94
94
  v-bind="$attrs"
95
95
  class="vcs-list-item-component"
96
+ :data-list-item-name="item.name"
96
97
  >
97
98
  <template #prepend="scope">
98
99
  <slot name="prepend" v-bind="scope">
@@ -1,5 +1,9 @@
1
1
  <template>
2
- <div class="vcs-tree-node" v-if="matchFilter">
2
+ <div
3
+ class="vcs-tree-node"
4
+ v-if="matchFilter"
5
+ :data-tree-item-name="item.name"
6
+ >
3
7
  <v-row
4
8
  no-gutters
5
9
  class="treenode flex-nowrap text-truncate"
@@ -33,6 +33,7 @@
33
33
  <script>
34
34
  import { watch } from 'vue';
35
35
  import { useDisplay } from 'vuetify';
36
+ import { getLogger } from '@vcsuite/logger';
36
37
  import {
37
38
  useProxiedAtomicModel,
38
39
  useProxiedComplexModel,
@@ -114,7 +115,10 @@
114
115
  [() => props.items, () => props.openAll],
115
116
  () => {
116
117
  if (props.openAll) {
117
- localOpenedItems.value = [...props.items.map((item) => item.name)];
118
+ const newItems = props.items
119
+ .map((item) => item.name)
120
+ .filter((name) => !localOpenedItems.value.includes(name));
121
+ localOpenedItems.value.push(...newItems);
118
122
  }
119
123
  },
120
124
  {
@@ -141,7 +145,15 @@
141
145
  itemClicked(item, event) {
142
146
  if (item?.clickable) {
143
147
  if (item?.clicked && !item?.disabled) {
144
- item.clicked(event);
148
+ const p = item.clicked(event);
149
+ if (p instanceof Promise) {
150
+ p.catch((e) => {
151
+ getLogger('VcsTreeview.vue').error(
152
+ `Tree view item failed to click ${item.name}`,
153
+ e,
154
+ );
155
+ });
156
+ }
145
157
  }
146
158
  } else if (
147
159
  (props.openOnClick ?? false) !== false &&
@@ -5,6 +5,7 @@
5
5
  :model-value="!!modelValue"
6
6
  @update:modelValue="handleCheckbox"
7
7
  :disabled="disabled"
8
+ class="pr-1"
8
9
  />
9
10
  <v-menu
10
11
  :close-on-content-click="false"
@@ -73,7 +74,7 @@
73
74
  * @vue-prop {boolean} [disabled=false] - Disable the input
74
75
  */
75
76
  export default {
76
- name: 'MenuWrapper',
77
+ name: 'StyleMenuWrapper',
77
78
  components: {
78
79
  VSheet,
79
80
  VMenu,
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <MenuWrapper
2
+ <StyleMenuWrapper
3
3
  class="vcs-fill-menu"
4
4
  :value-fallback="{ color: [255, 255, 255, 1] }"
5
5
  name="components.style.fill"
@@ -11,7 +11,7 @@
11
11
  <template #content>
12
12
  <VcsFillSelector v-bind="{ ...$attrs, ...$props }" />
13
13
  </template>
14
- </MenuWrapper>
14
+ </StyleMenuWrapper>
15
15
  </template>
16
16
 
17
17
  <script>
@@ -19,7 +19,7 @@
19
19
  import { VSheet } from 'vuetify/components';
20
20
  import { useProxiedAtomicModel } from '../modelHelper.js';
21
21
  import VcsFillSelector from './VcsFillSelector.vue';
22
- import MenuWrapper from './MenuWrapper.vue';
22
+ import StyleMenuWrapper from './StyleMenuWrapper.vue';
23
23
  import { useColorObject, rgbaObjectToString } from './composables.js';
24
24
 
25
25
  /**
@@ -33,7 +33,7 @@
33
33
  components: {
34
34
  VSheet,
35
35
  VcsFillSelector,
36
- MenuWrapper,
36
+ StyleMenuWrapper,
37
37
  },
38
38
  props: {
39
39
  modelValue: {
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <MenuWrapper
2
+ <StyleMenuWrapper
3
3
  class="vcs-image-menu"
4
4
  :value-fallback="{
5
5
  radius: 10,
@@ -21,13 +21,13 @@
21
21
  class="pb-2"
22
22
  />
23
23
  </template>
24
- </MenuWrapper>
24
+ </StyleMenuWrapper>
25
25
  </template>
26
26
 
27
27
  <script>
28
28
  import { onMounted, ref, watch } from 'vue';
29
29
  import { useProxiedAtomicModel } from '../modelHelper.js';
30
- import MenuWrapper from './MenuWrapper.vue';
30
+ import StyleMenuWrapper from './StyleMenuWrapper.vue';
31
31
  import VcsImageSelector, { drawImageStyle } from './VcsImageSelector.vue';
32
32
 
33
33
  /**
@@ -37,7 +37,7 @@
37
37
  export default {
38
38
  name: 'VcsImageMenu',
39
39
  components: {
40
- MenuWrapper,
40
+ StyleMenuWrapper,
41
41
  VcsImageSelector,
42
42
  },
43
43
  props: {
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <MenuWrapper
2
+ <StyleMenuWrapper
3
3
  class="vcs-stroke-menu"
4
4
  :value-fallback="{ color: [0, 0, 0, 1], width: 1 }"
5
5
  name="components.style.stroke"
@@ -18,7 +18,7 @@
18
18
  <template #content>
19
19
  <VcsStrokeSelector v-bind="{ ...$attrs, ...$props }" />
20
20
  </template>
21
- </MenuWrapper>
21
+ </StyleMenuWrapper>
22
22
  </template>
23
23
 
24
24
  <script>
@@ -26,7 +26,7 @@
26
26
  import { VSheet } from 'vuetify/components';
27
27
  import { useProxiedAtomicModel } from '../modelHelper.js';
28
28
  import VcsStrokeSelector from './VcsStrokeSelector.vue';
29
- import MenuWrapper from './MenuWrapper.vue';
29
+ import StyleMenuWrapper from './StyleMenuWrapper.vue';
30
30
  import { useColorObject, rgbaObjectToString } from './composables.js';
31
31
 
32
32
  /**
@@ -40,7 +40,7 @@
40
40
  components: {
41
41
  VSheet,
42
42
  VcsStrokeSelector,
43
- MenuWrapper,
43
+ StyleMenuWrapper,
44
44
  },
45
45
  props: {
46
46
  modelValue: {
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <MenuWrapper
2
+ <StyleMenuWrapper
3
3
  class="vcs-text-menu"
4
4
  :value-fallback="fallbackStyle"
5
5
  name="components.style.text"
@@ -13,14 +13,14 @@
13
13
  <template #content>
14
14
  <VcsTextSelector v-bind="{ ...$attrs, ...$props }" />
15
15
  </template>
16
- </MenuWrapper>
16
+ </StyleMenuWrapper>
17
17
  </template>
18
18
 
19
19
  <script>
20
20
  import { computed } from 'vue';
21
21
  import { useProxiedAtomicModel } from '../modelHelper.js';
22
22
  import VcsTextSelector from './VcsTextSelector.vue';
23
- import MenuWrapper from './MenuWrapper.vue';
23
+ import StyleMenuWrapper from './StyleMenuWrapper.vue';
24
24
  import { rgbaObjectToString, useColorObject } from './composables.js';
25
25
 
26
26
  export const fallbackStyle = {
@@ -38,7 +38,7 @@
38
38
  export default {
39
39
  name: 'VcsTextMenu',
40
40
  components: {
41
- MenuWrapper,
41
+ StyleMenuWrapper,
42
42
  VcsTextSelector,
43
43
  },
44
44
  props: {
@@ -16,12 +16,10 @@
16
16
  </template>
17
17
 
18
18
  <script>
19
- import { inject, ref, watch } from 'vue';
19
+ import { inject, computed } from 'vue';
20
20
  import { VSheet } from 'vuetify/components';
21
21
  import VcsTreeview from '../components/lists/VcsTreeview.vue';
22
22
 
23
- /** The open state Symbol of the ContentTree */
24
- export const openStateMapSymbol = Symbol('openStateMap');
25
23
  /**
26
24
  * @description
27
25
  * Implements Treeview and shows content tree
@@ -37,52 +35,16 @@
37
35
  },
38
36
  setup(props) {
39
37
  const app = inject('vcsApp');
40
- const open = ref(app.contentTree.getTreeOpenState(props.windowState.id));
41
- const tree = app.contentTree.getComputedVisibleTree(props.windowState.id);
42
-
43
- function getWithVisibleChildren(item) {
44
- return [
45
- item.name,
46
- ...(item.visibleChildren
47
- ?.map((c) => getWithVisibleChildren(c))
48
- ?.flat() ?? []),
49
- ];
50
- }
51
38
 
52
- if (!app.contentTree[openStateMapSymbol]) {
53
- app.contentTree[openStateMapSymbol] = new Map();
54
- }
55
- /**
56
- * @type {Map<string, string[]>}
57
- */
58
- const openStateMap = app.contentTree[openStateMapSymbol];
59
- // watch for new visible children, which should start init open
60
- watch(
61
- tree,
62
- (value, oldValue) => {
63
- if (openStateMap.has(app.maps.activeMap?.name)) {
64
- open.value = openStateMap.get(app.maps.activeMap?.name);
65
- } else {
66
- const items = [...app.contentTree]
67
- .filter((i) => i.initOpen && i.getTreeViewItem().visible)
68
- .map(({ name }) => name);
69
- const oldValues = oldValue
70
- ? oldValue.map(getWithVisibleChildren).flat()
71
- : [];
72
- const changed = items.filter(
73
- (name) => !oldValues.includes(name) && !open.value.includes(name),
74
- );
75
- open.value.push(...changed);
76
- }
39
+ const open = computed({
40
+ get: () => app.contentTree.getTreeOpenState(props.windowState.id),
41
+ set: (value) => {
42
+ app.contentTree
43
+ .getTreeOpenState(props.windowState.id)
44
+ .splice(0, Infinity, ...value);
77
45
  },
78
- { immediate: true },
79
- );
80
-
81
- watch(open, () => {
82
- if (app.maps.activeMap) {
83
- openStateMap.set(app.maps.activeMap.name, [...open.value]);
84
- }
85
46
  });
47
+ const tree = app.contentTree.getComputedVisibleTree(props.windowState.id);
86
48
 
87
49
  return {
88
50
  tree,
@@ -1,5 +1,3 @@
1
- /** The open state Symbol of the ContentTree */
2
- export const openStateMapSymbol: unique symbol;
3
1
  declare const _default: import("vue").DefineComponent<{
4
2
  windowState: {
5
3
  type: ObjectConstructor;
@@ -7,7 +5,7 @@ declare const _default: import("vue").DefineComponent<{
7
5
  };
8
6
  }, {
9
7
  tree: any;
10
- open: import("vue").Ref<any>;
8
+ open: import("vue").WritableComputedRef<any>;
11
9
  }, any, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
12
10
  windowState: {
13
11
  type: ObjectConstructor;
@@ -78,6 +78,12 @@ declare class ContentTreeCollection extends IndexedCollection<ContentTreeItem> {
78
78
  * @private
79
79
  */
80
80
  private _setTreeView;
81
+ /**
82
+ * @param {ContentTreeItem} item
83
+ * @returns {string}
84
+ * @private
85
+ */
86
+ private _getSubtreeIdForItem;
81
87
  /**
82
88
  * Returns all managed subtrees. Entries are not persisted and will change, if the trees get recalculated.
83
89
  * @type {import("vue").Ref<Map<string, import("./contentTreeItem.js").TreeViewItem>>}
@@ -107,6 +113,7 @@ declare class ContentTreeCollection extends IndexedCollection<ContentTreeItem> {
107
113
  */
108
114
  getChildrenForSubTree(id: string): Array<ContentTreeItem>;
109
115
  /**
116
+ * This returns a proxy to the subtrees open state. You should mutate this array in place.
110
117
  * @param {string} id
111
118
  * @returns {Array<string>}
112
119
  */