@vcmap/ui 5.0.0-rc.10 → 5.0.0-rc.13

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 (165) hide show
  1. package/README.md +12 -5
  2. package/build/build.js +6 -3
  3. package/build/buildHelpers.js +12 -4
  4. package/build/buildPreview.js +7 -0
  5. package/build/getPluginProxies.js +4 -0
  6. package/config/aerowest.config.json +13 -3
  7. package/config/base.config.json +398 -219
  8. package/config/codes.config.json +397 -0
  9. package/config/dev.config.json +375 -1
  10. package/config/graphFeatureInfo.config.json +100 -0
  11. package/config/www.config.json +1232 -0
  12. package/dist/assets/{cesium.eb5667.js → cesium.21663e.js} +0 -0
  13. package/dist/assets/cesium.js +1 -1
  14. package/dist/assets/core.63242d.js +4 -0
  15. package/dist/assets/core.js +1 -1
  16. package/dist/assets/font/OFL.txt +93 -0
  17. package/dist/assets/font/TitilliumWeb-Regular.woff2 +0 -0
  18. package/dist/assets/{index.4ccd4433.js → index.44b91cfe.js} +1 -1
  19. package/dist/assets/{ol.ef03b1.js → ol.88ba9d.js} +0 -0
  20. package/dist/assets/ol.js +1 -1
  21. package/dist/assets/ui.3c2933.css +1 -0
  22. package/dist/assets/ui.3c2933.js +71 -0
  23. package/dist/assets/ui.js +1 -1
  24. package/dist/assets/vue.c897fc.js +9 -0
  25. package/dist/assets/vue.js +2 -1
  26. package/dist/assets/{vuetify.401a29.css → vuetify.147c3a.css} +1 -1
  27. package/dist/assets/{vuetify.401a29.js → vuetify.147c3a.js} +72 -72
  28. package/dist/assets/vuetify.js +2 -2
  29. package/dist/index.html +1 -5
  30. package/index.js +39 -5
  31. package/lib/vue.js +1 -0
  32. package/map.config.json +15 -6
  33. package/package.json +17 -8
  34. package/plugins/@vcmap/create-link/fallbackCreateLink.vue +71 -0
  35. package/plugins/@vcmap/create-link/index.js +83 -0
  36. package/plugins/@vcmap/create-link/package.json +6 -0
  37. package/plugins/@vcmap/pluginExample/index.js +2 -2
  38. package/plugins/@vcmap/pluginExample/pluginExampleComponent.vue +20 -3
  39. package/plugins/@vcmap/project-selector/ProjectSelectorComponent.vue +1 -1
  40. package/plugins/@vcmap/project-selector/index.js +1 -1
  41. package/plugins/@vcmap/project-selector/package.json +1 -2
  42. package/plugins/@vcmap/theme-changer/ThemeChangerComponent.vue +1 -1
  43. package/plugins/@vcmap/theme-changer/index.js +1 -1
  44. package/plugins/@vcmap/theme-changer/package.json +1 -2
  45. package/plugins/categoryTest/Categories.vue +89 -1
  46. package/plugins/categoryTest/Category.vue +1 -1
  47. package/plugins/example/index.js +10 -23
  48. package/plugins/simple-graph/README.md +51 -0
  49. package/plugins/simple-graph/SimpleGraphComponent.vue +70 -0
  50. package/plugins/simple-graph/index.js +17 -0
  51. package/plugins/simple-graph/package.json +11 -0
  52. package/plugins/simple-graph/simpleGraphView.js +76 -0
  53. package/plugins/test/editor.vue +1 -1
  54. package/plugins/test/index.js +76 -9
  55. package/plugins/test/toolbox-data.js +82 -57
  56. package/plugins/test/windowManagerExample.vue +1 -1
  57. package/src/actions/stateRefAction.js +2 -2
  58. package/src/actions/styleSelector.vue +1 -1
  59. package/src/application/Navbar.vue +13 -2
  60. package/src/application/VcsApp.vue +301 -116
  61. package/src/application/VcsMap.vue +1 -1
  62. package/src/application/VcsSettings.vue +1 -1
  63. package/src/application/vcsAppWrapper.vue +1 -0
  64. package/src/assets/font/OFL.txt +93 -0
  65. package/src/assets/font/TitilliumWeb-Regular.woff2 +0 -0
  66. package/src/components/form-inputs-controls/VcsCheckbox.vue +13 -0
  67. package/src/components/form-inputs-controls/VcsColorPicker.vue +1 -1
  68. package/src/components/form-inputs-controls/VcsRadio.vue +123 -0
  69. package/src/components/form-output/VcsFormattedNumber.vue +1 -1
  70. package/src/components/lists/VcsActionList.vue +22 -7
  71. package/src/components/lists/VcsTreeview.vue +4 -4
  72. package/src/components/lists/VcsTreeviewLeaf.vue +10 -3
  73. package/src/components/lists/VcsTreeviewSearchbar.vue +1 -2
  74. package/src/components/tables/VcsTable.vue +245 -0
  75. package/src/contentTree/LayerTree.vue +1 -1
  76. package/src/contentTree/contentTreeCollection.js +4 -4
  77. package/src/contentTree/contentTreeItem.js +9 -9
  78. package/src/contentTree/groupContentTreeItem.js +1 -1
  79. package/src/contentTree/layerContentTreeItem.js +15 -1
  80. package/src/contentTree/layerGroupContentTreeItem.js +21 -1
  81. package/src/contentTree/nodeContentTreeItem.js +1 -1
  82. package/src/featureInfo/AddressBalloonComponent.vue +47 -0
  83. package/src/featureInfo/BalloonComponent.vue +140 -0
  84. package/src/featureInfo/abstractFeatureInfoView.js +313 -0
  85. package/src/featureInfo/addressBalloonFeatureInfoView.js +118 -0
  86. package/src/featureInfo/balloonFeatureInfoView.js +151 -0
  87. package/src/featureInfo/balloonHelper.js +132 -0
  88. package/src/featureInfo/featureInfo.js +457 -0
  89. package/src/featureInfo/featureInfoInteraction.js +42 -0
  90. package/src/featureInfo/iframeFeatureInfoView.js +95 -0
  91. package/src/featureInfo/tableFeatureInfoView.js +106 -0
  92. package/src/i18n/de.js +26 -0
  93. package/src/i18n/en.js +26 -0
  94. package/src/i18n/i18nCollection.js +17 -0
  95. package/src/icons/+all.js +80 -0
  96. package/src/icons/ClippingHorizontalIcon.vue +7 -0
  97. package/src/icons/ClippingIcon.vue +7 -0
  98. package/src/icons/ClippingVerticalIcon.vue +7 -0
  99. package/src/icons/ColorPickerIcon.vue +7 -0
  100. package/src/icons/ComponentsIcon.vue +2 -2
  101. package/src/icons/DimensionsHouseIcon.vue +11 -9
  102. package/src/icons/EditIcon.vue +7 -0
  103. package/src/icons/GlobalTerrainIcon.vue +9 -0
  104. package/src/icons/GroundIcon.vue +18 -0
  105. package/src/icons/HideIcon.vue +12 -0
  106. package/src/icons/LogoutIcon.vue +7 -0
  107. package/src/icons/ObjectAttributeIcon.vue +2 -13
  108. package/src/icons/PedestrianIcon.vue +2 -3
  109. package/src/icons/PenIcon.vue +2 -9
  110. package/src/icons/PoiIcon.vue +5 -2
  111. package/src/icons/PointSelectIcon.vue +4 -2
  112. package/src/icons/QueryIcon.vue +6 -7
  113. package/src/icons/ScreenshotIcon.vue +16 -0
  114. package/src/icons/ShareIcon.vue +4 -16
  115. package/src/icons/SkipNextIcon.vue +3 -1
  116. package/src/icons/TerrainBoxIcon.vue +9 -0
  117. package/src/icons/ToolsIcon.vue +4 -30
  118. package/src/icons/UploadIcon.vue +2 -9
  119. package/src/icons/UserProfileIcon.vue +7 -0
  120. package/src/icons/UserShareIcon.vue +7 -0
  121. package/src/icons/VideoRecorderIcon.vue +5 -9
  122. package/src/icons/ViewpointFlightIcon.vue +11 -0
  123. package/src/icons/ViewpointIcon.vue +11 -0
  124. package/src/icons/Viewshed360Icon.vue +7 -0
  125. package/src/icons/ViewshedConeIcon.vue +7 -0
  126. package/src/icons/ViewshedIcon.vue +7 -0
  127. package/src/icons/WallIcon.vue +4 -9
  128. package/src/legend/legendHelper.js +193 -0
  129. package/src/legend/styleLegendItem.vue +129 -0
  130. package/src/legend/vcsLegend.vue +92 -0
  131. package/src/manager/buttonManager.js +7 -12
  132. package/src/manager/categoryManager/ComponentsManager.vue +30 -0
  133. package/src/manager/categoryManager/categoryManager.js +500 -0
  134. package/src/manager/contextMenu/contextMenuComponent.vue +43 -0
  135. package/src/manager/contextMenu/contextMenuInteraction.js +42 -0
  136. package/src/manager/contextMenu/contextMenuManager.js +197 -0
  137. package/src/manager/navbarManager.js +9 -9
  138. package/src/manager/toolbox/GroupToolboxComponent.vue +118 -0
  139. package/src/manager/toolbox/SelectToolboxComponent.vue +128 -0
  140. package/src/manager/toolbox/ToolboxManager.vue +116 -98
  141. package/src/manager/toolbox/toolboxManager.js +235 -86
  142. package/src/manager/window/WindowComponent.vue +1 -1
  143. package/src/manager/window/WindowManager.vue +5 -3
  144. package/src/manager/window/windowManager.js +118 -14
  145. package/src/navigation/mapNavigation.vue +3 -5
  146. package/src/navigation/overviewMap.js +28 -5
  147. package/src/navigation/vcsCompass.vue +1 -1
  148. package/src/pluginHelper.js +42 -10
  149. package/src/setup.js +0 -2
  150. package/src/state.js +256 -0
  151. package/src/styles/_theming.scss +0 -5
  152. package/src/styles/variables.scss +7 -0
  153. package/src/styles/vcsFont.scss +17 -0
  154. package/src/uiConfig.js +79 -0
  155. package/src/vcsUiApp.js +213 -22
  156. package/src/vuePlugins/vuetify.js +14 -4
  157. package/config/berlin.config.json +0 -510
  158. package/dist/assets/core.216494.js +0 -4
  159. package/dist/assets/ui.99a1a7.css +0 -1
  160. package/dist/assets/ui.99a1a7.js +0 -70
  161. package/dist/assets/vue-composition-api.c5aca1.js +0 -14
  162. package/dist/assets/vue-composition-api.js +0 -2
  163. package/dist/assets/vue.762edd.js +0 -9
  164. package/lib/vue-composition-api.js +0 -2
  165. package/src/manager/toolbox/ToolboxGroupComponent.vue +0 -128
@@ -0,0 +1,123 @@
1
+ <template>
2
+ <VcsTooltip
3
+ :tooltip-position="tooltipPosition"
4
+ :tooltip="errorMessage"
5
+ color="error"
6
+ >
7
+ <template #activator="{ on, attrs }">
8
+ <span v-on="on">
9
+ <v-radio-group
10
+ hide-details
11
+ class="w-full vcs-radio-group"
12
+ :dense="$attrs.dense!==false"
13
+ :ripple="false"
14
+ v-bind="{...$attrs, ...attrs}"
15
+ v-on="{...$listeners, ...on}"
16
+ @update:error="setError"
17
+ >
18
+ <v-radio
19
+ v-for="(item, idx) in items"
20
+ :id="`radio-${idx}`"
21
+ :key="`radio-${idx}`"
22
+ :ripple="false"
23
+ :color="item.color ?? 'secondary'"
24
+ :value="item.value ?? item"
25
+ :disabled="item.disabled ?? false"
26
+ :class="$attrs.dense!==false ? 'vcs-radio-dense' : 'vcs-radio'"
27
+ >
28
+ <template #label>
29
+ <VcsLabel :html-for="`radio-${idx}`" :dense="!!$attrs.dense">
30
+ {{ $t(item.label ?? item) }}
31
+ </VcsLabel>
32
+ </template>
33
+ </v-radio>
34
+ </v-radio-group>
35
+ </span>
36
+ </template>
37
+ </VcsTooltip>
38
+ </template>
39
+ <style lang="scss" scoped>
40
+ @import "../../styles/vcsFont";
41
+ .v-input--radio-group--column .v-radio:not(:last-child):not(:only-child) {
42
+ margin-bottom: 0;
43
+ }
44
+ .v-input{
45
+ &.vcs-radio-group{
46
+ ::v-deep {
47
+ margin-top: 0;
48
+ padding-top: 0;
49
+ label.v-label,
50
+ .v-icon.v-icon{
51
+ font-size: $base-font-size;
52
+ color: inherit;
53
+ }
54
+ .v-radio:not(:last-child):not(:only-child){
55
+ margin-bottom: 0;
56
+ }
57
+ .v-input--selection-controls__input{
58
+ margin: 0;
59
+ }
60
+ }
61
+ }
62
+ }
63
+ .vcs-radio {
64
+ height: 40px;
65
+ align-items: center;
66
+ }
67
+ .vcs-radio-dense {
68
+ height: 32px;
69
+ align-items: center;
70
+ }
71
+ </style>
72
+ <script>
73
+ import VcsTooltip from '../notification/VcsTooltip.vue';
74
+ import VcsLabel from './VcsLabel.vue';
75
+ import validate from '../notification/validation.js';
76
+
77
+ /**
78
+ * @typedef {Object} VcsRadioItem
79
+ * @property {string} label
80
+ * @property {string} [color='secondary']
81
+ * @property {any} value
82
+ * @property {boolean} [disabled=false]
83
+ */
84
+
85
+ /**
86
+ * @description Stylized wrapper around {@link https://vuetifyjs.com/en/api/v-radio-group/ |vuetify v-radio-group} using
87
+ * {@link https://vuetifyjs.com/en/api/v-radio/ |vuetify v-radio}.
88
+ * Provides two height options depending on "dense" property:
89
+ * - if dense is set true (default), height is 24 px
90
+ * - if dense is set false, height is 32 px
91
+ * Provides VcsTooltip to show error messages
92
+ * @vue-prop {('bottom' | 'left' | 'top' | 'right')} [tooltipPosition='right'] - Position of the error tooltip.
93
+ * @vue-prop {Array<string|VcsRadioItem>} items - A list of options. If strings are provided, the string is used as label and value.
94
+ */
95
+ export default {
96
+ name: 'VcsRadio',
97
+ components: { VcsTooltip, VcsLabel },
98
+ props: {
99
+ tooltipPosition: {
100
+ type: String,
101
+ default: 'right',
102
+ },
103
+ items: {
104
+ type: Array,
105
+ required: true,
106
+ },
107
+ },
108
+ data() {
109
+ return {
110
+ errorMessage: '',
111
+ };
112
+ },
113
+ methods: {
114
+ setError() {
115
+ const rules = [...this.$attrs.rules].concat(this.$attrs.errorMessages);
116
+ this.errorMessage = validate(rules, this.$attrs.value).join('\n');
117
+ },
118
+ },
119
+ model: {
120
+ event: 'change',
121
+ },
122
+ };
123
+ </script>
@@ -27,7 +27,7 @@
27
27
  }
28
28
  </style>
29
29
  <script>
30
- import { computed } from '@vue/composition-api';
30
+ import { computed } from 'vue';
31
31
 
32
32
  /**
33
33
  * Converts a number (e.g. 12345678,9) to a locale-aware and
@@ -51,20 +51,35 @@
51
51
  * @property {boolean} [active=false] - optional state of button. If active, button is rendered in primary color
52
52
  */
53
53
 
54
+ /**
55
+ * pattern to check actions
56
+ * @type {Object}
57
+ */
58
+ export const ActionPattern = {
59
+ name: String,
60
+ title: [undefined, String],
61
+ icon: [undefined, String],
62
+ callback: Function,
63
+ active: [undefined, Boolean],
64
+ };
65
+
66
+ /**
67
+ * @param {VcsAction} action
68
+ * @returns {boolean}
69
+ */
70
+ export function validateAction(action) {
71
+ return is(action, ActionPattern);
72
+ }
73
+
54
74
  /**
55
75
  * @param {Array<VcsAction>} actions
56
76
  * @returns {boolean}
57
77
  */
58
78
  export function validateActions(actions) {
59
- return actions.every(item => is(item, {
60
- name: String,
61
- title: [undefined, String],
62
- icon: [undefined, String],
63
- callback: Function,
64
- active: [undefined, Boolean],
65
- }));
79
+ return actions.every(validateAction);
66
80
  }
67
81
 
82
+
68
83
  /**
69
84
  * @description
70
85
  * A component rendering a list of actions with overflow mechanic using
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <div class="d-contents">
3
3
  <VcsTreeviewSearchbar
4
- v-if="hasSearchbar"
4
+ v-if="showSearchbar"
5
5
  :placeholder="searchbarPlaceholder"
6
6
  v-model="search"
7
7
  />
@@ -55,7 +55,7 @@
55
55
  </style>
56
56
 
57
57
  <script>
58
- import { getCurrentInstance, ref } from '@vue/composition-api';
58
+ import { getCurrentInstance, ref } from 'vue';
59
59
  import VcsTreeviewLeaf from './VcsTreeviewLeaf.vue';
60
60
  import VcsTreeviewSearchbar from './VcsTreeviewSearchbar.vue';
61
61
 
@@ -63,14 +63,14 @@
63
63
  * @description extends API of https://vuetifyjs.com/en/api/v-treeview/
64
64
  * Can render dynamic components as leaf items.
65
65
  * In order to display an item needs to be registered and added to `availableComponents`.
66
- * @vue-prop {boolean} [hasSearchbar=false] - Whether there is a searchbar for this treeview
66
+ * @vue-prop {boolean} [showSearchbar=false] - Whether there is a searchbar for this treeview
67
67
  * @vue-prop {string} [searchbarPlaceholder] - Placeholder text for the searchbar, will be translated
68
68
  */
69
69
  export default {
70
70
  name: 'VcsTreeview',
71
71
  components: { VcsTreeviewSearchbar, VcsTreeviewLeaf },
72
72
  props: {
73
- hasSearchbar: {
73
+ showSearchbar: {
74
74
  type: Boolean,
75
75
  default: false,
76
76
  },
@@ -13,7 +13,7 @@
13
13
  <span ref="imgContainer" />
14
14
  </span>
15
15
 
16
- <div class="position-relative col-8 pa-0 d-flex align-center">
16
+ <div class="position-relative col-8 pa-0 d-flex align-center treeview-label" :title="$t(item.title)">
17
17
  <span>{{ $t(item.title) }}</span>
18
18
  </div>
19
19
  <VcsActionButtonList
@@ -27,6 +27,13 @@
27
27
  />
28
28
  </div>
29
29
  </template>
30
+ <style lang="css" scoped>
31
+ .treeview-label span{
32
+ white-space: nowrap;
33
+ overflow: hidden;
34
+ text-overflow: ellipsis;
35
+ }
36
+ </style>
30
37
 
31
38
  <script>
32
39
  import
@@ -34,7 +41,7 @@
34
41
  computed,
35
42
  onMounted,
36
43
  ref,
37
- } from '@vue/composition-api';
44
+ } from 'vue';
38
45
 
39
46
  import VcsActionButtonList from '../buttons/VcsActionButtonList.vue';
40
47
 
@@ -61,7 +68,7 @@
61
68
  const iconType = ref();
62
69
  const imgContainer = ref();
63
70
 
64
- const leaf = computed(() => props.item.children.length === 0);
71
+ const leaf = computed(() => props.item?.children?.length === 0);
65
72
 
66
73
  onMounted(() => { // TODO make icon reactive
67
74
  const { icon } = props.item;
@@ -104,7 +104,7 @@
104
104
 
105
105
 
106
106
  <script>
107
- import { onMounted, onUnmounted } from '@vue/composition-api';
107
+ import { onMounted, onUnmounted } from 'vue';
108
108
 
109
109
  import { Subject } from 'rxjs';
110
110
  import { debounceTime } from 'rxjs/operators';
@@ -147,7 +147,6 @@
147
147
  onUnmounted(() => sub.unsubscribe());
148
148
 
149
149
  return {
150
- sub,
151
150
  handleInput: (val) => {
152
151
  sub.next(val);
153
152
  },
@@ -0,0 +1,245 @@
1
+ <template>
2
+ <v-card>
3
+ <VcsTreeviewSearchbar
4
+ v-if="showSearchbar"
5
+ :placeholder="$t(searchbarPlaceholder)"
6
+ v-model="search"
7
+ />
8
+ <v-data-table
9
+ dense
10
+ item-key="key"
11
+ :headers="translatedHeaders"
12
+ :items="items"
13
+ :items-per-page.sync="itemsPerPageRef"
14
+ :page.sync="page"
15
+ :search="search"
16
+ :custom-filter="handleFilter"
17
+ hide-default-footer
18
+ class="vcs-table"
19
+ >
20
+ <!-- eslint-disable-next-line -->
21
+ <template #item.key="{ item }">
22
+ <td class="vcs-table">
23
+ {{ $t(item.key) }}
24
+ </td>
25
+ </template>
26
+ <!-- eslint-disable-next-line -->
27
+ <template #item.value="{ item }">
28
+ <td class="vcs-table">
29
+ {{ $t(item.value) }}
30
+ </td>
31
+ </template>
32
+ <template #footer>
33
+ <v-divider />
34
+ <v-container class="pa-2" v-if="items.length > itemsPerPageRef">
35
+ <v-row
36
+ dense
37
+ no-gutters
38
+ align="center"
39
+ justify="center"
40
+ >
41
+ <v-menu offset-y dense>
42
+ <template #activator="{ on, attrs }">
43
+ <VcsButton
44
+ small
45
+ color="primary"
46
+ v-bind="attrs"
47
+ v-on="on"
48
+ >
49
+ {{ itemsPerPageRef }}
50
+ <v-icon>mdi-chevron-down</v-icon>
51
+ </VcsButton>
52
+ </template>
53
+ <v-list>
54
+ <v-list-item
55
+ v-for="(number, index) in itemsPerPageArray"
56
+ :key="index"
57
+ @click="updateItemsPerPage(number)"
58
+ >
59
+ <v-list-item-title>{{ number }}</v-list-item-title>
60
+ </v-list-item>
61
+ </v-list>
62
+ </v-menu>
63
+ <span class="grey--text mx-2">{{ $t('components.vcsTable.itemsPerPage') }}</span>
64
+ <span class="grey--text mx-2">{{ itemsFrom }} - {{ itemsTo }} of {{ items.length }}</span>
65
+ <VcsButton
66
+ small
67
+ icon="mdi-chevron-left"
68
+ @click="formerPage"
69
+ tooltip="components.vcsTable.formerPage"
70
+ :disabled="page < 2"
71
+ class="mx-2"
72
+ />
73
+ <VcsButton
74
+ small
75
+ icon="mdi-chevron-right"
76
+ @click="nextPage"
77
+ tooltip="components.vcsTable.nextPage"
78
+ :disabled="page > numberOfPages - 1"
79
+ class="mx-1"
80
+ />
81
+ </v-row>
82
+ </v-container>
83
+ </template>
84
+ </v-data-table>
85
+ </v-card>
86
+ </template>
87
+ <script>
88
+ import { getCurrentInstance, ref, computed } from 'vue';
89
+ import VcsTreeviewSearchbar from '../lists/VcsTreeviewSearchbar.vue';
90
+ import VcsButton from '../buttons/VcsButton.vue';
91
+
92
+ /**
93
+ * @typedef {Object} TableItem
94
+ * @property {string} key
95
+ * @property {string} value
96
+ */
97
+
98
+ /**
99
+ * @param {Object} attributes
100
+ * @param {Array<TableItem>} [items]
101
+ * @param {string} [parent]
102
+ * @returns {Array<TableItem>}
103
+ */
104
+ export function attributesToItems(attributes, items = [], parent = undefined) {
105
+ const nestedKey = (key, nested) => (nested ? `${nested}.${key}` : key);
106
+ Object.entries(attributes).forEach(([key, value]) => {
107
+ if (value instanceof Object) {
108
+ attributesToItems(value, items, nestedKey(key, parent));
109
+ } else {
110
+ const item = { key: nestedKey(key, parent), value };
111
+ if (parent) { item.group = parent; }
112
+ items.push(item);
113
+ }
114
+ });
115
+ return items;
116
+ }
117
+
118
+ /**
119
+ * @description A table view for feature attributes using {@link https://vuetifyjs.com/en/api/v-data-table/#props|vuetify v-data-table }
120
+ * @vue-prop {string} featureId - feature's id
121
+ * @vue-prop {Object} attributes - feature's attributes
122
+ * @vue-prop {Array<{text: string, value: string}>} [headers] - optional array defining column names
123
+ * @vue-prop {boolean} [showSearchbar=true] - whether to show searchbar
124
+ * @vue-prop {string} [searchbarPlaceholder='Search'] - placeholder for searchbar
125
+ * @vue-computed {Array<{key:string,value:string}>} items - from attributes derived table items
126
+ */
127
+ export default {
128
+ name: 'VcsTable',
129
+ components: { VcsButton, VcsTreeviewSearchbar },
130
+ props: {
131
+ featureId: {
132
+ type: String,
133
+ required: true,
134
+ },
135
+ attributes: {
136
+ type: Object,
137
+ required: true,
138
+ },
139
+ headers: {
140
+ type: Array,
141
+ default: () => [
142
+ { text: 'components.vcsTable.key', value: 'key', width: '160px' },
143
+ { text: 'components.vcsTable.value', value: 'value', width: '160px' },
144
+ ],
145
+ },
146
+ itemsPerPage: {
147
+ type: Number,
148
+ default: 10,
149
+ },
150
+ itemsPerPageArray: {
151
+ type: Array,
152
+ default: () => [5, 10, 15],
153
+ },
154
+ showSearchbar: {
155
+ type: Boolean,
156
+ default: true,
157
+ },
158
+ searchbarPlaceholder: {
159
+ type: String,
160
+ default: 'components.vcsTable.searchbarPlaceholder',
161
+ },
162
+ },
163
+ setup(props) {
164
+ const vm = getCurrentInstance().proxy;
165
+
166
+ const items = computed(() => {
167
+ return attributesToItems({
168
+ featureId: props.featureId,
169
+ ...props.attributes,
170
+ });
171
+ });
172
+
173
+ const translatedHeaders = computed(() => {
174
+ return props.headers.map((hd) => {
175
+ hd.text = vm.$t(hd.text);
176
+ return hd;
177
+ });
178
+ });
179
+
180
+ const itemsPerPageRef = ref(props.itemsPerPage);
181
+ const numberOfPages = computed(() => {
182
+ return Math.ceil(items.value.length / itemsPerPageRef.value);
183
+ });
184
+
185
+ const page = ref(1);
186
+ const itemsFrom = computed(() => ((page.value - 1) * itemsPerPageRef.value) + 1);
187
+ const itemsTo = computed(() => {
188
+ const last = page.value * itemsPerPageRef.value;
189
+ return last < items.value.length ? last : items.value.length;
190
+ });
191
+
192
+ /**
193
+ * @param {any} value
194
+ * @param {string} search
195
+ * @param {TableItem} item
196
+ * @returns {boolean}
197
+ */
198
+ // eslint-disable-next-line default-param-last
199
+ const handleFilter = (value, search = '', item) => {
200
+ const q = search.toLocaleLowerCase();
201
+ return [item.key, item.value].some((i) => {
202
+ const content = i.toString();
203
+ const translated = vm.$t(content);
204
+ return translated.toLowerCase().includes(q) || content.toLowerCase().includes(q);
205
+ });
206
+ };
207
+
208
+ return {
209
+ search: ref(''),
210
+ page,
211
+ items,
212
+ itemsPerPageRef,
213
+ itemsFrom,
214
+ itemsTo,
215
+ numberOfPages,
216
+ nextPage() {
217
+ if (page.value + 1 <= numberOfPages.value) {
218
+ page.value += 1;
219
+ }
220
+ },
221
+ formerPage() {
222
+ if (page.value - 1 >= 1) {
223
+ page.value -= 1;
224
+ }
225
+ },
226
+ updateItemsPerPage(number) {
227
+ itemsPerPageRef.value = number;
228
+ },
229
+ handleFilter,
230
+ translatedHeaders,
231
+ };
232
+ },
233
+ };
234
+ </script>
235
+
236
+ <style lang="scss" scoped>
237
+ .vcs-table {
238
+ td {
239
+ max-width: 160px;
240
+ overflow: hidden;
241
+ text-overflow: ellipsis;
242
+ white-space: nowrap;
243
+ }
244
+ }
245
+ </style>
@@ -10,7 +10,7 @@
10
10
  </template>
11
11
 
12
12
  <script>
13
- import { inject } from '@vue/composition-api';
13
+ import { inject } from 'vue';
14
14
  import VcsTreeview from '../components/lists/VcsTreeview.vue';
15
15
 
16
16
  /**
@@ -1,7 +1,7 @@
1
1
  // eslint-disable-next-line max-classes-per-file
2
2
  import { IndexedCollection, makeOverrideCollection, getObjectFromClassRegistry } from '@vcmap/core';
3
3
  import { v4 as uuid } from 'uuid';
4
- import { computed, ref } from '@vue/composition-api';
4
+ import { computed, ref } from 'vue';
5
5
  import ContentTreeItem from './contentTreeItem.js';
6
6
  import { vcsAppSymbol } from '../pluginHelper.js';
7
7
  import SubContentTreeItem, { subTreeSymbol } from './subContentTreeItem.js';
@@ -73,7 +73,7 @@ class ContentTreeCollection extends IndexedCollection {
73
73
  */
74
74
  this._defaultSubtreeItem = new SubContentTreeItem({ name: 'Content', icon: '$vcsLayers', title: 'content.title' }, app);
75
75
  /**
76
- * @type {import("@vue/composition-api").Ref<Map<string, TreeViewItem>>}
76
+ * @type {import("vue").Ref<Map<string, TreeViewItem>>}
77
77
  * @private
78
78
  */
79
79
  this._subTreeViewItems = ref(new Map());
@@ -211,7 +211,7 @@ class ContentTreeCollection extends IndexedCollection {
211
211
 
212
212
  /**
213
213
  * @param {string} id
214
- * @returns {import("@vue/composition-api").ComputedRef<Array<TreeViewItem>>}
214
+ * @returns {import("vue").ComputedRef<Array<TreeViewItem>>}
215
215
  */
216
216
  getComputedVisibleTree(id) {
217
217
  return computed(() => {
@@ -253,7 +253,7 @@ class ContentTreeCollection extends IndexedCollection {
253
253
 
254
254
  /**
255
255
  * @param {string} id
256
- * @returns {import("@vue/composition-api").Ref<Array<string>>}
256
+ * @returns {import("vue").Ref<Array<string>>}
257
257
  */
258
258
  getTreeOpenStateRef(id) {
259
259
  const subTree = this._getSubTree(id);
@@ -1,4 +1,4 @@
1
- import { ref, reactive, computed } from '@vue/composition-api';
1
+ import { ref, reactive, computed } from 'vue';
2
2
  import { check, checkMaybe } from '@vcsuite/check';
3
3
  import { parseBoolean, parseNumber } from '@vcsuite/parsers';
4
4
  import { ClassRegistry, VcsEvent } from '@vcmap/core';
@@ -63,7 +63,7 @@ class ContentTreeItem {
63
63
  this._app = app;
64
64
 
65
65
  /**
66
- * @type {import("@vue/composition-api").Ref<Array<VcsAction>>}
66
+ * @type {import("vue").Ref<Array<VcsAction>>}
67
67
  * @private
68
68
  */
69
69
  this._actions = ref([]);
@@ -76,28 +76,28 @@ class ContentTreeItem {
76
76
 
77
77
  /**
78
78
  * Whether to display this item or not.
79
- * @type {import("@vue/composition-api").Ref<boolean>}
79
+ * @type {import("vue").Ref<boolean>}
80
80
  * @private
81
81
  */
82
82
  this._visible = ref(true);
83
83
 
84
84
  /**
85
85
  * Whether this item reacts to click events, e.g. with visual feedback
86
- * @type {import("@vue/composition-api").Ref<boolean>}
86
+ * @type {import("vue").Ref<boolean>}
87
87
  * @private
88
88
  */
89
89
  this._clickable = ref(true);
90
90
 
91
91
  /**
92
92
  * Whether this item should be displayed as disabled.
93
- * @type {import("@vue/composition-api").Ref<boolean>}
93
+ * @type {import("vue").Ref<boolean>}
94
94
  * @private
95
95
  */
96
96
  this._disabled = ref(false);
97
97
 
98
98
  /**
99
99
  * The state of this item. NONE if this item cannot have a state.
100
- * @type {import("@vue/composition-api").Ref<StateActionState>}
100
+ * @type {import("vue").Ref<StateActionState>}
101
101
  * @private
102
102
  */
103
103
  this._state = ref(StateActionState.NONE);
@@ -116,20 +116,20 @@ class ContentTreeItem {
116
116
  this.infoUrl = options.infoUrl;
117
117
 
118
118
  /**
119
- * @type {import("@vue/composition-api").Ref<Object<string, string>|string|undefined>}
119
+ * @type {import("vue").Ref<Object<string, string>|string|undefined>}
120
120
  * @private
121
121
  */
122
122
  this._title = ref(options.title);
123
123
 
124
124
  /**
125
125
  * An optional icon to display with this item. Can be an URL or HTMLElement.
126
- * @type {import("@vue/composition-api").Ref<string|HTMLCanvasElement|HTMLImageElement|undefined>}
126
+ * @type {import("vue").Ref<string|HTMLCanvasElement|HTMLImageElement|undefined>}
127
127
  * @private
128
128
  */
129
129
  this._icon = ref(options.icon);
130
130
 
131
131
  /**
132
- * @type {import("@vue/composition-api").Ref<Array<TreeViewItem>>}
132
+ * @type {import("vue").Ref<Array<TreeViewItem>>}
133
133
  * @protected
134
134
  */
135
135
  this._children = ref([]);
@@ -1,4 +1,4 @@
1
- import { watch } from '@vue/composition-api';
1
+ import { watch } from 'vue';
2
2
  import ContentTreeItem, { contentTreeClassRegistry } from './contentTreeItem.js';
3
3
  import { StateActionState } from '../actions/stateRefAction.js';
4
4
 
@@ -1,5 +1,5 @@
1
1
  import { ViewPoint } from '@vcmap/core';
2
- import { reactive } from '@vue/composition-api';
2
+ import { reactive } from 'vue';
3
3
  import { StateActionState } from '../actions/stateRefAction.js';
4
4
  import { createGoToViewpointAction, createModalAction } from '../actions/actionHelper.js';
5
5
  import component from '../actions/styleSelector.vue';
@@ -10,6 +10,7 @@ import { contentTreeClassRegistry } from './contentTreeItem.js';
10
10
  /**
11
11
  * @typedef {ContentTreeItemOptions} LayerContentTreeItemOptions
12
12
  * @property {string} layerName
13
+ * @property {Array<string>} layerNamesToDeactivate list of LayerNames which should be deactivated if the click activates the layer
13
14
  */
14
15
 
15
16
  /**
@@ -80,6 +81,14 @@ class LayerContentTreeItem extends VcsObjectContentTreeItem {
80
81
  */
81
82
  this._layerName = options.layerName;
82
83
 
84
+ /**
85
+ * @type {Array<string>}
86
+ * @private
87
+ */
88
+ this._layerNamesToDeactivate = Array.isArray(options.layerNamesToDeactivate) ?
89
+ options.layerNamesToDeactivate.slice() :
90
+ [];
91
+
83
92
  /**
84
93
  * @type {Array<Function>}
85
94
  * @private
@@ -210,6 +219,10 @@ class LayerContentTreeItem extends VcsObjectContentTreeItem {
210
219
  if (this._layer) {
211
220
  if (this.state === StateActionState.INACTIVE) {
212
221
  await this._layer.activate();
222
+ this._layerNamesToDeactivate
223
+ .map(n => this._app.layers.getByKey(n))
224
+ .filter(l => l)
225
+ .forEach(l => l.deactivate());
213
226
  } else {
214
227
  this._layer.deactivate();
215
228
  }
@@ -222,6 +235,7 @@ class LayerContentTreeItem extends VcsObjectContentTreeItem {
222
235
  toJSON() {
223
236
  const config = super.toJSON();
224
237
  config.layerName = this._layerName;
238
+ config.layerNamesToDeactivate = this._layerNamesToDeactivate.slice();
225
239
  return config;
226
240
  }
227
241