@vcmap/ui 5.0.0-rc.26 → 5.0.0-rc.27

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 (102) hide show
  1. package/build/buildCesium.js +7 -0
  2. package/config/dev.config.json +4 -0
  3. package/dist/assets/cesium/ThirdParty/Workers/basis_transcoder.js +21 -0
  4. package/dist/assets/cesium/ThirdParty/Workers/draco_decoder_nodejs.js +117 -0
  5. package/dist/assets/cesium/ThirdParty/Workers/package.json +1 -0
  6. package/dist/assets/cesium/ThirdParty/Workers/pako_deflate.min.js +2 -0
  7. package/dist/assets/cesium/ThirdParty/Workers/pako_inflate.min.js +2 -0
  8. package/dist/assets/cesium/ThirdParty/Workers/z-worker-pako.js +1 -0
  9. package/dist/assets/cesium/ThirdParty/basis_transcoder.wasm +0 -0
  10. package/dist/assets/cesium/ThirdParty/draco_decoder.wasm +0 -0
  11. package/dist/assets/cesium/ThirdParty/google-earth-dbroot-parser.js +8337 -0
  12. package/dist/assets/{cesium.305b7c.js → cesium.82fdbe.js} +4 -4
  13. package/dist/assets/cesium.js +1 -1
  14. package/dist/assets/{core.f3d6d4.js → core.df069a.js} +2 -2
  15. package/dist/assets/core.js +1 -1
  16. package/dist/assets/index-1cff371d.js +1 -0
  17. package/dist/assets/ol.js +1 -1
  18. package/dist/assets/style/icon-marker-blue.534e37.png +0 -0
  19. package/dist/assets/style/icon-marker-green.0b6a92.png +0 -0
  20. package/dist/assets/style/icon-marker-o-blue.7b6d62.png +0 -0
  21. package/dist/assets/style/icon-marker-o-green.c863c0.png +0 -0
  22. package/dist/assets/style/icon-marker-o-red.93ff58.png +0 -0
  23. package/dist/assets/style/icon-marker-o.036477.png +0 -0
  24. package/dist/assets/style/icon-marker-red.313d03.png +0 -0
  25. package/dist/assets/style/icon-marker.70960f.png +0 -0
  26. package/dist/assets/style/icon-pin-blue.7be369.png +0 -0
  27. package/dist/assets/style/icon-pin-green.cbb935.png +0 -0
  28. package/dist/assets/style/icon-pin-red.3f25b2.png +0 -0
  29. package/dist/assets/style/icon-pin.b7ce77.png +0 -0
  30. package/dist/assets/{ui.74022f.css → ui.3ed7ff.css} +2 -2
  31. package/dist/assets/ui.3ed7ff.js +14763 -0
  32. package/dist/assets/ui.js +1 -1
  33. package/dist/assets/vue.js +2 -2
  34. package/dist/assets/{vuetify.30486f.js → vuetify.614278.js} +1 -1
  35. package/dist/assets/vuetify.js +2 -2
  36. package/dist/index.html +1 -1
  37. package/index.js +17 -1
  38. package/package.json +1 -1
  39. package/plugins/@vcmap/create-link/index.js +8 -8
  40. package/plugins/@vcmap-show-case/collection-manager-example/index.js +6 -1
  41. package/plugins/@vcmap-show-case/form-inputs-example/FormInputsExample.vue +36 -8
  42. package/plugins/@vcmap-show-case/form-inputs-example/exampleActions.js +0 -19
  43. package/plugins/@vcmap-show-case/form-inputs-example/index.js +1 -2
  44. package/plugins/@vcmap-show-case/style-input-example/README.md +4 -0
  45. package/plugins/@vcmap-show-case/style-input-example/index.js +42 -0
  46. package/plugins/@vcmap-show-case/style-input-example/package.json +5 -0
  47. package/plugins/@vcmap-show-case/style-input-example/styleExample.vue +191 -0
  48. package/plugins/@vcmap-show-case/window-tester/WindowExample.vue +12 -13
  49. package/plugins/@vcmap-show-case/window-tester/windowExampleToggleChild.vue +44 -0
  50. package/public/assets/style/icon-marker-blue.png +0 -0
  51. package/public/assets/style/icon-marker-green.png +0 -0
  52. package/public/assets/style/icon-marker-o-blue.png +0 -0
  53. package/public/assets/style/icon-marker-o-green.png +0 -0
  54. package/public/assets/style/icon-marker-o-red.png +0 -0
  55. package/public/assets/style/icon-marker-o.png +0 -0
  56. package/public/assets/style/icon-marker-red.png +0 -0
  57. package/public/assets/style/icon-marker.png +0 -0
  58. package/public/assets/style/icon-pin-blue.png +0 -0
  59. package/public/assets/style/icon-pin-green.png +0 -0
  60. package/public/assets/style/icon-pin-red.png +0 -0
  61. package/public/assets/style/icon-pin.png +0 -0
  62. package/src/actions/actionHelper.js +1 -0
  63. package/src/application/VcsApp.vue +7 -1
  64. package/src/components/buttons/VcsActionButtonList.vue +1 -0
  65. package/src/components/form-inputs-controls/VcsCheckbox.vue +3 -2
  66. package/src/components/form-inputs-controls/VcsFormSection.vue +59 -9
  67. package/src/components/form-inputs-controls/VcsLabel.vue +10 -0
  68. package/src/components/form-inputs-controls/VcsRadioGrid.vue +175 -0
  69. package/src/components/form-inputs-controls/VcsSelect.vue +3 -0
  70. package/src/components/form-inputs-controls/VcsTextField.vue +12 -0
  71. package/src/components/icons/+all.js +4 -0
  72. package/src/components/icons/EditVerticesIcon.vue +39 -0
  73. package/src/components/lists/VcsActionList.vue +2 -0
  74. package/src/components/style/MenuWrapper.vue +138 -0
  75. package/src/components/style/VcsFillMenu.vue +61 -0
  76. package/src/components/style/VcsFillSelector.vue +45 -0
  77. package/src/components/style/VcsImageMenu.vue +84 -0
  78. package/src/components/style/VcsImageSelector.vue +609 -0
  79. package/src/components/style/VcsStrokeMenu.vue +73 -0
  80. package/src/components/style/VcsStrokeSelector.vue +87 -0
  81. package/src/components/style/VcsTextMenu.vue +81 -0
  82. package/src/components/style/VcsTextSelector.vue +271 -0
  83. package/src/components/style/VcsVectorStyleComponent.vue +119 -0
  84. package/src/components/style/composables.js +84 -0
  85. package/src/contentTree/contentTreeCollection.js +1 -0
  86. package/src/i18n/de.js +51 -17
  87. package/src/i18n/en.js +56 -22
  88. package/src/legend/vcsLegend.vue +7 -5
  89. package/src/manager/collectionManager/CollectionComponent.vue +9 -17
  90. package/src/manager/collectionManager/CollectionComponentList.vue +22 -9
  91. package/src/manager/collectionManager/CollectionManager.vue +20 -1
  92. package/src/manager/collectionManager/collectionComponent.js +11 -0
  93. package/src/manager/window/WindowComponent.vue +2 -1
  94. package/src/manager/window/WindowManager.vue +23 -9
  95. package/src/manager/window/windowHelper.js +76 -4
  96. package/src/manager/window/windowManager.js +38 -6
  97. package/src/vcsUiApp.js +1 -0
  98. package/dist/assets/index-f94d5be3.js +0 -1
  99. package/dist/assets/ui.74022f.js +0 -13466
  100. /package/dist/assets/{ol.39cc05.js → ol.90a5d0.js} +0 -0
  101. /package/dist/assets/{vue.9b8c6e.js → vue.537ff3.js} +0 -0
  102. /package/dist/assets/{vuetify.30486f.css → vuetify.614278.css} +0 -0
package/src/i18n/de.js CHANGED
@@ -9,7 +9,7 @@ const messages = {
9
9
  tooltip: 'Menü',
10
10
  },
11
11
  share: {
12
- tooltip: 'Den aktuellen Kartenausschnitt teilen.',
12
+ tooltip: 'Aktuellen Kartenausschnitt teilen',
13
13
  },
14
14
  },
15
15
  content: {
@@ -22,24 +22,24 @@ const messages = {
22
22
  title: 'Weitere Informationen',
23
23
  },
24
24
  viewpointAction: {
25
- title: 'Springe zur Ansicht',
25
+ title: 'Zur Ansicht springen',
26
26
  },
27
27
  styleAction: {
28
- title: 'Öffne Stil Auswahl',
28
+ title: 'Stilauswahl öffnen',
29
29
  },
30
30
  layerExtentAction: {
31
- name: 'Ebenenausdehnung',
31
+ name: 'Auf Ebene zoomen',
32
32
  title: 'Auf Ebenenausdehnung zoomen',
33
33
  },
34
34
  },
35
35
  navigation: {
36
- obliqueLeftTooltip: 'Schrägluftbild nach links drehen',
37
- obliqueRightTooltip: 'Schrägluftbild nach rechts drehen',
36
+ obliqueLeftTooltip: 'Ansicht nach links drehen',
37
+ obliqueRightTooltip: 'Ansicht nach rechts drehen',
38
38
  zoomInTooltip: 'Hineinzoomen',
39
39
  zoomOutTooltip: 'Herauszoomen',
40
40
  pitchTooltip: 'Kameraneigung: {0}°',
41
41
  overviewMapTooltip: 'Übersichtskarte',
42
- homeButton: 'Springe zur Startansicht',
42
+ homeButton: 'Zur Startansicht springen',
43
43
  },
44
44
  categoryManager: {
45
45
  title: 'Mein Arbeitsbereich',
@@ -50,10 +50,10 @@ const messages = {
50
50
  empty: 'Es gibt noch keine Einträge.',
51
51
  },
52
52
  components: {
53
- pin: 'Fenster andocken.',
54
- close: 'Fenster schließen.',
53
+ pin: 'Fenster andocken',
54
+ close: 'Fenster schließen',
55
55
  vcsFormSection: {
56
- help: 'Hilfe anzeigen.',
56
+ help: 'Hilfe anzeigen',
57
57
  },
58
58
  vcsTable: {
59
59
  key: 'Name',
@@ -68,6 +68,40 @@ const messages = {
68
68
  noDataPlaceholder: 'Keine Daten verfügbar',
69
69
  noResultsPlaceholder: 'Keine übereinstimmenden Einträge gefunden',
70
70
  },
71
+ style: {
72
+ fill: 'Füll Stil',
73
+ stroke: 'Linien Stil',
74
+ reset: 'Zurücksetzen',
75
+ lineWidth: 'Linienbreite',
76
+ type: 'Typ',
77
+ points: 'Points',
78
+ radius: 'Radius',
79
+ radius2: 'Radius2',
80
+ angle: 'Winkel',
81
+ rotation: 'Rotation',
82
+ scale: 'Skalierung',
83
+ opacity: 'Deckkraft',
84
+ image: 'Punkt Stil',
85
+ icon: 'Icon',
86
+ presets: 'Vorlagen',
87
+ shape: 'Form',
88
+ circle: 'Kreis',
89
+ square: 'Quadrat',
90
+ rectangle: 'Rechteck',
91
+ triangle: 'Dreieck',
92
+ star: 'Stern',
93
+ cross: 'Kreuz',
94
+ x: 'X',
95
+ custom: 'Benutzerdefiniert',
96
+ bold: 'Fett',
97
+ italic: 'Kursiv',
98
+ text: 'Text',
99
+ enterText: 'Text hier eingeben',
100
+ allowedRange: 'Erlaubter Wertebereich',
101
+ notValid: 'Eingabe nicht gültig',
102
+ required: 'Eingabe ist erforderlich',
103
+ offset: 'Versatz',
104
+ },
71
105
  },
72
106
  settings: {
73
107
  title: 'Einstellungen',
@@ -80,8 +114,8 @@ const messages = {
80
114
  },
81
115
  },
82
116
  featureInfo: {
83
- activateToolTitle: 'Informationstool aktivieren',
84
- deactivateToolTitle: 'Informationstool deaktivieren',
117
+ activateToolTitle: 'Informationswerkzeug aktivieren',
118
+ deactivateToolTitle: 'Informationswerkzeug deaktivieren',
85
119
  },
86
120
  legend: {
87
121
  title: 'Legende',
@@ -93,10 +127,10 @@ const messages = {
93
127
  search: {
94
128
  title: 'Suche',
95
129
  tooltip: 'Suche',
96
- select: 'Suchergebnis selektieren',
97
- placeholder: 'Suche nach Straße, Adresse, Ort, POI',
130
+ select: 'Suchergebnis auswählen',
131
+ placeholder: 'Suche nach Adresse oder Ort/Sehenswürdigkeit',
98
132
  zoomToFeatureAction: 'Auf Ergebnis zoomen',
99
- zoomToAll: 'Zu allen Ergebnissen zoomen',
133
+ zoomToAll: 'Auf alle Ergebnisse zoomen',
100
134
  },
101
135
  toolbox: {
102
136
  flight: 'Flug',
@@ -105,8 +139,8 @@ const messages = {
105
139
  footer: {
106
140
  title: 'Fußzeile',
107
141
  attributions: {
108
- title: 'Attribution',
109
- tooltip: 'Öffne Attribution Fenster',
142
+ title: 'Attributionen',
143
+ tooltip: 'Öffne Attributionsfenster',
110
144
  },
111
145
  },
112
146
  notification: {
package/src/i18n/en.js CHANGED
@@ -1,15 +1,15 @@
1
1
  const messages = {
2
2
  navbar: {
3
3
  maps: {
4
- CesiumMap: 'Activate 3D map',
5
- OpenlayersMap: 'Activate 2D map',
6
- ObliqueMap: 'Activate Oblique map',
4
+ CesiumMap: 'Enable 3D view',
5
+ OpenlayersMap: 'Enable 2D view',
6
+ ObliqueMap: 'Enable oblique view',
7
7
  },
8
8
  menu: {
9
9
  tooltip: 'Menu',
10
10
  },
11
11
  share: {
12
- tooltip: 'Share current view of the map.',
12
+ tooltip: 'Share current view of the map',
13
13
  },
14
14
  },
15
15
  content: {
@@ -19,27 +19,27 @@ const messages = {
19
19
  placeholder: 'Search elements',
20
20
  },
21
21
  infoAction: {
22
- title: 'Info',
22
+ title: 'Further informationen',
23
23
  },
24
24
  viewpointAction: {
25
25
  title: 'Go to viewpoint',
26
26
  },
27
27
  styleAction: {
28
- title: 'Open Style selector',
28
+ title: 'Open style selector',
29
29
  },
30
30
  layerExtentAction: {
31
- name: 'Layer extent',
32
- title: 'Jump to layer extent',
31
+ name: 'Zoom to extent',
32
+ title: 'Zoom to layer extent',
33
33
  },
34
34
  },
35
35
  navigation: {
36
- obliqueLeftTooltip: 'Rotate view left',
37
- obliqueRightTooltip: 'Rotate view right',
36
+ obliqueLeftTooltip: 'Rotate view to left',
37
+ obliqueRightTooltip: 'Rotate view to right',
38
38
  zoomInTooltip: 'Zoom in',
39
39
  zoomOutTooltip: 'Zoom out',
40
40
  pitchTooltip: 'Camera pitch: {0}°',
41
- overviewMapTooltip: 'Overview Map',
42
- homeButton: 'Go to starting view',
41
+ overviewMapTooltip: 'Show overview map',
42
+ homeButton: 'Go to home view',
43
43
  },
44
44
  categoryManager: {
45
45
  title: 'My Workspace',
@@ -50,28 +50,62 @@ const messages = {
50
50
  empty: 'There are no entries yet.',
51
51
  },
52
52
  components: {
53
- pin: 'Pin window.',
54
- close: 'Close window.',
53
+ pin: 'Dock window',
54
+ close: 'Close window',
55
55
  vcsFormSection: {
56
- help: 'Show help.',
56
+ help: 'Show help',
57
57
  },
58
58
  vcsTable: {
59
59
  key: 'Name',
60
60
  value: 'Value',
61
61
  },
62
62
  vcsDataTable: {
63
- searchbarPlaceholder: 'Name, Value, ...',
63
+ searchbarPlaceholder: 'Name, value, ...',
64
64
  itemsPerPage: 'per page',
65
65
  ofItems: 'of',
66
66
  nextPage: 'Next page',
67
- formerPage: 'Former page',
67
+ formerPage: 'Previous page',
68
68
  noDataPlaceholder: 'No data available',
69
69
  noResultsPlaceholder: 'No matching records found',
70
70
  },
71
+ style: {
72
+ fill: 'Fill',
73
+ stroke: 'Stroke',
74
+ reset: 'Reset',
75
+ lineWidth: 'Line width',
76
+ type: 'Type',
77
+ points: 'Points',
78
+ radius: 'Radius',
79
+ radius2: 'Radius2',
80
+ angle: 'Angle',
81
+ rotation: 'Rotation',
82
+ scale: 'Scale',
83
+ opacity: 'Opacity',
84
+ image: 'Point style',
85
+ icon: 'Icon',
86
+ shape: 'Shape',
87
+ presets: 'Presets',
88
+ circle: 'Circle',
89
+ square: 'Square',
90
+ rectangle: 'Rectangle',
91
+ triangle: 'Triangle',
92
+ star: 'Star',
93
+ cross: 'Cross',
94
+ x: 'X',
95
+ custom: 'Custom',
96
+ bold: 'Bold',
97
+ italic: 'Italic',
98
+ text: 'Text',
99
+ enterText: 'Enter text here',
100
+ allowedRange: 'Allowed value range',
101
+ notValid: 'Input not valid',
102
+ required: 'Input is required',
103
+ offset: 'Offset',
104
+ },
71
105
  },
72
106
  settings: {
73
107
  title: 'Settings',
74
- tooltip: 'Settings',
108
+ tooltip: 'Configure settings',
75
109
  languageSelector: 'Language',
76
110
  theme: {
77
111
  title: 'Color theme',
@@ -80,8 +114,8 @@ const messages = {
80
114
  },
81
115
  },
82
116
  featureInfo: {
83
- activateToolTitle: 'Activate Infotool',
84
- deactivateToolTitle: 'Deactivate Infotool',
117
+ activateToolTitle: 'Enable Info Tool',
118
+ deactivateToolTitle: 'Disable Info Tool',
85
119
  },
86
120
  legend: {
87
121
  title: 'Legend',
@@ -94,7 +128,7 @@ const messages = {
94
128
  title: 'Search',
95
129
  tooltip: 'Search',
96
130
  select: 'Select result item',
97
- placeholder: 'Search for Street, Address, Landmark, POI',
131
+ placeholder: 'Search for address or landmark/point of interest',
98
132
  zoomToFeatureAction: 'Zoom to result',
99
133
  zoomToAll: 'Zoom to all',
100
134
  },
@@ -106,7 +140,7 @@ const messages = {
106
140
  title: 'Footer',
107
141
  attributions: {
108
142
  title: 'Attributions',
109
- tooltip: 'Open Attributions Window',
143
+ tooltip: 'Open attributions window',
110
144
  },
111
145
  },
112
146
  notification: {
@@ -108,13 +108,15 @@
108
108
  };
109
109
 
110
110
  /**
111
- * Sets all entry panels open
112
111
  * @type {import("vue").ComputedRef<number[]>}
113
112
  */
114
- const panels = computed(() => {
115
- return [...Array(props.entries.length).keys()].filter(
116
- (p, idx) => !!props.entries[idx].open,
117
- );
113
+ const panels = computed({
114
+ get() {
115
+ return [...Array(props.entries.length).keys()].filter(
116
+ (p, idx) => !!props.entries[idx].open,
117
+ );
118
+ },
119
+ set() {},
118
120
  });
119
121
 
120
122
  return {
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <v-expansion-panel @change="active = !active">
2
+ <v-expansion-panel>
3
3
  <v-expansion-panel-header hide-actions class="px-2">
4
4
  <template #default="{ open }">
5
5
  <div class="d-flex justify-space-between">
@@ -15,7 +15,7 @@
15
15
  </v-expansion-panel-header>
16
16
  <v-expansion-panel-content class="pb-1">
17
17
  <vcs-list
18
- :items="items.slice(0, 10)"
18
+ :items="items.slice(0, limit)"
19
19
  :draggable="draggable"
20
20
  :selectable="selectable"
21
21
  :single-select="singleSelect"
@@ -23,7 +23,7 @@
23
23
  :show-title="false"
24
24
  @item-moved="move"
25
25
  />
26
- <v-sheet v-if="items.length > 10" class="ma-2 pl-2">
26
+ <v-sheet v-if="items.length > limit" class="ma-2 pl-2">
27
27
  <VcsButton @click="openCollectionComponentList">
28
28
  {{ $t('collectionManager.more') }}
29
29
  </VcsButton>
@@ -36,7 +36,7 @@
36
36
  </template>
37
37
 
38
38
  <script>
39
- import { inject, ref } from 'vue';
39
+ import { inject } from 'vue';
40
40
  import {
41
41
  VIcon,
42
42
  VExpansionPanel,
@@ -44,13 +44,14 @@
44
44
  VExpansionPanelContent,
45
45
  VSheet,
46
46
  } from 'vuetify/lib';
47
- import { IndexedCollection } from '@vcmap/core';
48
47
  import VcsList from '../../components/lists/VcsList.vue';
49
48
  import VcsActionButtonList from '../../components/buttons/VcsActionButtonList.vue';
50
49
  import VcsButton from '../../components/buttons/VcsButton.vue';
51
50
  import { vcsAppSymbol } from '../../pluginHelper.js';
52
51
  import { WindowSlot } from '../window/windowManager.js';
53
- import CollectionComponentList from './CollectionComponentList.vue';
52
+ import CollectionComponentList, {
53
+ moveItem,
54
+ } from './CollectionComponentList.vue';
54
55
 
55
56
  /**
56
57
  * Renders the first ten items of a collectionComponent in a List. Uses CollectionComponentList to render more items.
@@ -76,7 +77,6 @@
76
77
  */
77
78
  const collectionComponent = inject('collectionComponent');
78
79
  const windowId = `${collectionComponent.id}-list`;
79
- const active = ref(false);
80
80
 
81
81
  return {
82
82
  title: collectionComponent.title,
@@ -85,19 +85,11 @@
85
85
  draggable: collectionComponent.draggable,
86
86
  selectable: collectionComponent.selectable,
87
87
  singleSelect: collectionComponent.singleSelect,
88
+ limit: collectionComponent.limit,
88
89
  actions: collectionComponent.getActions(),
89
90
  move({ item, targetIndex }) {
90
- if (collectionComponent.collection instanceof IndexedCollection) {
91
- const collectionItem = collectionComponent.collection.getByKey(
92
- item.name,
93
- );
94
- collectionComponent.collection.moveTo(
95
- collectionItem,
96
- targetIndex, // collectionItemOffset.value for paginated lists?
97
- );
98
- }
91
+ moveItem(collectionComponent, item, targetIndex);
99
92
  },
100
- active,
101
93
  openCollectionComponentList() {
102
94
  if (app.windowManager.has(windowId)) {
103
95
  setTimeout(() => {
@@ -15,6 +15,27 @@
15
15
  import { IndexedCollection } from '@vcmap/core';
16
16
  import VcsList from '../../components/lists/VcsList.vue';
17
17
 
18
+ /**
19
+ * Moves an item to a new position.
20
+ * New position is derived from a target item in the collection.
21
+ * This ensures correct movement, if rendered list is only a subset of the collection.
22
+ * @param {CollectionComponent} collectionComponent
23
+ * @param {VcsListItem} item
24
+ * @param {number} targetIndex
25
+ */
26
+ export function moveItem(collectionComponent, item, targetIndex) {
27
+ const { collection } = collectionComponent;
28
+ if (collection instanceof IndexedCollection) {
29
+ const collectionItem = collection.getByKey(item.name);
30
+ const keyProperty = collection.uniqueKey;
31
+ const targetItem = collectionComponent.items.value[targetIndex];
32
+ const targetIndexCol = [...collection].findIndex(
33
+ (i) => i[keyProperty] === targetItem[keyProperty],
34
+ );
35
+ collection.moveTo(collectionItem, targetIndexCol);
36
+ }
37
+ }
38
+
18
39
  /**
19
40
  * Renders the items of a CollectionComponent in a List.
20
41
  * The collectionComponent must be passed via {@link https://vuejs.org/api/composition-api-dependency-injection.html |provide }.
@@ -44,15 +65,7 @@
44
65
  selectable: collectionComponent.selectable,
45
66
  singleSelect: collectionComponent.singleSelect,
46
67
  move({ item, targetIndex }) {
47
- if (collectionComponent.collection instanceof IndexedCollection) {
48
- const collectionItem = collectionComponent.collection.getByKey(
49
- item.id,
50
- );
51
- collectionComponent.collection.moveTo(
52
- collectionItem,
53
- targetIndex, // collectionItemOffset.value for paginated lists?
54
- );
55
- }
68
+ moveItem(collectionComponent, item, targetIndex);
56
69
  },
57
70
  };
58
71
  },
@@ -4,6 +4,7 @@
4
4
  accordion
5
5
  multiple
6
6
  v-if="componentIds.length > 0"
7
+ v-model="panels"
7
8
  class="rounded-0"
8
9
  >
9
10
  <collection-component-provider
@@ -16,7 +17,7 @@
16
17
  </template>
17
18
 
18
19
  <script>
19
- import { inject, ref } from 'vue';
20
+ import { computed, inject, ref } from 'vue';
20
21
  import { VExpansionPanels, VContainer } from 'vuetify/lib';
21
22
  import CollectionComponentProvider from './CollectionComponentProvider.vue';
22
23
 
@@ -35,8 +36,26 @@
35
36
  const collectionManager = inject('collectionManager');
36
37
  const componentIds = ref(collectionManager.componentIds);
37
38
 
39
+ /**
40
+ * @type {WritableComputedRef<number[]>}
41
+ */
42
+ const panels = computed({
43
+ get() {
44
+ return [...Array(componentIds.value.length).keys()].filter(
45
+ (p, idx) =>
46
+ !!collectionManager.get(componentIds.value[idx]).open.value,
47
+ );
48
+ },
49
+ set(value) {
50
+ componentIds.value.forEach((id, idx) => {
51
+ collectionManager.get(id).open.value = value.includes(idx);
52
+ });
53
+ },
54
+ });
55
+
38
56
  return {
39
57
  componentIds,
58
+ panels,
40
59
  };
41
60
  },
42
61
  };
@@ -2,6 +2,7 @@ import { IndexedCollection, isOverrideCollection } from '@vcmap/core';
2
2
  import { getLogger } from '@vcsuite/logger';
3
3
  import { v4 as uuidv4 } from 'uuid';
4
4
  import { computed, ref } from 'vue';
5
+ import { parseNumber } from '@vcsuite/parsers';
5
6
  import { validateAction } from '../../components/lists/VcsActionList.vue';
6
7
  import { sortByWeight } from '../buttonManager.js';
7
8
 
@@ -12,6 +13,7 @@ import { sortByWeight } from '../buttonManager.js';
12
13
  * @property {boolean} [draggable] - only supported for IndexedCollections
13
14
  * @property {boolean} [selectable]
14
15
  * @property {boolean} [singleSelect]
16
+ * @property {number} [limit=10] - limit number of items in rendered list (more items are rendered in extra window)
15
17
  */
16
18
 
17
19
  /**
@@ -53,6 +55,15 @@ class CollectionComponent {
53
55
  * @type {import("vue").Ref<string>}
54
56
  */
55
57
  this.title = ref(options.title);
58
+ /**
59
+ * @type {import("vue").Ref<boolean>}
60
+ */
61
+ this.open = ref(false);
62
+ /**
63
+ *
64
+ * @type {import("vue").Ref<number>}
65
+ */
66
+ this.limit = ref(parseNumber(options.limit, 10));
56
67
  /**
57
68
  * @type {import("vue").Ref<boolean>}
58
69
  * @private
@@ -91,7 +91,8 @@
91
91
  const isDockedLeft = computed(() => {
92
92
  return (
93
93
  props.slotWindow === WindowSlot.STATIC ||
94
- props.slotWindow === WindowSlot.DYNAMIC_LEFT
94
+ props.slotWindow === WindowSlot.DYNAMIC_LEFT ||
95
+ props.slotWindow === WindowSlot.DYNAMIC_CHILD
95
96
  );
96
97
  });
97
98
  const isDockedRight = computed(
@@ -60,7 +60,7 @@
60
60
  import WindowComponent from './WindowComponent.vue';
61
61
  import WindowComponentHeader from './WindowComponentHeader.vue';
62
62
  import {
63
- applyPositionOnTarget,
63
+ getPositionAppliedOnTarget,
64
64
  getTargetSize,
65
65
  moveWindow,
66
66
  } from './windowHelper.js';
@@ -98,6 +98,23 @@
98
98
  const isOnTop = (id) => {
99
99
  return windowManager.get(id)?.zIndex.value === componentIds.length - 1;
100
100
  };
101
+ /**
102
+ * @param {WindowComponent} windowComponent
103
+ * @returns {WindowPosition|null}
104
+ */
105
+ const getPosition = (windowComponent) => {
106
+ if (!windowComponent) {
107
+ return null;
108
+ }
109
+ const parentComponent =
110
+ !windowComponent?.state?.dockable &&
111
+ windowManager.get(windowComponent.parentId);
112
+ return getPositionAppliedOnTarget(
113
+ windowComponent?.position,
114
+ targetSize.value,
115
+ getPosition(parentComponent),
116
+ );
117
+ };
101
118
  /**
102
119
  * @param {string} id
103
120
  * @returns {import("vue").ComputedRef<Object>}
@@ -105,15 +122,10 @@
105
122
  const getStyles = (id) =>
106
123
  computed(() => {
107
124
  const windowComponent = windowManager.get(id);
108
- const state = windowComponent?.state;
109
- const position = applyPositionOnTarget(
110
- windowComponent?.position,
111
- targetSize.value,
112
- );
113
125
  return {
114
126
  zIndex: windowComponent.zIndex.value,
115
- ...position,
116
- ...(state.styles || {}),
127
+ ...getPosition(windowComponent),
128
+ ...(windowComponent?.state?.styles || {}),
117
129
  };
118
130
  });
119
131
  /**
@@ -129,7 +141,9 @@
129
141
  * @param {{dx: number, dy: number}} translation
130
142
  */
131
143
  const move = (id, translation) => {
132
- moveWindow(id, translation, windowManager, targetSize.value);
144
+ const windowComponent = windowManager.get(id);
145
+ const position = getPosition(windowComponent);
146
+ moveWindow(id, translation, windowManager, targetSize.value, position);
133
147
  };
134
148
 
135
149
  const componentIdRef = ref(componentIds);
@@ -263,13 +263,23 @@ export function updateWindowPosition(previous, update, targetSize) {
263
263
  * @param {{dx: number, dy: number}} translation - translation in px
264
264
  * @param {WindowManager} windowManager
265
265
  * @param {DOMRect} targetSize - the map's target size
266
+ * @param {WindowPosition|null} windowPosition - Optional position to be preferred over windowComponent's position as start.
266
267
  */
267
- export function moveWindow(id, translation, windowManager, targetSize) {
268
+ export function moveWindow(
269
+ id,
270
+ translation,
271
+ windowManager,
272
+ targetSize,
273
+ windowPosition = null,
274
+ ) {
268
275
  const { position, slot } = windowManager.get(id);
269
276
  if (slot.value === WindowSlot.STATIC) {
270
277
  return;
271
278
  }
272
- const windowPositionOptions = optionsFromWindowPosition(position, targetSize);
279
+ const windowPositionOptions = optionsFromWindowPosition(
280
+ windowPosition || position,
281
+ targetSize,
282
+ );
273
283
  if (windowPositionOptions.top !== undefined) {
274
284
  windowPositionOptions.top += translation.dy;
275
285
  }
@@ -373,16 +383,78 @@ export function clipToTargetSize(windowPositionOptions, targetSize) {
373
383
  }
374
384
 
375
385
  /**
376
- * Applies the position on the target clipping the position to the target's size.
386
+ * Derives a child window position from a parent window, placing the child top-right of the parent.
387
+ * @param {WindowPositionOptions} windowPositionOptions - numerical WindowPositionOptions
388
+ * @param {DOMRect} targetSize - the map's target size
389
+ * @param {WindowPositionOptions} parentPosition - numerical WindowPositionOptions
390
+ */
391
+ export function applyParentPosition(
392
+ windowPositionOptions,
393
+ targetSize,
394
+ parentPosition,
395
+ ) {
396
+ const {
397
+ left,
398
+ right,
399
+ top,
400
+ bottom,
401
+ width,
402
+ height,
403
+ minWidth,
404
+ minHeight,
405
+ maxWidth,
406
+ maxHeight,
407
+ } = optionsFromWindowPosition(parentPosition, targetSize);
408
+ let parentWidth = width;
409
+ if (minWidth !== undefined && minWidth > width) {
410
+ parentWidth = minWidth;
411
+ }
412
+ if (maxWidth !== undefined && maxWidth < width) {
413
+ parentWidth = maxWidth;
414
+ }
415
+ if (parentWidth === undefined) {
416
+ parentWidth = targetSize.width - right - left;
417
+ }
418
+ let parentLeft = left;
419
+ if (parentLeft === undefined) {
420
+ parentLeft = targetSize.width - right - parentWidth;
421
+ }
422
+ let parentTop = top;
423
+ if (parentTop === undefined) {
424
+ let parentHeight = height;
425
+ if (minHeight !== undefined && minHeight > height) {
426
+ parentHeight = minHeight;
427
+ }
428
+ if (maxHeight !== undefined && maxHeight < height) {
429
+ parentHeight = maxHeight;
430
+ }
431
+ parentTop = targetSize.height - bottom - parentHeight;
432
+ }
433
+ windowPositionOptions.left = parentLeft + parentWidth + 2;
434
+ windowPositionOptions.top = parentTop;
435
+ }
436
+
437
+ /**
438
+ * Returns the position applied on the target by clipping the position to the target's size.
439
+ * Maintains units of the input position.
440
+ * If parent position is provided, returned position is placed top-right of its parent
377
441
  * @param {WindowPosition} position
378
442
  * @param {DOMRect} targetSize
443
+ * @param {WindowPosition|null} parentPosition
379
444
  * @returns {WindowPosition}
380
445
  */
381
- export function applyPositionOnTarget(position, targetSize) {
446
+ export function getPositionAppliedOnTarget(
447
+ position,
448
+ targetSize,
449
+ parentPosition,
450
+ ) {
382
451
  if (!targetSize) {
383
452
  return position;
384
453
  }
385
454
  const windowPositionOptions = optionsFromWindowPosition(position, targetSize);
455
+ if (parentPosition) {
456
+ applyParentPosition(windowPositionOptions, targetSize, parentPosition);
457
+ }
386
458
  const clippedPosition = clipToTargetSize(windowPositionOptions, targetSize);
387
459
  const updatedPosition = updateWindowPosition(
388
460
  position,