@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.
- package/dist/assets/cesium.js +1 -1
- package/dist/assets/{core-40347ebd.js → core-1d7afc4a.js} +482 -474
- package/dist/assets/core.js +1 -1
- package/dist/assets/ol.js +1 -1
- package/dist/assets/ui-21d54a73.css +1 -0
- package/dist/assets/{ui-2ffb4653.js → ui-21d54a73.js} +8462 -8350
- package/dist/assets/ui.js +1 -1
- package/dist/assets/vue.js +1 -1
- package/dist/assets/{vuetify-b7b7e394.js → vuetify-e7de6710.js} +1 -1
- package/dist/assets/vuetify.js +1 -1
- package/package.json +2 -2
- package/src/application/VcsNavbar.vue +4 -1
- package/src/components/buttons/VcsToolButton.vue +2 -2
- package/src/components/form-inputs-controls/VcsChipArrayInput.vue +1 -1
- package/src/components/form-inputs-controls/VcsFileInput.vue +1 -1
- package/src/components/form-inputs-controls/VcsTextArea.vue +1 -1
- package/src/components/form-inputs-controls/VcsTextField.vue +1 -1
- package/src/components/lists/VcsList.vue +31 -40
- package/src/components/lists/VcsList.vue.d.ts +3 -9
- package/src/components/lists/VcsTreeviewSearchbar.vue +7 -1
- package/src/components/lists/VcsTreeviewSearchbar.vue.d.ts +1 -0
- package/src/components/tables/VcsTable.vue +2 -9
- package/src/legend/VcsLegend.vue +16 -6
- package/src/manager/window/WindowComponent.vue +15 -12
- package/src/pluginHelper.js +1 -0
- package/src/search/ResultItem.vue +5 -22
- package/src/search/ResultItem.vue.d.ts +1 -1
- package/src/search/markText.d.ts +10 -0
- package/src/search/markText.js +63 -0
- package/src/state.d.ts +19 -3
- package/src/state.js +87 -5
- package/src/vcsUiApp.js +7 -0
- package/dist/assets/ui-2ffb4653.css +0 -1
- /package/dist/assets/{cesium-e01742ab.js → cesium-72d0b355.js} +0 -0
- /package/dist/assets/{ol-13735e8d.js → ol-6dcd0d3d.js} +0 -0
- /package/dist/assets/{vue-7d362088.js → vue-24ff798c.js} +0 -0
- /package/dist/assets/{vuetify-b7b7e394.css → vuetify-e7de6710.css} +0 -0
package/dist/assets/ui.js
CHANGED
@@ -1 +1 @@
|
|
1
|
-
export * from "./ui-
|
1
|
+
export * from "./ui-21d54a73.js";
|
package/dist/assets/vue.js
CHANGED
@@ -1 +1 @@
|
|
1
|
-
export * from "./vue-
|
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-
|
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() {
|
package/dist/assets/vuetify.js
CHANGED
@@ -1 +1 @@
|
|
1
|
-
export * from "./vuetify-
|
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.
|
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.
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
-
@
|
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
|
-
|
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 #
|
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"
|
package/src/legend/VcsLegend.vue
CHANGED
@@ -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(
|
92
|
+
const panels = ref(handledEntries.slice());
|
91
93
|
|
92
94
|
watch(props.entries, () => {
|
93
|
-
|
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
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
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 {
|
package/src/pluginHelper.js
CHANGED
@@ -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(() =>
|
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<
|
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,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
|
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)];
|