@vcmap/ui 6.3.11 → 6.3.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.
- package/build/build.js +5 -0
- package/build/staging/Dockerfile +2 -0
- package/config/base.config.json +207 -404
- package/config/clipping.config.json +16 -80
- package/config/cluster.config.json +2 -2
- package/config/components-show-case.config.json +1 -1
- package/config/concepts-show-case.config.json +1 -1
- package/config/dev/geojson.config.json +491 -0
- package/config/{i3s.config.json → dev/i3s.config.json} +78 -150
- package/config/{mapbox.config.json → dev/mapbox.config.json} +24 -58
- package/config/dev/vector-tile.config.json +196 -0
- package/config/{wms-layers.config.json → dev/wms.config.json} +22 -39
- package/config/dev.config.json +91 -887
- package/config/geofence.config.json +2 -4
- package/config/graph-feature-info.config.json +84 -0
- package/config/guided-tour.config.json +2 -2
- package/config/hello-world.config.json +1 -1
- package/config/projects.config.json +19 -20
- package/config/splashscreen.config.json +1 -1
- package/config/theming.config.json +1 -1
- package/config/www/city-planning.config.json +215 -0
- package/config/www/climate-environment.config.json +1244 -0
- package/config/www/iot-sensors.config.json +440 -0
- package/config/www/soest.config.json +632 -0
- package/config/www.config.json +1352 -1722
- package/dist/.htaccess +5 -0
- package/dist/assets/{cesium-09c8c37e.js → cesium-d2fefdc2.js} +25018 -24401
- package/dist/assets/cesium.js +1 -1
- package/dist/assets/{core-f093e6ba.js → core-be181847.js} +1138 -1138
- package/dist/assets/core-workers/panoramaImageWorker.js +1 -1
- package/dist/assets/core.js +1 -1
- package/dist/assets/ol.js +1 -1
- package/dist/assets/ui-8f8426e4.css +1 -0
- package/dist/assets/{ui-da598216.js → ui-8f8426e4.js} +13290 -12542
- package/dist/assets/ui.js +1 -1
- package/dist/assets/vue.js +1 -1
- package/dist/assets/{vuetify-1429f242.js → vuetify-8df23ea4.js} +1 -1
- package/dist/assets/vuetify.js +1 -1
- package/package.json +2 -2
- package/plugins/@vcmap-show-case/extent-example/src/ExtentExample.vue +16 -2
- package/plugins/@vcmap-show-case/icons-example/src/AllIconsComponent.vue +7 -5
- package/plugins/@vcmap-show-case/notifier-tester/src/NotifierTester.vue +5 -6
- package/plugins/@vcmap-show-case/project-selector/README.md +18 -7
- package/plugins/@vcmap-show-case/project-selector/src/ProjectSelectorComponent.vue +9 -0
- package/plugins/@vcmap-show-case/project-selector/src/index.js +87 -27
- package/plugins/@vcmap-show-case/simple-graph/src/SimpleGraphComponent.vue +10 -3
- package/plugins/@vcmap-show-case/simple-graph/src/index.js +10 -1
- package/plugins/@vcmap-show-case/switch-map-callback-example/README.md +1 -1
- package/plugins/package.json +4 -3
- package/src/application/VcsApp.vue +3 -7
- package/src/application/attributionsHelper.d.ts +27 -5
- package/src/application/attributionsHelper.js +116 -58
- package/src/components/lists/VcsGroupedList.vue +29 -1
- package/src/components/lists/VcsList.vue +35 -4
- package/src/components/lists/VcsList.vue.d.ts +2 -0
- package/src/components/lists/VcsTreeview.vue +63 -31
- package/src/components/lists/VcsTreeview.vue.d.ts +9 -0
- package/src/components/plugins/VcsWorkspaceWrapper.vue +6 -0
- package/src/components/plugins/VcsWorkspaceWrapper.vue.d.ts +9 -0
- package/src/contentTree/LayerTree.vue +13 -2
- package/src/featureInfo/ClusterFeatureComponent.vue +1 -0
- package/src/featureInfo/abstractFeatureInfoView.js +13 -9
- package/src/manager/window/WindowComponent.vue +5 -1
- package/src/vcsUiApp.d.ts +19 -7
- package/src/vcsUiApp.js +17 -0
- package/config/aerowest.config.json +0 -386
- package/config/analysis.config.json +0 -17
- package/config/dynamic-layer.config.json +0 -33
- package/config/graphFeatureInfo.config.json +0 -141
- package/config/pano.config.json +0 -726
- package/config/solar.config.json +0 -66
- package/config/vectorTile.config.json +0 -112
- package/dist/assets/ui-da598216.css +0 -1
- /package/dist/assets/core-workers/{panoramaImageWorker.js-e1e34b3c.js → panoramaImageWorker.js-eecf04e1.js} +0 -0
- /package/dist/assets/{ol-5a959f4c.js → ol-3438e1c5.js} +0 -0
- /package/dist/assets/{vue-20dd2b78.js → vue-dd509a16.js} +0 -0
- /package/dist/assets/{vuetify-1429f242.css → vuetify-8df23ea4.css} +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { reactive } from 'vue';
|
|
1
|
+
import { reactive, watch } from 'vue';
|
|
2
2
|
import { ObliqueMap } from '@vcmap/core';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -16,6 +16,14 @@ import { ObliqueMap } from '@vcmap/core';
|
|
|
16
16
|
* @property {AttributionOptions|Array<AttributionOptions>} attributions - attributions of a map, layer or oblique collection
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
+
/**
|
|
20
|
+
* @typedef {Object} Attributions
|
|
21
|
+
* @property {import("vue").UnwrapRef<Array<AttributionEntry>>} entries - reactive array of attribution entries
|
|
22
|
+
* @property {function(import("@vcmap/core").VcsMap, string|import('../pluginHelper.js').vcsAppSymbol): function():void} registerMap - function to register a map and its layer collection for an owner, returns a function to unregister it
|
|
23
|
+
* @property {function(string|import('../pluginHelper.js').vcsAppSymbol):void} removeOwner - unregister all maps registered by an owner
|
|
24
|
+
* @property {function():void} destroy - function to clear all listeners and clean up attributions
|
|
25
|
+
*/
|
|
26
|
+
|
|
19
27
|
/**
|
|
20
28
|
* merges attribution entries of same providers
|
|
21
29
|
* @param {Array<AttributionEntry>} entries
|
|
@@ -64,17 +72,17 @@ export function mergeAttributions(entries) {
|
|
|
64
72
|
* Listens to state changes of maps, layers and oblique collections and synchronizes the entries array correspondingly.
|
|
65
73
|
* Returns a destroy function to clear listeners.
|
|
66
74
|
* @param {import("../vcsUiApp.js").default} app
|
|
67
|
-
* @returns {
|
|
75
|
+
* @returns {Attributions}
|
|
68
76
|
*/
|
|
69
77
|
export function getAttributions(app) {
|
|
70
78
|
/**
|
|
71
79
|
* @type {import("vue").UnwrapRef<Array<AttributionEntry>>}
|
|
72
80
|
*/
|
|
73
81
|
const entries = reactive([]);
|
|
74
|
-
/**
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
82
|
+
/** @type {Map<import("@vcmap/core").VcsMap, { collection: import("@vcmap/core").LayerCollection, registrations: Map<function():void, string|import('../pluginHelper.js').vcsAppSymbol>, removeListeners: Array<function():void> }>} */
|
|
83
|
+
const registeredMaps = new Map();
|
|
84
|
+
/** @type {Map<import("@vcmap/core").ObliqueMap, function():void>} */
|
|
85
|
+
const obliqueListeners = new Map();
|
|
78
86
|
|
|
79
87
|
/**
|
|
80
88
|
* Adds an entry for an object using a combination of the object's className and name as key.
|
|
@@ -99,73 +107,123 @@ export function getAttributions(app) {
|
|
|
99
107
|
}
|
|
100
108
|
}
|
|
101
109
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
(
|
|
108
|
-
);
|
|
109
|
-
if (idx >= 0) {
|
|
110
|
-
entries.splice(idx, 1);
|
|
110
|
+
function updateAttributions() {
|
|
111
|
+
entries.splice(0);
|
|
112
|
+
/** @type {Map<import("@vcmap/core").VcsMap, import("@vcmap/core").LayerCollection>} */
|
|
113
|
+
const visibleMaps = new Map();
|
|
114
|
+
if (app.maps.activeMap) {
|
|
115
|
+
visibleMaps.set(app.maps.activeMap, app.maps.activeMap.layerCollection);
|
|
111
116
|
}
|
|
117
|
+
if (app.overviewMap.active) {
|
|
118
|
+
const overviewMap = app.overviewMap.map;
|
|
119
|
+
visibleMaps.set(overviewMap, overviewMap.layerCollection);
|
|
120
|
+
}
|
|
121
|
+
registeredMaps.forEach(({ collection }, map) => {
|
|
122
|
+
if (map.active) {
|
|
123
|
+
visibleMaps.set(map, collection);
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
obliqueListeners.forEach((removeListener, map) => {
|
|
127
|
+
if (!visibleMaps.has(map)) {
|
|
128
|
+
removeListener();
|
|
129
|
+
obliqueListeners.delete(map);
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
visibleMaps.forEach((collection, map) => {
|
|
133
|
+
if (map.active) {
|
|
134
|
+
addAttributions(map);
|
|
135
|
+
}
|
|
136
|
+
[...collection].forEach((layer) => {
|
|
137
|
+
if (layer.active && layer.isSupported(map)) {
|
|
138
|
+
addAttributions(layer);
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
if (map instanceof ObliqueMap) {
|
|
142
|
+
if (map.collection) {
|
|
143
|
+
addAttributions(map.collection);
|
|
144
|
+
}
|
|
145
|
+
if (!obliqueListeners.has(map)) {
|
|
146
|
+
obliqueListeners.set(
|
|
147
|
+
map,
|
|
148
|
+
map.collectionChanged.addEventListener(updateAttributions),
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
});
|
|
112
153
|
}
|
|
113
154
|
|
|
155
|
+
const listeners = [
|
|
156
|
+
app.maps.mapActivated.addEventListener(updateAttributions),
|
|
157
|
+
app.layers.stateChanged.addEventListener(updateAttributions),
|
|
158
|
+
app.layers.added.addEventListener(updateAttributions),
|
|
159
|
+
app.layers.removed.addEventListener(updateAttributions),
|
|
160
|
+
app.maps.removed.addEventListener(updateAttributions),
|
|
161
|
+
watch(app.overviewMap.currentState, updateAttributions),
|
|
162
|
+
];
|
|
163
|
+
|
|
164
|
+
updateAttributions();
|
|
165
|
+
|
|
114
166
|
/**
|
|
115
|
-
*
|
|
116
|
-
* @param {import(
|
|
167
|
+
* @param {import("@vcmap/core").VcsMap} map
|
|
168
|
+
* @param {string|import('../pluginHelper.js').vcsAppSymbol} owner
|
|
169
|
+
* @returns {function():void}
|
|
117
170
|
*/
|
|
118
|
-
function
|
|
119
|
-
if (
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
171
|
+
function registerMap(map, owner) {
|
|
172
|
+
if (!registeredMaps.has(map)) {
|
|
173
|
+
registeredMaps.set(map, {
|
|
174
|
+
collection: map.layerCollection,
|
|
175
|
+
registrations: new Map(),
|
|
176
|
+
removeListeners: [
|
|
177
|
+
map.stateChanged.addEventListener(updateAttributions),
|
|
178
|
+
map.layerCollection.added.addEventListener(updateAttributions),
|
|
179
|
+
map.layerCollection.removed.addEventListener(updateAttributions),
|
|
180
|
+
],
|
|
181
|
+
});
|
|
126
182
|
}
|
|
183
|
+
const unregister = () => {
|
|
184
|
+
const current = registeredMaps.get(map);
|
|
185
|
+
if (!current?.registrations.delete(unregister)) {
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
if (current.registrations.size === 0) {
|
|
189
|
+
current.removeListeners.forEach((removeListener) => {
|
|
190
|
+
removeListener();
|
|
191
|
+
});
|
|
192
|
+
registeredMaps.delete(map);
|
|
193
|
+
}
|
|
194
|
+
updateAttributions();
|
|
195
|
+
};
|
|
196
|
+
registeredMaps.get(map).registrations.set(unregister, owner);
|
|
197
|
+
updateAttributions();
|
|
198
|
+
return unregister;
|
|
127
199
|
}
|
|
128
200
|
|
|
129
201
|
/**
|
|
130
|
-
*
|
|
131
|
-
* @param {import("@vcmap/core").VcsMap} map
|
|
202
|
+
* @param {string|import('../pluginHelper.js').vcsAppSymbol} owner
|
|
132
203
|
*/
|
|
133
|
-
function
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
[...map.layerCollection].forEach((layer) => {
|
|
141
|
-
if (layer.isSupported(map)) {
|
|
142
|
-
syncAttributions(layer);
|
|
143
|
-
}
|
|
204
|
+
function removeOwner(owner) {
|
|
205
|
+
registeredMaps.forEach(({ registrations }) => {
|
|
206
|
+
registrations.forEach((registrationOwner, unregister) => {
|
|
207
|
+
if (registrationOwner === owner) {
|
|
208
|
+
unregister();
|
|
209
|
+
}
|
|
210
|
+
});
|
|
144
211
|
});
|
|
145
|
-
if (map instanceof ObliqueMap) {
|
|
146
|
-
addAttributions(map.collection);
|
|
147
|
-
obliqueListener = map.collectionChanged.addEventListener(
|
|
148
|
-
(obliqueCollection) => {
|
|
149
|
-
[...app.obliqueCollections].forEach(removeAttributions);
|
|
150
|
-
addAttributions(obliqueCollection);
|
|
151
|
-
},
|
|
152
|
-
);
|
|
153
|
-
}
|
|
154
212
|
}
|
|
155
213
|
|
|
156
|
-
const listeners = [
|
|
157
|
-
app.maps.mapActivated.addEventListener(initAttributions),
|
|
158
|
-
app.layers.stateChanged.addEventListener(syncAttributions),
|
|
159
|
-
app.layers.removed.addEventListener(removeAttributions),
|
|
160
|
-
app.maps.removed.addEventListener(removeAttributions),
|
|
161
|
-
];
|
|
162
|
-
|
|
163
|
-
initAttributions(app.maps.activeMap);
|
|
164
|
-
|
|
165
214
|
const destroy = () => {
|
|
166
215
|
listeners.forEach((cb) => cb());
|
|
167
|
-
|
|
216
|
+
obliqueListeners.forEach((removeListener) => {
|
|
217
|
+
removeListener();
|
|
218
|
+
});
|
|
219
|
+
obliqueListeners.clear();
|
|
220
|
+
registeredMaps.forEach(({ removeListeners }) => {
|
|
221
|
+
removeListeners.forEach((removeListener) => {
|
|
222
|
+
removeListener();
|
|
223
|
+
});
|
|
224
|
+
});
|
|
225
|
+
registeredMaps.clear();
|
|
168
226
|
};
|
|
169
227
|
|
|
170
|
-
return { entries, destroy };
|
|
228
|
+
return { entries, registerMap, removeOwner, destroy };
|
|
171
229
|
}
|
|
@@ -35,6 +35,7 @@
|
|
|
35
35
|
* @vue-prop {boolean} [singleSelect=false]
|
|
36
36
|
* @vue-prop {Array<import("./VcsListItemComponent.vue").VcsListItem>} [modelValue=[]] - the initial items to be selected.
|
|
37
37
|
* @vue-prop {boolean} [searchable=false] - if this list can have its items searched.
|
|
38
|
+
* @vue-prop {boolean} [stickySearchbar=false] - Keeps the searchbar at the top of the scroll container.
|
|
38
39
|
* @vue-prop {function(import("./VcsListItemComponent.vue").VcsListItem, string):boolean} [customFilter] - a function to customize filtering when searching.
|
|
39
40
|
* @vue-prop {string} [searchbarPlaceholder] - placeholder to render inside the search field
|
|
40
41
|
*/
|
|
@@ -73,6 +74,10 @@
|
|
|
73
74
|
type: Boolean,
|
|
74
75
|
default: false,
|
|
75
76
|
},
|
|
77
|
+
stickySearchbar: {
|
|
78
|
+
type: Boolean,
|
|
79
|
+
default: false,
|
|
80
|
+
},
|
|
76
81
|
searchbarPlaceholder: {
|
|
77
82
|
type: String,
|
|
78
83
|
default: undefined,
|
|
@@ -142,7 +147,10 @@
|
|
|
142
147
|
</script>
|
|
143
148
|
|
|
144
149
|
<template>
|
|
145
|
-
<div
|
|
150
|
+
<div
|
|
151
|
+
class="vcs-grouped-list"
|
|
152
|
+
:class="{ 'sticky-searchbar': stickySearchbar && searchable }"
|
|
153
|
+
>
|
|
146
154
|
<VcsTreeviewSearchbar
|
|
147
155
|
v-if="searchable"
|
|
148
156
|
:placeholder="searchbarPlaceholder"
|
|
@@ -178,6 +186,26 @@
|
|
|
178
186
|
</template>
|
|
179
187
|
|
|
180
188
|
<style scoped lang="scss">
|
|
189
|
+
.vcs-grouped-list {
|
|
190
|
+
display: block;
|
|
191
|
+
flex: 1 1 auto;
|
|
192
|
+
min-height: 0;
|
|
193
|
+
overflow: auto;
|
|
194
|
+
scrollbar-gutter: stable;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
.vcs-grouped-list.sticky-searchbar {
|
|
198
|
+
--searchbar-height: calc(var(--v-vcs-font-size) * 2 + 18px);
|
|
199
|
+
margin-top: var(--searchbar-height);
|
|
200
|
+
|
|
201
|
+
> .vcs-treeview-searchbar {
|
|
202
|
+
width: 100%;
|
|
203
|
+
position: absolute !important;
|
|
204
|
+
margin-top: calc(var(--searchbar-height) * -1);
|
|
205
|
+
z-index: 2;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
181
209
|
.panels .vcs-expansion-panel:not(:last-child) {
|
|
182
210
|
border-bottom: 1px solid rgb(var(--v-theme-base-lighten-2));
|
|
183
211
|
}
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div
|
|
2
|
+
<div
|
|
3
|
+
class="vcs-list"
|
|
4
|
+
:class="{
|
|
5
|
+
'sticky-searchbar': stickySearchbar && searchable,
|
|
6
|
+
}"
|
|
7
|
+
>
|
|
3
8
|
<vcs-treeview-searchbar
|
|
4
9
|
v-if="searchable"
|
|
5
10
|
:placeholder="searchbarPlaceholder"
|
|
@@ -113,6 +118,7 @@
|
|
|
113
118
|
* @vue-prop {boolean} [singleSelect=false]
|
|
114
119
|
* @vue-prop {Array<import("./VcsListItemComponent.vue").VcsListItem>} [modelValue=[]] - the initial items to be selected.
|
|
115
120
|
* @vue-prop {boolean} [searchable=false] - if this list can have its items searched.
|
|
121
|
+
* @vue-prop {boolean} [stickySearchbar=false] - Keeps the searchbar at the top of the scroll container.
|
|
116
122
|
* @vue-prop {function(import("./VcsListItemComponent.vue").VcsListItem, string):boolean} [customFilter] - a function to customize filtering when searching.
|
|
117
123
|
* @vue-prop {string} [searchbarPlaceholder] - placeholder to render inside the search field
|
|
118
124
|
* @vue-prop {boolean} [showTitle=true] - show the title component
|
|
@@ -162,6 +168,10 @@
|
|
|
162
168
|
type: Boolean,
|
|
163
169
|
default: false,
|
|
164
170
|
},
|
|
171
|
+
stickySearchbar: {
|
|
172
|
+
type: Boolean,
|
|
173
|
+
default: false,
|
|
174
|
+
},
|
|
165
175
|
customFilter: {
|
|
166
176
|
type: Function,
|
|
167
177
|
default: undefined,
|
|
@@ -282,6 +292,30 @@
|
|
|
282
292
|
</script>
|
|
283
293
|
|
|
284
294
|
<style lang="scss" scoped>
|
|
295
|
+
.vcs-list {
|
|
296
|
+
display: block;
|
|
297
|
+
flex: 1 1 auto;
|
|
298
|
+
min-height: 0;
|
|
299
|
+
overflow: auto;
|
|
300
|
+
scrollbar-gutter: stable;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
.vcs-list > .v-list {
|
|
304
|
+
overflow: visible;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
.vcs-list.sticky-searchbar {
|
|
308
|
+
--searchbar-height: calc(var(--v-vcs-font-size) * 2 + 18px);
|
|
309
|
+
margin-top: var(--searchbar-height);
|
|
310
|
+
|
|
311
|
+
> .vcs-treeview-searchbar {
|
|
312
|
+
width: 100%;
|
|
313
|
+
position: absolute !important;
|
|
314
|
+
margin-top: calc(var(--searchbar-height) * -1);
|
|
315
|
+
z-index: 2;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
285
319
|
:deep(.v-list) {
|
|
286
320
|
.v-list-item__lighten_even:nth-child(even) {
|
|
287
321
|
background-color: rgb(var(--v-theme-base-lighten-4));
|
|
@@ -339,7 +373,4 @@
|
|
|
339
373
|
}
|
|
340
374
|
}
|
|
341
375
|
}
|
|
342
|
-
.d-contents {
|
|
343
|
-
display: contents;
|
|
344
|
-
}
|
|
345
376
|
</style>
|
|
@@ -7,6 +7,7 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<{}
|
|
|
7
7
|
items: unknown[];
|
|
8
8
|
selectable: boolean;
|
|
9
9
|
actions: unknown[];
|
|
10
|
+
stickySearchbar: boolean;
|
|
10
11
|
singleSelect: boolean;
|
|
11
12
|
searchable: boolean;
|
|
12
13
|
showTitle: boolean;
|
|
@@ -24,6 +25,7 @@ declare const _default: __VLS_WithTemplateSlots<import("vue").DefineComponent<{}
|
|
|
24
25
|
readonly items?: unknown[] | undefined;
|
|
25
26
|
readonly selectable?: boolean | undefined;
|
|
26
27
|
readonly actions?: unknown[] | undefined;
|
|
28
|
+
readonly stickySearchbar?: boolean | undefined;
|
|
27
29
|
readonly singleSelect?: boolean | undefined;
|
|
28
30
|
readonly searchable?: boolean | undefined;
|
|
29
31
|
readonly showTitle?: boolean | undefined;
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div
|
|
2
|
+
<div
|
|
3
|
+
class="vcs-treeview"
|
|
4
|
+
:class="{ 'sticky-searchbar': stickySearchbar && showSearchbar }"
|
|
5
|
+
>
|
|
3
6
|
<VcsTreeviewSearchbar
|
|
4
7
|
v-if="showSearchbar"
|
|
5
8
|
:placeholder="searchbarPlaceholder"
|
|
@@ -12,37 +15,39 @@
|
|
|
12
15
|
<slot name="search-append" v-bind="searchAppend" />
|
|
13
16
|
</template>
|
|
14
17
|
</VcsTreeviewSearchbar>
|
|
15
|
-
<div
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
<VcsTreeNode
|
|
22
|
-
class="root-node"
|
|
23
|
-
:class="{
|
|
24
|
-
'vcs-draggable-item': isDraggable,
|
|
25
|
-
}"
|
|
26
|
-
:item="item"
|
|
27
|
-
:path="[index]"
|
|
28
|
-
:search="localSearchValue"
|
|
29
|
-
v-model:opened="localOpenedItems"
|
|
30
|
-
:custom-filter="customFilter"
|
|
31
|
-
:open-on-click="openOnClick"
|
|
32
|
-
:item-children="itemChildren"
|
|
33
|
-
:draggable="isDraggable"
|
|
34
|
-
@mousedown.shift="$event.preventDefault()"
|
|
35
|
-
@dragstart="dragStart"
|
|
36
|
-
@dragover="dragOver"
|
|
37
|
-
@dragend="dragEnd"
|
|
38
|
-
@drop="drop"
|
|
39
|
-
@item-toggled="itemToggled"
|
|
40
|
-
@click="itemClicked"
|
|
18
|
+
<div class="treeview-items">
|
|
19
|
+
<div
|
|
20
|
+
v-for="(item, index) in items"
|
|
21
|
+
:key="item.name"
|
|
22
|
+
class="vcs-treeitem"
|
|
23
|
+
:class="{ 'mobile-spacing': xs }"
|
|
41
24
|
>
|
|
42
|
-
<
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
25
|
+
<VcsTreeNode
|
|
26
|
+
class="root-node"
|
|
27
|
+
:class="{
|
|
28
|
+
'vcs-draggable-item': isDraggable,
|
|
29
|
+
}"
|
|
30
|
+
:item="item"
|
|
31
|
+
:path="[index]"
|
|
32
|
+
:search="localSearchValue"
|
|
33
|
+
v-model:opened="localOpenedItems"
|
|
34
|
+
:custom-filter="customFilter"
|
|
35
|
+
:open-on-click="openOnClick"
|
|
36
|
+
:item-children="itemChildren"
|
|
37
|
+
:draggable="isDraggable"
|
|
38
|
+
@mousedown.shift="$event.preventDefault()"
|
|
39
|
+
@dragstart="dragStart"
|
|
40
|
+
@dragover="dragOver"
|
|
41
|
+
@dragend="dragEnd"
|
|
42
|
+
@drop="drop"
|
|
43
|
+
@item-toggled="itemToggled"
|
|
44
|
+
@click="itemClicked"
|
|
45
|
+
>
|
|
46
|
+
<template v-for="slot of forwardSlots" #[slot]="scope">
|
|
47
|
+
<slot :name="slot" v-bind="scope ?? {}" />
|
|
48
|
+
</template>
|
|
49
|
+
</VcsTreeNode>
|
|
50
|
+
</div>
|
|
46
51
|
</div>
|
|
47
52
|
</div>
|
|
48
53
|
</template>
|
|
@@ -73,6 +78,7 @@
|
|
|
73
78
|
* @vue-prop {boolean} [openOnClick=false] - Whether to open items on title click.
|
|
74
79
|
* @vue-prop {string} [search=''] - The value used to filter the items.
|
|
75
80
|
* @vue-prop {boolean} [showSearchbar=false] - Whether there is a searchbar for this treeview.
|
|
81
|
+
* @vue-prop {boolean} [stickySearchbar=false] - Keeps the searchbar at the top of the scroll container.
|
|
76
82
|
* @vue-prop {string} [searchbarPlaceholder] - Placeholder text for the searchbar, will be translated.
|
|
77
83
|
* @vue-prop {function(arg0: import("./VcsTreeNode.vue").VcsTreeNodeItem, arg1: string|undefined):boolean} [customFilter] - a function to customize filtering when searching.
|
|
78
84
|
* @vue-prop {import("./dragHelper.js").DropTargetZonesFunction} [dropTargetZones] - a function to define allowed drop target zones per item.
|
|
@@ -116,6 +122,10 @@
|
|
|
116
122
|
type: Boolean,
|
|
117
123
|
default: false,
|
|
118
124
|
},
|
|
125
|
+
stickySearchbar: {
|
|
126
|
+
type: Boolean,
|
|
127
|
+
default: false,
|
|
128
|
+
},
|
|
119
129
|
searchbarPlaceholder: {
|
|
120
130
|
type: String,
|
|
121
131
|
default: undefined,
|
|
@@ -203,6 +213,28 @@
|
|
|
203
213
|
</script>
|
|
204
214
|
|
|
205
215
|
<style lang="scss" scoped>
|
|
216
|
+
.vcs-treeview {
|
|
217
|
+
display: block;
|
|
218
|
+
flex: 1 1 auto;
|
|
219
|
+
min-height: 0;
|
|
220
|
+
overflow: auto;
|
|
221
|
+
scrollbar-gutter: stable;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
.treeview-items {
|
|
225
|
+
display: block;
|
|
226
|
+
}
|
|
227
|
+
.vcs-treeview.sticky-searchbar {
|
|
228
|
+
--searchbar-height: calc(var(--v-vcs-font-size) * 2 + 18px);
|
|
229
|
+
margin-top: var(--searchbar-height);
|
|
230
|
+
|
|
231
|
+
> .vcs-treeview-searchbar {
|
|
232
|
+
width: 100%;
|
|
233
|
+
position: absolute !important;
|
|
234
|
+
margin-top: calc(var(--searchbar-height) * -1);
|
|
235
|
+
z-index: 2;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
206
238
|
// Hide node component when not rendered (e.g. filtered by search)
|
|
207
239
|
.vcs-treeitem:not(:has(.vcs-tree-node)) {
|
|
208
240
|
display: none;
|
|
@@ -31,6 +31,10 @@ declare const _default: import("vue").DefineComponent<{
|
|
|
31
31
|
type: BooleanConstructor;
|
|
32
32
|
default: boolean;
|
|
33
33
|
};
|
|
34
|
+
stickySearchbar: {
|
|
35
|
+
type: BooleanConstructor;
|
|
36
|
+
default: boolean;
|
|
37
|
+
};
|
|
34
38
|
searchbarPlaceholder: {
|
|
35
39
|
type: StringConstructor;
|
|
36
40
|
default: undefined;
|
|
@@ -92,6 +96,10 @@ declare const _default: import("vue").DefineComponent<{
|
|
|
92
96
|
type: BooleanConstructor;
|
|
93
97
|
default: boolean;
|
|
94
98
|
};
|
|
99
|
+
stickySearchbar: {
|
|
100
|
+
type: BooleanConstructor;
|
|
101
|
+
default: boolean;
|
|
102
|
+
};
|
|
95
103
|
searchbarPlaceholder: {
|
|
96
104
|
type: StringConstructor;
|
|
97
105
|
default: undefined;
|
|
@@ -122,6 +130,7 @@ declare const _default: import("vue").DefineComponent<{
|
|
|
122
130
|
customFilter: Function;
|
|
123
131
|
openAll: boolean;
|
|
124
132
|
showSearchbar: boolean;
|
|
133
|
+
stickySearchbar: boolean;
|
|
125
134
|
searchbarPlaceholder: string;
|
|
126
135
|
dropTargetZones: Function;
|
|
127
136
|
}, {}>;
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
<div class="d-flex gc-2 w-100 justify-end">
|
|
15
15
|
<slot name="secondaryButton" />
|
|
16
16
|
<VcsFormButton
|
|
17
|
+
v-if="showNew"
|
|
17
18
|
variant="filled"
|
|
18
19
|
:disabled="disableNew"
|
|
19
20
|
:tooltip="tooltipNew"
|
|
@@ -39,6 +40,7 @@
|
|
|
39
40
|
* Providing a footer with add and new buttons.
|
|
40
41
|
* @vue-prop {boolean} [showFooter=true] - Flag to hide the footer.
|
|
41
42
|
* @vue-prop {boolean} [showAdd=true] - Flag to show an add button in the footer. You need to handle @addClicked in a child component.
|
|
43
|
+
* @vue-prop {boolean} [showNew=true] - Flag to show a new button in the footer.
|
|
42
44
|
* @vue-prop {boolean} [disableAdd=false] - Flag to render add button disabled.
|
|
43
45
|
* @vue-prop {boolean} [tooltipAdd='components.addToMyWorkspace'] - Option to change the add button tooltip.
|
|
44
46
|
* @vue-prop {boolean} [disableNew=false] - Flag to render new button disabled.
|
|
@@ -66,6 +68,10 @@
|
|
|
66
68
|
type: Boolean,
|
|
67
69
|
default: true,
|
|
68
70
|
},
|
|
71
|
+
showNew: {
|
|
72
|
+
type: Boolean,
|
|
73
|
+
default: true,
|
|
74
|
+
},
|
|
69
75
|
disableAdd: {
|
|
70
76
|
type: Boolean,
|
|
71
77
|
default: false,
|
|
@@ -7,6 +7,10 @@ declare const _default: import("vue").DefineComponent<{
|
|
|
7
7
|
type: BooleanConstructor;
|
|
8
8
|
default: boolean;
|
|
9
9
|
};
|
|
10
|
+
showNew: {
|
|
11
|
+
type: BooleanConstructor;
|
|
12
|
+
default: boolean;
|
|
13
|
+
};
|
|
10
14
|
disableAdd: {
|
|
11
15
|
type: BooleanConstructor;
|
|
12
16
|
default: boolean;
|
|
@@ -42,6 +46,10 @@ declare const _default: import("vue").DefineComponent<{
|
|
|
42
46
|
type: BooleanConstructor;
|
|
43
47
|
default: boolean;
|
|
44
48
|
};
|
|
49
|
+
showNew: {
|
|
50
|
+
type: BooleanConstructor;
|
|
51
|
+
default: boolean;
|
|
52
|
+
};
|
|
45
53
|
disableAdd: {
|
|
46
54
|
type: BooleanConstructor;
|
|
47
55
|
default: boolean;
|
|
@@ -73,6 +81,7 @@ declare const _default: import("vue").DefineComponent<{
|
|
|
73
81
|
actions: unknown[];
|
|
74
82
|
showFooter: boolean;
|
|
75
83
|
showAdd: boolean;
|
|
84
|
+
showNew: boolean;
|
|
76
85
|
disableAdd: boolean;
|
|
77
86
|
tooltipAdd: string;
|
|
78
87
|
newButtonTitle: string;
|
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
<VcsTreeview
|
|
4
4
|
v-if="tree && tree.length"
|
|
5
5
|
:items="tree"
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
show-searchbar
|
|
7
|
+
sticky-searchbar
|
|
8
8
|
open-on-click
|
|
9
|
+
v-model:opened="open"
|
|
9
10
|
:searchbar-placeholder="'content.search.placeholder'"
|
|
10
11
|
item-children="visibleChildren"
|
|
11
12
|
>
|
|
@@ -103,3 +104,13 @@
|
|
|
103
104
|
},
|
|
104
105
|
};
|
|
105
106
|
</script>
|
|
107
|
+
|
|
108
|
+
<style lang="scss" scoped>
|
|
109
|
+
.layer-tree {
|
|
110
|
+
display: flex;
|
|
111
|
+
flex-direction: column;
|
|
112
|
+
flex: 1 1 auto;
|
|
113
|
+
min-height: 0;
|
|
114
|
+
overflow: hidden;
|
|
115
|
+
}
|
|
116
|
+
</style>
|
|
@@ -287,19 +287,20 @@ function getWindowState(app, state, attributes) {
|
|
|
287
287
|
}
|
|
288
288
|
|
|
289
289
|
/**
|
|
290
|
-
* Recursively searches for parent feature attributes, if __PARENT_FEATURE property is set. Parent feature is searched in the
|
|
290
|
+
* Recursively searches for parent feature attributes, if __PARENT_FEATURE property is set. Parent feature is searched in the content of the given feature.
|
|
291
291
|
* @param {import("ol").Feature|import("@vcmap-cesium/engine").Cesium3DTileFeature|import("@vcmap-cesium/engine").Cesium3DTilePointFeature} feature
|
|
292
292
|
* @param {Array<object>} records - array of parent feature attributes
|
|
293
293
|
* @returns {Array<object>} record of parent feature ids and their attributes
|
|
294
294
|
*/
|
|
295
295
|
function getParentFeatureAttributes(feature, records = []) {
|
|
296
296
|
const parentId = feature.getProperty('__PARENT_FEATURE');
|
|
297
|
-
if (parentId !== 'null' && feature.content
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
297
|
+
if (parentId !== undefined && parentId !== 'null' && feature.content) {
|
|
298
|
+
const { content } = feature;
|
|
299
|
+
for (let i = 0; i < content.featuresLength; i++) {
|
|
300
|
+
const contentFeature = content.getFeature(i);
|
|
301
|
+
if (contentFeature.getProperty('id') === parentId) {
|
|
302
|
+
records.push(contentFeature.getAttributes());
|
|
303
|
+
return getParentFeatureAttributes(contentFeature, records);
|
|
303
304
|
}
|
|
304
305
|
}
|
|
305
306
|
}
|
|
@@ -442,6 +443,10 @@ class AbstractFeatureInfoView extends VcsObject {
|
|
|
442
443
|
*/
|
|
443
444
|
getAttributes(feature) {
|
|
444
445
|
let attributes = this._getAttributesFromFeature(feature);
|
|
446
|
+
attributes = applyEmptyAttributesFilter(
|
|
447
|
+
attributes,
|
|
448
|
+
this.removeNoDataAttributes,
|
|
449
|
+
);
|
|
445
450
|
if (this.attributeKeys.length > 0) {
|
|
446
451
|
attributes = applyAttributeFilter(attributes, this.attributeKeys);
|
|
447
452
|
}
|
|
@@ -452,8 +457,7 @@ class AbstractFeatureInfoView extends VcsObject {
|
|
|
452
457
|
applyKeyMapping(attributes, this.keyMapping);
|
|
453
458
|
}
|
|
454
459
|
attributes = applyOlcsAttributeFilter(attributes, this.attributeKeys);
|
|
455
|
-
|
|
456
|
-
return applyEmptyAttributesFilter(attributes, this.removeNoDataAttributes);
|
|
460
|
+
return applyDoubleUnderscoreFilter(attributes, this.attributeKeys);
|
|
457
461
|
}
|
|
458
462
|
|
|
459
463
|
/**
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
</div>
|
|
29
29
|
<v-divider v-if="!windowState.hideHeader" />
|
|
30
30
|
<div
|
|
31
|
-
class="overflow-x-hidden overflow-y-auto mb-1 d-flex flex-grow-1 flex-column"
|
|
31
|
+
class="window-content overflow-x-hidden overflow-y-auto mb-1 d-flex flex-grow-1 flex-column"
|
|
32
32
|
:class="{
|
|
33
33
|
rounded: !isDocked,
|
|
34
34
|
}"
|
|
@@ -169,6 +169,10 @@
|
|
|
169
169
|
</script>
|
|
170
170
|
|
|
171
171
|
<style scoped>
|
|
172
|
+
.window-content > :deep(:has(> .sticky-searchbar:only-child)) {
|
|
173
|
+
display: contents;
|
|
174
|
+
}
|
|
175
|
+
|
|
172
176
|
.marginToTop {
|
|
173
177
|
margin-top: 2px;
|
|
174
178
|
}
|