mirror of
https://github.com/nasa/openmct.git
synced 2025-06-17 14:48:13 +00:00
Address testathon issues relating to context menu (#2235)
* Support category arrays for legacy actions * Fixed object path listener. Removed old context menus * Removed old fullscreen action and Screenfull dependency * Restore confirmation dialog on remove * Restored tests * Remove unused legacy policies
This commit is contained in:
committed by
Pete Richards
parent
a87fc51fbb
commit
c748569433
@ -58,7 +58,6 @@
|
|||||||
"printj": "^1.1.0",
|
"printj": "^1.1.0",
|
||||||
"raw-loader": "^0.5.1",
|
"raw-loader": "^0.5.1",
|
||||||
"request": "^2.69.0",
|
"request": "^2.69.0",
|
||||||
"screenfull": "^3.3.2",
|
|
||||||
"split": "^1.0.0",
|
"split": "^1.0.0",
|
||||||
"style-loader": "^0.21.0",
|
"style-loader": "^0.21.0",
|
||||||
"v8-compile-cache": "^1.1.0",
|
"v8-compile-cache": "^1.1.0",
|
||||||
|
@ -31,7 +31,6 @@ define([
|
|||||||
"./src/navigation/NavigateAction",
|
"./src/navigation/NavigateAction",
|
||||||
"./src/navigation/OrphanNavigationHandler",
|
"./src/navigation/OrphanNavigationHandler",
|
||||||
"./src/windowing/NewTabAction",
|
"./src/windowing/NewTabAction",
|
||||||
"./src/windowing/FullscreenAction",
|
|
||||||
"./src/windowing/WindowTitler",
|
"./src/windowing/WindowTitler",
|
||||||
"./res/templates/browse.html",
|
"./res/templates/browse.html",
|
||||||
"./res/templates/browse-object.html",
|
"./res/templates/browse-object.html",
|
||||||
@ -53,7 +52,6 @@ define([
|
|||||||
NavigateAction,
|
NavigateAction,
|
||||||
OrphanNavigationHandler,
|
OrphanNavigationHandler,
|
||||||
NewTabAction,
|
NewTabAction,
|
||||||
FullscreenAction,
|
|
||||||
WindowTitler,
|
WindowTitler,
|
||||||
browseTemplate,
|
browseTemplate,
|
||||||
browseObjectTemplate,
|
browseObjectTemplate,
|
||||||
@ -225,13 +223,6 @@ define([
|
|||||||
"group": "windowing",
|
"group": "windowing",
|
||||||
"cssClass": "icon-new-window",
|
"cssClass": "icon-new-window",
|
||||||
"priority": "preferred"
|
"priority": "preferred"
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "fullscreen",
|
|
||||||
"implementation": FullscreenAction,
|
|
||||||
"category": "view-control",
|
|
||||||
"group": "windowing",
|
|
||||||
"priority": "default"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"runs": [
|
"runs": [
|
||||||
@ -265,18 +256,6 @@ define([
|
|||||||
key: "inspectorRegion",
|
key: "inspectorRegion",
|
||||||
template: inspectorRegionTemplate
|
template: inspectorRegionTemplate
|
||||||
}
|
}
|
||||||
],
|
|
||||||
"licenses": [
|
|
||||||
{
|
|
||||||
"name": "screenfull.js",
|
|
||||||
"version": "1.2.0",
|
|
||||||
"description": "Wrapper for cross-browser usage of fullscreen API",
|
|
||||||
"author": "Sindre Sorhus",
|
|
||||||
"website": "https://github.com/sindresorhus/screenfull.js/",
|
|
||||||
"copyright": "Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)",
|
|
||||||
"license": "license-mit",
|
|
||||||
"link": "https://github.com/sindresorhus/screenfull.js/blob/gh-pages/license"
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1,64 +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.
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Module defining FullscreenAction. Created by vwoeltje on 11/18/14.
|
|
||||||
*/
|
|
||||||
define(
|
|
||||||
["screenfull"],
|
|
||||||
function (screenfull) {
|
|
||||||
|
|
||||||
var ENTER_FULLSCREEN = "Enter full screen mode",
|
|
||||||
EXIT_FULLSCREEN = "Exit full screen mode";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The fullscreen action toggles between fullscreen display
|
|
||||||
* and regular in-window display.
|
|
||||||
* @memberof platform/commonUI/browse
|
|
||||||
* @constructor
|
|
||||||
* @implements {Action}
|
|
||||||
*/
|
|
||||||
function FullscreenAction(context) {
|
|
||||||
this.context = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
FullscreenAction.prototype.perform = function () {
|
|
||||||
screenfull.toggle();
|
|
||||||
};
|
|
||||||
|
|
||||||
FullscreenAction.prototype.getMetadata = function () {
|
|
||||||
// We override getMetadata, because the icon cssClass and
|
|
||||||
// description need to be determined at run-time
|
|
||||||
// based on whether or not we are currently
|
|
||||||
// full screen.
|
|
||||||
var metadata = Object.create(FullscreenAction);
|
|
||||||
metadata.cssClass = screenfull.isFullscreen ? "icon-fullscreen-expand" : "icon-fullscreen-collapse";
|
|
||||||
metadata.description = screenfull.isFullscreen ?
|
|
||||||
EXIT_FULLSCREEN : ENTER_FULLSCREEN;
|
|
||||||
metadata.group = "windowing";
|
|
||||||
metadata.context = this.context;
|
|
||||||
return metadata;
|
|
||||||
};
|
|
||||||
|
|
||||||
return FullscreenAction;
|
|
||||||
}
|
|
||||||
);
|
|
@ -1,59 +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.
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* MCTRepresentationSpec. Created by vwoeltje on 11/6/14.
|
|
||||||
*/
|
|
||||||
define(
|
|
||||||
["../../src/windowing/FullscreenAction", "screenfull"],
|
|
||||||
function (FullscreenAction, screenfull) {
|
|
||||||
|
|
||||||
describe("The fullscreen action", function () {
|
|
||||||
var action,
|
|
||||||
oldToggle;
|
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
// Screenfull is not shimmed or injected, so
|
|
||||||
// we need to spy on it in the global scope.
|
|
||||||
oldToggle = screenfull.toggle;
|
|
||||||
|
|
||||||
screenfull.toggle = jasmine.createSpy("toggle");
|
|
||||||
|
|
||||||
action = new FullscreenAction({});
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(function () {
|
|
||||||
screenfull.toggle = oldToggle;
|
|
||||||
});
|
|
||||||
|
|
||||||
it("toggles fullscreen mode when performed", function () {
|
|
||||||
action.perform();
|
|
||||||
expect(screenfull.toggle).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("provides displayable metadata", function () {
|
|
||||||
expect(action.getMetadata().cssClass).toBeDefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
@ -34,9 +34,6 @@ define([
|
|||||||
"./src/actions/CancelAction",
|
"./src/actions/CancelAction",
|
||||||
"./src/policies/EditActionPolicy",
|
"./src/policies/EditActionPolicy",
|
||||||
"./src/policies/EditPersistableObjectsPolicy",
|
"./src/policies/EditPersistableObjectsPolicy",
|
||||||
"./src/policies/EditableLinkPolicy",
|
|
||||||
"./src/policies/EditableMovePolicy",
|
|
||||||
"./src/policies/EditContextualActionPolicy",
|
|
||||||
"./src/representers/EditRepresenter",
|
"./src/representers/EditRepresenter",
|
||||||
"./src/capabilities/EditorCapability",
|
"./src/capabilities/EditorCapability",
|
||||||
"./src/capabilities/TransactionCapabilityDecorator",
|
"./src/capabilities/TransactionCapabilityDecorator",
|
||||||
@ -69,9 +66,6 @@ define([
|
|||||||
CancelAction,
|
CancelAction,
|
||||||
EditActionPolicy,
|
EditActionPolicy,
|
||||||
EditPersistableObjectsPolicy,
|
EditPersistableObjectsPolicy,
|
||||||
EditableLinkPolicy,
|
|
||||||
EditableMovePolicy,
|
|
||||||
EditContextualActionPolicy,
|
|
||||||
EditRepresenter,
|
EditRepresenter,
|
||||||
EditorCapability,
|
EditorCapability,
|
||||||
TransactionCapabilityDecorator,
|
TransactionCapabilityDecorator,
|
||||||
@ -174,7 +168,7 @@ define([
|
|||||||
"name": "Remove",
|
"name": "Remove",
|
||||||
"description": "Remove this object from its containing object.",
|
"description": "Remove this object from its containing object.",
|
||||||
"depends": [
|
"depends": [
|
||||||
"dialogService",
|
"openmct",
|
||||||
"navigationService"
|
"navigationService"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -240,19 +234,6 @@ define([
|
|||||||
"implementation": EditPersistableObjectsPolicy,
|
"implementation": EditPersistableObjectsPolicy,
|
||||||
"depends": ["openmct"]
|
"depends": ["openmct"]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"category": "action",
|
|
||||||
"implementation": EditContextualActionPolicy,
|
|
||||||
"depends": ["navigationService", "editModeBlacklist", "nonEditContextBlacklist"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"category": "action",
|
|
||||||
"implementation": EditableMovePolicy
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"category": "action",
|
|
||||||
"implementation": EditableLinkPolicy
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"implementation": CreationPolicy,
|
"implementation": CreationPolicy,
|
||||||
"category": "creation"
|
"category": "creation"
|
||||||
@ -349,16 +330,6 @@ define([
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"constants": [
|
|
||||||
{
|
|
||||||
"key": "editModeBlacklist",
|
|
||||||
"value": ["copy", "follow", "link", "locate"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "nonEditContextBlacklist",
|
|
||||||
"value": ["copy", "follow", "properties", "move", "link", "remove", "locate"]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"capabilities": [
|
"capabilities": [
|
||||||
{
|
{
|
||||||
"key": "editor",
|
"key": "editor",
|
||||||
|
@ -42,9 +42,9 @@ define([
|
|||||||
* @constructor
|
* @constructor
|
||||||
* @implements {Action}
|
* @implements {Action}
|
||||||
*/
|
*/
|
||||||
function RemoveAction(dialogService, navigationService, context) {
|
function RemoveAction(openmct, navigationService, context) {
|
||||||
this.domainObject = (context || {}).domainObject;
|
this.domainObject = (context || {}).domainObject;
|
||||||
this.dialogService = dialogService;
|
this.openmct = openmct;
|
||||||
this.navigationService = navigationService;
|
this.navigationService = navigationService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,7 +53,6 @@ define([
|
|||||||
*/
|
*/
|
||||||
RemoveAction.prototype.perform = function () {
|
RemoveAction.prototype.perform = function () {
|
||||||
var dialog,
|
var dialog,
|
||||||
dialogService = this.dialogService,
|
|
||||||
domainObject = this.domainObject,
|
domainObject = this.domainObject,
|
||||||
navigationService = this.navigationService;
|
navigationService = this.navigationService;
|
||||||
/*
|
/*
|
||||||
@ -104,13 +103,13 @@ define([
|
|||||||
* capability. Based on object's location and selected object's location
|
* capability. Based on object's location and selected object's location
|
||||||
* user may be navigated to existing parent object
|
* user may be navigated to existing parent object
|
||||||
*/
|
*/
|
||||||
function removeFromContext(object) {
|
function removeFromContext() {
|
||||||
var contextCapability = object.getCapability('context'),
|
var contextCapability = domainObject.getCapability('context'),
|
||||||
parent = contextCapability.getParent();
|
parent = contextCapability.getParent();
|
||||||
|
|
||||||
// If currently within path of removed object(s),
|
// If currently within path of removed object(s),
|
||||||
// navigates to existing object up tree
|
// navigates to existing object up tree
|
||||||
checkObjectNavigation(object, parent);
|
checkObjectNavigation(domainObject, parent);
|
||||||
|
|
||||||
return parent.useCapability('mutation', doMutate);
|
return parent.useCapability('mutation', doMutate);
|
||||||
}
|
}
|
||||||
@ -119,7 +118,7 @@ define([
|
|||||||
* Pass in the function to remove the domain object so it can be
|
* Pass in the function to remove the domain object so it can be
|
||||||
* associated with an 'OK' button press
|
* associated with an 'OK' button press
|
||||||
*/
|
*/
|
||||||
dialog = new RemoveDialog(dialogService, domainObject, removeFromContext);
|
dialog = new RemoveDialog(this.openmct, domainObject, removeFromContext);
|
||||||
dialog.show();
|
dialog.show();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -36,8 +36,8 @@ define([], function () {
|
|||||||
* @memberof platform/commonUI/edit
|
* @memberof platform/commonUI/edit
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function RemoveDialog(dialogService, domainObject, removeCallback) {
|
function RemoveDialog(openmct, domainObject, removeCallback) {
|
||||||
this.dialogService = dialogService;
|
this.openmct = openmct;
|
||||||
this.domainObject = domainObject;
|
this.domainObject = domainObject;
|
||||||
this.removeCallback = removeCallback;
|
this.removeCallback = removeCallback;
|
||||||
}
|
}
|
||||||
@ -46,31 +46,26 @@ define([], function () {
|
|||||||
* Display a dialog to confirm the removal of a domain object.
|
* Display a dialog to confirm the removal of a domain object.
|
||||||
*/
|
*/
|
||||||
RemoveDialog.prototype.show = function () {
|
RemoveDialog.prototype.show = function () {
|
||||||
var dialog,
|
let dialog = this.openmct.overlays.dialog({
|
||||||
domainObject = this.domainObject,
|
title: 'Remove ' + this.domainObject.getModel().name,
|
||||||
removeCallback = this.removeCallback,
|
iconClass: 'alert',
|
||||||
model = {
|
message: 'Warning! This action will permanently remove this object. Are you sure you want to continue?',
|
||||||
title: 'Remove ' + domainObject.getModel().name,
|
buttons: [
|
||||||
actionText: 'Warning! This action will permanently remove this object. Are you sure you want to continue?',
|
{
|
||||||
severity: 'alert',
|
|
||||||
primaryOption: {
|
|
||||||
label: 'OK',
|
label: 'OK',
|
||||||
callback: function () {
|
callback: () => {
|
||||||
removeCallback(domainObject);
|
this.removeCallback();
|
||||||
dialog.dismiss();
|
dialog.dismiss();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
options: [
|
{
|
||||||
{
|
label: 'Cancel',
|
||||||
label: 'Cancel',
|
callback: () => {
|
||||||
callback: function () {
|
dialog.dismiss();
|
||||||
dialog.dismiss();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
};
|
]
|
||||||
setTimeout(() => this.removeCallback(domainObject));
|
});
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return RemoveDialog;
|
return RemoveDialog;
|
||||||
|
@ -1,75 +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(
|
|
||||||
[],
|
|
||||||
function () {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Policy controlling whether the context menu is visible when
|
|
||||||
* objects are being edited
|
|
||||||
* @param navigationService
|
|
||||||
* @param editModeBlacklist A blacklist of actions disallowed from
|
|
||||||
* context menu when navigated object is being edited
|
|
||||||
* @param nonEditContextBlacklist A blacklist of actions disallowed
|
|
||||||
* from context menu of non-editable objects, when navigated object
|
|
||||||
* is being edited
|
|
||||||
* @constructor
|
|
||||||
* @param editModeBlacklist A blacklist of actions disallowed from
|
|
||||||
* context menu when navigated object is being edited
|
|
||||||
* @param nonEditContextBlacklist A blacklist of actions disallowed
|
|
||||||
* from context menu of non-editable objects, when navigated object
|
|
||||||
* @implements {Policy.<Action, ActionContext>}
|
|
||||||
*/
|
|
||||||
function EditContextualActionPolicy(navigationService, editModeBlacklist, nonEditContextBlacklist) {
|
|
||||||
this.navigationService = navigationService;
|
|
||||||
|
|
||||||
//The list of objects disallowed on target object when in edit mode
|
|
||||||
this.editModeBlacklist = editModeBlacklist;
|
|
||||||
//The list of objects disallowed on target object that is not in
|
|
||||||
// edit mode (ie. the context menu in the tree on the LHS).
|
|
||||||
this.nonEditContextBlacklist = nonEditContextBlacklist;
|
|
||||||
}
|
|
||||||
|
|
||||||
EditContextualActionPolicy.prototype.allow = function (action, context) {
|
|
||||||
var selectedObject = context.domainObject,
|
|
||||||
navigatedObject = this.navigationService.getNavigation(),
|
|
||||||
actionMetadata = action.getMetadata ? action.getMetadata() : {};
|
|
||||||
|
|
||||||
// FIXME: need to restore support for changing contextual actions
|
|
||||||
// based on edit mode.
|
|
||||||
// if (navigatedObject.hasCapability("editor") && navigatedObject.getCapability("editor").isEditContextRoot()) {
|
|
||||||
// if (selectedObject.hasCapability("editor") && selectedObject.getCapability("editor").inEditContext()) {
|
|
||||||
// return this.editModeBlacklist.indexOf(actionMetadata.key) === -1;
|
|
||||||
// } else {
|
|
||||||
// //Target is in the context menu
|
|
||||||
// return this.nonEditContextBlacklist.indexOf(actionMetadata.key) === -1;
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
// return true;
|
|
||||||
// }
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
return EditContextualActionPolicy;
|
|
||||||
}
|
|
||||||
);
|
|
@ -1,51 +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([], function () {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Policy suppressing links when the linked-to domain object is in
|
|
||||||
* edit mode. Domain objects being edited may not have been persisted,
|
|
||||||
* so creating links to these can result in inconsistent state.
|
|
||||||
*
|
|
||||||
* @memberof platform/commonUI/edit
|
|
||||||
* @constructor
|
|
||||||
* @implements {Policy.<View, DomainObject>}
|
|
||||||
*/
|
|
||||||
function EditableLinkPolicy() {
|
|
||||||
}
|
|
||||||
|
|
||||||
EditableLinkPolicy.prototype.allow = function (action, context) {
|
|
||||||
var key = action.getMetadata().key,
|
|
||||||
object;
|
|
||||||
|
|
||||||
if (key === 'link') {
|
|
||||||
object = context.selectedObject || context.domainObject;
|
|
||||||
return !(object.hasCapability("editor") && object.getCapability("editor").inEditContext());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Like all policies, allow by default.
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
return EditableLinkPolicy;
|
|
||||||
});
|
|
@ -1,52 +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([], function () {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Policy suppressing move actions among editable and non-editable
|
|
||||||
* domain objects.
|
|
||||||
* @memberof platform/commonUI/edit
|
|
||||||
* @constructor
|
|
||||||
* @implements {Policy.<View, DomainObject>}
|
|
||||||
*/
|
|
||||||
function EditableMovePolicy() {
|
|
||||||
}
|
|
||||||
|
|
||||||
EditableMovePolicy.prototype.allow = function (action, context) {
|
|
||||||
var domainObject = context.domainObject,
|
|
||||||
selectedObject = context.selectedObject,
|
|
||||||
key = action.getMetadata().key,
|
|
||||||
isDomainObjectEditing = domainObject.hasCapability('editor') &&
|
|
||||||
domainObject.getCapability('editor').inEditContext();
|
|
||||||
|
|
||||||
if (key === 'move' && isDomainObjectEditing) {
|
|
||||||
return !!selectedObject && selectedObject.hasCapability('editor') &&
|
|
||||||
selectedObject.getCapability('editor').inEditContext();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Like all policies, allow by default.
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
return EditableMovePolicy;
|
|
||||||
});
|
|
@ -29,7 +29,7 @@ define(
|
|||||||
actionContext,
|
actionContext,
|
||||||
capabilities,
|
capabilities,
|
||||||
mockContext,
|
mockContext,
|
||||||
mockDialogService,
|
mockOverlayAPI,
|
||||||
mockDomainObject,
|
mockDomainObject,
|
||||||
mockMutation,
|
mockMutation,
|
||||||
mockNavigationService,
|
mockNavigationService,
|
||||||
@ -68,9 +68,9 @@ define(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
mockDialogService = jasmine.createSpyObj(
|
mockOverlayAPI = jasmine.createSpyObj(
|
||||||
"dialogService",
|
"overlayAPI",
|
||||||
["showBlockingMessage"]
|
["dialog"]
|
||||||
);
|
);
|
||||||
|
|
||||||
mockNavigationService = jasmine.createSpyObj(
|
mockNavigationService = jasmine.createSpyObj(
|
||||||
@ -96,7 +96,7 @@ define(
|
|||||||
|
|
||||||
actionContext = { domainObject: mockDomainObject };
|
actionContext = { domainObject: mockDomainObject };
|
||||||
|
|
||||||
action = new RemoveAction(mockDialogService, mockNavigationService, actionContext);
|
action = new RemoveAction({overlays: mockOverlayAPI}, mockNavigationService, actionContext);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("only applies to objects with parents", function () {
|
it("only applies to objects with parents", function () {
|
||||||
@ -118,7 +118,7 @@ define(
|
|||||||
|
|
||||||
action.perform();
|
action.perform();
|
||||||
|
|
||||||
expect(mockDialogService.showBlockingMessage).toHaveBeenCalled();
|
expect(mockOverlayAPI.dialog).toHaveBeenCalled();
|
||||||
|
|
||||||
// Also check that no mutation happens at this point
|
// Also check that no mutation happens at this point
|
||||||
expect(mockParent.useCapability).not.toHaveBeenCalledWith("mutation", jasmine.any(Function));
|
expect(mockParent.useCapability).not.toHaveBeenCalledWith("mutation", jasmine.any(Function));
|
||||||
@ -158,13 +158,13 @@ define(
|
|||||||
mockGrandchildContext = jasmine.createSpyObj("context", ["getParent"]);
|
mockGrandchildContext = jasmine.createSpyObj("context", ["getParent"]);
|
||||||
mockRootContext = jasmine.createSpyObj("context", ["getParent"]);
|
mockRootContext = jasmine.createSpyObj("context", ["getParent"]);
|
||||||
|
|
||||||
mockDialogService.showBlockingMessage.and.returnValue(mockDialogHandle);
|
mockOverlayAPI.dialog.and.returnValue(mockDialogHandle);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("mutates the parent when performed", function () {
|
it("mutates the parent when performed", function () {
|
||||||
action.perform();
|
action.perform();
|
||||||
mockDialogService.showBlockingMessage.calls.mostRecent().args[0]
|
mockOverlayAPI.dialog.calls.mostRecent().args[0]
|
||||||
.primaryOption.callback();
|
.buttons[0].callback();
|
||||||
|
|
||||||
expect(mockMutation.invoke)
|
expect(mockMutation.invoke)
|
||||||
.toHaveBeenCalledWith(jasmine.any(Function));
|
.toHaveBeenCalledWith(jasmine.any(Function));
|
||||||
@ -174,8 +174,8 @@ define(
|
|||||||
var mutator, result;
|
var mutator, result;
|
||||||
|
|
||||||
action.perform();
|
action.perform();
|
||||||
mockDialogService.showBlockingMessage.calls.mostRecent().args[0]
|
mockOverlayAPI.dialog.calls.mostRecent().args[0]
|
||||||
.primaryOption.callback();
|
.buttons[0].callback();
|
||||||
|
|
||||||
mutator = mockMutation.invoke.calls.mostRecent().args[0];
|
mutator = mockMutation.invoke.calls.mostRecent().args[0];
|
||||||
result = mutator(model);
|
result = mutator(model);
|
||||||
@ -212,8 +212,8 @@ define(
|
|||||||
mockType.hasFeature.and.returnValue(true);
|
mockType.hasFeature.and.returnValue(true);
|
||||||
|
|
||||||
action.perform();
|
action.perform();
|
||||||
mockDialogService.showBlockingMessage.calls.mostRecent().args[0]
|
mockOverlayAPI.dialog.calls.mostRecent().args[0]
|
||||||
.primaryOption.callback();
|
.buttons[0].callback();
|
||||||
|
|
||||||
// Expects navigation to parent of domainObject (removed object)
|
// Expects navigation to parent of domainObject (removed object)
|
||||||
expect(mockNavigationService.setNavigation).toHaveBeenCalledWith(mockParent);
|
expect(mockNavigationService.setNavigation).toHaveBeenCalledWith(mockParent);
|
||||||
@ -242,8 +242,8 @@ define(
|
|||||||
mockType.hasFeature.and.returnValue(true);
|
mockType.hasFeature.and.returnValue(true);
|
||||||
|
|
||||||
action.perform();
|
action.perform();
|
||||||
mockDialogService.showBlockingMessage.calls.mostRecent().args[0]
|
mockOverlayAPI.dialog.calls.mostRecent().args[0]
|
||||||
.primaryOption.callback();
|
.buttons[0].callback();
|
||||||
|
|
||||||
// Expects no navigation to occur
|
// Expects no navigation to occur
|
||||||
expect(mockNavigationService.setNavigation).not.toHaveBeenCalled();
|
expect(mockNavigationService.setNavigation).not.toHaveBeenCalled();
|
||||||
|
@ -1,120 +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.
|
|
||||||
*****************************************************************************/
|
|
||||||
/*global describe,it,expect,beforeEach,jasmine*/
|
|
||||||
|
|
||||||
define(
|
|
||||||
["../../src/policies/EditContextualActionPolicy"],
|
|
||||||
function (EditContextualActionPolicy) {
|
|
||||||
|
|
||||||
describe("The Edit contextual action policy", function () {
|
|
||||||
var policy,
|
|
||||||
navigationService,
|
|
||||||
mockAction,
|
|
||||||
context,
|
|
||||||
navigatedObject,
|
|
||||||
mockDomainObject,
|
|
||||||
mockEditorCapability,
|
|
||||||
metadata,
|
|
||||||
editModeBlacklist = ["copy", "follow", "window", "link", "locate"],
|
|
||||||
nonEditContextBlacklist = ["copy", "follow", "properties", "move", "link", "remove", "locate"];
|
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
mockEditorCapability = jasmine.createSpyObj("editorCapability", ["isEditContextRoot", "inEditContext"]);
|
|
||||||
|
|
||||||
navigatedObject = jasmine.createSpyObj("navigatedObject", ["hasCapability", "getCapability"]);
|
|
||||||
navigatedObject.getCapability.and.returnValue(mockEditorCapability);
|
|
||||||
navigatedObject.hasCapability.and.returnValue(false);
|
|
||||||
|
|
||||||
|
|
||||||
mockDomainObject = jasmine.createSpyObj("domainObject", ["hasCapability", "getCapability"]);
|
|
||||||
mockDomainObject.hasCapability.and.returnValue(false);
|
|
||||||
mockDomainObject.getCapability.and.returnValue(mockEditorCapability);
|
|
||||||
|
|
||||||
navigationService = jasmine.createSpyObj("navigationService", ["getNavigation"]);
|
|
||||||
navigationService.getNavigation.and.returnValue(navigatedObject);
|
|
||||||
|
|
||||||
metadata = {key: "move"};
|
|
||||||
mockAction = jasmine.createSpyObj("action", ["getMetadata"]);
|
|
||||||
mockAction.getMetadata.and.returnValue(metadata);
|
|
||||||
|
|
||||||
context = {domainObject: mockDomainObject};
|
|
||||||
|
|
||||||
policy = new EditContextualActionPolicy(navigationService, editModeBlacklist, nonEditContextBlacklist);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Allows all actions when navigated object not in edit mode', function () {
|
|
||||||
expect(policy.allow(mockAction, context)).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Allows "window" action when navigated object in edit mode,' +
|
|
||||||
' but selected object not in edit mode ', function () {
|
|
||||||
navigatedObject.hasCapability.and.returnValue(true);
|
|
||||||
mockEditorCapability.isEditContextRoot.and.returnValue(true);
|
|
||||||
metadata.key = "window";
|
|
||||||
expect(policy.allow(mockAction, context)).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Allows "remove" action when navigated object in edit mode,' +
|
|
||||||
' and selected object not editable, but its parent is.',
|
|
||||||
function () {
|
|
||||||
var mockParent = jasmine.createSpyObj("parentObject", ["hasCapability"]),
|
|
||||||
mockContextCapability = jasmine.createSpyObj("contextCapability", ["getParent"]);
|
|
||||||
|
|
||||||
mockParent.hasCapability.and.returnValue(true);
|
|
||||||
mockContextCapability.getParent.and.returnValue(mockParent);
|
|
||||||
navigatedObject.hasCapability.and.returnValue(true);
|
|
||||||
|
|
||||||
mockDomainObject.getCapability.and.returnValue(mockContextCapability);
|
|
||||||
mockDomainObject.hasCapability.and.callFake(function (capability) {
|
|
||||||
switch (capability) {
|
|
||||||
case "editor": return false;
|
|
||||||
case "context": return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
metadata.key = "remove";
|
|
||||||
|
|
||||||
expect(policy.allow(mockAction, context)).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Disallows "move" action when navigated object in edit mode,' +
|
|
||||||
' but selected object not in edit mode ', function () {
|
|
||||||
navigatedObject.hasCapability.and.returnValue(true);
|
|
||||||
mockEditorCapability.isEditContextRoot.and.returnValue(true);
|
|
||||||
mockEditorCapability.inEditContext.and.returnValue(false);
|
|
||||||
metadata.key = "move";
|
|
||||||
expect(policy.allow(mockAction, context)).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Disallows copy action when navigated object and' +
|
|
||||||
' selected object in edit mode', function () {
|
|
||||||
navigatedObject.hasCapability.and.returnValue(true);
|
|
||||||
mockDomainObject.hasCapability.and.returnValue(true);
|
|
||||||
mockEditorCapability.isEditContextRoot.and.returnValue(true);
|
|
||||||
mockEditorCapability.inEditContext.and.returnValue(true);
|
|
||||||
|
|
||||||
metadata.key = "copy";
|
|
||||||
expect(policy.allow(mockAction, context)).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
@ -31,7 +31,6 @@ define([
|
|||||||
"./src/controllers/TreeNodeController",
|
"./src/controllers/TreeNodeController",
|
||||||
"./src/controllers/ActionGroupController",
|
"./src/controllers/ActionGroupController",
|
||||||
"./src/controllers/ToggleController",
|
"./src/controllers/ToggleController",
|
||||||
"./src/controllers/ContextMenuController",
|
|
||||||
"./src/controllers/ClickAwayController",
|
"./src/controllers/ClickAwayController",
|
||||||
"./src/controllers/ViewSwitcherController",
|
"./src/controllers/ViewSwitcherController",
|
||||||
"./src/controllers/GetterSetterController",
|
"./src/controllers/GetterSetterController",
|
||||||
@ -65,7 +64,6 @@ define([
|
|||||||
"./res/templates/tree-node.html",
|
"./res/templates/tree-node.html",
|
||||||
"./res/templates/label.html",
|
"./res/templates/label.html",
|
||||||
"./res/templates/controls/action-group.html",
|
"./res/templates/controls/action-group.html",
|
||||||
"./res/templates/menu/context-menu.html",
|
|
||||||
"./res/templates/controls/switcher.html",
|
"./res/templates/controls/switcher.html",
|
||||||
"./res/templates/object-inspector.html",
|
"./res/templates/object-inspector.html",
|
||||||
"./res/templates/controls/selector.html",
|
"./res/templates/controls/selector.html",
|
||||||
@ -84,7 +82,6 @@ define([
|
|||||||
TreeNodeController,
|
TreeNodeController,
|
||||||
ActionGroupController,
|
ActionGroupController,
|
||||||
ToggleController,
|
ToggleController,
|
||||||
ContextMenuController,
|
|
||||||
ClickAwayController,
|
ClickAwayController,
|
||||||
ViewSwitcherController,
|
ViewSwitcherController,
|
||||||
GetterSetterController,
|
GetterSetterController,
|
||||||
@ -118,7 +115,6 @@ define([
|
|||||||
treeNodeTemplate,
|
treeNodeTemplate,
|
||||||
labelTemplate,
|
labelTemplate,
|
||||||
actionGroupTemplate,
|
actionGroupTemplate,
|
||||||
contextMenuTemplate,
|
|
||||||
switcherTemplate,
|
switcherTemplate,
|
||||||
objectInspectorTemplate,
|
objectInspectorTemplate,
|
||||||
selectorTemplate,
|
selectorTemplate,
|
||||||
@ -252,13 +248,6 @@ define([
|
|||||||
"key": "ToggleController",
|
"key": "ToggleController",
|
||||||
"implementation": ToggleController
|
"implementation": ToggleController
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"key": "ContextMenuController",
|
|
||||||
"implementation": ContextMenuController,
|
|
||||||
"depends": [
|
|
||||||
"$scope"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"key": "ClickAwayController",
|
"key": "ClickAwayController",
|
||||||
"implementation": ClickAwayController,
|
"implementation": ClickAwayController,
|
||||||
@ -517,13 +506,6 @@ define([
|
|||||||
"action"
|
"action"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"key": "context-menu",
|
|
||||||
"template": contextMenuTemplate,
|
|
||||||
"uses": [
|
|
||||||
"action"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"key": "switcher",
|
"key": "switcher",
|
||||||
"template": switcherTemplate,
|
"template": switcherTemplate,
|
||||||
|
@ -1,33 +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.
|
|
||||||
-->
|
|
||||||
<div class="menu-element context-menu-wrapper mobile-disable-select" ng-controller="ContextMenuController">
|
|
||||||
<div class="menu context-menu">
|
|
||||||
<ul>
|
|
||||||
<li ng-repeat="menuAction in menuActions"
|
|
||||||
ng-click="menuAction.perform()"
|
|
||||||
title="{{menuAction.getMetadata().description}}"
|
|
||||||
class="{{menuAction.getMetadata().cssClass}}">
|
|
||||||
{{menuAction.getMetadata().name}}
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
@ -1,51 +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.
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Module defining ContextMenuController. Created by vwoeltje on 11/17/14.
|
|
||||||
*/
|
|
||||||
define(
|
|
||||||
[],
|
|
||||||
function () {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Controller for the context menu. Maintains an up-to-date
|
|
||||||
* list of applicable actions (those from category "contextual")
|
|
||||||
*
|
|
||||||
* @memberof platform/commonUI/general
|
|
||||||
* @constructor
|
|
||||||
*/
|
|
||||||
function ContextMenuController($scope) {
|
|
||||||
// Refresh variable "menuActions" in the scope
|
|
||||||
function updateActions() {
|
|
||||||
$scope.menuActions = $scope.action ?
|
|
||||||
$scope.action.getActions({ category: 'contextual' }) :
|
|
||||||
[];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update using the action capability
|
|
||||||
$scope.$watch("action", updateActions);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ContextMenuController;
|
|
||||||
}
|
|
||||||
);
|
|
@ -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(
|
|
||||||
["../../src/controllers/ContextMenuController"],
|
|
||||||
function (ContextMenuController) {
|
|
||||||
|
|
||||||
describe("The context menu controller", function () {
|
|
||||||
var mockScope,
|
|
||||||
mockActions,
|
|
||||||
controller;
|
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
mockActions = jasmine.createSpyObj("action", ["getActions"]);
|
|
||||||
mockScope = jasmine.createSpyObj("$scope", ["$watch"]);
|
|
||||||
controller = new ContextMenuController(mockScope);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("watches scope that may change applicable actions", function () {
|
|
||||||
// The action capability
|
|
||||||
expect(mockScope.$watch).toHaveBeenCalledWith(
|
|
||||||
"action",
|
|
||||||
jasmine.any(Function)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("populates the scope with grouped and ungrouped actions", function () {
|
|
||||||
mockScope.action = mockActions;
|
|
||||||
mockScope.parameters = { category: "test" };
|
|
||||||
|
|
||||||
mockActions.getActions.and.returnValue(["a", "b", "c"]);
|
|
||||||
|
|
||||||
// Call the watch
|
|
||||||
mockScope.$watch.calls.mostRecent().args[1]();
|
|
||||||
|
|
||||||
// Should have grouped and ungrouped actions in scope now
|
|
||||||
expect(mockScope.menuActions.length).toEqual(3);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
@ -25,12 +25,10 @@ define([
|
|||||||
"./src/MCTRepresentation",
|
"./src/MCTRepresentation",
|
||||||
"./src/gestures/DragGesture",
|
"./src/gestures/DragGesture",
|
||||||
"./src/gestures/DropGesture",
|
"./src/gestures/DropGesture",
|
||||||
"./src/gestures/ContextMenuGesture",
|
|
||||||
"./src/gestures/GestureProvider",
|
"./src/gestures/GestureProvider",
|
||||||
"./src/gestures/GestureRepresenter",
|
"./src/gestures/GestureRepresenter",
|
||||||
"./src/services/DndService",
|
"./src/services/DndService",
|
||||||
"./src/TemplateLinker",
|
"./src/TemplateLinker",
|
||||||
"./src/actions/ContextMenuAction",
|
|
||||||
"./src/TemplatePrefetcher",
|
"./src/TemplatePrefetcher",
|
||||||
'legacyRegistry'
|
'legacyRegistry'
|
||||||
], function (
|
], function (
|
||||||
@ -38,12 +36,10 @@ define([
|
|||||||
MCTRepresentation,
|
MCTRepresentation,
|
||||||
DragGesture,
|
DragGesture,
|
||||||
DropGesture,
|
DropGesture,
|
||||||
ContextMenuGesture,
|
|
||||||
GestureProvider,
|
GestureProvider,
|
||||||
GestureRepresenter,
|
GestureRepresenter,
|
||||||
DndService,
|
DndService,
|
||||||
TemplateLinker,
|
TemplateLinker,
|
||||||
ContextMenuAction,
|
|
||||||
TemplatePrefetcher,
|
TemplatePrefetcher,
|
||||||
legacyRegistry
|
legacyRegistry
|
||||||
) {
|
) {
|
||||||
@ -88,14 +84,6 @@ define([
|
|||||||
"dndService",
|
"dndService",
|
||||||
"$q"
|
"$q"
|
||||||
]
|
]
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "menu",
|
|
||||||
"implementation": ContextMenuGesture,
|
|
||||||
"depends": [
|
|
||||||
"$timeout",
|
|
||||||
"agentService"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"components": [
|
"components": [
|
||||||
@ -136,19 +124,6 @@ define([
|
|||||||
"comment": "For internal use by mct-include and mct-representation."
|
"comment": "For internal use by mct-include and mct-representation."
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"actions": [
|
|
||||||
{
|
|
||||||
"key": "menu",
|
|
||||||
"implementation": ContextMenuAction,
|
|
||||||
"depends": [
|
|
||||||
"$compile",
|
|
||||||
"$document",
|
|
||||||
"$rootScope",
|
|
||||||
"popupService",
|
|
||||||
"agentService"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"runs": [
|
"runs": [
|
||||||
{
|
{
|
||||||
"priority": "mandatory",
|
"priority": "mandatory",
|
||||||
|
@ -1,138 +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.
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Module defining ContextMenuAction. Created by shale on 06/30/2015.
|
|
||||||
*/
|
|
||||||
define(
|
|
||||||
["../gestures/GestureConstants"],
|
|
||||||
function (GestureConstants) {
|
|
||||||
|
|
||||||
var MENU_TEMPLATE = "<mct-representation key=\"'context-menu'\" " +
|
|
||||||
"mct-object=\"domainObject\" " +
|
|
||||||
"ng-class=\"menuClass\" " +
|
|
||||||
"ng-style=\"menuStyle\">" +
|
|
||||||
"</mct-representation>",
|
|
||||||
dismissExistingMenu;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Launches a custom context menu for the domain object it contains.
|
|
||||||
*
|
|
||||||
* @memberof platform/representation
|
|
||||||
* @constructor
|
|
||||||
* @param $compile Angular's $compile service
|
|
||||||
* @param $document the current document
|
|
||||||
* @param $rootScope Angular's root scope
|
|
||||||
* @param {platform/commonUI/general.PopupService} popupService
|
|
||||||
* @param actionContext the context in which the action
|
|
||||||
* should be performed
|
|
||||||
* @implements {Action}
|
|
||||||
*/
|
|
||||||
function ContextMenuAction(
|
|
||||||
$compile,
|
|
||||||
$document,
|
|
||||||
$rootScope,
|
|
||||||
popupService,
|
|
||||||
agentService,
|
|
||||||
actionContext
|
|
||||||
) {
|
|
||||||
this.$compile = $compile;
|
|
||||||
this.agentService = agentService;
|
|
||||||
this.actionContext = actionContext;
|
|
||||||
this.popupService = popupService;
|
|
||||||
this.getDocument = function () {
|
|
||||||
return $document;
|
|
||||||
};
|
|
||||||
this.getRootScope = function () {
|
|
||||||
return $rootScope;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
ContextMenuAction.prototype.perform = function () {
|
|
||||||
var $compile = this.$compile,
|
|
||||||
$document = this.getDocument(),
|
|
||||||
$rootScope = this.getRootScope(),
|
|
||||||
actionContext = this.actionContext,
|
|
||||||
eventCoords = [
|
|
||||||
actionContext.event.pageX,
|
|
||||||
actionContext.event.pageY
|
|
||||||
],
|
|
||||||
menuDim = GestureConstants.MCT_MENU_DIMENSIONS,
|
|
||||||
body = $document.find('body'),
|
|
||||||
scope = $rootScope.$new(),
|
|
||||||
initiatingEvent = this.agentService.isMobile() ?
|
|
||||||
'touchstart' : 'mousedown',
|
|
||||||
menu,
|
|
||||||
popup;
|
|
||||||
|
|
||||||
// Remove the context menu
|
|
||||||
function dismiss() {
|
|
||||||
if (popup) {
|
|
||||||
popup.dismiss();
|
|
||||||
popup = undefined;
|
|
||||||
}
|
|
||||||
scope.$destroy();
|
|
||||||
body.off("mousedown", dismiss);
|
|
||||||
dismissExistingMenu = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dismiss any menu which was already showing
|
|
||||||
if (dismissExistingMenu) {
|
|
||||||
dismissExistingMenu();
|
|
||||||
}
|
|
||||||
|
|
||||||
// ...and record the presence of this menu.
|
|
||||||
dismissExistingMenu = dismiss;
|
|
||||||
|
|
||||||
// Set up the scope, including menu positioning
|
|
||||||
scope.domainObject = actionContext.domainObject;
|
|
||||||
scope.menuClass = { "context-menu-holder": true };
|
|
||||||
// Create the context menu
|
|
||||||
menu = $compile(MENU_TEMPLATE)(scope);
|
|
||||||
|
|
||||||
popup = this.popupService.display(menu, eventCoords, {
|
|
||||||
marginX: -menuDim[0],
|
|
||||||
marginY: -menuDim[1]
|
|
||||||
});
|
|
||||||
|
|
||||||
scope.menuClass['go-left'] = popup.goesLeft();
|
|
||||||
scope.menuClass['go-up'] = popup.goesUp();
|
|
||||||
|
|
||||||
// Stop propagation so that clicks or touches on the menu do not close the menu
|
|
||||||
menu.on(initiatingEvent, function (event) {
|
|
||||||
event.stopPropagation();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Dismiss the menu when body is clicked/touched elsewhere
|
|
||||||
// ('mousedown' because 'click' breaks left-click context menus)
|
|
||||||
// ('touchstart' because 'touch' breaks context menus up)
|
|
||||||
body.on(initiatingEvent, dismiss);
|
|
||||||
// NOTE: Apply to mobile?
|
|
||||||
menu.on('click', dismiss);
|
|
||||||
|
|
||||||
// Don't launch browser's context menu
|
|
||||||
actionContext.event.preventDefault();
|
|
||||||
};
|
|
||||||
|
|
||||||
return ContextMenuAction;
|
|
||||||
}
|
|
||||||
);
|
|
@ -1,100 +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.
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Module defining ContextMenuGesture.
|
|
||||||
* Created by vwoeltje on 11/17/14. Modified by shale on 06/30/2015.
|
|
||||||
*/
|
|
||||||
define(
|
|
||||||
function () {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add listeners to a representation such that it calls the
|
|
||||||
* context menu action for the domain object it contains.
|
|
||||||
*
|
|
||||||
* @memberof platform/representation
|
|
||||||
* @constructor
|
|
||||||
* @param element the jqLite-wrapped element which should exhibit
|
|
||||||
* the context menu
|
|
||||||
* @param {DomainObject} domainObject the object on which actions
|
|
||||||
* in the context menu will be performed
|
|
||||||
* @implements {Gesture}
|
|
||||||
*/
|
|
||||||
function ContextMenuGesture($timeout, agentService, element, domainObject) {
|
|
||||||
var isPressing,
|
|
||||||
isDragging,
|
|
||||||
longTouchTime = 500;
|
|
||||||
|
|
||||||
function showMenu(event) {
|
|
||||||
domainObject.getCapability('action').perform({
|
|
||||||
key: 'menu',
|
|
||||||
domainObject: domainObject,
|
|
||||||
event: event
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// When context menu event occurs, show object actions instead
|
|
||||||
if (!agentService.isMobile()) {
|
|
||||||
|
|
||||||
// When context menu event occurs, show object actions instead
|
|
||||||
element.on('contextmenu', showMenu);
|
|
||||||
} else if (agentService.isMobile()) {
|
|
||||||
|
|
||||||
// If on mobile device, then start timeout for the single touch event
|
|
||||||
// during the timeout 'isPressing' is true.
|
|
||||||
element.on('touchstart', function (event) {
|
|
||||||
if (event.touches.length < 2) {
|
|
||||||
isPressing = true;
|
|
||||||
|
|
||||||
// After the timeout, if 'isPressing' is
|
|
||||||
// true, display context menu for object
|
|
||||||
$timeout(function () {
|
|
||||||
if (isPressing && !isDragging) {
|
|
||||||
showMenu(event);
|
|
||||||
}
|
|
||||||
}, longTouchTime);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// If on Mobile Device, and user scrolls/drags set flag to true
|
|
||||||
element.on('touchmove', function () {
|
|
||||||
isDragging = true;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Whenever the touch event ends, 'isPressing' & 'isDragging' is false.
|
|
||||||
element.on('touchend', function () {
|
|
||||||
isPressing = false;
|
|
||||||
isDragging = false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.showMenuCallback = showMenu;
|
|
||||||
this.element = element;
|
|
||||||
}
|
|
||||||
|
|
||||||
ContextMenuGesture.prototype.destroy = function () {
|
|
||||||
this.element.off('contextmenu', this.showMenu);
|
|
||||||
};
|
|
||||||
|
|
||||||
return ContextMenuGesture;
|
|
||||||
}
|
|
||||||
);
|
|
@ -1,202 +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.
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Module defining ContextMenuActionSpec. Created by shale on 07/02/2015.
|
|
||||||
*/
|
|
||||||
define(
|
|
||||||
["../../src/actions/ContextMenuAction"],
|
|
||||||
function (ContextMenuAction) {
|
|
||||||
|
|
||||||
var JQLITE_FUNCTIONS = ["on", "off", "find", "append", "remove"],
|
|
||||||
DOMAIN_OBJECT_METHODS = ["getId", "getModel", "getCapability", "hasCapability", "useCapability"];
|
|
||||||
|
|
||||||
|
|
||||||
describe("The 'context menu' action", function () {
|
|
||||||
var mockCompile,
|
|
||||||
mockCompiledTemplate,
|
|
||||||
mockMenu,
|
|
||||||
mockDocument,
|
|
||||||
mockBody,
|
|
||||||
mockPopupService,
|
|
||||||
mockRootScope,
|
|
||||||
mockAgentService,
|
|
||||||
mockScope,
|
|
||||||
mockDomainObject,
|
|
||||||
mockEvent,
|
|
||||||
mockPopup,
|
|
||||||
mockActionContext,
|
|
||||||
action;
|
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
mockCompile = jasmine.createSpy("$compile");
|
|
||||||
mockCompiledTemplate = jasmine.createSpy("template");
|
|
||||||
mockMenu = jasmine.createSpyObj("menu", JQLITE_FUNCTIONS);
|
|
||||||
mockDocument = jasmine.createSpyObj("$document", JQLITE_FUNCTIONS);
|
|
||||||
mockBody = jasmine.createSpyObj("body", JQLITE_FUNCTIONS);
|
|
||||||
mockPopupService =
|
|
||||||
jasmine.createSpyObj("popupService", ["display"]);
|
|
||||||
mockPopup = jasmine.createSpyObj("popup", [
|
|
||||||
"dismiss",
|
|
||||||
"goesLeft",
|
|
||||||
"goesUp"
|
|
||||||
]);
|
|
||||||
mockRootScope = jasmine.createSpyObj("$rootScope", ["$new"]);
|
|
||||||
mockAgentService = jasmine.createSpyObj("agentService", ["isMobile"]);
|
|
||||||
mockScope = jasmine.createSpyObj("scope", ["$destroy"]);
|
|
||||||
mockDomainObject = jasmine.createSpyObj("domainObject", DOMAIN_OBJECT_METHODS);
|
|
||||||
mockEvent = jasmine.createSpyObj("event", ["preventDefault", "stopPropagation"]);
|
|
||||||
mockEvent.pageX = 123;
|
|
||||||
mockEvent.pageY = 321;
|
|
||||||
|
|
||||||
mockCompile.and.returnValue(mockCompiledTemplate);
|
|
||||||
mockCompiledTemplate.and.returnValue(mockMenu);
|
|
||||||
mockDocument.find.and.returnValue(mockBody);
|
|
||||||
mockRootScope.$new.and.returnValue(mockScope);
|
|
||||||
mockPopupService.display.and.returnValue(mockPopup);
|
|
||||||
|
|
||||||
mockActionContext = {key: 'menu', domainObject: mockDomainObject, event: mockEvent};
|
|
||||||
|
|
||||||
action = new ContextMenuAction(
|
|
||||||
mockCompile,
|
|
||||||
mockDocument,
|
|
||||||
mockRootScope,
|
|
||||||
mockPopupService,
|
|
||||||
mockAgentService,
|
|
||||||
mockActionContext
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("displays a popup when performed", function () {
|
|
||||||
action.perform();
|
|
||||||
expect(mockPopupService.display).toHaveBeenCalledWith(
|
|
||||||
mockMenu,
|
|
||||||
[mockEvent.pageX, mockEvent.pageY],
|
|
||||||
jasmine.any(Object)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("prevents the default context menu behavior", function () {
|
|
||||||
action.perform();
|
|
||||||
expect(mockEvent.preventDefault).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("adds classes to menus based on position", function () {
|
|
||||||
var booleans = [false, true];
|
|
||||||
|
|
||||||
booleans.forEach(function (goLeft) {
|
|
||||||
booleans.forEach(function (goUp) {
|
|
||||||
mockPopup.goesLeft.and.returnValue(goLeft);
|
|
||||||
mockPopup.goesUp.and.returnValue(goUp);
|
|
||||||
action.perform();
|
|
||||||
expect(!!mockScope.menuClass['go-up'])
|
|
||||||
.toEqual(goUp);
|
|
||||||
expect(!!mockScope.menuClass['go-left'])
|
|
||||||
.toEqual(goLeft);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
it("removes a menu when body is clicked", function () {
|
|
||||||
// Show the menu
|
|
||||||
action.perform();
|
|
||||||
|
|
||||||
// Verify precondition
|
|
||||||
expect(mockBody.remove).not.toHaveBeenCalled();
|
|
||||||
|
|
||||||
// Find and fire body's mousedown listener
|
|
||||||
mockBody.on.calls.all().forEach(function (call) {
|
|
||||||
if (call.args[0] === 'mousedown') {
|
|
||||||
call.args[1]();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Menu should have been removed
|
|
||||||
expect(mockPopup.dismiss).toHaveBeenCalled();
|
|
||||||
|
|
||||||
// Listener should have been detached from body
|
|
||||||
expect(mockBody.off).toHaveBeenCalledWith(
|
|
||||||
'mousedown',
|
|
||||||
jasmine.any(Function)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("removes a menu when it is clicked", function () {
|
|
||||||
// Show the menu
|
|
||||||
action.perform();
|
|
||||||
|
|
||||||
// Verify precondition
|
|
||||||
expect(mockMenu.remove).not.toHaveBeenCalled();
|
|
||||||
|
|
||||||
// Find and fire menu's click listener
|
|
||||||
mockMenu.on.calls.all().forEach(function (call) {
|
|
||||||
if (call.args[0] === 'click') {
|
|
||||||
call.args[1]();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Menu should have been removed
|
|
||||||
expect(mockPopup.dismiss).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("keeps a menu when menu is clicked", function () {
|
|
||||||
// Show the menu
|
|
||||||
action.perform();
|
|
||||||
// Find and fire body's mousedown listener
|
|
||||||
mockMenu.on.calls.all().forEach(function (call) {
|
|
||||||
if (call.args[0] === 'mousedown') {
|
|
||||||
call.args[1](mockEvent);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Menu should have been removed
|
|
||||||
expect(mockPopup.dismiss).not.toHaveBeenCalled();
|
|
||||||
|
|
||||||
// Listener should have been detached from body
|
|
||||||
expect(mockBody.off).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("keeps a menu when menu is clicked on mobile", function () {
|
|
||||||
mockAgentService.isMobile.and.returnValue(true);
|
|
||||||
action = new ContextMenuAction(
|
|
||||||
mockCompile,
|
|
||||||
mockDocument,
|
|
||||||
mockRootScope,
|
|
||||||
mockPopupService,
|
|
||||||
mockAgentService,
|
|
||||||
mockActionContext
|
|
||||||
);
|
|
||||||
action.perform();
|
|
||||||
|
|
||||||
mockMenu.on.calls.all().forEach(function (call) {
|
|
||||||
if (call.args[0] === 'touchstart') {
|
|
||||||
call.args[1](mockEvent);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(mockPopup.dismiss).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
@ -1,119 +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.
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Module defining ContextMenuGestureSpec. Created by vwoeltje on 11/22/14.
|
|
||||||
*/
|
|
||||||
define(
|
|
||||||
["../../src/gestures/ContextMenuGesture"],
|
|
||||||
function (ContextMenuGesture) {
|
|
||||||
|
|
||||||
var JQLITE_FUNCTIONS = ["on", "off", "find", "append", "remove"],
|
|
||||||
DOMAIN_OBJECT_METHODS = ["getId", "getModel", "getCapability", "hasCapability", "useCapability"];
|
|
||||||
|
|
||||||
|
|
||||||
describe("The 'context menu' gesture", function () {
|
|
||||||
var mockTimeout,
|
|
||||||
mockElement,
|
|
||||||
mockAgentService,
|
|
||||||
mockDomainObject,
|
|
||||||
mockTouchEvent,
|
|
||||||
mockContextMenuAction,
|
|
||||||
mockTouch,
|
|
||||||
gesture,
|
|
||||||
fireGesture,
|
|
||||||
fireTouchStartGesture,
|
|
||||||
fireTouchEndGesture;
|
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
mockTimeout = jasmine.createSpy("$timeout");
|
|
||||||
mockElement = jasmine.createSpyObj("element", JQLITE_FUNCTIONS);
|
|
||||||
mockAgentService = jasmine.createSpyObj("agentService", ["isMobile"]);
|
|
||||||
mockDomainObject = jasmine.createSpyObj("domainObject", DOMAIN_OBJECT_METHODS);
|
|
||||||
mockContextMenuAction = jasmine.createSpyObj(
|
|
||||||
"action",
|
|
||||||
["perform", "getActions"]
|
|
||||||
);
|
|
||||||
|
|
||||||
mockDomainObject.getCapability.and.returnValue(mockContextMenuAction);
|
|
||||||
mockContextMenuAction.perform.and.returnValue(jasmine.any(Function));
|
|
||||||
mockAgentService.isMobile.and.returnValue(false);
|
|
||||||
|
|
||||||
|
|
||||||
gesture = new ContextMenuGesture(mockTimeout, mockAgentService, mockElement, mockDomainObject);
|
|
||||||
|
|
||||||
// Capture the contextmenu callback
|
|
||||||
fireGesture = mockElement.on.calls.mostRecent().args[1];
|
|
||||||
});
|
|
||||||
|
|
||||||
it("attaches a callback for context menu events", function () {
|
|
||||||
// Fire a click and expect it to happen
|
|
||||||
fireGesture();
|
|
||||||
expect(mockElement.on).toHaveBeenCalledWith(
|
|
||||||
"contextmenu",
|
|
||||||
jasmine.any(Function)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("detaches a callback for context menu events when destroyed", function () {
|
|
||||||
expect(mockElement.off).not.toHaveBeenCalled();
|
|
||||||
|
|
||||||
gesture.destroy();
|
|
||||||
|
|
||||||
expect(mockElement.off).toHaveBeenCalledWith(
|
|
||||||
"contextmenu",
|
|
||||||
//mockElement.on.calls.mostRecent().args[1]
|
|
||||||
mockDomainObject.calls
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("attaches a callback for context menu events on mobile", function () {
|
|
||||||
// Mock touch event and set to mobile device
|
|
||||||
mockTouchEvent = jasmine.createSpyObj("event", ["preventDefault", "touches"]);
|
|
||||||
mockTouch = jasmine.createSpyObj("touch", ["length"]);
|
|
||||||
mockTouch.length = 1;
|
|
||||||
mockTouchEvent.touches.and.returnValue(mockTouch);
|
|
||||||
mockAgentService.isMobile.and.returnValue(true);
|
|
||||||
|
|
||||||
// Then create new (mobile) gesture
|
|
||||||
gesture = new ContextMenuGesture(mockTimeout, mockAgentService, mockElement, mockDomainObject);
|
|
||||||
|
|
||||||
// Set calls for the touchstart and touchend gestures
|
|
||||||
fireTouchStartGesture = mockElement.on.calls.all()[1].args[1];
|
|
||||||
fireTouchEndGesture = mockElement.on.calls.mostRecent().args[1];
|
|
||||||
|
|
||||||
// Fire touchstart and expect touch start to begin
|
|
||||||
fireTouchStartGesture(mockTouchEvent);
|
|
||||||
expect(mockElement.on).toHaveBeenCalledWith(
|
|
||||||
"touchstart",
|
|
||||||
jasmine.any(Function)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Expect timeout to begin and then fireTouchEnd
|
|
||||||
expect(mockTimeout).toHaveBeenCalled();
|
|
||||||
mockTimeout.calls.mostRecent().args[0]();
|
|
||||||
fireTouchEndGesture(mockTouchEvent);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
@ -24,7 +24,7 @@ import LegacyContextMenuAction from './LegacyContextMenuAction';
|
|||||||
|
|
||||||
export default function LegacyActionAdapter(openmct, legacyActions) {
|
export default function LegacyActionAdapter(openmct, legacyActions) {
|
||||||
function contextualCategoryOnly(action) {
|
function contextualCategoryOnly(action) {
|
||||||
if (action.category === 'contextual') {
|
if (action.category === 'contextual' || (Array.isArray(action.category) && action.category.includes('contextual'))) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
console.warn(`DEPRECATION WARNING: Action ${action.definition.key} in bundle ${action.bundle.path} is non-contextual and should be migrated.`);
|
console.warn(`DEPRECATION WARNING: Action ${action.definition.key} in bundle ${action.bundle.path} is non-contextual and should be migrated.`);
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
import { timingSafeEqual } from "crypto";
|
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
* Open MCT, Copyright (c) 2014-2018, United States Government
|
* Open MCT, Copyright (c) 2014-2018, United States Government
|
||||||
* as represented by the Administrator of the National Aeronautics and Space
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
@ -21,6 +19,9 @@ import { timingSafeEqual } from "crypto";
|
|||||||
* this source code distribution or the Licensing information page available
|
* this source code distribution or the Licensing information page available
|
||||||
* at runtime from the About dialog for additional information.
|
* at runtime from the About dialog for additional information.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
import _ from 'lodash';
|
||||||
|
const INSIDE_EDIT_PATH_BLACKLIST = ["copy", "follow", "link", "locate", "move", "link"];
|
||||||
|
const OUTSIDE_EDIT_PATH_BLACKLIST = ["copy", "follow", "properties", "move", "link", "remove", "locate"];
|
||||||
|
|
||||||
export default class LegacyContextMenuAction {
|
export default class LegacyContextMenuAction {
|
||||||
constructor(openmct, LegacyAction) {
|
constructor(openmct, LegacyAction) {
|
||||||
@ -33,9 +34,34 @@ export default class LegacyContextMenuAction {
|
|||||||
|
|
||||||
appliesTo(objectPath) {
|
appliesTo(objectPath) {
|
||||||
let legacyObject = this.openmct.legacyObject(objectPath);
|
let legacyObject = this.openmct.legacyObject(objectPath);
|
||||||
return this.LegacyAction.appliesTo({
|
|
||||||
domainObject: legacyObject
|
return (this.LegacyAction.appliesTo === undefined ||
|
||||||
});
|
this.LegacyAction.appliesTo({domainObject: legacyObject})) &&
|
||||||
|
!this.isBlacklisted(objectPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
isBlacklisted(objectPath) {
|
||||||
|
let navigatedObject = this.openmct.router.path[0];
|
||||||
|
let isEditing = this.openmct.editor.isEditing();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is the object being edited, or a child of the object being edited?
|
||||||
|
*/
|
||||||
|
function isInsideEditPath() {
|
||||||
|
return objectPath.some((object) => _.eq(object.identifier, navigatedObject.identifier));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isEditing) {
|
||||||
|
if (isInsideEditPath()) {
|
||||||
|
return INSIDE_EDIT_PATH_BLACKLIST.some(actionKey => this.LegacyAction.key === actionKey);
|
||||||
|
} else {
|
||||||
|
return OUTSIDE_EDIT_PATH_BLACKLIST.some(actionKey => this.LegacyAction.key === actionKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
invoke(objectPath) {
|
invoke(objectPath) {
|
||||||
|
@ -50,7 +50,6 @@
|
|||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
|
|
||||||
> * + * {
|
> * + * {
|
||||||
@include test();
|
|
||||||
margin-top: $interiorMargin;
|
margin-top: $interiorMargin;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,11 +4,11 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import contextMenu from '../../../ui/components/mixins/context-menu'
|
import contextMenu from '../../../ui/components/mixins/context-menu-gesture'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: ['object-path'],
|
props: ['objectPath'],
|
||||||
mixins: [contextMenu]
|
mixins: [contextMenu],
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -150,11 +150,11 @@
|
|||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import contextMenu from '../../../ui/components/mixins/context-menu';
|
import contextMenuGesture from '../../../ui/components/mixins/context-menu-gesture';
|
||||||
import objectLink from '../../../ui/components/mixins/object-link';
|
import objectLink from '../../../ui/components/mixins/object-link';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
mixins: [contextMenu, objectLink],
|
mixins: [contextMenuGesture, objectLink],
|
||||||
props: ['item']
|
props: ['item']
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -54,11 +54,11 @@
|
|||||||
<script>
|
<script>
|
||||||
|
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import contextMenu from '../../../ui/components/mixins/context-menu';
|
import contextMenuGesture from '../../../ui/components/mixins/context-menu-gesture';
|
||||||
import objectLink from '../../../ui/components/mixins/object-link';
|
import objectLink from '../../../ui/components/mixins/object-link';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
mixins: [contextMenu, objectLink],
|
mixins: [contextMenuGesture, objectLink],
|
||||||
props: ['item'],
|
props: ['item'],
|
||||||
methods: {
|
methods: {
|
||||||
formatTime(timestamp, format) {
|
formatTime(timestamp, format) {
|
||||||
|
@ -52,7 +52,6 @@
|
|||||||
this.domainObject = this.node.object;
|
this.domainObject = this.node.object;
|
||||||
let removeListener = this.openmct.objects.observe(this.domainObject, '*', (newObject) => {
|
let removeListener = this.openmct.objects.observe(this.domainObject, '*', (newObject) => {
|
||||||
this.domainObject = newObject;
|
this.domainObject = newObject;
|
||||||
this.node.objectPath.splice(0, 1, newObject);
|
|
||||||
});
|
});
|
||||||
this.$once('hook:destroyed', removeListener);
|
this.$once('hook:destroyed', removeListener);
|
||||||
if (this.openmct.composition.get(this.node.object)) {
|
if (this.openmct.composition.get(this.node.object)) {
|
||||||
|
@ -11,6 +11,14 @@ export default {
|
|||||||
mounted() {
|
mounted() {
|
||||||
//TODO: touch support
|
//TODO: touch support
|
||||||
this.$el.addEventListener('contextmenu', this.showContextMenu);
|
this.$el.addEventListener('contextmenu', this.showContextMenu);
|
||||||
|
|
||||||
|
function updateObject(oldObject, newObject) {
|
||||||
|
Object.assign(oldObject, newObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.objectPath.forEach(object => this.$once('hook:destroy',
|
||||||
|
this.openmct.objects.observe(object, '*', updateObject.bind(this, object)))
|
||||||
|
);
|
||||||
},
|
},
|
||||||
destroyed() {
|
destroyed() {
|
||||||
this.$el.removeEventListener('contextMenu', this.showContextMenu);
|
this.$el.removeEventListener('contextMenu', this.showContextMenu);
|
||||||
|
@ -1,40 +0,0 @@
|
|||||||
export default {
|
|
||||||
inject: ['openmct'],
|
|
||||||
props: {
|
|
||||||
'objectPath': {
|
|
||||||
type: Array,
|
|
||||||
default() {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
// TODO: handle mobile context menu listeners.
|
|
||||||
|
|
||||||
this.$el.addEventListener('contextmenu', this.showContextMenu);
|
|
||||||
|
|
||||||
this.objectPath.forEach((o, i) => {
|
|
||||||
let removeListener = this.openmct.objects.observe(
|
|
||||||
o,
|
|
||||||
'*',
|
|
||||||
(newDomainObject) => {
|
|
||||||
this.objectPath.splice(i, 1, newDomainObject);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
this.$once('hook:destroyed', removeListener);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
destroyed() {
|
|
||||||
this.$el.removeEventListener('contextmenu', this.showContextMenu);
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
showContextMenu(event) {
|
|
||||||
let legacyObject = this.openmct.legacyObject(this.objectPath);
|
|
||||||
legacyObject.getCapability('action').perform({
|
|
||||||
key: 'menu',
|
|
||||||
domainObject: legacyObject,
|
|
||||||
event: event
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
Reference in New Issue
Block a user