Compare commits

...

4 Commits

Author SHA1 Message Date
8493b481dd make reviewer requested changes 2020-08-13 14:46:18 -07:00
28723b59b7 Merge branch 'master' into context-menu-option 2020-06-10 16:36:33 -07:00
9fa7de0b77 remove unused files 2020-06-10 16:30:24 -07:00
54bfc84ada replaced contextMenu with overlay menu 2020-06-10 16:06:42 -07:00
16 changed files with 165 additions and 98 deletions

View File

@ -240,7 +240,7 @@ define([
this.overlays = new OverlayAPI.default();
this.contextMenu = new api.ContextMenuRegistry();
this.menus = new api.MenuAPI(this);
this.router = new ApplicationRouter();

View File

@ -33,5 +33,5 @@ export default function LegacyActionAdapter(openmct, legacyActions) {
legacyActions.filter(contextualCategoryOnly)
.map(LegacyAction => new LegacyContextMenuAction(openmct, LegacyAction))
.forEach(openmct.contextMenu.registerAction);
.forEach(openmct.menus.registerObjectAction);
}

View File

@ -28,8 +28,8 @@ define([
'./telemetry/TelemetryAPI',
'./indicators/IndicatorAPI',
'./notifications/NotificationAPI',
'./contextMenu/ContextMenuAPI',
'./Editor'
'./Editor',
'./menu/MenuAPI'
], function (
TimeAPI,
@ -39,8 +39,8 @@ define([
TelemetryAPI,
IndicatorAPI,
NotificationAPI,
ContextMenuAPI,
EditorAPI
EditorAPI,
MenuAPI
) {
return {
TimeAPI: TimeAPI,
@ -51,6 +51,6 @@ define([
IndicatorAPI: IndicatorAPI,
NotificationAPI: NotificationAPI.default,
EditorAPI: EditorAPI,
ContextMenuRegistry: ContextMenuAPI.default
MenuAPI: MenuAPI.default
};
});

View File

@ -1,5 +1,5 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2018, United States Government
* Open MCT, Copyright (c) 2014-2020, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
@ -20,29 +20,32 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
import ContextMenuComponent from './ContextMenu.vue';
import Vue from 'vue';
import Menu from './menu.js';
/**
* The ContextMenuAPI allows the addition of new context menu actions, and for the context menu to be launched from
* The MenuAPI allows the addition of new context menu actions, and for the context menu to be launched from
* custom HTML elements.
* @interface ContextMenuAPI
* @interface MenuAPI
* @memberof module:openmct
*/
class ContextMenuAPI {
constructor() {
this._allActions = [];
this._activeContextMenu = undefined;
this._hideActiveContextMenu = this._hideActiveContextMenu.bind(this);
this.registerAction = this.registerAction.bind(this);
class MenuAPI {
constructor(openmct) {
this.openmct = openmct;
this._allObjectActions = [];
this.showMenu = this.showMenu.bind(this);
this.registerObjectAction = this.registerObjectAction.bind(this);
this._clearMenuComponent = this._clearMenuComponent.bind(this);
this._applicableObjectActions = this._applicableObjectActions.bind(this);
this._showObjectMenu = this._showObjectMenu.bind(this);
}
/**
* Defines an item to be added to context menus. Allows specification of text, appearance, and behavior when
* selected. Applicabilioty can be restricted by specification of an `appliesTo` function.
*
* @interface ContextMenuAction
* @interface ObjectAction
* @memberof module:openmct
* @property {string} name the human-readable name of this view
* @property {string} description a longer-form description (typically
@ -68,17 +71,32 @@ class ContextMenuAPI {
/**
* @param {ContextMenuAction} actionDefinition
*/
registerAction(actionDefinition) {
this._allActions.push(actionDefinition);
registerObjectAction(actionDefinition) {
this._allObjectActions.push(actionDefinition);
}
/**
* @private
*/
_showContextMenuForObjectPath(objectPath, x, y, actionsToBeIncluded) {
showMenu(x, y, actions) {
if (this.menuComponent) {
this.menuComponent.dismiss();
}
let applicableActions = this._allActions.filter((action) => {
let options = {
x,
y,
actions
}
this.menuComponent = new Menu(options);
this.menuComponent.on('destroy', this._clearMenuComponent);
}
_clearMenuComponent() {
this.menuComponent = undefined;
delete this.menuComponent;
}
_applicableObjectActions(objectPath, actionsToBeIncluded) {
let applicableActions = this._allObjectActions.filter((action) => {
if (actionsToBeIncluded) {
if (action.appliesTo === undefined && actionsToBeIncluded.includes(action.key)) {
return true;
@ -92,66 +110,19 @@ class ContextMenuAPI {
}
});
if (this._activeContextMenu) {
this._hideActiveContextMenu();
}
this._activeContextMenu = this._createContextMenuForObject(objectPath, applicableActions);
this._activeContextMenu.$mount();
document.body.appendChild(this._activeContextMenu.$el);
let position = this._calculatePopupPosition(x, y, this._activeContextMenu.$el);
this._activeContextMenu.$el.style.left = `${position.x}px`;
this._activeContextMenu.$el.style.top = `${position.y}px`;
document.addEventListener('click', this._hideActiveContextMenu);
}
/**
* @private
*/
_calculatePopupPosition(eventPosX, eventPosY, menuElement) {
let menuDimensions = menuElement.getBoundingClientRect();
let overflowX = (eventPosX + menuDimensions.width) - document.body.clientWidth;
let overflowY = (eventPosY + menuDimensions.height) - document.body.clientHeight;
if (overflowX > 0) {
eventPosX = eventPosX - overflowX;
}
if (overflowY > 0) {
eventPosY = eventPosY - overflowY;
}
return {
x: eventPosX,
y: eventPosY
}
}
/**
* @private
*/
_hideActiveContextMenu() {
document.removeEventListener('click', this._hideActiveContextMenu);
document.body.removeChild(this._activeContextMenu.$el);
this._activeContextMenu.$destroy();
this._activeContextMenu = undefined;
}
/**
* @private
*/
_createContextMenuForObject(objectPath, actions) {
return new Vue({
components: {
ContextMenu: ContextMenuComponent
},
provide: {
actions: actions,
objectPath: objectPath
},
template: '<ContextMenu></ContextMenu>'
applicableActions.forEach(action => {
action.callBack = () => {
return action.invoke(objectPath);
};
});
return applicableActions;
}
_showObjectMenu(objectPath, x, y, actionsToBeIncluded) {
let applicableActions = this._applicableObjectActions(objectPath, actionsToBeIncluded);
this.showMenu(x, y, applicableActions);
}
}
export default ContextMenuAPI;
export default MenuAPI;

View File

@ -6,7 +6,7 @@
:key="action.name"
:class="action.cssClass"
:title="action.description"
@click="action.invoke(objectPath)"
@click="action.callBack"
>
{{ action.name }}
</li>
@ -19,6 +19,6 @@
<script>
export default {
inject: ['actions', 'objectPath']
inject: ['actions']
}
</script>

94
src/api/menu/menu.js Normal file
View File

@ -0,0 +1,94 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2020, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
import EventEmitter from 'EventEmitter';
import MenuComponent from './components/Menu.vue';
import Vue from 'vue';
class Menu extends EventEmitter {
constructor(options) {
super();
this.options = options;
this.component = new Vue({
provide: {
actions: options.actions
},
components: {
MenuComponent
},
template: '<menu-component />'
});
if (options.onDestroy) {
this.once('destroy', options.onDestroy);
}
this.dismiss = this.dismiss.bind(this);
this.show = this.show.bind(this);
this.show();
}
dismiss() {
this.emit('destroy');
document.body.removeChild(this.component.$el);
document.removeEventListener('click', this.dismiss);
this.component.$destroy();
}
show() {
this.component.$mount();
document.body.appendChild(this.component.$el);
let position = this._calculatePopupPosition(this.options.x, this.options.y, this.component.$el);
this.component.$el.style.left = `${position.x}px`;
this.component.$el.style.top = `${position.y}px`;
document.addEventListener('click', this.dismiss);
}
/**
* @private
*/
_calculatePopupPosition(eventPosX, eventPosY, menuElement) {
let menuDimensions = menuElement.getBoundingClientRect();
let overflowX = (eventPosX + menuDimensions.width) - document.body.clientWidth;
let overflowY = (eventPosY + menuDimensions.height) - document.body.clientHeight;
if (overflowX > 0) {
eventPosX = eventPosX - overflowX;
}
if (overflowY > 0) {
eventPosY = eventPosY - overflowY;
}
return {
x: eventPosX,
y: eventPosY
};
}
}
export default Menu;

View File

@ -22,6 +22,7 @@ class OverlayAPI {
this.dismissLastOverlay();
}
});
}
/**
@ -128,6 +129,7 @@ class OverlayAPI {
return progressDialog;
}
}
export default OverlayAPI;

View File

@ -153,7 +153,7 @@ export default {
this.timestampKey = timeSystem.key;
},
showContextMenu(event) {
this.openmct.contextMenu._showContextMenuForObjectPath(this.currentObjectPath, event.x, event.y, CONTEXT_MENU_ACTIONS);
this.openmct.menus._showObjectMenu(this.currentObjectPath, event.x, event.y, CONTEXT_MENU_ACTIONS);
}
}
}

View File

@ -48,7 +48,7 @@ define([
openmct.indicators.add(indicator);
openmct.contextMenu.registerAction(new ClearDataAction.default(openmct, appliesToObjects));
openmct.menus.registerObjectAction(new ClearDataAction.default(openmct, appliesToObjects));
};
};
});

View File

@ -248,7 +248,7 @@ export default {
this.$emit('formatChanged', this.item, format);
},
showContextMenu(event) {
this.openmct.contextMenu._showContextMenuForObjectPath(this.currentObjectPath, event.x, event.y, CONTEXT_MENU_ACTIONS);
this.openmct.menus._showObjectMenu(this.currentObjectPath, event.x, event.y, CONTEXT_MENU_ACTIONS);
}
}
}

View File

@ -23,6 +23,6 @@ import GoToOriginalAction from './goToOriginalAction';
export default function () {
return function (openmct) {
openmct.contextMenu.registerAction(new GoToOriginalAction(openmct));
openmct.menus.registerObjectAction(new GoToOriginalAction(openmct));
};
}

View File

@ -23,6 +23,6 @@ import RemoveAction from "./RemoveAction";
export default function () {
return function (openmct) {
openmct.contextMenu.registerAction(new RemoveAction(openmct));
openmct.menus.registerObjectAction(new RemoveAction(openmct));
}
}

View File

@ -175,7 +175,7 @@ export default {
let contextualObjectPath = this.objectPath.slice();
contextualObjectPath.unshift(domainObject);
this.openmct.contextMenu._showContextMenuForObjectPath(contextualObjectPath, event.x, event.y, this.row.getContextMenuActions());
this.openmct.menus._showObjectMenu(contextualObjectPath, event.x, event.y, this.row.getContextMenuActions());
});
}
}

View File

@ -267,7 +267,7 @@ export default {
});
},
showContextMenu(event) {
this.openmct.contextMenu._showContextMenuForObjectPath(this.openmct.router.path, event.clientX, event.clientY);
this.openmct.menus._showObjectMenu(this.openmct.router.path, event.clientX, event.clientY);
},
goToParent() {
window.location.hash = this.parentUrl;

View File

@ -30,7 +30,7 @@ export default {
showContextMenu(event) {
event.preventDefault();
event.stopPropagation();
this.openmct.contextMenu._showContextMenuForObjectPath(this.objectPath, event.clientX, event.clientY);
this.openmct.menus._showObjectMenu(this.objectPath, event.clientX, event.clientY);
}
}
};

View File

@ -24,7 +24,7 @@ import ViewHistoricalDataAction from './ViewHistoricalDataAction';
export default function () {
return function (openmct) {
openmct.contextMenu.registerAction(new PreviewAction(openmct));
openmct.contextMenu.registerAction(new ViewHistoricalDataAction(openmct));
openmct.menus.registerObjectAction(new PreviewAction(openmct));
openmct.menus.registerObjectAction(new ViewHistoricalDataAction(openmct));
};
}