@vcmap/ui 5.0.0-rc.10 → 5.0.0-rc.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -5
- package/build/build.js +6 -3
- package/build/buildHelpers.js +12 -4
- package/build/buildPreview.js +7 -0
- package/build/getPluginProxies.js +4 -0
- package/config/aerowest.config.json +13 -3
- package/config/base.config.json +398 -219
- package/config/codes.config.json +397 -0
- package/config/dev.config.json +375 -1
- package/config/graphFeatureInfo.config.json +100 -0
- package/config/www.config.json +1232 -0
- package/dist/assets/{cesium.eb5667.js → cesium.21663e.js} +0 -0
- package/dist/assets/cesium.js +1 -1
- package/dist/assets/core.63242d.js +4 -0
- package/dist/assets/core.js +1 -1
- package/dist/assets/font/OFL.txt +93 -0
- package/dist/assets/font/TitilliumWeb-Regular.woff2 +0 -0
- package/dist/assets/{index.4ccd4433.js → index.44b91cfe.js} +1 -1
- package/dist/assets/{ol.ef03b1.js → ol.88ba9d.js} +0 -0
- package/dist/assets/ol.js +1 -1
- package/dist/assets/ui.3c2933.css +1 -0
- package/dist/assets/ui.3c2933.js +71 -0
- package/dist/assets/ui.js +1 -1
- package/dist/assets/vue.c897fc.js +9 -0
- package/dist/assets/vue.js +2 -1
- package/dist/assets/{vuetify.401a29.css → vuetify.147c3a.css} +1 -1
- package/dist/assets/{vuetify.401a29.js → vuetify.147c3a.js} +72 -72
- package/dist/assets/vuetify.js +2 -2
- package/dist/index.html +1 -5
- package/index.js +39 -5
- package/lib/vue.js +1 -0
- package/map.config.json +15 -6
- package/package.json +17 -8
- package/plugins/@vcmap/create-link/fallbackCreateLink.vue +71 -0
- package/plugins/@vcmap/create-link/index.js +83 -0
- package/plugins/@vcmap/create-link/package.json +6 -0
- package/plugins/@vcmap/pluginExample/index.js +2 -2
- package/plugins/@vcmap/pluginExample/pluginExampleComponent.vue +20 -3
- package/plugins/@vcmap/project-selector/ProjectSelectorComponent.vue +1 -1
- package/plugins/@vcmap/project-selector/index.js +1 -1
- package/plugins/@vcmap/project-selector/package.json +1 -2
- package/plugins/@vcmap/theme-changer/ThemeChangerComponent.vue +1 -1
- package/plugins/@vcmap/theme-changer/index.js +1 -1
- package/plugins/@vcmap/theme-changer/package.json +1 -2
- package/plugins/categoryTest/Categories.vue +89 -1
- package/plugins/categoryTest/Category.vue +1 -1
- package/plugins/example/index.js +10 -23
- package/plugins/simple-graph/README.md +51 -0
- package/plugins/simple-graph/SimpleGraphComponent.vue +70 -0
- package/plugins/simple-graph/index.js +17 -0
- package/plugins/simple-graph/package.json +11 -0
- package/plugins/simple-graph/simpleGraphView.js +76 -0
- package/plugins/test/editor.vue +1 -1
- package/plugins/test/index.js +76 -9
- package/plugins/test/toolbox-data.js +82 -57
- package/plugins/test/windowManagerExample.vue +1 -1
- package/src/actions/stateRefAction.js +2 -2
- package/src/actions/styleSelector.vue +1 -1
- package/src/application/Navbar.vue +13 -2
- package/src/application/VcsApp.vue +301 -116
- package/src/application/VcsMap.vue +1 -1
- package/src/application/VcsSettings.vue +1 -1
- package/src/application/vcsAppWrapper.vue +1 -0
- package/src/assets/font/OFL.txt +93 -0
- package/src/assets/font/TitilliumWeb-Regular.woff2 +0 -0
- package/src/components/form-inputs-controls/VcsCheckbox.vue +13 -0
- package/src/components/form-inputs-controls/VcsColorPicker.vue +1 -1
- package/src/components/form-inputs-controls/VcsRadio.vue +123 -0
- package/src/components/form-output/VcsFormattedNumber.vue +1 -1
- package/src/components/lists/VcsActionList.vue +22 -7
- package/src/components/lists/VcsTreeview.vue +4 -4
- package/src/components/lists/VcsTreeviewLeaf.vue +10 -3
- package/src/components/lists/VcsTreeviewSearchbar.vue +1 -2
- package/src/components/tables/VcsTable.vue +245 -0
- package/src/contentTree/LayerTree.vue +1 -1
- package/src/contentTree/contentTreeCollection.js +4 -4
- package/src/contentTree/contentTreeItem.js +9 -9
- package/src/contentTree/groupContentTreeItem.js +1 -1
- package/src/contentTree/layerContentTreeItem.js +15 -1
- package/src/contentTree/layerGroupContentTreeItem.js +21 -1
- package/src/contentTree/nodeContentTreeItem.js +1 -1
- package/src/featureInfo/AddressBalloonComponent.vue +47 -0
- package/src/featureInfo/BalloonComponent.vue +140 -0
- package/src/featureInfo/abstractFeatureInfoView.js +313 -0
- package/src/featureInfo/addressBalloonFeatureInfoView.js +118 -0
- package/src/featureInfo/balloonFeatureInfoView.js +151 -0
- package/src/featureInfo/balloonHelper.js +132 -0
- package/src/featureInfo/featureInfo.js +457 -0
- package/src/featureInfo/featureInfoInteraction.js +42 -0
- package/src/featureInfo/iframeFeatureInfoView.js +95 -0
- package/src/featureInfo/tableFeatureInfoView.js +106 -0
- package/src/i18n/de.js +26 -0
- package/src/i18n/en.js +26 -0
- package/src/i18n/i18nCollection.js +17 -0
- package/src/icons/+all.js +80 -0
- package/src/icons/ClippingHorizontalIcon.vue +7 -0
- package/src/icons/ClippingIcon.vue +7 -0
- package/src/icons/ClippingVerticalIcon.vue +7 -0
- package/src/icons/ColorPickerIcon.vue +7 -0
- package/src/icons/ComponentsIcon.vue +2 -2
- package/src/icons/DimensionsHouseIcon.vue +11 -9
- package/src/icons/EditIcon.vue +7 -0
- package/src/icons/GlobalTerrainIcon.vue +9 -0
- package/src/icons/GroundIcon.vue +18 -0
- package/src/icons/HideIcon.vue +12 -0
- package/src/icons/LogoutIcon.vue +7 -0
- package/src/icons/ObjectAttributeIcon.vue +2 -13
- package/src/icons/PedestrianIcon.vue +2 -3
- package/src/icons/PenIcon.vue +2 -9
- package/src/icons/PoiIcon.vue +5 -2
- package/src/icons/PointSelectIcon.vue +4 -2
- package/src/icons/QueryIcon.vue +6 -7
- package/src/icons/ScreenshotIcon.vue +16 -0
- package/src/icons/ShareIcon.vue +4 -16
- package/src/icons/SkipNextIcon.vue +3 -1
- package/src/icons/TerrainBoxIcon.vue +9 -0
- package/src/icons/ToolsIcon.vue +4 -30
- package/src/icons/UploadIcon.vue +2 -9
- package/src/icons/UserProfileIcon.vue +7 -0
- package/src/icons/UserShareIcon.vue +7 -0
- package/src/icons/VideoRecorderIcon.vue +5 -9
- package/src/icons/ViewpointFlightIcon.vue +11 -0
- package/src/icons/ViewpointIcon.vue +11 -0
- package/src/icons/Viewshed360Icon.vue +7 -0
- package/src/icons/ViewshedConeIcon.vue +7 -0
- package/src/icons/ViewshedIcon.vue +7 -0
- package/src/icons/WallIcon.vue +4 -9
- package/src/legend/legendHelper.js +193 -0
- package/src/legend/styleLegendItem.vue +129 -0
- package/src/legend/vcsLegend.vue +92 -0
- package/src/manager/buttonManager.js +7 -12
- package/src/manager/categoryManager/ComponentsManager.vue +30 -0
- package/src/manager/categoryManager/categoryManager.js +500 -0
- package/src/manager/contextMenu/contextMenuComponent.vue +43 -0
- package/src/manager/contextMenu/contextMenuInteraction.js +42 -0
- package/src/manager/contextMenu/contextMenuManager.js +197 -0
- package/src/manager/navbarManager.js +9 -9
- package/src/manager/toolbox/GroupToolboxComponent.vue +118 -0
- package/src/manager/toolbox/SelectToolboxComponent.vue +128 -0
- package/src/manager/toolbox/ToolboxManager.vue +116 -98
- package/src/manager/toolbox/toolboxManager.js +235 -86
- package/src/manager/window/WindowComponent.vue +1 -1
- package/src/manager/window/WindowManager.vue +5 -3
- package/src/manager/window/windowManager.js +118 -14
- package/src/navigation/mapNavigation.vue +3 -5
- package/src/navigation/overviewMap.js +28 -5
- package/src/navigation/vcsCompass.vue +1 -1
- package/src/pluginHelper.js +42 -10
- package/src/setup.js +0 -2
- package/src/state.js +256 -0
- package/src/styles/_theming.scss +0 -5
- package/src/styles/variables.scss +7 -0
- package/src/styles/vcsFont.scss +17 -0
- package/src/uiConfig.js +79 -0
- package/src/vcsUiApp.js +213 -22
- package/src/vuePlugins/vuetify.js +14 -4
- package/config/berlin.config.json +0 -510
- package/dist/assets/core.216494.js +0 -4
- package/dist/assets/ui.99a1a7.css +0 -1
- package/dist/assets/ui.99a1a7.js +0 -70
- package/dist/assets/vue-composition-api.c5aca1.js +0 -14
- package/dist/assets/vue-composition-api.js +0 -2
- package/dist/assets/vue.762edd.js +0 -9
- package/lib/vue-composition-api.js +0 -2
- package/src/manager/toolbox/ToolboxGroupComponent.vue +0 -128
@@ -0,0 +1,197 @@
|
|
1
|
+
import { CesiumMap, BaseOLMap } from '@vcmap/core';
|
2
|
+
import { unByKey } from 'ol/Observable.js';
|
3
|
+
import { check } from '@vcsuite/check';
|
4
|
+
import ContextMenuInteraction from './contextMenuInteraction.js';
|
5
|
+
import { vcsAppSymbol } from '../../pluginHelper.js';
|
6
|
+
import { validateAction } from '../../components/lists/VcsActionList.vue';
|
7
|
+
import { getFittedWindowPositionOptionsFromMapEvent, WindowSlot } from '../window/windowManager.js';
|
8
|
+
import ContextMenuComponent, { contextMenuWindowId } from './contextMenuComponent.vue';
|
9
|
+
import { sortByOwner } from '../navbarManager.js';
|
10
|
+
|
11
|
+
/**
|
12
|
+
* @typedef {Object} ContextMenuEventHandler
|
13
|
+
* @property {string|symbol} owner
|
14
|
+
* @property {function(import("@vcmap/core").InteractionEvent):Promise<Array<VcsAction>>|Array<VcsAction>} handler
|
15
|
+
*/
|
16
|
+
|
17
|
+
/**
|
18
|
+
* @param {import("@vcmap/core").VcsMap} map
|
19
|
+
* @param {function():void} clear
|
20
|
+
* @returns {function():void} - returns stop listener function.
|
21
|
+
*/
|
22
|
+
function setupViewPointChanged(map, clear) {
|
23
|
+
const currentViewpoint = map.getViewPointSync();
|
24
|
+
const postRenderHandler = () => {
|
25
|
+
if (!currentViewpoint.equals(map.getViewPointSync(), 0.001)) {
|
26
|
+
clear();
|
27
|
+
}
|
28
|
+
};
|
29
|
+
|
30
|
+
if (map instanceof CesiumMap) {
|
31
|
+
return map.getScene().postRender.addEventListener(postRenderHandler);
|
32
|
+
} else if (map instanceof BaseOLMap) {
|
33
|
+
const key = map.olMap.on('postrender', postRenderHandler);
|
34
|
+
return () => {
|
35
|
+
unByKey(key);
|
36
|
+
};
|
37
|
+
}
|
38
|
+
return () => {};
|
39
|
+
}
|
40
|
+
|
41
|
+
/**
|
42
|
+
* The context menu manager handles right click events in the current map and displays a
|
43
|
+
* context menu based on registered action providers.
|
44
|
+
* @class
|
45
|
+
*/
|
46
|
+
class ContextMenuManager {
|
47
|
+
/**
|
48
|
+
* @param {VcsUiApp} app
|
49
|
+
*/
|
50
|
+
constructor(app) {
|
51
|
+
/**
|
52
|
+
* @type {VcsUiApp}
|
53
|
+
* @private
|
54
|
+
*/
|
55
|
+
this._app = app;
|
56
|
+
/**
|
57
|
+
* @type {ContextMenuInteraction}
|
58
|
+
* @private
|
59
|
+
*/
|
60
|
+
this._interaction = new ContextMenuInteraction(
|
61
|
+
this._handleRightClick.bind(this),
|
62
|
+
async () => {
|
63
|
+
this.clear();
|
64
|
+
},
|
65
|
+
);
|
66
|
+
/**
|
67
|
+
* @type {Array<ContextMenuEventHandler>}
|
68
|
+
* @private
|
69
|
+
*/
|
70
|
+
this._eventHandlers = [];
|
71
|
+
/**
|
72
|
+
* @type {function():void|null}
|
73
|
+
* @private
|
74
|
+
*/
|
75
|
+
this._interactionListener = null;
|
76
|
+
/**
|
77
|
+
* @type {Array<function():void>}
|
78
|
+
* @private
|
79
|
+
*/
|
80
|
+
this._listeners = [];
|
81
|
+
}
|
82
|
+
|
83
|
+
_ensureInteraction() {
|
84
|
+
if (!this._interactionListener) {
|
85
|
+
this._interactionListener = this._app.maps.eventHandler.addPersistentInteraction(this._interaction);
|
86
|
+
}
|
87
|
+
}
|
88
|
+
|
89
|
+
_setupListeners() {
|
90
|
+
const clear = this.clear.bind(this);
|
91
|
+
this._listeners = [
|
92
|
+
this._app.layers.stateChanged.addEventListener(clear),
|
93
|
+
this._app.maps.mapActivated.addEventListener(clear),
|
94
|
+
setupViewPointChanged(this._app.maps.activeMap, clear),
|
95
|
+
];
|
96
|
+
}
|
97
|
+
|
98
|
+
/**
|
99
|
+
* @param {import("@vcmap/core").InteractionEvent} event
|
100
|
+
* @private
|
101
|
+
*/
|
102
|
+
async _handleRightClick(event) {
|
103
|
+
this.clear();
|
104
|
+
const actionArrays = await Promise.all(this._eventHandlers.map(({ handler }) => handler(event)));
|
105
|
+
const actions = actionArrays
|
106
|
+
.filter(i => Array.isArray(i))
|
107
|
+
.flatMap(i => i)
|
108
|
+
.filter(validateAction);
|
109
|
+
|
110
|
+
if (actions.length > 0) {
|
111
|
+
const position = getFittedWindowPositionOptionsFromMapEvent(event.windowPosition, 320, actions.length * 32);
|
112
|
+
if (position.left) { // ensure we nudge the window, so it does not trigger the default right click.
|
113
|
+
position.left += 1;
|
114
|
+
} else {
|
115
|
+
position.right += 1;
|
116
|
+
}
|
117
|
+
|
118
|
+
this._app.windowManager.add({
|
119
|
+
id: contextMenuWindowId,
|
120
|
+
component: ContextMenuComponent,
|
121
|
+
state: {
|
122
|
+
hideHeader: true,
|
123
|
+
},
|
124
|
+
props: {
|
125
|
+
actions,
|
126
|
+
showIcon: true,
|
127
|
+
},
|
128
|
+
position,
|
129
|
+
slow: WindowSlot.DETACHED,
|
130
|
+
}, vcsAppSymbol);
|
131
|
+
|
132
|
+
this._setupListeners();
|
133
|
+
}
|
134
|
+
}
|
135
|
+
|
136
|
+
/**
|
137
|
+
* Adds a handler to the context menu. A handler is called with the interaction event on each right click.
|
138
|
+
* If the handler returns an array of valid actions, said actions will be displayed in the context menu
|
139
|
+
* @param {function(import("@vcmap/core").InteractionEvent):Promise<Array<VcsAction>>|Array<VcsAction>} handler
|
140
|
+
* @param {string|symbol} owner
|
141
|
+
*/
|
142
|
+
addEventHandler(handler, owner) {
|
143
|
+
check(handler, Function);
|
144
|
+
check(owner, [String, vcsAppSymbol]);
|
145
|
+
|
146
|
+
this._ensureInteraction();
|
147
|
+
this._eventHandlers.push({ owner, handler });
|
148
|
+
const order = [...this._app.plugins].map(p => p.name);
|
149
|
+
this._eventHandlers.sort((a, b) => {
|
150
|
+
return sortByOwner(a.owner, b.owner, order);
|
151
|
+
});
|
152
|
+
}
|
153
|
+
|
154
|
+
/**
|
155
|
+
* Remove a single handler
|
156
|
+
* @param {function(import("@vcmap/core").InteractionEvent):Promise<Array<VcsAction>>|Array<VcsAction>} handler
|
157
|
+
*/
|
158
|
+
removeHandler(handler) {
|
159
|
+
this._eventHandlers = this._eventHandlers.filter(({ handler: itemHandler }) => itemHandler !== handler);
|
160
|
+
if (this._eventHandlers.length === 0 && this._interactionListener) {
|
161
|
+
this._interactionListener();
|
162
|
+
this._interactionListener = null;
|
163
|
+
}
|
164
|
+
}
|
165
|
+
|
166
|
+
/**
|
167
|
+
* Remove all handlers associated with this owner
|
168
|
+
* @param {string|symbol} owner
|
169
|
+
*/
|
170
|
+
removeOwner(owner) {
|
171
|
+
this._eventHandlers = this._eventHandlers.filter(({ owner: handlerOwner }) => handlerOwner !== owner);
|
172
|
+
if (this._eventHandlers.length === 0 && this._interactionListener) {
|
173
|
+
this._interactionListener();
|
174
|
+
this._interactionListener = null;
|
175
|
+
}
|
176
|
+
}
|
177
|
+
|
178
|
+
/**
|
179
|
+
* Clear any currently opened context menus
|
180
|
+
*/
|
181
|
+
clear() {
|
182
|
+
this._listeners.forEach((cb) => { cb(); });
|
183
|
+
this._listeners = [];
|
184
|
+
this._app.windowManager.remove(contextMenuWindowId);
|
185
|
+
}
|
186
|
+
|
187
|
+
destroy() {
|
188
|
+
this._interaction.destroy();
|
189
|
+
if (this._interactionListener) {
|
190
|
+
this._interactionListener();
|
191
|
+
this._interactionListener = null;
|
192
|
+
}
|
193
|
+
this._eventHandlers = [];
|
194
|
+
}
|
195
|
+
}
|
196
|
+
|
197
|
+
export default ContextMenuManager;
|
@@ -1,20 +1,20 @@
|
|
1
1
|
import { check } from '@vcsuite/check';
|
2
|
-
import
|
2
|
+
import ButtonManager from './buttonManager.js';
|
3
3
|
import { vcsAppSymbol } from '../pluginHelper.js';
|
4
4
|
|
5
5
|
export const locationSymbol = Symbol('location');
|
6
6
|
|
7
7
|
/**
|
8
8
|
* sorts by owner and optionally plugin order
|
9
|
-
* @param {
|
10
|
-
* @param {
|
9
|
+
* @param {string | symbol} ownerA
|
10
|
+
* @param {string | symbol} ownerB
|
11
11
|
* @param {string[]} [order] order of owners to sort by
|
12
12
|
* @returns {number}
|
13
13
|
*/
|
14
|
-
function sortByOwner(
|
14
|
+
export function sortByOwner(ownerA, ownerB, order = []) {
|
15
15
|
const sorted = [vcsAppSymbol, ...order];
|
16
|
-
const indexA = sorted.indexOf(
|
17
|
-
const indexB = sorted.indexOf(
|
16
|
+
const indexA = sorted.indexOf(ownerA);
|
17
|
+
const indexB = sorted.indexOf(ownerB);
|
18
18
|
|
19
19
|
if (indexA === indexB) {
|
20
20
|
return 0;
|
@@ -35,19 +35,19 @@ function sortByOwner(a, b, order = []) {
|
|
35
35
|
* @param {Array<ButtonComponent>} buttonComponents
|
36
36
|
* @param {ButtonLocation} location Button render position
|
37
37
|
* @param {string[]} [order] optional order to sort by (plugin names)
|
38
|
-
* @param {function(
|
38
|
+
* @param {function(ownerA:string, ownerB:string, order: string[]):number} [compareFn=sortByOwner] Per default components are sorted by owner: app first, then plugins
|
39
39
|
* @returns {Array<VcsAction>}
|
40
40
|
*/
|
41
41
|
export function getActionsByLocation(buttonComponents, location, order = [], compareFn = sortByOwner) {
|
42
42
|
return [...buttonComponents]
|
43
43
|
.filter(b => b[locationSymbol] === location)
|
44
|
-
.sort((a, b) => compareFn(a, b, order))
|
44
|
+
.sort((a, b) => compareFn(a.owner, b.owner, order))
|
45
45
|
.map(b => b.action);
|
46
46
|
}
|
47
47
|
|
48
48
|
/**
|
49
49
|
* Possible render positions of buttons in navbar from left to right
|
50
|
-
* @enum
|
50
|
+
* @enum {number}
|
51
51
|
*/
|
52
52
|
export const ButtonLocation = {
|
53
53
|
MAP: 0,
|
@@ -0,0 +1,118 @@
|
|
1
|
+
<template>
|
2
|
+
<div v-if="orderedButtons.length > 0">
|
3
|
+
<v-menu
|
4
|
+
v-model="open"
|
5
|
+
@input="$emit('toggle', open)"
|
6
|
+
offset-y
|
7
|
+
:nudge-left="nudgeLeft"
|
8
|
+
z-index="0"
|
9
|
+
>
|
10
|
+
<template #activator="{ on, attrs }">
|
11
|
+
<VcsButton
|
12
|
+
class="vcs-toolbox-toogle-button"
|
13
|
+
width="48"
|
14
|
+
:icon="group.icon"
|
15
|
+
:tooltip="group.title"
|
16
|
+
:active="open || hasActiveAction"
|
17
|
+
:color="hasActiveAction ? 'primary' : 'basic'"
|
18
|
+
v-bind="attrs"
|
19
|
+
v-on="on"
|
20
|
+
large
|
21
|
+
>
|
22
|
+
<v-icon v-text="open ? 'mdi-chevron-up' : 'mdi-chevron-down'" color="accent" class="text--darken-3" />
|
23
|
+
</VcsButton>
|
24
|
+
</template>
|
25
|
+
|
26
|
+
<v-toolbar
|
27
|
+
id="vcs-toolbox-toolbar--secondary"
|
28
|
+
class="vcs-toolbox-2 toolbar__secondary mx-auto v-sheet marginToTop"
|
29
|
+
:height="40"
|
30
|
+
width="fit-content"
|
31
|
+
color="basic"
|
32
|
+
dense
|
33
|
+
>
|
34
|
+
<v-toolbar-items class="w-full">
|
35
|
+
<div class="d-flex align-center justify-space-between w-full mx-1">
|
36
|
+
<VcsButton
|
37
|
+
v-for="({id, action}) in orderedButtons"
|
38
|
+
:key="id"
|
39
|
+
:tooltip="action.title"
|
40
|
+
:icon="action.icon"
|
41
|
+
:active="action.active"
|
42
|
+
@click="action.callback($event)"
|
43
|
+
v-bind="{...$attrs}"
|
44
|
+
large
|
45
|
+
/>
|
46
|
+
</div>
|
47
|
+
</v-toolbar-items>
|
48
|
+
</v-toolbar>
|
49
|
+
</v-menu>
|
50
|
+
</div>
|
51
|
+
</template>
|
52
|
+
<style lang="scss">
|
53
|
+
.vcs-toolbox-2 {
|
54
|
+
.v-toolbar__content {
|
55
|
+
padding: 0;
|
56
|
+
}
|
57
|
+
}
|
58
|
+
|
59
|
+
.marginToTop {
|
60
|
+
margin-top: 3px;
|
61
|
+
}
|
62
|
+
</style>
|
63
|
+
<script>
|
64
|
+
import { computed, ref } from 'vue';
|
65
|
+
import VcsButton from '../../components/buttons/VcsButton.vue';
|
66
|
+
import { getComponentsByOrder } from './toolboxManager.js';
|
67
|
+
|
68
|
+
/**
|
69
|
+
* @description
|
70
|
+
* A Toolbox Button rendering a menu dropdown with actions using {@link https://vuetifyjs.com/en/api/v-menu/|vuetify v-menu} and {@link VcsButton}.
|
71
|
+
* The button is rendered in primary color if at least one action is active.
|
72
|
+
* The button is rendered in basic color if menu is open and no action is active.
|
73
|
+
* @vue-prop {GroupToolboxComponent} group - A toolbox group of type 'group'.
|
74
|
+
* @vue-computed {Array<ButtonComponent>} buttons - Buttons of the group.
|
75
|
+
* @vue-computed {Array<ButtonComponent>} orderedButtons - Buttons of the group sorted by owner.
|
76
|
+
* @vue-computed {boolean} hasActiveAction - Whether the group has an active action.
|
77
|
+
* @vue-computed {number} nudgeLeft - offset of the dropdown toolbar to the left
|
78
|
+
*/
|
79
|
+
export default {
|
80
|
+
name: 'ToolboxActionGroup',
|
81
|
+
components: { VcsButton },
|
82
|
+
props: {
|
83
|
+
group: {
|
84
|
+
type: Object,
|
85
|
+
required: true,
|
86
|
+
},
|
87
|
+
},
|
88
|
+
setup(props) {
|
89
|
+
const open = ref(false);
|
90
|
+
|
91
|
+
const buttons = computed(() => {
|
92
|
+
const { buttonManager } = props.group;
|
93
|
+
const buttonIds = ref(buttonManager.componentIds);
|
94
|
+
return buttonIds.value.map(id => buttonManager.get(id));
|
95
|
+
});
|
96
|
+
const orderedButtons = computed(() => getComponentsByOrder(buttons.value));
|
97
|
+
const hasActiveAction = computed(() => orderedButtons.value.some(a => a.action.active));
|
98
|
+
|
99
|
+
/**
|
100
|
+
* v-menu auto prop is not working as expected.
|
101
|
+
* Workaround using hardcoded button sizes and paddings
|
102
|
+
* @type {ComputedRef<number>}
|
103
|
+
*/
|
104
|
+
const nudgeLeft = computed(() => {
|
105
|
+
const toolboxBtnWidth = 42 + 8; // with padding
|
106
|
+
const menuBtnWidth = 48;
|
107
|
+
return (buttons.value.length * (toolboxBtnWidth / 2)) - (menuBtnWidth / 2);
|
108
|
+
});
|
109
|
+
|
110
|
+
return {
|
111
|
+
open,
|
112
|
+
orderedButtons,
|
113
|
+
nudgeLeft,
|
114
|
+
hasActiveAction,
|
115
|
+
};
|
116
|
+
},
|
117
|
+
};
|
118
|
+
</script>
|
@@ -0,0 +1,128 @@
|
|
1
|
+
<template>
|
2
|
+
<div
|
3
|
+
v-if="group.action"
|
4
|
+
:class="{ 'vcs-toolbox-action-select-button--active': open }"
|
5
|
+
style="width:fit-content"
|
6
|
+
>
|
7
|
+
<VcsButton
|
8
|
+
:key="group.action.tools[group.action.currentIndex].name"
|
9
|
+
:tooltip="group.action.tools[group.action.currentIndex].title"
|
10
|
+
:icon="group.action.tools[group.action.currentIndex].icon"
|
11
|
+
:active="group.action.active"
|
12
|
+
@click.stop="group.action.callback($event)"
|
13
|
+
v-bind="{...$attrs}"
|
14
|
+
class="vcs-toolbox-action-selected"
|
15
|
+
:min-width="32"
|
16
|
+
:width="32"
|
17
|
+
large
|
18
|
+
/>
|
19
|
+
<v-menu
|
20
|
+
v-model="open"
|
21
|
+
@input="$emit('toggle', open)"
|
22
|
+
offset-y
|
23
|
+
:nudge-left="nudgeLeft"
|
24
|
+
z-index="0"
|
25
|
+
>
|
26
|
+
<template #activator="{ on, attrs }">
|
27
|
+
<VcsButton
|
28
|
+
:tooltip="group.action.title"
|
29
|
+
v-bind="attrs"
|
30
|
+
v-on="on"
|
31
|
+
class="vcs-toolbox-action-select"
|
32
|
+
:min-width="16"
|
33
|
+
:width="16"
|
34
|
+
large
|
35
|
+
>
|
36
|
+
<v-icon v-text="open ? 'mdi-chevron-up' : 'mdi-chevron-down'" color="accent" class="text--darken-3" />
|
37
|
+
</VcsButton>
|
38
|
+
</template>
|
39
|
+
|
40
|
+
<v-toolbar
|
41
|
+
class="vcs-toolbox-2 toolbar__secondary mx-auto v-sheet marginToTop justify-center"
|
42
|
+
:height="40"
|
43
|
+
width="fit-content"
|
44
|
+
color="basic"
|
45
|
+
dense
|
46
|
+
>
|
47
|
+
<v-toolbar-items class="w-full">
|
48
|
+
<div class="d-flex align-center justify-space-between w-full mx-1">
|
49
|
+
<VcsButton
|
50
|
+
v-for="(item, index) in group.action.tools"
|
51
|
+
:key="`${item.name}-${index}`"
|
52
|
+
:tooltip="item.title"
|
53
|
+
:icon="item.icon"
|
54
|
+
@click="group.action.selected(index)"
|
55
|
+
v-bind="{...$attrs}"
|
56
|
+
large
|
57
|
+
/>
|
58
|
+
</div>
|
59
|
+
</v-toolbar-items>
|
60
|
+
</v-toolbar>
|
61
|
+
</v-menu>
|
62
|
+
</div>
|
63
|
+
</template>
|
64
|
+
<style lang="scss">
|
65
|
+
.vcs-toolbox-action-selected > .v-btn.vcs-button--large {
|
66
|
+
max-width: 40px;
|
67
|
+
}
|
68
|
+
|
69
|
+
.vcs-toolbox-action-select > .v-btn.vcs-button--large {
|
70
|
+
max-width: 8px;
|
71
|
+
}
|
72
|
+
|
73
|
+
.vcs-toolbox-action-select-button--active {
|
74
|
+
//border: 2px solid var(--v-basic-base);
|
75
|
+
border-radius: 5px;
|
76
|
+
background: var(--v-basic-base);
|
77
|
+
}
|
78
|
+
|
79
|
+
.vcs-toolbox-2 {
|
80
|
+
.v-toolbar__content {
|
81
|
+
padding: 0;
|
82
|
+
}
|
83
|
+
}
|
84
|
+
|
85
|
+
.marginToTop {
|
86
|
+
margin-top: 3px;
|
87
|
+
}
|
88
|
+
</style>
|
89
|
+
<script>
|
90
|
+
import { ref, computed } from 'vue';
|
91
|
+
import VcsButton from '../../components/buttons/VcsButton.vue';
|
92
|
+
|
93
|
+
/**
|
94
|
+
* @description
|
95
|
+
* A dynamic Toolbox Button rendering a selected item and a dropdown to select an item using {@link https://vuetifyjs.com/en/api/v-menu/|vuetify v-menu} and {@link VcsButton}.
|
96
|
+
* @vue-prop {SelectToolboxComponent} group - A toolbox group of type 'select'.
|
97
|
+
* @vue-computed {number} nudgeLeft - offset of the dropdown toolbar to the left
|
98
|
+
*/
|
99
|
+
export default {
|
100
|
+
name: 'ToolboxActionSelect',
|
101
|
+
components: { VcsButton },
|
102
|
+
props: {
|
103
|
+
group: {
|
104
|
+
type: Object,
|
105
|
+
required: true,
|
106
|
+
},
|
107
|
+
},
|
108
|
+
setup(props) {
|
109
|
+
const open = ref(false);
|
110
|
+
|
111
|
+
/**
|
112
|
+
* v-menu auto prop is not working as expected.
|
113
|
+
* Workaround using hardcoded button sizes and paddings
|
114
|
+
* @type {ComputedRef<number>}
|
115
|
+
*/
|
116
|
+
const nudgeLeft = computed(() => {
|
117
|
+
const toolboxBtnWidth = 42 + 8; // with padding
|
118
|
+
const menuBtnWidth = 16;
|
119
|
+
return (props.group.action.tools.length * (toolboxBtnWidth / 2)) + (menuBtnWidth / 2);
|
120
|
+
});
|
121
|
+
|
122
|
+
return {
|
123
|
+
open,
|
124
|
+
nudgeLeft,
|
125
|
+
};
|
126
|
+
},
|
127
|
+
};
|
128
|
+
</script>
|