@vcmap/ui 6.3.0-rc.1 → 6.3.0-rc.2
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/config/base.config.json +6 -3
- package/config/cluster.config.json +2 -1
- package/config/dev.config.json +377 -1
- package/dist/assets/cesium.js +1 -1
- package/dist/assets/{core-b7d98022.js → core-c23fc5f1.js} +10565 -8835
- 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-e61976d4.css +1 -0
- package/dist/assets/{ui-94adeedc.js → ui-e61976d4.js} +6650 -6544
- package/dist/assets/ui.js +1 -1
- package/dist/assets/vue.js +1 -1
- package/dist/assets/{vuetify-2f71239e.js → vuetify-de6f6eb0.js} +1 -1
- package/dist/assets/vuetify.js +1 -1
- package/index.d.ts +3 -1
- package/index.js +1 -1
- package/package.json +1 -1
- package/plugins/@vcmap-show-case/panel-tester/src/TextPanelExample.vue +1 -1
- package/plugins/package.json +4 -3
- package/src/actions/actionHelper.d.ts +0 -1
- package/src/actions/actionHelper.js +3 -3
- package/src/application/VcsApp.vue +12 -1
- package/src/application/VcsApp.vue.d.ts +32 -0
- package/src/application/VcsAttributions.vue +9 -0
- package/src/application/VcsAttributionsFooter.vue.d.ts +1 -0
- package/src/application/VcsContainer.vue.d.ts +31 -0
- package/src/application/VcsMobileMenuList.vue +16 -1
- package/src/application/VcsObliqueFooter.vue +19 -6
- package/src/application/VcsObliqueFooter.vue.d.ts +1 -0
- package/src/application/VcsPanoramaFooter.vue +26 -6
- package/src/application/VcsTextPageFooter.vue +4 -0
- package/src/application/attributionsHelper.d.ts +7 -1
- package/src/application/attributionsHelper.js +7 -2
- package/src/application/uiConfigHelper.d.ts +6 -0
- package/src/application/uiConfigHelper.js +28 -0
- package/src/contentTree/wmsGroupContentTreeItem.d.ts +52 -6
- package/src/contentTree/wmsGroupContentTreeItem.js +127 -28
- package/src/featureInfo/balloonHelper.js +8 -2
- package/src/i18n/de.d.ts +1 -0
- package/src/i18n/de.js +1 -0
- package/src/i18n/en.d.ts +1 -0
- package/src/i18n/en.js +1 -0
- package/src/manager/panel/PanelComponent.vue +48 -27
- package/src/manager/panel/PanelComponent.vue.d.ts +0 -1
- package/src/manager/panel/PanelManagerComponent.vue +42 -19
- package/src/manager/panel/PanelManagerComponent.vue.d.ts +4 -3
- package/src/search/SearchComponent.vue +9 -11
- package/src/search/SearchComponent.vue.d.ts +2 -1
- package/src/search/search.js +2 -0
- package/src/uiConfig.d.ts +46 -0
- package/src/uiConfig.js +3 -0
- package/dist/assets/ui-94adeedc.css +0 -1
- /package/dist/assets/{cesium-4fcc8a17.js → cesium-8369e63b.js} +0 -0
- /package/dist/assets/core-workers/{panoramaImageWorker.js-fc0f2458.js → panoramaImageWorker.js-f9c706f1.js} +0 -0
- /package/dist/assets/{ol-8c487975.js → ol-9f59d99f.js} +0 -0
- /package/dist/assets/{vue-225a7b37.js → vue-f6136dc6.js} +0 -0
- /package/dist/assets/{vuetify-2f71239e.css → vuetify-de6f6eb0.css} +0 -0
|
@@ -16,9 +16,31 @@ export type WMSEntry = {
|
|
|
16
16
|
name: string;
|
|
17
17
|
active: import("vue").Ref<boolean>;
|
|
18
18
|
activeStyle: import("vue").Ref<string>;
|
|
19
|
-
title
|
|
20
|
-
extent
|
|
21
|
-
styles
|
|
19
|
+
title?: string | undefined;
|
|
20
|
+
extent?: import("@vcmap/core").Extent | undefined;
|
|
21
|
+
styles?: WMSStyleEntry[] | undefined;
|
|
22
|
+
};
|
|
23
|
+
export type SerializedWMSLegend = {
|
|
24
|
+
url: string;
|
|
25
|
+
width: number;
|
|
26
|
+
height: number;
|
|
27
|
+
};
|
|
28
|
+
export type SerializedWMSStyle = {
|
|
29
|
+
name: string;
|
|
30
|
+
title?: string | undefined;
|
|
31
|
+
legend?: SerializedWMSLegend[] | undefined;
|
|
32
|
+
};
|
|
33
|
+
export type SerializedWMSLayer = {
|
|
34
|
+
name: string;
|
|
35
|
+
title?: string | undefined;
|
|
36
|
+
/**
|
|
37
|
+
* Layer extent, in WGS84 coordinates
|
|
38
|
+
*/
|
|
39
|
+
extent?: number[] | undefined;
|
|
40
|
+
styles?: SerializedWMSStyle[] | undefined;
|
|
41
|
+
};
|
|
42
|
+
export type SerializedWMSCapabilities = {
|
|
43
|
+
layers: Array<SerializedWMSLayer>;
|
|
22
44
|
};
|
|
23
45
|
/**
|
|
24
46
|
* @typedef {import('./contentTreeItem.js').ContentTreeItemOptions &
|
|
@@ -41,9 +63,33 @@ export type WMSEntry = {
|
|
|
41
63
|
* @property {string} name
|
|
42
64
|
* @property {import("vue").Ref<boolean>} active
|
|
43
65
|
* @property {import("vue").Ref<string>} activeStyle
|
|
44
|
-
* @property {string} title
|
|
45
|
-
* @property {import("@vcmap/core").Extent} extent
|
|
46
|
-
* @property {Array<WMSStyleEntry>} styles
|
|
66
|
+
* @property {string} [title]
|
|
67
|
+
* @property {import("@vcmap/core").Extent} [extent]
|
|
68
|
+
* @property {Array<WMSStyleEntry>} [styles]
|
|
69
|
+
*/
|
|
70
|
+
/**
|
|
71
|
+
* @typedef {Object} SerializedWMSLegend
|
|
72
|
+
* @property {string} url
|
|
73
|
+
* @property {number} width
|
|
74
|
+
* @property {number} height
|
|
75
|
+
*/
|
|
76
|
+
/**
|
|
77
|
+
* @typedef {Object} SerializedWMSStyle
|
|
78
|
+
* @property {string} name
|
|
79
|
+
* @property {string} [title]
|
|
80
|
+
* @property {SerializedWMSLegend[]} [legend]
|
|
81
|
+
*/
|
|
82
|
+
/**
|
|
83
|
+
* @typedef {Object} SerializedWMSLayer
|
|
84
|
+
* @property {string} name
|
|
85
|
+
* @property {string} [title]
|
|
86
|
+
* @property {number[]} [extent] Layer extent, in WGS84 coordinates
|
|
87
|
+
* @property {SerializedWMSStyle[]} [styles]
|
|
88
|
+
*/
|
|
89
|
+
/**
|
|
90
|
+
* @description The serialized form of WMS Capabilities are used in the configuration to avoid fetching the capabilities on every startup.
|
|
91
|
+
* @typedef {Object} SerializedWMSCapabilities
|
|
92
|
+
* @property {Array<SerializedWMSLayer>} layers
|
|
47
93
|
*/
|
|
48
94
|
/**
|
|
49
95
|
* A WMSGroupItem, will take over a WMSLayer and request the Capabilities of the layer to show all available
|
|
@@ -2,6 +2,7 @@ import { markVolatile } from '@vcmap/core';
|
|
|
2
2
|
import { getLogger } from '@vcsuite/logger';
|
|
3
3
|
import { ref } from 'vue';
|
|
4
4
|
import { parseBoolean } from '@vcsuite/parsers';
|
|
5
|
+
import { is } from '@vcsuite/check';
|
|
5
6
|
import deepEqual from 'fast-deep-equal';
|
|
6
7
|
import WMSCapabilities from 'ol/format/WMSCapabilities';
|
|
7
8
|
import { StateActionState } from '../actions/stateRefAction.js';
|
|
@@ -10,6 +11,90 @@ import WmsChildContentTreeItem from './wmsChildContentTreeItem.js';
|
|
|
10
11
|
import VcsObjectContentTreeItem from './vcsObjectContentTreeItem.js';
|
|
11
12
|
import { legendSymbol } from '../legend/legendHelper.js';
|
|
12
13
|
|
|
14
|
+
/**
|
|
15
|
+
*
|
|
16
|
+
* @param {string} src The OnlineRessource property of the legend
|
|
17
|
+
* @param {number} width The width of the image
|
|
18
|
+
* @param {string} title The title of the layer.
|
|
19
|
+
* @returns {import('../legend/legendHelper.js').StyleLegendItem}
|
|
20
|
+
*/
|
|
21
|
+
function parseLegend(src, width, title) {
|
|
22
|
+
if (width < 25) {
|
|
23
|
+
return {
|
|
24
|
+
type: 'StyleLegendItem',
|
|
25
|
+
colNr: 1,
|
|
26
|
+
rows: [{ type: 'IconLegendRow', title, image: { src } }],
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
return { type: 'ImageLegendItem', popoutBtn: true, src };
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
*
|
|
34
|
+
* @param {SerializedWMSCapabilities} capabilities
|
|
35
|
+
* @returns {WMSEntry[]}
|
|
36
|
+
*/
|
|
37
|
+
function parseSerializedCapabilities(capabilities) {
|
|
38
|
+
if (capabilities?.layers?.length > 0) {
|
|
39
|
+
return capabilities.layers
|
|
40
|
+
.filter((layer) => {
|
|
41
|
+
if (!is(layer, { name: String })) {
|
|
42
|
+
getLogger(this.className).warn(
|
|
43
|
+
`Ignoring WMS Layer without name in layer ${this._layerName}`,
|
|
44
|
+
);
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
return true;
|
|
48
|
+
})
|
|
49
|
+
.map((layer) => {
|
|
50
|
+
const styles = layer.styles
|
|
51
|
+
?.filter((s) => {
|
|
52
|
+
if (!is(s, { name: String })) {
|
|
53
|
+
getLogger(this.className).warn(
|
|
54
|
+
`Ignoring WMS Style without name in layer ${this._layerName}`,
|
|
55
|
+
);
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
return true;
|
|
59
|
+
})
|
|
60
|
+
.map((s) => ({
|
|
61
|
+
name: s.name,
|
|
62
|
+
title: s.title,
|
|
63
|
+
legend:
|
|
64
|
+
s.legend
|
|
65
|
+
?.filter((l) => {
|
|
66
|
+
if (!is(l, { url: String, width: Number, height: Number })) {
|
|
67
|
+
getLogger(this.className).warn(
|
|
68
|
+
`Ignoring invalid WMS Legend in style ${s.name} in layer ${this._layerName}`,
|
|
69
|
+
);
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
return true;
|
|
73
|
+
})
|
|
74
|
+
.map((l) => parseLegend(l.url, l.width, s.title || '')) || [],
|
|
75
|
+
}));
|
|
76
|
+
|
|
77
|
+
const wmsEntry = {
|
|
78
|
+
name: layer.name,
|
|
79
|
+
active: ref(false),
|
|
80
|
+
activeStyle: ref(''),
|
|
81
|
+
};
|
|
82
|
+
if (layer.title) {
|
|
83
|
+
wmsEntry.title = layer.title;
|
|
84
|
+
}
|
|
85
|
+
if (layer.extent) {
|
|
86
|
+
wmsEntry.extent = layer.extent;
|
|
87
|
+
}
|
|
88
|
+
if (styles?.length > 0) {
|
|
89
|
+
wmsEntry.styles = styles;
|
|
90
|
+
}
|
|
91
|
+
return wmsEntry;
|
|
92
|
+
});
|
|
93
|
+
} else {
|
|
94
|
+
return [];
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
13
98
|
/**
|
|
14
99
|
* @param {string} rawUrl
|
|
15
100
|
* @param {Record<string, string>} parameters
|
|
@@ -49,27 +134,9 @@ async function getWMSEntries(rawUrl, parameters) {
|
|
|
49
134
|
title: style.Title,
|
|
50
135
|
legend: style.LegendURL?.filter(
|
|
51
136
|
(legend) => legend.OnlineResource,
|
|
52
|
-
).map((legend) =>
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
return {
|
|
56
|
-
type: 'StyleLegendItem',
|
|
57
|
-
colNr: 1,
|
|
58
|
-
rows: [
|
|
59
|
-
{
|
|
60
|
-
type: 'IconLegendRow',
|
|
61
|
-
title: layer.Title,
|
|
62
|
-
image: { src },
|
|
63
|
-
},
|
|
64
|
-
],
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
return {
|
|
68
|
-
type: 'ImageLegendItem',
|
|
69
|
-
src,
|
|
70
|
-
popoutBtn: true,
|
|
71
|
-
};
|
|
72
|
-
}),
|
|
137
|
+
).map((legend) =>
|
|
138
|
+
parseLegend(legend.OnlineResource, legend.size[0], layer.Title),
|
|
139
|
+
),
|
|
73
140
|
};
|
|
74
141
|
}) ?? [];
|
|
75
142
|
return {
|
|
@@ -133,9 +200,34 @@ function createWMSChildContentTreeItem(
|
|
|
133
200
|
* @property {string} name
|
|
134
201
|
* @property {import("vue").Ref<boolean>} active
|
|
135
202
|
* @property {import("vue").Ref<string>} activeStyle
|
|
136
|
-
* @property {string} title
|
|
137
|
-
* @property {import("@vcmap/core").Extent} extent
|
|
138
|
-
* @property {Array<WMSStyleEntry>} styles
|
|
203
|
+
* @property {string} [title]
|
|
204
|
+
* @property {import("@vcmap/core").Extent} [extent]
|
|
205
|
+
* @property {Array<WMSStyleEntry>} [styles]
|
|
206
|
+
*/
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* @typedef {Object} SerializedWMSLegend
|
|
210
|
+
* @property {string} url
|
|
211
|
+
* @property {number} width
|
|
212
|
+
* @property {number} height
|
|
213
|
+
*/
|
|
214
|
+
/**
|
|
215
|
+
* @typedef {Object} SerializedWMSStyle
|
|
216
|
+
* @property {string} name
|
|
217
|
+
* @property {string} [title]
|
|
218
|
+
* @property {SerializedWMSLegend[]} [legend]
|
|
219
|
+
*/
|
|
220
|
+
/**
|
|
221
|
+
* @typedef {Object} SerializedWMSLayer
|
|
222
|
+
* @property {string} name
|
|
223
|
+
* @property {string} [title]
|
|
224
|
+
* @property {number[]} [extent] Layer extent, in WGS84 coordinates
|
|
225
|
+
* @property {SerializedWMSStyle[]} [styles]
|
|
226
|
+
*/
|
|
227
|
+
/**
|
|
228
|
+
* @description The serialized form of WMS Capabilities are used in the configuration to avoid fetching the capabilities on every startup.
|
|
229
|
+
* @typedef {Object} SerializedWMSCapabilities
|
|
230
|
+
* @property {Array<SerializedWMSLayer>} layers
|
|
139
231
|
*/
|
|
140
232
|
|
|
141
233
|
/**
|
|
@@ -504,10 +596,17 @@ class WMSGroupContentTreeItem extends VcsObjectContentTreeItem {
|
|
|
504
596
|
this.clickable = !this._setWMSLayersExclusive;
|
|
505
597
|
|
|
506
598
|
try {
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
599
|
+
let availableWMSEntries = [];
|
|
600
|
+
if (this._layer.properties.capabilities) {
|
|
601
|
+
availableWMSEntries = parseSerializedCapabilities(
|
|
602
|
+
this._layer.properties.capabilities,
|
|
603
|
+
);
|
|
604
|
+
} else {
|
|
605
|
+
availableWMSEntries = await getWMSEntries(
|
|
606
|
+
this._layer.url,
|
|
607
|
+
this._layer.parameters,
|
|
608
|
+
);
|
|
609
|
+
}
|
|
511
610
|
// check if the layer still exists, it can happen that the layer was removed while fetching the capabilities.
|
|
512
611
|
if (!this._layer) {
|
|
513
612
|
return;
|
|
@@ -91,10 +91,16 @@ export function setBalloonPosition(windowManager, id, windowPosition, target) {
|
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
const { width, height, maxWidth, maxHeight } = windowManager.get(id).position;
|
|
94
|
+
|
|
95
|
+
// Get the actual map target bounding rect to account for panel offsets
|
|
96
|
+
const targetRect = target?.getBoundingClientRect();
|
|
97
|
+
const offsetX = targetRect ? targetRect.left : 0;
|
|
98
|
+
const offsetY = targetRect ? targetRect.top : 0;
|
|
99
|
+
|
|
94
100
|
const mapWindowPosition = getWindowPositionOptionsFromMapEvent(
|
|
95
101
|
new Cartesian2(
|
|
96
|
-
windowPosition.x - balloonOffset.x,
|
|
97
|
-
windowPosition.y - balloonOffset.y,
|
|
102
|
+
windowPosition.x - balloonOffset.x + offsetX,
|
|
103
|
+
windowPosition.y - balloonOffset.y + offsetY,
|
|
98
104
|
),
|
|
99
105
|
target,
|
|
100
106
|
WindowAlignment.BOTTOM_LEFT,
|
package/src/i18n/de.d.ts
CHANGED
|
@@ -527,6 +527,7 @@ declare namespace messages {
|
|
|
527
527
|
export let select: string;
|
|
528
528
|
let placeholder_1: string;
|
|
529
529
|
export { placeholder_1 as placeholder };
|
|
530
|
+
export let hideWindow: string;
|
|
530
531
|
export let zoomToFeatureAction: string;
|
|
531
532
|
export let zoomToAll: string;
|
|
532
533
|
export let zoomToAllMobile: string;
|
package/src/i18n/de.js
CHANGED
|
@@ -372,6 +372,7 @@ const messages = {
|
|
|
372
372
|
tooltip: 'Suche',
|
|
373
373
|
select: 'Suchergebnis auswählen',
|
|
374
374
|
placeholder: 'Suche nach Adresse oder Ort/Sehenswürdigkeit',
|
|
375
|
+
hideWindow: 'Suche ausblenden',
|
|
375
376
|
zoomToFeatureAction: 'Auf Ergebnis zoomen',
|
|
376
377
|
zoomToAll: 'Auf alle Ergebnisse zoomen',
|
|
377
378
|
zoomToAllMobile: 'Auf alle zoomen',
|
package/src/i18n/en.d.ts
CHANGED
|
@@ -527,6 +527,7 @@ declare namespace messages {
|
|
|
527
527
|
export let select: string;
|
|
528
528
|
let placeholder_1: string;
|
|
529
529
|
export { placeholder_1 as placeholder };
|
|
530
|
+
export let hideWindow: string;
|
|
530
531
|
export let zoomToFeatureAction: string;
|
|
531
532
|
export let zoomToAllMobile: string;
|
|
532
533
|
export let zoomToAll: string;
|
package/src/i18n/en.js
CHANGED
|
@@ -372,6 +372,7 @@ const messages = {
|
|
|
372
372
|
tooltip: 'Search',
|
|
373
373
|
select: 'Select result item',
|
|
374
374
|
placeholder: 'Search for address or landmark/point of interest',
|
|
375
|
+
hideWindow: 'Hide search',
|
|
375
376
|
zoomToFeatureAction: 'Zoom to result',
|
|
376
377
|
zoomToAllMobile: 'Zoom to all',
|
|
377
378
|
zoomToAll: 'Zoom to all',
|
|
@@ -10,10 +10,20 @@
|
|
|
10
10
|
'theme--dark': appIsDark,
|
|
11
11
|
resizable: panelState.resizable,
|
|
12
12
|
}"
|
|
13
|
-
@mousedown="startResize"
|
|
14
|
-
@mouseup="stopResize"
|
|
15
13
|
>
|
|
16
|
-
<
|
|
14
|
+
<div class="panel-content">
|
|
15
|
+
<slot />
|
|
16
|
+
</div>
|
|
17
|
+
<div
|
|
18
|
+
class="resize-handle"
|
|
19
|
+
:class="{
|
|
20
|
+
'resize-handle-left': isLeft,
|
|
21
|
+
'resize-handle-right': isRight,
|
|
22
|
+
'resize-handle-bottom': isBottom,
|
|
23
|
+
'resize-handle-resizable': panelState.resizable,
|
|
24
|
+
}"
|
|
25
|
+
@pointerdown="startResize"
|
|
26
|
+
></div>
|
|
17
27
|
</div>
|
|
18
28
|
</template>
|
|
19
29
|
|
|
@@ -53,19 +63,12 @@
|
|
|
53
63
|
() => props.panelState.location === PanelLocation.BOTTOM,
|
|
54
64
|
),
|
|
55
65
|
startResize(e) {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
resizable &&
|
|
59
|
-
((location === PanelLocation.LEFT &&
|
|
60
|
-
e.currentTarget.clientWidth - e.offsetX < 4) ||
|
|
61
|
-
(location === PanelLocation.RIGHT && e.offsetX < 4) ||
|
|
62
|
-
(location === PanelLocation.BOTTOM && e.offsetY < 4))
|
|
63
|
-
) {
|
|
64
|
-
emit('resize', props.panelState.id);
|
|
66
|
+
if (!props.panelState.resizable) {
|
|
67
|
+
return;
|
|
65
68
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
emit('resize',
|
|
69
|
+
e.preventDefault();
|
|
70
|
+
e.stopPropagation();
|
|
71
|
+
emit('resize', props.panelState.id);
|
|
69
72
|
},
|
|
70
73
|
};
|
|
71
74
|
},
|
|
@@ -74,39 +77,57 @@
|
|
|
74
77
|
|
|
75
78
|
<style scoped lang="scss">
|
|
76
79
|
.panel-component {
|
|
80
|
+
display: flex;
|
|
81
|
+
flex-direction: column;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.theme--light {
|
|
85
|
+
background: rgb(var(--v-theme-surface));
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.theme--dark {
|
|
89
|
+
background: rgb(var(--v-theme-surface));
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.panel-content {
|
|
93
|
+
flex: 1;
|
|
94
|
+
overflow: auto;
|
|
77
95
|
padding: 0 4px;
|
|
96
|
+
min-height: 0; /* Important for flex children to be scrollable */
|
|
78
97
|
}
|
|
79
|
-
|
|
80
|
-
|
|
98
|
+
|
|
99
|
+
.resize-handle {
|
|
81
100
|
position: absolute;
|
|
82
101
|
background: rgb(var(--v-theme-surface-light));
|
|
83
102
|
}
|
|
84
103
|
|
|
85
|
-
.
|
|
104
|
+
.resize-handle-left {
|
|
86
105
|
width: 4px;
|
|
87
106
|
top: 0;
|
|
88
107
|
bottom: 0;
|
|
89
108
|
right: 0;
|
|
90
109
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
}
|
|
94
|
-
.panel-component-right::after {
|
|
110
|
+
|
|
111
|
+
.resize-handle-right {
|
|
95
112
|
width: 4px;
|
|
96
113
|
top: 0;
|
|
97
114
|
bottom: 0;
|
|
98
115
|
left: 0;
|
|
99
116
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
}
|
|
103
|
-
.panel-component-bottom::after {
|
|
117
|
+
|
|
118
|
+
.resize-handle-bottom {
|
|
104
119
|
left: 0;
|
|
105
120
|
right: 0;
|
|
106
121
|
top: 0;
|
|
107
122
|
height: 4px;
|
|
108
123
|
}
|
|
109
|
-
|
|
124
|
+
|
|
125
|
+
.resize-handle-resizable.resize-handle-left,
|
|
126
|
+
.resize-handle-resizable.resize-handle-right {
|
|
127
|
+
cursor: ew-resize;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.resize-handle-resizable.resize-handle-bottom {
|
|
110
131
|
cursor: n-resize;
|
|
111
132
|
}
|
|
112
133
|
</style>
|
|
@@ -9,7 +9,6 @@ declare const _default: import("vue").DefineComponent<{
|
|
|
9
9
|
isRight: import("vue").ComputedRef<boolean>;
|
|
10
10
|
isBottom: import("vue").ComputedRef<boolean>;
|
|
11
11
|
startResize(e: any): void;
|
|
12
|
-
stopResize(): void;
|
|
13
12
|
}, any, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, "resize"[], "resize", import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
14
13
|
panelState: {
|
|
15
14
|
type: ObjectConstructor;
|
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div
|
|
3
3
|
class="vcs-panel-frame panel-manager-component"
|
|
4
|
-
@
|
|
5
|
-
@
|
|
4
|
+
@pointerup="setResizing(undefined)"
|
|
5
|
+
@pointerleave="setResizing(undefined)"
|
|
6
6
|
ref="panelFrameRef"
|
|
7
7
|
>
|
|
8
|
+
<div
|
|
9
|
+
v-if="resizing"
|
|
10
|
+
class="resize-overlay"
|
|
11
|
+
:style="{ cursor: resizeCursor }"
|
|
12
|
+
@pointermove="resizingFunction"
|
|
13
|
+
></div>
|
|
8
14
|
<PanelComponent
|
|
9
15
|
:panel-state="mainPanel.state"
|
|
10
16
|
:style="getPosition(mainPanel)"
|
|
11
|
-
class="overflow-auto"
|
|
12
17
|
>
|
|
13
18
|
<VcsMainMap />
|
|
14
19
|
</PanelComponent>
|
|
@@ -18,7 +23,6 @@
|
|
|
18
23
|
:panel-state="getState(id)"
|
|
19
24
|
:style="getStyles(id).value"
|
|
20
25
|
:class="getState(id).classes"
|
|
21
|
-
class="overflow-auto"
|
|
22
26
|
@resize="setResizing"
|
|
23
27
|
>
|
|
24
28
|
<component
|
|
@@ -36,6 +40,7 @@
|
|
|
36
40
|
computed,
|
|
37
41
|
getCurrentInstance,
|
|
38
42
|
inject,
|
|
43
|
+
onUnmounted,
|
|
39
44
|
reactive,
|
|
40
45
|
ref,
|
|
41
46
|
watch,
|
|
@@ -84,7 +89,7 @@
|
|
|
84
89
|
const { componentIds } = panelManager;
|
|
85
90
|
const panelFrameRef = ref();
|
|
86
91
|
const resizing = ref(undefined);
|
|
87
|
-
|
|
92
|
+
const resizingFunction = ref(() => {});
|
|
88
93
|
|
|
89
94
|
/**
|
|
90
95
|
* @param {string} id
|
|
@@ -126,12 +131,13 @@
|
|
|
126
131
|
if (panel) {
|
|
127
132
|
let resizeKey;
|
|
128
133
|
if (panel[panelLocationSymbol] === PanelLocation.BOTTOM) {
|
|
134
|
+
const frameRect = panelFrameRef.value.getBoundingClientRect();
|
|
129
135
|
const height =
|
|
130
|
-
((
|
|
136
|
+
((frameRect.bottom - e.clientY) /
|
|
131
137
|
panelFrameRef.value.parentElement.offsetHeight) *
|
|
132
138
|
100;
|
|
133
139
|
setPanelPosition(panelManager, panel, {
|
|
134
|
-
height: `${Math.round(
|
|
140
|
+
height: `${Math.round(height)}%`,
|
|
135
141
|
});
|
|
136
142
|
} else {
|
|
137
143
|
const width =
|
|
@@ -160,25 +166,21 @@
|
|
|
160
166
|
const setResizing = (id) => {
|
|
161
167
|
if (id) {
|
|
162
168
|
resizing.value = id;
|
|
163
|
-
resizingFunction = (e) => {
|
|
169
|
+
resizingFunction.value = (e) => {
|
|
164
170
|
e.preventDefault();
|
|
165
171
|
resize(panelManager.get(id), e);
|
|
166
172
|
};
|
|
167
|
-
panelFrameRef.value.addEventListener(
|
|
168
|
-
'mousemove',
|
|
169
|
-
resizingFunction,
|
|
170
|
-
false,
|
|
171
|
-
);
|
|
172
173
|
} else {
|
|
173
174
|
resizing.value = undefined;
|
|
174
|
-
|
|
175
|
-
'mousemove',
|
|
176
|
-
resizingFunction,
|
|
177
|
-
false,
|
|
178
|
-
);
|
|
175
|
+
resizingFunction.value = () => {};
|
|
179
176
|
}
|
|
180
177
|
};
|
|
181
178
|
|
|
179
|
+
// Clean up resizing state on unmount
|
|
180
|
+
onUnmounted(() => {
|
|
181
|
+
setResizing(undefined);
|
|
182
|
+
});
|
|
183
|
+
|
|
182
184
|
watch(
|
|
183
185
|
() => [...componentIds],
|
|
184
186
|
() => {
|
|
@@ -197,6 +199,17 @@
|
|
|
197
199
|
);
|
|
198
200
|
});
|
|
199
201
|
|
|
202
|
+
const resizeCursor = computed(() => {
|
|
203
|
+
if (!resizing.value) {
|
|
204
|
+
return 'default';
|
|
205
|
+
}
|
|
206
|
+
const panel = panelManager.get(resizing.value);
|
|
207
|
+
if (panel && panel[panelLocationSymbol] === PanelLocation.BOTTOM) {
|
|
208
|
+
return 'n-resize';
|
|
209
|
+
}
|
|
210
|
+
return 'ew-resize';
|
|
211
|
+
});
|
|
212
|
+
|
|
200
213
|
return {
|
|
201
214
|
mainPanel,
|
|
202
215
|
componentIds,
|
|
@@ -205,13 +218,15 @@
|
|
|
205
218
|
getStyles,
|
|
206
219
|
getState,
|
|
207
220
|
getProps,
|
|
221
|
+
addMobileClass,
|
|
208
222
|
panelFrameRef,
|
|
223
|
+
resizing,
|
|
224
|
+
resizeCursor,
|
|
209
225
|
setResizing,
|
|
210
226
|
resizingFunction,
|
|
211
227
|
close: (id) => {
|
|
212
228
|
panelManager.remove(id);
|
|
213
229
|
},
|
|
214
|
-
addMobileClass,
|
|
215
230
|
};
|
|
216
231
|
},
|
|
217
232
|
};
|
|
@@ -228,4 +243,12 @@
|
|
|
228
243
|
.vcs-panel-border {
|
|
229
244
|
padding: 5px;
|
|
230
245
|
}
|
|
246
|
+
.resize-overlay {
|
|
247
|
+
position: absolute;
|
|
248
|
+
top: 0;
|
|
249
|
+
left: 0;
|
|
250
|
+
right: 0;
|
|
251
|
+
bottom: 0;
|
|
252
|
+
z-index: 9999;
|
|
253
|
+
}
|
|
231
254
|
</style>
|
|
@@ -17,7 +17,6 @@ declare const _default: import("vue").DefineComponent<{}, {
|
|
|
17
17
|
isRight: import("vue").ComputedRef<boolean>;
|
|
18
18
|
isBottom: import("vue").ComputedRef<boolean>;
|
|
19
19
|
startResize(e: any): void;
|
|
20
|
-
stopResize(): void;
|
|
21
20
|
}, any, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, "resize"[], "resize", import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
22
21
|
panelState: {
|
|
23
22
|
type: ObjectConstructor;
|
|
@@ -29,10 +28,12 @@ declare const _default: import("vue").DefineComponent<{}, {
|
|
|
29
28
|
getStyles: (id: string) => import("vue").ComputedRef<Object>;
|
|
30
29
|
getState: (id: string) => PanelState;
|
|
31
30
|
getProps: (id: string) => Object;
|
|
31
|
+
addMobileClass: import("vue").ComputedRef<any>;
|
|
32
32
|
panelFrameRef: import("vue").Ref<any>;
|
|
33
|
+
resizing: import("vue").Ref<undefined>;
|
|
34
|
+
resizeCursor: import("vue").ComputedRef<"default" | "n-resize" | "ew-resize">;
|
|
33
35
|
setResizing: (id: any) => void;
|
|
34
|
-
resizingFunction: () => void
|
|
36
|
+
resizingFunction: import("vue").Ref<() => void>;
|
|
35
37
|
close: (id: any) => void;
|
|
36
|
-
addMobileClass: import("vue").ComputedRef<any>;
|
|
37
38
|
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{}>>, {}, {}>;
|
|
38
39
|
export default _default;
|
|
@@ -21,11 +21,7 @@
|
|
|
21
21
|
</span>
|
|
22
22
|
<template v-if="results.length > 0">
|
|
23
23
|
<v-divider class="mt-1 base-darken-1" />
|
|
24
|
-
<ResultsComponent
|
|
25
|
-
:query="query"
|
|
26
|
-
:results="results"
|
|
27
|
-
:show-selected-only="showSelectedOnly"
|
|
28
|
-
/>
|
|
24
|
+
<ResultsComponent :query="query" :results="results" />
|
|
29
25
|
<v-divider />
|
|
30
26
|
|
|
31
27
|
<v-row no-gutters>
|
|
@@ -33,9 +29,10 @@
|
|
|
33
29
|
<div class="button-container d-flex align-center px-2 pt-2 pb-1">
|
|
34
30
|
<VcsFormButton
|
|
35
31
|
class="fixed-button"
|
|
36
|
-
|
|
32
|
+
tooltip="search.hideWindow"
|
|
33
|
+
@click="closeWindow"
|
|
37
34
|
>
|
|
38
|
-
<v-icon icon="mdi-
|
|
35
|
+
<v-icon icon="mdi-minus-box-multiple-outline" />
|
|
39
36
|
</VcsFormButton>
|
|
40
37
|
<VcsFormButton
|
|
41
38
|
@click="zoomToAll"
|
|
@@ -71,6 +68,8 @@
|
|
|
71
68
|
import VcsFormButton from '../components/buttons/VcsFormButton.vue';
|
|
72
69
|
import { useFontSize } from '../vuePlugins/vuetify.js';
|
|
73
70
|
|
|
71
|
+
export const searchComponentId = 'searchId';
|
|
72
|
+
|
|
74
73
|
/**
|
|
75
74
|
* @description Stylized search component providing an input field for search inputs.
|
|
76
75
|
* Renders a list of results using {@link ResultsComponent }
|
|
@@ -98,8 +97,6 @@
|
|
|
98
97
|
const { xs } = useDisplay();
|
|
99
98
|
let queryPreSuggestion = '';
|
|
100
99
|
|
|
101
|
-
const showSelectedOnly = ref(false);
|
|
102
|
-
|
|
103
100
|
let suggestionTimeout;
|
|
104
101
|
|
|
105
102
|
const onInput = () => {
|
|
@@ -140,7 +137,6 @@
|
|
|
140
137
|
suggesting.value = '';
|
|
141
138
|
suggestions.value = [];
|
|
142
139
|
queryPreSuggestion = '';
|
|
143
|
-
showSelectedOnly.value = false;
|
|
144
140
|
};
|
|
145
141
|
|
|
146
142
|
const search = async () => {
|
|
@@ -163,7 +159,6 @@
|
|
|
163
159
|
return fontSize.value + 11;
|
|
164
160
|
});
|
|
165
161
|
return {
|
|
166
|
-
showSelectedOnly,
|
|
167
162
|
xs,
|
|
168
163
|
query,
|
|
169
164
|
searching,
|
|
@@ -193,6 +188,9 @@
|
|
|
193
188
|
query.value = queryPreSuggestion;
|
|
194
189
|
}
|
|
195
190
|
},
|
|
191
|
+
closeWindow() {
|
|
192
|
+
app.windowManager.remove(searchComponentId);
|
|
193
|
+
},
|
|
196
194
|
};
|
|
197
195
|
},
|
|
198
196
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
export const searchComponentId: "searchId";
|
|
1
2
|
declare const _default: import("vue").DefineComponent<{}, {
|
|
2
|
-
showSelectedOnly: import("vue").Ref<boolean>;
|
|
3
3
|
xs: import("vue").Ref<boolean>;
|
|
4
4
|
query: import("vue").Ref<string>;
|
|
5
5
|
searching: import("vue").Ref<boolean>;
|
|
@@ -15,5 +15,6 @@ declare const _default: import("vue").DefineComponent<{}, {
|
|
|
15
15
|
selectedSuggestion: import("vue").Ref<number>;
|
|
16
16
|
onInput: () => void;
|
|
17
17
|
selectSuggestion(value: any): void;
|
|
18
|
+
closeWindow(): void;
|
|
18
19
|
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{}>>, {}, {}>;
|
|
19
20
|
export default _default;
|