@vcmap/ui 5.0.0-rc.16 → 5.0.0-rc.17
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/buildHelpers.js +7 -1
- package/config/base.config.json +3 -45
- package/config/www.config.json +9 -10
- package/dist/assets/{cesium.430460.js → cesium.41de56.js} +0 -0
- package/dist/assets/cesium.js +1 -1
- package/dist/assets/{core.5089ba.js → core.af84e3.js} +1700 -1718
- package/dist/assets/core.js +1 -1
- package/dist/assets/{index.854f8e2b.js → index.5b773cad.js} +1 -1
- package/dist/assets/{ol.9be53a.js → ol.5c7490.js} +0 -0
- package/dist/assets/ol.js +1 -1
- package/dist/assets/{ui.49010a.css → ui.dffe32.css} +1 -1
- package/dist/assets/{ui.49010a.js → ui.dffe32.js} +6345 -6011
- package/dist/assets/ui.js +1 -1
- package/dist/assets/{vue.247c1c.js → vue.25da17.js} +0 -0
- package/dist/assets/vue.js +2 -2
- package/dist/assets/{vuetify.735e58.css → vuetify.e4ece7.css} +0 -0
- package/dist/assets/{vuetify.735e58.js → vuetify.e4ece7.js} +5 -2
- package/dist/assets/vuetify.js +2 -2
- package/dist/index.html +1 -1
- package/index.js +14 -3
- package/package.json +2 -2
- package/plugins/@vcmap/pluginExample/index.js +2 -1
- package/plugins/@vcmap/pluginExample/pluginExampleComponent.vue +7 -0
- package/plugins/categoryTest/Categories.vue +27 -13
- package/plugins/categoryTest/Category.vue +7 -1
- package/plugins/categoryTest/index.js +1 -1
- package/plugins/test/allIconsComponent.vue +3 -3
- package/plugins/test/index.js +6 -4
- package/plugins/test/testList.vue +4 -1
- package/plugins/test/vcsContent.vue +1 -1
- package/plugins/test/windowManagerExample.vue +9 -7
- package/src/actions/actionHelper.js +10 -9
- package/src/application/VcsApp.vue +25 -26
- package/src/components/form-inputs-controls/VcsCheckbox.vue +1 -0
- package/src/components/form-inputs-controls/VcsFormSection.vue +14 -6
- package/src/components/lists/VcsList.vue +4 -2
- package/src/contentTree/contentTreeCollection.js +9 -0
- package/src/contentTree/layerContentTreeItem.js +1 -1
- package/src/featureInfo/BalloonComponent.vue +3 -0
- package/src/featureInfo/balloonFeatureInfoView.js +2 -8
- package/src/featureInfo/balloonHelper.js +22 -5
- package/src/featureInfo/featureInfo.js +1 -2
- package/src/i18n/de.js +6 -1
- package/src/i18n/en.js +6 -1
- package/src/manager/categoryManager/CategoryComponent.vue +115 -0
- package/src/manager/categoryManager/CategoryComponentList.vue +57 -0
- package/src/manager/categoryManager/CategoryManager.vue +35 -0
- package/src/manager/categoryManager/categoryManager.js +251 -165
- package/src/manager/contextMenu/contextMenuManager.js +8 -2
- package/src/manager/window/WindowComponent.vue +49 -75
- package/src/manager/window/WindowComponentHeader.vue +49 -7
- package/src/manager/window/WindowManager.vue +53 -30
- package/src/manager/window/windowHelper.js +341 -0
- package/src/manager/window/windowManager.js +162 -150
- package/src/notifier/notifier.js +4 -5
- package/src/vcsUiApp.js +7 -1
- package/src/manager/categoryManager/ComponentsManager.vue +0 -30
@@ -1,5 +1,5 @@
|
|
1
|
-
import {
|
2
|
-
import { contextIdSymbol, IndexedCollection } from '@vcmap/core';
|
1
|
+
import { reactive } from 'vue';
|
2
|
+
import { contextIdSymbol, IndexedCollection, VcsEvent } from '@vcmap/core';
|
3
3
|
import { check } from '@vcsuite/check';
|
4
4
|
import { sortByOwner } from '../navbarManager.js';
|
5
5
|
import { validateAction, validateActions } from '../../components/lists/VcsActionList.vue';
|
@@ -8,7 +8,7 @@ import { validateAction, validateActions } from '../../components/lists/VcsActio
|
|
8
8
|
* @callback MappingFunction
|
9
9
|
* @param {T} item
|
10
10
|
* @param {import("@vcmap/core").Category<T>} category
|
11
|
-
* @param {import("@vcmap/ui").
|
11
|
+
* @param {import("@vcmap/ui").VcsListItem & { destroy: (function():void)|undefined }} listItem - you can add a destroy callback for cleanup
|
12
12
|
* @template {Object} T
|
13
13
|
*/
|
14
14
|
|
@@ -30,63 +30,99 @@ import { validateAction, validateActions } from '../../components/lists/VcsActio
|
|
30
30
|
*/
|
31
31
|
|
32
32
|
/**
|
33
|
-
*
|
33
|
+
* @typedef {Object} ManagedCategory
|
34
|
+
* @property {string} categoryName
|
35
|
+
* @property {string} title
|
36
|
+
* @property {Array<VcsAction>} actions
|
37
|
+
* @property {Array<VcsListItem & { destroy: (function():void|undefined) }>} items
|
38
|
+
* @property {boolean} selectable
|
39
|
+
* @property {boolean} singleSelect
|
40
|
+
* @property {Array<VcsListItem>} selection
|
41
|
+
* @property {function():void} destroy - called when the item is destroyed. do not call yourself, remove the category from the manager
|
42
|
+
*/
|
43
|
+
|
44
|
+
/**
|
45
|
+
* @typedef {Object} ManagedCategoryOptions
|
46
|
+
* @property {string} categoryName
|
47
|
+
* @property {boolean} [selectable]
|
48
|
+
* @property {boolean} [singleSelect]
|
49
|
+
* @property {Array<VcsAction>} [actions]
|
50
|
+
*/
|
51
|
+
|
52
|
+
/**
|
53
|
+
* uses the itemMappings to transform the given Item to an VcsListItem usable in the VcsList
|
34
54
|
* @param {T} item
|
35
55
|
* @param {import("@vcmap/core").Category<T>} category
|
36
56
|
* @param {Array<ItemMapping<T>>} itemMappings
|
37
|
-
* @returns {import("@vcmap/ui").
|
57
|
+
* @returns {import("@vcmap/ui").VcsListItem & { destroy: (function():void)|undefined }}
|
38
58
|
* @template T
|
39
59
|
* @private
|
40
60
|
*/
|
41
61
|
function transformItem(item, category, itemMappings) {
|
42
62
|
const keyProperty = category.collection.uniqueKey;
|
43
|
-
const
|
63
|
+
const listItem = {
|
44
64
|
get id() { return item[keyProperty]; },
|
45
65
|
title: item?.properties?.title || item[keyProperty],
|
46
66
|
actions: [],
|
47
|
-
children: [],
|
48
67
|
};
|
49
68
|
itemMappings.forEach((itemMapping) => {
|
50
69
|
if (itemMapping.predicate(item, category)) {
|
51
|
-
itemMapping.mappingFunction(item, category,
|
70
|
+
itemMapping.mappingFunction(item, category, listItem);
|
52
71
|
}
|
53
72
|
});
|
54
|
-
|
73
|
+
listItem.actions = listItem.actions.filter((action) => {
|
55
74
|
return validateAction(action);
|
56
75
|
});
|
57
|
-
return
|
76
|
+
return listItem;
|
58
77
|
}
|
59
78
|
|
60
79
|
/**
|
61
|
-
* Inserts the item into the
|
80
|
+
* Inserts the item into the items array at the correct relative position in respect to the position of the item
|
62
81
|
* in the collection
|
63
|
-
* @param {import("@vcmap/ui").
|
82
|
+
* @param {import("@vcmap/ui").VcsListItem} item
|
64
83
|
* @param {import("@vcmap/core").Collection} collection
|
65
|
-
* @param {Array<import("@vcmap/ui").
|
84
|
+
* @param {Array<import("@vcmap/ui").VcsListItem>} items
|
66
85
|
* @private
|
67
86
|
*/
|
68
|
-
function insertItem(item, collection,
|
87
|
+
function insertItem(item, collection, items) {
|
69
88
|
if (collection instanceof IndexedCollection) {
|
70
89
|
const newItemIndex = collection.indexOfKey(item.id);
|
71
90
|
if (newItemIndex === collection.size - 1) {
|
72
|
-
|
91
|
+
items.push(item);
|
73
92
|
} else {
|
74
|
-
const positionInChildren =
|
75
|
-
const treeViewItemIndex = collection.indexOfKey(
|
93
|
+
const positionInChildren = items.findIndex((listItem) => {
|
94
|
+
const treeViewItemIndex = collection.indexOfKey(listItem.id);
|
76
95
|
return newItemIndex < treeViewItemIndex;
|
77
96
|
});
|
78
97
|
if (positionInChildren >= 0) {
|
79
|
-
|
98
|
+
items.splice(positionInChildren, 0, item);
|
99
|
+
} else {
|
100
|
+
items.push(item);
|
80
101
|
}
|
81
102
|
}
|
82
103
|
} else {
|
83
|
-
|
104
|
+
items.push(item);
|
105
|
+
}
|
106
|
+
}
|
107
|
+
|
108
|
+
/**
|
109
|
+
* @param {ManagedCategoryOptions} current
|
110
|
+
* @param {ManagedCategoryOptions} next
|
111
|
+
* @returns {ManagedCategoryOptions}
|
112
|
+
*/
|
113
|
+
function reduceCategoryOptions(current, next) {
|
114
|
+
if (next.actions?.length > 0) {
|
115
|
+
current.actions.push(...next.actions);
|
84
116
|
}
|
117
|
+
current.selectable = current.selectable ?? next.selectable;
|
118
|
+
current.singleSelect = current.singleSelect ?? next.singleSelect;
|
119
|
+
return current;
|
85
120
|
}
|
86
121
|
|
87
122
|
/**
|
88
123
|
* a categoryManager manages categories, and synchronizes a tree of VcsTreeView Items.
|
89
124
|
* provides an API to add/remove Categories.
|
125
|
+
* @implements {VcsComponentManager<ManagedCategory, ManagedCategoryOptions>}
|
90
126
|
*/
|
91
127
|
class CategoryManager {
|
92
128
|
/**
|
@@ -100,16 +136,10 @@ class CategoryManager {
|
|
100
136
|
this._app = app;
|
101
137
|
|
102
138
|
/**
|
103
|
-
* @type {Map<string, Map<string|symbol,
|
139
|
+
* @type {Map<string, Map<string|symbol, ManagedCategoryOptions>>}
|
104
140
|
* @private
|
105
141
|
*/
|
106
|
-
this.
|
107
|
-
|
108
|
-
/**
|
109
|
-
* @type {Map<string, Array<function():void>>}
|
110
|
-
* @private
|
111
|
-
*/
|
112
|
-
this._managedCategoriesListeners = new Map();
|
142
|
+
this._managedCategoryOptions = new Map();
|
113
143
|
|
114
144
|
/**
|
115
145
|
* @type {function():void}
|
@@ -117,7 +147,7 @@ class CategoryManager {
|
|
117
147
|
*/
|
118
148
|
this._dynamicContextIdListener = this._app.dynamicContextIdChanged.addEventListener((id) => {
|
119
149
|
this._dynamicContextId = id;
|
120
|
-
this.
|
150
|
+
this._resetManagedCategories();
|
121
151
|
});
|
122
152
|
|
123
153
|
/**
|
@@ -139,12 +169,23 @@ class CategoryManager {
|
|
139
169
|
* @private
|
140
170
|
*/
|
141
171
|
this._itemMappings = [];
|
142
|
-
|
143
172
|
/**
|
144
|
-
* @type {
|
173
|
+
* @type {Map<string, ManagedCategory>}
|
145
174
|
* @private
|
146
175
|
*/
|
147
|
-
this.
|
176
|
+
this._managedCategories = new Map();
|
177
|
+
/**
|
178
|
+
* @type {Array<string>}
|
179
|
+
*/
|
180
|
+
this.componentIds = [];
|
181
|
+
/**
|
182
|
+
* @type {VcsEvent<ManagedCategory>}
|
183
|
+
*/
|
184
|
+
this.added = new VcsEvent();
|
185
|
+
/**
|
186
|
+
* @type {VcsEvent<ManagedCategory>}
|
187
|
+
*/
|
188
|
+
this.removed = new VcsEvent();
|
148
189
|
}
|
149
190
|
|
150
191
|
/**
|
@@ -158,27 +199,10 @@ class CategoryManager {
|
|
158
199
|
const itemMappings = this._itemMappings.filter((itemMapping) => {
|
159
200
|
return itemMapping.categoryNames.includes(category.name);
|
160
201
|
});
|
161
|
-
const
|
162
|
-
const
|
163
|
-
if (
|
164
|
-
insertItem(
|
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
|
-
} */
|
202
|
+
const listItem = transformItem(item, category, itemMappings);
|
203
|
+
const managedCategory = this.get(category.name);
|
204
|
+
if (managedCategory) {
|
205
|
+
insertItem(listItem, category.collection, managedCategory.items);
|
182
206
|
}
|
183
207
|
}
|
184
208
|
|
@@ -191,13 +215,14 @@ class CategoryManager {
|
|
191
215
|
* @private
|
192
216
|
*/
|
193
217
|
_handleItemMoved(item, category) {
|
194
|
-
const
|
195
|
-
if (
|
196
|
-
const index =
|
218
|
+
const managedCategory = this.get(category.name);
|
219
|
+
if (managedCategory) {
|
220
|
+
const index = managedCategory.items
|
221
|
+
.findIndex((elem) => { return elem.id === item[category.collection.uniqueKey]; });
|
197
222
|
if (index > -1) {
|
198
|
-
const
|
199
|
-
|
200
|
-
insertItem(
|
223
|
+
const listItem = managedCategory.items[index];
|
224
|
+
managedCategory.items.splice(index, 1);
|
225
|
+
insertItem(listItem, category.collection, managedCategory.items);
|
201
226
|
}
|
202
227
|
}
|
203
228
|
}
|
@@ -210,73 +235,75 @@ class CategoryManager {
|
|
210
235
|
* @private
|
211
236
|
*/
|
212
237
|
_handleItemRemoved(item, category) {
|
213
|
-
const
|
214
|
-
if (
|
215
|
-
const index =
|
238
|
+
const managedCategory = this.get(category.name);
|
239
|
+
if (managedCategory) {
|
240
|
+
const index = managedCategory.items
|
241
|
+
.findIndex((elem) => { return elem.id === item[category.collection.uniqueKey]; });
|
216
242
|
if (index > -1) {
|
217
|
-
|
243
|
+
const listItem = managedCategory.items[index];
|
244
|
+
if (listItem.destroy) {
|
245
|
+
listItem.destroy();
|
246
|
+
}
|
247
|
+
managedCategory.items.splice(index, 1);
|
218
248
|
}
|
219
249
|
}
|
220
250
|
}
|
221
251
|
|
222
252
|
/**
|
223
|
-
* removes all
|
253
|
+
* removes all items from all categories and rebuilds the item tree depending on the ContextId
|
224
254
|
* @private
|
225
255
|
*/
|
226
|
-
|
227
|
-
this.
|
228
|
-
|
229
|
-
this._resetCategory(categoryName);
|
256
|
+
_resetManagedCategories() {
|
257
|
+
this._managedCategoryOptions.forEach((value, categoryName) => {
|
258
|
+
this._resetCategoryItems(categoryName);
|
230
259
|
});
|
231
260
|
}
|
232
261
|
|
233
262
|
/**
|
234
|
-
* resets the category, removes the currently managed state and rebuilds the categoryItem and all children
|
235
263
|
* @param {string} categoryName
|
236
264
|
* @private
|
237
265
|
*/
|
238
|
-
|
266
|
+
_resetCategoryItems(categoryName) {
|
239
267
|
const category = this._app.categories.getByKey(categoryName);
|
240
|
-
|
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
|
-
}
|
268
|
+
const managedCategory = this.get(categoryName);
|
250
269
|
|
251
|
-
|
252
|
-
|
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);
|
270
|
+
if (category && managedCategory) {
|
271
|
+
const itemMappings = this._itemMappings.filter((itemMapping) => {
|
272
|
+
return itemMapping.categoryNames.includes(categoryName);
|
265
273
|
});
|
274
|
+
if (managedCategory.selection.length > 0) {
|
275
|
+
managedCategory.selection = [];
|
276
|
+
}
|
277
|
+
managedCategory.items.forEach((item) => {
|
278
|
+
if (item.destroy) {
|
279
|
+
item.destroy();
|
280
|
+
}
|
281
|
+
});
|
282
|
+
managedCategory.items = [...category.collection]
|
283
|
+
.filter((item) => {
|
284
|
+
return item[contextIdSymbol] === this._dynamicContextId;
|
285
|
+
})
|
286
|
+
.map((item) => {
|
287
|
+
return transformItem(item, category, itemMappings);
|
288
|
+
});
|
289
|
+
}
|
290
|
+
}
|
266
291
|
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
this._items.value.push(categoryItem);
|
292
|
+
/**
|
293
|
+
* create the managed category
|
294
|
+
* @param {string} categoryName
|
295
|
+
* @returns {ManagedCategory}
|
296
|
+
* @private
|
297
|
+
*/
|
298
|
+
_createManagedCategory(categoryName) {
|
299
|
+
const category = this._app.categories.getByKey(categoryName);
|
300
|
+
if (!category) {
|
301
|
+
throw new Error(`Could not find Category: ${categoryName}`);
|
278
302
|
}
|
279
303
|
|
304
|
+
const options = [...this._managedCategoryOptions.get(category.name).values()] // does not have to be sorted, since this is the first owner
|
305
|
+
.reduce(reduceCategoryOptions, { actions: [] });
|
306
|
+
|
280
307
|
const listeners = [
|
281
308
|
category.collection.added.addEventListener((item) => {
|
282
309
|
if (item[contextIdSymbol] === this._dynamicContextId) {
|
@@ -303,77 +330,124 @@ class CategoryManager {
|
|
303
330
|
}));
|
304
331
|
}
|
305
332
|
|
306
|
-
|
333
|
+
/** @type {ManagedCategory} */
|
334
|
+
const managedCategory = reactive({
|
335
|
+
...options,
|
336
|
+
get categoryName() { return category.name; },
|
337
|
+
selection: [],
|
338
|
+
title: category.title,
|
339
|
+
items: [],
|
340
|
+
destroy() {
|
341
|
+
listeners.forEach((cb) => { cb(); });
|
342
|
+
this.items.forEach((item) => {
|
343
|
+
if (item.destroy) {
|
344
|
+
item.destroy();
|
345
|
+
}
|
346
|
+
});
|
347
|
+
this.items = [];
|
348
|
+
},
|
349
|
+
});
|
350
|
+
|
351
|
+
this._managedCategories.set(categoryName, managedCategory);
|
352
|
+
this._resetCategoryItems(categoryName);
|
353
|
+
this.componentIds.push(categoryName);
|
354
|
+
this.added.raiseEvent(managedCategory);
|
355
|
+
|
356
|
+
return managedCategory;
|
307
357
|
}
|
308
358
|
|
309
359
|
/**
|
310
|
-
* updates the
|
311
|
-
* Only updates the actions
|
360
|
+
* updates the managed categorys actions
|
312
361
|
* @param {string} categoryName
|
313
362
|
* @private
|
314
363
|
*/
|
315
364
|
_updateCategory(categoryName) {
|
316
|
-
if (this.
|
317
|
-
const
|
318
|
-
|
319
|
-
});
|
320
|
-
if (categoryUiItem) {
|
365
|
+
if (this._managedCategoryOptions.has(categoryName)) {
|
366
|
+
const managedCategory = this.get(categoryName);
|
367
|
+
if (managedCategory) {
|
321
368
|
const pluginNames = [...this._app.plugins].map(p => p.name);
|
322
|
-
const
|
369
|
+
const options = [...this._managedCategoryOptions.get(categoryName).entries()]
|
323
370
|
.sort(([ownerA], [ownerB]) => sortByOwner(ownerA, ownerB, pluginNames))
|
324
371
|
.map(([, value]) => value)
|
325
|
-
.
|
326
|
-
|
372
|
+
.reduce(reduceCategoryOptions, { actions: [] });
|
373
|
+
Object.assign(managedCategory, options);
|
327
374
|
}
|
328
375
|
}
|
329
376
|
}
|
330
377
|
|
378
|
+
/**
|
379
|
+
* @param {string} categoryName
|
380
|
+
* @returns {ManagedCategory|undefined}
|
381
|
+
*/
|
382
|
+
get(categoryName) {
|
383
|
+
return this._managedCategories.get(categoryName);
|
384
|
+
}
|
385
|
+
|
386
|
+
/**
|
387
|
+
* @param {string} categoryName
|
388
|
+
* @returns {boolean}
|
389
|
+
*/
|
390
|
+
has(categoryName) {
|
391
|
+
return this._managedCategories.has(categoryName);
|
392
|
+
}
|
393
|
+
|
331
394
|
/**
|
332
395
|
* adds a category to this manager, the category will be shown in the components window.
|
333
396
|
* If a category has been added by several owners the actions will be merged and sorted by the order of the
|
334
397
|
* owner in the app.plugins collection.
|
335
|
-
* @param {
|
336
|
-
* @param {string
|
337
|
-
* @
|
398
|
+
* @param {ManagedCategoryOptions} managedCategoryOptions
|
399
|
+
* @param {string|symbol} owner
|
400
|
+
* @returns {ManagedCategory}
|
338
401
|
*/
|
339
|
-
|
340
|
-
check(
|
402
|
+
add(managedCategoryOptions, owner) {
|
403
|
+
check(managedCategoryOptions, { categoryName: String });
|
341
404
|
check(owner, [String, Symbol]);
|
342
|
-
|
405
|
+
|
406
|
+
const { categoryName } = managedCategoryOptions;
|
407
|
+
if (managedCategoryOptions.actions && !validateActions(managedCategoryOptions.actions)) {
|
343
408
|
throw new Error('Invalid actions Array');
|
344
409
|
}
|
345
410
|
if (!this._app.categories.hasKey(categoryName)) {
|
346
411
|
throw new Error(`Could not find category: ${categoryName}`);
|
347
412
|
}
|
348
413
|
|
349
|
-
if (this.
|
414
|
+
if (this._managedCategoryOptions.get(categoryName)?.has(owner)) {
|
350
415
|
throw new Error(`Category has already been added by this owner: ${categoryName}, ${owner}`);
|
351
416
|
}
|
352
417
|
|
353
|
-
|
418
|
+
/** @type {ManagedCategoryOptions} */
|
419
|
+
const clonedOptions = {
|
420
|
+
categoryName,
|
421
|
+
actions: managedCategoryOptions.actions?.slice?.() ?? [],
|
422
|
+
selectable: managedCategoryOptions.selectable,
|
423
|
+
singleSelect: managedCategoryOptions.singleSelect,
|
424
|
+
};
|
425
|
+
|
426
|
+
if (!this._managedCategoryOptions.has(categoryName)) {
|
354
427
|
const managedCategory = new Map();
|
355
|
-
managedCategory.set(owner,
|
356
|
-
this.
|
357
|
-
this.
|
428
|
+
managedCategory.set(owner, clonedOptions);
|
429
|
+
this._managedCategoryOptions.set(categoryName, managedCategory);
|
430
|
+
return this._createManagedCategory(categoryName);
|
358
431
|
} else {
|
359
|
-
this.
|
432
|
+
this._managedCategoryOptions.get(categoryName).set(owner, clonedOptions);
|
360
433
|
this._updateCategory(categoryName);
|
434
|
+
return this.get(categoryName);
|
361
435
|
}
|
362
436
|
}
|
363
437
|
|
364
438
|
/**
|
365
|
-
* removes a category from this manager
|
439
|
+
* removes a category for a specific owner from this manager
|
366
440
|
* @param {string} categoryName
|
367
|
-
* @param {string
|
441
|
+
* @param {string|symbol} owner
|
368
442
|
*/
|
369
|
-
|
443
|
+
remove(categoryName, owner) {
|
370
444
|
check(categoryName, String);
|
371
445
|
check(owner, [String, Symbol]);
|
372
|
-
if (!this.
|
446
|
+
if (!this._managedCategoryOptions.has(categoryName)) {
|
373
447
|
return;
|
374
448
|
}
|
375
|
-
this.
|
376
|
-
if (this.
|
449
|
+
this._managedCategoryOptions.get(categoryName).delete(owner);
|
450
|
+
if (this._managedCategoryOptions.get(categoryName).size > 0) {
|
377
451
|
this._updateCategory(categoryName);
|
378
452
|
} else {
|
379
453
|
this._removeCategory(categoryName);
|
@@ -381,28 +455,26 @@ class CategoryManager {
|
|
381
455
|
}
|
382
456
|
|
383
457
|
/**
|
384
|
-
* removes a Category from management, removes all Listeners, and updates the
|
458
|
+
* removes a Category from management, removes all Listeners, and updates the listItems
|
385
459
|
* @param {string} categoryName
|
386
460
|
* @private
|
387
461
|
*/
|
388
462
|
_removeCategory(categoryName) {
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
463
|
+
const managedCategory = this.get(categoryName);
|
464
|
+
this._managedCategoryOptions.delete(categoryName);
|
465
|
+
const index = this.componentIds.indexOf(categoryName);
|
466
|
+
if (index > -1) {
|
467
|
+
this.componentIds.splice(index, 1);
|
468
|
+
}
|
469
|
+
if (managedCategory) {
|
470
|
+
this._managedCategories.delete(categoryName);
|
471
|
+
managedCategory.destroy();
|
472
|
+
this.removed.raiseEvent(managedCategory);
|
395
473
|
}
|
396
|
-
this._managedCategoriesListeners.get(categoryName)
|
397
|
-
?.forEach((listenerCallback) => {
|
398
|
-
listenerCallback();
|
399
|
-
});
|
400
|
-
this._managedCategoriesListeners.delete(categoryName);
|
401
|
-
this._managedCategories.delete(categoryName);
|
402
474
|
}
|
403
475
|
|
404
476
|
/**
|
405
|
-
* adds MappingFunction the categoryManager. For the given categoryNames each Item will be transformed by the
|
477
|
+
* adds MappingFunction to the categoryManager. For the given categoryNames each Item will be transformed by the
|
406
478
|
* mappingFunction if the predicate returns true.
|
407
479
|
* @param {PredicateFunction} predicate
|
408
480
|
* @param {MappingFunction} mappingFunction
|
@@ -431,8 +503,8 @@ class CategoryManager {
|
|
431
503
|
};
|
432
504
|
this._itemMappings.push(itemMapping);
|
433
505
|
itemMapping.categoryNames.forEach((categoryName) => {
|
434
|
-
if (this.
|
435
|
-
this.
|
506
|
+
if (this._managedCategoryOptions.has(categoryName)) {
|
507
|
+
this._resetCategoryItems(categoryName);
|
436
508
|
}
|
437
509
|
});
|
438
510
|
}
|
@@ -454,7 +526,7 @@ class CategoryManager {
|
|
454
526
|
return true;
|
455
527
|
});
|
456
528
|
new Set(affectedCategories).forEach((categoryName) => {
|
457
|
-
this.
|
529
|
+
this._resetCategoryItems(categoryName);
|
458
530
|
});
|
459
531
|
}
|
460
532
|
|
@@ -464,24 +536,36 @@ class CategoryManager {
|
|
464
536
|
*/
|
465
537
|
removeOwner(owner) {
|
466
538
|
check(owner, [String, Symbol]);
|
467
|
-
|
468
|
-
|
539
|
+
const affectedCategories = [];
|
540
|
+
this._managedCategoryOptions.forEach((managedCategory, categoryName) => {
|
541
|
+
if (managedCategory.delete(owner)) {
|
542
|
+
affectedCategories.push(categoryName);
|
543
|
+
}
|
469
544
|
if (managedCategory.size === 0) {
|
470
|
-
this.
|
545
|
+
this._managedCategoryOptions.delete(categoryName);
|
471
546
|
}
|
472
547
|
});
|
473
|
-
|
474
|
-
|
548
|
+
affectedCategories.forEach((categoryName) => {
|
549
|
+
if (this._managedCategoryOptions.has(categoryName)) {
|
550
|
+
this._updateCategory(categoryName);
|
551
|
+
} else {
|
552
|
+
this._removeCategory(categoryName);
|
553
|
+
}
|
475
554
|
});
|
476
|
-
this.
|
555
|
+
this._itemMappings = this._itemMappings
|
556
|
+
.filter((itemMapping) => {
|
557
|
+
return itemMapping.owner !== owner;
|
558
|
+
});
|
559
|
+
this._resetManagedCategories();
|
477
560
|
}
|
478
561
|
|
479
562
|
/**
|
480
|
-
*
|
481
|
-
* @returns {import("vue").Ref<Array<import("@vcmap/ui").TreeViewItem>>}
|
563
|
+
* Clears the manager of all added categories and item mappings
|
482
564
|
*/
|
483
|
-
|
484
|
-
|
565
|
+
clear() {
|
566
|
+
[...this.componentIds]
|
567
|
+
.forEach((categoryName) => { this._removeCategory(categoryName); });
|
568
|
+
this._itemMappings = [];
|
485
569
|
}
|
486
570
|
|
487
571
|
/**
|
@@ -490,12 +574,14 @@ class CategoryManager {
|
|
490
574
|
destroy() {
|
491
575
|
this._dynamicContextIdListener();
|
492
576
|
this._appCategoriesRemovedListener();
|
493
|
-
this.
|
494
|
-
this._managedCategories.
|
495
|
-
|
496
|
-
listeners.forEach((listener) => { listener(); });
|
577
|
+
this.componentIds = [];
|
578
|
+
this._managedCategories.forEach((item) => {
|
579
|
+
item.destroy();
|
497
580
|
});
|
498
|
-
this.
|
581
|
+
this._managedCategories.clear();
|
582
|
+
this._managedCategoryOptions.clear();
|
583
|
+
this.added.destroy();
|
584
|
+
this.removed.destroy();
|
499
585
|
}
|
500
586
|
}
|
501
587
|
|
@@ -4,7 +4,8 @@ import { check } from '@vcsuite/check';
|
|
4
4
|
import ContextMenuInteraction from './contextMenuInteraction.js';
|
5
5
|
import { vcsAppSymbol } from '../../pluginHelper.js';
|
6
6
|
import { validateAction } from '../../components/lists/VcsActionList.vue';
|
7
|
-
import {
|
7
|
+
import { WindowSlot } from '../window/windowManager.js';
|
8
|
+
import { getFittedWindowPositionOptionsFromMapEvent } from '../window/windowHelper.js';
|
8
9
|
import ContextMenuComponent, { contextMenuWindowId } from './contextMenuComponent.vue';
|
9
10
|
import { sortByOwner } from '../navbarManager.js';
|
10
11
|
|
@@ -108,7 +109,12 @@ class ContextMenuManager {
|
|
108
109
|
.filter(validateAction);
|
109
110
|
|
110
111
|
if (actions.length > 0) {
|
111
|
-
const position = getFittedWindowPositionOptionsFromMapEvent(
|
112
|
+
const position = getFittedWindowPositionOptionsFromMapEvent(
|
113
|
+
event.windowPosition,
|
114
|
+
320,
|
115
|
+
actions.length * 32,
|
116
|
+
this._app.maps.target,
|
117
|
+
);
|
112
118
|
if (position.left) { // ensure we nudge the window, so it does not trigger the default right click.
|
113
119
|
position.left += 1;
|
114
120
|
} else {
|