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

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 (51) hide show
  1. package/build/bundle.js +2 -1
  2. package/config/base.config.json +22 -0
  3. package/config/www.config.json +1 -1
  4. package/dist/assets/cesium/Workers/cesiumWorkerBootstrapper.js +1 -1
  5. package/dist/assets/cesium/Workers/package.js +1 -1
  6. package/dist/assets/cesium/Workers/transferTypedArrayTest.js +1 -1
  7. package/dist/assets/{cesium.82fdbe.js → cesium.16590b.js} +29788 -29589
  8. package/dist/assets/cesium.js +1 -1
  9. package/dist/assets/{core.df069a.js → core.74da2a.js} +4330 -4231
  10. package/dist/assets/core.js +1 -1
  11. package/dist/assets/index-cb070eff.js +1 -0
  12. package/dist/assets/{ol.90a5d0.js → ol.50a512.js} +11405 -11126
  13. package/dist/assets/ol.js +1 -1
  14. package/dist/assets/{ui.3ed7ff.css → ui.d3054c.css} +2 -2
  15. package/dist/assets/{ui.3ed7ff.js → ui.d3054c.js} +2811 -2711
  16. package/dist/assets/ui.js +1 -1
  17. package/dist/assets/vue.js +2 -2
  18. package/dist/assets/{vuetify.614278.js → vuetify.946bd8.js} +1 -1
  19. package/dist/assets/vuetify.js +2 -2
  20. package/dist/index.html +1 -1
  21. package/index.js +1 -0
  22. package/lib/olLib.js +6 -0
  23. package/package.json +4 -4
  24. package/plugins/@vcmap-show-case/window-tester/WindowExample.vue +27 -9
  25. package/plugins/@vcmap-show-case/window-tester/index.js +13 -1
  26. package/plugins/@vcmap-show-case/window-tester/windowExampleToggleChild.vue +11 -10
  27. package/src/actions/actionHelper.js +7 -3
  28. package/src/application/VcsApp.vue +31 -0
  29. package/src/components/form-inputs-controls/VcsTextField.vue +3 -2
  30. package/src/components/icons/+all.js +3 -3
  31. package/src/components/lists/VcsTreeviewLeaf.vue +1 -1
  32. package/src/components/lists/VcsTreeviewSearchbar.vue +9 -4
  33. package/src/components/tables/VcsDataTable.vue +100 -13
  34. package/src/contentTree/contentTreeCollection.js +22 -11
  35. package/src/featureInfo/abstractFeatureInfoView.js +3 -1
  36. package/src/featureInfo/balloonFeatureInfoView.js +3 -2
  37. package/src/featureInfo/featureInfo.js +1 -0
  38. package/src/i18n/de.js +4 -0
  39. package/src/i18n/en.js +4 -0
  40. package/src/manager/collectionManager/CollectionComponent.vue +6 -1
  41. package/src/manager/collectionManager/collectionComponent.js +6 -0
  42. package/src/manager/window/WindowComponent.vue +4 -1
  43. package/src/manager/window/WindowComponentHeader.vue +25 -13
  44. package/src/manager/window/windowManager.js +6 -2
  45. package/src/navigation/overviewMap.js +1 -1
  46. package/src/uiConfig.js +1 -0
  47. package/src/vcsUiApp.js +29 -8
  48. package/dist/assets/index-1cff371d.js +0 -1
  49. /package/dist/assets/{vue.537ff3.js → vue.30740e.js} +0 -0
  50. /package/dist/assets/{vuetify.614278.css → vuetify.946bd8.css} +0 -0
  51. /package/src/components/icons/{PolygonIcon.vue → PointIcon.vue} +0 -0
@@ -4,7 +4,6 @@ import {
4
4
  makeOverrideCollection,
5
5
  getObjectFromClassRegistry,
6
6
  } from '@vcmap/core';
7
- import { v4 as uuid } from 'uuid';
8
7
  import { computed, ref } from 'vue';
9
8
  import ContentTreeItem from './contentTreeItem.js';
10
9
  import { vcsAppSymbol } from '../pluginHelper.js';
@@ -71,6 +70,11 @@ class ContentTreeCollection extends IndexedCollection {
71
70
  this._weightListeners.get(child.name)();
72
71
  this._weightListeners.delete(child.name);
73
72
  }
73
+ if (this._subTreeListeners.has(child.name)) {
74
+ this._subTreeListeners.get(child.name)();
75
+ this._subTreeListeners.delete(child.name);
76
+ this._subTreeViewItems.value.delete(child.name);
77
+ }
74
78
  }),
75
79
  this.moved.addEventListener(recreateTree),
76
80
  ];
@@ -90,10 +94,10 @@ class ContentTreeCollection extends IndexedCollection {
90
94
  this._subTreeViewItems = ref(new Map());
91
95
  /**
92
96
  * The subtree content action button destroy handlers
93
- * @type {Array<function():void>}
97
+ * @type {Map<string, function():void>}
94
98
  * @private
95
99
  */
96
- this._subTreeListeners = [];
100
+ this._subTreeListeners = new Map();
97
101
  /**
98
102
  * @type {boolean}
99
103
  * @private
@@ -106,7 +110,7 @@ class ContentTreeCollection extends IndexedCollection {
106
110
  */
107
111
  _clearSubTrees() {
108
112
  this._subTreeViewItems.value.clear();
109
- this._subTreeListeners.forEach((cb) => {
113
+ [...this._subTreeListeners.values()].forEach((cb) => {
110
114
  cb();
111
115
  });
112
116
  }
@@ -119,7 +123,7 @@ class ContentTreeCollection extends IndexedCollection {
119
123
  */
120
124
  _createSubtreeActionButton(subTreeViewItem, slot = WindowSlot.STATIC) {
121
125
  // TODO make configurable?
122
- const id = uuid();
126
+ const id = subTreeViewItem.name;
123
127
  const app = this._app;
124
128
  const { action, destroy } = createToggleAction(
125
129
  // TODO icon & title are not reactive
@@ -135,6 +139,9 @@ class ContentTreeCollection extends IndexedCollection {
135
139
  state: {
136
140
  headerIcon: subTreeViewItem.icon,
137
141
  headerTitle: subTreeViewItem.title,
142
+ infoUrlCallback: app.getHelpUrlCallback(
143
+ '/components/contentspace.html#id_content',
144
+ ),
138
145
  },
139
146
  },
140
147
  app.windowManager,
@@ -158,7 +165,6 @@ class ContentTreeCollection extends IndexedCollection {
158
165
  * @private
159
166
  */
160
167
  _setTreeView() {
161
- this._clearSubTrees();
162
168
  /** @type {Map<string, ParentTreeViewItem>} */
163
169
  const baseTreeMap = new Map();
164
170
  [...this._array]
@@ -210,9 +216,14 @@ class ContentTreeCollection extends IndexedCollection {
210
216
  ...topLevelItems.filter((i) => i[subTreeSymbol]),
211
217
  ];
212
218
 
213
- this._subTreeListeners = subTrees.map((subTree) =>
214
- this._createSubtreeActionButton(subTree),
215
- );
219
+ subTrees.forEach((subTree) => {
220
+ if (!this._app.navbarManager.has(subTree.name)) {
221
+ this._subTreeListeners.set(
222
+ subTree.name,
223
+ this._createSubtreeActionButton(subTree),
224
+ );
225
+ }
226
+ });
216
227
  }
217
228
 
218
229
  /**
@@ -225,8 +236,8 @@ class ContentTreeCollection extends IndexedCollection {
225
236
  }
226
237
 
227
238
  /**
228
- * All ids of the currently managed subtrees. Ids are not persisted and will change if
229
- * the trees get recalculated. The first ID is always the default tree. Other ids are subtree ids.
239
+ * All ids of the currently managed subtrees.
240
+ * The first ID is always the default tree. Other ids are subtree ids.
230
241
  * Order of ids is dependent on their position in the collection and weight.
231
242
  * @type {Array<string>}
232
243
  * @readonly
@@ -303,15 +303,17 @@ class AbstractFeatureInfoView extends VcsObject {
303
303
  /**
304
304
  * This method is being called by featureInfo, whenever a new window is created (added to the windowManager).
305
305
  * May be overwritten by classes extending AbstractFeatureInfoView.
306
+ * @param {VcsUiApp} app
306
307
  * @param {FeatureInfoEvent} featureInfo
307
308
  * @param {import("@vcmap/core").Layer} layer
308
309
  * @returns {WindowComponentOptions}
309
310
  */
310
- getWindowComponentOptions(featureInfo, layer) {
311
+ getWindowComponentOptions(app, featureInfo, layer) {
311
312
  return {
312
313
  state: this.window.state ?? {
313
314
  headerTitle: layer.properties?.title || layer.name,
314
315
  headerIcon: '$vcsInfo',
316
+ infoUrl: app.getHelpUrlCallback('/tools/infoTool.html'),
315
317
  },
316
318
  slot: this.window.slot ?? WindowSlot.DYNAMIC_LEFT,
317
319
  component: this.component,
@@ -127,12 +127,13 @@ class BalloonFeatureInfoView extends AbstractFeatureInfoView {
127
127
  }
128
128
 
129
129
  /**
130
+ * @param {VcsUiApp} app
130
131
  * @param {FeatureInfoEvent} featureInfo
131
132
  * @param {import("@vcmap/core").Layer} layer
132
133
  * @returns {WindowComponentOptions}
133
134
  */
134
- getWindowComponentOptions(featureInfo, layer) {
135
- const options = super.getWindowComponentOptions(featureInfo, layer);
135
+ getWindowComponentOptions(app, featureInfo, layer) {
136
+ const options = super.getWindowComponentOptions(app, featureInfo, layer);
136
137
  options.state.hideHeader = true;
137
138
  options.state.classes = ['balloon'];
138
139
  options.slot = WindowSlot.DETACHED;
@@ -442,6 +442,7 @@ class FeatureInfo extends Collection {
442
442
  {
443
443
  id: this._windowId,
444
444
  ...usedFeatureInfoView.getWindowComponentOptions(
445
+ this._app,
445
446
  { feature, position, windowPosition },
446
447
  layer,
447
448
  ),
package/src/i18n/de.js CHANGED
@@ -113,6 +113,10 @@ const messages = {
113
113
  light: 'Hell',
114
114
  },
115
115
  },
116
+ help: {
117
+ title: 'Hilfe',
118
+ tooltip: 'Externe Hilfeseite in neuem Browser Tab öffnen',
119
+ },
116
120
  featureInfo: {
117
121
  activateToolTitle: 'Informationswerkzeug aktivieren',
118
122
  deactivateToolTitle: 'Informationswerkzeug deaktivieren',
package/src/i18n/en.js CHANGED
@@ -113,6 +113,10 @@ const messages = {
113
113
  light: 'Light',
114
114
  },
115
115
  },
116
+ help: {
117
+ title: 'Help',
118
+ tooltip: 'Open external help page in new browser tab',
119
+ },
116
120
  featureInfo: {
117
121
  activateToolTitle: 'Enable Info Tool',
118
122
  deactivateToolTitle: 'Disable Info Tool',
@@ -9,7 +9,11 @@
9
9
  </v-icon>
10
10
  {{ $t(title) }}
11
11
  </div>
12
- <VcsActionButtonList v-if="actions?.length > 0" :actions="actions" />
12
+ <VcsActionButtonList
13
+ v-if="actions?.length > 0"
14
+ :actions="actions"
15
+ :overflow-count="overflowCount"
16
+ />
13
17
  </div>
14
18
  </template>
15
19
  </v-expansion-panel-header>
@@ -85,6 +89,7 @@
85
89
  draggable: collectionComponent.draggable,
86
90
  selectable: collectionComponent.selectable,
87
91
  singleSelect: collectionComponent.singleSelect,
92
+ overflowCount: collectionComponent.overflowCount,
88
93
  limit: collectionComponent.limit,
89
94
  actions: collectionComponent.getActions(),
90
95
  move({ item, targetIndex }) {
@@ -13,6 +13,7 @@ import { sortByWeight } from '../buttonManager.js';
13
13
  * @property {boolean} [draggable] - only supported for IndexedCollections
14
14
  * @property {boolean} [selectable]
15
15
  * @property {boolean} [singleSelect]
16
+ * @property {number} [overflowCount=2] - number of header action buttons rendered until overflow
16
17
  * @property {number} [limit=10] - limit number of items in rendered list (more items are rendered in extra window)
17
18
  */
18
19
 
@@ -59,6 +60,11 @@ class CollectionComponent {
59
60
  * @type {import("vue").Ref<boolean>}
60
61
  */
61
62
  this.open = ref(false);
63
+ /**
64
+ *
65
+ * @type {import("vue").Ref<number>}
66
+ */
67
+ this.overflowCount = ref(parseNumber(options.overflowCount, 2));
62
68
  /**
63
69
  *
64
70
  * @type {import("vue").Ref<number>}
@@ -8,7 +8,7 @@
8
8
  :draggable="isDraggable"
9
9
  :class="{
10
10
  rounded: !isDocked,
11
- marginToTop: isDocked,
11
+ marginToTop: isDocked || !isChild,
12
12
  'rounded-br': isDynamicLeft,
13
13
  'rounded-bl': isDynamicRight,
14
14
  }"
@@ -20,6 +20,7 @@
20
20
  class="pa-2"
21
21
  :class="{
22
22
  'cursor-grab': isDynamic,
23
+ child: isChild,
23
24
  }"
24
25
  >
25
26
  <slot name="headerComponent" :props="$attrs" />
@@ -86,6 +87,7 @@
86
87
  provide(key, value);
87
88
  });
88
89
 
90
+ const isChild = computed(() => !!props.windowState.parentId);
89
91
  const isDynamic = computed(() => props.slotWindow !== WindowSlot.STATIC);
90
92
  const isDocked = computed(() => props.slotWindow !== WindowSlot.DETACHED);
91
93
  const isDockedLeft = computed(() => {
@@ -144,6 +146,7 @@
144
146
 
145
147
  return {
146
148
  isDynamic,
149
+ isChild,
147
150
  isDocked,
148
151
  isDynamicLeft: isDockedLeft,
149
152
  isDynamicRight: isDockedRight,
@@ -15,7 +15,7 @@
15
15
  class="d-inline-block user-select-none font-weight-bold"
16
16
  :class="{ 'text--primary': isOnTop }"
17
17
  >
18
- {{ $t(windowState.headerTitle) }}
18
+ {{ translatedHeaderTitle }}
19
19
  </span>
20
20
  </h3>
21
21
  <div class="d-flex justify-space-between align-center">
@@ -27,7 +27,7 @@
27
27
  <v-divider vertical inset class="mx-1" />
28
28
  </template>
29
29
  <VcsButton
30
- v-if="windowState.infoUrl"
30
+ v-if="infoAction"
31
31
  @click.stop="infoAction.callback()"
32
32
  :icon="infoAction.icon"
33
33
  :tooltip="infoAction.title"
@@ -65,7 +65,7 @@
65
65
 
66
66
  <script>
67
67
  import { VIcon, VDivider } from 'vuetify/lib';
68
- import { computed } from 'vue';
68
+ import { computed, getCurrentInstance } from 'vue';
69
69
  import VcsButton from '../../components/buttons/VcsButton.vue';
70
70
  import VcsActionButtonList from '../../components/buttons/VcsActionButtonList.vue';
71
71
  import { createLinkAction } from '../../actions/actionHelper.js';
@@ -75,6 +75,8 @@
75
75
  * @vue-prop {WindowState} windowState - state of the window component.
76
76
  * @vue-event {void} pin - raised when pin button is clicked
77
77
  * @vue-event {void} close - raised when close button is clicked
78
+ * @vue-computed {boolean} isDockable
79
+ * @vue-computed {string} translatedHeaderTitle - translates header title and joins array
78
80
  */
79
81
  export default {
80
82
  name: 'WindowComponentHeader',
@@ -110,21 +112,31 @@
110
112
  () => !props.windowState.hidePin && props.windowState.dockable,
111
113
  );
112
114
 
113
- const infoAction = props.windowState.infoUrl
114
- ? createLinkAction(
115
- {
116
- name: 'info',
117
- title: 'content.infoAction.title',
118
- icon: '$vcsInfo',
119
- },
120
- props.windowState.infoUrl,
121
- )
122
- : {};
115
+ const vm = getCurrentInstance().proxy;
116
+
117
+ const translatedHeaderTitle = computed(() =>
118
+ Array.isArray(props.windowState.headerTitle)
119
+ ? props.windowState.headerTitle.map((t) => vm.$t(t)).join(' ')
120
+ : vm.$t(props.windowState.headerTitle),
121
+ );
122
+
123
+ const infoAction =
124
+ props.windowState.infoUrl || props.windowState.infoUrlCallback
125
+ ? createLinkAction(
126
+ {
127
+ name: 'info',
128
+ title: 'content.infoAction.title',
129
+ icon: '$vcsHelp',
130
+ },
131
+ props.windowState.infoUrl || props.windowState.infoUrlCallback,
132
+ )
133
+ : undefined;
123
134
 
124
135
  return {
125
136
  pin,
126
137
  close,
127
138
  isDockable,
139
+ translatedHeaderTitle,
128
140
  infoAction,
129
141
  };
130
142
  },
@@ -120,11 +120,12 @@ export function isSlotPosition(windowPosition) {
120
120
  * @property {string|vcsAppSymbol} owner Owner of the window, set by windowManager on add
121
121
  * @property {boolean} [hideHeader] be used to not show the header.
122
122
  * @property {boolean} [hidePin] be used to not show the pin button.
123
- * @property {string} [headerTitle]
123
+ * @property {string|string[]} [headerTitle] An optional translatable header. If an array is provided all elements are translated and joined afterward.
124
124
  * @property {string} [headerIcon]
125
125
  * @property {Array<VcsAction>} [headerActions]
126
126
  * @property {number} [headerActionsOverflow]
127
127
  * @property {string} [infoUrl] An optional url referencing help or further information on the window's content.
128
+ * @property {function():string} [infoUrlCallback] An optional function returning an url referencing help or further information. Can be used for urls depending on the app's locale, e.g. app.getHelpUrl()
128
129
  * @property {boolean} [dockable] Auto derived from hidePin, current slot, current position and initial position.
129
130
  * @property {Object<string, string>} [styles] Can be used to add additional styles to the root WindowComponent. Use Vue Style Bindings Object Syntax https://vuejs.org/v2/guide/class-and-style.html
130
131
  * @property {Array<string>|Object<string,string>} [classes] Can be used to add additional classes to the root WindowComponent. Use Vue Class Bindings Syntax https://vuejs.org/v2/guide/class-and-style.html
@@ -466,6 +467,7 @@ class WindowManager {
466
467
  );
467
468
  }
468
469
  const id = windowComponentOptions.id || uuidv4();
470
+ const parentId = windowComponentOptions?.parentId;
469
471
  const slotOption =
470
472
  windowComponentOptions.slot?.value || windowComponentOptions.slot;
471
473
  const slot = parseEnumValue(slotOption, WindowSlot, WindowSlot.DETACHED);
@@ -492,6 +494,7 @@ class WindowManager {
492
494
 
493
495
  const state = reactive({
494
496
  id,
497
+ parentId,
495
498
  owner,
496
499
  hideHeader: !!windowComponentOptions?.state?.hideHeader,
497
500
  hidePin: !!windowComponentOptions?.state?.hidePin,
@@ -502,6 +505,7 @@ class WindowManager {
502
505
  windowComponentOptions?.state?.headerActionsOverflow,
503
506
  dockable: false,
504
507
  infoUrl: windowComponentOptions?.state?.infoUrl,
508
+ infoUrlCallback: windowComponentOptions?.state?.infoUrlCallback,
505
509
  classes,
506
510
  styles,
507
511
  });
@@ -520,7 +524,7 @@ class WindowManager {
520
524
  return id;
521
525
  },
522
526
  get parentId() {
523
- return windowComponentOptions?.parentId;
527
+ return parentId;
524
528
  },
525
529
  get state() {
526
530
  return state;
@@ -228,7 +228,7 @@ class OverviewMap {
228
228
  clone.activate();
229
229
  const idx = this._map.layerCollection.indexOf(clone);
230
230
  if (idx < 0) {
231
- this._map.layerCollection.add(clone, 0);
231
+ this._map.layerCollection.add(clone);
232
232
  } else {
233
233
  this._map.layerCollection.remove(clone);
234
234
  this._map.layerCollection.add(clone, idx);
package/src/uiConfig.js CHANGED
@@ -14,6 +14,7 @@ import { ref } from 'vue';
14
14
  * @property {string} [appTitle] - an optional title to display next to the company logo
15
15
  * @property {string} [primaryColor] - an optional primary color to use in all themes
16
16
  * @property {boolean} [startingFeatureInfo] - an optional flag whether to activate feature info on startup (default active)
17
+ * @property {string} [helpBaseUrl='https://help.vc.systems/'] - an optional URL to a help landing page
17
18
  */
18
19
 
19
20
  /**
package/src/vcsUiApp.js CHANGED
@@ -1,23 +1,23 @@
1
1
  import {
2
- VcsApp,
3
- moduleIdSymbol,
4
2
  Collection,
5
- makeOverrideCollection,
6
- destroyCollection,
7
- OverrideClassRegistry,
8
3
  defaultDynamicModuleId,
4
+ destroyCollection,
5
+ getObjectFromClassRegistry,
6
+ makeOverrideCollection,
7
+ moduleIdSymbol,
9
8
  ObliqueMap,
9
+ OverrideClassRegistry,
10
+ VcsApp,
11
+ VcsEvent,
10
12
  Viewpoint,
11
13
  volatileModuleId,
12
- VcsEvent,
13
- getObjectFromClassRegistry,
14
14
  } from '@vcmap/core';
15
15
  import { getLogger as getLoggerByName } from '@vcsuite/logger';
16
16
  import {
17
+ deserializePlugin,
17
18
  isValidPackageName,
18
19
  loadPlugin,
19
20
  serializePlugin,
20
- deserializePlugin,
21
21
  } from './pluginHelper.js';
22
22
  import ToolboxManager, {
23
23
  setupDefaultGroups,
@@ -443,6 +443,27 @@ class VcsUiApp extends VcsApp {
443
443
  return this._notifier;
444
444
  }
445
445
 
446
+ /**
447
+ * Returns a callback function providing a URL to help page.
448
+ * The default helpBaseUrl can be changed by adding an 'helpBaseUrl' item to the UiConfig Collection.
449
+ * The callback derives the url from the VC Map mayor and minor version, the current app locale and a provided path pointing to a specific help section.
450
+ * This function can be used for the WindowState infoUrlCallback property.
451
+ * @param {string} [path] - the path to a help section
452
+ * @param {string} [subpage='vc-map'] - path to a subpage. Default is 'vc-map'.
453
+ * @returns {function():string}
454
+ */
455
+ getHelpUrlCallback(path = '', subpage = 'vc-map') {
456
+ const mayorMinorVersion = /\d+\.\d+/.exec(VcsUiApp.getVersion())[0];
457
+ return () => {
458
+ const base =
459
+ this.uiConfig.config.value.helpBaseUrl || 'https://help.vc.systems/';
460
+ const url = `${subpage}-${this.locale}/v${mayorMinorVersion}/${path}`;
461
+ // const url = `${this.locale}/${subpage}/v${mayorMinorVersion}/${path}`;
462
+ const { href } = new URL(url, base);
463
+ return href.replace(/\/+/g, '/');
464
+ };
465
+ }
466
+
446
467
  /**
447
468
  * Get the state of the application. When passed the forUrl flag, only a minimal set of states shall be provided for a sharable link to the current state (to ensure
448
469
  * the maximum URL length is not exceeded). This includes: layer active state & styling, active map, active viewpoint,
@@ -1 +0,0 @@
1
- import{initAppFromAppConfig as p}from"./ui.3ed7ff.js";p("#app","app.config.json");
File without changes