@vcmap/ui 6.0.10 → 6.0.12

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 (37) hide show
  1. package/dist/assets/cesium.js +1 -1
  2. package/dist/assets/{core-40347ebd.js → core-1d7afc4a.js} +482 -474
  3. package/dist/assets/core.js +1 -1
  4. package/dist/assets/ol.js +1 -1
  5. package/dist/assets/ui-21d54a73.css +1 -0
  6. package/dist/assets/{ui-2ffb4653.js → ui-21d54a73.js} +8462 -8350
  7. package/dist/assets/ui.js +1 -1
  8. package/dist/assets/vue.js +1 -1
  9. package/dist/assets/{vuetify-b7b7e394.js → vuetify-e7de6710.js} +1 -1
  10. package/dist/assets/vuetify.js +1 -1
  11. package/package.json +2 -2
  12. package/src/application/VcsNavbar.vue +4 -1
  13. package/src/components/buttons/VcsToolButton.vue +2 -2
  14. package/src/components/form-inputs-controls/VcsChipArrayInput.vue +1 -1
  15. package/src/components/form-inputs-controls/VcsFileInput.vue +1 -1
  16. package/src/components/form-inputs-controls/VcsTextArea.vue +1 -1
  17. package/src/components/form-inputs-controls/VcsTextField.vue +1 -1
  18. package/src/components/lists/VcsList.vue +31 -40
  19. package/src/components/lists/VcsList.vue.d.ts +3 -9
  20. package/src/components/lists/VcsTreeviewSearchbar.vue +7 -1
  21. package/src/components/lists/VcsTreeviewSearchbar.vue.d.ts +1 -0
  22. package/src/components/tables/VcsTable.vue +2 -9
  23. package/src/legend/VcsLegend.vue +16 -6
  24. package/src/manager/window/WindowComponent.vue +15 -12
  25. package/src/pluginHelper.js +1 -0
  26. package/src/search/ResultItem.vue +5 -22
  27. package/src/search/ResultItem.vue.d.ts +1 -1
  28. package/src/search/markText.d.ts +10 -0
  29. package/src/search/markText.js +63 -0
  30. package/src/state.d.ts +19 -3
  31. package/src/state.js +87 -5
  32. package/src/vcsUiApp.js +7 -0
  33. package/dist/assets/ui-2ffb4653.css +0 -1
  34. /package/dist/assets/{cesium-e01742ab.js → cesium-72d0b355.js} +0 -0
  35. /package/dist/assets/{ol-13735e8d.js → ol-6dcd0d3d.js} +0 -0
  36. /package/dist/assets/{vue-7d362088.js → vue-24ff798c.js} +0 -0
  37. /package/dist/assets/{vuetify-b7b7e394.css → vuetify-e7de6710.css} +0 -0
package/dist/assets/ui.js CHANGED
@@ -1 +1 @@
1
- export * from "./ui-2ffb4653.js";
1
+ export * from "./ui-21d54a73.js";
@@ -1 +1 @@
1
- export * from "./vue-7d362088.js";
1
+ export * from "./vue-24ff798c.js";
@@ -10,7 +10,7 @@ function loadCss(href) {
10
10
  elem.onerror = reject;
11
11
  document.head.appendChild(elem);
12
12
  });
13
- } await loadCss('./assets/vuetify-b7b7e394.css');import { watch as X, onScopeDispose as tt, effectScope as Ul, shallowRef as K, Fragment as ie, reactive as it, computed as b, watchEffect as Ne, toRefs as Wt, capitalize as On, isVNode as Oc, Comment as Rc, unref as ot, warn as Ha, getCurrentInstance as Nc, ref as W, provide as Ae, inject as ye, defineComponent as Hc, camelize as Ir, h as jt, toRaw as Ee, createVNode as r, mergeProps as N, onBeforeUnmount as nt, readonly as Kl, onDeactivated as _r, onActivated as zc, onMounted as Ke, nextTick as Se, TransitionGroup as ql, Transition as Ht, isRef as _n, toRef as F, onBeforeMount as Xl, withDirectives as $e, resolveDirective as dt, vShow as xt, onUpdated as Wc, Text as jc, resolveDynamicComponent as Yc, markRaw as Gc, Teleport as Uc, cloneVNode as Kc, createTextVNode as Pt, onUnmounted as qc, onBeforeUpdate as Xc, withModifiers as Pl, toDisplayString as Zc, vModelText as Qc, resolveComponent as Jc, render as Tr } from "./vue-7d362088.js";
13
+ } await loadCss('./assets/vuetify-e7de6710.css');import { watch as X, onScopeDispose as tt, effectScope as Ul, shallowRef as K, Fragment as ie, reactive as it, computed as b, watchEffect as Ne, toRefs as Wt, capitalize as On, isVNode as Oc, Comment as Rc, unref as ot, warn as Ha, getCurrentInstance as Nc, ref as W, provide as Ae, inject as ye, defineComponent as Hc, camelize as Ir, h as jt, toRaw as Ee, createVNode as r, mergeProps as N, onBeforeUnmount as nt, readonly as Kl, onDeactivated as _r, onActivated as zc, onMounted as Ke, nextTick as Se, TransitionGroup as ql, Transition as Ht, isRef as _n, toRef as F, onBeforeMount as Xl, withDirectives as $e, resolveDirective as dt, vShow as xt, onUpdated as Wc, Text as jc, resolveDynamicComponent as Yc, markRaw as Gc, Teleport as Uc, cloneVNode as Kc, createTextVNode as Pt, onUnmounted as qc, onBeforeUpdate as Xc, withModifiers as Pl, toDisplayString as Zc, vModelText as Qc, resolveComponent as Jc, render as Tr } from "./vue-24ff798c.js";
14
14
  function rt(e, n) {
15
15
  let t;
16
16
  function a() {
@@ -1 +1 @@
1
- export * from "./vuetify-b7b7e394.js";
1
+ export * from "./vuetify-e7de6710.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vcmap/ui",
3
- "version": "6.0.10",
3
+ "version": "6.0.12",
4
4
  "author": "Virtual City Systems",
5
5
  "license": "MIT",
6
6
  "scripts": {
@@ -57,7 +57,7 @@
57
57
  },
58
58
  "peerDependencies": {
59
59
  "@vcmap-cesium/engine": "^11.0.2",
60
- "@vcmap/core": "^6.0.6",
60
+ "@vcmap/core": "^6.0.7",
61
61
  "ol": "^10.2.1",
62
62
  "vue": "~3.4.38",
63
63
  "vuetify": "^3.7.3"
@@ -48,7 +48,7 @@
48
48
  </div>
49
49
  </v-toolbar-items>
50
50
  </v-col>
51
- <v-col class="d-flex justify-center">
51
+ <v-col class="d-flex justify-center flex-grow-2 mx-2">
52
52
  <div class="d-flex align-center">
53
53
  <template v-if="!xs">
54
54
  <img class="logo" :src="logo" draggable="false" alt="Logo" />
@@ -133,6 +133,9 @@
133
133
  bottom: 0;
134
134
  position: fixed;
135
135
  }
136
+ .flex-grow-2 {
137
+ flex-grow: 2;
138
+ }
136
139
  </style>
137
140
 
138
141
  <script>
@@ -73,7 +73,7 @@
73
73
  import { useFontSize } from '../../vuePlugins/vuetify.js';
74
74
 
75
75
  /**
76
- * @description a button with tooltip extending {@link https://vuetifyjs.com/en/api/v-btn/|vuetify v-btn} using {@link VcsTooltip}. Used for tool buttons in the Navbar.
76
+ * @description a button with tooltip extending {@link https://vuetifyjs.com/en/api/v-btn/\|vuetify v-btn}. Used for tool buttons in the Navbar.
77
77
  * @vue-prop {boolean} active - Whether button has background color. Applies vuetify primary color if color property is not set.
78
78
  * @vue-prop {boolean} disabled - Whether button is disabled.
79
79
  * @vue-prop {string} color - Passes property to v-btn in case prop active is true.
@@ -82,7 +82,7 @@
82
82
  * @vue-prop {string} icon - When given, will display an icon in the button. Replaces vuetify icon property.
83
83
  * @vue-prop {string} tooltip - Text content of a tooltip which appears on hover with default delay.
84
84
  * @vue-prop {('bottom' | 'left' | 'top' | 'right')} tooltipPosition - Position of the tooltip.
85
- * @vue-prop {Object<string, any>} tooltipProps - Properties to be passed to VcsTooltip {@link https://vuetifyjs.com/en/api/v-tooltip/#props|vuetify v-tooltip}
85
+ * @vue-prop {Object<string, any>} tooltipProps - Properties to be passed to the tooltip {@link https://vuetifyjs.com/en/api/v-tooltip/#props|vuetify v-tooltip}
86
86
  * @vue-computed {string} appliedColor - color applied to button, depending on size and state
87
87
  * @vue-computed {boolean} hasDefaultSlot
88
88
  */
@@ -116,7 +116,7 @@
116
116
 
117
117
  /**
118
118
  * @description Renders elements of an array as chips with an input field to edit or add new elements.
119
- * Provides VcsTooltip to show error messages on focus
119
+ * Provides a tooltip to show error messages on focus
120
120
  * When clicking esc key, previous input is restored.
121
121
  * @vue-prop {T[]} modelValue
122
122
  * @vue-prop {string} [type] - The input type (string or number)
@@ -57,7 +57,7 @@
57
57
 
58
58
  /**
59
59
  * @description extends API of {@link https://vuetifyjs.com/en/api/v-file-input v-text-field}.
60
- * Provides VcsTooltip to
60
+ * Provides a tooltip to
61
61
  * - show error messages on focus
62
62
  * - show tooltips, if supplied, when hovered over append-icon
63
63
  * When clicking esc key, previous input is restored.
@@ -146,7 +146,7 @@
146
146
  /**
147
147
  * @description extends API of {@link https://vuetifyjs.com/en/api/v-textarea/|vuetify v-textarea}.
148
148
  * Default for number of rows can be overwritten using the vuetify API.
149
- * Provides VcsTooltip to
149
+ * Provides a tooltip to
150
150
  * - show error messages on focus
151
151
  * - show tooltips, if no error messages are available
152
152
  * @vue-prop {('bottom' | 'left' | 'top' | 'right')} [tooltipPosition='right'] - Position of the error tooltip.
@@ -76,7 +76,7 @@
76
76
 
77
77
  /**
78
78
  * @description extends API of {@link https://vuetifyjs.com/en/api/v-text-field v-text-field}.
79
- * Provides VcsTooltip to
79
+ * Provides a tooltip to
80
80
  * - show error messages on focus
81
81
  * - show tooltips, if no error messages are available
82
82
  * When clicking esc key, previous input is restored.
@@ -5,7 +5,7 @@
5
5
  :placeholder="searchbarPlaceholder"
6
6
  v-model="query"
7
7
  />
8
- <v-list :class="{ 'vcs-list__selectable': selectable }">
8
+ <v-list>
9
9
  <v-list-item v-if="showTitle && title">
10
10
  <template #prepend>
11
11
  <v-icon v-if="icon">
@@ -39,11 +39,12 @@
39
39
  :key="`item-${index}`"
40
40
  :active="selected.includes(item)"
41
41
  @mousedown.shift="$event.preventDefault()"
42
- @mouseover="hovering = index"
43
- @mouseout="hovering = undefined"
44
42
  :draggable="isDraggable"
45
43
  @dragstart="drag($event, item, index)"
46
- @mouseup="drop($event, index)"
44
+ @dragover.prevent="dragOver($event, index)"
45
+ @dragend="dragEnd($event)"
46
+ @drop="drop($event, index)"
47
+ @dragleave="dragLeave($event, index)"
47
48
  :class="{
48
49
  'v-list-item__selected': selected.includes(item),
49
50
  'v-list-item__lighten_even': lightenEven,
@@ -342,7 +343,7 @@
342
343
  }
343
344
  draggedItem = null;
344
345
  dragging.value = undefined;
345
- document.removeEventListener('mouseup', drop);
346
+ hovering.value = undefined;
346
347
  }
347
348
  }
348
349
 
@@ -352,14 +353,32 @@
352
353
  * @param {number} index
353
354
  */
354
355
  function drag(e, item, index) {
356
+ e.stopPropagation();
355
357
  if (isDraggable.value) {
356
358
  dragging.value = index;
357
359
  draggedItem = item;
358
360
  e.dataTransfer.effectAllowed = 'move';
359
- document.addEventListener('mouseup', drop);
360
361
  }
361
362
  }
362
363
 
364
+ function dragOver(e, index) {
365
+ e.stopPropagation();
366
+ e.preventDefault();
367
+ hovering.value = index;
368
+ }
369
+
370
+ function dragLeave(e) {
371
+ e.stopPropagation();
372
+ e.preventDefault();
373
+ hovering.value = undefined;
374
+ }
375
+
376
+ function dragEnd(e) {
377
+ e.stopPropagation();
378
+ dragging.value = undefined;
379
+ hovering.value = undefined;
380
+ }
381
+
363
382
  /**
364
383
  * @type {import("vue").ComputedRef<Array<import("./VcsListItemComponent.vue").VcsListItem>>}
365
384
  */
@@ -410,15 +429,15 @@
410
429
  * @param {PointerEvent} event
411
430
  */
412
431
  select(item, event) {
432
+ if (!props.selectable || item.disabled) {
433
+ return;
434
+ }
413
435
  if (!isReactive(item)) {
414
436
  throw new Error('Trying to select an unreactive item');
415
437
  }
416
438
  if (Array.isArray(item.clickedCallbacks)) {
417
439
  item.clickedCallbacks.forEach((cb) => cb(event));
418
440
  }
419
- if (!props.selectable || item.disabled) {
420
- return;
421
- }
422
441
  if (props.singleSelect) {
423
442
  if (selected.value[0] === item) {
424
443
  item.selectionChanged?.(false);
@@ -499,39 +518,11 @@
499
518
 
500
519
  emit('update:modelValue', selected.value);
501
520
  },
502
- /**
503
- * @param {import("vue").UnwrapNestedRefs<import("./VcsListItemComponent.vue").VcsListItem>} item
504
- */
505
- add(item) {
506
- if (!isReactive(item)) {
507
- throw new Error('Trying to select an unreactive item');
508
- }
509
- if (!selected.value.includes(item) && !item.disabled) {
510
- item.selectionChanged?.(true);
511
- selected.value = [...selected.value, item];
512
- emit('update:modelValue', selected.value);
513
- }
514
- },
515
- /**
516
- * @param {import("vue").UnwrapNestedRefs<import("./VcsListItemComponent.vue").VcsListItem>} item
517
- */
518
- remove(item) {
519
- if (selected.value.includes(item) && !item.disabled) {
520
- item.selectionChanged?.(false);
521
- selected.value = selected.value.filter((i) => i !== item);
522
- emit('update:modelValue', selected.value);
523
- }
524
- },
525
- clear() {
526
- selected.value
527
- .filter((i) => i.selectionChanged)
528
- .forEach((i) => i.selectionChanged(false));
529
- selected.value = [];
530
- firstSelected = null;
531
- emit('update:modelValue', selected.value);
532
- },
533
521
  drag,
534
522
  drop,
523
+ dragOver,
524
+ dragLeave,
525
+ dragEnd,
535
526
  listHeader,
536
527
  listHeaderTooltip: createEllipseTooltip(
537
528
  computed(() => listHeader.value?.$el),
@@ -86,17 +86,11 @@ declare const _default: import("vue").DefineComponent<{
86
86
  * @param {PointerEvent} event
87
87
  */
88
88
  select(item: any, event: PointerEvent): void;
89
- /**
90
- * @param {import("vue").UnwrapNestedRefs<import("./VcsListItemComponent.vue").VcsListItem>} item
91
- */
92
- add(item: import("vue").UnwrapNestedRefs<import("./VcsListItemComponent.vue").VcsListItem>): void;
93
- /**
94
- * @param {import("vue").UnwrapNestedRefs<import("./VcsListItemComponent.vue").VcsListItem>} item
95
- */
96
- remove(item: import("vue").UnwrapNestedRefs<import("./VcsListItemComponent.vue").VcsListItem>): void;
97
- clear(): void;
98
89
  drag: (e: MouseEvent, item: import("./VcsListItemComponent.vue").VcsListItem, index: number) => void;
99
90
  drop: (e: MouseEvent, targetIndex: number) => void;
91
+ dragOver: (e: any, index: any) => void;
92
+ dragLeave: (e: any) => void;
93
+ dragEnd: (e: any) => void;
100
94
  listHeader: import("vue").Ref<any>;
101
95
  listHeaderTooltip: import("vue").ComputedRef<string>;
102
96
  hasIntermediateSlot: import("vue").ComputedRef<boolean>;
@@ -1,5 +1,6 @@
1
1
  <template>
2
2
  <div
3
+ v-bind="noListenerAttrs"
3
4
  class="pa-2 bg-base-lighten-3 position-relative d-flex flex-row justify-space-between align-center rounded-0 vcs-treeview-searchbar"
4
5
  >
5
6
  <slot name="prepend">
@@ -76,9 +77,11 @@
76
77
  </style>
77
78
 
78
79
  <script>
80
+ import { computed } from 'vue';
79
81
  import { VIcon } from 'vuetify/components';
80
82
  import VcsTextField from '../form-inputs-controls/VcsTextField.vue';
81
83
  import { useIconSize } from '../../vuePlugins/vuetify.js';
84
+ import { removeListenersFromAttrs } from '../attrsHelpers.js';
82
85
 
83
86
  /**
84
87
  * @description stylized searchbar used in VcsTreeview, VcsDataTable and VcsList
@@ -91,6 +94,7 @@
91
94
  */
92
95
  export default {
93
96
  name: 'VcsTreeviewSearchbar',
97
+ inheritAttrs: false,
94
98
  components: {
95
99
  VIcon,
96
100
  VcsTextField,
@@ -105,10 +109,12 @@
105
109
  default: false,
106
110
  },
107
111
  },
108
- setup() {
112
+ setup(_, { attrs }) {
109
113
  const iconSize = useIconSize();
114
+ const noListenerAttrs = computed(() => removeListenersFromAttrs(attrs));
110
115
  return {
111
116
  iconSize,
117
+ noListenerAttrs,
112
118
  };
113
119
  },
114
120
  };
@@ -9,6 +9,7 @@ declare const _default: import("vue").DefineComponent<{
9
9
  };
10
10
  }, {
11
11
  iconSize: import("vue").ComputedRef<number>;
12
+ noListenerAttrs: import("vue").ComputedRef<Record<string, unknown>>;
12
13
  }, any, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
13
14
  placeholder: {
14
15
  type: StringConstructor;
@@ -5,15 +5,8 @@
5
5
  :items="items"
6
6
  :headers="[keyHeader, valueHeader]"
7
7
  >
8
- <template #body="{ page, itemsPerPage }">
9
- <tr
10
- class="v-data-table__tr"
11
- v-for="(item, idx) in items.slice(
12
- (page - 1) * itemsPerPage,
13
- page * itemsPerPage,
14
- )"
15
- :key="`row-${idx}`"
16
- >
8
+ <template #item="{ index, item }">
9
+ <tr class="v-data-table__tr" :key="`row-${index}`">
17
10
  <vcs-table-cell :title="item.key" :width="keyHeader.width" />
18
11
  <vcs-table-cell
19
12
  :title="item.value"
@@ -13,7 +13,6 @@
13
13
  :value="entry.key"
14
14
  :heading="entry.title"
15
15
  :header-actions="entry.actions"
16
- @group:selected="entry.open = !entry.open"
17
16
  >
18
17
  <v-list class="pl-6 pb-2">
19
18
  <div v-for="(item, idx) in entry.legend" :key="idx">
@@ -84,13 +83,27 @@
84
83
  iframe.style.height = `${iframe.contentWindow.document.documentElement.scrollHeight}px`;
85
84
  };
86
85
 
86
+ let handledEntries = props.entries
87
+ .filter((e) => e.open)
88
+ .map((e) => e.key);
87
89
  /**
88
90
  * @type {import("vue").Ref<string[]>}
89
91
  */
90
- const panels = ref(props.entries.filter((e) => e.open).map((e) => e.key));
92
+ const panels = ref(handledEntries.slice());
91
93
 
92
94
  watch(props.entries, () => {
93
- panels.value = props.entries.filter((e) => e.open).map((e) => e.key);
95
+ props.entries.forEach((e) => {
96
+ if (!handledEntries.includes(e.key)) {
97
+ handledEntries.push(e.key);
98
+ panels.value.push(e.key);
99
+ }
100
+ });
101
+ handledEntries = handledEntries.filter((key) =>
102
+ props.entries.find((e) => e.key === key),
103
+ );
104
+ panels.value = panels.value.filter((key) =>
105
+ props.entries.find((e) => e.key === key),
106
+ );
94
107
  });
95
108
 
96
109
  const cid = useComponentId();
@@ -110,7 +123,4 @@
110
123
  max-width: 100%;
111
124
  height: auto;
112
125
  }
113
- .rotate {
114
- transform: rotate(-90deg);
115
- }
116
126
  </style>
@@ -129,24 +129,27 @@
129
129
  if (!isDraggable.value) {
130
130
  e.preventDefault();
131
131
  e.stopPropagation();
132
+ } else {
133
+ startEvent = e;
134
+ // set mouse cursor to move
135
+ e.dataTransfer.effectAllowed = 'move';
132
136
  }
133
- startEvent = e;
134
- // set mouse cursor to move
135
- e.dataTransfer.effectAllowed = 'move';
136
137
  };
137
138
  /**
138
139
  * @param {DragEvent} endEvent
139
140
  */
140
141
  const dragEnd = (endEvent) => {
141
- const movement = {
142
- dx: endEvent.clientX - startEvent.clientX,
143
- dy: endEvent.clientY - startEvent.clientY,
144
- };
145
- emit('moved', movement);
146
- startEvent = null;
147
- isDraggable.value = false;
148
- endEvent.target.parentElement.ondragover = null;
149
- app.maps.target.ondragover = null;
142
+ if (isDraggable.value) {
143
+ const movement = {
144
+ dx: endEvent.clientX - startEvent.clientX,
145
+ dy: endEvent.clientY - startEvent.clientY,
146
+ };
147
+ emit('moved', movement);
148
+ startEvent = null;
149
+ isDraggable.value = false;
150
+ endEvent.target.parentElement.ondragover = null;
151
+ app.maps.target.ondragover = null;
152
+ }
150
153
  };
151
154
 
152
155
  return {
@@ -186,6 +186,7 @@ export function getPluginEntry(base, pluginUrl) {
186
186
  const baseUrl = new URL(base);
187
187
  const pluginModuleUrl = new URL(pluginUrl);
188
188
  pluginModuleUrl.searchParams.delete('version'); // semver is part of config
189
+ pluginModuleUrl.searchParams.delete('mapVersion'); // semver is set on loadPlugin by the app
189
190
  if (baseUrl.origin !== pluginModuleUrl.origin) {
190
191
  return pluginModuleUrl.toString();
191
192
  }
@@ -32,28 +32,9 @@
32
32
  VListItemTitle,
33
33
  VTooltip,
34
34
  } from 'vuetify/components';
35
+ import DOMPurify from 'dompurify';
35
36
  import VcsActionButtonList from '../components/buttons/VcsActionButtonList.vue';
36
-
37
- /**
38
- * @param {string} text
39
- * @param {string} query
40
- * @returns {string}
41
- */
42
- function markText(text, query) {
43
- let replacement = text;
44
- if (query) {
45
- const partials = query
46
- .split(/[.,\s]/)
47
- .filter((partial) => partial.trim());
48
- partials.forEach((partial) => {
49
- replacement = replacement.replaceAll(
50
- new RegExp(`(^|[^>])(${partial})`, 'ig'),
51
- '<span>$1<span class="text-primary">$2</span></span>',
52
- );
53
- });
54
- }
55
- return replacement;
56
- }
37
+ import { markText } from './markText.js';
57
38
 
58
39
  /**
59
40
  * @description ResultItem with optional icon or image, title and optional actions
@@ -83,7 +64,9 @@
83
64
  },
84
65
  setup(props) {
85
66
  const hasActions = computed(() => props.item?.actions?.length > 0);
86
- const marked = computed(() => markText(props.item.title, props.query));
67
+ const marked = computed(() =>
68
+ DOMPurify.sanitize(markText(props.item.title, props.query)),
69
+ );
87
70
 
88
71
  return {
89
72
  hasActions,
@@ -9,7 +9,7 @@ declare const _default: import("vue").DefineComponent<{
9
9
  };
10
10
  }, {
11
11
  hasActions: import("vue").ComputedRef<boolean>;
12
- marked: import("vue").ComputedRef<string>;
12
+ marked: import("vue").ComputedRef<any>;
13
13
  }, any, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
14
14
  query: {
15
15
  type: StringConstructor;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * @param {string} text
3
+ * @param {string} query
4
+ * @returns {string}
5
+ */
6
+ export function markText(text: string, query: string): string;
7
+ export type Block = {
8
+ start: number;
9
+ end: number;
10
+ };
@@ -0,0 +1,63 @@
1
+ /**
2
+ * @typedef {Object} Block
3
+ * @property {number} start
4
+ * @property {number} end
5
+ */
6
+
7
+ /**
8
+ * @param {Block[]} blocks
9
+ * @param {Block} candidate
10
+ * @returns {boolean}
11
+ */
12
+ function isBlockWithinBlocks(blocks, candidate) {
13
+ return blocks.some(
14
+ (block) => candidate.start >= block.start && candidate.end <= block.end,
15
+ );
16
+ }
17
+
18
+ /**
19
+ * @param {string} text
20
+ * @param {RegExp} partial
21
+ * @param {Block[]} blocks
22
+ */
23
+ function addPartialBlocks(text, partial, blocks) {
24
+ let match;
25
+ // eslint-disable-next-line no-cond-assign
26
+ while ((match = partial.exec(text))) {
27
+ const block = {
28
+ start: match.index,
29
+ end: match.index + match[0].length,
30
+ };
31
+ if (!isBlockWithinBlocks(blocks, block)) {
32
+ blocks.push(block);
33
+ }
34
+ }
35
+ }
36
+
37
+ /**
38
+ * @param {string} text
39
+ * @param {string} query
40
+ * @returns {string}
41
+ */
42
+ // eslint-disable-next-line import/prefer-default-export
43
+ export function markText(text, query) {
44
+ let replacement = text;
45
+ if (query) {
46
+ const partials = query
47
+ .split(/[.,\s]/)
48
+ .map((p) => p.trim())
49
+ .filter((p) => !!p)
50
+ .sort((a, b) => b.length - a.length); // we sort partials by length so we can ensure smaller partials aren't already covered by larger ones
51
+
52
+ const blocks = [];
53
+ partials.forEach((partial) => {
54
+ addPartialBlocks(text, new RegExp(partial, 'ig'), blocks);
55
+ });
56
+
57
+ blocks.sort((a, b) => a.start - b.start);
58
+ blocks.reverse().forEach((block) => {
59
+ replacement = `${replacement.substring(0, block.start)}<span class="text-primary">${replacement.substring(block.start, block.end)}</span>${replacement.substring(block.end)}`;
60
+ });
61
+ }
62
+ return replacement;
63
+ }
package/src/state.d.ts CHANGED
@@ -2,6 +2,16 @@
2
2
  * @returns {AppState}
3
3
  */
4
4
  export function createEmptyState(): AppState;
5
+ /**
6
+ * @param {UrlViewpointState} state
7
+ * @returns {import("@vcmap/core").ViewpointOptions|null}
8
+ */
9
+ export function parseUrlProjectedViewpointState(state: UrlViewpointState): import("@vcmap/core").ViewpointOptions | null;
10
+ /**
11
+ * @param {UrlExtentState} state
12
+ * @returns {import("@vcmap/core").ViewpointOptions|null}
13
+ */
14
+ export function parseUrlExtentState(state: UrlExtentState): import("@vcmap/core").ViewpointOptions | null;
5
15
  /**
6
16
  * @param {(URL)=} url
7
17
  * @returns {AppState}
@@ -35,9 +45,14 @@ export type UrlPluginState = [string, unknown];
35
45
  /**
36
46
  * The URL state of a viewpoint is an array, the first entry is the camera position (or 0)
37
47
  * the second is the ground position (or 0), the third is the distance, the last three are
38
- * heading, pitch, roll in that order
48
+ * heading, pitch, roll in that order follow by an optional projection code
49
+ */
50
+ export type UrlViewpointState = [Array<number> | 0, Array<number> | 0, number, number, number, number, number?];
51
+ /**
52
+ * The URL state of an Extent is an array, the first entry is the extent
53
+ * the second is the projection code if needed.
39
54
  */
40
- export type UrlViewpointState = [Array<number> | 0, Array<number> | 0, number, number, number, number];
55
+ export type UrlExtentState = [import("ol/extent").Extent, number];
41
56
  export type AppState = {
42
57
  activeViewpoint?: import("@vcmap/core").ViewpointOptions | undefined;
43
58
  activeMap?: string | undefined;
@@ -46,6 +61,7 @@ export type AppState = {
46
61
  plugins: Array<PluginState<unknown>>;
47
62
  activeObliqueCollection?: string | undefined;
48
63
  };
64
+ export type CachedAppState = AppState;
49
65
  /**
50
66
  * The URL state of the app is an array. To null parameters, pass in 0 instead.
51
67
  * The first entry is the viewpoint state, the second the active map name
@@ -54,4 +70,4 @@ export type AppState = {
54
70
  * the fifth is an array of plugin states
55
71
  * the sixth is the currently active oblique collection or 0 if not applicable
56
72
  */
57
- export type UrlAppState = [[0 | number[], 0 | number[], number, number, number, number], string, Array<string>, Array<[string, number, string | 0]>, Array<[string, unknown]>, (string | 0)];
73
+ export type UrlAppState = [[0 | number[], 0 | number[], number, number, number, number, (number | undefined)?] | [import("ol/extent").Extent, number], string, Array<string>, Array<[string, number, string | 0]>, Array<[string, unknown]>, (string | 0)];