Implemented context menu action registry

This commit is contained in:
Andrew Henry 2018-11-22 15:53:50 -08:00
parent 74faf1bd48
commit a7948ce83e
9 changed files with 93 additions and 217 deletions

@ -222,6 +222,8 @@ define([
this.overlays = new OverlayAPI.default();
this.contextMenu = new api.ContextMenuRegistry();
this.legacyRegistry = defaultRegistry;
this.install(this.plugins.Plot());
this.install(this.plugins.TelemetryTable());

@ -28,6 +28,7 @@ define([
'./telemetry/TelemetryAPI',
'./indicators/IndicatorAPI',
'./notifications/NotificationAPI',
'./contextMenu/ContextMenuRegistry',
'./Editor'
], function (
@ -38,6 +39,7 @@ define([
TelemetryAPI,
IndicatorAPI,
NotificationAPI,
ContextMenuRegistry,
EditorAPI
) {
return {
@ -48,6 +50,7 @@ define([
TelemetryAPI: TelemetryAPI,
IndicatorAPI: IndicatorAPI,
NotificationAPI: NotificationAPI.default,
EditorAPI: EditorAPI
EditorAPI: EditorAPI,
ContextMenuRegistry: ContextMenuRegistry.default
};
});

@ -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;
});
});

@ -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>
<div class="c-menu">
<ul>
<li v-for="item in contextMenuItems"
:class="item.class"
:title="item.title">
{{ item.name }}
<li v-for="action in actions"
:key="action.name"
:class="action.cssClass"
:title="action.description"
@click="action.invoke">
{{ action.name }}
</li>
<li v-if="actions.length === 0">No actions defined.</li>
</ul>
</div>
</template>
<script>
export default {
data: function () {
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'}
]
}
}
inject: ['actions']
}
</script>

@ -11,11 +11,10 @@
<script>
import ContextMenu from '../mixins/context-menu';
import ObjectLink from '../mixins/object-link';
export default {
mixins: [ContextMenu, ObjectLink],
mixins: [ObjectLink],
inject: ['openmct'],
props: {
domainObject: Object
@ -32,6 +31,8 @@ export default {
});
this.$once('hook:destroyed', removeListener);
}
let detachContextMenu = this.openmct.contextMenu.attachTo(this.$el);
this.$once('hook:destroyed', detachContextMenu);
},
computed: {
typeClass() {