mirror of
https://github.com/nasa/openmct.git
synced 2025-06-16 14:18:16 +00:00
Implemented context menu action registry
This commit is contained in:
@ -222,6 +222,8 @@ define([
|
|||||||
|
|
||||||
this.overlays = new OverlayAPI.default();
|
this.overlays = new OverlayAPI.default();
|
||||||
|
|
||||||
|
this.contextMenu = new api.ContextMenuRegistry();
|
||||||
|
|
||||||
this.legacyRegistry = defaultRegistry;
|
this.legacyRegistry = defaultRegistry;
|
||||||
this.install(this.plugins.Plot());
|
this.install(this.plugins.Plot());
|
||||||
this.install(this.plugins.TelemetryTable());
|
this.install(this.plugins.TelemetryTable());
|
||||||
|
@ -28,6 +28,7 @@ define([
|
|||||||
'./telemetry/TelemetryAPI',
|
'./telemetry/TelemetryAPI',
|
||||||
'./indicators/IndicatorAPI',
|
'./indicators/IndicatorAPI',
|
||||||
'./notifications/NotificationAPI',
|
'./notifications/NotificationAPI',
|
||||||
|
'./contextMenu/ContextMenuRegistry',
|
||||||
'./Editor'
|
'./Editor'
|
||||||
|
|
||||||
], function (
|
], function (
|
||||||
@ -38,6 +39,7 @@ define([
|
|||||||
TelemetryAPI,
|
TelemetryAPI,
|
||||||
IndicatorAPI,
|
IndicatorAPI,
|
||||||
NotificationAPI,
|
NotificationAPI,
|
||||||
|
ContextMenuRegistry,
|
||||||
EditorAPI
|
EditorAPI
|
||||||
) {
|
) {
|
||||||
return {
|
return {
|
||||||
@ -48,6 +50,7 @@ define([
|
|||||||
TelemetryAPI: TelemetryAPI,
|
TelemetryAPI: TelemetryAPI,
|
||||||
IndicatorAPI: IndicatorAPI,
|
IndicatorAPI: IndicatorAPI,
|
||||||
NotificationAPI: NotificationAPI.default,
|
NotificationAPI: NotificationAPI.default,
|
||||||
EditorAPI: EditorAPI
|
EditorAPI: EditorAPI,
|
||||||
|
ContextMenuRegistry: ContextMenuRegistry.default
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
75
src/api/contextMenu/ContextMenuRegistry.js
Normal file
75
src/api/contextMenu/ContextMenuRegistry.js
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
import ContextMenuComponent from '../../ui/components/controls/ContextMenu.vue';
|
||||||
|
import Vue from 'vue';
|
||||||
|
|
||||||
|
class ContextMenuRegistry {
|
||||||
|
constructor() {
|
||||||
|
this._allActions = [];
|
||||||
|
this._activeContextMenu = undefined;
|
||||||
|
|
||||||
|
this._hideActiveContextMenu = this._hideActiveContextMenu.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
registerAction(actionDefinition) {
|
||||||
|
this._allActions.push(actionDefinition);
|
||||||
|
}
|
||||||
|
|
||||||
|
attachTo(targetElement, objectPath) {
|
||||||
|
let showContextMenu = (event) => {
|
||||||
|
this._showContextMenuForObjectPath(event, objectPath);
|
||||||
|
};
|
||||||
|
|
||||||
|
targetElement.addEventListener('contextmenu', showContextMenu);
|
||||||
|
|
||||||
|
return function detach() {
|
||||||
|
targetElement.removeEventListener('contextMenu', showContextMenu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_showContextMenuForObjectPath(event, objectPath) {
|
||||||
|
let applicableActions = this._allActions.filter(
|
||||||
|
(action) => action.appliesTo(objectPath));
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
if (this._activeContextMenu) {
|
||||||
|
this._hideActiveContextMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
this._activeContextMenu = this._createContextMenuFromActions(applicableActions);
|
||||||
|
this._activeContextMenu.$mount();
|
||||||
|
this._activeContextMenu.$el.style.left = `${event.clientX}px`;
|
||||||
|
this._activeContextMenu.$el.style.top = `${event.clientY}px`;
|
||||||
|
|
||||||
|
document.body.appendChild(this._activeContextMenu.$el);
|
||||||
|
document.addEventListener('click', this._hideActiveContextMenu);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_hideActiveContextMenu() {
|
||||||
|
document.removeEventListener('click', this._hideActiveContextMenu);
|
||||||
|
document.body.removeChild(this._activeContextMenu.$el);
|
||||||
|
this._activeContextMenu.$destroy();
|
||||||
|
this._activeContextMenu = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_createContextMenuFromActions(actions) {
|
||||||
|
return new Vue({
|
||||||
|
components: {
|
||||||
|
ContextMenu: ContextMenuComponent
|
||||||
|
},
|
||||||
|
provide: {
|
||||||
|
actions: actions
|
||||||
|
},
|
||||||
|
template: '<ContextMenu></ContextMenu>'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export default ContextMenuRegistry;
|
@ -148,4 +148,4 @@ define([], function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return DisplayLayoutToolbar;
|
return DisplayLayoutToolbar;
|
||||||
});
|
});
|
||||||
|
@ -1,78 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2014-2018, 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.
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
define(['zepto'], function ($) {
|
|
||||||
/**
|
|
||||||
* @typedef Context
|
|
||||||
* @property {*} item
|
|
||||||
* @property {HTMLElement} element
|
|
||||||
* @property {Context} parent the containing context (may be undefined)
|
|
||||||
* @memberof module:openmct
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
function ContextManager() {
|
|
||||||
this.counter = 0;
|
|
||||||
this.contexts = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
ContextManager.prototype.nextId = function () {
|
|
||||||
this.counter += 1;
|
|
||||||
return "context-" + this.counter;
|
|
||||||
};
|
|
||||||
|
|
||||||
ContextManager.prototype.context = function (item, htmlElement) {
|
|
||||||
var $element = $(htmlElement);
|
|
||||||
var id = $element.attr('data-context') || this.nextId();
|
|
||||||
|
|
||||||
$element.attr('data-context', id);
|
|
||||||
|
|
||||||
if (this.contexts[id] && this.contexts[id].item !== item) {
|
|
||||||
this.release(htmlElement);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.contexts[id]) {
|
|
||||||
var $parent = $element.closest('[data-context]');
|
|
||||||
var parentId = $parent.attr('data-context');
|
|
||||||
var parentContext = parentId ? this.contexts[parentId] : undefined;
|
|
||||||
this.contexts[id] = {
|
|
||||||
item: item,
|
|
||||||
element: htmlElement,
|
|
||||||
parent: parentContext
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.contexts[id];
|
|
||||||
};
|
|
||||||
|
|
||||||
ContextManager.prototype.release = function (htmlElement) {
|
|
||||||
var $element = $(htmlElement);
|
|
||||||
var id = $element.attr('data-context');
|
|
||||||
|
|
||||||
if (id) {
|
|
||||||
delete this.contexts[id];
|
|
||||||
$element.removeAttr('data-context');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return ContextManager;
|
|
||||||
});
|
|
@ -1,58 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2014-2018, 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.
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
define(['zepto'], function ($) {
|
|
||||||
function HoverGesture(hoverManager) {
|
|
||||||
this.hoverManager = hoverManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
HoverGesture.prototype.apply = function (htmlElement) {
|
|
||||||
var $element = $(htmlElement);
|
|
||||||
var hoverManager = this.hoverManager;
|
|
||||||
|
|
||||||
function update() {
|
|
||||||
$(hoverManager.all()).removeClass('hovering');
|
|
||||||
$(hoverManager.top()).addClass('hovering');
|
|
||||||
}
|
|
||||||
|
|
||||||
function enter() {
|
|
||||||
hoverManager.add(htmlElement);
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
|
|
||||||
function leave() {
|
|
||||||
hoverManager.remove(htmlElement);
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
|
|
||||||
$element.on('mouseenter', enter);
|
|
||||||
$element.on('mouseleave', leave);
|
|
||||||
|
|
||||||
return function () {
|
|
||||||
leave();
|
|
||||||
$element.off('mouseenter', enter);
|
|
||||||
$element.off('mouseleave', leave);
|
|
||||||
}.bind(this);
|
|
||||||
};
|
|
||||||
|
|
||||||
return HoverGesture;
|
|
||||||
});
|
|
@ -1,60 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2014-2018, 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.
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
define(['zepto'], function ($) {
|
|
||||||
function SelectGesture(selection, contextManager) {
|
|
||||||
this.selection = selection;
|
|
||||||
this.contextManager = contextManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
SelectGesture.prototype.apply = function (htmlElement, item) {
|
|
||||||
var $element = $(htmlElement);
|
|
||||||
var contextManager = this.contextManager;
|
|
||||||
var selection = this.selection;
|
|
||||||
var path = contextManager.path(item, htmlElement);
|
|
||||||
|
|
||||||
function select() {
|
|
||||||
selection.add(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
function change() {
|
|
||||||
var selected = selection.primary();
|
|
||||||
$element.toggleClass(
|
|
||||||
'selected',
|
|
||||||
selected && path.matches(selected)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
$element.addClass('selectable');
|
|
||||||
$element.on('click', select);
|
|
||||||
selection.on('change', change);
|
|
||||||
change(); // Initialize
|
|
||||||
|
|
||||||
return function () {
|
|
||||||
contextManager.release(htmlElement);
|
|
||||||
$element.off('click', select);
|
|
||||||
selection.off('change', change);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
return SelectGesture;
|
|
||||||
});
|
|
@ -1,29 +1,20 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="c-menu">
|
<div class="c-menu">
|
||||||
<ul>
|
<ul>
|
||||||
<li v-for="item in contextMenuItems"
|
<li v-for="action in actions"
|
||||||
:class="item.class"
|
:key="action.name"
|
||||||
:title="item.title">
|
:class="action.cssClass"
|
||||||
{{ item.name }}
|
:title="action.description"
|
||||||
|
@click="action.invoke">
|
||||||
|
{{ action.name }}
|
||||||
</li>
|
</li>
|
||||||
|
<li v-if="actions.length === 0">No actions defined.</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
data: function () {
|
inject: ['actions']
|
||||||
return {
|
|
||||||
contextMenuItems: [
|
|
||||||
{name: 'Open In New Tab', class: 'icon-new-window', title: 'Open in a new browser tab'},
|
|
||||||
{name: 'Preview', class: 'hide-in-t-main-view icon-eye-open', title: 'Preview in large dialog'},
|
|
||||||
{name: 'Edit Properties...', class: 'major icon-pencil', title: 'Edit properties of this object.'},
|
|
||||||
{name: 'Duplicate', class: 'icon-duplicate', title: 'Duplicate object to another location.'},
|
|
||||||
{name: 'Create Link', class: 'icon-link', title: 'Create Link to object in another location.'},
|
|
||||||
{name: 'Export as JSON', class: 'icon-export', title: 'Export as JSON'},
|
|
||||||
{name: 'Import from JSON', class: 'icon-import', title: 'Import from JSON'}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
@ -11,11 +11,10 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
import ContextMenu from '../mixins/context-menu';
|
|
||||||
import ObjectLink from '../mixins/object-link';
|
import ObjectLink from '../mixins/object-link';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
mixins: [ContextMenu, ObjectLink],
|
mixins: [ObjectLink],
|
||||||
inject: ['openmct'],
|
inject: ['openmct'],
|
||||||
props: {
|
props: {
|
||||||
domainObject: Object
|
domainObject: Object
|
||||||
@ -32,6 +31,8 @@ export default {
|
|||||||
});
|
});
|
||||||
this.$once('hook:destroyed', removeListener);
|
this.$once('hook:destroyed', removeListener);
|
||||||
}
|
}
|
||||||
|
let detachContextMenu = this.openmct.contextMenu.attachTo(this.$el);
|
||||||
|
this.$once('hook:destroyed', detachContextMenu);
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
typeClass() {
|
typeClass() {
|
||||||
|
Reference in New Issue
Block a user