@vcmap/ui 6.0.0-rc.3 → 6.0.0-rc.5

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 (161) hide show
  1. package/build/buildHelpers.js +60 -11
  2. package/build/bundle.js +1 -1
  3. package/build/info/publish.js +25 -31
  4. package/build/lintTypes.js +5 -0
  5. package/config/base.config.json +2 -1
  6. package/config/dev.config.json +7 -1
  7. package/config/www.config.json +25 -22
  8. package/dist/assets/@mdi/font/css/{materialdesignicons.min-7a4f6be0.css → materialdesignicons.min-680621ca.css} +1 -1
  9. package/dist/assets/{cesium-cb4dbfba.js → cesium-126f111a.js} +272 -385
  10. package/dist/assets/cesium.js +1 -1
  11. package/dist/assets/{core-72f21835.js → core-1c8b8674.js} +1417 -1453
  12. package/dist/assets/core.js +1 -1
  13. package/dist/assets/{ol-2d33bc8b.js → ol-27f9b3f3.js} +233 -329
  14. package/dist/assets/ol.js +1 -1
  15. package/dist/assets/ui-7214428e.css +1 -0
  16. package/dist/assets/{ui-2ab43a16.js → ui-7214428e.js} +9573 -9438
  17. package/dist/assets/ui.js +1 -1
  18. package/dist/assets/vue-c78a5f76.js +6083 -0
  19. package/dist/assets/vue.js +1 -1
  20. package/dist/assets/{vuetify-760ced3b.css → vuetify-88a2fabe.css} +2 -2
  21. package/dist/assets/{vuetify-760ced3b.js → vuetify-88a2fabe.js} +7672 -7877
  22. package/dist/assets/vuetify.js +1 -1
  23. package/index.d.ts +6 -8
  24. package/index.js +7 -5
  25. package/package.json +16 -16
  26. package/plugins/@vcmap-show-case/form-inputs-example/src/FormInputsExample.vue +2 -3
  27. package/plugins/@vcmap-show-case/project-selector/src/ModulesListComponent.vue +18 -11
  28. package/plugins/@vcmap-show-case/search-example/src/index.js +1 -0
  29. package/plugins/@vcmap-show-case/search-example/src/searchImpl.js +35 -5
  30. package/plugins/@vcmap-show-case/toolbox-example/src/index.js +2 -1
  31. package/plugins/package.json +3 -23
  32. package/public/assets/@mdi/font/css/materialdesignicons.min.css +1 -1
  33. package/src/actions/StyleSelector.vue +1 -1
  34. package/src/actions/actionHelper.js +13 -2
  35. package/src/actions/listActions.d.ts +4 -4
  36. package/src/actions/listActions.js +2 -2
  37. package/src/application/VcsApp.vue +96 -31
  38. package/src/application/VcsApp.vue.d.ts +297 -4
  39. package/src/application/VcsContainer.vue +26 -9
  40. package/src/application/VcsContainer.vue.d.ts +237 -0
  41. package/src/application/VcsMainMap.vue +7 -7
  42. package/src/application/VcsMainMap.vue.d.ts +2 -2
  43. package/src/application/VcsNavbar.vue +5 -1
  44. package/src/application/VcsSplashScreen.vue +24 -26
  45. package/src/application/VcsTextPageFooter.vue +2 -1
  46. package/src/components/buttons/VcsActionButtonList.vue +59 -3
  47. package/src/components/buttons/VcsActionButtonList.vue.d.ts +28 -0
  48. package/src/components/form-inputs-controls/VcsChipArrayInput.vue +15 -13
  49. package/src/components/form-inputs-controls/VcsChipArrayInput.vue.d.ts +3 -4
  50. package/src/components/form-inputs-controls/VcsCoordinate.vue +4 -3
  51. package/src/components/form-inputs-controls/VcsSelect.vue +1 -4
  52. package/src/components/form-inputs-controls/VcsSlider.vue +0 -1
  53. package/src/components/form-inputs-controls/VcsSlider.vue.d.ts +2 -4
  54. package/src/components/form-inputs-controls/VcsTextArea.vue +1 -4
  55. package/src/components/form-inputs-controls/VcsTextField.vue +14 -0
  56. package/src/components/form-inputs-controls/VcsTextField.vue.d.ts +9 -0
  57. package/src/components/form-inputs-controls/VcsWizardStep.vue +2 -5
  58. package/src/components/form-inputs-controls/vcsTextField.scss +1 -4
  59. package/src/components/form-output/VcsFormattedNumber.vue +6 -4
  60. package/src/components/form-output/VcsMarkdown.vue +15 -12
  61. package/src/components/form-output/VcsMarkdown.vue.d.ts +1 -0
  62. package/src/components/form-output/markdownHelper.d.ts +30 -0
  63. package/src/components/form-output/markdownHelper.js +398 -0
  64. package/src/components/import/VcsFileDrop.vue +8 -5
  65. package/src/components/import/VcsImportComponent.vue +4 -3
  66. package/src/components/import/VcsImportComponent.vue.d.ts +1 -2
  67. package/src/components/lists/VcsActionList.vue +4 -0
  68. package/src/components/lists/VcsList.vue +22 -37
  69. package/src/components/lists/VcsList.vue.d.ts +14 -55
  70. package/src/components/lists/{VcsListItem.vue → VcsListItemComponent.vue} +17 -1
  71. package/src/components/lists/VcsListItemComponent.vue.d.ts +69 -0
  72. package/src/components/lists/VcsTreeview.vue +43 -16
  73. package/src/components/lists/VcsTreeview.vue.d.ts +14 -3
  74. package/src/components/lists/VcsTreeviewLeaf.vue +15 -6
  75. package/src/components/lists/VcsTreeviewSearchbar.vue +2 -2
  76. package/src/components/notification/VcsHelp.vue +1 -1
  77. package/src/components/notification/VcsHelp.vue.d.ts +3 -2
  78. package/src/components/section/VcsExpansionPanel.vue +2 -2
  79. package/src/components/section/VcsFormSection.vue +10 -4
  80. package/src/components/section/VcsFormSection.vue.d.ts +1 -2
  81. package/src/components/style/VcsTextMenu.vue +1 -1
  82. package/src/components/style/VcsVectorStyleComponent.vue +1 -1
  83. package/src/components/tables/VcsDataTable.vue +28 -22
  84. package/src/components/tables/VcsTable.vue +45 -62
  85. package/src/components/tables/VcsTable.vue.d.ts +30 -17
  86. package/src/components/tables/VcsTableCell.vue +72 -0
  87. package/src/components/tables/VcsTableCell.vue.d.ts +13 -0
  88. package/src/components/vector-properties/VcsFeatureEditingWindow.vue +6 -5
  89. package/src/components/vector-properties/VcsFeatureTransforms.vue +5 -0
  90. package/src/components/viewpoint/VcsViewpointComponent.vue +2 -2
  91. package/src/components/viewpoint/VcsViewpointEditor.vue +2 -2
  92. package/src/contentTree/LayerTree.vue +9 -27
  93. package/src/contentTree/LayerTree.vue.d.ts +1 -1
  94. package/src/contentTree/contentTreeCollection.d.ts +1 -0
  95. package/src/contentTree/contentTreeCollection.js +45 -11
  96. package/src/featureInfo/BalloonComponent.vue +14 -15
  97. package/src/featureInfo/MarkdownBalloonComponent.vue +4 -2
  98. package/src/featureInfo/MarkdownBalloonComponent.vue.d.ts +2 -2
  99. package/src/featureInfo/abstractFeatureInfoView.d.ts +6 -0
  100. package/src/featureInfo/abstractFeatureInfoView.js +15 -7
  101. package/src/featureInfo/featureInfo.d.ts +5 -5
  102. package/src/featureInfo/featureInfo.js +51 -31
  103. package/src/featureInfo/iframeFeatureInfoView.d.ts +8 -2
  104. package/src/featureInfo/iframeFeatureInfoView.js +15 -5
  105. package/src/featureInfo/markdownBalloonFeatureInfoView.d.ts +1 -1
  106. package/src/featureInfo/markdownBalloonFeatureInfoView.js +5 -5
  107. package/src/featureInfo/markdownFeatureInfoView.d.ts +1 -1
  108. package/src/featureInfo/markdownFeatureInfoView.js +9 -11
  109. package/src/featureInfo/tableFeatureInfoView.js +13 -4
  110. package/src/manager/collectionManager/CollectionComponentList.vue +1 -1
  111. package/src/manager/collectionManager/CollectionComponentList.vue.d.ts +2 -2
  112. package/src/manager/collectionManager/collectionComponentClass.d.ts +1 -1
  113. package/src/manager/collectionManager/collectionComponentClass.js +2 -2
  114. package/src/manager/collectionManager/editorCollectionComponentClass.js +2 -1
  115. package/src/manager/panel/PanelComponent.vue +2 -9
  116. package/src/manager/panel/PanelManagerComponent.vue +7 -3
  117. package/src/manager/panel/panelHelper.js +3 -3
  118. package/src/manager/panel/panelManager.d.ts +9 -1
  119. package/src/manager/panel/panelManager.js +15 -3
  120. package/src/manager/toolbox/GroupToolboxComponent.vue +8 -4
  121. package/src/manager/toolbox/GroupToolboxComponent.vue.d.ts +1 -0
  122. package/src/manager/toolbox/SelectToolboxComponent.vue +7 -4
  123. package/src/manager/toolbox/SelectToolboxComponent.vue.d.ts +1 -0
  124. package/src/manager/toolbox/ToolboxManager.vue +9 -6
  125. package/src/manager/toolbox/ToolboxManager.vue.d.ts +1 -0
  126. package/src/manager/window/WindowComponent.vue +12 -8
  127. package/src/manager/window/WindowComponentHeader.vue +29 -8
  128. package/src/manager/window/WindowComponentHeader.vue.d.ts +2 -0
  129. package/src/manager/window/WindowManager.vue +2 -2
  130. package/src/navigation/MapNavigation.vue +20 -0
  131. package/src/navigation/locatorHelper.js +1 -1
  132. package/src/navigation/overviewMap.js +1 -1
  133. package/src/notifier/NotifierComponent.vue +18 -15
  134. package/src/search/ResultItem.vue +18 -6
  135. package/src/search/ResultsComponent.vue +31 -20
  136. package/src/search/ResultsComponent.vue.d.ts +2 -1
  137. package/src/search/SearchComponent.vue +8 -14
  138. package/src/search/SearchComponent.vue.d.ts +1 -0
  139. package/src/siteConfig.js +8 -8
  140. package/src/styles/_typography.scss +0 -2
  141. package/src/styles/main.scss +0 -4
  142. package/src/uiConfig.d.ts +300 -5
  143. package/src/uiConfig.js +28 -16
  144. package/src/vcsUiApp.d.ts +7 -7
  145. package/src/vcsUiApp.js +10 -9
  146. package/src/vuePlugins/vuetify.js +3 -0
  147. package/dist/assets/ui-2ab43a16.css +0 -1
  148. package/dist/assets/vue-03b265aa.js +0 -6096
  149. package/src/application/markdownHelper.d.ts +0 -12
  150. package/src/application/markdownHelper.js +0 -70
  151. package/src/components/lists/VcsListItem.vue.d.ts +0 -27
  152. package/src/components/notification/VcsTooltip.vue +0 -156
  153. package/src/components/notification/VcsTooltip.vue.d.ts +0 -27
  154. package/src/featureInfo/MarkdownComponent.vue +0 -16
  155. package/src/featureInfo/MarkdownComponent.vue.d.ts +0 -7
  156. package/src/styles/_theming.scss +0 -73
  157. package/src/styles/settings.scss +0 -6
  158. package/src/styles/shades.scss +0 -4
  159. package/src/styles/variables.scss +0 -140
  160. package/src/styles/vcsFont.scss +0 -2
  161. package/src/styles/vcsGrid.scss +0 -3
@@ -5,7 +5,7 @@ declare const _default: import("vue").DefineComponent<{
5
5
  };
6
6
  }, {
7
7
  tree: any;
8
- opened: import("vue").WritableComputedRef<any[]>;
8
+ open: import("vue").Ref<any>;
9
9
  }, any, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
10
10
  windowState: {
11
11
  type: ObjectConstructor;
@@ -62,6 +62,7 @@ declare class ContentTreeCollection extends IndexedCollection<ContentTreeItem> {
62
62
  private _suspendListeners;
63
63
  /**
64
64
  * @private
65
+ * @param {Array<string>} exclude
65
66
  */
66
67
  private _clearSubTrees;
67
68
  /**
@@ -53,6 +53,24 @@ class ContentTreeCollection extends IndexedCollection {
53
53
  */
54
54
  this._weightListeners = new Map();
55
55
 
56
+ const uiConfigChanged = () => {
57
+ this.subTreeViewItems.value.forEach((subTree) => {
58
+ if (
59
+ !this._app.uiConfig.config.hideContentTree &&
60
+ !this._subTreeListeners.has(subTree.name)
61
+ ) {
62
+ this._subTreeListeners.get(subTree.name)?.();
63
+ this._subTreeListeners.set(
64
+ subTree.name,
65
+ this._createSubtreeActionButton(subTree),
66
+ );
67
+ } else if (this._app.uiConfig.config.hideContentTree) {
68
+ this._subTreeListeners.get(subTree.name)?.();
69
+ this._subTreeListeners.delete(subTree.name);
70
+ }
71
+ });
72
+ };
73
+
56
74
  /**
57
75
  * @type {Array<function():void>}
58
76
  * @private
@@ -78,6 +96,8 @@ class ContentTreeCollection extends IndexedCollection {
78
96
  }
79
97
  }),
80
98
  this.moved.addEventListener(() => recreateTree(true)),
99
+ app.uiConfig.added.addEventListener(uiConfigChanged),
100
+ app.uiConfig.removed.addEventListener(uiConfigChanged),
81
101
  ];
82
102
  /**
83
103
  * This is the default content tree.
@@ -113,11 +133,19 @@ class ContentTreeCollection extends IndexedCollection {
113
133
 
114
134
  /**
115
135
  * @private
136
+ * @param {Array<string>} exclude
116
137
  */
117
- _clearSubTrees() {
118
- this._subTreeViewItems.value.clear();
119
- [...this._subTreeListeners.values()].forEach((cb) => {
120
- cb();
138
+ _clearSubTrees(exclude = []) {
139
+ this._subTreeViewItems.value.forEach((tree, key) => {
140
+ if (!exclude.includes(key)) {
141
+ this._subTreeViewItems.value.delete(key);
142
+ }
143
+ });
144
+ this._subTreeListeners.forEach((cb, key) => {
145
+ if (!exclude.includes(key)) {
146
+ cb();
147
+ this._subTreeListeners.delete(key);
148
+ }
121
149
  });
122
150
  }
123
151
 
@@ -159,7 +187,6 @@ class ContentTreeCollection extends IndexedCollection {
159
187
  vcsAppSymbol,
160
188
  ButtonLocation.CONTENT,
161
189
  );
162
- this._subTreeViewItems.value.set(id, subTreeViewItem);
163
190
  return () => {
164
191
  app.windowManager.remove(id);
165
192
  app.navbarManager.remove(id);
@@ -228,14 +255,21 @@ class ContentTreeCollection extends IndexedCollection {
228
255
  defaultSubTreeViewItem,
229
256
  ...topLevelItems.filter((i) => i[subTreeSymbol]),
230
257
  ];
231
-
258
+ this._clearSubTrees(
259
+ subTrees.map((tree) => {
260
+ return tree.name;
261
+ }),
262
+ );
232
263
  subTrees.forEach((subTree) => {
233
264
  if (!this._app.navbarManager.has(subTree.name) || resetSubtreeButtons) {
234
- this._subTreeListeners.get(subTree.name)?.();
235
- this._subTreeListeners.set(
236
- subTree.name,
237
- this._createSubtreeActionButton(subTree),
238
- );
265
+ this._subTreeViewItems.value.set(subTree.name, subTree);
266
+ if (!this._app.uiConfig.config.hideContentTree) {
267
+ this._subTreeListeners.get(subTree.name)?.();
268
+ this._subTreeListeners.set(
269
+ subTree.name,
270
+ this._createSubtreeActionButton(subTree),
271
+ );
272
+ }
239
273
  } else {
240
274
  const buttonComponent = this._app.navbarManager.get(subTree.name);
241
275
  if (buttonComponent.weight !== subTree[subTreeItemWeight]) {
@@ -1,9 +1,11 @@
1
1
  <template>
2
2
  <v-card class="mx-auto elevation-0" v-if="position">
3
3
  <slot name="balloon-header" :attrs="{ ...$props, ...$attrs }">
4
- <v-list-item class="px-2 align-center">
4
+ <v-list-item class="px-1">
5
5
  <template #prepend>
6
- <v-icon color="primary" size="16" class="mr-2"> $vcsInfo </v-icon>
6
+ <div class="pl-1 pr-2">
7
+ <v-icon color="primary" size="16"> $vcsInfo </v-icon>
8
+ </div>
7
9
  </template>
8
10
  <v-list-item-title>
9
11
  <h3 class="font-weight-bold">
@@ -13,12 +15,14 @@
13
15
  <v-list-item-subtitle v-if="balloonSubtitle">
14
16
  {{ $st(balloonSubtitle) }}
15
17
  </v-list-item-subtitle>
16
- <VcsButton
17
- @click.stop="close"
18
- icon="mdi-close-thick"
19
- tooltip="components.close"
20
- class="d-flex"
21
- />
18
+ <template #append>
19
+ <VcsButton
20
+ @click.stop="close"
21
+ icon="mdi-close-thick"
22
+ tooltip="components.close"
23
+ class="px-1"
24
+ />
25
+ </template>
22
26
  </v-list-item>
23
27
  </slot>
24
28
 
@@ -194,8 +198,6 @@
194
198
  </script>
195
199
 
196
200
  <style lang="scss">
197
- @import '../styles/shades.scss';
198
-
199
201
  .balloon {
200
202
  z-index: 0 !important;
201
203
  }
@@ -213,11 +215,8 @@
213
215
  width: 0;
214
216
  filter: drop-shadow(1px 2px 1px rgba(0, 0, 0, 0.3));
215
217
  }
216
- .theme--light .balloon:after {
217
- border-color: map-get($shades, 'white') transparent;
218
- }
219
- .theme--dark .balloon:after {
220
- border-color: map-get($shades, 'black') transparent;
218
+ .balloon:after {
219
+ border-color: rgb(var(--v-theme-surface-light)) transparent;
221
220
  }
222
221
  .balloon .v-list-item .v-list-item__title,
223
222
  .balloon .v-list-item .v-list-item__subtitle {
@@ -1,10 +1,11 @@
1
1
  <template>
2
2
  <BalloonComponent v-bind="{ ...$attrs }">
3
- <div class="pa-2" v-html="html" />
3
+ <VcsMarkdown :content="content" />
4
4
  </BalloonComponent>
5
5
  </template>
6
6
  <script>
7
7
  import BalloonComponent from './BalloonComponent.vue';
8
+ import VcsMarkdown from '../components/form-output/VcsMarkdown.vue';
8
9
 
9
10
  /**
10
11
  * @description A balloon showing markdown content
@@ -12,12 +13,13 @@
12
13
  export default {
13
14
  name: 'MarkdownBalloonComponent',
14
15
  props: {
15
- html: {
16
+ content: {
16
17
  type: String,
17
18
  required: true,
18
19
  },
19
20
  },
20
21
  components: {
22
+ VcsMarkdown,
21
23
  BalloonComponent,
22
24
  },
23
25
  };
@@ -1,10 +1,10 @@
1
1
  declare const _default: import("vue").DefineComponent<{
2
- html: {
2
+ content: {
3
3
  type: StringConstructor;
4
4
  required: true;
5
5
  };
6
6
  }, any, any, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
7
- html: {
7
+ content: {
8
8
  type: StringConstructor;
9
9
  required: true;
10
10
  };
@@ -164,6 +164,12 @@ declare class AbstractFeatureInfoView extends VcsObject {
164
164
  * @type {import("vue").Component<FeatureInfoProps, unknown, unknown>|undefined}
165
165
  */
166
166
  get component(): import("vue").Component<FeatureInfoProps, unknown, unknown, import("vue").ComputedOptions, import("vue").MethodOptions, {}, any> | undefined;
167
+ /**
168
+ * @param {undefined|import("ol").Feature|import("@vcmap-cesium/engine").Cesium3DTileFeature|import("@vcmap-cesium/engine").Cesium3DTilePointFeature} feature
169
+ * @returns {Object}
170
+ * @protected
171
+ */
172
+ protected _getAttributesFromFeature(feature: undefined | import("ol").Feature | import("@vcmap-cesium/engine").Cesium3DTileFeature | import("@vcmap-cesium/engine").Cesium3DTilePointFeature): Object;
167
173
  /**
168
174
  * This method returns all relevant attributes for this view.
169
175
  * Called by `getProperties()` to pass attributes as props object to the VueComponent of this view.
@@ -1,7 +1,7 @@
1
1
  import { VcsObject } from '@vcmap/core';
2
2
  import { WindowSlot } from '../manager/window/windowManager.js';
3
3
  import { defaultTagOptions } from '../components/tables/VcsTable.vue';
4
- import { replaceAttributes } from '../application/markdownHelper.js';
4
+ import { renderTemplate } from '../components/form-output/markdownHelper.js';
5
5
 
6
6
  /**
7
7
  * @typedef {Object} FeatureInfoProps
@@ -251,11 +251,9 @@ function getWindowState(app, state, attributes) {
251
251
  let headerTitle = state?.headerTitle;
252
252
  if (headerTitle) {
253
253
  if (Array.isArray(headerTitle)) {
254
- headerTitle = headerTitle.map((item) =>
255
- replaceAttributes(item, attributes),
256
- );
254
+ headerTitle = headerTitle.map((item) => renderTemplate(item, attributes));
257
255
  } else {
258
- headerTitle = replaceAttributes(headerTitle, attributes);
256
+ headerTitle = renderTemplate(headerTitle, attributes);
259
257
  }
260
258
  }
261
259
  return {
@@ -343,6 +341,16 @@ class AbstractFeatureInfoView extends VcsObject {
343
341
  return this._component;
344
342
  }
345
343
 
344
+ /**
345
+ * @param {undefined|import("ol").Feature|import("@vcmap-cesium/engine").Cesium3DTileFeature|import("@vcmap-cesium/engine").Cesium3DTilePointFeature} feature
346
+ * @returns {Object}
347
+ * @protected
348
+ */
349
+ // eslint-disable-next-line class-methods-use-this
350
+ _getAttributesFromFeature(feature) {
351
+ return feature?.getProperty('attributes') || {};
352
+ }
353
+
346
354
  /**
347
355
  * This method returns all relevant attributes for this view.
348
356
  * Called by `getProperties()` to pass attributes as props object to the VueComponent of this view.
@@ -352,7 +360,7 @@ class AbstractFeatureInfoView extends VcsObject {
352
360
  * @returns {Object}
353
361
  */
354
362
  getAttributes(feature) {
355
- let attributes = feature.getProperty('attributes') || {};
363
+ let attributes = this._getAttributesFromFeature(feature);
356
364
  if (this.attributeKeys.length > 0) {
357
365
  attributes = applyAttributeFilter(attributes, this.attributeKeys);
358
366
  }
@@ -375,7 +383,7 @@ class AbstractFeatureInfoView extends VcsObject {
375
383
  */
376
384
  getTags(feature) {
377
385
  if (this.tags) {
378
- const attributes = feature.getProperty('attributes') || {};
386
+ const attributes = this._getAttributesFromFeature(feature);
379
387
  const tags = Object.keys(this.tags)
380
388
  .filter(
381
389
  (key) =>
@@ -10,11 +10,6 @@ export function getHighlightStyle(feature: FeatureType, layer: import("@vcmap/co
10
10
  * @returns {FeatureInfoSession}
11
11
  */
12
12
  export function createFeatureInfoSession(app: import("../vcsUiApp.js").default): FeatureInfoSession;
13
- /**
14
- * @typedef {Object} FeatureInfoSession
15
- * @property {VcsEvent<void>} stopped
16
- * @property {function():void} stop
17
- */
18
13
  /**
19
14
  * @type {ClassRegistry<import("@vcmap/core").Ctor<typeof AbstractFeatureInfoView>>}
20
15
  */
@@ -43,6 +38,11 @@ export type FeatureInfoSession = {
43
38
  };
44
39
  import { ClassRegistry } from '@vcmap/core';
45
40
  import AbstractFeatureInfoView from './abstractFeatureInfoView.js';
41
+ /**
42
+ * @typedef {Object} FeatureInfoSession
43
+ * @property {VcsEvent<void>} stopped
44
+ * @property {function():void} stop
45
+ */
46
46
  /**
47
47
  * @class FeatureInfo
48
48
  * @description Provides registration of featureInfoClasses and stores featureInfoView instances.
@@ -23,6 +23,7 @@ import {
23
23
  import { Feature } from 'ol';
24
24
  import { check, maybe, oneOf } from '@vcsuite/check';
25
25
 
26
+ import { reactive } from 'vue';
26
27
  import { vcsAppSymbol } from '../pluginHelper.js';
27
28
  import FeatureInfoInteraction from './featureInfoInteraction.js';
28
29
  import AbstractFeatureInfoView from './abstractFeatureInfoView.js';
@@ -52,6 +53,17 @@ function getLogger() {
52
53
  return getLoggerByName('featureInfo');
53
54
  }
54
55
 
56
+ /**
57
+ * @type {ClassRegistry<import("@vcmap/core").Ctor<typeof AbstractFeatureInfoView>>}
58
+ */
59
+ export const featureInfoClassRegistry = new ClassRegistry();
60
+
61
+ /**
62
+ * Symbol added to features to overwrite the layers predefined feature info
63
+ * @type {symbol}
64
+ */
65
+ export const featureInfoViewSymbol = Symbol('featureInfoView');
66
+
55
67
  /**
56
68
  * @param {FeatureType} feature
57
69
  * @param {import("@vcmap/core").Layer} layer
@@ -133,7 +145,7 @@ function setupFeatureInfoTool(app) {
133
145
  /** @type {FeatureInfoSession|null} */
134
146
  let session = null;
135
147
 
136
- const action = {
148
+ const action = reactive({
137
149
  name: 'featureInfoToggle',
138
150
  title: 'featureInfo.activateToolTitle',
139
151
  icon: '$vcsInfo',
@@ -144,46 +156,65 @@ function setupFeatureInfoTool(app) {
144
156
  } else {
145
157
  session = createFeatureInfoSession(app);
146
158
  session.stopped.addEventListener(() => {
147
- this.active = false;
159
+ action.active = false;
148
160
  session = null;
149
161
  app.featureInfo.clear();
150
- this.title = 'featureInfo.activateToolTitle';
162
+ action.title = 'featureInfo.activateToolTitle';
151
163
  });
152
164
  this.active = true;
153
- this.title = 'featureInfo.deactivateToolTitle';
165
+ action.title = 'featureInfo.deactivateToolTitle';
154
166
  }
155
167
  },
156
- };
168
+ });
157
169
 
158
170
  function addFeatureInfoButton() {
159
171
  if (app.uiConfig.getByKey('startingFeatureInfo')?.value !== false) {
160
172
  action.callback();
161
173
  }
162
- app.toolboxManager.add(
163
- {
164
- id: 'featureInfo',
165
- type: ToolboxType.SINGLE,
166
- action,
167
- },
168
- vcsAppSymbol,
169
- );
174
+ if (!app.toolboxManager.has('featureInfo')) {
175
+ app.toolboxManager.add(
176
+ {
177
+ id: 'featureInfo',
178
+ type: ToolboxType.SINGLE,
179
+ action,
180
+ },
181
+ vcsAppSymbol,
182
+ );
183
+ }
170
184
  }
171
185
 
172
- if ([...app.layers].some((l) => l.properties?.featureInfo)) {
186
+ if (
187
+ [...app.layers].some((l) => l.properties?.featureInfo) ||
188
+ app.search.resultLayer.getFeatures().some((f) => !!f[featureInfoViewSymbol])
189
+ ) {
173
190
  addFeatureInfoButton();
174
191
  }
175
192
 
176
193
  const listeners = [
177
194
  app.layers.added.addEventListener((layer) => {
178
- if (
179
- layer?.properties?.featureInfo &&
180
- !app.toolboxManager.has('featureInfo')
181
- ) {
195
+ if (layer?.properties?.featureInfo) {
182
196
  addFeatureInfoButton();
183
197
  }
184
198
  }),
185
199
  app.layers.removed.addEventListener(() => {
186
200
  if (
201
+ ![...app.layers].some((l) => l.properties?.featureInfo) &&
202
+ !app.search.resultLayer
203
+ .getFeatures()
204
+ .some((f) => !!f[featureInfoViewSymbol]) &&
205
+ app.toolboxManager.has('featureInfo')
206
+ ) {
207
+ app.toolboxManager.remove('featureInfo');
208
+ }
209
+ }),
210
+ app.search.resultsChanged.addEventListener(() => {
211
+ if (
212
+ app.search.resultLayer
213
+ .getFeatures()
214
+ .some((f) => !!f[featureInfoViewSymbol])
215
+ ) {
216
+ addFeatureInfoButton();
217
+ } else if (
187
218
  ![...app.layers].some((l) => l.properties?.featureInfo) &&
188
219
  app.toolboxManager.has('featureInfo')
189
220
  ) {
@@ -207,17 +238,6 @@ function setupFeatureInfoTool(app) {
207
238
  * @property {function():void} stop
208
239
  */
209
240
 
210
- /**
211
- * @type {ClassRegistry<import("@vcmap/core").Ctor<typeof AbstractFeatureInfoView>>}
212
- */
213
- export const featureInfoClassRegistry = new ClassRegistry();
214
-
215
- /**
216
- * Symbol added to features to overwrite the layers predefined feature info
217
- * @type {symbol}
218
- */
219
- export const featureInfoViewSymbol = Symbol('featureInfoView');
220
-
221
241
  /**
222
242
  * @class FeatureInfo
223
243
  * @description Provides registration of featureInfoClasses and stores featureInfoView instances.
@@ -414,7 +434,7 @@ class FeatureInfo extends Collection {
414
434
  [featureId]: getHighlightStyle(
415
435
  feature,
416
436
  layer,
417
- this._app.uiConfig.config.value.primaryColor ??
437
+ this._app.uiConfig.config.primaryColor ??
418
438
  getDefaultPrimaryColor(this._app),
419
439
  ),
420
440
  });
@@ -426,7 +446,7 @@ class FeatureInfo extends Collection {
426
446
  [featureId]: getHighlightStyle(
427
447
  feature,
428
448
  layer,
429
- this._app.uiConfig.config.value.primaryColor ??
449
+ this._app.uiConfig.config.primaryColor ??
430
450
  getDefaultPrimaryColor(this._app),
431
451
  ),
432
452
  });
@@ -9,7 +9,7 @@ export type IframeFeatureInfoViewProps = any & {
9
9
  };
10
10
  /**
11
11
  * @typedef {import("./abstractFeatureInfoView.js").FeatureInfoViewOptions & { src: string, title?: string }} IframeFeatureInfoViewOptions
12
- * @property {string} src - Specifies the address of the document to embed in the <iframe>. Variables wrapped in `${}` are replaced by their values, e.g. `${featureId}` or `${attributes.gml:name}`
12
+ * @property {string} src - Specifies the address of the document to embed in the <iframe>. Variables wrapped in `${}` are replaced by their values, e.g. `${featureId}` or `${gml:name}`
13
13
  * @property {string} [title] - optional title for the <iframe>
14
14
  */
15
15
  /**
@@ -34,7 +34,13 @@ declare class IframeFeatureInfoView extends AbstractFeatureInfoView {
34
34
  */
35
35
  title: string | undefined;
36
36
  /**
37
- * Variables wrapped in `${}` within `src` are replaced by their values, e.g. `${featureId}` or `${attributes.gml:name}`
37
+ * @param {Record<string, unknown>} attributes
38
+ * @protected
39
+ * @returns {string}
40
+ */
41
+ protected _renderTemplate(attributes: Record<string, unknown>): string;
42
+ /**
43
+ * Supports markdown templates (e.g. {{someProperty}}) and style expressions to derive a URL
38
44
  * @param {import("./featureInfo.js").FeatureInfoEvent} featureInfo
39
45
  * @param {import("@vcmap/core").Layer} layer
40
46
  * @returns {IframeFeatureInfoViewProps}
@@ -1,9 +1,10 @@
1
+ import { renderTemplate } from '../components/form-output/markdownHelper.js';
1
2
  import AbstractFeatureInfoView from './abstractFeatureInfoView.js';
2
3
  import IframeComponent from './IframeComponent.vue';
3
4
 
4
5
  /**
5
6
  * @typedef {import("./abstractFeatureInfoView.js").FeatureInfoViewOptions & { src: string, title?: string }} IframeFeatureInfoViewOptions
6
- * @property {string} src - Specifies the address of the document to embed in the <iframe>. Variables wrapped in `${}` are replaced by their values, e.g. `${featureId}` or `${attributes.gml:name}`
7
+ * @property {string} src - Specifies the address of the document to embed in the <iframe>. Variables wrapped in `${}` are replaced by their values, e.g. `${featureId}` or `${gml:name}`
7
8
  * @property {string} [title] - optional title for the <iframe>
8
9
  */
9
10
 
@@ -41,7 +42,16 @@ class IframeFeatureInfoView extends AbstractFeatureInfoView {
41
42
  }
42
43
 
43
44
  /**
44
- * Variables wrapped in `${}` within `src` are replaced by their values, e.g. `${featureId}` or `${attributes.gml:name}`
45
+ * @param {Record<string, unknown>} attributes
46
+ * @protected
47
+ * @returns {string}
48
+ */
49
+ _renderTemplate(attributes) {
50
+ return renderTemplate(this.src, attributes);
51
+ }
52
+
53
+ /**
54
+ * Supports markdown templates (e.g. {{someProperty}}) and style expressions to derive a URL
45
55
  * @param {import("./featureInfo.js").FeatureInfoEvent} featureInfo
46
56
  * @param {import("@vcmap/core").Layer} layer
47
57
  * @returns {IframeFeatureInfoViewProps}
@@ -50,9 +60,9 @@ class IframeFeatureInfoView extends AbstractFeatureInfoView {
50
60
  const properties = super.getProperties(featureInfo, layer);
51
61
  return {
52
62
  ...properties,
53
- src: this.src.replace(/\$\{(.*?)}/g, (match, token) => {
54
- const variable = token.split('.');
55
- return variable.reduce((obj, prop) => obj?.[prop], properties);
63
+ src: this._renderTemplate({
64
+ ...properties,
65
+ ...properties.attributes,
56
66
  }),
57
67
  title: this.title,
58
68
  };
@@ -33,7 +33,7 @@ declare class MarkdownBalloonFeatureInfoView extends BalloonFeatureInfoView {
33
33
  */
34
34
  protected _renderTemplate(attributes: Record<string, unknown>): string;
35
35
  /**
36
- * Variables wrapped in `${}` within `src` are replaced by their values, e.g. `${featureId}` or `${attributes.gml:name}`
36
+ * Supports markdown templates (e.g. {{someProperty}}) and style expressions to derive markdown rendering
37
37
  * @param {import("./featureInfo.js").FeatureInfoEvent} featureInfo
38
38
  * @param {import("@vcmap/core").Layer} layer
39
39
  * @returns {MarkdownBalloonFeatureInfoViewProps}
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  parseAndSanitizeMarkdown,
3
- replaceAttributes,
4
- } from '../application/markdownHelper.js';
3
+ renderTemplate,
4
+ } from '../components/form-output/markdownHelper.js';
5
5
  import BalloonFeatureInfoView from './balloonFeatureInfoView.js';
6
6
  import MarkdownBalloonComponent from './MarkdownBalloonComponent.vue';
7
7
 
@@ -47,11 +47,11 @@ class MarkdownBalloonFeatureInfoView extends BalloonFeatureInfoView {
47
47
  * @returns {string}
48
48
  */
49
49
  _renderTemplate(attributes) {
50
- return replaceAttributes(this.template, attributes);
50
+ return renderTemplate(this.template, attributes);
51
51
  }
52
52
 
53
53
  /**
54
- * Variables wrapped in `${}` within `src` are replaced by their values, e.g. `${featureId}` or `${attributes.gml:name}`
54
+ * Supports markdown templates (e.g. {{someProperty}}) and style expressions to derive markdown rendering
55
55
  * @param {import("./featureInfo.js").FeatureInfoEvent} featureInfo
56
56
  * @param {import("@vcmap/core").Layer} layer
57
57
  * @returns {MarkdownBalloonFeatureInfoViewProps}
@@ -60,7 +60,7 @@ class MarkdownBalloonFeatureInfoView extends BalloonFeatureInfoView {
60
60
  const properties = super.getProperties(featureInfo, layer);
61
61
  return {
62
62
  ...properties,
63
- html: parseAndSanitizeMarkdown(
63
+ content: parseAndSanitizeMarkdown(
64
64
  this._renderTemplate({ ...properties, ...properties.attributes }),
65
65
  ),
66
66
  };
@@ -33,7 +33,7 @@ declare class MarkdownFeatureInfoView extends AbstractFeatureInfoView {
33
33
  */
34
34
  protected _renderTemplate(attributes: Record<string, unknown>): string;
35
35
  /**
36
- * Variables wrapped in `${}` within `src` are replaced by their values, e.g. `${featureId}` or `${attributes.gml:name}`
36
+ * Supports markdown templates (e.g. {{someProperty}}) and style expressions to derive a markdown rendering
37
37
  * @param {import("./featureInfo.js").FeatureInfoEvent} featureInfo
38
38
  * @param {import("@vcmap/core").Layer} layer
39
39
  * @returns {MarkdownFeatureInfoViewProps}
@@ -1,9 +1,6 @@
1
+ import { renderTemplate } from '../components/form-output/markdownHelper.js';
1
2
  import AbstractFeatureInfoView from './abstractFeatureInfoView.js';
2
- import {
3
- parseAndSanitizeMarkdown,
4
- replaceAttributes,
5
- } from '../application/markdownHelper.js';
6
- import MarkdownComponent from './MarkdownComponent.vue';
3
+ import VcsMarkdown from '../components/form-output/VcsMarkdown.vue';
7
4
 
8
5
  /**
9
6
  * @typedef {import("./abstractFeatureInfoView.js").FeatureInfoViewOptions & { template: string | string[] }} MarkdownFeatureInfoViewOptions
@@ -31,7 +28,7 @@ class MarkdownFeatureInfoView extends AbstractFeatureInfoView {
31
28
  * @param {MarkdownFeatureInfoViewOptions} options
32
29
  */
33
30
  constructor(options) {
34
- super(options, MarkdownComponent);
31
+ super(options, VcsMarkdown);
35
32
 
36
33
  /**
37
34
  * @type {string | string[]}
@@ -47,11 +44,11 @@ class MarkdownFeatureInfoView extends AbstractFeatureInfoView {
47
44
  * @returns {string}
48
45
  */
49
46
  _renderTemplate(attributes) {
50
- return replaceAttributes(this.template, attributes);
47
+ return renderTemplate(this.template, attributes);
51
48
  }
52
49
 
53
50
  /**
54
- * Variables wrapped in `${}` within `src` are replaced by their values, e.g. `${featureId}` or `${attributes.gml:name}`
51
+ * Supports markdown templates (e.g. {{someProperty}}) and style expressions to derive a markdown rendering
55
52
  * @param {import("./featureInfo.js").FeatureInfoEvent} featureInfo
56
53
  * @param {import("@vcmap/core").Layer} layer
57
54
  * @returns {MarkdownFeatureInfoViewProps}
@@ -60,9 +57,10 @@ class MarkdownFeatureInfoView extends AbstractFeatureInfoView {
60
57
  const properties = super.getProperties(featureInfo, layer);
61
58
  return {
62
59
  ...properties,
63
- html: parseAndSanitizeMarkdown(
64
- this._renderTemplate({ ...properties, ...properties.attributes }),
65
- ),
60
+ content: this._renderTemplate({
61
+ ...properties,
62
+ ...properties.attributes,
63
+ }),
66
64
  };
67
65
  }
68
66
 
@@ -79,6 +79,19 @@ class TableFeatureInfoView extends AbstractFeatureInfoView {
79
79
  this.searchbarPlaceholder = options.searchbarPlaceholder;
80
80
  }
81
81
 
82
+ /**
83
+ * @param {undefined|import("ol").Feature|import("@vcmap-cesium/engine").Cesium3DTileFeature|import("@vcmap-cesium/engine").Cesium3DTilePointFeature} feature
84
+ * @returns {Object}
85
+ * @private
86
+ */
87
+ _getAttributesFromFeature(feature) {
88
+ const attributes = super._getAttributesFromFeature(feature);
89
+ return {
90
+ ...attributes,
91
+ featureId: feature.getId(),
92
+ };
93
+ }
94
+
82
95
  /**
83
96
  * @param {import("./featureInfo.js").FeatureInfoEvent} featureInfo
84
97
  * @param {import("@vcmap/core").Layer} layer
@@ -92,10 +105,6 @@ class TableFeatureInfoView extends AbstractFeatureInfoView {
92
105
  itemsPerPageArray: this.itemsPerPageArray,
93
106
  showSearchbar: this.showSearchbar,
94
107
  searchbarPlaceholder: this.searchbarPlaceholder,
95
- headers: [
96
- { text: 'components.vcsTable.key', value: 'key', width: '128px' },
97
- { text: 'components.vcsTable.value', value: 'value', width: '192px' },
98
- ],
99
108
  };
100
109
  }
101
110