@vcmap/ui 5.0.0-rc.12 → 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.
Files changed (37) hide show
  1. package/README.md +1 -1
  2. package/dist/assets/{cesium.4057e6.js → cesium.21663e.js} +0 -0
  3. package/dist/assets/cesium.js +1 -1
  4. package/dist/assets/{core.deb2b7.js → core.63242d.js} +1 -1
  5. package/dist/assets/core.js +1 -1
  6. package/dist/assets/{index.7aa11f5a.js → index.44b91cfe.js} +1 -1
  7. package/dist/assets/{ol.70b137.js → ol.88ba9d.js} +0 -0
  8. package/dist/assets/ol.js +1 -1
  9. package/dist/assets/ui.3c2933.css +1 -0
  10. package/dist/assets/{ui.9eb282.js → ui.3c2933.js} +43 -42
  11. package/dist/assets/ui.js +1 -1
  12. package/dist/assets/{vue.65d93f.js → vue.c897fc.js} +0 -0
  13. package/dist/assets/vue.js +2 -2
  14. package/dist/assets/{vuetify.149dde.css → vuetify.147c3a.css} +0 -0
  15. package/dist/assets/{vuetify.149dde.js → vuetify.147c3a.js} +1 -1
  16. package/dist/assets/vuetify.js +2 -2
  17. package/dist/index.html +1 -1
  18. package/index.js +1 -0
  19. package/package.json +12 -2
  20. package/plugins/example/index.js +10 -23
  21. package/plugins/test/index.js +13 -4
  22. package/plugins/test/toolbox-data.js +82 -57
  23. package/src/application/VcsApp.vue +1 -1
  24. package/src/components/lists/VcsActionList.vue +13 -7
  25. package/src/featureInfo/BalloonComponent.vue +2 -0
  26. package/src/featureInfo/featureInfo.js +5 -3
  27. package/src/i18n/de.js +4 -0
  28. package/src/i18n/en.js +4 -0
  29. package/src/manager/buttonManager.js +2 -7
  30. package/src/manager/navbarManager.js +1 -1
  31. package/src/manager/toolbox/GroupToolboxComponent.vue +118 -0
  32. package/src/manager/toolbox/SelectToolboxComponent.vue +128 -0
  33. package/src/manager/toolbox/ToolboxManager.vue +116 -99
  34. package/src/manager/toolbox/toolboxManager.js +233 -88
  35. package/src/vcsUiApp.js +1 -1
  36. package/dist/assets/ui.9eb282.css +0 -1
  37. package/src/manager/toolbox/ToolboxGroupComponent.vue +0 -132
package/dist/assets/ui.js CHANGED
@@ -1 +1 @@
1
- export * from "./ui.9eb282.js";
1
+ export * from "./ui.3c2933.js";
File without changes
@@ -1,2 +1,2 @@
1
- export * from "./vue.65d93f.js";
2
- export { default } from "./vue.65d93f.js";
1
+ export * from "./vue.c897fc.js";
2
+ export { default } from "./vue.c897fc.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.149dde.css');var Qr=Object.defineProperty,Jr=Object.defineProperties;var to=Object.getOwnPropertyDescriptors;var oe=Object.getOwnPropertySymbols;var Ki=Object.prototype.hasOwnProperty,Xi=Object.prototype.propertyIsEnumerable;var Ui=(t,e,i)=>e in t?Qr(t,e,{enumerable:!0,configurable:!0,writable:!0,value:i}):t[e]=i,s=(t,e)=>{for(var i in e||(e={}))Ki.call(e,i)&&Ui(t,i,e[i]);if(oe)for(var i of oe(e))Xi.call(e,i)&&Ui(t,i,e[i]);return t},h=(t,e)=>Jr(t,to(e));var q=(t,e)=>{var i={};for(var a in t)Ki.call(t,a)&&e.indexOf(a)<0&&(i[a]=t[a]);if(t!=null&&oe)for(var a of oe(t))e.indexOf(a)<0&&Xi.call(t,a)&&(i[a]=t[a]);return i};import _ from"./vue.65d93f.js";var qd=(()=>`.theme--light.v-application{background:#FFFFFF;color:#000000de}.theme--light.v-application .text--primary{color:#000000de!important}.theme--light.v-application .text--secondary{color:#0009!important}.theme--light.v-application .text--disabled{color:#00000061!important}.theme--dark.v-application{background:#121212;color:#fff}.theme--dark.v-application .text--primary{color:#fff!important}.theme--dark.v-application .text--secondary{color:#ffffffb3!important}.theme--dark.v-application .text--disabled{color:#ffffff80!important}.v-application{display:flex;position:relative}.v-application a{cursor:pointer}.v-application--is-rtl{direction:rtl}.v-application--wrap{flex:1 1 auto;backface-visibility:hidden;display:flex;flex-direction:column;min-height:100vh;max-width:100%;position:relative}@-moz-document url-prefix(){@media print{.v-application,.v-application--wrap{display:block}}}
13
+ } await loadCss('./assets/vuetify.147c3a.css');var Qr=Object.defineProperty,Jr=Object.defineProperties;var to=Object.getOwnPropertyDescriptors;var oe=Object.getOwnPropertySymbols;var Ki=Object.prototype.hasOwnProperty,Xi=Object.prototype.propertyIsEnumerable;var Ui=(t,e,i)=>e in t?Qr(t,e,{enumerable:!0,configurable:!0,writable:!0,value:i}):t[e]=i,s=(t,e)=>{for(var i in e||(e={}))Ki.call(e,i)&&Ui(t,i,e[i]);if(oe)for(var i of oe(e))Xi.call(e,i)&&Ui(t,i,e[i]);return t},h=(t,e)=>Jr(t,to(e));var q=(t,e)=>{var i={};for(var a in t)Ki.call(t,a)&&e.indexOf(a)<0&&(i[a]=t[a]);if(t!=null&&oe)for(var a of oe(t))e.indexOf(a)<0&&Xi.call(t,a)&&(i[a]=t[a]);return i};import _ from"./vue.c897fc.js";var qd=(()=>`.theme--light.v-application{background:#FFFFFF;color:#000000de}.theme--light.v-application .text--primary{color:#000000de!important}.theme--light.v-application .text--secondary{color:#0009!important}.theme--light.v-application .text--disabled{color:#00000061!important}.theme--dark.v-application{background:#121212;color:#fff}.theme--dark.v-application .text--primary{color:#fff!important}.theme--dark.v-application .text--secondary{color:#ffffffb3!important}.theme--dark.v-application .text--disabled{color:#ffffff80!important}.v-application{display:flex;position:relative}.v-application a{cursor:pointer}.v-application--is-rtl{direction:rtl}.v-application--wrap{flex:1 1 auto;backface-visibility:hidden;display:flex;flex-direction:column;min-height:100vh;max-width:100%;position:relative}@-moz-document url-prefix(){@media print{.v-application,.v-application--wrap{display:block}}}
14
14
  `)();const je=_.extend().extend({name:"themeable",provide(){return{theme:this.themeableProvide}},inject:{theme:{default:{isDark:!1}}},props:{dark:{type:Boolean,default:null},light:{type:Boolean,default:null}},data(){return{themeableProvide:{isDark:!1}}},computed:{appIsDark(){return this.$vuetify.theme.dark||!1},isDark(){return this.dark===!0?!0:this.light===!0?!1:this.theme.isDark},themeClasses(){return{"theme--dark":this.isDark,"theme--light":!this.isDark}},rootIsDark(){return this.dark===!0?!0:this.light===!0?!1:this.appIsDark},rootThemeClasses(){return{"theme--dark":this.rootIsDark,"theme--light":!this.rootIsDark}}},watch:{isDark:{handler(t,e){t!==e&&(this.themeableProvide.isDark=this.isDark)},immediate:!0}}});var y=je;function qi(t){const e=s(s({},t.props),t.injections),i=je.options.computed.isDark.call(e);return je.options.computed.themeClasses.call({isDark:i})}function v(...t){return _.extend({mixins:t})}var eo=v(y).extend({name:"v-app",props:{dark:{type:Boolean,default:void 0},id:{type:String,default:"app"},light:{type:Boolean,default:void 0}},computed:{isDark(){return this.$vuetify.theme.dark}},beforeCreate(){if(!this.$vuetify||this.$vuetify===this.$root)throw new Error("Vuetify is not properly initialized, see https://vuetifyjs.com/getting-started/quick-start#bootstrapping-the-vuetify-object")},render(t){const e=t("div",{staticClass:"v-application--wrap"},this.$slots.default);return t("div",{staticClass:"v-application",class:s({"v-application--is-rtl":this.$vuetify.rtl,"v-application--is-ltr":!this.$vuetify.rtl},this.themeClasses),attrs:{"data-app":!0},domProps:{id:this.id}},[e])}}),Zd=(()=>`.theme--light.v-app-bar.v-toolbar.v-sheet{background-color:#f5f5f5}.theme--dark.v-app-bar.v-toolbar.v-sheet{background-color:#272727}.v-sheet.v-app-bar.v-toolbar{border-radius:0}.v-sheet.v-app-bar.v-toolbar:not(.v-sheet--outlined){box-shadow:0 2px 4px -1px #0003,0 4px 5px #00000024,0 1px 10px #0000001f}.v-sheet.v-app-bar.v-toolbar.v-sheet--shaped{border-radius:24px 0}.v-app-bar:not([data-booted=true]){transition:none!important}.v-app-bar.v-app-bar--fixed{position:fixed;top:0;z-index:5}.v-app-bar.v-app-bar.v-app-bar--hide-shadow{box-shadow:0 0 #0003,0 0 #00000024,0 0 #0000001f!important}.v-app-bar--fade-img-on-scroll .v-toolbar__image .v-image__image{transition:.4s opacity cubic-bezier(.4,0,.2,1)}.v-app-bar.v-toolbar--prominent.v-app-bar--shrink-on-scroll .v-toolbar__image{will-change:opacity}.v-app-bar.v-toolbar--prominent.v-app-bar--shrink-on-scroll.v-app-bar--collapse-on-scroll .v-toolbar__extension{display:none}.v-app-bar.v-toolbar--prominent.v-app-bar--shrink-on-scroll.v-app-bar--is-scrolled .v-toolbar__title{padding-top:9px}.v-app-bar.v-toolbar--prominent.v-app-bar--shrink-on-scroll.v-app-bar--is-scrolled:not(.v-app-bar--bottom) .v-toolbar__title{padding-bottom:9px}.v-app-bar.v-app-bar--shrink-on-scroll .v-toolbar__title{font-size:inherit}.v-app-bar-title__placeholder,.v-app-bar-title__content{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.v-app-bar-title__content{position:absolute}
15
15
  `)(),Qd=(()=>`.theme--light.v-toolbar.v-sheet{background-color:#fff}.theme--dark.v-toolbar.v-sheet{background-color:#272727}.v-sheet.v-toolbar{border-radius:0}.v-sheet.v-toolbar:not(.v-sheet--outlined){box-shadow:0 2px 4px -1px #0003,0 4px 5px #00000024,0 1px 10px #0000001f}.v-sheet.v-toolbar.v-sheet--shaped{border-radius:24px 0}.v-toolbar{contain:layout;display:block;flex:1 1 auto;max-width:100%;transition:.2s cubic-bezier(.4,0,.2,1) transform,.2s cubic-bezier(.4,0,.2,1) background-color,.2s cubic-bezier(.4,0,.2,1) left,.2s cubic-bezier(.4,0,.2,1) right,.28s cubic-bezier(.4,0,.2,1) box-shadow,.25s cubic-bezier(.4,0,.2,1) max-width,.25s cubic-bezier(.4,0,.2,1) width;position:relative;box-shadow:0 2px 4px -1px #0003,0 4px 5px #00000024,0 1px 10px #0000001f}.v-toolbar .v-input{padding-top:0;margin-top:0}.v-toolbar__content,.v-toolbar__extension{padding:4px 16px}.v-toolbar__content .v-btn.v-btn--icon.v-size--default,.v-toolbar__extension .v-btn.v-btn--icon.v-size--default{height:48px;width:48px}.v-application--is-ltr .v-toolbar__content>.v-btn.v-btn--icon:first-child,.v-application--is-ltr .v-toolbar__extension>.v-btn.v-btn--icon:first-child{margin-left:-12px}.v-application--is-rtl .v-toolbar__content>.v-btn.v-btn--icon:first-child,.v-application--is-rtl .v-toolbar__extension>.v-btn.v-btn--icon:first-child{margin-right:-12px}.v-application--is-ltr .v-toolbar__content>.v-btn.v-btn--icon:first-child+.v-toolbar__title,.v-application--is-ltr .v-toolbar__extension>.v-btn.v-btn--icon:first-child+.v-toolbar__title{padding-left:20px}.v-application--is-rtl .v-toolbar__content>.v-btn.v-btn--icon:first-child+.v-toolbar__title,.v-application--is-rtl .v-toolbar__extension>.v-btn.v-btn--icon:first-child+.v-toolbar__title{padding-right:20px}.v-application--is-ltr .v-toolbar__content>.v-btn.v-btn--icon:last-child,.v-application--is-ltr .v-toolbar__extension>.v-btn.v-btn--icon:last-child{margin-right:-12px}.v-application--is-rtl .v-toolbar__content>.v-btn.v-btn--icon:last-child,.v-application--is-rtl .v-toolbar__extension>.v-btn.v-btn--icon:last-child{margin-left:-12px}.v-toolbar__content>.v-tabs,.v-toolbar__extension>.v-tabs{height:inherit;margin-top:-4px;margin-bottom:-4px}.v-toolbar__content>.v-tabs>.v-slide-group.v-tabs-bar,.v-toolbar__extension>.v-tabs>.v-slide-group.v-tabs-bar{background-color:inherit;height:inherit}.v-toolbar__content>.v-tabs:first-child,.v-toolbar__extension>.v-tabs:first-child{margin-left:-16px}.v-toolbar__content>.v-tabs:last-child,.v-toolbar__extension>.v-tabs:last-child{margin-right:-16px}.v-toolbar__content,.v-toolbar__extension{align-items:center;display:flex;position:relative;z-index:0}.v-toolbar__image{border-radius:inherit;position:absolute;top:0;bottom:0;width:100%;z-index:0;contain:strict}.v-toolbar__image .v-image{border-radius:inherit}.v-toolbar__items{display:flex;height:inherit}.v-toolbar__items>.v-btn{border-radius:0;height:100%!important;max-height:none}.v-toolbar__title{font-size:1.25rem;line-height:1.5;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.v-toolbar.v-toolbar--absolute{position:absolute;top:0;z-index:1}.v-toolbar.v-toolbar--bottom{top:initial;bottom:0}.v-toolbar.v-toolbar--collapse .v-toolbar__title{white-space:nowrap}.v-toolbar.v-toolbar--collapsed{max-width:112px;overflow:hidden}.v-application--is-ltr .v-toolbar.v-toolbar--collapsed{border-bottom-right-radius:24px}.v-application--is-rtl .v-toolbar.v-toolbar--collapsed{border-bottom-left-radius:24px}.v-toolbar.v-toolbar--collapsed .v-toolbar__title,.v-toolbar.v-toolbar--collapsed .v-toolbar__extension{display:none}.v-toolbar--dense .v-toolbar__content,.v-toolbar--dense .v-toolbar__extension{padding-top:0;padding-bottom:0}.v-toolbar--flat{box-shadow:0 0 #0003,0 0 #00000024,0 0 #0000001f!important}.v-toolbar--floating{display:inline-flex}.v-toolbar--prominent .v-toolbar__content{align-items:flex-start}.v-toolbar--prominent .v-toolbar__title{font-size:1.5rem;padding-top:6px}.v-toolbar--prominent:not(.v-toolbar--bottom) .v-toolbar__title{align-self:flex-end;padding-bottom:6px;padding-top:0}
16
16
  `)(),Jd=(()=>`.theme--light.v-sheet{background-color:#fff;border-color:#fff;color:#000000de}.theme--light.v-sheet--outlined{border:thin solid rgba(0,0,0,.12)}.theme--dark.v-sheet{background-color:#1e1e1e;border-color:#1e1e1e;color:#fff}.theme--dark.v-sheet--outlined{border:thin solid rgba(255,255,255,.12)}.v-sheet{border-radius:0}.v-sheet:not(.v-sheet--outlined){box-shadow:0 0 #0003,0 0 #00000024,0 0 #0000001f}.v-sheet.v-sheet--shaped{border-radius:24px 0}
@@ -1,2 +1,2 @@
1
- export * from "./vuetify.149dde.js";
2
- export { default } from "./vuetify.149dde.js";
1
+ export * from "./vuetify.147c3a.js";
2
+ export { default } from "./vuetify.147c3a.js";
package/dist/index.html CHANGED
@@ -3,7 +3,7 @@
3
3
  <head>
4
4
  <meta charset="utf-8" />
5
5
  <meta name="viewport" content="width=device-width,initial-scale=1.0" />
6
- <script type="module" crossorigin src="./assets/index.7aa11f5a.js"></script>
6
+ <script type="module" crossorigin src="./assets/index.44b91cfe.js"></script>
7
7
  </head>
8
8
  <body style="height: 100vH;">
9
9
  <noscript>
package/index.js CHANGED
@@ -59,6 +59,7 @@ export {
59
59
 
60
60
  export { default as ButtonManager } from './src/manager/buttonManager.js';
61
61
  export { NavbarManager, ButtonLocation, getActionsByLocation } from './src/manager/navbarManager.js';
62
+ export { default as ToolboxManager, ToolboxType } from './src/manager/toolbox/toolboxManager.js';
62
63
  export { default as CategoryManager } from './src/manager/categoryManager/categoryManager.js';
63
64
  export { default as ComponentsManager } from './src/manager/categoryManager/ComponentsManager.vue';
64
65
  export { default as ContextMenuManager } from './src/manager/contextMenu/contextMenuManager.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vcmap/ui",
3
- "version": "5.0.0-rc.12",
3
+ "version": "5.0.0-rc.13",
4
4
  "author": "Virtual City Systems",
5
5
  "license": "MIT",
6
6
  "scripts": {
@@ -121,5 +121,15 @@
121
121
  "node": "^16.14.0",
122
122
  "npm": "^8.3.1"
123
123
  },
124
- "type": "module"
124
+ "type": "module",
125
+ "exports": {
126
+ ".": "./index.js",
127
+ "./config/*.json": "./config/*.json",
128
+ "./src/assets/logo.svg": "./src/assets/logo.svg",
129
+ "./src/assets/logo-mobile.svg": "./src/assets/logo-mobile.svg",
130
+ "./build/buildHelpers.js": "./build/buildHelpers.js",
131
+ "./build/getPluginProxies.js": "./build/getPluginProxies.js",
132
+ "./build/determineHost.js": "./build/determineHost.js",
133
+ "./src/styles/variables.scss": "./src/styles/variables.scss"
134
+ }
125
135
  }
@@ -40,30 +40,17 @@ export default async function (config) {
40
40
  '@vcmap/example',
41
41
  ButtonLocation.TOOL,
42
42
  );
43
- const buttonComponents = [
44
- {
45
- id: 'distance3D',
46
- action: {
47
- name: 'distance3D',
48
- title: '3D distance',
49
- icon: '$vcs3dDistance',
50
- active: false,
51
- callback() { this.active = !this.active; },
52
- },
53
- },
54
- {
55
- id: 'area3D',
56
- action: {
57
- name: 'area3D',
58
- title: '3D area',
59
- icon: '$vcs3dArea',
60
- active: false,
61
- callback() { this.active = !this.active; },
62
- },
43
+ const miscGroup = app.toolboxManager.get('miscellaneous');
44
+ miscGroup.buttonManager.add({
45
+ id: 'example',
46
+ action: {
47
+ name: 'example',
48
+ title: 'example',
49
+ icon: 'mdi-circle-small',
50
+ active: false,
51
+ callback() { this.active = !this.active; },
63
52
  },
64
- ];
65
- const measurementGroup = app.toolboxManager.requestGroup('measurement');
66
- buttonComponents.forEach(c => measurementGroup.buttonManager.add(c, '@vcmap/example'));
53
+ }, '@vcmap/example');
67
54
  },
68
55
  destroy() {
69
56
  if (this._destroyAction) {
@@ -1,6 +1,8 @@
1
1
  import VectorSource from 'ol/source/Vector.js';
2
2
  import { Feature } from 'ol';
3
- import { ButtonLocation, createModalAction, createToggleAction, setStateToUrl, WindowSlot } from '@vcmap/ui';
3
+ import {
4
+ ButtonLocation, createModalAction, createToggleAction, setStateToUrl, ToolboxType, WindowSlot,
5
+ } from '@vcmap/ui';
4
6
  import { toolboxData } from './toolbox-data.js';
5
7
  import editor from './editor.vue';
6
8
  import windowManagerExample from './windowManagerExample.vue';
@@ -136,9 +138,16 @@ export default async function () {
136
138
  '@vcmap/test',
137
139
  ButtonLocation.TOOL,
138
140
  );
139
- toolboxData.forEach(([{ id, icon, title, buttonComponents }, owner]) => {
140
- const group = app.toolboxManager.requestGroup(id, icon, title);
141
- buttonComponents.forEach(c => group.buttonManager.add(c, owner));
141
+ toolboxData.forEach(([{ buttonComponents, ...toolboxComponentOptions }, owner]) => {
142
+ let group;
143
+ if (app.toolboxManager.has(toolboxComponentOptions.id)) {
144
+ group = app.toolboxManager.get(toolboxComponentOptions.id);
145
+ } else {
146
+ group = app.toolboxManager.add(toolboxComponentOptions, owner);
147
+ }
148
+ if (group.type === ToolboxType.GROUP && buttonComponents) {
149
+ buttonComponents.forEach(c => group.buttonManager.add(c, owner));
150
+ }
142
151
  });
143
152
 
144
153
  app.contextMenuManager.addEventHandler(async (event) => {
@@ -1,104 +1,129 @@
1
+ import { ToolboxType } from '@vcmap/ui';
2
+
3
+ const dummySelectAction = {
4
+ active: false,
5
+ currentIndex: 0,
6
+ _stop() {
7
+ console.log('stopping session', this._session);
8
+ this._session = null;
9
+ this.active = false;
10
+ },
11
+ _start() {
12
+ const startSession = tool => ({ type: tool });
13
+ this._session = startSession(this.tools[this.currentIndex].name);
14
+ this.active = true;
15
+ console.log('starting session', this._session);
16
+ },
17
+ callback() {
18
+ if (this.active) {
19
+ this._stop();
20
+ } else {
21
+ this._start();
22
+ }
23
+ },
24
+ selected(index) {
25
+ this.currentIndex = index;
26
+ if (this.active) {
27
+ this._session.type = this.tools[this.currentIndex].name;
28
+ console.log('updating active session', this._session);
29
+ } else {
30
+ this._start();
31
+ }
32
+ },
33
+ };
34
+
1
35
  // eslint-disable-next-line import/prefer-default-export
2
36
  export const toolboxData = [
3
37
  [
4
38
  {
5
- id: 'select',
6
- buttonComponents: [
7
- {
8
- id: 'select',
9
- action: {
10
- name: 'select',
11
- title: 'select',
12
- icon: '$vcsPointSelect',
13
- active: false,
14
- callback() { this.active = !this.active; },
15
- },
16
- },
17
- ],
39
+ id: 'singleSelect',
40
+ type: ToolboxType.SINGLE,
41
+ action: {
42
+ name: 'select',
43
+ title: 'single select',
44
+ icon: '$vcsPointSelect',
45
+ active: false,
46
+ callback() { this.active = !this.active; },
47
+ },
18
48
  },
19
49
  '@vcmap/test',
20
50
  ],
21
51
  [
22
52
  {
23
53
  id: 'multiSelect',
24
- icon: '$vcsPen',
25
- title: 'multi select',
26
- buttonComponents: [
27
- {
28
- id: 'pen',
29
- action: {
54
+ type: ToolboxType.SELECT,
55
+ action: {
56
+ name: 'multiSelect',
57
+ title: 'multi select',
58
+ ...dummySelectAction,
59
+ tools: [
60
+ {
30
61
  name: 'pen',
31
62
  title: 'Item 1',
32
63
  icon: '$vcsPen',
33
- active: false,
34
- callback() { this.active = !this.active; },
35
64
  },
36
- },
37
- {
38
- id: 'object',
39
- action: {
65
+ {
40
66
  name: 'object',
41
67
  title: 'Item 2',
42
68
  icon: '$vcsObjectSelect',
43
- active: false,
44
- callback() { this.active = !this.active; },
45
69
  },
46
- },
47
- ],
70
+ ],
71
+ },
48
72
  },
49
73
  '@vcmap/test',
50
74
  ],
51
75
  [
52
76
  {
53
77
  id: 'measurement',
54
- icon: '$vcsDimensionsHouse',
55
- title: 'measurement',
56
- buttonComponents: [
57
- {
58
- id: 'distance',
59
- action: {
78
+ type: ToolboxType.SELECT,
79
+ action: {
80
+ name: 'measurement',
81
+ title: 'measurement',
82
+ ...dummySelectAction,
83
+ tools: [
84
+ {
60
85
  name: 'distance',
61
86
  title: '2D distance',
62
87
  icon: '$vcs2dDistance',
63
- active: false,
64
- callback() { this.active = !this.active; },
65
88
  },
66
- },
67
- {
68
- id: 'area',
69
- action: {
89
+ {
70
90
  name: 'area',
71
91
  title: '2D area',
72
92
  icon: '$vcs2dArea',
73
- active: false,
74
- callback() { this.active = !this.active; },
75
93
  },
76
- },
77
- ],
94
+ {
95
+ name: 'distance3D',
96
+ title: '3D distance',
97
+ icon: '$vcs3dDistance',
98
+ },
99
+ {
100
+ name: 'area3D',
101
+ title: '3D area',
102
+ icon: '$vcs3dArea',
103
+ },
104
+ ],
105
+ },
78
106
  },
79
107
  '@vcmap/test',
80
108
  ],
81
109
  [
82
110
  {
83
111
  id: 'toggle',
84
- buttonComponents: [
85
- {
86
- id: 'split',
87
- action: {
88
- name: 'split',
89
- title: 'split view',
90
- icon: '$vcsSplitView',
91
- active: false,
92
- callback() { this.active = !this.active; },
93
- },
94
- },
95
- ],
112
+ type: ToolboxType.SINGLE,
113
+ action: {
114
+ name: 'split',
115
+ title: 'split view',
116
+ icon: '$vcsSplitView',
117
+ active: false,
118
+ callback() { this.active = !this.active; },
119
+ },
96
120
  },
97
121
  '@vcmap/test',
98
122
  ],
99
123
  [
100
124
  {
101
125
  id: 'flight',
126
+ type: ToolboxType.GROUP,
102
127
  icon: '$vcsVideoRecorder',
103
128
  title: 'flight',
104
129
  buttonComponents: [
@@ -279,7 +279,7 @@
279
279
  ButtonLocation.CONTENT,
280
280
  );
281
281
  }
282
- watch(app.categoryManager.items, () => {
282
+ watch(app.categoryManager.items.value, () => {
283
283
  if (app.categoryManager.items.value.length > 0) {
284
284
  if (!app.navbarManager.has('component-manager')) {
285
285
  app.navbarManager.add(
@@ -51,18 +51,24 @@
51
51
  * @property {boolean} [active=false] - optional state of button. If active, button is rendered in primary color
52
52
  */
53
53
 
54
+ /**
55
+ * pattern to check actions
56
+ * @type {Object}
57
+ */
58
+ export const ActionPattern = {
59
+ name: String,
60
+ title: [undefined, String],
61
+ icon: [undefined, String],
62
+ callback: Function,
63
+ active: [undefined, Boolean],
64
+ };
65
+
54
66
  /**
55
67
  * @param {VcsAction} action
56
68
  * @returns {boolean}
57
69
  */
58
70
  export function validateAction(action) {
59
- return is(action, {
60
- name: String,
61
- title: [undefined, String],
62
- icon: [undefined, String],
63
- callback: Function,
64
- active: [undefined, Boolean],
65
- });
71
+ return is(action, ActionPattern);
66
72
  }
67
73
 
68
74
  /**
@@ -51,6 +51,7 @@
51
51
 
52
52
  import { inject, onMounted, onUnmounted, watch } from 'vue';
53
53
  import { setupBalloonPositionListener } from './balloonHelper.js';
54
+ import VcsButton from '../components/buttons/VcsButton.vue';
54
55
 
55
56
  /**
56
57
  * @description A balloon viewing feature attributes. Size dynamic dependent on number of attributes.
@@ -65,6 +66,7 @@
65
66
  */
66
67
  export default {
67
68
  name: 'BalloonComponent',
69
+ components: { VcsButton },
68
70
  props: {
69
71
  featureId: {
70
72
  type: String,
@@ -27,6 +27,7 @@ import { Feature } from 'ol';
27
27
  import { check, checkMaybe } from '@vcsuite/check';
28
28
  import { v4 as uuidv4 } from 'uuid';
29
29
 
30
+ import { ToolboxType } from '@vcmap/ui';
30
31
  import { vcsAppSymbol } from '../pluginHelper.js';
31
32
  import FeatureInfoInteraction from './featureInfoInteraction.js';
32
33
  import AbstractFeatureInfoView from './abstractFeatureInfoView.js';
@@ -153,9 +154,10 @@ function setupFeatureInfoTool(app) {
153
154
  },
154
155
  };
155
156
 
156
- app.toolboxManager.requestGroup('featureInfo').buttonManager.add(
157
+ app.toolboxManager.add(
157
158
  {
158
- id: 'featureInfoTool',
159
+ id: 'featureInfo',
160
+ type: ToolboxType.SINGLE,
159
161
  action,
160
162
  },
161
163
  vcsAppSymbol,
@@ -436,7 +438,7 @@ class FeatureInfo {
436
438
  destroy() {
437
439
  this._clearInternal();
438
440
  this._featureChanged.destroy();
439
- this._app.toolboxManager.requestGroup('featureInfo').buttonManager.remove('featureInfoTool');
441
+ this._app.toolboxManager.remove('featureInfo');
440
442
  if (this._scratchLayer) {
441
443
  this._app.layers.remove(this._scratchLayer);
442
444
  this._scratchLayer.destroy();
package/src/i18n/de.js CHANGED
@@ -69,6 +69,10 @@ const messages = {
69
69
  openInNew: 'In neuem Browser Tab öffnen',
70
70
  defaultLabelText: 'Text',
71
71
  },
72
+ toolbox: {
73
+ flight: 'Flug',
74
+ miscellaneous: 'Verschiedenes',
75
+ },
72
76
  footer: {
73
77
  title: 'Fußzeile',
74
78
  },
package/src/i18n/en.js CHANGED
@@ -69,6 +69,10 @@ const messages = {
69
69
  openInNew: 'Open in new tab',
70
70
  defaultLabelText: 'Text',
71
71
  },
72
+ toolbox: {
73
+ flight: 'flight',
74
+ miscellaneous: 'miscellaneous',
75
+ },
72
76
  footer: {
73
77
  title: 'Footer',
74
78
  },
@@ -3,6 +3,7 @@ import { VcsEvent } from '@vcmap/core';
3
3
  import { v4 as uuidv4 } from 'uuid';
4
4
  import { check, checkMaybe } from '@vcsuite/check';
5
5
  import { vcsAppSymbol } from '../pluginHelper.js';
6
+ import { ActionPattern } from '../components/lists/VcsActionList.vue';
6
7
 
7
8
  /**
8
9
  * @typedef ButtonComponentOptions
@@ -86,13 +87,7 @@ class ButtonManager {
86
87
  */
87
88
  add(buttonComponentOptions, owner) {
88
89
  checkMaybe(buttonComponentOptions.id, String);
89
- check(buttonComponentOptions.action, {
90
- name: String,
91
- title: [undefined, String],
92
- icon: [undefined, String],
93
- callback: Function,
94
- active: [undefined, Boolean],
95
- });
90
+ check(buttonComponentOptions.action, ActionPattern);
96
91
  check(owner, [String, vcsAppSymbol]);
97
92
 
98
93
  if (buttonComponentOptions.id && this.has(buttonComponentOptions.id)) {
@@ -47,7 +47,7 @@ export function getActionsByLocation(buttonComponents, location, order = [], com
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>