@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.
- package/README.md +12 -5
- package/build/build.js +6 -3
- package/build/buildHelpers.js +12 -4
- package/build/buildPreview.js +7 -0
- package/build/getPluginProxies.js +4 -0
- package/config/aerowest.config.json +13 -3
- package/config/base.config.json +398 -219
- package/config/codes.config.json +397 -0
- package/config/dev.config.json +375 -1
- package/config/graphFeatureInfo.config.json +100 -0
- package/config/www.config.json +1232 -0
- package/dist/assets/{cesium.eb5667.js → cesium.21663e.js} +0 -0
- package/dist/assets/cesium.js +1 -1
- package/dist/assets/core.63242d.js +4 -0
- package/dist/assets/core.js +1 -1
- package/dist/assets/font/OFL.txt +93 -0
- package/dist/assets/font/TitilliumWeb-Regular.woff2 +0 -0
- package/dist/assets/{index.4ccd4433.js → index.44b91cfe.js} +1 -1
- package/dist/assets/{ol.ef03b1.js → ol.88ba9d.js} +0 -0
- package/dist/assets/ol.js +1 -1
- package/dist/assets/ui.3c2933.css +1 -0
- package/dist/assets/ui.3c2933.js +71 -0
- package/dist/assets/ui.js +1 -1
- package/dist/assets/vue.c897fc.js +9 -0
- package/dist/assets/vue.js +2 -1
- package/dist/assets/{vuetify.401a29.css → vuetify.147c3a.css} +1 -1
- package/dist/assets/{vuetify.401a29.js → vuetify.147c3a.js} +72 -72
- package/dist/assets/vuetify.js +2 -2
- package/dist/index.html +1 -5
- package/index.js +39 -5
- package/lib/vue.js +1 -0
- package/map.config.json +15 -6
- package/package.json +17 -8
- package/plugins/@vcmap/create-link/fallbackCreateLink.vue +71 -0
- package/plugins/@vcmap/create-link/index.js +83 -0
- package/plugins/@vcmap/create-link/package.json +6 -0
- package/plugins/@vcmap/pluginExample/index.js +2 -2
- package/plugins/@vcmap/pluginExample/pluginExampleComponent.vue +20 -3
- package/plugins/@vcmap/project-selector/ProjectSelectorComponent.vue +1 -1
- package/plugins/@vcmap/project-selector/index.js +1 -1
- package/plugins/@vcmap/project-selector/package.json +1 -2
- package/plugins/@vcmap/theme-changer/ThemeChangerComponent.vue +1 -1
- package/plugins/@vcmap/theme-changer/index.js +1 -1
- package/plugins/@vcmap/theme-changer/package.json +1 -2
- package/plugins/categoryTest/Categories.vue +89 -1
- package/plugins/categoryTest/Category.vue +1 -1
- package/plugins/example/index.js +10 -23
- package/plugins/simple-graph/README.md +51 -0
- package/plugins/simple-graph/SimpleGraphComponent.vue +70 -0
- package/plugins/simple-graph/index.js +17 -0
- package/plugins/simple-graph/package.json +11 -0
- package/plugins/simple-graph/simpleGraphView.js +76 -0
- package/plugins/test/editor.vue +1 -1
- package/plugins/test/index.js +76 -9
- package/plugins/test/toolbox-data.js +82 -57
- package/plugins/test/windowManagerExample.vue +1 -1
- package/src/actions/stateRefAction.js +2 -2
- package/src/actions/styleSelector.vue +1 -1
- package/src/application/Navbar.vue +13 -2
- package/src/application/VcsApp.vue +301 -116
- package/src/application/VcsMap.vue +1 -1
- package/src/application/VcsSettings.vue +1 -1
- package/src/application/vcsAppWrapper.vue +1 -0
- package/src/assets/font/OFL.txt +93 -0
- package/src/assets/font/TitilliumWeb-Regular.woff2 +0 -0
- package/src/components/form-inputs-controls/VcsCheckbox.vue +13 -0
- package/src/components/form-inputs-controls/VcsColorPicker.vue +1 -1
- package/src/components/form-inputs-controls/VcsRadio.vue +123 -0
- package/src/components/form-output/VcsFormattedNumber.vue +1 -1
- package/src/components/lists/VcsActionList.vue +22 -7
- package/src/components/lists/VcsTreeview.vue +4 -4
- package/src/components/lists/VcsTreeviewLeaf.vue +10 -3
- package/src/components/lists/VcsTreeviewSearchbar.vue +1 -2
- package/src/components/tables/VcsTable.vue +245 -0
- package/src/contentTree/LayerTree.vue +1 -1
- package/src/contentTree/contentTreeCollection.js +4 -4
- package/src/contentTree/contentTreeItem.js +9 -9
- package/src/contentTree/groupContentTreeItem.js +1 -1
- package/src/contentTree/layerContentTreeItem.js +15 -1
- package/src/contentTree/layerGroupContentTreeItem.js +21 -1
- package/src/contentTree/nodeContentTreeItem.js +1 -1
- package/src/featureInfo/AddressBalloonComponent.vue +47 -0
- package/src/featureInfo/BalloonComponent.vue +140 -0
- package/src/featureInfo/abstractFeatureInfoView.js +313 -0
- package/src/featureInfo/addressBalloonFeatureInfoView.js +118 -0
- package/src/featureInfo/balloonFeatureInfoView.js +151 -0
- package/src/featureInfo/balloonHelper.js +132 -0
- package/src/featureInfo/featureInfo.js +457 -0
- package/src/featureInfo/featureInfoInteraction.js +42 -0
- package/src/featureInfo/iframeFeatureInfoView.js +95 -0
- package/src/featureInfo/tableFeatureInfoView.js +106 -0
- package/src/i18n/de.js +26 -0
- package/src/i18n/en.js +26 -0
- package/src/i18n/i18nCollection.js +17 -0
- package/src/icons/+all.js +80 -0
- package/src/icons/ClippingHorizontalIcon.vue +7 -0
- package/src/icons/ClippingIcon.vue +7 -0
- package/src/icons/ClippingVerticalIcon.vue +7 -0
- package/src/icons/ColorPickerIcon.vue +7 -0
- package/src/icons/ComponentsIcon.vue +2 -2
- package/src/icons/DimensionsHouseIcon.vue +11 -9
- package/src/icons/EditIcon.vue +7 -0
- package/src/icons/GlobalTerrainIcon.vue +9 -0
- package/src/icons/GroundIcon.vue +18 -0
- package/src/icons/HideIcon.vue +12 -0
- package/src/icons/LogoutIcon.vue +7 -0
- package/src/icons/ObjectAttributeIcon.vue +2 -13
- package/src/icons/PedestrianIcon.vue +2 -3
- package/src/icons/PenIcon.vue +2 -9
- package/src/icons/PoiIcon.vue +5 -2
- package/src/icons/PointSelectIcon.vue +4 -2
- package/src/icons/QueryIcon.vue +6 -7
- package/src/icons/ScreenshotIcon.vue +16 -0
- package/src/icons/ShareIcon.vue +4 -16
- package/src/icons/SkipNextIcon.vue +3 -1
- package/src/icons/TerrainBoxIcon.vue +9 -0
- package/src/icons/ToolsIcon.vue +4 -30
- package/src/icons/UploadIcon.vue +2 -9
- package/src/icons/UserProfileIcon.vue +7 -0
- package/src/icons/UserShareIcon.vue +7 -0
- package/src/icons/VideoRecorderIcon.vue +5 -9
- package/src/icons/ViewpointFlightIcon.vue +11 -0
- package/src/icons/ViewpointIcon.vue +11 -0
- package/src/icons/Viewshed360Icon.vue +7 -0
- package/src/icons/ViewshedConeIcon.vue +7 -0
- package/src/icons/ViewshedIcon.vue +7 -0
- package/src/icons/WallIcon.vue +4 -9
- package/src/legend/legendHelper.js +193 -0
- package/src/legend/styleLegendItem.vue +129 -0
- package/src/legend/vcsLegend.vue +92 -0
- package/src/manager/buttonManager.js +7 -12
- package/src/manager/categoryManager/ComponentsManager.vue +30 -0
- package/src/manager/categoryManager/categoryManager.js +500 -0
- package/src/manager/contextMenu/contextMenuComponent.vue +43 -0
- package/src/manager/contextMenu/contextMenuInteraction.js +42 -0
- package/src/manager/contextMenu/contextMenuManager.js +197 -0
- package/src/manager/navbarManager.js +9 -9
- package/src/manager/toolbox/GroupToolboxComponent.vue +118 -0
- package/src/manager/toolbox/SelectToolboxComponent.vue +128 -0
- package/src/manager/toolbox/ToolboxManager.vue +116 -98
- package/src/manager/toolbox/toolboxManager.js +235 -86
- package/src/manager/window/WindowComponent.vue +1 -1
- package/src/manager/window/WindowManager.vue +5 -3
- package/src/manager/window/windowManager.js +118 -14
- package/src/navigation/mapNavigation.vue +3 -5
- package/src/navigation/overviewMap.js +28 -5
- package/src/navigation/vcsCompass.vue +1 -1
- package/src/pluginHelper.js +42 -10
- package/src/setup.js +0 -2
- package/src/state.js +256 -0
- package/src/styles/_theming.scss +0 -5
- package/src/styles/variables.scss +7 -0
- package/src/styles/vcsFont.scss +17 -0
- package/src/uiConfig.js +79 -0
- package/src/vcsUiApp.js +213 -22
- package/src/vuePlugins/vuetify.js +14 -4
- package/config/berlin.config.json +0 -510
- package/dist/assets/core.216494.js +0 -4
- package/dist/assets/ui.99a1a7.css +0 -1
- package/dist/assets/ui.99a1a7.js +0 -70
- package/dist/assets/vue-composition-api.c5aca1.js +0 -14
- package/dist/assets/vue-composition-api.js +0 -2
- package/dist/assets/vue.762edd.js +0 -9
- package/lib/vue-composition-api.js +0 -2
- package/src/manager/toolbox/ToolboxGroupComponent.vue +0 -128
@@ -1,9 +1,9 @@
|
|
1
|
-
|
2
|
-
import { reactive } from '@vue/composition-api';
|
1
|
+
import { reactive } from 'vue';
|
3
2
|
import { VcsEvent } from '@vcmap/core';
|
4
3
|
import { v4 as uuidv4 } from 'uuid';
|
5
4
|
import { check, checkMaybe } from '@vcsuite/check';
|
6
5
|
import { vcsAppSymbol } from '../pluginHelper.js';
|
6
|
+
import { ActionPattern } from '../components/lists/VcsActionList.vue';
|
7
7
|
|
8
8
|
/**
|
9
9
|
* @typedef ButtonComponentOptions
|
@@ -23,7 +23,7 @@ import { vcsAppSymbol } from '../pluginHelper.js';
|
|
23
23
|
* @description Manages a set of Map Buttons
|
24
24
|
* @implements VcsComponentManager<ButtonComponent,ButtonComponentOptions>
|
25
25
|
*/
|
26
|
-
|
26
|
+
class ButtonManager {
|
27
27
|
constructor() {
|
28
28
|
/**
|
29
29
|
* @type {import("@vcmap/core").VcsEvent<ButtonComponent>}
|
@@ -37,8 +37,7 @@ export class ButtonManager {
|
|
37
37
|
* reactive ordered array of ids,
|
38
38
|
* @type {Array<string>}
|
39
39
|
*/
|
40
|
-
this.componentIds =
|
41
|
-
|
40
|
+
this.componentIds = [];
|
42
41
|
/**
|
43
42
|
* @type {Map<string, ButtonComponent>}
|
44
43
|
* @private
|
@@ -88,13 +87,7 @@ export class ButtonManager {
|
|
88
87
|
*/
|
89
88
|
add(buttonComponentOptions, owner) {
|
90
89
|
checkMaybe(buttonComponentOptions.id, String);
|
91
|
-
check(buttonComponentOptions.action,
|
92
|
-
name: String,
|
93
|
-
title: [undefined, String],
|
94
|
-
icon: [undefined, String],
|
95
|
-
callback: Function,
|
96
|
-
active: [undefined, Boolean],
|
97
|
-
});
|
90
|
+
check(buttonComponentOptions.action, ActionPattern);
|
98
91
|
check(owner, [String, vcsAppSymbol]);
|
99
92
|
|
100
93
|
if (buttonComponentOptions.id && this.has(buttonComponentOptions.id)) {
|
@@ -154,3 +147,5 @@ export class ButtonManager {
|
|
154
147
|
this._buttonComponents.clear();
|
155
148
|
}
|
156
149
|
}
|
150
|
+
|
151
|
+
export default ButtonManager;
|
@@ -0,0 +1,30 @@
|
|
1
|
+
<template>
|
2
|
+
<div>
|
3
|
+
<VcsTreeview
|
4
|
+
v-if="tree && tree.length"
|
5
|
+
:items="tree"
|
6
|
+
:has-searchbar="true"
|
7
|
+
/>
|
8
|
+
</div>
|
9
|
+
</template>
|
10
|
+
|
11
|
+
<script>
|
12
|
+
import { inject } from 'vue';
|
13
|
+
import VcsTreeview from '../../components/lists/VcsTreeview.vue';
|
14
|
+
|
15
|
+
/**
|
16
|
+
* @description
|
17
|
+
* uses a VcsTreeview and shows 'a components Window' based on the "categoryManager"
|
18
|
+
* Uses the provided 'vcsApp'
|
19
|
+
*/
|
20
|
+
export default {
|
21
|
+
name: 'VcsComponentsManager',
|
22
|
+
components: { VcsTreeview },
|
23
|
+
setup() {
|
24
|
+
const app = inject('vcsApp');
|
25
|
+
return {
|
26
|
+
tree: app.categoryManager.items,
|
27
|
+
};
|
28
|
+
},
|
29
|
+
};
|
30
|
+
</script>
|
@@ -0,0 +1,500 @@
|
|
1
|
+
import { ref } from 'vue';
|
2
|
+
import { contextIdSymbol, IndexedCollection } from '@vcmap/core';
|
3
|
+
import { check } from '@vcsuite/check';
|
4
|
+
import { sortByOwner } from '../navbarManager.js';
|
5
|
+
import { validateAction, validateActions } from '../../components/lists/VcsActionList.vue';
|
6
|
+
|
7
|
+
/**
|
8
|
+
* @callback MappingFunction
|
9
|
+
* @param {T} item
|
10
|
+
* @param {import("@vcmap/core").Category<T>} category
|
11
|
+
* @param {import("@vcmap/ui").TreeViewItem} treeViewItem
|
12
|
+
* @template {Object} T
|
13
|
+
*/
|
14
|
+
|
15
|
+
/**
|
16
|
+
* @callback PredicateFunction
|
17
|
+
* @param {T} item
|
18
|
+
* @param {import("@vcmap/core").Category<T>} category
|
19
|
+
* @returns {boolean}
|
20
|
+
* @template {Object} T
|
21
|
+
*/
|
22
|
+
|
23
|
+
/**
|
24
|
+
* @typedef {Object} ItemMapping
|
25
|
+
* @property {MappingFunction<T>} mappingFunction
|
26
|
+
* @property {PredicateFunction<T>} predicate
|
27
|
+
* @property {Array<string>} categoryNames
|
28
|
+
* @property {string | symbol} owner
|
29
|
+
* @template T
|
30
|
+
*/
|
31
|
+
|
32
|
+
/**
|
33
|
+
* uses the itemMappings to transform the given Item to an TreeViewItem usable in the VCSTreeView
|
34
|
+
* @param {T} item
|
35
|
+
* @param {import("@vcmap/core").Category<T>} category
|
36
|
+
* @param {Array<ItemMapping<T>>} itemMappings
|
37
|
+
* @returns {import("@vcmap/ui").TreeViewItem}
|
38
|
+
* @template T
|
39
|
+
* @private
|
40
|
+
*/
|
41
|
+
function transformItem(item, category, itemMappings) {
|
42
|
+
const keyProperty = category.collection.uniqueKey;
|
43
|
+
const treeViewItem = {
|
44
|
+
get id() { return item[keyProperty]; },
|
45
|
+
title: item?.properties?.title || item[keyProperty],
|
46
|
+
actions: [],
|
47
|
+
children: [],
|
48
|
+
};
|
49
|
+
itemMappings.forEach((itemMapping) => {
|
50
|
+
if (itemMapping.predicate(item, category)) {
|
51
|
+
itemMapping.mappingFunction(item, category, treeViewItem);
|
52
|
+
}
|
53
|
+
});
|
54
|
+
treeViewItem.actions = treeViewItem.actions.filter((action) => {
|
55
|
+
return validateAction(action);
|
56
|
+
});
|
57
|
+
return treeViewItem;
|
58
|
+
}
|
59
|
+
|
60
|
+
/**
|
61
|
+
* Inserts the item into the children array at the correct relative position in respect to the position of the item
|
62
|
+
* in the collection
|
63
|
+
* @param {import("@vcmap/ui").TreeViewItem} item
|
64
|
+
* @param {import("@vcmap/core").Collection} collection
|
65
|
+
* @param {Array<import("@vcmap/ui").TreeViewItem>} children
|
66
|
+
* @private
|
67
|
+
*/
|
68
|
+
function insertItem(item, collection, children) {
|
69
|
+
if (collection instanceof IndexedCollection) {
|
70
|
+
const newItemIndex = collection.indexOfKey(item.id);
|
71
|
+
if (newItemIndex === collection.size - 1) {
|
72
|
+
children.push(item);
|
73
|
+
} else {
|
74
|
+
const positionInChildren = children.findIndex((treeViewItem) => {
|
75
|
+
const treeViewItemIndex = collection.indexOfKey(treeViewItem.id);
|
76
|
+
return newItemIndex < treeViewItemIndex;
|
77
|
+
});
|
78
|
+
if (positionInChildren >= 0) {
|
79
|
+
children.splice(positionInChildren, 0, item);
|
80
|
+
}
|
81
|
+
}
|
82
|
+
} else {
|
83
|
+
children.push(item);
|
84
|
+
}
|
85
|
+
}
|
86
|
+
|
87
|
+
/**
|
88
|
+
* a categoryManager manages categories, and synchronizes a tree of VcsTreeView Items.
|
89
|
+
* provides an API to add/remove Categories.
|
90
|
+
*/
|
91
|
+
export default class CategoryManager {
|
92
|
+
/**
|
93
|
+
* @param {import("@vcmap/ui").VcsUiApp} app
|
94
|
+
*/
|
95
|
+
constructor(app) {
|
96
|
+
/**
|
97
|
+
* @type {import("@vcmap/ui").VcsUiApp}
|
98
|
+
* @private
|
99
|
+
*/
|
100
|
+
this._app = app;
|
101
|
+
|
102
|
+
/**
|
103
|
+
* @type {Map<string, Map<string|symbol, Array<import("@vcmap/ui").VcsAction>>>}
|
104
|
+
* @private
|
105
|
+
*/
|
106
|
+
this._managedCategories = new Map();
|
107
|
+
|
108
|
+
/**
|
109
|
+
* @type {Map<string, Array<function():void>>}
|
110
|
+
* @private
|
111
|
+
*/
|
112
|
+
this._managedCategoriesListeners = new Map();
|
113
|
+
|
114
|
+
/**
|
115
|
+
* @type {function():void}
|
116
|
+
* @private
|
117
|
+
*/
|
118
|
+
this._dynamicContextIdListener = this._app.dynamicContextIdChanged.addEventListener((id) => {
|
119
|
+
this._dynamicContextId = id;
|
120
|
+
this._resetItems();
|
121
|
+
});
|
122
|
+
|
123
|
+
/**
|
124
|
+
* @type {function():void}
|
125
|
+
* @private
|
126
|
+
*/
|
127
|
+
this._appCategoriesRemovedListener = this._app.categories.removed.addEventListener((category) => {
|
128
|
+
this._removeCategory(category.name);
|
129
|
+
});
|
130
|
+
|
131
|
+
/**
|
132
|
+
* @type {string}
|
133
|
+
* @private
|
134
|
+
*/
|
135
|
+
this._dynamicContextId = this._app.dynamicContextId;
|
136
|
+
|
137
|
+
/**
|
138
|
+
* @type {Array<ItemMapping<*>>}
|
139
|
+
* @private
|
140
|
+
*/
|
141
|
+
this._itemMappings = [];
|
142
|
+
|
143
|
+
/**
|
144
|
+
* @type {import("vue").Ref<Array<import("@vcmap/ui").TreeViewItem>>}
|
145
|
+
* @private
|
146
|
+
*/
|
147
|
+
this._items = ref([]);
|
148
|
+
}
|
149
|
+
|
150
|
+
/**
|
151
|
+
* synchronizes the category items with the internal items list.
|
152
|
+
* @param {T} item
|
153
|
+
* @param {import("@vcmap/core").Category<T>} category
|
154
|
+
* @template T
|
155
|
+
* @private
|
156
|
+
*/
|
157
|
+
_handleItemAdded(item, category) {
|
158
|
+
const itemMappings = this._itemMappings.filter((itemMapping) => {
|
159
|
+
return itemMapping.categoryNames.includes(category.name);
|
160
|
+
});
|
161
|
+
const finishedUiItem = transformItem(item, category, itemMappings);
|
162
|
+
const categoryItem = this.items.value.find((elem) => { return elem.id === category.name; });
|
163
|
+
if (categoryItem) {
|
164
|
+
insertItem(finishedUiItem, category.collection, categoryItem.children);
|
165
|
+
/* if (category.collection instanceof IndexedCollection) {
|
166
|
+
const newItemIndex = category.collection.indexOf(item);
|
167
|
+
let indexToInsert = 0;
|
168
|
+
// eslint-disable-next-line for-direction
|
169
|
+
for (let index = categoryItem.children.length - 1; index >= 0; index--) {
|
170
|
+
const treeViewItem = categoryItem.children[index];
|
171
|
+
const treeViewItemIndex = category.collection.indexOfKey(treeViewItem.id);
|
172
|
+
if (treeViewItemIndex < newItemIndex) {
|
173
|
+
// should be added directly after this item
|
174
|
+
indexToInsert = index + 1;
|
175
|
+
break;
|
176
|
+
}
|
177
|
+
}
|
178
|
+
categoryItem.children.splice(indexToInsert, 0, finishedUiItem);
|
179
|
+
} else {
|
180
|
+
categoryItem.children.push(finishedUiItem);
|
181
|
+
} */
|
182
|
+
}
|
183
|
+
}
|
184
|
+
|
185
|
+
/**
|
186
|
+
* synchronizes the order of the treeViewItems with respect to the order of the items in the collection.
|
187
|
+
* removes and reinserts the moved item.
|
188
|
+
* @param {T} item
|
189
|
+
* @param {import("@vcmap/core").Category<T>} category
|
190
|
+
* @template T
|
191
|
+
* @private
|
192
|
+
*/
|
193
|
+
_handleItemMoved(item, category) {
|
194
|
+
const categoryItem = this.items.value.find((elem) => { return elem.id === category.name; });
|
195
|
+
if (categoryItem) {
|
196
|
+
const index = categoryItem.children.findIndex((elem) => { return elem.id === item.name; });
|
197
|
+
if (index > -1) {
|
198
|
+
const treeViewItem = categoryItem.children[index];
|
199
|
+
categoryItem.children.splice(index, 1);
|
200
|
+
insertItem(treeViewItem, category.collection, categoryItem.children);
|
201
|
+
}
|
202
|
+
}
|
203
|
+
}
|
204
|
+
|
205
|
+
/**
|
206
|
+
* synchronizes the category items with the internal items list.
|
207
|
+
* @param {T} item
|
208
|
+
* @param {import("@vcmap/core").Category<T>} category
|
209
|
+
* @template T
|
210
|
+
* @private
|
211
|
+
*/
|
212
|
+
_handleItemRemoved(item, category) {
|
213
|
+
const categoryItem = this.items.value.find((elem) => { return elem.id === category.name; });
|
214
|
+
if (categoryItem) {
|
215
|
+
const index = categoryItem.children.findIndex((elem) => { return elem.id === item.name; });
|
216
|
+
if (index > -1) {
|
217
|
+
categoryItem.children.splice(index, 1);
|
218
|
+
}
|
219
|
+
}
|
220
|
+
}
|
221
|
+
|
222
|
+
/**
|
223
|
+
* removes all Items and rebuilds the item tree depending on the ContextId
|
224
|
+
* @private
|
225
|
+
*/
|
226
|
+
_resetItems() {
|
227
|
+
this.items.value.splice(0);
|
228
|
+
this._managedCategories.forEach((value, categoryName) => {
|
229
|
+
this._resetCategory(categoryName);
|
230
|
+
});
|
231
|
+
}
|
232
|
+
|
233
|
+
/**
|
234
|
+
* resets the category, removes the currently managed state and rebuilds the categoryItem and all children
|
235
|
+
* @param {string} categoryName
|
236
|
+
* @private
|
237
|
+
*/
|
238
|
+
_resetCategory(categoryName) {
|
239
|
+
const category = this._app.categories.getByKey(categoryName);
|
240
|
+
if (!category) {
|
241
|
+
throw new Error(`Could not find Category: ${categoryName}`);
|
242
|
+
}
|
243
|
+
// cleanup existing listeners
|
244
|
+
if (this._managedCategoriesListeners.has(categoryName)) {
|
245
|
+
this._managedCategoriesListeners.get(categoryName).forEach((listener) => {
|
246
|
+
listener();
|
247
|
+
});
|
248
|
+
this._managedCategoriesListeners.delete(categoryName);
|
249
|
+
}
|
250
|
+
|
251
|
+
const categoryItemIndex = this._items.value.findIndex((item) => {
|
252
|
+
return item.id === category.name;
|
253
|
+
});
|
254
|
+
const actions = [...this._managedCategories.get(category.name).values()].flatMap(ownerActions => ownerActions);
|
255
|
+
|
256
|
+
const itemMappings = this._itemMappings.filter((itemMapping) => {
|
257
|
+
return itemMapping.categoryNames.includes(category.name);
|
258
|
+
});
|
259
|
+
const children = [...category.collection]
|
260
|
+
.filter((item) => {
|
261
|
+
return item[contextIdSymbol] === this._dynamicContextId;
|
262
|
+
})
|
263
|
+
.map((item) => {
|
264
|
+
return transformItem(item, category, itemMappings);
|
265
|
+
});
|
266
|
+
|
267
|
+
|
268
|
+
const categoryItem = {
|
269
|
+
id: category.name,
|
270
|
+
title: category.title,
|
271
|
+
children,
|
272
|
+
actions,
|
273
|
+
};
|
274
|
+
if (categoryItemIndex >= 0) {
|
275
|
+
this._items.value.splice(categoryItemIndex, 1, categoryItem);
|
276
|
+
} else {
|
277
|
+
this._items.value.push(categoryItem);
|
278
|
+
}
|
279
|
+
|
280
|
+
const listeners = [
|
281
|
+
category.collection.added.addEventListener((item) => {
|
282
|
+
if (item[contextIdSymbol] === this._dynamicContextId) {
|
283
|
+
this._handleItemAdded(item, category);
|
284
|
+
}
|
285
|
+
}),
|
286
|
+
category.collection.removed.addEventListener((item) => {
|
287
|
+
if (item[contextIdSymbol] === this._dynamicContextId) {
|
288
|
+
this._handleItemRemoved(item, category);
|
289
|
+
}
|
290
|
+
}),
|
291
|
+
category.collection.replaced.addEventListener((replacedEvent) => {
|
292
|
+
if (replacedEvent.old[contextIdSymbol] === this._dynamicContextId) {
|
293
|
+
this._handleItemRemoved(replacedEvent.old, category);
|
294
|
+
}
|
295
|
+
}),
|
296
|
+
];
|
297
|
+
|
298
|
+
if (category.collection instanceof IndexedCollection) {
|
299
|
+
listeners.push(category.collection.moved.addEventListener((item) => {
|
300
|
+
if (item[contextIdSymbol] === this._dynamicContextId) {
|
301
|
+
this._handleItemMoved(item, category);
|
302
|
+
}
|
303
|
+
}));
|
304
|
+
}
|
305
|
+
|
306
|
+
this._managedCategoriesListeners.set(category.name, listeners);
|
307
|
+
}
|
308
|
+
|
309
|
+
/**
|
310
|
+
* updates the root item of this category in the items array.
|
311
|
+
* Only updates the actions
|
312
|
+
* @param {string} categoryName
|
313
|
+
* @private
|
314
|
+
*/
|
315
|
+
_updateCategory(categoryName) {
|
316
|
+
if (this._managedCategories.has(categoryName)) {
|
317
|
+
const categoryUiItem = this._items.value.find((item) => {
|
318
|
+
return item.id === categoryName;
|
319
|
+
});
|
320
|
+
if (categoryUiItem) {
|
321
|
+
const pluginNames = [...this._app.plugins].map(p => p.name);
|
322
|
+
const actions = [...this._managedCategories.get(categoryName).entries()]
|
323
|
+
.sort(([ownerA], [ownerB]) => sortByOwner(ownerA, ownerB, pluginNames))
|
324
|
+
.map(([, value]) => value)
|
325
|
+
.flatMap(ownerActions => ownerActions);
|
326
|
+
categoryUiItem.actions = actions;
|
327
|
+
}
|
328
|
+
}
|
329
|
+
}
|
330
|
+
|
331
|
+
/**
|
332
|
+
* adds a category to this manager, the category will be shown in the components window.
|
333
|
+
* If a category has been added by several owners the actions will be merged and sorted by the order of the
|
334
|
+
* owner in the app.plugins collection.
|
335
|
+
* @param {string} categoryName
|
336
|
+
* @param {string | symbol} owner
|
337
|
+
* @param {Array<VcsAction>} actions
|
338
|
+
*/
|
339
|
+
addCategory(categoryName, owner, actions) {
|
340
|
+
check(categoryName, String);
|
341
|
+
check(owner, [String, Symbol]);
|
342
|
+
if (!validateActions(actions)) {
|
343
|
+
throw new Error('Invalid actions Array');
|
344
|
+
}
|
345
|
+
if (!this._app.categories.hasKey(categoryName)) {
|
346
|
+
throw new Error(`Could not find category: ${categoryName}`);
|
347
|
+
}
|
348
|
+
|
349
|
+
if (this._managedCategories.get(categoryName)?.has(owner)) {
|
350
|
+
throw new Error(`Category has already been added by this owner: ${categoryName}, ${owner}`);
|
351
|
+
}
|
352
|
+
|
353
|
+
if (!this._managedCategories.has(categoryName)) {
|
354
|
+
const managedCategory = new Map();
|
355
|
+
managedCategory.set(owner, actions.slice());
|
356
|
+
this._managedCategories.set(categoryName, managedCategory);
|
357
|
+
this._resetCategory(categoryName);
|
358
|
+
} else {
|
359
|
+
this._managedCategories.get(categoryName).set(owner, actions.slice());
|
360
|
+
this._updateCategory(categoryName);
|
361
|
+
}
|
362
|
+
}
|
363
|
+
|
364
|
+
/**
|
365
|
+
* removes a category from this manager
|
366
|
+
* @param {string} categoryName
|
367
|
+
* @param {string | symbol} owner
|
368
|
+
*/
|
369
|
+
removeCategory(categoryName, owner) {
|
370
|
+
check(categoryName, String);
|
371
|
+
check(owner, [String, Symbol]);
|
372
|
+
if (!this._managedCategories.has(categoryName)) {
|
373
|
+
return;
|
374
|
+
}
|
375
|
+
this._managedCategories.get(categoryName).delete(owner);
|
376
|
+
if (this._managedCategories.get(categoryName).size > 0) {
|
377
|
+
this._updateCategory(categoryName);
|
378
|
+
} else {
|
379
|
+
this._removeCategory(categoryName);
|
380
|
+
}
|
381
|
+
}
|
382
|
+
|
383
|
+
/**
|
384
|
+
* removes a Category from management, removes all Listeners, and updates the treeViewItems
|
385
|
+
* @param {string} categoryName
|
386
|
+
* @private
|
387
|
+
*/
|
388
|
+
_removeCategory(categoryName) {
|
389
|
+
// remove rootCategoryItem
|
390
|
+
const categoryItemIndex = this._items.value.findIndex((item) => {
|
391
|
+
return item.id === categoryName;
|
392
|
+
});
|
393
|
+
if (categoryItemIndex >= 0) {
|
394
|
+
this._items.value.splice(categoryItemIndex, 1);
|
395
|
+
}
|
396
|
+
this._managedCategoriesListeners.get(categoryName)
|
397
|
+
?.forEach((listenerCallback) => {
|
398
|
+
listenerCallback();
|
399
|
+
});
|
400
|
+
this._managedCategoriesListeners.delete(categoryName);
|
401
|
+
this._managedCategories.delete(categoryName);
|
402
|
+
}
|
403
|
+
|
404
|
+
/**
|
405
|
+
* adds MappingFunction the categoryManager. For the given categoryNames each Item will be transformed by the
|
406
|
+
* mappingFunction if the predicate returns true.
|
407
|
+
* @param {PredicateFunction} predicate
|
408
|
+
* @param {MappingFunction} mappingFunction
|
409
|
+
* @param {Array<string>} categoryNames list of categories this mappingFunction should be used on
|
410
|
+
* @param {string | symbol} owner
|
411
|
+
*/
|
412
|
+
addMappingFunction(predicate, mappingFunction, categoryNames, owner) {
|
413
|
+
check(predicate, Function);
|
414
|
+
check(mappingFunction, Function);
|
415
|
+
check(categoryNames, [String]);
|
416
|
+
check(owner, [String, Symbol]);
|
417
|
+
if (categoryNames.length === 0) {
|
418
|
+
throw new Error('Provide at least one categoryName');
|
419
|
+
}
|
420
|
+
if (this._itemMappings.find((itemMapping) => {
|
421
|
+
return itemMapping.mappingFunction === mappingFunction && itemMapping.owner === owner;
|
422
|
+
})) {
|
423
|
+
throw new Error('Could not add MappingFunction, the MappingFunction is already under management');
|
424
|
+
}
|
425
|
+
/** @type {ItemMapping} */
|
426
|
+
const itemMapping = {
|
427
|
+
predicate,
|
428
|
+
mappingFunction,
|
429
|
+
categoryNames: categoryNames.slice(),
|
430
|
+
owner,
|
431
|
+
};
|
432
|
+
this._itemMappings.push(itemMapping);
|
433
|
+
itemMapping.categoryNames.forEach((categoryName) => {
|
434
|
+
if (this._managedCategories.has(categoryName)) {
|
435
|
+
this._resetCategory(categoryName);
|
436
|
+
}
|
437
|
+
});
|
438
|
+
}
|
439
|
+
|
440
|
+
/**
|
441
|
+
* removes the given mappingFunction
|
442
|
+
* @param {MappingFunction} mappingFunction
|
443
|
+
* @param {string | symbol} owner
|
444
|
+
*/
|
445
|
+
removeMappingFunction(mappingFunction, owner) {
|
446
|
+
check(mappingFunction, Function);
|
447
|
+
check(owner, [String, Symbol]);
|
448
|
+
const affectedCategories = [];
|
449
|
+
this._itemMappings = this._itemMappings.filter((itemMapping) => {
|
450
|
+
if (itemMapping.mappingFunction === mappingFunction && itemMapping.owner === owner) {
|
451
|
+
affectedCategories.push(...itemMapping.categoryNames);
|
452
|
+
return false;
|
453
|
+
}
|
454
|
+
return true;
|
455
|
+
});
|
456
|
+
new Set(affectedCategories).forEach((categoryName) => {
|
457
|
+
this._resetCategory(categoryName);
|
458
|
+
});
|
459
|
+
}
|
460
|
+
|
461
|
+
/**
|
462
|
+
* removes managed categories and mappingFunctions belonging to the given owner.
|
463
|
+
* @param {string | symbol} owner
|
464
|
+
*/
|
465
|
+
removeOwner(owner) {
|
466
|
+
check(owner, [String, Symbol]);
|
467
|
+
this._managedCategories.forEach((managedCategory, categoryName) => {
|
468
|
+
managedCategory.delete(owner);
|
469
|
+
if (managedCategory.size === 0) {
|
470
|
+
this._managedCategories.delete(categoryName);
|
471
|
+
}
|
472
|
+
});
|
473
|
+
this._itemMappings = this._itemMappings.filter((itemMapping) => {
|
474
|
+
return itemMapping.owner !== owner;
|
475
|
+
});
|
476
|
+
this._resetItems();
|
477
|
+
}
|
478
|
+
|
479
|
+
/**
|
480
|
+
* Array to render in TreeView
|
481
|
+
* @returns {import("vue").Ref<Array<import("@vcmap/ui").TreeViewItem>>}
|
482
|
+
*/
|
483
|
+
get items() {
|
484
|
+
return this._items;
|
485
|
+
}
|
486
|
+
|
487
|
+
/**
|
488
|
+
* destroys the categoryManager, removes all Listeners and clears all Managed Categories
|
489
|
+
*/
|
490
|
+
destroy() {
|
491
|
+
this._dynamicContextIdListener();
|
492
|
+
this._appCategoriesRemovedListener();
|
493
|
+
this.items.value.splice(0);
|
494
|
+
this._managedCategories.clear();
|
495
|
+
[...this._managedCategoriesListeners.values()].forEach((listeners) => {
|
496
|
+
listeners.forEach((listener) => { listener(); });
|
497
|
+
});
|
498
|
+
this._managedCategoriesListeners.clear();
|
499
|
+
}
|
500
|
+
}
|
@@ -0,0 +1,43 @@
|
|
1
|
+
<template>
|
2
|
+
<div @click.stop="close">
|
3
|
+
<VcsActionList
|
4
|
+
:actions="actions"
|
5
|
+
:show-icon="true"
|
6
|
+
/>
|
7
|
+
</div>
|
8
|
+
</template>
|
9
|
+
|
10
|
+
<script>
|
11
|
+
import { inject } from 'vue';
|
12
|
+
import VcsActionList from '../../components/lists/VcsActionList.vue';
|
13
|
+
|
14
|
+
/**
|
15
|
+
* @type {string}
|
16
|
+
*/
|
17
|
+
export const contextMenuWindowId = 'contextMenuWindow';
|
18
|
+
|
19
|
+
export default {
|
20
|
+
name: 'ContextMenuComponent',
|
21
|
+
components: { VcsActionList },
|
22
|
+
props: {
|
23
|
+
actions: {
|
24
|
+
type: Array,
|
25
|
+
required: true,
|
26
|
+
},
|
27
|
+
},
|
28
|
+
setup() {
|
29
|
+
const app = inject('vcsApp');
|
30
|
+
|
31
|
+
const close = () => {
|
32
|
+
app.windowManager.remove(contextMenuWindowId);
|
33
|
+
};
|
34
|
+
|
35
|
+
return {
|
36
|
+
close,
|
37
|
+
};
|
38
|
+
},
|
39
|
+
};
|
40
|
+
</script>
|
41
|
+
|
42
|
+
<style scoped>
|
43
|
+
</style>
|
@@ -0,0 +1,42 @@
|
|
1
|
+
import { AbstractInteraction, EventType, ModificationKeyType, PointerKeyType } from '@vcmap/core';
|
2
|
+
|
3
|
+
/**
|
4
|
+
* Class to call a callback on right click and a callback on any other click
|
5
|
+
* @class
|
6
|
+
* @extends {AbstractInteraction}
|
7
|
+
*/
|
8
|
+
class ContextMenuInteraction extends AbstractInteraction {
|
9
|
+
/**
|
10
|
+
* @param {function(import("@vcmap/core").InteractionEvent):Promise<void>} rightClick - the right click callback, called on right click only
|
11
|
+
* @param {function(import("@vcmap/core").InteractionEvent):Promise<void>} clear - the clear callback
|
12
|
+
*/
|
13
|
+
constructor(rightClick, clear) {
|
14
|
+
super(EventType.CLICK, ModificationKeyType.ALL, PointerKeyType.ALL);
|
15
|
+
/**
|
16
|
+
* @type {function(import("@vcmap/core").InteractionEvent): Promise<void>}
|
17
|
+
* @private
|
18
|
+
*/
|
19
|
+
this._clear = clear;
|
20
|
+
/**
|
21
|
+
* @type {function(import("@vcmap/core").InteractionEvent): Promise<void>}
|
22
|
+
* @private
|
23
|
+
*/
|
24
|
+
this._rightClick = rightClick;
|
25
|
+
}
|
26
|
+
|
27
|
+
/**
|
28
|
+
* @inheritDoc
|
29
|
+
* @param {import("@vcmap/core").InteractionEvent} event
|
30
|
+
* @returns {Promise<import("@vcmap/core").InteractionEvent>}
|
31
|
+
*/
|
32
|
+
async pipe(event) {
|
33
|
+
if (event.pointer & PointerKeyType.RIGHT) {
|
34
|
+
await this._rightClick(event);
|
35
|
+
} else {
|
36
|
+
await this._clear(event);
|
37
|
+
}
|
38
|
+
return event;
|
39
|
+
}
|
40
|
+
}
|
41
|
+
|
42
|
+
export default ContextMenuInteraction;
|