Compare commits
2 Commits
select-tab
...
table-perf
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d026a67ac0 | ||
|
|
78018628ce |
@@ -99,10 +99,10 @@ define([
|
|||||||
|
|
||||||
GeneratorMetadataProvider.prototype.getMetadata = function (domainObject) {
|
GeneratorMetadataProvider.prototype.getMetadata = function (domainObject) {
|
||||||
return _.extend(
|
return _.extend(
|
||||||
{},
|
{},
|
||||||
domainObject.telemetry,
|
domainObject.telemetry,
|
||||||
METADATA_BY_TYPE[domainObject.type]
|
METADATA_BY_TYPE[domainObject.type]
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
return GeneratorMetadataProvider;
|
return GeneratorMetadataProvider;
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
<span class="h-indicator" ng-controller="DialogLaunchController">
|
<span class="h-indicator" ng-controller="DialogLaunchController">
|
||||||
<!-- DO NOT ADD SPACES BETWEEN THE SPANS - IT ADDS WHITE SPACE!! -->
|
<!-- DO NOT ADD SPACES BETWEEN THE SPANS - IT ADDS WHITE SPACE!! -->
|
||||||
<div class="c-indicator c-indicator--clickable icon-box-with-arrow s-status-available"><span class="label c-indicator__label">
|
<div class="ls-indicator icon-box-with-arrow s-status-available"><span class="label">
|
||||||
<button ng-click="launchProgress(true)">Known</button>
|
<a ng-click="launchProgress(true)">Known</a>
|
||||||
<button ng-click="launchProgress(false)">Unknown</button>
|
<a ng-click="launchProgress(false)">Unknown</a>
|
||||||
<button ng-click="launchError()">Error</button>
|
<a ng-click="launchError()">Error</a>
|
||||||
<button ng-click="launchInfo()">Info</button>
|
<a ng-click="launchInfo()">Info</a>
|
||||||
</span></div>
|
</span></div>
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
<span class="h-indicator" ng-controller="NotificationLaunchController">
|
<span class="h-indicator" ng-controller="NotificationLaunchController">
|
||||||
<!-- DO NOT ADD SPACES BETWEEN THE SPANS - IT ADDS WHITE SPACE!! -->
|
<!-- DO NOT ADD SPACES BETWEEN THE SPANS - IT ADDS WHITE SPACE!! -->
|
||||||
<div class="c-indicator c-indicator--clickable icon-bell s-status-available"><span class="label c-indicator__label">
|
<div class="ls-indicator icon-bell s-status-available"><span class="label">
|
||||||
<button ng-click="newInfo()">Success</button>
|
<a ng-click="newInfo()">Success</a>
|
||||||
<button ng-click="newError()">Error</button>
|
<a ng-click="newError()">Error</a>
|
||||||
<button ng-click="newAlert()">Alert</button>
|
<a ng-click="newAlert()">Alert</a>
|
||||||
<button ng-click="newProgress()">Progress</button>
|
<a ng-click="newProgress()">Progress</a>
|
||||||
</span></div>
|
</span></div>
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
13
index.html
13
index.html
@@ -27,7 +27,7 @@
|
|||||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||||
<title></title>
|
<title></title>
|
||||||
<script src="dist/openmct.js"></script>
|
<script src="dist/openmct.js"></script>
|
||||||
<link rel="stylesheet" href="dist/styles/openmct.css">
|
<link rel="stylesheet" href="dist/openmct.css">
|
||||||
<link rel="icon" type="image/png" href="dist/favicons/favicon-32x32.png" sizes="32x32">
|
<link rel="icon" type="image/png" href="dist/favicons/favicon-32x32.png" sizes="32x32">
|
||||||
<link rel="icon" type="image/png" href="dist/favicons/favicon-96x96.png" sizes="96x96">
|
<link rel="icon" type="image/png" href="dist/favicons/favicon-96x96.png" sizes="96x96">
|
||||||
<link rel="icon" type="image/png" href="dist/favicons/favicon-16x16.png" sizes="16x16">
|
<link rel="icon" type="image/png" href="dist/favicons/favicon-16x16.png" sizes="16x16">
|
||||||
@@ -50,12 +50,10 @@
|
|||||||
openmct.install(openmct.plugins.Generator());
|
openmct.install(openmct.plugins.Generator());
|
||||||
openmct.install(openmct.plugins.ExampleImagery());
|
openmct.install(openmct.plugins.ExampleImagery());
|
||||||
openmct.install(openmct.plugins.UTCTimeSystem());
|
openmct.install(openmct.plugins.UTCTimeSystem());
|
||||||
|
openmct.install(openmct.plugins.ImportExport());
|
||||||
openmct.install(openmct.plugins.AutoflowView({
|
openmct.install(openmct.plugins.AutoflowView({
|
||||||
type: "telemetry.panel"
|
type: "telemetry.panel"
|
||||||
}));
|
}));
|
||||||
openmct.install(openmct.plugins.DisplayLayout({
|
|
||||||
showAsView: ['summary-widget', 'example.imagery']
|
|
||||||
}));
|
|
||||||
openmct.install(openmct.plugins.Conductor({
|
openmct.install(openmct.plugins.Conductor({
|
||||||
menuOptions: [
|
menuOptions: [
|
||||||
{
|
{
|
||||||
@@ -79,9 +77,10 @@
|
|||||||
}));
|
}));
|
||||||
openmct.install(openmct.plugins.SummaryWidget());
|
openmct.install(openmct.plugins.SummaryWidget());
|
||||||
openmct.install(openmct.plugins.Notebook());
|
openmct.install(openmct.plugins.Notebook());
|
||||||
openmct.install(openmct.plugins.Filters(['table', 'telemetry.plot.overlay']));
|
openmct.install(openmct.plugins.FolderView());
|
||||||
openmct.install(openmct.plugins.ObjectMigration());
|
openmct.install(openmct.plugins.Tabs());
|
||||||
openmct.install(openmct.plugins.ClearData(['table', 'telemetry.plot.overlay', 'telemetry.plot.stacked']));
|
openmct.install(openmct.plugins.FlexibleLayout());
|
||||||
|
openmct.install(openmct.plugins.LADTable());
|
||||||
openmct.start();
|
openmct.start();
|
||||||
</script>
|
</script>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
"description": "The Open MCT core platform",
|
"description": "The Open MCT core platform",
|
||||||
"dependencies": {},
|
"dependencies": {},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"acorn": "6.2.0",
|
|
||||||
"angular": "1.4.14",
|
"angular": "1.4.14",
|
||||||
"angular-route": "1.4.14",
|
"angular-route": "1.4.14",
|
||||||
"babel-eslint": "8.2.6",
|
"babel-eslint": "8.2.6",
|
||||||
@@ -26,7 +25,7 @@
|
|||||||
"eventemitter3": "^1.2.0",
|
"eventemitter3": "^1.2.0",
|
||||||
"exports-loader": "^0.7.0",
|
"exports-loader": "^0.7.0",
|
||||||
"express": "^4.13.1",
|
"express": "^4.13.1",
|
||||||
"fast-sass-loader": "1.4.6",
|
"fast-sass-loader": "^1.4.5",
|
||||||
"file-loader": "^1.1.11",
|
"file-loader": "^1.1.11",
|
||||||
"file-saver": "^1.3.8",
|
"file-saver": "^1.3.8",
|
||||||
"git-rev-sync": "^1.4.0",
|
"git-rev-sync": "^1.4.0",
|
||||||
@@ -56,7 +55,7 @@
|
|||||||
"node-bourbon": "^4.2.3",
|
"node-bourbon": "^4.2.3",
|
||||||
"node-sass": "^4.9.2",
|
"node-sass": "^4.9.2",
|
||||||
"painterro": "^0.2.65",
|
"painterro": "^0.2.65",
|
||||||
"printj": "^1.2.1",
|
"printj": "^1.1.0",
|
||||||
"raw-loader": "^0.5.1",
|
"raw-loader": "^0.5.1",
|
||||||
"request": "^2.69.0",
|
"request": "^2.69.0",
|
||||||
"split": "^1.0.0",
|
"split": "^1.0.0",
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ define([
|
|||||||
"./src/navigation/NavigateAction",
|
"./src/navigation/NavigateAction",
|
||||||
"./src/navigation/OrphanNavigationHandler",
|
"./src/navigation/OrphanNavigationHandler",
|
||||||
"./src/windowing/NewTabAction",
|
"./src/windowing/NewTabAction",
|
||||||
|
"./src/windowing/WindowTitler",
|
||||||
"./res/templates/browse.html",
|
"./res/templates/browse.html",
|
||||||
"./res/templates/browse-object.html",
|
"./res/templates/browse-object.html",
|
||||||
"./res/templates/browse/object-header.html",
|
"./res/templates/browse/object-header.html",
|
||||||
@@ -51,6 +52,7 @@ define([
|
|||||||
NavigateAction,
|
NavigateAction,
|
||||||
OrphanNavigationHandler,
|
OrphanNavigationHandler,
|
||||||
NewTabAction,
|
NewTabAction,
|
||||||
|
WindowTitler,
|
||||||
browseTemplate,
|
browseTemplate,
|
||||||
browseObjectTemplate,
|
browseObjectTemplate,
|
||||||
objectHeaderTemplate,
|
objectHeaderTemplate,
|
||||||
@@ -224,6 +226,14 @@ define([
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"runs": [
|
"runs": [
|
||||||
|
{
|
||||||
|
"implementation": WindowTitler,
|
||||||
|
"depends": [
|
||||||
|
"navigationService",
|
||||||
|
"$rootScope",
|
||||||
|
"$document"
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"implementation": OrphanNavigationHandler,
|
"implementation": OrphanNavigationHandler,
|
||||||
"depends": [
|
"depends": [
|
||||||
|
|||||||
51
platform/commonUI/browse/src/windowing/WindowTitler.js
Normal file
51
platform/commonUI/browse/src/windowing/WindowTitler.js
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* 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 () {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the title of the current window to reflect the name
|
||||||
|
* of the currently navigated-to domain object.
|
||||||
|
* @memberof platform/commonUI/browse
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function WindowTitler(navigationService, $rootScope, $document) {
|
||||||
|
// Look up name of the navigated domain object...
|
||||||
|
function getNavigatedObjectName() {
|
||||||
|
var navigatedObject = navigationService.getNavigation();
|
||||||
|
return navigatedObject && navigatedObject.getModel().name;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the window title...
|
||||||
|
function setTitle(name) {
|
||||||
|
$document[0].title = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Watch the former, and invoke the latter
|
||||||
|
$rootScope.$watch(getNavigatedObjectName, setTitle);
|
||||||
|
}
|
||||||
|
|
||||||
|
return WindowTitler;
|
||||||
|
}
|
||||||
|
);
|
||||||
78
platform/commonUI/browse/test/windowing/WindowTitlerSpec.js
Normal file
78
platform/commonUI/browse/test/windowing/WindowTitlerSpec.js
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* 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.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WindowTitlerSpec. Created by vwoeltje on 11/6/14.
|
||||||
|
*/
|
||||||
|
define(
|
||||||
|
["../../src/windowing/WindowTitler"],
|
||||||
|
function (WindowTitler) {
|
||||||
|
|
||||||
|
describe("The window titler", function () {
|
||||||
|
var mockNavigationService,
|
||||||
|
mockRootScope,
|
||||||
|
mockDocument,
|
||||||
|
mockDomainObject,
|
||||||
|
titler; // eslint-disable-line
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
mockNavigationService = jasmine.createSpyObj(
|
||||||
|
'navigationService',
|
||||||
|
['getNavigation']
|
||||||
|
);
|
||||||
|
mockRootScope = jasmine.createSpyObj(
|
||||||
|
'$rootScope',
|
||||||
|
['$watch']
|
||||||
|
);
|
||||||
|
mockDomainObject = jasmine.createSpyObj(
|
||||||
|
'domainObject',
|
||||||
|
['getModel']
|
||||||
|
);
|
||||||
|
mockDocument = [{}];
|
||||||
|
|
||||||
|
mockDomainObject.getModel.and.returnValue({ name: 'Test name' });
|
||||||
|
mockNavigationService.getNavigation.and.returnValue(mockDomainObject);
|
||||||
|
|
||||||
|
titler = new WindowTitler(
|
||||||
|
mockNavigationService,
|
||||||
|
mockRootScope,
|
||||||
|
mockDocument
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("listens for changes to the name of the navigated object", function () {
|
||||||
|
expect(mockRootScope.$watch).toHaveBeenCalledWith(
|
||||||
|
jasmine.any(Function),
|
||||||
|
jasmine.any(Function)
|
||||||
|
);
|
||||||
|
expect(mockRootScope.$watch.calls.mostRecent().args[0]())
|
||||||
|
.toEqual('Test name');
|
||||||
|
});
|
||||||
|
|
||||||
|
it("sets the title to the name of the navigated object", function () {
|
||||||
|
mockRootScope.$watch.calls.mostRecent().args[1]("Some name");
|
||||||
|
expect(mockDocument[0].title).toEqual("Some name");
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
@@ -28,7 +28,6 @@ define([
|
|||||||
"./res/templates/dialog.html",
|
"./res/templates/dialog.html",
|
||||||
"./res/templates/overlay-blocking-message.html",
|
"./res/templates/overlay-blocking-message.html",
|
||||||
"./res/templates/message.html",
|
"./res/templates/message.html",
|
||||||
"./res/templates/notification-message.html",
|
|
||||||
"./res/templates/overlay-message-list.html",
|
"./res/templates/overlay-message-list.html",
|
||||||
"./res/templates/overlay.html",
|
"./res/templates/overlay.html",
|
||||||
'legacyRegistry'
|
'legacyRegistry'
|
||||||
@@ -40,7 +39,6 @@ define([
|
|||||||
dialogTemplate,
|
dialogTemplate,
|
||||||
overlayBlockingMessageTemplate,
|
overlayBlockingMessageTemplate,
|
||||||
messageTemplate,
|
messageTemplate,
|
||||||
notificationMessageTemplate,
|
|
||||||
overlayMessageListTemplate,
|
overlayMessageListTemplate,
|
||||||
overlayTemplate,
|
overlayTemplate,
|
||||||
legacyRegistry
|
legacyRegistry
|
||||||
@@ -65,8 +63,7 @@ define([
|
|||||||
"depends": [
|
"depends": [
|
||||||
"$document",
|
"$document",
|
||||||
"$compile",
|
"$compile",
|
||||||
"$rootScope",
|
"$rootScope"
|
||||||
"$timeout"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -91,10 +88,6 @@ define([
|
|||||||
"key": "message",
|
"key": "message",
|
||||||
"template": messageTemplate
|
"template": messageTemplate
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"key": "notification-message",
|
|
||||||
"template": notificationMessageTemplate
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"key": "overlay-message-list",
|
"key": "overlay-message-list",
|
||||||
"template": overlayMessageListTemplate
|
"template": overlayMessageListTemplate
|
||||||
|
|||||||
@@ -19,24 +19,24 @@
|
|||||||
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.
|
||||||
-->
|
-->
|
||||||
<div class="c-overlay__top-bar">
|
<div class="abs top-bar">
|
||||||
<div class="c-overlay__dialog-title">{{ngModel.title}}</div>
|
<div class="dialog-title">{{ngModel.title}}</div>
|
||||||
<div class="c-overlay__dialog-hint hint">All fields marked <span class="req icon-asterisk"></span> are required.</div>
|
<div class="hint">All fields marked <span class="req icon-asterisk"></span> are required.</div>
|
||||||
</div>
|
</div>
|
||||||
<div class='c-overlay__contents-main'>
|
<div class='abs editor'>
|
||||||
<mct-form ng-model="ngModel.value"
|
<mct-form ng-model="ngModel.value"
|
||||||
structure="ngModel.structure"
|
structure="ngModel.structure"
|
||||||
class="validates"
|
class="validates"
|
||||||
name="createForm">
|
name="createForm">
|
||||||
</mct-form>
|
</mct-form>
|
||||||
</div>
|
</div>
|
||||||
<div class="c-overlay__button-bar">
|
<div class="abs bottom-bar">
|
||||||
<a class='c-button c-button--major'
|
<a class='s-button major'
|
||||||
ng-class="{ disabled: !createForm.$valid }"
|
ng-class="{ disabled: !createForm.$valid }"
|
||||||
ng-click="ngModel.confirm()">
|
ng-click="ngModel.confirm()">
|
||||||
OK
|
OK
|
||||||
</a>
|
</a>
|
||||||
<a class='c-button '
|
<a class='s-button'
|
||||||
ng-click="ngModel.cancel()">
|
ng-click="ngModel.cancel()">
|
||||||
Cancel
|
Cancel
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -1,32 +1,25 @@
|
|||||||
<div class="c-message"
|
<div class="l-message"
|
||||||
ng-class="'message-severity-' + ngModel.severity">
|
ng-class="'message-severity-' + ngModel.severity">
|
||||||
<div class="w-message-contents">
|
<div class="w-message-contents">
|
||||||
<div class="c-message__top-bar">
|
<div class="top-bar">
|
||||||
<div class="c-message__title">{{ngModel.title}}</div>
|
<div class="title">{{ngModel.message}}</div>
|
||||||
</div>
|
|
||||||
<div class="c-message__hint" ng-hide="ngModel.hint === undefined">
|
|
||||||
{{ngModel.hint}}
|
|
||||||
<span ng-if="ngModel.timestamp !== undefined">[{{ngModel.timestamp}}]</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="message-body">
|
<div class="message-body">
|
||||||
<div class="message-action">
|
|
||||||
{{ngModel.actionText}}
|
|
||||||
</div>
|
|
||||||
<mct-include key="'progress-bar'"
|
<mct-include key="'progress-bar'"
|
||||||
ng-model="ngModel"
|
ng-model="ngModel"
|
||||||
ng-show="ngModel.progress !== undefined || ngModel.unknownProgress"></mct-include>
|
ng-show="ngModel.progressPerc !== undefined"></mct-include>
|
||||||
</div>
|
</div>
|
||||||
<div class="c-overlay__button-bar">
|
<div class="bottom-bar">
|
||||||
<button ng-repeat="dialogOption in ngModel.options"
|
<a ng-repeat="dialogOption in ngModel.options"
|
||||||
class="c-button"
|
class="s-button"
|
||||||
ng-click="dialogOption.callback()">
|
ng-click="dialogOption.callback()">
|
||||||
{{dialogOption.label}}
|
{{dialogOption.label}}
|
||||||
</button>
|
</a>
|
||||||
<button class="c-button c-button--major"
|
<a class="s-button major"
|
||||||
ng-if="ngModel.primaryOption"
|
ng-if="ngModel.primaryOption"
|
||||||
ng-click="ngModel.primaryOption.callback()">
|
ng-click="ngModel.primaryOption.callback()">
|
||||||
{{ngModel.primaryOption.label}}
|
{{ngModel.primaryOption.label}}
|
||||||
</button>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,25 +0,0 @@
|
|||||||
<div class="c-message"
|
|
||||||
ng-class="'message-severity-' + ngModel.severity">
|
|
||||||
<div class="w-message-contents">
|
|
||||||
<div class="c-message__top-bar">
|
|
||||||
<div class="c-message__title">{{ngModel.message}}</div>
|
|
||||||
</div>
|
|
||||||
<div class="message-body">
|
|
||||||
<mct-include key="'progress-bar'"
|
|
||||||
ng-model="ngModel"
|
|
||||||
ng-show="ngModel.progressPerc !== undefined"></mct-include>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="c-overlay__button-bar">
|
|
||||||
<button ng-repeat="dialogOption in ngModel.options"
|
|
||||||
class="c-button"
|
|
||||||
ng-click="dialogOption.callback()">
|
|
||||||
{{dialogOption.label}}
|
|
||||||
</button>
|
|
||||||
<button class="c-button c-button--major"
|
|
||||||
ng-if="ngModel.primaryOption"
|
|
||||||
ng-click="ngModel.primaryOption.callback()">
|
|
||||||
{{ngModel.primaryOption.label}}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@@ -1,23 +1,22 @@
|
|||||||
<mct-container key="overlay">
|
<mct-container key="overlay">
|
||||||
<div class="t-message-list c-overlay__contents">
|
<div class="t-message-list">
|
||||||
<div class="c-overlay__top-bar">
|
<div class="top-bar">
|
||||||
<div class="c-overlay__dialog-title">{{ngModel.dialog.title}}</div>
|
<div class="dialog-title">{{ngModel.dialog.title}}</div>
|
||||||
<div class="c-overlay__dialog-hint">Displaying {{ngModel.dialog.messages.length}} message<span
|
<div class="hint">Displaying {{ngModel.dialog.messages.length}} message<span ng-show="ngModel.dialog.messages.length > 1 ||
|
||||||
ng-show="ngModel.dialog.messages.length > 1 ||
|
ngModel.dialog.messages.length == 0">s</span>
|
||||||
ngModel.dialog.messages.length == 0">s</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-messages c-overlay__messages">
|
<div class="w-messages">
|
||||||
<mct-include
|
<mct-include
|
||||||
ng-repeat="msg in ngModel.dialog.messages | orderBy: '-'"
|
ng-repeat="msg in ngModel.dialog.messages | orderBy: '-'"
|
||||||
key="'notification-message'" ng-model="msg.model"></mct-include>
|
key="'message'" ng-model="msg.model"></mct-include>
|
||||||
</div>
|
</div>
|
||||||
<div class="c-overlay__bottom-bar">
|
<div class="bottom-bar">
|
||||||
<button ng-repeat="dialogAction in ngModel.dialog.actions"
|
<a ng-repeat="dialogAction in ngModel.dialog.actions"
|
||||||
class="c-button c-button--major"
|
class="s-button major"
|
||||||
ng-click="dialogAction.action()">
|
ng-click="dialogAction.action()">
|
||||||
{{dialogAction.label}}
|
{{dialogAction.label}}
|
||||||
</button>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</mct-container>
|
</mct-container>
|
||||||
|
|||||||
@@ -19,18 +19,18 @@
|
|||||||
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.
|
||||||
-->
|
-->
|
||||||
<mct-container key="c-overlay__contents">
|
<mct-container key="overlay">
|
||||||
<div class=c-overlay__top-bar">
|
<div class="abs top-bar">
|
||||||
<div class="c-overlay__dialog-title">{{ngModel.dialog.title}}</div>
|
<div class="dialog-title">{{ngModel.dialog.title}}</div>
|
||||||
<div class="c-overlay__dialog-hint hint">{{ngModel.dialog.hint}}</div>
|
<div class="hint">{{ngModel.dialog.hint}}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class='c-overlay__contents-main'>
|
<div class='abs editor'>
|
||||||
<mct-include key="ngModel.dialog.template"
|
<mct-include key="ngModel.dialog.template"
|
||||||
parameters="ngModel.dialog.parameters"
|
parameters="ngModel.dialog.parameters"
|
||||||
ng-model="ngModel.dialog.model">
|
ng-model="ngModel.dialog.model">
|
||||||
</mct-include>
|
</mct-include>
|
||||||
</div>
|
</div>
|
||||||
<div class="c-overlay__button-bar">
|
<div class="abs bottom-bar">
|
||||||
<a ng-repeat="option in ngModel.dialog.options"
|
<a ng-repeat="option in ngModel.dialog.options"
|
||||||
href=''
|
href=''
|
||||||
class="s-button lg"
|
class="s-button lg"
|
||||||
|
|||||||
@@ -19,12 +19,12 @@
|
|||||||
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.
|
||||||
-->
|
-->
|
||||||
<div class="c-overlay l-overlay-small" ng-class="{'delayEntry100ms' : ngModel.delay}">
|
<div class="abs overlay l-dialog" ng-class="{'delayEntry100ms' : ngModel.delay}">
|
||||||
<div class="c-overlay__blocker"></div>
|
<div class="abs blocker"></div>
|
||||||
<div class="c-overlay__outer">
|
<div class="abs outer-holder">
|
||||||
<button ng-click="ngModel.cancel()"
|
<a ng-click="ngModel.cancel()"
|
||||||
ng-if="ngModel.cancel"
|
ng-if="ngModel.cancel"
|
||||||
class="c-click-icon c-overlay__close-button icon-x-in-circle"></button>
|
class="close icon-x-in-circle"></a>
|
||||||
<div class="c-overlay__contents" ng-transclude></div>
|
<div class="abs inner-holder contents" ng-transclude></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -44,9 +44,8 @@ define(
|
|||||||
* @memberof platform/commonUI/dialog
|
* @memberof platform/commonUI/dialog
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function OverlayService($document, $compile, $rootScope, $timeout) {
|
function OverlayService($document, $compile, $rootScope) {
|
||||||
this.$compile = $compile;
|
this.$compile = $compile;
|
||||||
this.$timeout = $timeout;
|
|
||||||
|
|
||||||
// Don't include $document and $rootScope directly;
|
// Don't include $document and $rootScope directly;
|
||||||
// avoids https://docs.angularjs.org/error/ng/cpws
|
// avoids https://docs.angularjs.org/error/ng/cpws
|
||||||
@@ -94,14 +93,12 @@ define(
|
|||||||
scope.key = key;
|
scope.key = key;
|
||||||
scope.typeClass = typeClass || 't-dialog';
|
scope.typeClass = typeClass || 't-dialog';
|
||||||
|
|
||||||
this.$timeout(() => {
|
// Create the overlay element and add it to the document's body
|
||||||
// Create the overlay element and add it to the document's body
|
element = this.$compile(TEMPLATE)(scope);
|
||||||
element = this.$compile(TEMPLATE)(scope);
|
|
||||||
|
// Append so that most recent dialog is last in DOM. This means the most recent dialog will be on top when
|
||||||
// Append so that most recent dialog is last in DOM. This means the most recent dialog will be on top when
|
// multiple overlays with the same z-index are active.
|
||||||
// multiple overlays with the same z-index are active.
|
this.findBody().append(element);
|
||||||
this.findBody().append(element);
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
dismiss: dismiss
|
dismiss: dismiss
|
||||||
|
|||||||
@@ -35,20 +35,16 @@ define(
|
|||||||
mockTemplate,
|
mockTemplate,
|
||||||
mockElement,
|
mockElement,
|
||||||
mockScope,
|
mockScope,
|
||||||
mockTimeout,
|
|
||||||
overlayService;
|
overlayService;
|
||||||
|
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
mockDocument = jasmine.createSpyObj("$document", ["find"]);
|
mockDocument = jasmine.createSpyObj("$document", ["find"]);
|
||||||
mockCompile = jasmine.createSpy("$compile");
|
mockCompile = jasmine.createSpy("$compile");
|
||||||
mockRootScope = jasmine.createSpyObj("$rootScope", ["$new"]);
|
mockRootScope = jasmine.createSpyObj("$rootScope", ["$new"]);
|
||||||
mockBody = jasmine.createSpyObj("body", ["append"]);
|
mockBody = jasmine.createSpyObj("body", ["prepend"]);
|
||||||
mockTemplate = jasmine.createSpy("template");
|
mockTemplate = jasmine.createSpy("template");
|
||||||
mockElement = jasmine.createSpyObj("element", ["remove"]);
|
mockElement = jasmine.createSpyObj("element", ["remove"]);
|
||||||
mockScope = jasmine.createSpyObj("scope", ["$destroy"]);
|
mockScope = jasmine.createSpyObj("scope", ["$destroy"]);
|
||||||
mockTimeout = function (callback) {
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
|
|
||||||
mockDocument.find.and.returnValue(mockBody);
|
mockDocument.find.and.returnValue(mockBody);
|
||||||
mockCompile.and.returnValue(mockTemplate);
|
mockCompile.and.returnValue(mockTemplate);
|
||||||
@@ -58,8 +54,7 @@ define(
|
|||||||
overlayService = new OverlayService(
|
overlayService = new OverlayService(
|
||||||
mockDocument,
|
mockDocument,
|
||||||
mockCompile,
|
mockCompile,
|
||||||
mockRootScope,
|
mockRootScope
|
||||||
mockTimeout
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -72,7 +67,7 @@ define(
|
|||||||
|
|
||||||
it("adds the templated element to the body", function () {
|
it("adds the templated element to the body", function () {
|
||||||
overlayService.createOverlay("test", {});
|
overlayService.createOverlay("test", {});
|
||||||
expect(mockBody.append).toHaveBeenCalledWith(mockElement);
|
expect(mockBody.prepend).toHaveBeenCalledWith(mockElement);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("places the provided model/key in its template's scope", function () {
|
it("places the provided model/key in its template's scope", function () {
|
||||||
|
|||||||
@@ -160,7 +160,7 @@ define([
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"key": "remove",
|
"key": "remove",
|
||||||
"category": "legacy",
|
"category": "contextual",
|
||||||
"implementation": RemoveAction,
|
"implementation": RemoveAction,
|
||||||
"cssClass": "icon-trash",
|
"cssClass": "icon-trash",
|
||||||
"name": "Remove",
|
"name": "Remove",
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ define(
|
|||||||
name: "Properties",
|
name: "Properties",
|
||||||
rows: this.properties.map(function (property, index) {
|
rows: this.properties.map(function (property, index) {
|
||||||
// Property definition is same as form row definition
|
// Property definition is same as form row definition
|
||||||
var row = JSON.parse(JSON.stringify(property.getDefinition()));
|
var row = Object.create(property.getDefinition());
|
||||||
row.key = index;
|
row.key = index;
|
||||||
return row;
|
return row;
|
||||||
}).filter(function (row) {
|
}).filter(function (row) {
|
||||||
|
|||||||
@@ -23,7 +23,11 @@
|
|||||||
/**
|
/**
|
||||||
* Module defining RemoveAction. Created by vwoeltje on 11/17/14.
|
* Module defining RemoveAction. Created by vwoeltje on 11/17/14.
|
||||||
*/
|
*/
|
||||||
define([], function () {
|
define([
|
||||||
|
'./RemoveDialog'
|
||||||
|
], function (
|
||||||
|
RemoveDialog
|
||||||
|
) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct an action which will remove the provided object manifestation.
|
* Construct an action which will remove the provided object manifestation.
|
||||||
@@ -110,7 +114,12 @@ define([], function () {
|
|||||||
return parent.useCapability('mutation', doMutate);
|
return parent.useCapability('mutation', doMutate);
|
||||||
}
|
}
|
||||||
|
|
||||||
removeFromContext();
|
/*
|
||||||
|
* Pass in the function to remove the domain object so it can be
|
||||||
|
* associated with an 'OK' button press
|
||||||
|
*/
|
||||||
|
dialog = new RemoveDialog(this.openmct, domainObject, removeFromContext);
|
||||||
|
dialog.show();
|
||||||
};
|
};
|
||||||
|
|
||||||
// Object needs to have a parent for Remove to be applicable
|
// Object needs to have a parent for Remove to be applicable
|
||||||
|
|||||||
72
platform/commonUI/edit/src/actions/RemoveDialog.js
Normal file
72
platform/commonUI/edit/src/actions/RemoveDialog.js
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2014-2017, 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 () {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @callback removeCallback
|
||||||
|
* @param {DomainObject} domainObject the domain object to be removed
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a new Remove dialog.
|
||||||
|
*
|
||||||
|
* @param {DialogService} dialogService the service that shows the dialog
|
||||||
|
* @param {DomainObject} domainObject the domain object to be removed
|
||||||
|
* @param {removeCallback} removeCallback callback that handles removal of the domain object
|
||||||
|
* @memberof platform/commonUI/edit
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function RemoveDialog(openmct, domainObject, removeCallback) {
|
||||||
|
this.openmct = openmct;
|
||||||
|
this.domainObject = domainObject;
|
||||||
|
this.removeCallback = removeCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display a dialog to confirm the removal of a domain object.
|
||||||
|
*/
|
||||||
|
RemoveDialog.prototype.show = function () {
|
||||||
|
let dialog = this.openmct.overlays.dialog({
|
||||||
|
title: 'Remove ' + this.domainObject.getModel().name,
|
||||||
|
iconClass: 'alert',
|
||||||
|
message: 'Warning! This action will permanently remove this object. Are you sure you want to continue?',
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
label: 'OK',
|
||||||
|
callback: () => {
|
||||||
|
this.removeCallback();
|
||||||
|
dialog.dismiss();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Cancel',
|
||||||
|
callback: () => {
|
||||||
|
dialog.dismiss();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return RemoveDialog;
|
||||||
|
});
|
||||||
@@ -92,7 +92,16 @@ function (
|
|||||||
* @memberof platform/commonUI/edit.SaveAction#
|
* @memberof platform/commonUI/edit.SaveAction#
|
||||||
*/
|
*/
|
||||||
SaveAsAction.prototype.perform = function () {
|
SaveAsAction.prototype.perform = function () {
|
||||||
return this.save();
|
// Discard the current root view (which will be the editing
|
||||||
|
// UI, which will have been pushed atop the Browse UI.)
|
||||||
|
function returnToBrowse(object) {
|
||||||
|
if (object) {
|
||||||
|
object.getCapability("action").perform("navigate");
|
||||||
|
}
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.save().then(returnToBrowse);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -162,6 +171,9 @@ function (
|
|||||||
function saveAfterClone(clonedObject) {
|
function saveAfterClone(clonedObject) {
|
||||||
return this.openmct.editor.save().then(() => {
|
return this.openmct.editor.save().then(() => {
|
||||||
// Force mutation for search indexing
|
// Force mutation for search indexing
|
||||||
|
clonedObject.useCapability('mutation', (model) => {
|
||||||
|
return model;
|
||||||
|
});
|
||||||
return clonedObject;
|
return clonedObject;
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -170,14 +182,6 @@ function (
|
|||||||
return fetchObject(clonedObject.getId())
|
return fetchObject(clonedObject.getId())
|
||||||
}
|
}
|
||||||
|
|
||||||
function indexForSearch(savedObject) {
|
|
||||||
savedObject.useCapability('mutation', (model) => {
|
|
||||||
return model;
|
|
||||||
});
|
|
||||||
|
|
||||||
return savedObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
function onSuccess(object) {
|
function onSuccess(object) {
|
||||||
self.notificationService.info("Save Succeeded");
|
self.notificationService.info("Save Succeeded");
|
||||||
return object;
|
return object;
|
||||||
@@ -188,7 +192,7 @@ function (
|
|||||||
if (reason !== "user canceled") {
|
if (reason !== "user canceled") {
|
||||||
self.notificationService.error("Save Failed");
|
self.notificationService.error("Save Failed");
|
||||||
}
|
}
|
||||||
throw reason;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return getParent(domainObject)
|
return getParent(domainObject)
|
||||||
@@ -199,7 +203,6 @@ function (
|
|||||||
.then(undirtyOriginals)
|
.then(undirtyOriginals)
|
||||||
.then(saveAfterClone)
|
.then(saveAfterClone)
|
||||||
.then(finishEditing)
|
.then(finishEditing)
|
||||||
.then(indexForSearch)
|
|
||||||
.then(hideBlockingDialog)
|
.then(hideBlockingDialog)
|
||||||
.then(onSuccess)
|
.then(onSuccess)
|
||||||
.catch(onFailure);
|
.catch(onFailure);
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ define(
|
|||||||
* @returns boolean
|
* @returns boolean
|
||||||
*/
|
*/
|
||||||
EditorCapability.prototype.inEditContext = function () {
|
EditorCapability.prototype.inEditContext = function () {
|
||||||
|
console.warn('DEPRECATION WARNING: isEditing checks must be done via openmct.editor.');
|
||||||
return this.openmct.editor.isEditing();
|
return this.openmct.editor.isEditing();
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -73,6 +74,7 @@ define(
|
|||||||
* @returns {*}
|
* @returns {*}
|
||||||
*/
|
*/
|
||||||
EditorCapability.prototype.isEditContextRoot = function () {
|
EditorCapability.prototype.isEditContextRoot = function () {
|
||||||
|
console.warn('DEPRECATION WARNING: isEditing checks must be done via openmct.editor.');
|
||||||
return this.openmct.editor.isEditing();
|
return this.openmct.editor.isEditing();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -67,38 +67,20 @@ define(
|
|||||||
openmct = this.openmct,
|
openmct = this.openmct,
|
||||||
newObject;
|
newObject;
|
||||||
|
|
||||||
|
function onSave() {
|
||||||
|
// openmct.editor.save();
|
||||||
|
}
|
||||||
|
|
||||||
function onCancel() {
|
function onCancel() {
|
||||||
openmct.editor.cancel();
|
openmct.editor.cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
function isFirstViewEditable(domainObject) {
|
|
||||||
let firstView = openmct.objectViews.get(domainObject)[0];
|
|
||||||
|
|
||||||
return firstView && firstView.canEdit && firstView.canEdit(domainObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
function navigateAndEdit(object) {
|
|
||||||
let objectPath = object.getCapability('context').getPath(),
|
|
||||||
url = '#/browse/' + objectPath
|
|
||||||
.slice(1)
|
|
||||||
.map(function (o) {
|
|
||||||
return o && openmct.objects.makeKeyString(o.getId());
|
|
||||||
})
|
|
||||||
.join('/');
|
|
||||||
|
|
||||||
window.location.href = url;
|
|
||||||
|
|
||||||
if (isFirstViewEditable(object.useCapability('adapter'))) {
|
|
||||||
openmct.editor.edit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
newModel.type = this.type.getKey();
|
newModel.type = this.type.getKey();
|
||||||
newModel.location = this.parent.getId();
|
newModel.location = this.parent.getId();
|
||||||
newObject = this.parent.useCapability('instantiation', newModel);
|
newObject = this.parent.useCapability('instantiation', newModel);
|
||||||
|
|
||||||
openmct.editor.edit();
|
openmct.editor.edit();
|
||||||
newObject.getCapability("action").perform("save-as").then(navigateAndEdit, onCancel);
|
newObject.getCapability("action").perform("save-as").then(onSave, onCancel);
|
||||||
// TODO: support editing object without saving object first.
|
// TODO: support editing object without saving object first.
|
||||||
// Which means we have to toggle createwizard afterwards. For now,
|
// Which means we have to toggle createwizard afterwards. For now,
|
||||||
// We will disable this.
|
// We will disable this.
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ define(
|
|||||||
name: "Properties",
|
name: "Properties",
|
||||||
rows: this.properties.map(function (property, index) {
|
rows: this.properties.map(function (property, index) {
|
||||||
// Property definition is same as form row definition
|
// Property definition is same as form row definition
|
||||||
var row = JSON.parse(JSON.stringify(property.getDefinition()));
|
var row = Object.create(property.getDefinition());
|
||||||
|
|
||||||
// Use index as the key into the formValue;
|
// Use index as the key into the formValue;
|
||||||
// this correlates to the indexing provided by
|
// this correlates to the indexing provided by
|
||||||
|
|||||||
@@ -77,19 +77,14 @@ define([], function () {
|
|||||||
return promiseFn().then(nextFn);
|
return promiseFn().then(nextFn);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* Clear any existing persistence calls for object with given ID. This ensures only the most recent persistence
|
|
||||||
* call is executed. This should prevent stale objects being persisted and overwriting fresh ones.
|
|
||||||
*/
|
|
||||||
if (this.isScheduled(id)) {
|
|
||||||
this.clearTransactionsFor(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.clearTransactionFns[id] =
|
if (!this.isScheduled(id)) {
|
||||||
this.transactionService.addToTransaction(
|
this.clearTransactionFns[id] =
|
||||||
chain(onCommit, release),
|
this.transactionService.addToTransaction(
|
||||||
chain(onCancel, release)
|
chain(onCommit, release),
|
||||||
);
|
chain(onCancel, release)
|
||||||
|
);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -93,33 +93,24 @@ define(
|
|||||||
expect(mockOnCancel).toHaveBeenCalled();
|
expect(mockOnCancel).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Adds callbacks to transaction", function () {
|
it("ignores subsequent calls for the same object", function () {
|
||||||
beforeEach(function () {
|
manager.addToTransaction(
|
||||||
spyOn(manager, 'clearTransactionsFor');
|
testId,
|
||||||
manager.clearTransactionsFor.and.callThrough();
|
jasmine.createSpy(),
|
||||||
});
|
jasmine.createSpy()
|
||||||
|
);
|
||||||
|
expect(mockTransactionService.addToTransaction.calls.count())
|
||||||
|
.toEqual(1);
|
||||||
|
});
|
||||||
|
|
||||||
it("and clears pending calls if same object", function () {
|
it("accepts subsequent calls for other objects", function () {
|
||||||
manager.addToTransaction(
|
manager.addToTransaction(
|
||||||
testId,
|
'other-id',
|
||||||
jasmine.createSpy(),
|
jasmine.createSpy(),
|
||||||
jasmine.createSpy()
|
jasmine.createSpy()
|
||||||
);
|
);
|
||||||
expect(manager.clearTransactionsFor).toHaveBeenCalledWith(testId);
|
expect(mockTransactionService.addToTransaction.calls.count())
|
||||||
});
|
.toEqual(2);
|
||||||
|
|
||||||
it("and does not clear pending calls if different object", function () {
|
|
||||||
manager.addToTransaction(
|
|
||||||
'other-id',
|
|
||||||
jasmine.createSpy(),
|
|
||||||
jasmine.createSpy()
|
|
||||||
);
|
|
||||||
expect(manager.clearTransactionsFor).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(function () {
|
|
||||||
expect(mockTransactionService.addToTransaction.calls.count()).toEqual(2);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("does not remove callbacks from the transaction", function () {
|
it("does not remove callbacks from the transaction", function () {
|
||||||
|
|||||||
@@ -20,8 +20,8 @@
|
|||||||
at runtime from the About dialog for additional information.
|
at runtime from the About dialog for additional information.
|
||||||
-->
|
-->
|
||||||
<!-- DO NOT ADD SPACES BETWEEN THE SPANS - IT ADDS WHITE SPACE!! -->
|
<!-- DO NOT ADD SPACES BETWEEN THE SPANS - IT ADDS WHITE SPACE!! -->
|
||||||
<div class="c-indicator {{ngModel.getCssClass()}}"
|
<div class="ls-indicator {{ngModel.getCssClass()}}"
|
||||||
title="{{ngModel.getDescription()}}"
|
title="{{ngModel.getDescription()}}"
|
||||||
ng-show="ngModel.getText().length > 0">
|
ng-show="ngModel.getText().length > 0">
|
||||||
<span class="label c-indicator__label">{{ngModel.getText()}}</span>
|
<span class="label">{{ngModel.getText()}}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
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.
|
||||||
-->
|
-->
|
||||||
<div class="c-object-label">
|
<div class="t-object-label l-flex-row flex-elem grows">
|
||||||
<div class="c-object-label__type-icon {{type.getCssClass()}}" ng-class="{ 'l-icon-link':location.isLink() }"></div>
|
<div class="t-item-icon flex-elem {{type.getCssClass()}}" ng-class="{ 'l-icon-link':location.isLink() }"></div>
|
||||||
<div class='c-object-label__name'>{{model.name}}</div>
|
<div class='t-title-label flex-elem grows'>{{model.name}}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
<div ng-controller="BannerController" ng-show="active.notification"
|
<div ng-controller="BannerController" ng-show="active.notification"
|
||||||
class="c-message-banner {{active.notification.model.severity}}" ng-class="{
|
class="l-message-banner s-message-banner {{active.notification.model.severity}}" ng-class="{
|
||||||
'minimized': active.notification.model.minimized,
|
'minimized': active.notification.model.minimized,
|
||||||
'new': !active.notification.model.minimized}"
|
'new': !active.notification.model.minimized}"
|
||||||
ng-click="maximize(active.notification)">
|
ng-click="maximize(active.notification)">
|
||||||
<span class="c-message-banner__message">
|
<span class="banner-elem label">
|
||||||
{{active.notification.model.title}}
|
{{active.notification.model.title}}
|
||||||
</span>
|
</span>
|
||||||
<span ng-show="active.notification.model.progress !== undefined || active.notification.model.unknownProgress">
|
<span ng-show="active.notification.model.progress !== undefined || active.notification.model.unknownProgress">
|
||||||
<mct-include key="'progress-bar'" class="c-message-banner__progress-bar"
|
<mct-include key="'progress-bar'" class="banner-elem"
|
||||||
ng-model="active.notification.model">
|
ng-model="active.notification.model">
|
||||||
</mct-include>
|
</mct-include>
|
||||||
</span>
|
</span>
|
||||||
@@ -16,5 +16,5 @@
|
|||||||
ng-click="action(active.notification.model.primaryOption.callback, $event)">
|
ng-click="action(active.notification.model.primaryOption.callback, $event)">
|
||||||
{{active.notification.model.primaryOption.label}}
|
{{active.notification.model.primaryOption.label}}
|
||||||
</a>
|
</a>
|
||||||
<button class="c-message-banner__close-button c-click-icon icon-x-in-circle" ng-click="dismiss(active.notification, $event)"></button>
|
<a class="banner-elem close icon-x" ng-click="dismiss(active.notification, $event)"></a>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -20,11 +20,14 @@
|
|||||||
at runtime from the About dialog for additional information.
|
at runtime from the About dialog for additional information.
|
||||||
-->
|
-->
|
||||||
<span ng-controller="ToggleController as toggle">
|
<span ng-controller="ToggleController as toggle">
|
||||||
<div class="u-contents" ng-controller="TreeNodeController as treeNode">
|
<span ng-controller="TreeNodeController as treeNode">
|
||||||
<div class="c-tree__item menus-to-left"
|
<span
|
||||||
ng-class="{selected: treeNode.isSelected()}">
|
class="tree-item menus-to-left"
|
||||||
<span class='c-disclosure-triangle c-tree__item__view-control'
|
ng-class="{selected: treeNode.isSelected()}"
|
||||||
ng-class="{ 'is-enabled': model.composition !== undefined, 'c-disclosure-triangle--expanded': toggle.isActive() }"
|
>
|
||||||
|
<span
|
||||||
|
class='ui-symbol view-control flex-elem'
|
||||||
|
ng-class="{ 'has-children': model.composition !== undefined, expanded: toggle.isActive() }"
|
||||||
ng-click="toggle.toggle(); treeNode.trackExpansion()"
|
ng-click="toggle.toggle(); treeNode.trackExpansion()"
|
||||||
>
|
>
|
||||||
</span>
|
</span>
|
||||||
@@ -36,15 +39,19 @@
|
|||||||
ng-click="treeNode.select()"
|
ng-click="treeNode.select()"
|
||||||
>
|
>
|
||||||
</mct-representation>
|
</mct-representation>
|
||||||
</div>
|
</span>
|
||||||
<div class="u-contents"
|
<span
|
||||||
|
class="tree-item-subtree"
|
||||||
ng-show="toggle.isActive()"
|
ng-show="toggle.isActive()"
|
||||||
ng-if="model.composition !== undefined">
|
ng-if="model.composition !== undefined"
|
||||||
|
>
|
||||||
|
|
||||||
<mct-representation key="'subtree'"
|
<mct-representation key="'subtree'"
|
||||||
ng-model="ngModel"
|
ng-model="ngModel"
|
||||||
parameters="parameters"
|
parameters="parameters"
|
||||||
mct-object="treeNode.hasBeenExpanded() && domainObject">
|
mct-object="treeNode.hasBeenExpanded() && domainObject">
|
||||||
</mct-representation>
|
</mct-representation>
|
||||||
</div>
|
|
||||||
</div>
|
</span>
|
||||||
|
</span>
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -19,8 +19,8 @@
|
|||||||
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.
|
||||||
-->
|
-->
|
||||||
<ul class="c-tree">
|
<ul class="tree">
|
||||||
<li class="c-tree__item-h">
|
<li>
|
||||||
<mct-representation key="'tree-node'"
|
<mct-representation key="'tree-node'"
|
||||||
mct-object="domainObject"
|
mct-object="domainObject"
|
||||||
ng-model="ngModel"
|
ng-model="ngModel"
|
||||||
|
|||||||
@@ -1,2 +1,4 @@
|
|||||||
<span class="c-tree__item js-tree__item"></span>
|
<span class="tree-item menus-to-left">
|
||||||
<span class="c-tree__item-subtree"></span>
|
</span>
|
||||||
|
<span class="tree-item-subtree">
|
||||||
|
</span>
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
<span class='c-disclosure-triangle c-tree__item__view-control'></span>
|
<span class='ui-symbol view-control flex-elem'>
|
||||||
|
</span>
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
<div class="rep-object-label c-object-label c-tree__item__label">
|
<span class="rep-object-label">
|
||||||
<div class="c-object-label__type-icon c-tree__item__type-icon t-item-icon"></div>
|
<div class="t-object-label l-flex-row flex-elem grows">
|
||||||
<div class="c-object-label__name c-tree__item__name t-title-label"></div>
|
<div class="t-item-icon flex-elem"></div>
|
||||||
</div>
|
<div class='t-title-label flex-elem grows'></div>
|
||||||
|
</div>
|
||||||
|
</span>
|
||||||
|
|||||||
@@ -54,7 +54,6 @@ define(
|
|||||||
if (isDestroyed) {
|
if (isDestroyed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var removeSelectable = openmct.selection.selectable(
|
var removeSelectable = openmct.selection.selectable(
|
||||||
element[0],
|
element[0],
|
||||||
scope.$eval(attrs.mctSelectable),
|
scope.$eval(attrs.mctSelectable),
|
||||||
|
|||||||
@@ -37,9 +37,9 @@ define([
|
|||||||
this.expanded = state;
|
this.expanded = state;
|
||||||
|
|
||||||
if (state) {
|
if (state) {
|
||||||
this.el.addClass('c-disclosure-triangle--expanded');
|
this.el.addClass('expanded');
|
||||||
} else {
|
} else {
|
||||||
this.el.removeClass('c-disclosure-triangle--expanded');
|
this.el.removeClass('expanded');
|
||||||
}
|
}
|
||||||
|
|
||||||
this.callbacks.forEach(function (callback) {
|
this.callbacks.forEach(function (callback) {
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ define([
|
|||||||
], function ($, nodeTemplate, ToggleView, TreeLabelView) {
|
], function ($, nodeTemplate, ToggleView, TreeLabelView) {
|
||||||
|
|
||||||
function TreeNodeView(gestureService, subtreeFactory, selectFn, openmct) {
|
function TreeNodeView(gestureService, subtreeFactory, selectFn, openmct) {
|
||||||
this.li = $('<li class="c-tree__item-h">');
|
this.li = $('<li>');
|
||||||
this.openmct = openmct;
|
this.openmct = openmct;
|
||||||
this.statusClasses = [];
|
this.statusClasses = [];
|
||||||
|
|
||||||
@@ -38,7 +38,7 @@ define([
|
|||||||
if (!this.subtreeView) {
|
if (!this.subtreeView) {
|
||||||
this.subtreeView = subtreeFactory();
|
this.subtreeView = subtreeFactory();
|
||||||
this.subtreeView.model(this.activeObject);
|
this.subtreeView.model(this.activeObject);
|
||||||
this.li.find('.c-tree__item-subtree').eq(0)
|
this.li.find('.tree-item-subtree').eq(0)
|
||||||
.append($(this.subtreeView.elements()));
|
.append($(this.subtreeView.elements()));
|
||||||
}
|
}
|
||||||
$(this.subtreeView.elements()).removeClass('hidden');
|
$(this.subtreeView.elements()).removeClass('hidden');
|
||||||
@@ -85,9 +85,9 @@ define([
|
|||||||
var obj = domainObject.useCapability('adapter');
|
var obj = domainObject.useCapability('adapter');
|
||||||
var hasComposition = this.openmct.composition.get(obj) !== undefined;
|
var hasComposition = this.openmct.composition.get(obj) !== undefined;
|
||||||
if (hasComposition) {
|
if (hasComposition) {
|
||||||
$(this.toggleView.elements()).addClass('is-enabled');
|
$(this.toggleView.elements()).removeClass('no-children');
|
||||||
} else {
|
} else {
|
||||||
$(this.toggleView.elements()).removeClass('is-enabled');
|
$(this.toggleView.elements()).addClass('no-children');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,7 +120,7 @@ define([
|
|||||||
selectedIdPath = getIdPath(domainObject);
|
selectedIdPath = getIdPath(domainObject);
|
||||||
|
|
||||||
if (this.onSelectionPath) {
|
if (this.onSelectionPath) {
|
||||||
this.li.find('.js-tree__item').eq(0).removeClass('is-selected');
|
this.li.find('.tree-item').eq(0).removeClass('selected');
|
||||||
if (this.subtreeView) {
|
if (this.subtreeView) {
|
||||||
this.subtreeView.value(undefined);
|
this.subtreeView.value(undefined);
|
||||||
}
|
}
|
||||||
@@ -136,7 +136,7 @@ define([
|
|||||||
|
|
||||||
if (this.onSelectionPath) {
|
if (this.onSelectionPath) {
|
||||||
if (activeIdPath.length === selectedIdPath.length) {
|
if (activeIdPath.length === selectedIdPath.length) {
|
||||||
this.li.find('.js-tree__item').eq(0).addClass('is-selected');
|
this.li.find('.tree-item').eq(0).addClass('selected');
|
||||||
} else {
|
} else {
|
||||||
// Expand to reveal the selection
|
// Expand to reveal the selection
|
||||||
this.toggleView.value(true);
|
this.toggleView.value(true);
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ define([
|
|||||||
], function ($, TreeNodeView, spinnerTemplate) {
|
], function ($, TreeNodeView, spinnerTemplate) {
|
||||||
|
|
||||||
function TreeView(gestureService, openmct, selectFn) {
|
function TreeView(gestureService, openmct, selectFn) {
|
||||||
this.ul = $('<ul class="c-tree"></ul>');
|
this.ul = $('<ul class="tree"></ul>');
|
||||||
this.nodeViews = [];
|
this.nodeViews = [];
|
||||||
this.callbacks = [];
|
this.callbacks = [];
|
||||||
this.selectFn = selectFn || this.value.bind(this);
|
this.selectFn = selectFn || this.value.bind(this);
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
<!-- DO NOT ADD SPACES BETWEEN THE SPANS - IT ADDS WHITE SPACE!! -->
|
<!-- DO NOT ADD SPACES BETWEEN THE SPANS - IT ADDS WHITE SPACE!! -->
|
||||||
<div ng-show="notifications.length > 0" class="c-indicator c-indicator--clickable s-status-{{highest.severity}} icon-bell"
|
<div ng-show="notifications.length > 0" class="ls-indicator s-status-{{highest.severity}} icon-bell"
|
||||||
ng-controller="NotificationIndicatorController">
|
ng-controller="NotificationIndicatorController">
|
||||||
<span class="label c-indicator__label">
|
<span class="label">
|
||||||
<button ng-click="showNotificationsList()">
|
<a ng-click="showNotificationsList()">
|
||||||
{{notifications.length}} Notification<span ng-show="notifications.length > 1">s</span></button>
|
{{notifications.length}} Notification<span ng-show="notifications.length > 1">s</span></a>
|
||||||
</span><span class="c-indicator__count">{{notifications.length}}</span>
|
</span><span class="count">{{notifications.length}}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -43,10 +43,23 @@ define([], function () {
|
|||||||
var mutationTopic = topic('mutation');
|
var mutationTopic = topic('mutation');
|
||||||
mutationTopic.listen(function (domainObject) {
|
mutationTopic.listen(function (domainObject) {
|
||||||
var persistence = domainObject.getCapability('persistence');
|
var persistence = domainObject.getCapability('persistence');
|
||||||
|
var wasActive = transactionService.isActive();
|
||||||
cacheService.put(domainObject.getId(), domainObject.getModel());
|
cacheService.put(domainObject.getId(), domainObject.getModel());
|
||||||
|
|
||||||
if (hasChanged(domainObject)) {
|
if (hasChanged(domainObject)) {
|
||||||
persistence.persist();
|
|
||||||
|
if (!wasActive) {
|
||||||
|
transactionService.startTransaction();
|
||||||
|
}
|
||||||
|
|
||||||
|
transactionService.addToTransaction(
|
||||||
|
persistence.persist.bind(persistence),
|
||||||
|
persistence.refresh.bind(persistence)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!wasActive) {
|
||||||
|
transactionService.commit();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,27 +24,22 @@ define(
|
|||||||
["../../src/runs/TransactingMutationListener"],
|
["../../src/runs/TransactingMutationListener"],
|
||||||
function (TransactingMutationListener) {
|
function (TransactingMutationListener) {
|
||||||
|
|
||||||
describe("TransactingMutationListener", function () {
|
xdescribe("TransactingMutationListener", function () {
|
||||||
var mockTopic,
|
var mockTopic,
|
||||||
mockMutationTopic,
|
mockMutationTopic,
|
||||||
mockCacheService,
|
|
||||||
mockTransactionService,
|
mockTransactionService,
|
||||||
mockDomainObject,
|
mockDomainObject,
|
||||||
mockModel,
|
|
||||||
mockPersistence;
|
mockPersistence;
|
||||||
|
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
mockTopic = jasmine.createSpy('topic');
|
mockTopic = jasmine.createSpy('topic');
|
||||||
mockMutationTopic =
|
mockMutationTopic =
|
||||||
jasmine.createSpyObj('mutation', ['listen']);
|
jasmine.createSpyObj('mutation', ['listen']);
|
||||||
mockCacheService =
|
|
||||||
jasmine.createSpyObj('cacheService', [
|
|
||||||
'put'
|
|
||||||
]);
|
|
||||||
mockTransactionService =
|
mockTransactionService =
|
||||||
jasmine.createSpyObj('transactionService', [
|
jasmine.createSpyObj('transactionService', [
|
||||||
'isActive',
|
'isActive',
|
||||||
'startTransaction',
|
'startTransaction',
|
||||||
|
'addToTransaction',
|
||||||
'commit'
|
'commit'
|
||||||
]);
|
]);
|
||||||
mockDomainObject = jasmine.createSpyObj(
|
mockDomainObject = jasmine.createSpyObj(
|
||||||
@@ -57,24 +52,18 @@ define(
|
|||||||
);
|
);
|
||||||
|
|
||||||
mockTopic.and.callFake(function (t) {
|
mockTopic.and.callFake(function (t) {
|
||||||
expect(t).toBe('mutation');
|
return (t === 'mutation') && mockMutationTopic;
|
||||||
return mockMutationTopic;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
mockDomainObject.getId.and.returnValue('mockId');
|
|
||||||
mockDomainObject.getCapability.and.callFake(function (c) {
|
mockDomainObject.getCapability.and.callFake(function (c) {
|
||||||
expect(c).toBe('persistence');
|
return (c === 'persistence') && mockPersistence;
|
||||||
return mockPersistence;
|
|
||||||
});
|
});
|
||||||
mockModel = {};
|
|
||||||
mockDomainObject.getModel.and.returnValue(mockModel);
|
|
||||||
|
|
||||||
mockPersistence.persisted.and.returnValue(true);
|
mockPersistence.persisted.and.returnValue(true);
|
||||||
|
|
||||||
return new TransactingMutationListener(
|
return new TransactingMutationListener(
|
||||||
mockTopic,
|
mockTopic,
|
||||||
mockTransactionService,
|
mockTransactionService
|
||||||
mockCacheService
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -83,27 +72,48 @@ define(
|
|||||||
.toHaveBeenCalledWith(jasmine.any(Function));
|
.toHaveBeenCalledWith(jasmine.any(Function));
|
||||||
});
|
});
|
||||||
|
|
||||||
it("calls persist if the model has changed", function () {
|
[false, true].forEach(function (isActive) {
|
||||||
mockModel.persisted = Date.now();
|
var verb = isActive ? "is" : "isn't";
|
||||||
|
|
||||||
//Mark the model dirty by setting the mutated date later than the last persisted date.
|
function onlyWhenInactive(expectation) {
|
||||||
mockModel.modified = mockModel.persisted + 1;
|
return isActive ? expectation.not : expectation;
|
||||||
|
}
|
||||||
|
|
||||||
mockMutationTopic.listen.calls.mostRecent()
|
describe("when a transaction " + verb + " active", function () {
|
||||||
.args[0](mockDomainObject);
|
var innerVerb = isActive ? "does" : "doesn't";
|
||||||
|
|
||||||
expect(mockPersistence.persist).toHaveBeenCalled();
|
beforeEach(function () {
|
||||||
});
|
mockTransactionService.isActive.and.returnValue(isActive);
|
||||||
|
});
|
||||||
|
|
||||||
it("does not call persist if the model has not changed", function () {
|
describe("and mutation occurs", function () {
|
||||||
mockModel.persisted = Date.now();
|
beforeEach(function () {
|
||||||
|
mockMutationTopic.listen.calls.mostRecent()
|
||||||
|
.args[0](mockDomainObject);
|
||||||
|
});
|
||||||
|
|
||||||
mockModel.modified = mockModel.persisted;
|
|
||||||
|
|
||||||
mockMutationTopic.listen.calls.mostRecent()
|
it(innerVerb + " start a new transaction", function () {
|
||||||
.args[0](mockDomainObject);
|
onlyWhenInactive(
|
||||||
|
expect(mockTransactionService.startTransaction)
|
||||||
|
).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
expect(mockPersistence.persist).not.toHaveBeenCalled();
|
it("adds to the active transaction", function () {
|
||||||
|
expect(mockTransactionService.addToTransaction)
|
||||||
|
.toHaveBeenCalledWith(
|
||||||
|
jasmine.any(Function),
|
||||||
|
jasmine.any(Function)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(innerVerb + " immediately commit", function () {
|
||||||
|
onlyWhenInactive(
|
||||||
|
expect(mockTransactionService.commit)
|
||||||
|
).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ define([
|
|||||||
"./src/actions/MoveAction",
|
"./src/actions/MoveAction",
|
||||||
"./src/actions/CopyAction",
|
"./src/actions/CopyAction",
|
||||||
"./src/actions/LinkAction",
|
"./src/actions/LinkAction",
|
||||||
|
"./src/actions/GoToOriginalAction",
|
||||||
"./src/actions/SetPrimaryLocationAction",
|
"./src/actions/SetPrimaryLocationAction",
|
||||||
"./src/services/LocatingCreationDecorator",
|
"./src/services/LocatingCreationDecorator",
|
||||||
"./src/services/LocatingObjectDecorator",
|
"./src/services/LocatingObjectDecorator",
|
||||||
@@ -40,6 +41,7 @@ define([
|
|||||||
MoveAction,
|
MoveAction,
|
||||||
CopyAction,
|
CopyAction,
|
||||||
LinkAction,
|
LinkAction,
|
||||||
|
GoToOriginalAction,
|
||||||
SetPrimaryLocationAction,
|
SetPrimaryLocationAction,
|
||||||
LocatingCreationDecorator,
|
LocatingCreationDecorator,
|
||||||
LocatingObjectDecorator,
|
LocatingObjectDecorator,
|
||||||
@@ -102,6 +104,14 @@ define([
|
|||||||
"linkService"
|
"linkService"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"key": "follow",
|
||||||
|
"name": "Go To Original",
|
||||||
|
"description": "Go to the original, un-linked instance of this object.",
|
||||||
|
"cssClass": "",
|
||||||
|
"category": "contextual",
|
||||||
|
"implementation": GoToOriginalAction
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"key": "locate",
|
"key": "locate",
|
||||||
"name": "Set Primary Location",
|
"name": "Set Primary Location",
|
||||||
|
|||||||
60
platform/entanglement/src/actions/GoToOriginalAction.js
Normal file
60
platform/entanglement/src/actions/GoToOriginalAction.js
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* 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 () {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements the "Go To Original" action, which follows a link back
|
||||||
|
* to an original instance of an object.
|
||||||
|
*
|
||||||
|
* @implements {Action}
|
||||||
|
* @constructor
|
||||||
|
* @private
|
||||||
|
* @memberof platform/entanglement
|
||||||
|
* @param {ActionContext} context the context in which the action
|
||||||
|
* will be performed
|
||||||
|
*/
|
||||||
|
function GoToOriginalAction(context) {
|
||||||
|
this.domainObject = context.domainObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
GoToOriginalAction.prototype.perform = function () {
|
||||||
|
return this.domainObject.getCapability("location").getOriginal()
|
||||||
|
.then(function (originalObject) {
|
||||||
|
var actionCapability =
|
||||||
|
originalObject.getCapability("action");
|
||||||
|
return actionCapability &&
|
||||||
|
actionCapability.perform("navigate");
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
GoToOriginalAction.appliesTo = function (context) {
|
||||||
|
var domainObject = context.domainObject;
|
||||||
|
return domainObject && domainObject.hasCapability("location") &&
|
||||||
|
domainObject.getCapability("location").isLink();
|
||||||
|
};
|
||||||
|
|
||||||
|
return GoToOriginalAction;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
93
platform/entanglement/test/actions/GoToOriginalActionSpec.js
Normal file
93
platform/entanglement/test/actions/GoToOriginalActionSpec.js
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* 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/actions/GoToOriginalAction',
|
||||||
|
'../DomainObjectFactory',
|
||||||
|
'../ControlledPromise'
|
||||||
|
],
|
||||||
|
function (GoToOriginalAction, domainObjectFactory, ControlledPromise) {
|
||||||
|
|
||||||
|
describe("The 'go to original' action", function () {
|
||||||
|
var testContext,
|
||||||
|
originalDomainObject,
|
||||||
|
mockLocationCapability,
|
||||||
|
mockOriginalActionCapability,
|
||||||
|
originalPromise,
|
||||||
|
action;
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
mockLocationCapability = jasmine.createSpyObj(
|
||||||
|
'location',
|
||||||
|
['isLink', 'isOriginal', 'getOriginal']
|
||||||
|
);
|
||||||
|
mockOriginalActionCapability = jasmine.createSpyObj(
|
||||||
|
'action',
|
||||||
|
['perform', 'getActions']
|
||||||
|
);
|
||||||
|
originalPromise = new ControlledPromise();
|
||||||
|
mockLocationCapability.getOriginal.and.returnValue(originalPromise);
|
||||||
|
mockLocationCapability.isLink.and.returnValue(true);
|
||||||
|
mockLocationCapability.isOriginal.and.callFake(function () {
|
||||||
|
return !mockLocationCapability.isLink();
|
||||||
|
});
|
||||||
|
testContext = {
|
||||||
|
domainObject: domainObjectFactory({
|
||||||
|
capabilities: {
|
||||||
|
location: mockLocationCapability
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
|
originalDomainObject = domainObjectFactory({
|
||||||
|
capabilities: {
|
||||||
|
action: mockOriginalActionCapability
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
action = new GoToOriginalAction(testContext);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("is applicable to links", function () {
|
||||||
|
expect(GoToOriginalAction.appliesTo(testContext))
|
||||||
|
.toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("is not applicable to originals", function () {
|
||||||
|
mockLocationCapability.isLink.and.returnValue(false);
|
||||||
|
expect(GoToOriginalAction.appliesTo(testContext))
|
||||||
|
.toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("navigates to original objects when performed", function () {
|
||||||
|
expect(mockOriginalActionCapability.perform)
|
||||||
|
.not.toHaveBeenCalled();
|
||||||
|
action.perform();
|
||||||
|
originalPromise.resolve(originalDomainObject);
|
||||||
|
expect(mockOriginalActionCapability.perform)
|
||||||
|
.toHaveBeenCalledWith('navigate');
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
@@ -24,10 +24,10 @@
|
|||||||
<button ng-click="timer.clickStopButton()"
|
<button ng-click="timer.clickStopButton()"
|
||||||
ng-hide="timer.timerState == 'stopped'"
|
ng-hide="timer.timerState == 'stopped'"
|
||||||
title="Reset"
|
title="Reset"
|
||||||
class="c-timer__ctrl-reset c-icon-button c-icon-button--major icon-reset"></button>
|
class="c-timer__ctrl-reset c-click-icon c-click-icon--major icon-reset"></button>
|
||||||
<button ng-click="timer.clickButton()"
|
<button ng-click="timer.clickButton()"
|
||||||
title="{{timer.buttonText()}}"
|
title="{{timer.buttonText()}}"
|
||||||
class="c-timer__ctrl-pause-play c-icon-button c-icon-button--major {{timer.buttonCssClass()}}"></button>
|
class="c-timer__ctrl-pause-play c-click-icon c-click-icon--major {{timer.buttonCssClass()}}"></button>
|
||||||
</div>
|
</div>
|
||||||
<div class="c-timer__direction {{timer.signClass()}}"
|
<div class="c-timer__direction {{timer.signClass()}}"
|
||||||
ng-hide="!timer.signClass()"></div>
|
ng-hide="!timer.signClass()"></div>
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ define(
|
|||||||
};
|
};
|
||||||
|
|
||||||
ClockIndicator.prototype.getCssClass = function () {
|
ClockIndicator.prototype.getCssClass = function () {
|
||||||
return "t-indicator-clock icon-clock no-minify c-indicator--not-clickable";
|
return "t-indicator-clock icon-clock no-collapse float-right";
|
||||||
};
|
};
|
||||||
|
|
||||||
ClockIndicator.prototype.getText = function () {
|
ClockIndicator.prototype.getText = function () {
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ define([
|
|||||||
"key": "url",
|
"key": "url",
|
||||||
"name": "URL",
|
"name": "URL",
|
||||||
"control": "textfield",
|
"control": "textfield",
|
||||||
|
"pattern": "^(ftp|https?)\\:\\/\\/",
|
||||||
"required": true,
|
"required": true,
|
||||||
"cssClass": "l-input-lg"
|
"cssClass": "l-input-lg"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,18 +1,22 @@
|
|||||||
<div class="t-imagery c-imagery" ng-controller="ImageryController as imagery">
|
<div class="t-imagery" ng-controller="ImageryController as imagery">
|
||||||
<mct-split-pane class='abs' anchor="bottom" alias="imagery">
|
<mct-split-pane class='abs' anchor="bottom" alias="imagery">
|
||||||
<div class="split-pane-component has-local-controls l-image-main-wrapper l-flex-col">
|
<div class="split-pane-component has-local-controls l-image-main-wrapper l-flex-col"
|
||||||
<div class="h-local-controls h-local-controls--overlay-content c-local-controls--show-on-hover l-flex-row c-imagery__lc">
|
ng-mouseenter="showLocalControls = true;"
|
||||||
<span class="holder flex-elem grows c-imagery__lc__sliders">
|
ng-mouseleave="showLocalControls = false;">
|
||||||
|
<div class="h-local-controls h-local-controls-overlay-content h-local-controls-trans s-local-controls local-controls-hidden l-flex-row">
|
||||||
|
<span class="holder flex-elem grows">
|
||||||
<input class="icon-brightness" type="range"
|
<input class="icon-brightness" type="range"
|
||||||
min="0"
|
min="0"
|
||||||
max="500"
|
max="500"
|
||||||
ng-model="filters.brightness" />
|
ng-model="filters.brightness">
|
||||||
|
</input>
|
||||||
<input class="icon-contrast" type="range"
|
<input class="icon-contrast" type="range"
|
||||||
min="0"
|
min="0"
|
||||||
max="500"
|
max="500"
|
||||||
ng-model="filters.contrast" />
|
ng-model="filters.contrast">
|
||||||
|
</input>
|
||||||
</span>
|
</span>
|
||||||
<span class="holder flex-elem t-reset-btn-holder c-imagery__lc__reset-btn">
|
<span class="holder flex-elem t-reset-btn-holder">
|
||||||
<a class="s-icon-button icon-reset t-btn-reset"
|
<a class="s-icon-button icon-reset t-btn-reset"
|
||||||
ng-click="filters = { brightness: 100, contrast: 100 }"></a>
|
ng-click="filters = { brightness: 100, contrast: 100 }"></a>
|
||||||
</span>
|
</span>
|
||||||
@@ -29,14 +33,14 @@
|
|||||||
|
|
||||||
<div class="l-image-main-controlbar flex-elem l-flex-row">
|
<div class="l-image-main-controlbar flex-elem l-flex-row">
|
||||||
<div class="l-datetime-w flex-elem grows">
|
<div class="l-datetime-w flex-elem grows">
|
||||||
<a class="c-button show-thumbs sm hidden icon-thumbs-strip"
|
<a class="s-button show-thumbs sm hidden icon-thumbs-strip"
|
||||||
ng-click="showThumbsBubble = (showThumbsBubble) ? false:true"></a>
|
ng-click="showThumbsBubble = (showThumbsBubble) ? false:true"></a>
|
||||||
<span class="l-time">{{imagery.getTime()}}</span>
|
<span class="l-time">{{imagery.getTime()}}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="h-local-controls flex-elem">
|
<div class="h-local-controls flex-elem">
|
||||||
<a class="c-button icon-pause pause-play"
|
<a class="s-button pause-play"
|
||||||
ng-click="imagery.paused(!imagery.paused())"
|
ng-click="imagery.paused(!imagery.paused())"
|
||||||
ng-class="{ 'is-paused': imagery.paused() }"></a>
|
ng-class="{ paused: imagery.paused() }"></a>
|
||||||
<a href=""
|
<a href=""
|
||||||
class="s-button l-mag s-mag vsm icon-reset"
|
class="s-button l-mag s-mag vsm icon-reset"
|
||||||
ng-click="clipped = false"
|
ng-click="clipped = false"
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ define([
|
|||||||
"key": "url",
|
"key": "url",
|
||||||
"name": "URL",
|
"name": "URL",
|
||||||
"control": "textfield",
|
"control": "textfield",
|
||||||
|
"pattern": "^(ftp|https?)\\:\\/\\/",
|
||||||
"required": true,
|
"required": true,
|
||||||
"cssClass": "l-input-lg"
|
"cssClass": "l-input-lg"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,13 +19,13 @@
|
|||||||
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.
|
||||||
-->
|
-->
|
||||||
<form name="mctForm" novalidate class="form c-form" autocomplete="off">
|
<form name="mctForm" novalidate class="form l-flex-col">
|
||||||
<span ng-repeat="section in structure.sections"
|
<span ng-repeat="section in structure.sections"
|
||||||
class="l-form-section c-form__section {{ section.cssClass }}">
|
class="l-form-section l-flex-col flex-elem {{ section.cssClass }}">
|
||||||
<h2 class="c-form__header" ng-if="section.name">
|
<h2 class="section-header flex-elem" ng-if="section.name">
|
||||||
{{section.name}}
|
{{section.name}}
|
||||||
</h2>
|
</h2>
|
||||||
<ng-form class="form-row c-form__row validates {{ section.cssClass }}"
|
<ng-form class="form-row validates l-flex-row flex-elem {{ section.cssClass }}"
|
||||||
ng-class="{
|
ng-class="{
|
||||||
first:$index < 1,
|
first:$index < 1,
|
||||||
req: row.required,
|
req: row.required,
|
||||||
@@ -37,11 +37,11 @@
|
|||||||
}"
|
}"
|
||||||
name="mctFormInner"
|
name="mctFormInner"
|
||||||
ng-repeat="row in section.rows">
|
ng-repeat="row in section.rows">
|
||||||
<div class='c-form__row__label label flex-elem' title="{{row.description}}">
|
<div class='label flex-elem' title="{{row.description}}">
|
||||||
{{row.name}}
|
{{row.name}}
|
||||||
</div>
|
</div>
|
||||||
<div class='c-form__row__controls controls flex-elem'>
|
<div class='controls flex-elem'>
|
||||||
<div class="c-form__controls-wrapper wrapper" ng-if="row.control">
|
<div class="wrapper" ng-if="row.control">
|
||||||
<mct-control key="row.control"
|
<mct-control key="row.control"
|
||||||
ng-model="ngModel"
|
ng-model="ngModel"
|
||||||
ng-required="row.required"
|
ng-required="row.required"
|
||||||
|
|||||||
@@ -29,13 +29,12 @@ define(
|
|||||||
function SnapshotPreviewController($scope, openmct) {
|
function SnapshotPreviewController($scope, openmct) {
|
||||||
|
|
||||||
$scope.previewImage = function (imageUrl) {
|
$scope.previewImage = function (imageUrl) {
|
||||||
let imageDiv = document.createElement('div');
|
let image = document.createElement('img');
|
||||||
imageDiv.classList = 'image-main s-image-main';
|
image.src = imageUrl;
|
||||||
imageDiv.style.backgroundImage = `url(${imageUrl})`;
|
|
||||||
|
|
||||||
let previewImageOverlay = openmct.overlays.overlay(
|
let previewImageOverlay = openmct.overlays.overlay(
|
||||||
{
|
{
|
||||||
element: imageDiv,
|
element: image,
|
||||||
size: 'large',
|
size: 'large',
|
||||||
buttons: [
|
buttons: [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -64,30 +64,12 @@ define(['zepto'], function ($) {
|
|||||||
var tree = this.generateNewIdentifiers(objTree);
|
var tree = this.generateNewIdentifiers(objTree);
|
||||||
var rootId = tree.rootId;
|
var rootId = tree.rootId;
|
||||||
var rootObj = this.instantiate(tree.openmct[rootId], rootId);
|
var rootObj = this.instantiate(tree.openmct[rootId], rootId);
|
||||||
var newStyleParent = parent.useCapability('adapter');
|
|
||||||
var newStyleRootObj = rootObj.useCapability('adapter');
|
|
||||||
|
|
||||||
if (this.openmct.composition.checkPolicy(newStyleParent, newStyleRootObj)) {
|
// Instantiate all objects in tree with their newly genereated ids,
|
||||||
// Instantiate all objects in tree with their newly generated ids,
|
// adding each to its rightful parent's composition
|
||||||
// adding each to its rightful parent's composition
|
rootObj.getCapability("location").setPrimaryLocation(parent.getId());
|
||||||
rootObj.getCapability("location").setPrimaryLocation(parent.getId());
|
this.deepInstantiate(rootObj, tree.openmct, []);
|
||||||
this.deepInstantiate(rootObj, tree.openmct, []);
|
parent.getCapability("composition").add(rootObj);
|
||||||
parent.getCapability("composition").add(rootObj);
|
|
||||||
} else {
|
|
||||||
var dialog = this.openmct.overlays.dialog({
|
|
||||||
iconClass: 'alert',
|
|
||||||
message: "We're sorry, but you cannot import that object type into this object.",
|
|
||||||
buttons: [
|
|
||||||
{
|
|
||||||
label: "Ok",
|
|
||||||
emphasis: true,
|
|
||||||
callback: function () {
|
|
||||||
dialog.dismiss();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
ImportAsJSONAction.prototype.deepInstantiate = function (parent, tree, seen) {
|
ImportAsJSONAction.prototype.deepInstantiate = function (parent, tree, seen) {
|
||||||
@@ -98,17 +80,15 @@ define(['zepto'], function ($) {
|
|||||||
var newObj;
|
var newObj;
|
||||||
|
|
||||||
seen.push(parent.getId());
|
seen.push(parent.getId());
|
||||||
|
parentModel.composition.forEach(function (childId, index) {
|
||||||
parentModel.composition.forEach(function (childId) {
|
if (!tree[childId] || seen.includes(childId)) {
|
||||||
let keystring = this.openmct.objects.makeKeyString(childId);
|
|
||||||
|
|
||||||
if (!tree[keystring] || seen.includes(keystring)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
newObj = this.instantiate(tree[keystring], keystring);
|
newObj = this.instantiate(tree[childId], childId);
|
||||||
|
parent.getCapability("composition").add(newObj);
|
||||||
newObj.getCapability("location")
|
newObj.getCapability("location")
|
||||||
.setPrimaryLocation(tree[keystring].location);
|
.setPrimaryLocation(tree[childId].location);
|
||||||
this.deepInstantiate(newObj, tree, seen);
|
this.deepInstantiate(newObj, tree, seen);
|
||||||
}, this);
|
}, this);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ define(
|
|||||||
}
|
}
|
||||||
|
|
||||||
CouchIndicator.prototype.getCssClass = function () {
|
CouchIndicator.prototype.getCssClass = function () {
|
||||||
return "c-indicator--clickable icon-database " + this.state.statusClass;
|
return "icon-database " + this.state.statusClass;
|
||||||
};
|
};
|
||||||
|
|
||||||
CouchIndicator.prototype.getGlyphClass = function () {
|
CouchIndicator.prototype.getGlyphClass = function () {
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ define(
|
|||||||
}
|
}
|
||||||
|
|
||||||
ElasticIndicator.prototype.getCssClass = function () {
|
ElasticIndicator.prototype.getCssClass = function () {
|
||||||
return "c-indicator--clickable icon-database";
|
return "icon-database";
|
||||||
};
|
};
|
||||||
ElasticIndicator.prototype.getGlyphClass = function () {
|
ElasticIndicator.prototype.getGlyphClass = function () {
|
||||||
return this.state.glyphClass;
|
return this.state.glyphClass;
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ define(
|
|||||||
}
|
}
|
||||||
|
|
||||||
LocalStorageIndicator.prototype.getCssClass = function () {
|
LocalStorageIndicator.prototype.getCssClass = function () {
|
||||||
return "c-indicator--clickable icon-database s-status-caution";
|
return "icon-database s-status-caution";
|
||||||
};
|
};
|
||||||
LocalStorageIndicator.prototype.getGlyphClass = function () {
|
LocalStorageIndicator.prototype.getGlyphClass = function () {
|
||||||
return 'caution';
|
return 'caution';
|
||||||
|
|||||||
@@ -37,17 +37,75 @@ define(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Discard failures
|
* Handle persistence failures by providing the user with a
|
||||||
|
* dialog summarizing these failures, and giving the option
|
||||||
|
* to overwrite/cancel as appropriate.
|
||||||
* @param {Array} failures persistence failures, as prepared
|
* @param {Array} failures persistence failures, as prepared
|
||||||
* by PersistenceQueueHandler
|
* by PersistenceQueueHandler
|
||||||
* @memberof platform/persistence/queue.PersistenceFailureHandler#
|
* @memberof platform/persistence/queue.PersistenceFailureHandler#
|
||||||
*/
|
*/
|
||||||
PersistenceFailureHandler.prototype.handle = function handleFailures(failures) {
|
PersistenceFailureHandler.prototype.handle = function handleFailures(failures) {
|
||||||
|
// Prepare dialog for display
|
||||||
var dialogModel = new PersistenceFailureDialog(failures),
|
var dialogModel = new PersistenceFailureDialog(failures),
|
||||||
revisionErrors = dialogModel.model.revised,
|
revisionErrors = dialogModel.model.revised,
|
||||||
$q = this.$q;
|
$q = this.$q;
|
||||||
|
|
||||||
|
// Refresh revision information for the domain object associated
|
||||||
|
// with this persistence failure
|
||||||
|
function refresh(failure) {
|
||||||
|
// Refresh the domain object to the latest from persistence
|
||||||
|
return failure.persistence.refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Issue a new persist call for the domain object associated with
|
||||||
|
// this failure.
|
||||||
|
function persist(failure) {
|
||||||
|
// Note that we reissue the persist request here, but don't
|
||||||
|
// return it, to avoid a circular wait. We trust that the
|
||||||
|
// PersistenceQueue will behave correctly on the next round
|
||||||
|
// of flushing.
|
||||||
|
failure.requeue();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retry persistence (overwrite) for this set of failed attempts
|
||||||
|
function retry(failuresToRetry) {
|
||||||
|
var models = {};
|
||||||
|
|
||||||
|
// Cache a copy of the model
|
||||||
|
function cacheModel(failure) {
|
||||||
|
// Clone...
|
||||||
|
models[failure.id] = JSON.parse(JSON.stringify(
|
||||||
|
failure.domainObject.getModel()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mutate a domain object to restore its model
|
||||||
|
function remutate(failure) {
|
||||||
|
var model = models[failure.id];
|
||||||
|
return failure.domainObject.useCapability(
|
||||||
|
"mutation",
|
||||||
|
function () {
|
||||||
|
return model;
|
||||||
|
},
|
||||||
|
model.modified
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cache the object models we might want to save
|
||||||
|
failuresToRetry.forEach(cacheModel);
|
||||||
|
|
||||||
|
// Strategy here:
|
||||||
|
// * Cache all of the models we might want to save (above)
|
||||||
|
// * Refresh all domain objects (so they are latest versions)
|
||||||
|
// * Re-insert the cached domain object models
|
||||||
|
// * Invoke persistence again
|
||||||
|
return $q.all(failuresToRetry.map(refresh)).then(function () {
|
||||||
|
return $q.all(failuresToRetry.map(remutate));
|
||||||
|
}).then(function () {
|
||||||
|
return $q.all(failuresToRetry.map(persist));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Discard changes for a failed refresh
|
// Discard changes for a failed refresh
|
||||||
function discard(failure) {
|
function discard(failure) {
|
||||||
var persistence =
|
var persistence =
|
||||||
@@ -60,7 +118,19 @@ define(
|
|||||||
return $q.all(failuresToDiscard.map(discard));
|
return $q.all(failuresToDiscard.map(discard));
|
||||||
}
|
}
|
||||||
|
|
||||||
return discardAll(revisionErrors);
|
// Handle user input (did they choose to overwrite?)
|
||||||
|
function handleChoice(key) {
|
||||||
|
// If so, try again
|
||||||
|
if (key === PersistenceFailureConstants.OVERWRITE_KEY) {
|
||||||
|
return retry(revisionErrors);
|
||||||
|
} else {
|
||||||
|
return discardAll(revisionErrors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prompt for user input, the overwrite if they said so.
|
||||||
|
return this.dialogService.getUserChoice(dialogModel)
|
||||||
|
.then(handleChoice, handleChoice);
|
||||||
};
|
};
|
||||||
|
|
||||||
return PersistenceFailureHandler;
|
return PersistenceFailureHandler;
|
||||||
|
|||||||
@@ -74,14 +74,43 @@ define(
|
|||||||
handler = new PersistenceFailureHandler(mockQ, mockDialogService);
|
handler = new PersistenceFailureHandler(mockQ, mockDialogService);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("discards on handle", function () {
|
it("shows a dialog to handle failures", function () {
|
||||||
handler.handle(mockFailures);
|
handler.handle(mockFailures);
|
||||||
|
expect(mockDialogService.getUserChoice).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("overwrites on request", function () {
|
||||||
|
mockQ.all.and.returnValue(asPromise([]));
|
||||||
|
handler.handle(mockFailures);
|
||||||
|
// User chooses overwrite
|
||||||
|
mockPromise.then.calls.mostRecent().args[0](Constants.OVERWRITE_KEY);
|
||||||
|
// Should refresh, remutate, and requeue all objects
|
||||||
|
mockFailures.forEach(function (mockFailure, i) {
|
||||||
|
expect(mockFailure.persistence.refresh).toHaveBeenCalled();
|
||||||
|
expect(mockFailure.requeue).toHaveBeenCalled();
|
||||||
|
expect(mockFailure.domainObject.useCapability).toHaveBeenCalledWith(
|
||||||
|
'mutation',
|
||||||
|
jasmine.any(Function),
|
||||||
|
i // timestamp
|
||||||
|
);
|
||||||
|
expect(mockFailure.domainObject.useCapability.calls.mostRecent().args[1]())
|
||||||
|
.toEqual({ id: mockFailure.id, modified: i });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("discards on request", function () {
|
||||||
|
mockQ.all.and.returnValue(asPromise([]));
|
||||||
|
handler.handle(mockFailures);
|
||||||
|
// User chooses overwrite
|
||||||
|
mockPromise.then.calls.mostRecent().args[0](false);
|
||||||
|
// Should refresh, but not remutate, and requeue all objects
|
||||||
mockFailures.forEach(function (mockFailure) {
|
mockFailures.forEach(function (mockFailure) {
|
||||||
expect(mockFailure.persistence.refresh).toHaveBeenCalled();
|
expect(mockFailure.persistence.refresh).toHaveBeenCalled();
|
||||||
expect(mockFailure.requeue).not.toHaveBeenCalled();
|
expect(mockFailure.requeue).not.toHaveBeenCalled();
|
||||||
expect(mockFailure.domainObject.useCapability).not.toHaveBeenCalled();
|
expect(mockFailure.domainObject.useCapability).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -45,7 +45,7 @@
|
|||||||
</mct-include>
|
</mct-include>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<a class="c-button c-search__btn-cancel"
|
<a class="s-button c-search__btn-cancel"
|
||||||
ng-show="!(ngModel.input === '' || ngModel.input === undefined)"
|
ng-show="!(ngModel.input === '' || ngModel.input === undefined)"
|
||||||
ng-click="ngModel.input = ''; ngModel.checkAll = true; menuController.checkAll(); controller.search()">
|
ng-click="ngModel.input = ''; ngModel.checkAll = true; menuController.checkAll(); controller.search()">
|
||||||
Cancel</a>
|
Cancel</a>
|
||||||
|
|||||||
43
src/MCT.js
43
src/MCT.js
@@ -44,9 +44,6 @@ define([
|
|||||||
'../platform/core/src/objects/DomainObjectImpl',
|
'../platform/core/src/objects/DomainObjectImpl',
|
||||||
'../platform/core/src/capabilities/ContextualDomainObject',
|
'../platform/core/src/capabilities/ContextualDomainObject',
|
||||||
'./ui/preview/plugin',
|
'./ui/preview/plugin',
|
||||||
'./api/Branding',
|
|
||||||
'./plugins/licenses/plugin',
|
|
||||||
'./plugins/remove/plugin',
|
|
||||||
'vue'
|
'vue'
|
||||||
], function (
|
], function (
|
||||||
EventEmitter,
|
EventEmitter,
|
||||||
@@ -72,9 +69,6 @@ define([
|
|||||||
DomainObjectImpl,
|
DomainObjectImpl,
|
||||||
ContextualDomainObject,
|
ContextualDomainObject,
|
||||||
PreviewPlugin,
|
PreviewPlugin,
|
||||||
BrandingAPI,
|
|
||||||
LicensesPlugin,
|
|
||||||
RemoveActionPlugin,
|
|
||||||
Vue
|
Vue
|
||||||
) {
|
) {
|
||||||
/**
|
/**
|
||||||
@@ -95,13 +89,6 @@ define([
|
|||||||
*/
|
*/
|
||||||
function MCT() {
|
function MCT() {
|
||||||
EventEmitter.call(this);
|
EventEmitter.call(this);
|
||||||
this.buildInfo = {
|
|
||||||
version: __OPENMCT_VERSION__,
|
|
||||||
buildDate: __OPENMCT_BUILD_DATE__,
|
|
||||||
revision: __OPENMCT_REVISION__,
|
|
||||||
branch: __OPENMCT_BUILD_BRANCH__
|
|
||||||
};
|
|
||||||
|
|
||||||
this.legacyBundle = { extensions: {
|
this.legacyBundle = { extensions: {
|
||||||
services: [
|
services: [
|
||||||
{
|
{
|
||||||
@@ -241,30 +228,16 @@ define([
|
|||||||
|
|
||||||
this.contextMenu = new api.ContextMenuRegistry();
|
this.contextMenu = new api.ContextMenuRegistry();
|
||||||
|
|
||||||
this.router = new ApplicationRouter();
|
|
||||||
|
|
||||||
this.branding = BrandingAPI.default;
|
|
||||||
|
|
||||||
this.legacyRegistry = defaultRegistry;
|
this.legacyRegistry = defaultRegistry;
|
||||||
|
|
||||||
// Plugin's that are installed by default
|
|
||||||
|
|
||||||
this.install(this.plugins.Plot());
|
this.install(this.plugins.Plot());
|
||||||
this.install(this.plugins.TelemetryTable());
|
this.install(this.plugins.TelemetryTable());
|
||||||
|
this.install(this.plugins.DisplayLayout());
|
||||||
this.install(PreviewPlugin.default());
|
this.install(PreviewPlugin.default());
|
||||||
this.install(LegacyIndicatorsPlugin());
|
|
||||||
this.install(LicensesPlugin.default());
|
|
||||||
this.install(RemoveActionPlugin.default());
|
|
||||||
this.install(this.plugins.ImportExport());
|
|
||||||
this.install(this.plugins.FolderView());
|
|
||||||
this.install(this.plugins.Tabs());
|
|
||||||
this.install(this.plugins.FlexibleLayout());
|
|
||||||
this.install(this.plugins.LADTable());
|
|
||||||
this.install(this.plugins.GoToOriginalAction());
|
|
||||||
|
|
||||||
if (typeof BUILD_CONSTANTS !== 'undefined') {
|
if (typeof BUILD_CONSTANTS !== 'undefined') {
|
||||||
this.install(buildInfoPlugin(BUILD_CONSTANTS));
|
this.install(buildInfoPlugin(BUILD_CONSTANTS));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MCT.prototype = Object.create(EventEmitter.prototype);
|
MCT.prototype = Object.create(EventEmitter.prototype);
|
||||||
@@ -335,12 +308,6 @@ define([
|
|||||||
* MCT; if undefined, MCT will be run in the body of the document
|
* MCT; if undefined, MCT will be run in the body of the document
|
||||||
*/
|
*/
|
||||||
MCT.prototype.start = function (domElement) {
|
MCT.prototype.start = function (domElement) {
|
||||||
if (!this.plugins.DisplayLayout._installed) {
|
|
||||||
this.install(this.plugins.DisplayLayout({
|
|
||||||
showAsView: ['summary-widget']
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!domElement) {
|
if (!domElement) {
|
||||||
domElement = document.body;
|
domElement = document.body;
|
||||||
}
|
}
|
||||||
@@ -364,8 +331,12 @@ define([
|
|||||||
legacyRegistry.register('adapter', this.legacyBundle);
|
legacyRegistry.register('adapter', this.legacyBundle);
|
||||||
legacyRegistry.enable('adapter');
|
legacyRegistry.enable('adapter');
|
||||||
|
|
||||||
|
this.install(LegacyIndicatorsPlugin());
|
||||||
|
|
||||||
|
this.router = new ApplicationRouter();
|
||||||
|
|
||||||
this.router.route(/^\/$/, () => {
|
this.router.route(/^\/$/, () => {
|
||||||
this.router.setPath('/browse/');
|
this.router.setPath('/browse/mine');
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -33,25 +33,20 @@ export default class LegacyContextMenuAction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
invoke(objectPath) {
|
invoke(objectPath) {
|
||||||
this.openmct.objects.getRoot().then((root) => {
|
let context = {
|
||||||
let pathWithRoot = objectPath.slice();
|
category: 'contextual',
|
||||||
pathWithRoot.push(root);
|
domainObject: this.openmct.legacyObject(objectPath)
|
||||||
|
}
|
||||||
|
let legacyAction = new this.LegacyAction(context);
|
||||||
|
|
||||||
let context = {
|
if (!legacyAction.getMetadata) {
|
||||||
category: 'contextual',
|
let metadata = Object.create(this.LegacyAction.definition);
|
||||||
domainObject: this.openmct.legacyObject(pathWithRoot)
|
metadata.context = context;
|
||||||
}
|
legacyAction.getMetadata = function () {
|
||||||
let legacyAction = new this.LegacyAction(context);
|
return metadata;
|
||||||
|
}.bind(legacyAction);
|
||||||
if (!legacyAction.getMetadata) {
|
}
|
||||||
let metadata = Object.create(this.LegacyAction.definition);
|
legacyAction.perform();
|
||||||
metadata.context = context;
|
|
||||||
legacyAction.getMetadata = function () {
|
|
||||||
return metadata;
|
|
||||||
}.bind(legacyAction);
|
|
||||||
}
|
|
||||||
legacyAction.perform();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
appliesTo(objectPath) {
|
appliesTo(objectPath) {
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ define([
|
|||||||
'./runs/RegisterLegacyTypes',
|
'./runs/RegisterLegacyTypes',
|
||||||
'./services/LegacyObjectAPIInterceptor',
|
'./services/LegacyObjectAPIInterceptor',
|
||||||
'./views/installLegacyViews',
|
'./views/installLegacyViews',
|
||||||
'./policies/LegacyCompositionPolicyAdapter',
|
'./policies/legacyCompositionPolicyAdapter',
|
||||||
'./actions/LegacyActionAdapter'
|
'./actions/LegacyActionAdapter'
|
||||||
], function (
|
], function (
|
||||||
legacyRegistry,
|
legacyRegistry,
|
||||||
|
|||||||
@@ -137,7 +137,8 @@ define([
|
|||||||
function callbackWrapper(series) {
|
function callbackWrapper(series) {
|
||||||
callback(createDatum(domainObject, metadata, series, series.getPointCount() - 1));
|
callback(createDatum(domainObject, metadata, series, series.getPointCount() - 1));
|
||||||
}
|
}
|
||||||
return capability.subscribe(callbackWrapper, request) || function () {};
|
|
||||||
|
return capability.subscribe(callbackWrapper, request);
|
||||||
};
|
};
|
||||||
|
|
||||||
LegacyTelemetryProvider.prototype.supportsLimits = function (domainObject) {
|
LegacyTelemetryProvider.prototype.supportsLimits = function (domainObject) {
|
||||||
@@ -157,7 +158,7 @@ define([
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
evaluate: function (datum, property) {
|
evaluate: function (datum, property) {
|
||||||
return limitEvaluator.evaluate(datum, property && property.key);
|
return limitEvaluator.evaluate(datum, property.key);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -57,10 +57,8 @@ define([
|
|||||||
}.bind(this);
|
}.bind(this);
|
||||||
|
|
||||||
handleLegacyMutation = function (legacyObject) {
|
handleLegacyMutation = function (legacyObject) {
|
||||||
var newStyleObject = utils.toNewFormat(legacyObject.getModel(), legacyObject.getId()),
|
var newStyleObject = utils.toNewFormat(legacyObject.getModel(), legacyObject.getId());
|
||||||
keystring = utils.makeKeyString(newStyleObject.identifier);
|
this.eventEmitter.emit(newStyleObject.identifier.key + ":*", newStyleObject);
|
||||||
|
|
||||||
this.eventEmitter.emit(keystring + ":*", newStyleObject);
|
|
||||||
this.eventEmitter.emit('mutation', newStyleObject);
|
this.eventEmitter.emit('mutation', newStyleObject);
|
||||||
}.bind(this);
|
}.bind(this);
|
||||||
|
|
||||||
|
|||||||
@@ -45,30 +45,15 @@ define([
|
|||||||
view: function (domainObject) {
|
view: function (domainObject) {
|
||||||
let $rootScope = openmct.$injector.get('$rootScope');
|
let $rootScope = openmct.$injector.get('$rootScope');
|
||||||
let templateLinker = openmct.$injector.get('templateLinker');
|
let templateLinker = openmct.$injector.get('templateLinker');
|
||||||
let scope = $rootScope.$new(true);
|
let scope = $rootScope.$new();
|
||||||
let legacyObject = convertToLegacyObject(domainObject);
|
let legacyObject = convertToLegacyObject(domainObject);
|
||||||
let isDestroyed = false;
|
let isDestroyed = false;
|
||||||
let unlistenToStatus;
|
|
||||||
let element;
|
|
||||||
scope.domainObject = legacyObject;
|
scope.domainObject = legacyObject;
|
||||||
scope.model = legacyObject.getModel();
|
scope.model = legacyObject.getModel();
|
||||||
let child;
|
|
||||||
let parent;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
show: function (container) {
|
show: function (container) {
|
||||||
parent = container;
|
|
||||||
child = document.createElement('div');
|
|
||||||
parent.appendChild(child);
|
|
||||||
let statusCapability = legacyObject.getCapability('status');
|
|
||||||
unlistenToStatus = statusCapability.listen((newStatus) => {
|
|
||||||
child.classList.remove('s-status-timeconductor-unsynced');
|
|
||||||
|
|
||||||
if (newStatus.includes('timeconductor-unsynced')) {
|
|
||||||
child.classList.add('s-status-timeconductor-unsynced');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// TODO: implement "gestures" support ?
|
// TODO: implement "gestures" support ?
|
||||||
let uses = legacyView.uses || [];
|
let uses = legacyView.uses || [];
|
||||||
let promises = [];
|
let promises = [];
|
||||||
@@ -89,13 +74,12 @@ define([
|
|||||||
uses.forEach(function (key, i) {
|
uses.forEach(function (key, i) {
|
||||||
scope[key] = results[i];
|
scope[key] = results[i];
|
||||||
});
|
});
|
||||||
element = openmct.$angular.element(child);
|
|
||||||
templateLinker.link(
|
templateLinker.link(
|
||||||
scope,
|
scope,
|
||||||
element,
|
openmct.$angular.element(container),
|
||||||
legacyView
|
legacyView
|
||||||
);
|
);
|
||||||
child.classList.add('u-contents');
|
container.classList.add('u-contents');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (promises.length) {
|
if (promises.length) {
|
||||||
@@ -108,16 +92,8 @@ define([
|
|||||||
link();
|
link();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onClearData() {
|
|
||||||
scope.$broadcast('clearData');
|
|
||||||
},
|
|
||||||
destroy: function () {
|
destroy: function () {
|
||||||
element.off();
|
|
||||||
element.remove();
|
|
||||||
scope.$destroy();
|
scope.$destroy();
|
||||||
element = null;
|
|
||||||
scope = null;
|
|
||||||
unlistenToStatus();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -25,34 +25,25 @@ define([
|
|||||||
cssClass: representation.cssClass,
|
cssClass: representation.cssClass,
|
||||||
description: representation.description,
|
description: representation.description,
|
||||||
canView: function (selection) {
|
canView: function (selection) {
|
||||||
if (selection.length !== 1 || selection[0].length === 0) {
|
if (!selection[0] || !selection[0].context.item) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
let domainObject = selection[0].context.item;
|
||||||
let selectionContext = selection[0][0].context;
|
return domainObject.type === typeDefinition.key;
|
||||||
|
|
||||||
if (!selectionContext.item) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return selectionContext.item.type === typeDefinition.key;
|
|
||||||
},
|
},
|
||||||
view: function (selection) {
|
view: function (selection) {
|
||||||
let domainObject = selection[0][0].context.item;
|
let domainObject = selection[0].context.item;
|
||||||
let $rootScope = openmct.$injector.get('$rootScope');
|
let $rootScope = openmct.$injector.get('$rootScope');
|
||||||
let templateLinker = openmct.$injector.get('templateLinker');
|
let templateLinker = openmct.$injector.get('templateLinker');
|
||||||
let scope = $rootScope.$new(true);
|
let scope = $rootScope.$new();
|
||||||
let legacyObject = convertToLegacyObject(domainObject);
|
let legacyObject = convertToLegacyObject(domainObject);
|
||||||
let isDestroyed = false;
|
let isDestroyed = false;
|
||||||
let element;
|
|
||||||
scope.domainObject = legacyObject;
|
scope.domainObject = legacyObject;
|
||||||
scope.model = legacyObject.getModel();
|
scope.model = legacyObject.getModel();
|
||||||
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
show: function (container) {
|
show: function (container) {
|
||||||
let child = document.createElement('div');
|
|
||||||
container.appendChild(child);
|
|
||||||
// TODO: implement "gestures" support ?
|
// TODO: implement "gestures" support ?
|
||||||
let uses = representation.uses || [];
|
let uses = representation.uses || [];
|
||||||
let promises = [];
|
let promises = [];
|
||||||
@@ -73,10 +64,9 @@ define([
|
|||||||
uses.forEach(function (key, i) {
|
uses.forEach(function (key, i) {
|
||||||
scope[key] = results[i];
|
scope[key] = results[i];
|
||||||
});
|
});
|
||||||
element = openmct.$angular.element(child)
|
|
||||||
templateLinker.link(
|
templateLinker.link(
|
||||||
scope,
|
scope,
|
||||||
element,
|
openmct.$angular.element(container),
|
||||||
representation
|
representation
|
||||||
);
|
);
|
||||||
container.style.height = '100%';
|
container.style.height = '100%';
|
||||||
@@ -93,11 +83,7 @@ define([
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
destroy: function () {
|
destroy: function () {
|
||||||
element.off();
|
|
||||||
element.remove();
|
|
||||||
scope.$destroy();
|
scope.$destroy();
|
||||||
element = null;
|
|
||||||
scope = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,45 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2014-2019, 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.
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
let brandingOptions = {};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef {Object} BrandingOptions
|
|
||||||
* @memberOf openmct/branding
|
|
||||||
* @property {string} smallLogoImage URL to the image to use as the applications logo.
|
|
||||||
* This logo will appear on every screen and when clicked will launch the about dialog.
|
|
||||||
* @property {string} aboutHtml Custom content for the about screen. When defined the
|
|
||||||
* supplied content will be inserted at the start of the about dialog, and the default
|
|
||||||
* Open MCT splash logo will be suppressed.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set branding options for the application. These will override certain visual elements
|
|
||||||
* of the application and allow for customization of the application.
|
|
||||||
* @param {BrandingOptions} options
|
|
||||||
*/
|
|
||||||
export default function Branding(options) {
|
|
||||||
if (arguments.length === 1) {
|
|
||||||
brandingOptions = options;
|
|
||||||
}
|
|
||||||
return brandingOptions;
|
|
||||||
}
|
|
||||||
@@ -28,6 +28,11 @@ export default class Editor extends EventEmitter {
|
|||||||
super();
|
super();
|
||||||
this.editing = false;
|
this.editing = false;
|
||||||
this.openmct = openmct;
|
this.openmct = openmct;
|
||||||
|
document.addEventListener('drop', (event) => {
|
||||||
|
if (!this.isEditing()) {
|
||||||
|
this.edit();
|
||||||
|
}
|
||||||
|
}, {capture: true});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -74,11 +79,9 @@ export default class Editor extends EventEmitter {
|
|||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
cancel() {
|
cancel() {
|
||||||
let cancelPromise = this.getTransactionService().cancel();
|
this.getTransactionService().cancel();
|
||||||
this.editing = false;
|
this.editing = false;
|
||||||
this.emit('isEditing', false);
|
this.emit('isEditing', false);
|
||||||
|
|
||||||
return cancelPromise;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -21,23 +21,7 @@ define([
|
|||||||
topicService.and.returnValue(mutationTopic);
|
topicService.and.returnValue(mutationTopic);
|
||||||
publicAPI = {};
|
publicAPI = {};
|
||||||
publicAPI.objects = jasmine.createSpyObj('ObjectAPI', [
|
publicAPI.objects = jasmine.createSpyObj('ObjectAPI', [
|
||||||
'get',
|
'get'
|
||||||
'mutate',
|
|
||||||
'observe',
|
|
||||||
'areIdsEqual'
|
|
||||||
]);
|
|
||||||
|
|
||||||
publicAPI.objects.areIdsEqual.and.callFake(function (id1, id2) {
|
|
||||||
return id1.namespace === id2.namespace && id1.key === id2.key;
|
|
||||||
});
|
|
||||||
|
|
||||||
publicAPI.composition = jasmine.createSpyObj('CompositionAPI', [
|
|
||||||
'checkPolicy'
|
|
||||||
]);
|
|
||||||
publicAPI.composition.checkPolicy.and.returnValue(true);
|
|
||||||
|
|
||||||
publicAPI.objects.eventEmitter = jasmine.createSpyObj('eventemitter', [
|
|
||||||
'on'
|
|
||||||
]);
|
]);
|
||||||
publicAPI.objects.get.and.callFake(function (identifier) {
|
publicAPI.objects.get.and.callFake(function (identifier) {
|
||||||
return Promise.resolve({identifier: identifier});
|
return Promise.resolve({identifier: identifier});
|
||||||
@@ -68,14 +52,6 @@ define([
|
|||||||
{
|
{
|
||||||
namespace: 'test',
|
namespace: 'test',
|
||||||
key: 'a'
|
key: 'a'
|
||||||
},
|
|
||||||
{
|
|
||||||
namespace: 'test',
|
|
||||||
key: 'b'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
namespace: 'test',
|
|
||||||
key: 'c'
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
@@ -92,55 +68,55 @@ define([
|
|||||||
composition.on('add', listener);
|
composition.on('add', listener);
|
||||||
|
|
||||||
return composition.load().then(function () {
|
return composition.load().then(function () {
|
||||||
expect(listener.calls.count()).toBe(3);
|
expect(listener.calls.count()).toBe(1);
|
||||||
expect(listener).toHaveBeenCalledWith({
|
expect(listener).toHaveBeenCalledWith({
|
||||||
identifier: {namespace: 'test', key: 'a'}
|
identifier: {namespace: 'test', key: 'a'}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('supports reordering of composition', function () {
|
|
||||||
var listener;
|
|
||||||
beforeEach(function () {
|
|
||||||
listener = jasmine.createSpy('reorderListener');
|
|
||||||
composition.on('reorder', listener);
|
|
||||||
|
|
||||||
return composition.load();
|
// TODO: Implement add/removal in new default provider.
|
||||||
});
|
xit('synchronizes changes between instances', function () {
|
||||||
it('', function () {
|
var otherComposition = compositionAPI.get(domainObject);
|
||||||
composition.reorder(1, 0);
|
var addListener = jasmine.createSpy('addListener');
|
||||||
let newComposition =
|
var removeListener = jasmine.createSpy('removeListener');
|
||||||
publicAPI.objects.mutate.calls.mostRecent().args[2];
|
var otherAddListener = jasmine.createSpy('otherAddListener');
|
||||||
let reorderPlan = listener.calls.mostRecent().args[0][0];
|
var otherRemoveListener = jasmine.createSpy('otherRemoveListener');
|
||||||
|
|
||||||
expect(reorderPlan.oldIndex).toBe(1);
|
|
||||||
expect(reorderPlan.newIndex).toBe(0);
|
|
||||||
expect(newComposition[0].key).toEqual('b');
|
|
||||||
expect(newComposition[1].key).toEqual('a');
|
|
||||||
expect(newComposition[2].key).toEqual('c');
|
|
||||||
});
|
|
||||||
it('', function () {
|
|
||||||
composition.reorder(0, 2);
|
|
||||||
let newComposition =
|
|
||||||
publicAPI.objects.mutate.calls.mostRecent().args[2];
|
|
||||||
let reorderPlan = listener.calls.mostRecent().args[0][0];
|
|
||||||
|
|
||||||
expect(reorderPlan.oldIndex).toBe(0);
|
|
||||||
expect(reorderPlan.newIndex).toBe(2);
|
|
||||||
expect(newComposition[0].key).toEqual('b');
|
|
||||||
expect(newComposition[1].key).toEqual('c');
|
|
||||||
expect(newComposition[2].key).toEqual('a');
|
|
||||||
})
|
|
||||||
});
|
|
||||||
it('supports adding an object to composition', function () {
|
|
||||||
let addListener = jasmine.createSpy('addListener');
|
|
||||||
let mockChildObject = {
|
|
||||||
identifier: {key: 'mock-key', namespace: ''}
|
|
||||||
};
|
|
||||||
composition.on('add', addListener);
|
composition.on('add', addListener);
|
||||||
composition.add(mockChildObject);
|
composition.on('remove', removeListener);
|
||||||
|
otherComposition.on('add', otherAddListener);
|
||||||
|
otherComposition.on('remove', otherRemoveListener);
|
||||||
|
|
||||||
expect(domainObject.composition.length).toBe(4);
|
return Promise.all([composition.load(), otherComposition.load()])
|
||||||
expect(domainObject.composition[3]).toEqual(mockChildObject.identifier);
|
.then(function () {
|
||||||
|
expect(addListener).toHaveBeenCalled();
|
||||||
|
expect(otherAddListener).toHaveBeenCalled();
|
||||||
|
expect(removeListener).not.toHaveBeenCalled();
|
||||||
|
expect(otherRemoveListener).not.toHaveBeenCalled();
|
||||||
|
|
||||||
|
var object = addListener.calls.mostRecent().args[0];
|
||||||
|
composition.remove(object);
|
||||||
|
expect(removeListener).toHaveBeenCalled();
|
||||||
|
expect(otherRemoveListener).toHaveBeenCalled();
|
||||||
|
|
||||||
|
addListener.reset();
|
||||||
|
otherAddListener.reset();
|
||||||
|
composition.add(object);
|
||||||
|
expect(addListener).toHaveBeenCalled();
|
||||||
|
expect(otherAddListener).toHaveBeenCalled();
|
||||||
|
|
||||||
|
removeListener.reset();
|
||||||
|
otherRemoveListener.reset();
|
||||||
|
otherComposition.remove(object);
|
||||||
|
expect(removeListener).toHaveBeenCalled();
|
||||||
|
expect(otherRemoveListener).toHaveBeenCalled();
|
||||||
|
|
||||||
|
addListener.reset();
|
||||||
|
otherAddListener.reset();
|
||||||
|
otherComposition.add(object);
|
||||||
|
expect(addListener).toHaveBeenCalled();
|
||||||
|
expect(otherAddListener).toHaveBeenCalled();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -163,9 +139,7 @@ define([
|
|||||||
key: 'thing'
|
key: 'thing'
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
},
|
}
|
||||||
add: jasmine.createSpy('add'),
|
|
||||||
remove: jasmine.createSpy('remove')
|
|
||||||
};
|
};
|
||||||
domainObject = {
|
domainObject = {
|
||||||
identifier: {
|
identifier: {
|
||||||
@@ -195,25 +169,6 @@ define([
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('Calling add or remove', function () {
|
|
||||||
let mockChildObject;
|
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
mockChildObject = {
|
|
||||||
identifier: {key: 'mock-key', namespace: ''}
|
|
||||||
};
|
|
||||||
composition.add(mockChildObject);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('calls add on the provider', function () {
|
|
||||||
expect(customProvider.add).toHaveBeenCalledWith(domainObject, mockChildObject.identifier);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('calls remove on the provider', function () {
|
|
||||||
composition.remove(mockChildObject);
|
|
||||||
expect(customProvider.remove).toHaveBeenCalledWith(domainObject, mockChildObject.identifier);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('dynamic custom composition', function () {
|
describe('dynamic custom composition', function () {
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ define([
|
|||||||
], function (
|
], function (
|
||||||
_
|
_
|
||||||
) {
|
) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A CompositionCollection represents the list of domain objects contained
|
* A CompositionCollection represents the list of domain objects contained
|
||||||
* by another domain object. It provides methods for loading this
|
* by another domain object. It provides methods for loading this
|
||||||
@@ -55,13 +56,13 @@ define([
|
|||||||
this.listeners = {
|
this.listeners = {
|
||||||
add: [],
|
add: [],
|
||||||
remove: [],
|
remove: [],
|
||||||
load: [],
|
load: []
|
||||||
reorder: []
|
|
||||||
};
|
};
|
||||||
this.onProviderAdd = this.onProviderAdd.bind(this);
|
this.onProviderAdd = this.onProviderAdd.bind(this);
|
||||||
this.onProviderRemove = this.onProviderRemove.bind(this);
|
this.onProviderRemove = this.onProviderRemove.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Listen for changes to this composition. Supports 'add', 'remove', and
|
* Listen for changes to this composition. Supports 'add', 'remove', and
|
||||||
* 'load' events.
|
* 'load' events.
|
||||||
@@ -74,9 +75,7 @@ define([
|
|||||||
if (!this.listeners[event]) {
|
if (!this.listeners[event]) {
|
||||||
throw new Error('Event not supported by composition: ' + event);
|
throw new Error('Event not supported by composition: ' + event);
|
||||||
}
|
}
|
||||||
if (!this.mutationListener) {
|
|
||||||
this._synchronize();
|
|
||||||
}
|
|
||||||
if (this.provider.on && this.provider.off) {
|
if (this.provider.on && this.provider.off) {
|
||||||
if (event === 'add') {
|
if (event === 'add') {
|
||||||
this.provider.on(
|
this.provider.on(
|
||||||
@@ -92,13 +91,6 @@ define([
|
|||||||
this.onProviderRemove,
|
this.onProviderRemove,
|
||||||
this
|
this
|
||||||
);
|
);
|
||||||
} if (event === 'reorder') {
|
|
||||||
this.provider.on(
|
|
||||||
this.domainObject,
|
|
||||||
'reorder',
|
|
||||||
this.onProviderReorder,
|
|
||||||
this
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,8 +124,6 @@ define([
|
|||||||
|
|
||||||
this.listeners[event].splice(index, 1);
|
this.listeners[event].splice(index, 1);
|
||||||
if (this.listeners[event].length === 0) {
|
if (this.listeners[event].length === 0) {
|
||||||
this._destroy();
|
|
||||||
|
|
||||||
// Remove provider listener if this is the last callback to
|
// Remove provider listener if this is the last callback to
|
||||||
// be removed.
|
// be removed.
|
||||||
if (this.provider.off && this.provider.on) {
|
if (this.provider.off && this.provider.on) {
|
||||||
@@ -151,13 +141,6 @@ define([
|
|||||||
this.onProviderRemove,
|
this.onProviderRemove,
|
||||||
this
|
this
|
||||||
);
|
);
|
||||||
} else if (event === 'reorder') {
|
|
||||||
this.provider.off(
|
|
||||||
this.domainObject,
|
|
||||||
'reorder',
|
|
||||||
this.onProviderReorder,
|
|
||||||
this
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -177,9 +160,6 @@ define([
|
|||||||
*/
|
*/
|
||||||
CompositionCollection.prototype.add = function (child, skipMutate) {
|
CompositionCollection.prototype.add = function (child, skipMutate) {
|
||||||
if (!skipMutate) {
|
if (!skipMutate) {
|
||||||
if (!this.publicAPI.composition.checkPolicy(this.domainObject, child)) {
|
|
||||||
throw `Object of type ${child.type} cannot be added to object of type ${this.domainObject.type}`;
|
|
||||||
}
|
|
||||||
this.provider.add(this.domainObject, child.identifier);
|
this.provider.add(this.domainObject, child.identifier);
|
||||||
} else {
|
} else {
|
||||||
this.emit('add', child);
|
this.emit('add', child);
|
||||||
@@ -229,29 +209,6 @@ define([
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Reorder the domain objects in this composition.
|
|
||||||
*
|
|
||||||
* A call to [load]{@link module:openmct.CompositionCollection#load}
|
|
||||||
* must have resolved before using this method.
|
|
||||||
*
|
|
||||||
* @param {number} oldIndex
|
|
||||||
* @param {number} newIndex
|
|
||||||
* @memberof module:openmct.CompositionCollection#
|
|
||||||
* @name remove
|
|
||||||
*/
|
|
||||||
CompositionCollection.prototype.reorder = function (oldIndex, newIndex, skipMutate) {
|
|
||||||
this.provider.reorder(this.domainObject, oldIndex, newIndex);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle reorder from provider.
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
CompositionCollection.prototype.onProviderReorder = function (reorderMap) {
|
|
||||||
this.emit('reorder', reorderMap);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle adds from provider.
|
* Handle adds from provider.
|
||||||
* @private
|
* @private
|
||||||
@@ -271,29 +228,16 @@ define([
|
|||||||
this.remove(child, true);
|
this.remove(child, true);
|
||||||
};
|
};
|
||||||
|
|
||||||
CompositionCollection.prototype._synchronize = function () {
|
|
||||||
this.mutationListener = this.publicAPI.objects.observe(this.domainObject, '*', (newDomainObject) => {
|
|
||||||
this.domainObject = JSON.parse(JSON.stringify(newDomainObject));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
CompositionCollection.prototype._destroy = function () {
|
|
||||||
if (this.mutationListener) {
|
|
||||||
this.mutationListener();
|
|
||||||
delete this.mutationListener;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Emit events.
|
* Emit events.
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
CompositionCollection.prototype.emit = function (event, ...payload) {
|
CompositionCollection.prototype.emit = function (event, payload) {
|
||||||
this.listeners[event].forEach(function (l) {
|
this.listeners[event].forEach(function (l) {
|
||||||
if (l.context) {
|
if (l.context) {
|
||||||
l.callback.apply(l.context, payload);
|
l.callback.call(l.context, payload);
|
||||||
} else {
|
} else {
|
||||||
l.callback(...payload);
|
l.callback(payload);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -48,11 +48,24 @@ define([
|
|||||||
this.listeningTo = {};
|
this.listeningTo = {};
|
||||||
this.onMutation = this.onMutation.bind(this);
|
this.onMutation = this.onMutation.bind(this);
|
||||||
|
|
||||||
|
this.cannotContainDuplicates = this.cannotContainDuplicates.bind(this);
|
||||||
this.cannotContainItself = this.cannotContainItself.bind(this);
|
this.cannotContainItself = this.cannotContainItself.bind(this);
|
||||||
|
|
||||||
|
compositionAPI.addPolicy(this.cannotContainDuplicates);
|
||||||
compositionAPI.addPolicy(this.cannotContainItself);
|
compositionAPI.addPolicy(this.cannotContainItself);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
DefaultCompositionProvider.prototype.cannotContainDuplicates = function (parent, child) {
|
||||||
|
return this.appliesTo(parent) &&
|
||||||
|
parent.composition.findIndex((composeeId) => {
|
||||||
|
return composeeId.namespace === child.identifier.namespace &&
|
||||||
|
composeeId.key === child.identifier.key;
|
||||||
|
}) === -1;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
@@ -113,7 +126,6 @@ define([
|
|||||||
objectListeners = this.listeningTo[keyString] = {
|
objectListeners = this.listeningTo[keyString] = {
|
||||||
add: [],
|
add: [],
|
||||||
remove: [],
|
remove: [],
|
||||||
reorder: [],
|
|
||||||
composition: [].slice.apply(domainObject.composition)
|
composition: [].slice.apply(domainObject.composition)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -148,7 +160,7 @@ define([
|
|||||||
});
|
});
|
||||||
|
|
||||||
objectListeners[event].splice(index, 1);
|
objectListeners[event].splice(index, 1);
|
||||||
if (!objectListeners.add.length && !objectListeners.remove.length && !objectListeners.reorder.length) {
|
if (!objectListeners.add.length && !objectListeners.remove.length) {
|
||||||
delete this.listeningTo[keyString];
|
delete this.listeningTo[keyString];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -166,12 +178,8 @@ define([
|
|||||||
* @method remove
|
* @method remove
|
||||||
*/
|
*/
|
||||||
DefaultCompositionProvider.prototype.remove = function (domainObject, childId) {
|
DefaultCompositionProvider.prototype.remove = function (domainObject, childId) {
|
||||||
let composition = domainObject.composition.filter(function (child) {
|
// TODO: this needs to be synchronized via mutation.
|
||||||
return !(childId.namespace === child.namespace &&
|
throw new Error('Default Provider does not implement removal.');
|
||||||
childId.key === child.key);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.publicAPI.objects.mutate(domainObject, 'composition', composition);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -186,66 +194,9 @@ define([
|
|||||||
* @memberof module:openmct.CompositionProvider#
|
* @memberof module:openmct.CompositionProvider#
|
||||||
* @method add
|
* @method add
|
||||||
*/
|
*/
|
||||||
DefaultCompositionProvider.prototype.add = function (parent, childId) {
|
DefaultCompositionProvider.prototype.add = function (domainObject, child) {
|
||||||
if (!this.includes(parent, childId)) {
|
throw new Error('Default Provider does not implement adding.');
|
||||||
parent.composition.push(childId);
|
// TODO: this needs to be synchronized via mutation
|
||||||
this.publicAPI.objects.mutate(parent, 'composition', parent.composition);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
DefaultCompositionProvider.prototype.includes = function (parent, childId) {
|
|
||||||
return parent.composition.findIndex(composee =>
|
|
||||||
this.publicAPI.objects.areIdsEqual(composee, childId)) !== -1;
|
|
||||||
};
|
|
||||||
|
|
||||||
DefaultCompositionProvider.prototype.reorder = function (domainObject, oldIndex, newIndex) {
|
|
||||||
let newComposition = domainObject.composition.slice();
|
|
||||||
let removeId = oldIndex > newIndex ? oldIndex + 1 : oldIndex;
|
|
||||||
let insertPosition = oldIndex < newIndex ? newIndex + 1 : newIndex;
|
|
||||||
//Insert object in new position
|
|
||||||
newComposition.splice(insertPosition, 0, domainObject.composition[oldIndex]);
|
|
||||||
newComposition.splice(removeId, 1);
|
|
||||||
|
|
||||||
let reorderPlan = [{
|
|
||||||
oldIndex,
|
|
||||||
newIndex
|
|
||||||
}];
|
|
||||||
|
|
||||||
if (oldIndex > newIndex) {
|
|
||||||
for (let i = newIndex; i < oldIndex; i++) {
|
|
||||||
reorderPlan.push({
|
|
||||||
oldIndex: i,
|
|
||||||
newIndex: i + 1
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (let i = oldIndex + 1; i <= newIndex; i++) {
|
|
||||||
reorderPlan.push({
|
|
||||||
oldIndex: i,
|
|
||||||
newIndex: i - 1
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.publicAPI.objects.mutate(domainObject, 'composition', newComposition);
|
|
||||||
|
|
||||||
let id = objectUtils.makeKeyString(domainObject.identifier);
|
|
||||||
var listeners = this.listeningTo[id];
|
|
||||||
|
|
||||||
if (!listeners) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
listeners.reorder.forEach(notify);
|
|
||||||
|
|
||||||
function notify(listener) {
|
|
||||||
if (listener.context) {
|
|
||||||
listener.callback.call(listener.context, reorderPlan);
|
|
||||||
} else {
|
|
||||||
listener.callback(reorderPlan);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ define(['zepto', './res/indicator-template.html'],
|
|||||||
this.openmct = openmct;
|
this.openmct = openmct;
|
||||||
this.element = $(indicatorTemplate)[0];
|
this.element = $(indicatorTemplate)[0];
|
||||||
|
|
||||||
this.textElement = this.element.querySelector('.js-indicator-text');
|
this.textElement = this.element.querySelector('.indicator-text');
|
||||||
|
|
||||||
//Set defaults
|
//Set defaults
|
||||||
this.text('New Indicator');
|
this.text('New Indicator');
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
<div class="c-indicator c-indicator--clickable c-indicator--simple" title="">
|
<div class="ls-indicator" title="">
|
||||||
<span class="label js-indicator-text c-indicator__label"></span>
|
<span class="label indicator-text"></span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -21,10 +21,8 @@
|
|||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
define([
|
define([
|
||||||
'./object-utils.js',
|
|
||||||
'lodash'
|
'lodash'
|
||||||
], function (
|
], function (
|
||||||
utils,
|
|
||||||
_
|
_
|
||||||
) {
|
) {
|
||||||
var ANY_OBJECT_EVENT = "mutation";
|
var ANY_OBJECT_EVENT = "mutation";
|
||||||
@@ -43,9 +41,7 @@ define([
|
|||||||
}
|
}
|
||||||
|
|
||||||
function qualifiedEventName(object, eventName) {
|
function qualifiedEventName(object, eventName) {
|
||||||
var keystring = utils.makeKeyString(object.identifier);
|
return [object.identifier.key, eventName].join(':');
|
||||||
|
|
||||||
return [keystring, eventName].join(':');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MutableObject.prototype.stopListening = function () {
|
MutableObject.prototype.stopListening = function () {
|
||||||
|
|||||||
@@ -226,20 +226,7 @@ define([
|
|||||||
(identifier.namespace === identifiers[0].namespace &&
|
(identifier.namespace === identifiers[0].namespace &&
|
||||||
identifier.key === identifiers[0].key);
|
identifier.key === identifiers[0].key);
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
ObjectAPI.prototype.getOriginalPath = function (identifier, path = []) {
|
|
||||||
return this.get(identifier).then((domainObject) => {
|
|
||||||
path.push(domainObject);
|
|
||||||
let location = domainObject.location;
|
|
||||||
|
|
||||||
if (location) {
|
|
||||||
return this.getOriginalPath(utils.parseKeyString(location), path);
|
|
||||||
} else {
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Uniquely identifies a domain object.
|
* Uniquely identifies a domain object.
|
||||||
|
|||||||
@@ -5,8 +5,7 @@ import Vue from 'vue';
|
|||||||
const cssClasses = {
|
const cssClasses = {
|
||||||
large: 'l-overlay-large',
|
large: 'l-overlay-large',
|
||||||
small: 'l-overlay-small',
|
small: 'l-overlay-small',
|
||||||
fit: 'l-overlay-fit',
|
fit: 'l-overlay-fit'
|
||||||
fullscreen: 'l-overlay-fullscreen'
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Overlay extends EventEmitter {
|
class Overlay extends EventEmitter {
|
||||||
|
|||||||
@@ -27,16 +27,10 @@
|
|||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import "~styles/sass-base";
|
@import "~styles/sass-base";
|
||||||
|
|
||||||
@mixin legacyMessage() {
|
|
||||||
flex: 0 1 auto;
|
|
||||||
font-family: symbolsfont;
|
|
||||||
font-size: $messageIconD; // Singleton message in a dialog
|
|
||||||
margin-right: $interiorMarginLg;
|
|
||||||
}
|
|
||||||
|
|
||||||
.c-message {
|
.c-message {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
padding: $interiorMarginLg;
|
||||||
|
|
||||||
> * + * {
|
> * + * {
|
||||||
margin-left: $interiorMarginLg;
|
margin-left: $interiorMarginLg;
|
||||||
@@ -64,44 +58,7 @@
|
|||||||
&__title,
|
&__title,
|
||||||
&__action-text {
|
&__action-text {
|
||||||
font-size: 1.2em; // TEMP
|
font-size: 1.2em; // TEMP
|
||||||
}
|
|
||||||
|
|
||||||
&--simple {
|
|
||||||
// Icon and text elements only
|
|
||||||
&:before {
|
|
||||||
font-size: 30px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
[class*='__text'] {
|
|
||||||
font-size: 1.25em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/************************** LEGACY */
|
|
||||||
&.message-severity-info:before {
|
|
||||||
@include legacyMessage();
|
|
||||||
content: $glyph-icon-info;
|
|
||||||
color: $colorInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.message-severity-alert:before {
|
|
||||||
@include legacyMessage();
|
|
||||||
content: $glyph-icon-alert-rect;
|
|
||||||
color: $colorWarningLo;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.message-severity-error:before {
|
|
||||||
@include legacyMessage();
|
|
||||||
content: $glyph-icon-alert-triangle;
|
|
||||||
color: $colorWarningHi;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Messages in a list
|
|
||||||
.c-overlay__messages & {
|
|
||||||
padding: $interiorMarginLg;
|
|
||||||
&:before {
|
|
||||||
font-size: $messageListIconD;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -56,46 +56,16 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&__close-button {
|
&__close-button {
|
||||||
$p: $interiorMargin;
|
$p: $interiorMarginSm;
|
||||||
border-radius: 100% !important;
|
border-radius: 100% !important;
|
||||||
color: $overlayColorFg;
|
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
font-size: 1.25em;
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: $p; right: $p;
|
top: $p; right: $p;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__contents {
|
&__contents {
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__top-bar {
|
|
||||||
flex: 0 0 auto;
|
|
||||||
flex-direction: column;
|
|
||||||
display: flex;
|
|
||||||
|
|
||||||
> * {
|
|
||||||
flex: 0 0 auto;
|
|
||||||
margin-bottom: $interiorMargin;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__dialog-title {
|
|
||||||
@include ellipsize();
|
|
||||||
font-size: 1.5em;
|
|
||||||
line-height: 120%;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__contents-main {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
flex: 1 1 auto;
|
|
||||||
height: 0; // Chrome 73 overflow bug fix
|
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
padding-right: $interiorMargin; // fend off scroll bar
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&__button-bar {
|
&__button-bar {
|
||||||
@@ -119,29 +89,18 @@
|
|||||||
.c-overlay {
|
.c-overlay {
|
||||||
&__blocker {
|
&__blocker {
|
||||||
@include abs();
|
@include abs();
|
||||||
background: $colorOvrBlocker;
|
background: rgba(black, 0.7);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Overlay types, styling for desktop. Appended to .l-overlay-wrapper element.
|
&__outer {
|
||||||
.l-overlay-large,
|
|
||||||
.l-overlay-small,
|
|
||||||
.l-overlay-fit {
|
|
||||||
.c-overlay__outer {
|
|
||||||
border-radius: $overlayCr;
|
border-radius: $overlayCr;
|
||||||
box-shadow: rgba(black, 0.5) 0 2px 25px;
|
box-shadow: rgba(black, 0.5) 0 2px 25px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.l-overlay-fullscreen {
|
|
||||||
// Used by About > Licenses display
|
|
||||||
.c-overlay__outer {
|
|
||||||
@include overlaySizing($overlayOuterMarginFullscreen);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Overlay types, styling for desktop. Appended to .l-overlay-wrapper element.
|
||||||
.l-overlay-large {
|
.l-overlay-large {
|
||||||
// Default
|
// Default
|
||||||
.c-overlay__outer {
|
.c-overlay__outer {
|
||||||
@@ -155,7 +114,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.t-dialog-sm .l-overlay-small, // Legacy dialog support
|
|
||||||
.l-overlay-fit {
|
.l-overlay-fit {
|
||||||
.c-overlay__outer {
|
.c-overlay__outer {
|
||||||
@include overlaySizing(auto);
|
@include overlaySizing(auto);
|
||||||
|
|||||||
@@ -280,11 +280,7 @@ define([
|
|||||||
if (!provider) {
|
if (!provider) {
|
||||||
return Promise.reject('No provider found');
|
return Promise.reject('No provider found');
|
||||||
}
|
}
|
||||||
return provider.request.apply(provider, arguments).catch((rejected) => {
|
return provider.request.apply(provider, arguments);
|
||||||
this.openmct.notifications.error('Error requesting telemetry data, see console for details');
|
|
||||||
console.error(rejected);
|
|
||||||
return Promise.reject(rejected);
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -301,7 +297,7 @@ define([
|
|||||||
* @returns {Function} a function which may be called to terminate
|
* @returns {Function} a function which may be called to terminate
|
||||||
* the subscription
|
* the subscription
|
||||||
*/
|
*/
|
||||||
TelemetryAPI.prototype.subscribe = function (domainObject, callback, options) {
|
TelemetryAPI.prototype.subscribe = function (domainObject, callback) {
|
||||||
var provider = this.findSubscriptionProvider(domainObject);
|
var provider = this.findSubscriptionProvider(domainObject);
|
||||||
|
|
||||||
if (!this.subscribeCache) {
|
if (!this.subscribeCache) {
|
||||||
@@ -320,7 +316,7 @@ define([
|
|||||||
subscriber.callbacks.forEach(function (cb) {
|
subscriber.callbacks.forEach(function (cb) {
|
||||||
cb(value);
|
cb(value);
|
||||||
});
|
});
|
||||||
}, options);
|
});
|
||||||
} else {
|
} else {
|
||||||
subscriber.unsubscribe = function () {};
|
subscriber.unsubscribe = function () {};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,22 +28,14 @@ define([
|
|||||||
describe('Telemetry API', function () {
|
describe('Telemetry API', function () {
|
||||||
var openmct;
|
var openmct;
|
||||||
var telemetryAPI;
|
var telemetryAPI;
|
||||||
var mockTypeService;
|
|
||||||
|
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
openmct = {
|
openmct = {
|
||||||
time: jasmine.createSpyObj('timeAPI', [
|
time: jasmine.createSpyObj('timeAPI', [
|
||||||
'timeSystem',
|
'timeSystem',
|
||||||
'bounds'
|
'bounds'
|
||||||
]),
|
|
||||||
$injector: jasmine.createSpyObj('injector', [
|
|
||||||
'get'
|
|
||||||
])
|
])
|
||||||
};
|
};
|
||||||
mockTypeService = jasmine.createSpyObj('typeService', [
|
|
||||||
'getType'
|
|
||||||
]);
|
|
||||||
openmct.$injector.get.and.returnValue(mockTypeService);
|
|
||||||
openmct.time.timeSystem.and.returnValue({key: 'system'});
|
openmct.time.timeSystem.and.returnValue({key: 'system'});
|
||||||
openmct.time.bounds.and.returnValue({start: 0, end: 1});
|
openmct.time.bounds.and.returnValue({start: 0, end: 1});
|
||||||
telemetryAPI = new TelemetryAPI(openmct);
|
telemetryAPI = new TelemetryAPI(openmct);
|
||||||
@@ -304,233 +296,5 @@ define([
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('metadata', function () {
|
|
||||||
let mockMetadata = {};
|
|
||||||
let mockObjectType = {
|
|
||||||
typeDef: {}
|
|
||||||
};
|
|
||||||
beforeEach(function () {
|
|
||||||
telemetryAPI.addProvider({
|
|
||||||
key: 'mockMetadataProvider',
|
|
||||||
supportsMetadata() {
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
getMetadata() {
|
|
||||||
return mockMetadata;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
mockTypeService.getType.and.returnValue(mockObjectType);
|
|
||||||
})
|
|
||||||
it('respects explicit priority', function () {
|
|
||||||
mockMetadata.values = [
|
|
||||||
{
|
|
||||||
key: "name",
|
|
||||||
name: "Name",
|
|
||||||
hints: {
|
|
||||||
priority: 2
|
|
||||||
}
|
|
||||||
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "timestamp",
|
|
||||||
name: "Timestamp",
|
|
||||||
hints: {
|
|
||||||
priority: 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "sin",
|
|
||||||
name: "Sine",
|
|
||||||
hints: {
|
|
||||||
priority: 4
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "cos",
|
|
||||||
name: "Cosine",
|
|
||||||
hints: {
|
|
||||||
priority: 3
|
|
||||||
}
|
|
||||||
}
|
|
||||||
];
|
|
||||||
let metadata = telemetryAPI.getMetadata({});
|
|
||||||
let values = metadata.values();
|
|
||||||
|
|
||||||
values.forEach((value, index) => {
|
|
||||||
expect(value.hints.priority).toBe(index + 1);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('if no explicit priority, defaults to order defined', function () {
|
|
||||||
mockMetadata.values = [
|
|
||||||
{
|
|
||||||
key: "name",
|
|
||||||
name: "Name"
|
|
||||||
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "timestamp",
|
|
||||||
name: "Timestamp"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "sin",
|
|
||||||
name: "Sine"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "cos",
|
|
||||||
name: "Cosine"
|
|
||||||
}
|
|
||||||
];
|
|
||||||
let metadata = telemetryAPI.getMetadata({});
|
|
||||||
let values = metadata.values();
|
|
||||||
|
|
||||||
values.forEach((value, index) => {
|
|
||||||
expect(value.key).toBe(mockMetadata.values[index].key);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
it('respects domain priority', function () {
|
|
||||||
mockMetadata.values = [
|
|
||||||
{
|
|
||||||
key: "name",
|
|
||||||
name: "Name"
|
|
||||||
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "timestamp-utc",
|
|
||||||
name: "Timestamp UTC",
|
|
||||||
hints: {
|
|
||||||
domain: 2
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "timestamp-local",
|
|
||||||
name: "Timestamp Local",
|
|
||||||
hints: {
|
|
||||||
domain: 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "sin",
|
|
||||||
name: "Sine",
|
|
||||||
hints: {
|
|
||||||
range: 2
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "cos",
|
|
||||||
name: "Cosine",
|
|
||||||
hints: {
|
|
||||||
range: 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
];
|
|
||||||
let metadata = telemetryAPI.getMetadata({});
|
|
||||||
let values = metadata.valuesForHints(['domain']);
|
|
||||||
|
|
||||||
expect(values[0].key).toBe('timestamp-local');
|
|
||||||
expect(values[1].key).toBe('timestamp-utc');
|
|
||||||
});
|
|
||||||
it('respects range priority', function () {
|
|
||||||
mockMetadata.values = [
|
|
||||||
{
|
|
||||||
key: "name",
|
|
||||||
name: "Name"
|
|
||||||
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "timestamp-utc",
|
|
||||||
name: "Timestamp UTC",
|
|
||||||
hints: {
|
|
||||||
domain: 2
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "timestamp-local",
|
|
||||||
name: "Timestamp Local",
|
|
||||||
hints: {
|
|
||||||
domain: 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "sin",
|
|
||||||
name: "Sine",
|
|
||||||
hints: {
|
|
||||||
range: 2
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "cos",
|
|
||||||
name: "Cosine",
|
|
||||||
hints: {
|
|
||||||
range: 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
];
|
|
||||||
let metadata = telemetryAPI.getMetadata({});
|
|
||||||
let values = metadata.valuesForHints(['range']);
|
|
||||||
|
|
||||||
expect(values[0].key).toBe('cos');
|
|
||||||
expect(values[1].key).toBe('sin');
|
|
||||||
});
|
|
||||||
it('respects priority and domain ordering', function () {
|
|
||||||
mockMetadata.values = [
|
|
||||||
{
|
|
||||||
key: "id",
|
|
||||||
name: "ID",
|
|
||||||
hints: {
|
|
||||||
priority: 2
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "name",
|
|
||||||
name: "Name",
|
|
||||||
hints: {
|
|
||||||
priority: 1
|
|
||||||
}
|
|
||||||
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "timestamp-utc",
|
|
||||||
name: "Timestamp UTC",
|
|
||||||
hints: {
|
|
||||||
domain: 2,
|
|
||||||
priority: 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "timestamp-local",
|
|
||||||
name: "Timestamp Local",
|
|
||||||
hints: {
|
|
||||||
domain: 1,
|
|
||||||
priority: 2
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "timestamp-pst",
|
|
||||||
name: "Timestamp PST",
|
|
||||||
hints: {
|
|
||||||
domain: 3,
|
|
||||||
priority: 2
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "sin",
|
|
||||||
name: "Sine"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "cos",
|
|
||||||
name: "Cosine"
|
|
||||||
}
|
|
||||||
];
|
|
||||||
let metadata = telemetryAPI.getMetadata({});
|
|
||||||
let values = metadata.valuesForHints(['priority', 'domain']);
|
|
||||||
[
|
|
||||||
'timestamp-utc',
|
|
||||||
'timestamp-local',
|
|
||||||
'timestamp-pst'
|
|
||||||
].forEach((key, index) => {
|
|
||||||
expect(values[index].key).toBe(key);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
})
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -116,18 +116,14 @@ define([
|
|||||||
return hints.every(hasHint, metadata);
|
return hints.every(hasHint, metadata);
|
||||||
}
|
}
|
||||||
var matchingMetadata = this.valueMetadatas.filter(hasHints);
|
var matchingMetadata = this.valueMetadatas.filter(hasHints);
|
||||||
let iteratees = hints.map(hint => {
|
var sortedMetadata = _.sortBy(matchingMetadata, function (metadata) {
|
||||||
return (metadata) => {
|
return hints.map(function (hint) {
|
||||||
return metadata.hints[hint];
|
return metadata.hints[hint];
|
||||||
}
|
});
|
||||||
});
|
});
|
||||||
return _.sortByAll(matchingMetadata, ...iteratees);
|
return sortedMetadata;
|
||||||
};
|
};
|
||||||
|
|
||||||
TelemetryMetadataManager.prototype.getFilterableValues = function () {
|
|
||||||
return this.valueMetadatas.filter(metadatum => metadatum.filters && metadatum.filters.length > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
TelemetryMetadataManager.prototype.getDefaultDisplayValue = function () {
|
TelemetryMetadataManager.prototype.getDefaultDisplayValue = function () {
|
||||||
let valueMetadata = this.valuesForHints(['range'])[0];
|
let valueMetadata = this.valuesForHints(['range'])[0];
|
||||||
|
|
||||||
|
|||||||
@@ -35,9 +35,6 @@ define([
|
|||||||
canView: function (domainObject) {
|
canView: function (domainObject) {
|
||||||
return domainObject.type === 'LadTableSet';
|
return domainObject.type === 'LadTableSet';
|
||||||
},
|
},
|
||||||
canEdit: function (domainObject) {
|
|
||||||
return domainObject.type === 'LadTableSet';
|
|
||||||
},
|
|
||||||
view: function (domainObject) {
|
view: function (domainObject) {
|
||||||
let component;
|
let component;
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
define([
|
define([
|
||||||
'./components/LADTable.vue',
|
'./components/LadTable.vue',
|
||||||
'vue'
|
'vue'
|
||||||
], function (
|
], function (
|
||||||
LadTableComponent,
|
LadTableComponent,
|
||||||
@@ -35,9 +35,6 @@ define([
|
|||||||
canView: function (domainObject) {
|
canView: function (domainObject) {
|
||||||
return domainObject.type === 'LadTable';
|
return domainObject.type === 'LadTable';
|
||||||
},
|
},
|
||||||
canEdit: function (domainObject) {
|
|
||||||
return domainObject.type === 'LadTable';
|
|
||||||
},
|
|
||||||
view: function (domainObject) {
|
view: function (domainObject) {
|
||||||
let component;
|
let component;
|
||||||
|
|
||||||
|
|||||||
@@ -41,7 +41,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import lodash from 'lodash';
|
import lodash from 'lodash';
|
||||||
import LadRow from './LADRow.vue';
|
import LadRow from './LadRow.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
inject: ['openmct', 'domainObject'],
|
inject: ['openmct', 'domainObject'],
|
||||||
@@ -65,25 +65,17 @@ export default {
|
|||||||
let index = _.findIndex(this.items, (item) => this.openmct.objects.makeKeyString(identifier) === item.key);
|
let index = _.findIndex(this.items, (item) => this.openmct.objects.makeKeyString(identifier) === item.key);
|
||||||
|
|
||||||
this.items.splice(index, 1);
|
this.items.splice(index, 1);
|
||||||
},
|
|
||||||
reorder(reorderPlan) {
|
|
||||||
let oldItems = this.items.slice();
|
|
||||||
reorderPlan.forEach((reorderEvent) => {
|
|
||||||
this.$set(this.items, reorderEvent.newIndex, oldItems[reorderEvent.oldIndex]);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.composition = this.openmct.composition.get(this.domainObject);
|
this.composition = this.openmct.composition.get(this.domainObject);
|
||||||
this.composition.on('add', this.addItem);
|
this.composition.on('add', this.addItem);
|
||||||
this.composition.on('remove', this.removeItem);
|
this.composition.on('remove', this.removeItem);
|
||||||
this.composition.on('reorder', this.reorder);
|
|
||||||
this.composition.load();
|
this.composition.load();
|
||||||
},
|
},
|
||||||
destroyed() {
|
destroyed() {
|
||||||
this.composition.off('add', this.addItem);
|
this.composition.off('add', this.addItem);
|
||||||
this.composition.off('remove', this.removeItem);
|
this.composition.off('remove', this.removeItem);
|
||||||
this.composition.off('reorder', this.reorder);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -52,7 +52,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import lodash from 'lodash';
|
import lodash from 'lodash';
|
||||||
import LadRow from './LADRow.vue';
|
import LadRow from './LadRow.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
inject: ['openmct', 'domainObject'],
|
inject: ['openmct', 'domainObject'],
|
||||||
@@ -93,12 +93,6 @@
|
|||||||
this.primaryTelemetryObjects.splice(index,1);
|
this.primaryTelemetryObjects.splice(index,1);
|
||||||
primary = undefined;
|
primary = undefined;
|
||||||
},
|
},
|
||||||
reorderPrimary(reorderPlan) {
|
|
||||||
let oldComposition = this.primaryTelemetryObjects.slice();
|
|
||||||
reorderPlan.forEach(reorderEvent => {
|
|
||||||
this.$set(this.primaryTelemetryObjects, reorderEvent.newIndex, oldComposition[reorderEvent.oldIndex]);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
addSecondary(primary) {
|
addSecondary(primary) {
|
||||||
return (domainObject) => {
|
return (domainObject) => {
|
||||||
let secondary = {};
|
let secondary = {};
|
||||||
@@ -126,13 +120,11 @@
|
|||||||
this.composition = this.openmct.composition.get(this.domainObject);
|
this.composition = this.openmct.composition.get(this.domainObject);
|
||||||
this.composition.on('add', this.addPrimary);
|
this.composition.on('add', this.addPrimary);
|
||||||
this.composition.on('remove', this.removePrimary);
|
this.composition.on('remove', this.removePrimary);
|
||||||
this.composition.on('reorder', this.reorderPrimary);
|
|
||||||
this.composition.load();
|
this.composition.load();
|
||||||
},
|
},
|
||||||
destroyed() {
|
destroyed() {
|
||||||
this.composition.off('add', this.addPrimary);
|
this.composition.off('add', this.addPrimary);
|
||||||
this.composition.off('remove', this.removePrimary);
|
this.composition.off('remove', this.removePrimary);
|
||||||
this.composition.off('reorder', this.reorderPrimary);
|
|
||||||
this.compositions.forEach(c => {
|
this.compositions.forEach(c => {
|
||||||
c.composition.off('add', c.addCallback);
|
c.composition.off('add', c.addCallback);
|
||||||
c.composition.off('remove', c.removeCallback);
|
c.composition.off('remove', c.removeCallback);
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="c-indicator c-indicator--clickable icon-session">
|
|
||||||
<span class="label c-indicator__label">
|
|
||||||
<button @click="globalClearEmit">Clear All Data</button>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
inject: ['openmct'],
|
|
||||||
methods: {
|
|
||||||
globalClearEmit() {
|
|
||||||
this.openmct.objectViews.emit('clearData');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2014-2019, 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([
|
|
||||||
'./components/globalClearIndicator.vue',
|
|
||||||
'./clearDataAction',
|
|
||||||
'vue'
|
|
||||||
], function (
|
|
||||||
GlobaClearIndicator,
|
|
||||||
ClearDataAction,
|
|
||||||
Vue
|
|
||||||
) {
|
|
||||||
return function plugin(appliesToObjects) {
|
|
||||||
appliesToObjects = appliesToObjects || [];
|
|
||||||
|
|
||||||
return function install(openmct) {
|
|
||||||
let component = new Vue ({
|
|
||||||
provide: {
|
|
||||||
openmct
|
|
||||||
},
|
|
||||||
components: {
|
|
||||||
GlobalClearIndicator: GlobaClearIndicator.default
|
|
||||||
},
|
|
||||||
template: '<GlobalClearIndicator></GlobalClearIndicator>'
|
|
||||||
}),
|
|
||||||
indicator = {
|
|
||||||
element: component.$mount().$el
|
|
||||||
};
|
|
||||||
|
|
||||||
openmct.indicators.add(indicator);
|
|
||||||
|
|
||||||
openmct.contextMenu.registerAction(new ClearDataAction.default(openmct, appliesToObjects));
|
|
||||||
};
|
|
||||||
};
|
|
||||||
});
|
|
||||||
@@ -1,62 +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.
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
import ClearDataActionPlugin from '../plugin.js';
|
|
||||||
import ClearDataAction from '../clearDataAction.js';
|
|
||||||
|
|
||||||
describe('When the Clear Data Plugin is installed,', function () {
|
|
||||||
var mockObjectViews = jasmine.createSpyObj('objectViews', ['emit']),
|
|
||||||
mockIndicatorProvider = jasmine.createSpyObj('indicators', ['add']),
|
|
||||||
mockContextMenuProvider = jasmine.createSpyObj('contextMenu', ['registerAction']),
|
|
||||||
openmct = {
|
|
||||||
objectViews: mockObjectViews,
|
|
||||||
indicators: mockIndicatorProvider,
|
|
||||||
contextMenu: mockContextMenuProvider,
|
|
||||||
install: function (plugin) {
|
|
||||||
plugin(this);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mockObjectPath = [
|
|
||||||
{name: 'mockObject1'},
|
|
||||||
{name: 'mockObject2'}
|
|
||||||
];
|
|
||||||
|
|
||||||
it('Global Clear Indicator is installed', function () {
|
|
||||||
openmct.install(ClearDataActionPlugin([]));
|
|
||||||
|
|
||||||
expect(mockIndicatorProvider.add).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Clear Data context menu action is installed', function () {
|
|
||||||
openmct.install(ClearDataActionPlugin([]));
|
|
||||||
|
|
||||||
expect(mockContextMenuProvider.registerAction).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('clear data action emits a clearData event when invoked', function () {
|
|
||||||
let action = new ClearDataAction(openmct);
|
|
||||||
|
|
||||||
action.invoke(mockObjectPath);
|
|
||||||
|
|
||||||
expect(mockObjectViews.emit).toHaveBeenCalledWith('clearData', mockObjectPath[0]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,77 +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([
|
|
||||||
'./components/AlphanumericFormatView.vue',
|
|
||||||
'vue'
|
|
||||||
], function (AlphanumericFormatView, Vue) {
|
|
||||||
|
|
||||||
function AlphanumericFormatViewProvider(openmct, options) {
|
|
||||||
function isTelemetryObject(selectionPath) {
|
|
||||||
let selectedObject = selectionPath[0].context.item;
|
|
||||||
let parentObject = selectionPath[1].context.item;
|
|
||||||
return parentObject &&
|
|
||||||
parentObject.type === 'layout' &&
|
|
||||||
selectedObject &&
|
|
||||||
openmct.telemetry.isTelemetryObject(selectedObject) &&
|
|
||||||
!options.showAsView.includes(selectedObject.type)
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
key: 'alphanumeric-format',
|
|
||||||
name: 'Alphanumeric Format',
|
|
||||||
canView: function (selection) {
|
|
||||||
if (selection.length === 0 || selection[0].length === 1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return selection.every(isTelemetryObject);
|
|
||||||
},
|
|
||||||
view: function (selection) {
|
|
||||||
let component;
|
|
||||||
return {
|
|
||||||
show: function (element) {
|
|
||||||
component = new Vue({
|
|
||||||
provide: {
|
|
||||||
openmct
|
|
||||||
},
|
|
||||||
components: {
|
|
||||||
AlphanumericFormatView: AlphanumericFormatView.default
|
|
||||||
},
|
|
||||||
template: '<alphanumeric-format-view></alphanumeric-format-view>',
|
|
||||||
el: element
|
|
||||||
});
|
|
||||||
},
|
|
||||||
destroy: function () {
|
|
||||||
component.$destroy();
|
|
||||||
component = undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
priority: function () {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return AlphanumericFormatViewProvider;
|
|
||||||
});
|
|
||||||
@@ -28,17 +28,11 @@ define([], function () {
|
|||||||
key: "layout",
|
key: "layout",
|
||||||
description: "A toolbar for objects inside a display layout.",
|
description: "A toolbar for objects inside a display layout.",
|
||||||
forSelection: function (selection) {
|
forSelection: function (selection) {
|
||||||
if (!selection || selection.length === 0) {
|
// Apply the layout toolbar if the edit mode is on, and the selected object
|
||||||
return false;
|
// is inside a layout, or the main layout is selected.
|
||||||
}
|
return (openmct.editor.isEditing() && selection &&
|
||||||
|
((selection[1] && selection[1].context.item && selection[1].context.item.type === 'layout') ||
|
||||||
let selectionPath = selection[0];
|
(selection[0].context.item && selection[0].context.item.type === 'layout')));
|
||||||
let selectedObject = selectionPath[0];
|
|
||||||
let selectedParent = selectionPath[1];
|
|
||||||
|
|
||||||
// Apply the layout toolbar if the selected object is inside a layout, or the main layout is selected.
|
|
||||||
return (selectedParent && selectedParent.context.item && selectedParent.context.item.type === 'layout') ||
|
|
||||||
(selectedObject.context.item && selectedObject.context.item.type === 'layout');
|
|
||||||
},
|
},
|
||||||
toolbar: function (selection) {
|
toolbar: function (selection) {
|
||||||
const DIALOG_FORM = {
|
const DIALOG_FORM = {
|
||||||
@@ -79,72 +73,190 @@ define([], function () {
|
|||||||
return openmct.$injector.get('dialogService').getUserInput(form, {});
|
return openmct.$injector.get('dialogService').getUserInput(form, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPath(selectionPath) {
|
function getPath() {
|
||||||
return `configuration.items[${selectionPath[0].context.index}]`;
|
return `configuration.items[${selection[0].context.index}]`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getAllTypes(selection) {
|
let selectedParent = selection[1] && selection[1].context.item,
|
||||||
return selection.filter(selectionPath => {
|
selectedObject = selection[0].context.item,
|
||||||
let type = selectionPath[0].context.layoutItem.type;
|
layoutItem = selection[0].context.layoutItem,
|
||||||
return type === 'text-view' ||
|
toolbar = [];
|
||||||
type === 'telemetry-view' ||
|
|
||||||
type === 'box-view' ||
|
if (selectedObject && selectedObject.type === 'layout') {
|
||||||
type === 'image-view' ||
|
toolbar.push({
|
||||||
type === 'line-view' ||
|
control: "menu",
|
||||||
type === 'subobject-view';
|
domainObject: selectedObject,
|
||||||
|
method: function (option) {
|
||||||
|
let name = option.name.toLowerCase();
|
||||||
|
let form = DIALOG_FORM[name];
|
||||||
|
if (form) {
|
||||||
|
getUserInput(form)
|
||||||
|
.then(element => selection[0].context.addElement(name, element));
|
||||||
|
} else {
|
||||||
|
selection[0].context.addElement(name);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
key: "add",
|
||||||
|
icon: "icon-plus",
|
||||||
|
label: "Add",
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
"name": "Box",
|
||||||
|
"class": "icon-box-round-corners"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Line",
|
||||||
|
"class": "icon-line-horz"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Text",
|
||||||
|
"class": "icon-font"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Image",
|
||||||
|
"class": "icon-image"
|
||||||
|
}
|
||||||
|
]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function getAddButton(selection, selectionPath) {
|
if (!layoutItem) {
|
||||||
if (selection.length === 1) {
|
return toolbar;
|
||||||
selectionPath = selectionPath || selection[0];
|
|
||||||
return {
|
|
||||||
control: "menu",
|
|
||||||
domainObject: selectionPath[0].context.item,
|
|
||||||
method: function (option) {
|
|
||||||
let name = option.name.toLowerCase();
|
|
||||||
let form = DIALOG_FORM[name];
|
|
||||||
if (form) {
|
|
||||||
getUserInput(form)
|
|
||||||
.then(element => selectionPath[0].context.addElement(name, element));
|
|
||||||
} else {
|
|
||||||
selectionPath[0].context.addElement(name);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
key: "add",
|
|
||||||
icon: "icon-plus",
|
|
||||||
label: "Add",
|
|
||||||
options: [
|
|
||||||
{
|
|
||||||
"name": "Box",
|
|
||||||
"class": "icon-box-round-corners"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Line",
|
|
||||||
"class": "icon-line-horz"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Text",
|
|
||||||
"class": "icon-font"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Image",
|
|
||||||
"class": "icon-image"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getToggleFrameButton(selectedParent, selection) {
|
let separator = {
|
||||||
return {
|
control: "separator"
|
||||||
|
};
|
||||||
|
let remove = {
|
||||||
|
control: "button",
|
||||||
|
domainObject: selectedParent,
|
||||||
|
icon: "icon-trash",
|
||||||
|
title: "Delete the selected object",
|
||||||
|
method: function () {
|
||||||
|
let removeItem = selection[1].context.removeItem;
|
||||||
|
let prompt = openmct.overlays.dialog({
|
||||||
|
iconClass: 'alert',
|
||||||
|
message: `Warning! This action will remove this item from the Display Layout. Do you want to continue?`,
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
label: 'Ok',
|
||||||
|
emphasis: 'true',
|
||||||
|
callback: function () {
|
||||||
|
removeItem(layoutItem, selection[0].context.index);
|
||||||
|
prompt.dismiss();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Cancel',
|
||||||
|
callback: function () {
|
||||||
|
prompt.dismiss();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let stackOrder = {
|
||||||
|
control: "menu",
|
||||||
|
domainObject: selectedParent,
|
||||||
|
icon: "icon-layers",
|
||||||
|
title: "Move the selected object above or below other objects",
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: "Move to Top",
|
||||||
|
value: "top",
|
||||||
|
class: "icon-arrow-double-up"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Move Up",
|
||||||
|
value: "up",
|
||||||
|
class: "icon-arrow-up"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Move Down",
|
||||||
|
value: "down",
|
||||||
|
class: "icon-arrow-down"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Move to Bottom",
|
||||||
|
value: "bottom",
|
||||||
|
class: "icon-arrow-double-down"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
method: function (option) {
|
||||||
|
selection[1].context.orderItem(option.value, selection[0].context.index);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let useGrid = {
|
||||||
|
control: "toggle-button",
|
||||||
|
domainObject: selectedParent,
|
||||||
|
property: function () {
|
||||||
|
return getPath() + ".useGrid";
|
||||||
|
},
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
value: false,
|
||||||
|
icon: "icon-grid-snap-to",
|
||||||
|
title: "Grid snapping enabled"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: true,
|
||||||
|
icon: "icon-grid-snap-no",
|
||||||
|
title: "Grid snapping disabled"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
let x = {
|
||||||
|
control: "input",
|
||||||
|
type: "number",
|
||||||
|
domainObject: selectedParent,
|
||||||
|
property: function () {
|
||||||
|
return getPath() + ".x";
|
||||||
|
},
|
||||||
|
label: "X:",
|
||||||
|
title: "X position"
|
||||||
|
},
|
||||||
|
y = {
|
||||||
|
control: "input",
|
||||||
|
type: "number",
|
||||||
|
domainObject: selectedParent,
|
||||||
|
property: function () {
|
||||||
|
return getPath() + ".y";
|
||||||
|
},
|
||||||
|
label: "Y:",
|
||||||
|
title: "Y position",
|
||||||
|
},
|
||||||
|
width = {
|
||||||
|
control: 'input',
|
||||||
|
type: 'number',
|
||||||
|
domainObject: selectedParent,
|
||||||
|
property: function () {
|
||||||
|
return getPath() + ".width";
|
||||||
|
},
|
||||||
|
label: 'W:',
|
||||||
|
title: 'Resize object width'
|
||||||
|
},
|
||||||
|
height = {
|
||||||
|
control: 'input',
|
||||||
|
type: 'number',
|
||||||
|
domainObject: selectedParent,
|
||||||
|
property: function () {
|
||||||
|
return getPath() + ".height";
|
||||||
|
},
|
||||||
|
label: 'H:',
|
||||||
|
title: 'Resize object height'
|
||||||
|
};
|
||||||
|
|
||||||
|
if (layoutItem.type === 'subobject-view') {
|
||||||
|
if (toolbar.length > 0) {
|
||||||
|
toolbar.push(separator);
|
||||||
|
}
|
||||||
|
|
||||||
|
toolbar.push({
|
||||||
control: "toggle-button",
|
control: "toggle-button",
|
||||||
domainObject: selectedParent,
|
domainObject: selectedParent,
|
||||||
applicableSelectedItems: selection.filter(selectionPath =>
|
property: function () {
|
||||||
selectionPath[0].context.layoutItem.type === 'subobject-view'
|
return getPath() + ".hasFrame";
|
||||||
),
|
|
||||||
property: function (selectionPath) {
|
|
||||||
return getPath(selectionPath) + ".hasFrame";
|
|
||||||
},
|
},
|
||||||
options: [
|
options: [
|
||||||
{
|
{
|
||||||
@@ -158,186 +270,52 @@ define([], function () {
|
|||||||
title: "Frame hidden"
|
title: "Frame hidden"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
});
|
||||||
}
|
toolbar.push(separator);
|
||||||
|
toolbar.push(stackOrder);
|
||||||
function getRemoveButton(selectedParent, selectionPath, selection) {
|
toolbar.push(x);
|
||||||
return {
|
toolbar.push(y);
|
||||||
control: "button",
|
toolbar.push(width);
|
||||||
domainObject: selectedParent,
|
toolbar.push(height);
|
||||||
icon: "icon-trash",
|
toolbar.push(useGrid);
|
||||||
title: "Delete the selected object",
|
toolbar.push(separator);
|
||||||
method: function () {
|
toolbar.push(remove);
|
||||||
let removeItem = selectionPath[1].context.removeItem;
|
} else {
|
||||||
let prompt = openmct.overlays.dialog({
|
|
||||||
iconClass: 'alert',
|
|
||||||
message: `Warning! This action will remove this item from the Display Layout. Do you want to continue?`,
|
|
||||||
buttons: [
|
|
||||||
{
|
|
||||||
label: 'Ok',
|
|
||||||
emphasis: 'true',
|
|
||||||
callback: function () {
|
|
||||||
removeItem(getAllTypes(selection));
|
|
||||||
prompt.dismiss();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Cancel',
|
|
||||||
callback: function () {
|
|
||||||
prompt.dismiss();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function getStackOrder(selectedParent, selectionPath) {
|
|
||||||
return {
|
|
||||||
control: "menu",
|
|
||||||
domainObject: selectedParent,
|
|
||||||
icon: "icon-layers",
|
|
||||||
title: "Move the selected object above or below other objects",
|
|
||||||
options: [
|
|
||||||
{
|
|
||||||
name: "Move to Top",
|
|
||||||
value: "top",
|
|
||||||
class: "icon-arrow-double-up"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Move Up",
|
|
||||||
value: "up",
|
|
||||||
class: "icon-arrow-up"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Move Down",
|
|
||||||
value: "down",
|
|
||||||
class: "icon-arrow-down"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Move to Bottom",
|
|
||||||
value: "bottom",
|
|
||||||
class: "icon-arrow-double-down"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
method: function (option) {
|
|
||||||
selectionPath[1].context.orderItem(option.value, getAllTypes(selection));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function getXInput(selectedParent, selection) {
|
|
||||||
if (selection.length === 1) {
|
|
||||||
return {
|
|
||||||
control: "input",
|
|
||||||
type: "number",
|
|
||||||
domainObject: selectedParent,
|
|
||||||
applicableSelectedItems: getAllTypes(selection),
|
|
||||||
property: function (selectionPath) {
|
|
||||||
return getPath(selectionPath) + ".x";
|
|
||||||
},
|
|
||||||
label: "X:",
|
|
||||||
title: "X position"
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getYInput(selectedParent, selection) {
|
|
||||||
if (selection.length === 1) {
|
|
||||||
return {
|
|
||||||
control: "input",
|
|
||||||
type: "number",
|
|
||||||
domainObject: selectedParent,
|
|
||||||
applicableSelectedItems: getAllTypes(selection),
|
|
||||||
property: function (selectionPath) {
|
|
||||||
return getPath(selectionPath) + ".y";
|
|
||||||
},
|
|
||||||
label: "Y:",
|
|
||||||
title: "Y position",
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getWidthInput(selectedParent, selection) {
|
|
||||||
if (selection.length === 1) {
|
|
||||||
return {
|
|
||||||
control: 'input',
|
|
||||||
type: 'number',
|
|
||||||
domainObject: selectedParent,
|
|
||||||
applicableSelectedItems: getAllTypes(selection),
|
|
||||||
property: function (selectionPath) {
|
|
||||||
return getPath(selectionPath) + ".width";
|
|
||||||
},
|
|
||||||
label: 'W:',
|
|
||||||
title: 'Resize object width'
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getHeightInput(selectedParent, selection) {
|
|
||||||
if (selection.length === 1) {
|
|
||||||
return {
|
|
||||||
control: 'input',
|
|
||||||
type: 'number',
|
|
||||||
domainObject: selectedParent,
|
|
||||||
applicableSelectedItems: getAllTypes(selection),
|
|
||||||
property: function (selectionPath) {
|
|
||||||
return getPath(selectionPath) + ".height";
|
|
||||||
},
|
|
||||||
label: 'H:',
|
|
||||||
title: 'Resize object height'
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getX2Input(selectedParent, selection) {
|
|
||||||
if (selection.length === 1) {
|
|
||||||
return {
|
|
||||||
control: "input",
|
|
||||||
type: "number",
|
|
||||||
domainObject: selectedParent,
|
|
||||||
applicableSelectedItems: selection.filter(selectionPath => {
|
|
||||||
return selectionPath[0].context.layoutItem.type === 'line-view';
|
|
||||||
}),
|
|
||||||
property: function (selectionPath) {
|
|
||||||
return getPath(selectionPath) + ".x2";
|
|
||||||
},
|
|
||||||
label: "X2:",
|
|
||||||
title: "X2 position"
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getY2Input(selectedParent, selection) {
|
|
||||||
if (selection.length === 1) {
|
|
||||||
return {
|
|
||||||
control: "input",
|
|
||||||
type: "number",
|
|
||||||
domainObject: selectedParent,
|
|
||||||
applicableSelectedItems: selection.filter(selectionPath => {
|
|
||||||
return selectionPath[0].context.layoutItem.type === 'line-view';
|
|
||||||
}),
|
|
||||||
property: function (selectionPath) {
|
|
||||||
return getPath(selectionPath) + ".y2";
|
|
||||||
},
|
|
||||||
label: "Y2:",
|
|
||||||
title: "Y2 position",
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getTextSizeMenu(selectedParent, selection) {
|
|
||||||
const TEXT_SIZE = [8, 9, 10, 11, 12, 13, 14, 15, 16, 20, 24, 30, 36, 48, 72, 96, 128];
|
const TEXT_SIZE = [8, 9, 10, 11, 12, 13, 14, 15, 16, 20, 24, 30, 36, 48, 72, 96, 128];
|
||||||
return {
|
let fill = {
|
||||||
|
control: "color-picker",
|
||||||
|
domainObject: selectedParent,
|
||||||
|
property: function () {
|
||||||
|
return getPath() + ".fill";
|
||||||
|
},
|
||||||
|
icon: "icon-paint-bucket",
|
||||||
|
title: "Set fill color"
|
||||||
|
},
|
||||||
|
stroke = {
|
||||||
|
control: "color-picker",
|
||||||
|
domainObject: selectedParent,
|
||||||
|
property: function () {
|
||||||
|
return getPath() + ".stroke";
|
||||||
|
},
|
||||||
|
icon: "icon-line-horz",
|
||||||
|
title: "Set border color"
|
||||||
|
},
|
||||||
|
color = {
|
||||||
|
control: "color-picker",
|
||||||
|
domainObject: selectedParent,
|
||||||
|
property: function () {
|
||||||
|
return getPath() + ".color";
|
||||||
|
},
|
||||||
|
icon: "icon-font",
|
||||||
|
mandatory: true,
|
||||||
|
title: "Set text color",
|
||||||
|
preventNone: true
|
||||||
|
},
|
||||||
|
size = {
|
||||||
control: "select-menu",
|
control: "select-menu",
|
||||||
domainObject: selectedParent,
|
domainObject: selectedParent,
|
||||||
applicableSelectedItems: selection.filter(selectionPath => {
|
property: function () {
|
||||||
let type = selectionPath[0].context.layoutItem.type;
|
return getPath() + ".size";
|
||||||
return type === 'text-view' || type === 'telemetry-view';
|
|
||||||
}),
|
|
||||||
property: function (selectionPath) {
|
|
||||||
return getPath(selectionPath) + ".size";
|
|
||||||
},
|
},
|
||||||
title: "Set text size",
|
title: "Set text size",
|
||||||
options: TEXT_SIZE.map(size => {
|
options: TEXT_SIZE.map(size => {
|
||||||
@@ -346,128 +324,13 @@ define([], function () {
|
|||||||
};
|
};
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
function getFillMenu(selectedParent, selection) {
|
if (layoutItem.type === 'telemetry-view') {
|
||||||
return {
|
let displayMode = {
|
||||||
control: "color-picker",
|
|
||||||
domainObject: selectedParent,
|
|
||||||
applicableSelectedItems: selection.filter(selectionPath => {
|
|
||||||
let type = selectionPath[0].context.layoutItem.type;
|
|
||||||
return type === 'text-view' ||
|
|
||||||
type === 'telemetry-view' ||
|
|
||||||
type === 'box-view';
|
|
||||||
}),
|
|
||||||
property: function (selectionPath) {
|
|
||||||
return getPath(selectionPath) + ".fill";
|
|
||||||
},
|
|
||||||
icon: "icon-paint-bucket",
|
|
||||||
title: "Set fill color"
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function getStrokeMenu(selectedParent, selection) {
|
|
||||||
return {
|
|
||||||
control: "color-picker",
|
|
||||||
domainObject: selectedParent,
|
|
||||||
applicableSelectedItems: selection.filter(selectionPath => {
|
|
||||||
let type = selectionPath[0].context.layoutItem.type;
|
|
||||||
return type === 'text-view' ||
|
|
||||||
type === 'telemetry-view' ||
|
|
||||||
type === 'box-view' ||
|
|
||||||
type === 'image-view' ||
|
|
||||||
type === 'line-view';
|
|
||||||
}),
|
|
||||||
property: function (selectionPath) {
|
|
||||||
return getPath(selectionPath) + ".stroke";
|
|
||||||
},
|
|
||||||
icon: "icon-line-horz",
|
|
||||||
title: "Set border color"
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function getTextColorMenu(selectedParent, selection) {
|
|
||||||
return {
|
|
||||||
control: "color-picker",
|
|
||||||
domainObject: selectedParent,
|
|
||||||
applicableSelectedItems: selection.filter(selectionPath => {
|
|
||||||
let type = selectionPath[0].context.layoutItem.type;
|
|
||||||
return type === 'text-view' || type === 'telemetry-view';
|
|
||||||
}),
|
|
||||||
property: function (selectionPath) {
|
|
||||||
return getPath(selectionPath) + ".color";
|
|
||||||
},
|
|
||||||
icon: "icon-font",
|
|
||||||
mandatory: true,
|
|
||||||
title: "Set text color",
|
|
||||||
preventNone: true
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function getURLButton(selectedParent, selection) {
|
|
||||||
return {
|
|
||||||
control: "button",
|
|
||||||
domainObject: selectedParent,
|
|
||||||
applicableSelectedItems: selection.filter(selectionPath => {
|
|
||||||
return selectionPath[0].context.layoutItem.type === 'image-view';
|
|
||||||
}),
|
|
||||||
property: function (selectionPath) {
|
|
||||||
return getPath(selectionPath);
|
|
||||||
},
|
|
||||||
icon: "icon-image",
|
|
||||||
title: "Edit image properties",
|
|
||||||
dialog: DIALOG_FORM['image']
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function getTextButton(selectedParent, selection) {
|
|
||||||
return {
|
|
||||||
control: "button",
|
|
||||||
domainObject: selectedParent,
|
|
||||||
applicableSelectedItems: selection.filter(selectionPath => {
|
|
||||||
return selectionPath[0].context.layoutItem.type === 'text-view';
|
|
||||||
}),
|
|
||||||
property: function (selectionPath) {
|
|
||||||
return getPath(selectionPath);
|
|
||||||
},
|
|
||||||
icon: "icon-gear",
|
|
||||||
title: "Edit text properties",
|
|
||||||
dialog: DIALOG_FORM['text']
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function getTelemetryValueMenu(selectionPath, selection) {
|
|
||||||
if (selection.length === 1) {
|
|
||||||
return {
|
|
||||||
control: "select-menu",
|
|
||||||
domainObject: selectionPath[1].context.item,
|
|
||||||
applicableSelectedItems: selection.filter(selectionPath => {
|
|
||||||
return selectionPath[0].context.layoutItem.type === 'telemetry-view';
|
|
||||||
}),
|
|
||||||
property: function (selectionPath) {
|
|
||||||
return getPath(selectionPath) + ".value";
|
|
||||||
},
|
|
||||||
title: "Set value",
|
|
||||||
options: openmct.telemetry.getMetadata(selectionPath[0].context.item).values().map(value => {
|
|
||||||
return {
|
|
||||||
name: value.name,
|
|
||||||
value: value.key
|
|
||||||
}
|
|
||||||
})
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getDisplayModeMenu(selectedParent, selection) {
|
|
||||||
if (selection.length === 1) {
|
|
||||||
return {
|
|
||||||
control: "select-menu",
|
control: "select-menu",
|
||||||
domainObject: selectedParent,
|
domainObject: selectedParent,
|
||||||
applicableSelectedItems: selection.filter(selectionPath => {
|
property: function () {
|
||||||
return selectionPath[0].context.layoutItem.type === 'telemetry-view';
|
return getPath() + ".displayMode";
|
||||||
}),
|
|
||||||
property: function (selectionPath) {
|
|
||||||
return getPath(selectionPath) + ".displayMode";
|
|
||||||
},
|
},
|
||||||
title: "Set display mode",
|
title: "Set display mode",
|
||||||
options: [
|
options: [
|
||||||
@@ -484,196 +347,146 @@ define([], function () {
|
|||||||
value: "value"
|
value: "value"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
value = {
|
||||||
|
control: "select-menu",
|
||||||
|
domainObject: selectedParent,
|
||||||
|
property: function () {
|
||||||
|
return getPath() + ".value";
|
||||||
|
},
|
||||||
|
title: "Set value",
|
||||||
|
options: openmct.telemetry.getMetadata(selectedObject).values().map(value => {
|
||||||
|
return {
|
||||||
|
name: value.name,
|
||||||
|
value: value.key
|
||||||
|
}
|
||||||
|
})
|
||||||
};
|
};
|
||||||
}
|
toolbar = [
|
||||||
}
|
displayMode,
|
||||||
|
separator,
|
||||||
function getSeparator() {
|
value,
|
||||||
return {
|
separator,
|
||||||
control: "separator"
|
fill,
|
||||||
};
|
stroke,
|
||||||
}
|
color,
|
||||||
|
separator,
|
||||||
function isMainLayoutSelected(selectionPath) {
|
size,
|
||||||
let selectedObject = selectionPath[0].context.item;
|
separator,
|
||||||
return selectedObject && selectedObject.type === 'layout' &&
|
stackOrder,
|
||||||
!selectionPath[0].context.layoutItem;
|
x,
|
||||||
}
|
y,
|
||||||
|
height,
|
||||||
if (isMainLayoutSelected(selection[0])) {
|
width,
|
||||||
return [getAddButton(selection)];
|
useGrid,
|
||||||
}
|
separator,
|
||||||
|
remove
|
||||||
let toolbar = {
|
];
|
||||||
'add-menu': [],
|
|
||||||
'toggle-frame': [],
|
|
||||||
'display-mode': [],
|
|
||||||
'telemetry-value': [],
|
|
||||||
'style': [],
|
|
||||||
'text-style': [],
|
|
||||||
'position': [],
|
|
||||||
'text': [],
|
|
||||||
'url': [],
|
|
||||||
'remove': [],
|
|
||||||
};
|
|
||||||
|
|
||||||
selection.forEach(selectionPath => {
|
|
||||||
let selectedParent = selectionPath[1].context.item;
|
|
||||||
let layoutItem = selectionPath[0].context.layoutItem;
|
|
||||||
|
|
||||||
if (layoutItem.type === 'subobject-view') {
|
|
||||||
if (toolbar['add-menu'].length === 0 && selectionPath[0].context.item.type === 'layout') {
|
|
||||||
toolbar['add-menu'] = [getAddButton(selection, selectionPath)];
|
|
||||||
}
|
|
||||||
if (toolbar['toggle-frame'].length === 0) {
|
|
||||||
toolbar['toggle-frame'] = [getToggleFrameButton(selectedParent, selection)];
|
|
||||||
}
|
|
||||||
if (toolbar['position'].length === 0) {
|
|
||||||
toolbar['position'] = [
|
|
||||||
getStackOrder(selectedParent, selectionPath),
|
|
||||||
getXInput(selectedParent, selection),
|
|
||||||
getYInput(selectedParent, selection),
|
|
||||||
getHeightInput(selectedParent, selection),
|
|
||||||
getWidthInput(selectedParent, selection)
|
|
||||||
];
|
|
||||||
}
|
|
||||||
if (toolbar['remove'].length === 0) {
|
|
||||||
toolbar['remove'] = [getRemoveButton(selectedParent, selectionPath, selection)];
|
|
||||||
}
|
|
||||||
} else if (layoutItem.type === 'telemetry-view') {
|
|
||||||
if (toolbar['display-mode'].length === 0) {
|
|
||||||
toolbar['display-mode'] = [getDisplayModeMenu(selectedParent, selection)];
|
|
||||||
}
|
|
||||||
if (toolbar['telemetry-value'].length === 0) {
|
|
||||||
toolbar['telemetry-value'] = [getTelemetryValueMenu(selectionPath, selection)];
|
|
||||||
}
|
|
||||||
if (toolbar['style'].length < 2) {
|
|
||||||
toolbar['style'] = [
|
|
||||||
getFillMenu(selectedParent, selection),
|
|
||||||
getStrokeMenu(selectedParent, selection)
|
|
||||||
];
|
|
||||||
}
|
|
||||||
if (toolbar['text-style'].length === 0) {
|
|
||||||
toolbar['text-style'] = [
|
|
||||||
getTextColorMenu(selectedParent, selection),
|
|
||||||
getTextSizeMenu(selectedParent, selection)
|
|
||||||
];
|
|
||||||
}
|
|
||||||
if (toolbar['position'].length === 0) {
|
|
||||||
toolbar['position'] = [
|
|
||||||
getStackOrder(selectedParent, selectionPath),
|
|
||||||
getXInput(selectedParent, selection),
|
|
||||||
getYInput(selectedParent, selection),
|
|
||||||
getHeightInput(selectedParent, selection),
|
|
||||||
getWidthInput(selectedParent, selection)
|
|
||||||
];
|
|
||||||
}
|
|
||||||
if (toolbar['remove'].length === 0) {
|
|
||||||
toolbar['remove'] = [getRemoveButton(selectedParent, selectionPath, selection)];
|
|
||||||
}
|
|
||||||
} else if (layoutItem.type === 'text-view') {
|
} else if (layoutItem.type === 'text-view') {
|
||||||
if (toolbar['style'].length < 2) {
|
let text = {
|
||||||
toolbar['style'] = [
|
control: "button",
|
||||||
getFillMenu(selectedParent, selection),
|
domainObject: selectedParent,
|
||||||
getStrokeMenu(selectedParent, selection)
|
property: function () {
|
||||||
];
|
return getPath();
|
||||||
}
|
},
|
||||||
if (toolbar['text-style'].length === 0) {
|
icon: "icon-gear",
|
||||||
toolbar['text-style'] = [
|
title: "Edit text properties",
|
||||||
getTextColorMenu(selectedParent, selection),
|
dialog: DIALOG_FORM['text']
|
||||||
getTextSizeMenu(selectedParent, selection)
|
};
|
||||||
];
|
toolbar = [
|
||||||
}
|
fill,
|
||||||
if (toolbar['position'].length === 0) {
|
stroke,
|
||||||
toolbar['position'] = [
|
separator,
|
||||||
getStackOrder(selectedParent, selectionPath),
|
color,
|
||||||
getXInput(selectedParent, selection),
|
size,
|
||||||
getYInput(selectedParent, selection),
|
separator,
|
||||||
getHeightInput(selectedParent, selection),
|
stackOrder,
|
||||||
getWidthInput(selectedParent, selection)
|
x,
|
||||||
];
|
y,
|
||||||
}
|
height,
|
||||||
if (toolbar['text'].length === 0) {
|
width,
|
||||||
toolbar['text'] = [getTextButton(selectedParent, selection)];
|
useGrid,
|
||||||
}
|
separator,
|
||||||
if (toolbar['remove'].length === 0) {
|
text,
|
||||||
toolbar['remove'] = [getRemoveButton(selectedParent, selectionPath, selection)];
|
separator,
|
||||||
}
|
remove
|
||||||
|
];
|
||||||
} else if (layoutItem.type === 'box-view') {
|
} else if (layoutItem.type === 'box-view') {
|
||||||
if (toolbar['style'].length < 2) {
|
toolbar = [
|
||||||
toolbar['style'] = [
|
fill,
|
||||||
getFillMenu(selectedParent, selection),
|
stroke,
|
||||||
getStrokeMenu(selectedParent, selection)
|
separator,
|
||||||
];
|
stackOrder,
|
||||||
}
|
x,
|
||||||
if (toolbar['position'].length === 0) {
|
y,
|
||||||
toolbar['position'] = [
|
height,
|
||||||
getStackOrder(selectedParent, selectionPath),
|
width,
|
||||||
getXInput(selectedParent, selection),
|
useGrid,
|
||||||
getYInput(selectedParent, selection),
|
separator,
|
||||||
getHeightInput(selectedParent, selection),
|
remove
|
||||||
getWidthInput(selectedParent, selection)
|
];
|
||||||
];
|
|
||||||
}
|
|
||||||
if (toolbar['remove'].length === 0) {
|
|
||||||
toolbar['remove'] = [getRemoveButton(selectedParent, selectionPath, selection)];
|
|
||||||
}
|
|
||||||
} else if (layoutItem.type === 'image-view') {
|
} else if (layoutItem.type === 'image-view') {
|
||||||
if (toolbar['style'].length === 0) {
|
let url = {
|
||||||
toolbar['style'] = [
|
control: "button",
|
||||||
getStrokeMenu(selectedParent, selection)
|
domainObject: selectedParent,
|
||||||
];
|
property: function () {
|
||||||
}
|
return getPath();
|
||||||
if (toolbar['position'].length === 0) {
|
},
|
||||||
toolbar['position'] = [
|
icon: "icon-image",
|
||||||
getStackOrder(selectedParent, selectionPath),
|
title: "Edit image properties",
|
||||||
getXInput(selectedParent, selection),
|
dialog: DIALOG_FORM['image']
|
||||||
getYInput(selectedParent, selection),
|
};
|
||||||
getHeightInput(selectedParent, selection),
|
toolbar = [
|
||||||
getWidthInput(selectedParent, selection)
|
stroke,
|
||||||
];
|
separator,
|
||||||
}
|
stackOrder,
|
||||||
if (toolbar['url'].length === 0) {
|
x,
|
||||||
toolbar['url'] = [getURLButton(selectedParent, selection)];
|
y,
|
||||||
}
|
height,
|
||||||
if (toolbar['remove'].length === 0) {
|
width,
|
||||||
toolbar['remove'] = [getRemoveButton(selectedParent, selectionPath, selection)];
|
useGrid,
|
||||||
}
|
separator,
|
||||||
|
url,
|
||||||
|
separator,
|
||||||
|
remove
|
||||||
|
];
|
||||||
} else if (layoutItem.type === 'line-view') {
|
} else if (layoutItem.type === 'line-view') {
|
||||||
if (toolbar['style'].length === 0) {
|
let x2 = {
|
||||||
toolbar['style'] = [
|
control: "input",
|
||||||
getStrokeMenu(selectedParent, selection)
|
type: "number",
|
||||||
];
|
domainObject: selectedParent,
|
||||||
}
|
property: function () {
|
||||||
if (toolbar['position'].length === 0) {
|
return getPath() + ".x2";
|
||||||
toolbar['position'] = [
|
},
|
||||||
getStackOrder(selectedParent, selectionPath),
|
label: "X2:",
|
||||||
getXInput(selectedParent, selection),
|
title: "X2 position"
|
||||||
getYInput(selectedParent, selection),
|
},
|
||||||
getX2Input(selectedParent, selection),
|
y2 = {
|
||||||
getY2Input(selectedParent, selection)
|
control: "input",
|
||||||
];
|
type: "number",
|
||||||
}
|
domainObject: selectedParent,
|
||||||
if (toolbar['remove'].length === 0) {
|
property: function () {
|
||||||
toolbar['remove'] = [getRemoveButton(selectedParent, selectionPath, selection)];
|
return getPath() + ".y2";
|
||||||
}
|
},
|
||||||
|
label: "Y2:",
|
||||||
|
title: "Y2 position",
|
||||||
|
};
|
||||||
|
toolbar = [
|
||||||
|
stroke,
|
||||||
|
separator,
|
||||||
|
stackOrder,
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
x2,
|
||||||
|
y2,
|
||||||
|
useGrid,
|
||||||
|
separator,
|
||||||
|
remove
|
||||||
|
];
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
let toolbarArray = Object.values(toolbar);
|
return toolbar;
|
||||||
return _.flatten(toolbarArray.reduce((accumulator, group, index) => {
|
|
||||||
group = group.filter(control => control !== undefined);
|
|
||||||
|
|
||||||
if (group.length > 0) {
|
|
||||||
accumulator.push(group);
|
|
||||||
|
|
||||||
if (index < toolbarArray.length - 1) {
|
|
||||||
accumulator.push(getSeparator());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return accumulator;
|
|
||||||
}, []));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ define(
|
|||||||
* @param {number[]} pixelDelta the offset from the
|
* @param {number[]} pixelDelta the offset from the
|
||||||
* original position, in pixels
|
* original position, in pixels
|
||||||
*/
|
*/
|
||||||
LayoutDrag.prototype.getAdjustedPositionAndDimensions = function (pixelDelta) {
|
LayoutDrag.prototype.getAdjustedPosition = function (pixelDelta) {
|
||||||
var gridDelta = toGridDelta(this.gridSize, pixelDelta);
|
var gridDelta = toGridDelta(this.gridSize, pixelDelta);
|
||||||
return {
|
return {
|
||||||
position: max(add(
|
position: max(add(
|
||||||
@@ -109,16 +109,6 @@ define(
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
LayoutDrag.prototype.getAdjustedPosition = function (pixelDelta) {
|
|
||||||
var gridDelta = toGridDelta(this.gridSize, pixelDelta);
|
|
||||||
return {
|
|
||||||
position: max(add(
|
|
||||||
this.rawPosition.position,
|
|
||||||
multiply(gridDelta, this.posFactor)
|
|
||||||
), [0, 0])
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
return LayoutDrag;
|
return LayoutDrag;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,90 +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.
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div class="c-properties" v-if="isEditing">
|
|
||||||
<div class="c-properties__header">Alphanumeric Format</div>
|
|
||||||
<ul class="c-properties__section">
|
|
||||||
<li class="c-properties__row">
|
|
||||||
<div class="c-properties__label" title="Printf formatting for the selected telemetry">
|
|
||||||
<label for="telemetryPrintfFormat">Format</label>
|
|
||||||
</div>
|
|
||||||
<div class="c-properties__value">
|
|
||||||
<input id="telemetryPrintfFormat"
|
|
||||||
type="text"
|
|
||||||
@change="formatTelemetry"
|
|
||||||
:value="telemetryFormat"
|
|
||||||
:placeholder="nonMixedFormat ? '' : 'Mixed'"
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
inject: ['openmct'],
|
|
||||||
data() {
|
|
||||||
let selectionPath = this.openmct.selection.get()[0];
|
|
||||||
return {
|
|
||||||
isEditing: this.openmct.editor.isEditing(),
|
|
||||||
telemetryFormat: undefined,
|
|
||||||
nonMixedFormat: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
toggleEdit(isEditing) {
|
|
||||||
this.isEditing = isEditing;
|
|
||||||
},
|
|
||||||
formatTelemetry(event) {
|
|
||||||
let newFormat = event.currentTarget.value;
|
|
||||||
this.openmct.selection.get().forEach(selectionPath => {
|
|
||||||
selectionPath[0].context.updateTelemetryFormat(newFormat);
|
|
||||||
});
|
|
||||||
this.telemetryFormat = newFormat;
|
|
||||||
},
|
|
||||||
handleSelection(selection) {
|
|
||||||
if (selection.length === 0 || selection[0].length < 2) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let format = selection[0][0].context.layoutItem.format;
|
|
||||||
this.nonMixedFormat = selection.every(selectionPath => {
|
|
||||||
return selectionPath[0].context.layoutItem.format === format;
|
|
||||||
});
|
|
||||||
|
|
||||||
this.telemetryFormat = this.nonMixedFormat ? format : '';
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
this.openmct.editor.on('isEditing', this.toggleEdit);
|
|
||||||
this.openmct.selection.on('change', this.handleSelection);
|
|
||||||
this.handleSelection(this.openmct.selection.get());
|
|
||||||
},
|
|
||||||
destroyed() {
|
|
||||||
this.openmct.editor.off('isEditing', this.toggleEdit);
|
|
||||||
this.openmct.selection.off('change', this.handleSelection);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
|
||||||
@@ -23,8 +23,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<layout-frame :item="item"
|
<layout-frame :item="item"
|
||||||
:grid-size="gridSize"
|
:grid-size="gridSize"
|
||||||
@move="(gridDelta) => $emit('move', gridDelta)"
|
@endDrag="(item, updates) => $emit('endDrag', item, updates)">
|
||||||
@endMove="() => $emit('endMove')">
|
|
||||||
<div class="c-box-view"
|
<div class="c-box-view"
|
||||||
:style="style">
|
:style="style">
|
||||||
</div>
|
</div>
|
||||||
@@ -55,7 +54,8 @@
|
|||||||
x: 1,
|
x: 1,
|
||||||
y: 1,
|
y: 1,
|
||||||
width: 10,
|
width: 10,
|
||||||
height: 5
|
height: 5,
|
||||||
|
useGrid: true
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
inject: ['openmct'],
|
inject: ['openmct'],
|
||||||
|
|||||||
@@ -23,11 +23,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="l-layout"
|
<div class="l-layout"
|
||||||
@dragover="handleDragOver"
|
@dragover="handleDragOver"
|
||||||
@click.capture="bypassSelection"
|
@click="bypassSelection"
|
||||||
@drop="handleDrop"
|
@drop="handleDrop">
|
||||||
:class="{
|
|
||||||
'is-multi-selected': selectedLayoutItems.length > 1
|
|
||||||
}">
|
|
||||||
<!-- Background grid -->
|
<!-- Background grid -->
|
||||||
<div class="l-layout__grid-holder c-grid">
|
<div class="l-layout__grid-holder c-grid">
|
||||||
<div class="c-grid__x l-grid l-grid-x"
|
<div class="c-grid__x l-grid l-grid-x"
|
||||||
@@ -42,39 +39,18 @@
|
|||||||
:is="item.type"
|
:is="item.type"
|
||||||
:item="item"
|
:item="item"
|
||||||
:key="item.id"
|
:key="item.id"
|
||||||
:gridSize="gridSize"
|
:gridSize="item.useGrid ? gridSize : [1, 1]"
|
||||||
:initSelect="initSelectIndex === index"
|
:initSelect="initSelectIndex === index"
|
||||||
:index="index"
|
:index="index"
|
||||||
:multiSelect="selectedLayoutItems.length > 1"
|
@endDrag="endDrag"
|
||||||
@move="move"
|
>
|
||||||
@endMove="endMove"
|
|
||||||
@endLineResize='endLineResize'
|
|
||||||
@formatChanged='updateTelemetryFormat'>
|
|
||||||
</component>
|
</component>
|
||||||
<edit-marquee v-if='showMarquee'
|
|
||||||
:gridSize="gridSize"
|
|
||||||
:selectedLayoutItems="selectedLayoutItems"
|
|
||||||
@endResize="endResize">
|
|
||||||
</edit-marquee>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import "~styles/sass-base";
|
@import "~styles/sass-base";
|
||||||
|
|
||||||
@mixin displayMarquee($c) {
|
|
||||||
> .c-frame-edit {
|
|
||||||
// All other frames
|
|
||||||
//@include test($c, 0.4);
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
> .c-frame > .c-frame-edit {
|
|
||||||
// Line object frame
|
|
||||||
//@include test($c, 0.4);
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.l-layout {
|
.l-layout {
|
||||||
@include abs();
|
@include abs();
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -94,7 +70,7 @@
|
|||||||
.l-shell__main-container {
|
.l-shell__main-container {
|
||||||
&[s-selected],
|
&[s-selected],
|
||||||
&[s-selected-parent] {
|
&[s-selected-parent] {
|
||||||
// Display grid and allow edit marquee to display in main layout holder when editing
|
// Display grid in main layout holder when editing
|
||||||
> .l-layout {
|
> .l-layout {
|
||||||
background: $editUIGridColorBg;
|
background: $editUIGridColorBg;
|
||||||
|
|
||||||
@@ -108,7 +84,7 @@
|
|||||||
.l-layout__frame {
|
.l-layout__frame {
|
||||||
&[s-selected],
|
&[s-selected],
|
||||||
&[s-selected-parent] {
|
&[s-selected-parent] {
|
||||||
// Display grid and allow edit marquee to display in nested layouts when editing
|
// Display grid in nested layouts when editing
|
||||||
> * > * > .l-layout {
|
> * > * > .l-layout {
|
||||||
background: $editUIGridColorBg;
|
background: $editUIGridColorBg;
|
||||||
box-shadow: inset $editUIGridColorFg 0 0 2px 1px;
|
box-shadow: inset $editUIGridColorFg 0 0 2px 1px;
|
||||||
@@ -119,21 +95,10 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*********************** EDIT MARQUEE CONTROL */
|
|
||||||
*[s-selected-parent] {
|
|
||||||
> .l-layout {
|
|
||||||
// When main shell layout is the parent
|
|
||||||
@include displayMarquee(deeppink);
|
|
||||||
}
|
|
||||||
> * > * > * {
|
|
||||||
// When a sub-layout is the parent
|
|
||||||
@include displayMarquee(blue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import uuid from 'uuid';
|
import uuid from 'uuid';
|
||||||
|
|
||||||
@@ -143,7 +108,6 @@
|
|||||||
import TextView from './TextView.vue'
|
import TextView from './TextView.vue'
|
||||||
import LineView from './LineView.vue'
|
import LineView from './LineView.vue'
|
||||||
import ImageView from './ImageView.vue'
|
import ImageView from './ImageView.vue'
|
||||||
import EditMarquee from './EditMarquee.vue'
|
|
||||||
|
|
||||||
const ITEM_TYPE_VIEW_MAP = {
|
const ITEM_TYPE_VIEW_MAP = {
|
||||||
'subobject-view': SubobjectView,
|
'subobject-view': SubobjectView,
|
||||||
@@ -159,10 +123,8 @@
|
|||||||
down: -1,
|
down: -1,
|
||||||
bottom: Number.NEGATIVE_INFINITY
|
bottom: Number.NEGATIVE_INFINITY
|
||||||
};
|
};
|
||||||
const DRAG_OBJECT_TRANSFER_PREFIX = 'openmct/domain-object/';
|
|
||||||
|
|
||||||
let components = ITEM_TYPE_VIEW_MAP;
|
const DRAG_OBJECT_TRANSFER_PREFIX = 'openmct/domain-object/';
|
||||||
components['edit-marquee'] = EditMarquee;
|
|
||||||
|
|
||||||
function getItemDefinition(itemType, ...options) {
|
function getItemDefinition(itemType, ...options) {
|
||||||
let itemView = ITEM_TYPE_VIEW_MAP[itemType];
|
let itemView = ITEM_TYPE_VIEW_MAP[itemType];
|
||||||
@@ -179,8 +141,7 @@
|
|||||||
let domainObject = JSON.parse(JSON.stringify(this.domainObject));
|
let domainObject = JSON.parse(JSON.stringify(this.domainObject));
|
||||||
return {
|
return {
|
||||||
internalDomainObject: domainObject,
|
internalDomainObject: domainObject,
|
||||||
initSelectIndex: undefined,
|
initSelectIndex: undefined
|
||||||
selection: []
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@@ -189,145 +150,82 @@
|
|||||||
},
|
},
|
||||||
layoutItems() {
|
layoutItems() {
|
||||||
return this.internalDomainObject.configuration.items;
|
return this.internalDomainObject.configuration.items;
|
||||||
},
|
|
||||||
selectedLayoutItems() {
|
|
||||||
return this.layoutItems.filter(item => {
|
|
||||||
return this.itemIsInCurrentSelection(item);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
showMarquee() {
|
|
||||||
let selectionPath = this.selection[0];
|
|
||||||
let singleSelectedLine = this.selection.length === 1 &&
|
|
||||||
selectionPath[0].context.layoutItem && selectionPath[0].context.layoutItem.type === 'line-view';
|
|
||||||
return selectionPath && selectionPath.length > 1 && !singleSelectedLine;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
inject: ['openmct', 'options'],
|
inject: ['openmct'],
|
||||||
props: ['domainObject'],
|
props: ['domainObject'],
|
||||||
components: components,
|
components: ITEM_TYPE_VIEW_MAP,
|
||||||
methods: {
|
methods: {
|
||||||
addElement(itemType, element) {
|
addElement(itemType, element) {
|
||||||
this.addItem(itemType + '-view', element);
|
this.addItem(itemType + '-view', element);
|
||||||
},
|
},
|
||||||
setSelection(selection) {
|
setSelection(selection) {
|
||||||
this.selection = selection;
|
if (selection.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.removeSelectionListener) {
|
||||||
|
this.removeSelectionListener();
|
||||||
|
}
|
||||||
|
|
||||||
|
let itemIndex = selection[0].context.index;
|
||||||
|
|
||||||
|
if (itemIndex !== undefined) {
|
||||||
|
this.attachSelectionListener(itemIndex);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
itemIsInCurrentSelection(item) {
|
attachSelectionListener(index) {
|
||||||
return this.selection.some(selectionPath =>
|
let path = `configuration.items[${index}].useGrid`;
|
||||||
selectionPath[0].context.layoutItem && selectionPath[0].context.layoutItem.id === item.id);
|
this.removeSelectionListener = this.openmct.objects.observe(this.internalDomainObject, path, function (value) {
|
||||||
|
let item = this.layoutItems[index];
|
||||||
|
|
||||||
|
if (value) {
|
||||||
|
item.x = Math.round(item.x / this.gridSize[0]);
|
||||||
|
item.y = Math.round(item.y / this.gridSize[1]);
|
||||||
|
item.width = Math.round(item.width / this.gridSize[0]);
|
||||||
|
item.height = Math.round(item.height / this.gridSize[1]);
|
||||||
|
|
||||||
|
if (item.x2) {
|
||||||
|
item.x2 = Math.round(item.x2 / this.gridSize[0]);
|
||||||
|
}
|
||||||
|
if (item.y2) {
|
||||||
|
item.y2 = Math.round(item.y2 / this.gridSize[1]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
item.x = this.gridSize[0] * item.x;
|
||||||
|
item.y = this.gridSize[1] * item.y;
|
||||||
|
item.width = this.gridSize[0] * item.width;
|
||||||
|
item.height = this.gridSize[1] * item.height;
|
||||||
|
|
||||||
|
if (item.x2) {
|
||||||
|
item.x2 = this.gridSize[0] * item.x2;
|
||||||
|
}
|
||||||
|
if (item.y2) {
|
||||||
|
item.y2 = this.gridSize[1] * item.y2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
item.useGrid = value;
|
||||||
|
this.mutate(`configuration.items[${index}]`, item);
|
||||||
|
}.bind(this));
|
||||||
},
|
},
|
||||||
bypassSelection($event) {
|
bypassSelection($event) {
|
||||||
if (this.dragInProgress) {
|
if (this.dragInProgress) {
|
||||||
if ($event) {
|
if ($event) {
|
||||||
$event.stopImmediatePropagation();
|
$event.stopImmediatePropagation();
|
||||||
}
|
}
|
||||||
this.dragInProgress = false;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
endLineResize(item, updates) {
|
endDrag(item, updates) {
|
||||||
this.dragInProgress = true;
|
this.dragInProgress = true;
|
||||||
|
setTimeout(function () {
|
||||||
|
this.dragInProgress = false;
|
||||||
|
}.bind(this), 0);
|
||||||
|
|
||||||
let index = this.layoutItems.indexOf(item);
|
let index = this.layoutItems.indexOf(item);
|
||||||
Object.assign(item, updates);
|
Object.assign(item, updates);
|
||||||
this.mutate(`configuration.items[${index}]`, item);
|
this.mutate(`configuration.items[${index}]`, item);
|
||||||
},
|
},
|
||||||
endResize(scaleWidth, scaleHeight, marqueeStart, marqueeOffset) {
|
|
||||||
this.dragInProgress = true;
|
|
||||||
this.layoutItems.forEach(item => {
|
|
||||||
if (this.itemIsInCurrentSelection(item)) {
|
|
||||||
let itemXInMarqueeSpace = item.x - marqueeStart.x;
|
|
||||||
let itemXInMarqueeSpaceAfterScale = Math.round(itemXInMarqueeSpace * scaleWidth);
|
|
||||||
item.x = itemXInMarqueeSpaceAfterScale + marqueeOffset.x + marqueeStart.x;
|
|
||||||
|
|
||||||
let itemYInMarqueeSpace = item.y - marqueeStart.y;
|
|
||||||
let itemYInMarqueeSpaceAfterScale = Math.round(itemYInMarqueeSpace * scaleHeight);
|
|
||||||
item.y = itemYInMarqueeSpaceAfterScale + marqueeOffset.y + marqueeStart.y;
|
|
||||||
|
|
||||||
if (item.x2) {
|
|
||||||
let itemX2InMarqueeSpace = item.x2 - marqueeStart.x;
|
|
||||||
let itemX2InMarqueeSpaceAfterScale = Math.round(itemX2InMarqueeSpace * scaleWidth);
|
|
||||||
item.x2 = itemX2InMarqueeSpaceAfterScale + marqueeOffset.x + marqueeStart.x;
|
|
||||||
} else {
|
|
||||||
item.width = Math.round(item.width * scaleWidth);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item.y2) {
|
|
||||||
let itemY2InMarqueeSpace = item.y2 - marqueeStart.y;
|
|
||||||
let itemY2InMarqueeSpaceAfterScale = Math.round(itemY2InMarqueeSpace * scaleHeight);
|
|
||||||
item.y2 = itemY2InMarqueeSpaceAfterScale + marqueeOffset.y + marqueeStart.y;
|
|
||||||
} else {
|
|
||||||
item.height = Math.round(item.height * scaleHeight);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.mutate("configuration.items", this.layoutItems);
|
|
||||||
},
|
|
||||||
move(gridDelta) {
|
|
||||||
this.dragInProgress = true;
|
|
||||||
|
|
||||||
if (!this.initialPositions) {
|
|
||||||
this.initialPositions = {};
|
|
||||||
_.cloneDeep(this.selectedLayoutItems).forEach(selectedItem => {
|
|
||||||
if (selectedItem.type === 'line-view') {
|
|
||||||
this.initialPositions[selectedItem.id] = [selectedItem.x, selectedItem.y, selectedItem.x2, selectedItem.y2];
|
|
||||||
this.startingMinX2 = this.startingMinX2 !== undefined ? Math.min(this.startingMinX2, selectedItem.x2) : selectedItem.x2;
|
|
||||||
this.startingMinY2 = this.startingMinY2 !== undefined ? Math.min(this.startingMinY2, selectedItem.y2) : selectedItem.y2;
|
|
||||||
} else {
|
|
||||||
this.initialPositions[selectedItem.id] = [selectedItem.x, selectedItem.y];
|
|
||||||
}
|
|
||||||
|
|
||||||
this.startingMinX = this.startingMinX !== undefined ? Math.min(this.startingMinX, selectedItem.x) : selectedItem.x;
|
|
||||||
this.startingMinY = this.startingMinY !== undefined ? Math.min(this.startingMinY, selectedItem.y) : selectedItem.y;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
let layoutItems = this.layoutItems.map(item => {
|
|
||||||
if (this.initialPositions[item.id]) {
|
|
||||||
this.updateItemPosition(item, gridDelta);
|
|
||||||
}
|
|
||||||
return item;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
updateItemPosition(item, gridDelta) {
|
|
||||||
let startingPosition = this.initialPositions[item.id];
|
|
||||||
let [startingX, startingY, startingX2, startingY2] = startingPosition;
|
|
||||||
|
|
||||||
if (this.startingMinX + gridDelta[0] >= 0) {
|
|
||||||
if (item.x2 !== undefined) {
|
|
||||||
if (this.startingMinX2 + gridDelta[0] >= 0) {
|
|
||||||
item.x = startingX + gridDelta[0];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
item.x = startingX + gridDelta[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.startingMinY + gridDelta[1] >= 0) {
|
|
||||||
if (item.y2 !== undefined) {
|
|
||||||
if (this.startingMinY2 + gridDelta[1] >= 0) {
|
|
||||||
item.y = startingY + gridDelta[1];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
item.y = startingY + gridDelta[1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item.x2 !== undefined && this.startingMinX2 + gridDelta[0] >= 0 && this.startingMinX + gridDelta[0] >= 0) {
|
|
||||||
item.x2 = startingX2 + gridDelta[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item.y2 !== undefined && this.startingMinY2 + gridDelta[1] >= 0 && this.startingMinY + gridDelta[1] >= 0) {
|
|
||||||
item.y2 = startingY2 + gridDelta[1];
|
|
||||||
}
|
|
||||||
},
|
|
||||||
endMove() {
|
|
||||||
this.mutate('configuration.items', this.layoutItems);
|
|
||||||
this.initialPositions = undefined;
|
|
||||||
this.startingMinX = undefined;
|
|
||||||
this.startingMinY = undefined;
|
|
||||||
this.startingMinX2 = undefined;
|
|
||||||
this.startingMinY2 = undefined;
|
|
||||||
},
|
|
||||||
mutate(path, value) {
|
mutate(path, value) {
|
||||||
this.openmct.objects.mutate(this.internalDomainObject, path, value);
|
this.openmct.objects.mutate(this.internalDomainObject, path, value);
|
||||||
},
|
},
|
||||||
@@ -385,8 +283,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
isTelemetry(domainObject) {
|
isTelemetry(domainObject) {
|
||||||
if (this.openmct.telemetry.isTelemetryObject(domainObject) &&
|
if (this.openmct.telemetry.isTelemetryObject(domainObject)
|
||||||
!this.options.showAsView.includes(domainObject.type)) {
|
&& domainObject.type !== 'summary-widget'
|
||||||
|
&& domainObject.type !== 'example.imagery') {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
@@ -415,15 +314,11 @@
|
|||||||
this.objectViewMap[keyString] = true;
|
this.objectViewMap[keyString] = true;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
removeItem(selectedItems) {
|
removeItem(item, index) {
|
||||||
let indices = [];
|
|
||||||
this.initSelectIndex = -1;
|
this.initSelectIndex = -1;
|
||||||
selectedItems.forEach(selectedItem => {
|
this.layoutItems.splice(index, 1);
|
||||||
indices.push(selectedItem[0].context.index);
|
|
||||||
this.untrackItem(selectedItem[0].context.layoutItem);
|
|
||||||
});
|
|
||||||
_.pullAt(this.layoutItems, indices);
|
|
||||||
this.mutate("configuration.items", this.layoutItems);
|
this.mutate("configuration.items", this.layoutItems);
|
||||||
|
this.untrackItem(item);
|
||||||
this.$el.click();
|
this.$el.click();
|
||||||
},
|
},
|
||||||
untrackItem(item) {
|
untrackItem(item) {
|
||||||
@@ -489,80 +384,21 @@
|
|||||||
this.mutate("configuration.items", layoutItems);
|
this.mutate("configuration.items", layoutItems);
|
||||||
this.$el.click();
|
this.$el.click();
|
||||||
},
|
},
|
||||||
orderItem(position, selectedItems) {
|
orderItem(position, index) {
|
||||||
let delta = ORDERS[position];
|
let delta = ORDERS[position];
|
||||||
let indices = [];
|
let newIndex = Math.max(Math.min(index + delta, this.layoutItems.length - 1), 0);
|
||||||
let newIndex = -1;
|
let item = this.layoutItems[index];
|
||||||
let items = [];
|
|
||||||
|
|
||||||
Object.assign(items, this.layoutItems);
|
if (newIndex !== index) {
|
||||||
this.selectedLayoutItems.forEach(selectedItem => {
|
this.layoutItems.splice(index, 1);
|
||||||
indices.push(this.layoutItems.indexOf(selectedItem));
|
this.layoutItems.splice(newIndex, 0, item);
|
||||||
});
|
this.mutate('configuration.items', this.layoutItems);
|
||||||
indices.sort((a, b) => a - b);
|
|
||||||
|
|
||||||
if (position === 'top' || position === 'up') {
|
if (this.removeSelectionListener) {
|
||||||
indices.reverse();
|
this.removeSelectionListener();
|
||||||
}
|
this.attachSelectionListener(newIndex);
|
||||||
|
|
||||||
if (position === 'top' || position === 'bottom') {
|
|
||||||
this.moveToTopOrBottom(position, indices, items, delta);
|
|
||||||
} else {
|
|
||||||
this.moveUpOrDown(position, indices, items, delta);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.mutate('configuration.items', this.layoutItems);
|
|
||||||
},
|
|
||||||
moveUpOrDown(position, indices, items, delta) {
|
|
||||||
let previousItemIndex = -1;
|
|
||||||
let newIndex = -1;
|
|
||||||
|
|
||||||
indices.forEach((itemIndex, index) => {
|
|
||||||
let isAdjacentItemSelected = position === 'up' ?
|
|
||||||
itemIndex + 1 === previousItemIndex :
|
|
||||||
itemIndex - 1 === previousItemIndex;
|
|
||||||
|
|
||||||
if (index > 0 && isAdjacentItemSelected) {
|
|
||||||
if (position === 'up') {
|
|
||||||
newIndex -= 1;
|
|
||||||
} else {
|
|
||||||
newIndex += 1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
newIndex = Math.max(Math.min(itemIndex + delta, this.layoutItems.length - 1), 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
previousItemIndex = itemIndex;
|
|
||||||
this.updateItemOrder(newIndex, itemIndex, items);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
moveToTopOrBottom(position, indices, items, delta) {
|
|
||||||
let newIndex = -1;
|
|
||||||
|
|
||||||
indices.forEach((itemIndex, index) => {
|
|
||||||
if (index === 0) {
|
|
||||||
newIndex = Math.max(Math.min(itemIndex + delta, this.layoutItems.length - 1), 0);
|
|
||||||
} else {
|
|
||||||
if (position === 'top') {
|
|
||||||
newIndex -= 1;
|
|
||||||
} else {
|
|
||||||
newIndex += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.updateItemOrder(newIndex, itemIndex, items);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
updateItemOrder(newIndex, itemIndex, items) {
|
|
||||||
if (newIndex !== itemIndex) {
|
|
||||||
this.layoutItems.splice(itemIndex, 1);
|
|
||||||
this.layoutItems.splice(newIndex, 0, items[itemIndex]);
|
|
||||||
}
|
}
|
||||||
},
|
|
||||||
updateTelemetryFormat(item, format) {
|
|
||||||
let index = _.findIndex(this.layoutItems, item);
|
|
||||||
item.format = format;
|
|
||||||
this.mutate(`configuration.items[${index}]`, item);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
@@ -577,10 +413,14 @@
|
|||||||
this.composition.load();
|
this.composition.load();
|
||||||
},
|
},
|
||||||
destroyed: function () {
|
destroyed: function () {
|
||||||
this.openmct.selection.off('change', this.setSelection);
|
this.openmct.off('change', this.setSelection);
|
||||||
this.composition.off('add', this.addChild);
|
this.composition.off('add', this.addChild);
|
||||||
this.composition.off('remove', this.removeChild);
|
this.composition.off('remove', this.removeChild);
|
||||||
this.unlisten();
|
this.unlisten();
|
||||||
|
|
||||||
|
if (this.removeSelectionListener) {
|
||||||
|
this.removeSelectionListener();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,233 +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.
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<!-- Resize handles -->
|
|
||||||
<div class="c-frame-edit" :style="style">
|
|
||||||
<div class="c-frame-edit__handle c-frame-edit__handle--nw"
|
|
||||||
@mousedown="startResize([1,1], [-1,-1], $event)"></div>
|
|
||||||
<div class="c-frame-edit__handle c-frame-edit__handle--ne"
|
|
||||||
@mousedown="startResize([0,1], [1,-1], $event)"></div>
|
|
||||||
<div class="c-frame-edit__handle c-frame-edit__handle--sw"
|
|
||||||
@mousedown="startResize([1,0], [-1,1], $event)"></div>
|
|
||||||
<div class="c-frame-edit__handle c-frame-edit__handle--se"
|
|
||||||
@mousedown="startResize([0,0], [1,1], $event)"></div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
@import "~styles/sass-base";
|
|
||||||
|
|
||||||
.c-frame-edit {
|
|
||||||
// In Layouts, this is the editing rect and handles
|
|
||||||
display: none; // Set to display: block in DisplayLayout.vue
|
|
||||||
pointer-events: none;
|
|
||||||
@include abs();
|
|
||||||
border: $editMarqueeBorder;
|
|
||||||
|
|
||||||
&__handle {
|
|
||||||
$d: 6px;
|
|
||||||
$o: floor($d * -0.5);
|
|
||||||
background: $editFrameColorHandleFg;
|
|
||||||
box-shadow: $editFrameColorHandleBg 0 0 0 2px;
|
|
||||||
pointer-events: all;
|
|
||||||
position: absolute;
|
|
||||||
width: $d; height: $d;
|
|
||||||
top: auto; right: auto; bottom: auto; left: auto;
|
|
||||||
|
|
||||||
&:before {
|
|
||||||
// Extended hit area
|
|
||||||
@include abs(-10px);
|
|
||||||
content: '';
|
|
||||||
display: block;
|
|
||||||
z-index: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background: $editUIColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
&--nwse {
|
|
||||||
cursor: nwse-resize;
|
|
||||||
}
|
|
||||||
|
|
||||||
&--nw {
|
|
||||||
cursor: nw-resize;
|
|
||||||
left: $o; top: $o;
|
|
||||||
}
|
|
||||||
|
|
||||||
&--ne {
|
|
||||||
cursor: ne-resize;
|
|
||||||
right: $o; top: $o;
|
|
||||||
}
|
|
||||||
|
|
||||||
&--se {
|
|
||||||
cursor: se-resize;
|
|
||||||
right: $o; bottom: $o;
|
|
||||||
}
|
|
||||||
|
|
||||||
&--sw {
|
|
||||||
cursor: sw-resize;
|
|
||||||
left: $o; bottom: $o;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import LayoutDrag from './../LayoutDrag'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
inject: ['openmct'],
|
|
||||||
props: {
|
|
||||||
selectedLayoutItems: Array,
|
|
||||||
gridSize: Array
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
dragPosition: undefined
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
style() {
|
|
||||||
let x = Number.POSITIVE_INFINITY;
|
|
||||||
let y = Number.POSITIVE_INFINITY;
|
|
||||||
let width = Number.NEGATIVE_INFINITY;
|
|
||||||
let height = Number.NEGATIVE_INFINITY;
|
|
||||||
|
|
||||||
this.selectedLayoutItems.forEach(item => {
|
|
||||||
if (item.x2 !== undefined) {
|
|
||||||
let lineWidth = Math.abs(item.x - item.x2);
|
|
||||||
let lineMinX = Math.min(item.x, item.x2);
|
|
||||||
x = Math.min(lineMinX, x);
|
|
||||||
width = Math.max(lineWidth + lineMinX, width);
|
|
||||||
} else {
|
|
||||||
x = Math.min(item.x, x);
|
|
||||||
width = Math.max(item.width + item.x, width);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item.y2 !== undefined) {
|
|
||||||
let lineHeight = Math.abs(item.y - item.y2);
|
|
||||||
let lineMinY = Math.min(item.y, item.y2);
|
|
||||||
y = Math.min(lineMinY, y);
|
|
||||||
height = Math.max(lineHeight + lineMinY, height);
|
|
||||||
} else {
|
|
||||||
y = Math.min(item.y, y);
|
|
||||||
height = Math.max(item.height + item.y, height);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (this.dragPosition) {
|
|
||||||
[x, y] = this.dragPosition.position;
|
|
||||||
[width, height] = this.dragPosition.dimensions;
|
|
||||||
} else {
|
|
||||||
width = width - x;
|
|
||||||
height = height - y;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.marqueePosition = {
|
|
||||||
x: x,
|
|
||||||
y: y,
|
|
||||||
width: width,
|
|
||||||
height: height
|
|
||||||
}
|
|
||||||
return this.getMarqueeStyle(x, y, width, height);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
getMarqueeStyle(x, y, width, height) {
|
|
||||||
return {
|
|
||||||
left: (this.gridSize[0] * x) + 'px',
|
|
||||||
top: (this.gridSize[1] * y) + 'px',
|
|
||||||
width: (this.gridSize[0] * width) + 'px',
|
|
||||||
height: (this.gridSize[1] * height) + 'px'
|
|
||||||
};
|
|
||||||
},
|
|
||||||
updatePosition(event) {
|
|
||||||
let currentPosition = [event.pageX, event.pageY];
|
|
||||||
this.initialPosition = this.initialPosition || currentPosition;
|
|
||||||
this.delta = currentPosition.map(function (value, index) {
|
|
||||||
return value - this.initialPosition[index];
|
|
||||||
}.bind(this));
|
|
||||||
},
|
|
||||||
startResize(posFactor, dimFactor, event) {
|
|
||||||
document.body.addEventListener('mousemove', this.continueResize);
|
|
||||||
document.body.addEventListener('mouseup', this.endResize);
|
|
||||||
this.marqueeStartPosition = {
|
|
||||||
position: [this.marqueePosition.x, this.marqueePosition.y],
|
|
||||||
dimensions: [this.marqueePosition.width, this.marqueePosition.height]
|
|
||||||
};
|
|
||||||
this.updatePosition(event);
|
|
||||||
this.activeDrag = new LayoutDrag(this.marqueeStartPosition, posFactor, dimFactor, this.gridSize);
|
|
||||||
event.preventDefault();
|
|
||||||
},
|
|
||||||
continueResize(event) {
|
|
||||||
event.preventDefault();
|
|
||||||
this.updatePosition(event);
|
|
||||||
this.dragPosition = this.activeDrag.getAdjustedPositionAndDimensions(this.delta);
|
|
||||||
},
|
|
||||||
endResize(event) {
|
|
||||||
document.body.removeEventListener('mousemove', this.continueResize);
|
|
||||||
document.body.removeEventListener('mouseup', this.endResize);
|
|
||||||
this.continueResize(event);
|
|
||||||
|
|
||||||
let marqueeStartWidth = this.marqueeStartPosition.dimensions[0];
|
|
||||||
let marqueeStartHeight = this.marqueeStartPosition.dimensions[1];
|
|
||||||
let marqueeStartX = this.marqueeStartPosition.position[0];
|
|
||||||
let marqueeStartY = this.marqueeStartPosition.position[1];
|
|
||||||
|
|
||||||
let marqueeEndX = this.dragPosition.position[0];
|
|
||||||
let marqueeEndY = this.dragPosition.position[1];
|
|
||||||
let marqueeEndWidth = this.dragPosition.dimensions[0];
|
|
||||||
let marqueeEndHeight = this.dragPosition.dimensions[1];
|
|
||||||
|
|
||||||
let scaleWidth = marqueeEndWidth / marqueeStartWidth;
|
|
||||||
let scaleHeight = marqueeEndHeight / marqueeStartHeight;
|
|
||||||
|
|
||||||
let marqueeStart = {
|
|
||||||
x: marqueeStartX,
|
|
||||||
y: marqueeStartY,
|
|
||||||
height: marqueeStartWidth,
|
|
||||||
width: marqueeStartHeight
|
|
||||||
};
|
|
||||||
let marqueeEnd = {
|
|
||||||
x: marqueeEndX,
|
|
||||||
y: marqueeEndY,
|
|
||||||
width: marqueeEndWidth,
|
|
||||||
height: marqueeEndHeight
|
|
||||||
};
|
|
||||||
let marqueeOffset = {
|
|
||||||
x: marqueeEnd.x - marqueeStart.x,
|
|
||||||
y: marqueeEnd.y - marqueeStart.y
|
|
||||||
};
|
|
||||||
|
|
||||||
this.$emit('endResize', scaleWidth, scaleHeight, marqueeStart, marqueeOffset);
|
|
||||||
this.dragPosition = undefined;
|
|
||||||
this.initialPosition = undefined;
|
|
||||||
this.marqueeStartPosition = undefined;
|
|
||||||
this.delta = undefined;
|
|
||||||
event.preventDefault();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
@@ -23,8 +23,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<layout-frame :item="item"
|
<layout-frame :item="item"
|
||||||
:grid-size="gridSize"
|
:grid-size="gridSize"
|
||||||
@move="(gridDelta) => $emit('move', gridDelta)"
|
@endDrag="(item, updates) => $emit('endDrag', item, updates)">
|
||||||
@endMove="() => $emit('endMove')">
|
|
||||||
<div class="c-image-view"
|
<div class="c-image-view"
|
||||||
:style="style">
|
:style="style">
|
||||||
</div>
|
</div>
|
||||||
@@ -57,7 +56,8 @@
|
|||||||
y: 1,
|
y: 1,
|
||||||
width: 10,
|
width: 10,
|
||||||
height: 5,
|
height: 5,
|
||||||
url: element.url
|
url: element.url,
|
||||||
|
useGrid: true
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
inject: ['openmct'],
|
inject: ['openmct'],
|
||||||
|
|||||||
@@ -24,14 +24,25 @@
|
|||||||
<div class="l-layout__frame c-frame"
|
<div class="l-layout__frame c-frame"
|
||||||
:class="{
|
:class="{
|
||||||
'no-frame': !item.hasFrame,
|
'no-frame': !item.hasFrame,
|
||||||
'u-inspectable': inspectable
|
'u-inspectable': inspectable,
|
||||||
|
'is-resizing': isResizing
|
||||||
}"
|
}"
|
||||||
:style="style">
|
:style="style">
|
||||||
|
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
|
|
||||||
<div class="c-frame-edit__move"
|
<!-- Drag handles -->
|
||||||
@mousedown="startMove([1,1], [0,0], $event)">
|
<div class="c-frame-edit">
|
||||||
|
<div class="c-frame-edit__move"
|
||||||
|
@mousedown="startDrag([1,1], [0,0], $event, 'move')"></div>
|
||||||
|
<div class="c-frame-edit__handle c-frame-edit__handle--nw"
|
||||||
|
@mousedown="startDrag([1,1], [-1,-1], $event, 'resize')"></div>
|
||||||
|
<div class="c-frame-edit__handle c-frame-edit__handle--ne"
|
||||||
|
@mousedown="startDrag([0,1], [1,-1], $event, 'resize')"></div>
|
||||||
|
<div class="c-frame-edit__handle c-frame-edit__handle--sw"
|
||||||
|
@mousedown="startDrag([1,0], [-1,1], $event, 'resize')"></div>
|
||||||
|
<div class="c-frame-edit__handle c-frame-edit__handle--se"
|
||||||
|
@mousedown="startDrag([0,0], [1,1], $event, 'resize')"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -39,7 +50,7 @@
|
|||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import "~styles/sass-base";
|
@import "~styles/sass-base";
|
||||||
|
|
||||||
/******************* FRAME */
|
/******************************* FRAME */
|
||||||
.c-frame {
|
.c-frame {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@@ -48,15 +59,124 @@
|
|||||||
> *:first-child {
|
> *:first-child {
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&:not(.no-frame) {
|
||||||
|
background: $colorBodyBg;
|
||||||
|
border: $browseFrameBorder;
|
||||||
|
padding: $interiorMargin;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.c-frame-edit__move {
|
.c-frame-edit {
|
||||||
|
// In Layouts, this is the editing rect and handles
|
||||||
|
// In Fixed Position, this is a wrapper element
|
||||||
|
@include abs();
|
||||||
display: none;
|
display: none;
|
||||||
|
|
||||||
|
&__move {
|
||||||
|
@include abs();
|
||||||
|
cursor: move;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__handle {
|
||||||
|
$d: 6px;
|
||||||
|
$o: floor($d * -0.5);
|
||||||
|
background: $editFrameColorHandleFg;
|
||||||
|
box-shadow: $editFrameColorHandleBg 0 0 0 2px;
|
||||||
|
display: none; // Set to block via s-selected selector
|
||||||
|
position: absolute;
|
||||||
|
width: $d; height: $d;
|
||||||
|
top: auto; right: auto; bottom: auto; left: auto;
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
// Extended hit area
|
||||||
|
@include abs(-10px);
|
||||||
|
content: '';
|
||||||
|
display: block;
|
||||||
|
z-index: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: $editUIColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--nwse {
|
||||||
|
cursor: nwse-resize;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--nw {
|
||||||
|
cursor: nw-resize;
|
||||||
|
left: $o; top: $o;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--ne {
|
||||||
|
cursor: ne-resize;
|
||||||
|
right: $o; top: $o;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--se {
|
||||||
|
cursor: se-resize;
|
||||||
|
right: $o; bottom: $o;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--sw {
|
||||||
|
cursor: sw-resize;
|
||||||
|
left: $o; bottom: $o;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.c-so-view.has-complex-content + .c-frame-edit {
|
||||||
|
// Target frames that hold domain objects that include header elements, as opposed to drawing and alpha objects
|
||||||
|
// Make the __move element a more affordable drag UI element
|
||||||
|
.c-frame-edit__move {
|
||||||
|
@include userSelectNone();
|
||||||
|
background: $editFrameMovebarColorBg;
|
||||||
|
box-shadow: rgba(black, 0.2) 0 1px;
|
||||||
|
bottom: auto;
|
||||||
|
height: 0; // Height is set on hover on s-selected.c-frame
|
||||||
|
opacity: 0.8;
|
||||||
|
max-height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
// Grippy
|
||||||
|
$h: 4px;
|
||||||
|
$tbOffset: ($editFrameMovebarH - $h) / 2;
|
||||||
|
$lrOffset: 25%;
|
||||||
|
@include grippy($editFrameMovebarColorFg);
|
||||||
|
content: '';
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
top: $tbOffset; right: $lrOffset; bottom: $tbOffset; left: $lrOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: $editFrameHovMovebarColorBg;
|
||||||
|
&:before { @include grippy($editFrameHovMovebarColorFg); }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.is-editing {
|
.is-editing {
|
||||||
/******************* STYLES FOR C-FRAME WHILE EDITING */
|
|
||||||
.c-frame {
|
.c-frame {
|
||||||
|
$moveBarOutDelay: 500ms;
|
||||||
|
&.no-frame {
|
||||||
|
border: $editFrameBorder; // Base border style for a frame element while editing.
|
||||||
|
}
|
||||||
|
|
||||||
|
&-edit {
|
||||||
|
display: contents;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-edit__move,
|
||||||
|
.c-so-view {
|
||||||
|
transition: $transOut;
|
||||||
|
transition-delay: $moveBarOutDelay;
|
||||||
|
}
|
||||||
|
|
||||||
&:not([s-selected]) {
|
&:not([s-selected]) {
|
||||||
&:hover {
|
&:hover {
|
||||||
border: $editFrameBorderHov;
|
border: $editFrameBorderHov;
|
||||||
@@ -68,110 +188,37 @@
|
|||||||
border: $editFrameSelectedBorder;
|
border: $editFrameSelectedBorder;
|
||||||
box-shadow: $editFrameSelectedShdw;
|
box-shadow: $editFrameSelectedShdw;
|
||||||
|
|
||||||
.c-frame-edit__move {
|
> .c-frame-edit {
|
||||||
cursor: move;
|
[class*='__handle'] {
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************* DEFAULT STYLES FOR -EDIT__MOVE */
|
|
||||||
// All object types
|
|
||||||
.c-frame-edit__move {
|
|
||||||
@include abs();
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Has-complex-content objects
|
|
||||||
.c-so-view.has-complex-content {
|
|
||||||
transition: $transOut;
|
|
||||||
transition-delay: $moveBarOutDelay;
|
|
||||||
|
|
||||||
> .c-so-view__local-controls {
|
|
||||||
transition: transform 250ms ease-in-out;
|
|
||||||
transition-delay: $moveBarOutDelay;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ .c-frame-edit__move {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.l-layout {
|
|
||||||
/******************* 0 - 1 ITEM SELECTED */
|
|
||||||
&:not(.is-multi-selected) {
|
|
||||||
> .l-layout__frame[s-selected] {
|
|
||||||
> .c-so-view.has-complex-content {
|
|
||||||
> .c-so-view__local-controls {
|
|
||||||
transition: transform $transOutTime ease-in-out;
|
|
||||||
transition-delay: $moveBarOutDelay;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ .c-frame-edit__move {
|
|
||||||
transition: $transOut;
|
|
||||||
transition-delay: $moveBarOutDelay;
|
|
||||||
@include userSelectNone();
|
|
||||||
background: $editFrameMovebarColorBg;
|
|
||||||
box-shadow: rgba(black, 0.2) 0 1px;
|
|
||||||
bottom: auto;
|
|
||||||
display: block;
|
|
||||||
height: 0; // Height is set on hover below
|
|
||||||
opacity: 0.8;
|
|
||||||
max-height: 100%;
|
|
||||||
overflow: hidden;
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
&:before {
|
|
||||||
// Grippy
|
|
||||||
$h: 4px;
|
|
||||||
$tbOffset: ($editFrameMovebarH - $h) / 2;
|
|
||||||
$lrOffset: 25%;
|
|
||||||
@include grippy($editFrameMovebarColorFg);
|
|
||||||
content: '';
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
top: $tbOffset;
|
|
||||||
right: $lrOffset;
|
|
||||||
bottom: $tbOffset;
|
|
||||||
left: $lrOffset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
> .c-so-view.has-complex-content {
|
|
||||||
transition: $transIn;
|
|
||||||
transition-delay: 0s;
|
|
||||||
padding-top: $editFrameMovebarH + $interiorMarginSm;
|
|
||||||
|
|
||||||
> .c-so-view__local-controls {
|
|
||||||
transform: translateY($editFrameMovebarH);
|
|
||||||
transition: transform $transInTime ease-in-out;
|
|
||||||
transition-delay: 0s;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ .c-frame-edit__move {
|
|
||||||
transition: $transIn;
|
|
||||||
transition-delay: 0s;
|
|
||||||
height: $editFrameMovebarH;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************* > 1 ITEMS SELECTED */
|
|
||||||
&.is-multi-selected {
|
|
||||||
.l-layout__frame[s-selected] {
|
|
||||||
> .c-so-view.has-complex-content + .c-frame-edit__move {
|
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.l-layout__frame:not(.is-resizing) {
|
||||||
|
// Show and animate the __move bar for sub-object views with complex content
|
||||||
|
&:hover > .c-so-view.has-complex-content {
|
||||||
|
// Move content down so the __move bar doesn't cover it.
|
||||||
|
padding-top: $editFrameMovebarH;
|
||||||
|
transition: $transIn;
|
||||||
|
|
||||||
|
&.c-so-view--no-frame {
|
||||||
|
// Move content down with a bit more space
|
||||||
|
padding-top: $editFrameMovebarH + $interiorMarginSm;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show the move bar
|
||||||
|
+ .c-frame-edit .c-frame-edit__move {
|
||||||
|
height: $editFrameMovebarH;
|
||||||
|
transition: $transIn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import LayoutDrag from './../LayoutDrag'
|
import LayoutDrag from './../LayoutDrag'
|
||||||
|
|
||||||
@@ -181,9 +228,21 @@
|
|||||||
item: Object,
|
item: Object,
|
||||||
gridSize: Array
|
gridSize: Array
|
||||||
},
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
dragPosition: undefined,
|
||||||
|
isResizing: undefined
|
||||||
|
}
|
||||||
|
},
|
||||||
computed: {
|
computed: {
|
||||||
style() {
|
style() {
|
||||||
let {x, y, width, height} = this.item;
|
let {x, y, width, height} = this.item;
|
||||||
|
|
||||||
|
if (this.dragPosition) {
|
||||||
|
[x, y] = this.dragPosition.position;
|
||||||
|
[width, height] = this.dragPosition.dimensions;
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
left: (this.gridSize[0] * x) + 'px',
|
left: (this.gridSize[0] * x) + 'px',
|
||||||
top: (this.gridSize[1] * y) + 'px',
|
top: (this.gridSize[1] * y) + 'px',
|
||||||
@@ -205,40 +264,36 @@
|
|||||||
return value - this.initialPosition[index];
|
return value - this.initialPosition[index];
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
},
|
},
|
||||||
startMove(posFactor, dimFactor, event) {
|
startDrag(posFactor, dimFactor, event, type) {
|
||||||
document.body.addEventListener('mousemove', this.continueMove);
|
document.body.addEventListener('mousemove', this.continueDrag);
|
||||||
document.body.addEventListener('mouseup', this.endMove);
|
document.body.addEventListener('mouseup', this.endDrag);
|
||||||
|
|
||||||
this.dragPosition = {
|
this.dragPosition = {
|
||||||
position: [this.item.x, this.item.y]
|
position: [this.item.x, this.item.y],
|
||||||
|
dimensions: [this.item.width, this.item.height]
|
||||||
};
|
};
|
||||||
this.updatePosition(event);
|
this.updatePosition(event);
|
||||||
this.activeDrag = new LayoutDrag(this.dragPosition, posFactor, dimFactor, this.gridSize);
|
this.activeDrag = new LayoutDrag(this.dragPosition, posFactor, dimFactor, this.gridSize);
|
||||||
|
this.isResizing = type === 'resize';
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
},
|
},
|
||||||
continueMove(event) {
|
continueDrag(event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
this.updatePosition(event);
|
this.updatePosition(event);
|
||||||
let newPosition = this.activeDrag.getAdjustedPosition(this.delta);
|
this.dragPosition = this.activeDrag.getAdjustedPosition(this.delta);
|
||||||
|
|
||||||
if (!_.isEqual(newPosition, this.dragPosition)) {
|
|
||||||
this.dragPosition = newPosition;
|
|
||||||
this.$emit('move', this.toGridDelta(this.delta));
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
endMove(event) {
|
endDrag(event) {
|
||||||
document.body.removeEventListener('mousemove', this.continueMove);
|
document.body.removeEventListener('mousemove', this.continueDrag);
|
||||||
document.body.removeEventListener('mouseup', this.endMove);
|
document.body.removeEventListener('mouseup', this.endDrag);
|
||||||
this.continueMove(event);
|
this.continueDrag(event);
|
||||||
this.$emit('endMove');
|
let [x, y] = this.dragPosition.position;
|
||||||
|
let [width, height] = this.dragPosition.dimensions;
|
||||||
|
this.$emit('endDrag', this.item, {x, y, width, height});
|
||||||
this.dragPosition = undefined;
|
this.dragPosition = undefined;
|
||||||
this.initialPosition = undefined;
|
this.initialPosition = undefined;
|
||||||
this.delta = undefined;
|
this.delta = undefined;
|
||||||
|
this.isResizing = undefined;
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
},
|
|
||||||
toGridDelta(pixelDelta) {
|
|
||||||
return pixelDelta.map((v, i) => {
|
|
||||||
return Math.round(v / this.gridSize[i]);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,9 +30,9 @@
|
|||||||
</line>
|
</line>
|
||||||
</svg>
|
</svg>
|
||||||
|
|
||||||
<div class="c-frame-edit__move"
|
<div class="c-frame-edit">
|
||||||
@mousedown="startDrag($event)"></div>
|
<div class="c-frame-edit__move"
|
||||||
<div class="c-frame-edit" v-if="showFrameEdit">
|
@mousedown="startDrag($event)"></div>
|
||||||
<div class="c-frame-edit__handle"
|
<div class="c-frame-edit__handle"
|
||||||
:class="startHandleClass"
|
:class="startHandleClass"
|
||||||
@mousedown="startDrag($event, 'start')"></div>
|
@mousedown="startDrag($event, 'start')"></div>
|
||||||
@@ -66,7 +66,8 @@
|
|||||||
y: 10,
|
y: 10,
|
||||||
x2: 10,
|
x2: 10,
|
||||||
y2: 5,
|
y2: 5,
|
||||||
stroke: '#717171'
|
stroke: '#717171',
|
||||||
|
useGrid: true
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
inject: ['openmct'],
|
inject: ['openmct'],
|
||||||
@@ -75,31 +76,24 @@
|
|||||||
gridSize: Array,
|
gridSize: Array,
|
||||||
initSelect: Boolean,
|
initSelect: Boolean,
|
||||||
index: Number,
|
index: Number,
|
||||||
multiSelect: Boolean
|
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
dragPosition: undefined,
|
dragPosition: undefined
|
||||||
dragging: undefined,
|
|
||||||
selection: []
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
showFrameEdit() {
|
|
||||||
let layoutItem = this.selection.length > 0 && this.selection[0][0].context.layoutItem;
|
|
||||||
return !this.multiSelect && layoutItem && layoutItem.id === this.item.id;
|
|
||||||
},
|
|
||||||
position() {
|
position() {
|
||||||
let {x, y, x2, y2} = this.item;
|
let {x, y, x2, y2} = this.item;
|
||||||
if (this.dragging && this.dragPosition) {
|
if (this.dragPosition) {
|
||||||
({x, y, x2, y2} = this.dragPosition);
|
({x, y, x2, y2} = this.dragPosition);
|
||||||
}
|
}
|
||||||
return {x, y, x2, y2};
|
return {x, y, x2, y2};
|
||||||
},
|
},
|
||||||
style() {
|
style() {
|
||||||
let {x, y, x2, y2} = this.position;
|
let {x, y, x2, y2} = this.position;
|
||||||
let width = Math.max(this.gridSize[0] * Math.abs(x - x2), 1);
|
let width = this.gridSize[0] * Math.abs(x - x2);
|
||||||
let height = Math.max(this.gridSize[1] * Math.abs(y - y2), 1);
|
let height = this.gridSize[1] * Math.abs(y - y2);
|
||||||
let left = this.gridSize[0] * Math.min(x, x2);
|
let left = this.gridSize[0] * Math.min(x, x2);
|
||||||
let top = this.gridSize[1] * Math.min(y, y2);
|
let top = this.gridSize[1] * Math.min(y, y2);
|
||||||
return {
|
return {
|
||||||
@@ -181,27 +175,13 @@
|
|||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
let pxDeltaX = this.startPosition[0] - event.pageX;
|
let pxDeltaX = this.startPosition[0] - event.pageX;
|
||||||
let pxDeltaY = this.startPosition[1] - event.pageY;
|
let pxDeltaY = this.startPosition[1] - event.pageY;
|
||||||
let newPosition = this.calculateDragPosition(pxDeltaX, pxDeltaY);
|
this.dragPosition = this.calculateDragPosition(pxDeltaX, pxDeltaY);
|
||||||
|
|
||||||
if (!this.dragging) {
|
|
||||||
if (!_.isEqual(newPosition, this.dragPosition)) {
|
|
||||||
let gridDelta = [event.pageX - this.startPosition[0], event.pageY - this.startPosition[1]];
|
|
||||||
this.dragPosition = newPosition;
|
|
||||||
this.$emit('move', this.toGridDelta(gridDelta));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.dragPosition = newPosition;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
endDrag(event) {
|
endDrag(event) {
|
||||||
document.body.removeEventListener('mousemove', this.continueDrag);
|
document.body.removeEventListener('mousemove', this.continueDrag);
|
||||||
document.body.removeEventListener('mouseup', this.endDrag);
|
document.body.removeEventListener('mouseup', this.endDrag);
|
||||||
let {x, y, x2, y2} = this.dragPosition;
|
let {x, y, x2, y2} = this.dragPosition;
|
||||||
if (!this.dragging) {
|
this.$emit('endDrag', this.item, {x, y, x2, y2});
|
||||||
this.$emit('endMove');
|
|
||||||
} else {
|
|
||||||
this.$emit('endLineResize', this.item, {x, y, x2, y2});
|
|
||||||
}
|
|
||||||
this.dragPosition = undefined;
|
this.dragPosition = undefined;
|
||||||
this.dragging = undefined;
|
this.dragging = undefined;
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
@@ -211,7 +191,6 @@
|
|||||||
let gridDeltaY = Math.round(pxDeltaY / this.gridSize[0]); // TODO: should this be gridSize[1]?
|
let gridDeltaY = Math.round(pxDeltaY / this.gridSize[0]); // TODO: should this be gridSize[1]?
|
||||||
let {x, y, x2, y2} = this.item;
|
let {x, y, x2, y2} = this.item;
|
||||||
let dragPosition = {x, y, x2, y2};
|
let dragPosition = {x, y, x2, y2};
|
||||||
|
|
||||||
if (this.dragging === 'start') {
|
if (this.dragging === 'start') {
|
||||||
dragPosition.x -= gridDeltaX;
|
dragPosition.x -= gridDeltaX;
|
||||||
dragPosition.y -= gridDeltaY;
|
dragPosition.y -= gridDeltaY;
|
||||||
@@ -226,14 +205,6 @@
|
|||||||
dragPosition.y2 -= gridDeltaY;
|
dragPosition.y2 -= gridDeltaY;
|
||||||
}
|
}
|
||||||
return dragPosition;
|
return dragPosition;
|
||||||
},
|
|
||||||
setSelection(selection) {
|
|
||||||
this.selection = selection;
|
|
||||||
},
|
|
||||||
toGridDelta(pixelDelta) {
|
|
||||||
return pixelDelta.map((v, i) => {
|
|
||||||
return Math.round(v / this.gridSize[i]);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
@@ -246,7 +217,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.openmct.selection.on('change', this.setSelection);
|
|
||||||
this.context = {
|
this.context = {
|
||||||
layoutItem: this.item,
|
layoutItem: this.item,
|
||||||
index: this.index
|
index: this.index
|
||||||
@@ -258,7 +228,6 @@
|
|||||||
if (this.removeSelectable) {
|
if (this.removeSelectable) {
|
||||||
this.removeSelectable();
|
this.removeSelectable();
|
||||||
}
|
}
|
||||||
this.openmct.selection.off('change', this.setSelection);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -22,14 +22,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<layout-frame :item="item"
|
<layout-frame :item="item"
|
||||||
:grid-size="gridSize"
|
:grid-size="gridSize"
|
||||||
:title="domainObject && domainObject.name"
|
@endDrag="(item, updates) => $emit('endDrag', item, updates)">
|
||||||
@move="(gridDelta) => $emit('move', gridDelta)"
|
|
||||||
@endMove="() => $emit('endMove')">
|
|
||||||
<object-frame v-if="domainObject"
|
<object-frame v-if="domainObject"
|
||||||
:domain-object="domainObject"
|
:domain-object="domainObject"
|
||||||
:object-path="objectPath"
|
:object-path="objectPath"
|
||||||
:has-frame="item.hasFrame"
|
:has-frame="item.hasFrame"
|
||||||
:show-edit-view="false"
|
|
||||||
ref="objectFrame">
|
ref="objectFrame">
|
||||||
</object-frame>
|
</object-frame>
|
||||||
</layout-frame>
|
</layout-frame>
|
||||||
@@ -68,7 +65,8 @@
|
|||||||
x: position[0],
|
x: position[0],
|
||||||
y: position[1],
|
y: position[1],
|
||||||
identifier: domainObject.identifier,
|
identifier: domainObject.identifier,
|
||||||
hasFrame: hasFrameByDefault(domainObject.type)
|
hasFrame: hasFrameByDefault(domainObject.type),
|
||||||
|
useGrid: true
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
inject: ['openmct'],
|
inject: ['openmct'],
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user