mirror of
https://github.com/nasa/openmct.git
synced 2025-06-27 03:22:04 +00:00
Compare commits
1 Commits
layout-imp
...
context-me
Author | SHA1 | Date | |
---|---|---|---|
485e948abe |
2
app.js
2
app.js
@ -46,7 +46,7 @@ webpackConfig.plugins.push(new webpack.HotModuleReplacementPlugin());
|
|||||||
webpackConfig.plugins.push(function() { this.plugin('watch-run', function(watching, callback) { console.log('Begin compile at ' + new Date()); callback(); }) });
|
webpackConfig.plugins.push(function() { this.plugin('watch-run', function(watching, callback) { console.log('Begin compile at ' + new Date()); callback(); }) });
|
||||||
|
|
||||||
webpackConfig.entry.openmct = [
|
webpackConfig.entry.openmct = [
|
||||||
'webpack-hot-middleware/client?reload=true',
|
'webpack-hot-middleware/client',
|
||||||
webpackConfig.entry.openmct
|
webpackConfig.entry.openmct
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ define([
|
|||||||
{
|
{
|
||||||
"key": "eventGenerator",
|
"key": "eventGenerator",
|
||||||
"name": "Event Message Generator",
|
"name": "Event Message Generator",
|
||||||
"cssClass": "icon-generator-events",
|
"cssClass": "icon-folder-new",
|
||||||
"description": "For development use. Creates sample event message data that mimics a live data stream.",
|
"description": "For development use. Creates sample event message data that mimics a live data stream.",
|
||||||
"priority": 10,
|
"priority": 10,
|
||||||
"features": "creation",
|
"features": "creation",
|
||||||
|
@ -38,7 +38,7 @@ define([
|
|||||||
openmct.types.addType("example.state-generator", {
|
openmct.types.addType("example.state-generator", {
|
||||||
name: "State Generator",
|
name: "State Generator",
|
||||||
description: "For development use. Generates test enumerated telemetry by cycling through a given set of states",
|
description: "For development use. Generates test enumerated telemetry by cycling through a given set of states",
|
||||||
cssClass: "icon-generator-telemetry",
|
cssClass: "icon-telemetry",
|
||||||
creatable: true,
|
creatable: true,
|
||||||
form: [
|
form: [
|
||||||
{
|
{
|
||||||
@ -66,7 +66,7 @@ define([
|
|||||||
openmct.types.addType("generator", {
|
openmct.types.addType("generator", {
|
||||||
name: "Sine Wave Generator",
|
name: "Sine Wave Generator",
|
||||||
description: "For development use. Generates example streaming telemetry data using a simple sine wave algorithm.",
|
description: "For development use. Generates example streaming telemetry data using a simple sine wave algorithm.",
|
||||||
cssClass: "icon-generator-telemetry",
|
cssClass: "icon-telemetry",
|
||||||
creatable: true,
|
creatable: true,
|
||||||
form: [
|
form: [
|
||||||
{
|
{
|
||||||
|
@ -79,34 +79,30 @@ define(
|
|||||||
* periodically, tracking an ongoing process.
|
* periodically, tracking an ongoing process.
|
||||||
*/
|
*/
|
||||||
$scope.newProgress = function () {
|
$scope.newProgress = function () {
|
||||||
let progress = 0;
|
|
||||||
var notificationModel = {
|
var notificationModel = {
|
||||||
title: "Progress notification example",
|
title: "Progress notification example",
|
||||||
severity: "info",
|
severity: "info",
|
||||||
progress: progress,
|
progress: 0,
|
||||||
actionText: getExampleActionText()
|
actionText: getExampleActionText()
|
||||||
};
|
};
|
||||||
let notification;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simulate an ongoing process and update the progress bar.
|
* Simulate an ongoing process and update the progress bar.
|
||||||
* @param notification
|
* @param notification
|
||||||
*/
|
*/
|
||||||
function incrementProgress() {
|
function incrementProgress() {
|
||||||
progress = Math.min(100, Math.floor(progress + Math.random() * 30))
|
notificationModel.progress = Math.min(100, Math.floor(notificationModel.progress + Math.random() * 30));
|
||||||
let progressText = ["Estimated time" +
|
notificationModel.progressText = ["Estimated time" +
|
||||||
" remaining:" +
|
" remaining:" +
|
||||||
" about ", 60 - Math.floor((progress / 100) * 60), " seconds"].join(" ");
|
" about ", 60 - Math.floor((notificationModel.progress / 100) * 60), " seconds"].join(" ");
|
||||||
notification.progress(progress, progressText);
|
if (notificationModel.progress < 100) {
|
||||||
|
|
||||||
if (progress < 100) {
|
|
||||||
$timeout(function () {
|
$timeout(function () {
|
||||||
incrementProgress(notificationModel);
|
incrementProgress(notificationModel);
|
||||||
}, 1000);
|
}, 1000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
notification = notificationService.notify(notificationModel);
|
notificationService.notify(notificationModel);
|
||||||
incrementProgress();
|
incrementProgress();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
201
index.html
201
index.html
@ -49,7 +49,6 @@
|
|||||||
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.ImportExport());
|
||||||
openmct.install(openmct.plugins.FixedView());
|
|
||||||
openmct.install(openmct.plugins.AutoflowView({
|
openmct.install(openmct.plugins.AutoflowView({
|
||||||
type: "telemetry.panel"
|
type: "telemetry.panel"
|
||||||
}));
|
}));
|
||||||
@ -77,208 +76,8 @@
|
|||||||
openmct.install(openmct.plugins.SummaryWidget());
|
openmct.install(openmct.plugins.SummaryWidget());
|
||||||
openmct.install(openmct.plugins.Notebook());
|
openmct.install(openmct.plugins.Notebook());
|
||||||
openmct.install(openmct.plugins.FolderView());
|
openmct.install(openmct.plugins.FolderView());
|
||||||
openmct.install(openmct.plugins.Tabs());
|
|
||||||
openmct.install(openmct.plugins.FlexibleLayout());
|
|
||||||
openmct.time.clock('local', {start: -THIRTY_MINUTES, end: 0});
|
openmct.time.clock('local', {start: -THIRTY_MINUTES, end: 0});
|
||||||
openmct.time.timeSystem('utc');
|
openmct.time.timeSystem('utc');
|
||||||
openmct.start();
|
openmct.start();
|
||||||
|
|
||||||
// openmct.toolbars.addProvider({
|
|
||||||
// name: "Testing Toolbar",
|
|
||||||
// key: "testing",
|
|
||||||
// description: "a mock toolbar that exercises all controls",
|
|
||||||
// forSelection: function (selection) {
|
|
||||||
// return true; // always applies.
|
|
||||||
// },
|
|
||||||
// toolbar: function (selection) {
|
|
||||||
// return [
|
|
||||||
// {
|
|
||||||
// control: 'menu',
|
|
||||||
// icon: 'icon-plus',
|
|
||||||
// label: 'Add',
|
|
||||||
// options: [
|
|
||||||
// { name: 'Box', class: 'icon-box', title: 'Add Box' },
|
|
||||||
// { name: 'Line', class: 'icon-line-horz', title: 'Add Line' },
|
|
||||||
// { name: 'Text', class: 'icon-font', title: 'Add Text' },
|
|
||||||
// { name: 'Image', class: 'icon-image', title: 'Add Image' }
|
|
||||||
// ]
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// control: 'separator'
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// control: 'color-picker',
|
|
||||||
// icon: 'icon-paint-bucket',
|
|
||||||
// value: '#33ff00',
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// control: 'color-picker',
|
|
||||||
// icon: 'icon-pencil',
|
|
||||||
// value: '#ffffff',
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// control: 'color-picker',
|
|
||||||
// icon: 'icon-font',
|
|
||||||
// value: '#333333',
|
|
||||||
// },
|
|
||||||
//
|
|
||||||
// {
|
|
||||||
// control: 'separator'
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// control: 'select-menu',
|
|
||||||
// value: 11,
|
|
||||||
// options: [
|
|
||||||
// { value: 9, name: '9 px' },
|
|
||||||
// { value: 10, name: '10 px' },
|
|
||||||
// { value: 11, name: '11 px' },
|
|
||||||
// { value: 12, name: '12 px' },
|
|
||||||
// { value: 13, name: '13 px' },
|
|
||||||
// { value: 14, name: '14 px' },
|
|
||||||
// { value: 16, name: '16 px' },
|
|
||||||
// { value: 18, name: '18 px' },
|
|
||||||
// { value: 20, name: '20 px' },
|
|
||||||
// { value: 24, name: '24 px' },
|
|
||||||
// { value: 28, name: '28 px' },
|
|
||||||
// { value: 32, name: '32 px' },
|
|
||||||
// { value: 40, name: '40 px' },
|
|
||||||
// { value: 48, name: '48 px' },
|
|
||||||
// { value: 56, name: '56 px' },
|
|
||||||
// { value: 64, name: '64 px' },
|
|
||||||
// { value: 72, name: '72 px' },
|
|
||||||
// { value: 80, name: '80 px' },
|
|
||||||
// { value: 88, name: '88 px' },
|
|
||||||
// { value: 96, name: '96 px' },
|
|
||||||
// { value: 128, name: '128 px' },
|
|
||||||
// { value: 160, name: '160 px' }
|
|
||||||
// ]
|
|
||||||
// },
|
|
||||||
//
|
|
||||||
// {
|
|
||||||
// control: 'separator'
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// control: 'menu',
|
|
||||||
// icon: 'icon-layers',
|
|
||||||
// options: [
|
|
||||||
// { name: 'Move to top', class: 'icon-arrow-double-up', title: 'Move to top' },
|
|
||||||
// { name: 'Move up', class: 'icon-arrow-up', title: 'Move up' },
|
|
||||||
// { name: 'Move down', class: 'icon-arrow-down', title: 'Move down' },
|
|
||||||
// { name: 'Move to bottom', class: 'icon-arrow-double-down', title: 'Move to bottom' }
|
|
||||||
// ]
|
|
||||||
// },
|
|
||||||
//
|
|
||||||
// {
|
|
||||||
// control: 'separator'
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// control: 'button',
|
|
||||||
// icon: 'icon-gear'
|
|
||||||
// },
|
|
||||||
//
|
|
||||||
// {
|
|
||||||
// control: 'separator'
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// control: 'input',
|
|
||||||
// type: 'number',
|
|
||||||
// label: 'X',
|
|
||||||
// value: 1,
|
|
||||||
// title: 'X position'
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// control: 'input',
|
|
||||||
// type: 'number',
|
|
||||||
// label: 'Y',
|
|
||||||
// value: 2,
|
|
||||||
// title: 'Y position'
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// control: 'input',
|
|
||||||
// type: 'number',
|
|
||||||
// label: 'W',
|
|
||||||
// value: 3,
|
|
||||||
// title: 'Width'
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// control: 'input',
|
|
||||||
// type: 'number',
|
|
||||||
// label: 'H',
|
|
||||||
// value: 4,
|
|
||||||
// title: 'Height'
|
|
||||||
// },
|
|
||||||
//
|
|
||||||
// {
|
|
||||||
// control: 'separator'
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// control: 'button',
|
|
||||||
// icon: 'icon-trash',
|
|
||||||
// label: 'delete',
|
|
||||||
// modifier: 'caution'
|
|
||||||
// },
|
|
||||||
//
|
|
||||||
// {
|
|
||||||
// control: 'separator'
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// control: 'checkbox',
|
|
||||||
// name: 'this is a checkbox',
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// control: 'separator'
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// control: 'toggle-button',
|
|
||||||
// title: 'Toggle Frame',
|
|
||||||
// property: 'hideFrame',
|
|
||||||
// value: false,
|
|
||||||
// options: [
|
|
||||||
// {
|
|
||||||
// value: true,
|
|
||||||
// icon: 'icon-frame-hide'
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// value: false,
|
|
||||||
// icon: 'icon-frame-show'
|
|
||||||
// }
|
|
||||||
// ]
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// control: 'toggle-button',
|
|
||||||
// title: 'Snap to grid',
|
|
||||||
// property: 'snapToGrid',
|
|
||||||
// value: true,
|
|
||||||
// options: [
|
|
||||||
// {
|
|
||||||
// value: true,
|
|
||||||
// icon: 'icon-grid-snap-to'
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// value: false,
|
|
||||||
// icon: 'icon-grid-snap-no'
|
|
||||||
// }
|
|
||||||
// ]
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// control: 'toggle-button',
|
|
||||||
// title: 'Toggle label',
|
|
||||||
// property: 'showLabel',
|
|
||||||
// value: true,
|
|
||||||
// options: [
|
|
||||||
// {
|
|
||||||
// value: true,
|
|
||||||
// icon: 'icon-two-parts-both'
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// value: false,
|
|
||||||
// icon: 'icon-two-parts-one-only'
|
|
||||||
// }
|
|
||||||
// ]
|
|
||||||
// }
|
|
||||||
// ];
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
</html>
|
</html>
|
||||||
|
@ -2,14 +2,31 @@
|
|||||||
ng-class="'message-severity-' + ngModel.severity">
|
ng-class="'message-severity-' + ngModel.severity">
|
||||||
<div class="w-message-contents">
|
<div class="w-message-contents">
|
||||||
<div class="top-bar">
|
<div class="top-bar">
|
||||||
<div class="title">{{ngModel.message}}</div>
|
<div class="title">{{ngModel.title}}</div>
|
||||||
|
</div>
|
||||||
|
<div class="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.progressPerc !== undefined"></mct-include>
|
ng-show="ngModel.progress !== undefined || ngModel.unknownProgress"></mct-include>
|
||||||
</div>
|
</div>
|
||||||
<div class="bottom-bar">
|
<div class="bottom-bar">
|
||||||
|
<a ng-repeat="dialogOption in ngModel.options"
|
||||||
|
class="s-button"
|
||||||
|
ng-click="dialogOption.callback()">
|
||||||
|
{{dialogOption.label}}
|
||||||
|
</a>
|
||||||
|
<a class="s-button major"
|
||||||
|
ng-if="ngModel.primaryOption"
|
||||||
|
ng-click="ngModel.primaryOption.callback()">
|
||||||
|
{{ngModel.primaryOption.label}}
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
define([
|
define([
|
||||||
"./src/controllers/EditActionController",
|
"./src/controllers/EditActionController",
|
||||||
"./src/controllers/EditPanesController",
|
"./src/controllers/EditPanesController",
|
||||||
|
"./src/controllers/ElementsController",
|
||||||
"./src/controllers/EditObjectController",
|
"./src/controllers/EditObjectController",
|
||||||
"./src/actions/EditAndComposeAction",
|
"./src/actions/EditAndComposeAction",
|
||||||
"./src/actions/EditAction",
|
"./src/actions/EditAction",
|
||||||
@ -46,6 +47,7 @@ define([
|
|||||||
"./src/creation/LocatorController",
|
"./src/creation/LocatorController",
|
||||||
"./src/creation/CreationPolicy",
|
"./src/creation/CreationPolicy",
|
||||||
"./src/creation/CreateActionProvider",
|
"./src/creation/CreateActionProvider",
|
||||||
|
"./src/creation/AddActionProvider",
|
||||||
"./src/creation/CreationService",
|
"./src/creation/CreationService",
|
||||||
"./res/templates/create/locator.html",
|
"./res/templates/create/locator.html",
|
||||||
"./res/templates/create/create-button.html",
|
"./res/templates/create/create-button.html",
|
||||||
@ -53,11 +55,13 @@ define([
|
|||||||
"./res/templates/library.html",
|
"./res/templates/library.html",
|
||||||
"./res/templates/edit-object.html",
|
"./res/templates/edit-object.html",
|
||||||
"./res/templates/edit-action-buttons.html",
|
"./res/templates/edit-action-buttons.html",
|
||||||
|
"./res/templates/elements.html",
|
||||||
"./res/templates/topbar-edit.html",
|
"./res/templates/topbar-edit.html",
|
||||||
'legacyRegistry'
|
'legacyRegistry'
|
||||||
], function (
|
], function (
|
||||||
EditActionController,
|
EditActionController,
|
||||||
EditPanesController,
|
EditPanesController,
|
||||||
|
ElementsController,
|
||||||
EditObjectController,
|
EditObjectController,
|
||||||
EditAndComposeAction,
|
EditAndComposeAction,
|
||||||
EditAction,
|
EditAction,
|
||||||
@ -81,6 +85,7 @@ define([
|
|||||||
LocatorController,
|
LocatorController,
|
||||||
CreationPolicy,
|
CreationPolicy,
|
||||||
CreateActionProvider,
|
CreateActionProvider,
|
||||||
|
AddActionProvider,
|
||||||
CreationService,
|
CreationService,
|
||||||
locatorTemplate,
|
locatorTemplate,
|
||||||
createButtonTemplate,
|
createButtonTemplate,
|
||||||
@ -88,6 +93,7 @@ define([
|
|||||||
libraryTemplate,
|
libraryTemplate,
|
||||||
editObjectTemplate,
|
editObjectTemplate,
|
||||||
editActionButtonsTemplate,
|
editActionButtonsTemplate,
|
||||||
|
elementsTemplate,
|
||||||
topbarEditTemplate,
|
topbarEditTemplate,
|
||||||
legacyRegistry
|
legacyRegistry
|
||||||
) {
|
) {
|
||||||
@ -109,6 +115,14 @@ define([
|
|||||||
"$scope"
|
"$scope"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"key": "ElementsController",
|
||||||
|
"implementation": ElementsController,
|
||||||
|
"depends": [
|
||||||
|
"$scope",
|
||||||
|
"openmct"
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"key": "EditObjectController",
|
"key": "EditObjectController",
|
||||||
"implementation": EditObjectController,
|
"implementation": EditObjectController,
|
||||||
@ -211,10 +225,10 @@ define([
|
|||||||
"description": "Save changes made to these objects.",
|
"description": "Save changes made to these objects.",
|
||||||
"depends": [
|
"depends": [
|
||||||
"$injector",
|
"$injector",
|
||||||
|
"policyService",
|
||||||
"dialogService",
|
"dialogService",
|
||||||
"copyService",
|
"copyService",
|
||||||
"notificationService",
|
"notificationService"
|
||||||
"openmct"
|
|
||||||
],
|
],
|
||||||
"priority": "mandatory"
|
"priority": "mandatory"
|
||||||
},
|
},
|
||||||
@ -282,6 +296,13 @@ define([
|
|||||||
"action"
|
"action"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"key": "edit-elements",
|
||||||
|
"template": elementsTemplate,
|
||||||
|
"gestures": [
|
||||||
|
"drop"
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"key": "topbar-edit",
|
"key": "topbar-edit",
|
||||||
"template": topbarEditTemplate
|
"template": topbarEditTemplate
|
||||||
@ -298,6 +319,12 @@ define([
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"templates": [
|
||||||
|
{
|
||||||
|
key: "elementsPool",
|
||||||
|
template: elementsTemplate
|
||||||
|
}
|
||||||
|
],
|
||||||
"components": [
|
"components": [
|
||||||
{
|
{
|
||||||
"type": "decorator",
|
"type": "decorator",
|
||||||
@ -329,6 +356,18 @@ define([
|
|||||||
"policyService"
|
"policyService"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"key": "AddActionProvider",
|
||||||
|
"provides": "actionService",
|
||||||
|
"type": "provider",
|
||||||
|
"implementation": AddActionProvider,
|
||||||
|
"depends": [
|
||||||
|
"$q",
|
||||||
|
"typeService",
|
||||||
|
"dialogService",
|
||||||
|
"policyService"
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"key": "CreationService",
|
"key": "CreationService",
|
||||||
"provides": "creationService",
|
"provides": "creationService",
|
||||||
|
49
platform/commonUI/edit/res/templates/elements.html
Normal file
49
platform/commonUI/edit/res/templates/elements.html
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
<!--
|
||||||
|
Open MCT, Copyright (c) 2014-2018, United States Government
|
||||||
|
as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
Administration. All rights reserved.
|
||||||
|
|
||||||
|
Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||||
|
"License"); you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
License for the specific language governing permissions and limitations
|
||||||
|
under the License.
|
||||||
|
|
||||||
|
Open MCT includes source code licensed under additional open source
|
||||||
|
licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
this source code distribution or the Licensing information page available
|
||||||
|
at runtime from the About dialog for additional information.
|
||||||
|
-->
|
||||||
|
<div ng-controller="ElementsController" class="flex-elem l-flex-col holder grows">
|
||||||
|
<mct-include key="'input-filter'"
|
||||||
|
class="flex-elem holder"
|
||||||
|
ng-model="filterBy">
|
||||||
|
</mct-include>
|
||||||
|
<div class="flex-elem grows vscroll scroll-pad">
|
||||||
|
<ul class="tree" id="inspector-elements-tree"
|
||||||
|
ng-if="composition.length > 0">
|
||||||
|
<li ng-repeat="containedObject in composition | filter:searchElements">
|
||||||
|
<span class="tree-item">
|
||||||
|
<span class="grippy-sm"
|
||||||
|
ng-if="composition.length > 1"
|
||||||
|
data-id="{{ containedObject.id }}"
|
||||||
|
mct-drag-down="dragDown($event)"
|
||||||
|
mct-drag="drag($event)"
|
||||||
|
mct-drag-up="dragUp($event)">
|
||||||
|
</span>
|
||||||
|
<mct-representation
|
||||||
|
class="rep-object-label"
|
||||||
|
key="'label'"
|
||||||
|
mct-object="containedObject">
|
||||||
|
</mct-representation>
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<div ng-if="composition.length === 0">No contained elements</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -69,8 +69,8 @@ define([], function () {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
setTimeout(() => this.removeCallback(domainObject));
|
|
||||||
|
|
||||||
|
dialog = this.dialogService.showBlockingMessage(model);
|
||||||
};
|
};
|
||||||
|
|
||||||
return RemoveDialog;
|
return RemoveDialog;
|
||||||
|
@ -40,20 +40,20 @@ function (
|
|||||||
*/
|
*/
|
||||||
function SaveAsAction(
|
function SaveAsAction(
|
||||||
$injector,
|
$injector,
|
||||||
|
policyService,
|
||||||
dialogService,
|
dialogService,
|
||||||
copyService,
|
copyService,
|
||||||
notificationService,
|
notificationService,
|
||||||
openmct,
|
|
||||||
context
|
context
|
||||||
) {
|
) {
|
||||||
this.domainObject = (context || {}).domainObject;
|
this.domainObject = (context || {}).domainObject;
|
||||||
this.injectObjectService = function () {
|
this.injectObjectService = function () {
|
||||||
this.objectService = $injector.get("objectService");
|
this.objectService = $injector.get("objectService");
|
||||||
};
|
};
|
||||||
|
this.policyService = policyService;
|
||||||
this.dialogService = dialogService;
|
this.dialogService = dialogService;
|
||||||
this.copyService = copyService;
|
this.copyService = copyService;
|
||||||
this.notificationService = notificationService;
|
this.notificationService = notificationService;
|
||||||
this.openmct = openmct;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -63,7 +63,7 @@ function (
|
|||||||
return new CreateWizard(
|
return new CreateWizard(
|
||||||
this.domainObject,
|
this.domainObject,
|
||||||
parent,
|
parent,
|
||||||
this.openmct
|
this.policyService
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -51,11 +51,8 @@ define(
|
|||||||
*/
|
*/
|
||||||
EditorCapability.prototype.edit = function () {
|
EditorCapability.prototype.edit = function () {
|
||||||
console.warn('DEPRECATED: cannot edit via edit capability, use openmct.editor instead.');
|
console.warn('DEPRECATED: cannot edit via edit capability, use openmct.editor instead.');
|
||||||
|
|
||||||
if (!this.openmct.editor.isEditing()) {
|
|
||||||
this.openmct.editor.edit();
|
this.openmct.editor.edit();
|
||||||
this.domainObject.getCapability('status').set('editing', true);
|
this.domainObject.getCapability('status').set('editing', true);
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -85,7 +82,6 @@ define(
|
|||||||
*/
|
*/
|
||||||
EditorCapability.prototype.save = function () {
|
EditorCapability.prototype.save = function () {
|
||||||
console.warn('DEPRECATED: cannot save via edit capability, use openmct.editor instead.');
|
console.warn('DEPRECATED: cannot save via edit capability, use openmct.editor instead.');
|
||||||
return Promise.resolve();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
EditorCapability.prototype.invoke = EditorCapability.prototype.edit;
|
EditorCapability.prototype.invoke = EditorCapability.prototype.edit;
|
||||||
@ -97,7 +93,6 @@ define(
|
|||||||
*/
|
*/
|
||||||
EditorCapability.prototype.finish = function () {
|
EditorCapability.prototype.finish = function () {
|
||||||
console.warn('DEPRECATED: cannot finish via edit capability, use openmct.editor instead.');
|
console.warn('DEPRECATED: cannot finish via edit capability, use openmct.editor instead.');
|
||||||
return Promise.resolve();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
197
platform/commonUI/edit/src/controllers/ElementsController.js
Normal file
197
platform/commonUI/edit/src/controllers/ElementsController.js
Normal file
@ -0,0 +1,197 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2014-2018, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
define(
|
||||||
|
['zepto'],
|
||||||
|
function ($) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The ElementsController prepares the elements view for display
|
||||||
|
*
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function ElementsController($scope, openmct) {
|
||||||
|
this.scope = $scope;
|
||||||
|
this.scope.composition = [];
|
||||||
|
this.openmct = openmct;
|
||||||
|
this.dragDown = this.dragDown.bind(this);
|
||||||
|
this.dragUp = this.dragUp.bind(this);
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
function filterBy(text) {
|
||||||
|
if (typeof text === 'undefined') {
|
||||||
|
return $scope.searchText;
|
||||||
|
} else {
|
||||||
|
$scope.searchText = text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function searchElements(value) {
|
||||||
|
if ($scope.searchText) {
|
||||||
|
return value.getModel().name.toLowerCase().search(
|
||||||
|
$scope.searchText.toLowerCase()) !== -1;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setSelection(selection) {
|
||||||
|
if (!selection[0]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self.mutationListener) {
|
||||||
|
self.mutationListener();
|
||||||
|
delete self.mutationListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
var domainObject = selection[0].context.oldItem;
|
||||||
|
self.refreshComposition(domainObject);
|
||||||
|
|
||||||
|
if (domainObject) {
|
||||||
|
|
||||||
|
self.mutationListener = domainObject.getCapability('mutation')
|
||||||
|
.listen(self.refreshComposition.bind(self, domainObject));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.filterBy = filterBy;
|
||||||
|
$scope.searchElements = searchElements;
|
||||||
|
|
||||||
|
openmct.selection.on('change', setSelection);
|
||||||
|
setSelection(openmct.selection.get());
|
||||||
|
|
||||||
|
$scope.dragDown = this.dragDown;
|
||||||
|
$scope.drag = this.drag;
|
||||||
|
$scope.dragUp = this.dragUp;
|
||||||
|
|
||||||
|
$scope.$on("$destroy", function () {
|
||||||
|
openmct.selection.off("change", setSelection);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoked on DragStart - Adds reordering class to parent UL element
|
||||||
|
* Sets selected object ID, to be used on Drag End
|
||||||
|
*
|
||||||
|
* @param {object} event | Mouse Event
|
||||||
|
*/
|
||||||
|
ElementsController.prototype.dragDown = function (event) {
|
||||||
|
if (!this.parentUL) {
|
||||||
|
this.parentUL = $(document).find('#inspector-elements-tree');
|
||||||
|
}
|
||||||
|
|
||||||
|
this.selectedTreeItem = $(event.target).parent();
|
||||||
|
this.selectedObjectId = event.target.getAttribute('data-id');
|
||||||
|
|
||||||
|
this.parentUL.addClass('reordering');
|
||||||
|
this.selectedTreeItem.addClass('reorder-actor');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoked on dragEnd - Removes selected object from position in composition
|
||||||
|
* and replaces it at the target position. Composition is then updated with current
|
||||||
|
* scope
|
||||||
|
*
|
||||||
|
* @param {object} event - Mouse Event
|
||||||
|
*/
|
||||||
|
ElementsController.prototype.dragUp = function (event) {
|
||||||
|
this.targetObjectId = event.target.getAttribute('data-id');
|
||||||
|
|
||||||
|
if (this.targetObjectId && this.selectedObjectId) {
|
||||||
|
var selectedObjectPosition,
|
||||||
|
targetObjectPosition;
|
||||||
|
|
||||||
|
selectedObjectPosition = findObjectInCompositionFromId(this.selectedObjectId, this.scope.composition);
|
||||||
|
targetObjectPosition = findObjectInCompositionFromId(this.targetObjectId, this.scope.composition);
|
||||||
|
|
||||||
|
if ((selectedObjectPosition !== -1) && (targetObjectPosition !== -1)) {
|
||||||
|
var selectedObject = this.scope.composition.splice(selectedObjectPosition, 1),
|
||||||
|
selection = this.openmct.selection.get(),
|
||||||
|
domainObject = selection ? selection[0].context.oldItem : undefined;
|
||||||
|
|
||||||
|
this.scope.composition.splice(targetObjectPosition, 0, selectedObject[0]);
|
||||||
|
|
||||||
|
if (domainObject) {
|
||||||
|
domainObject.getCapability('mutation').mutate(function (model) {
|
||||||
|
model.composition = this.scope.composition.map(function (dObject) {
|
||||||
|
return dObject.id;
|
||||||
|
});
|
||||||
|
}.bind(this));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.parentUL) {
|
||||||
|
this.parentUL.removeClass('reordering');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.selectedTreeItem) {
|
||||||
|
this.selectedTreeItem.removeClass('reorder-actor');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ElementsController.prototype.drag = function (event) {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the composition for the selected object and populates the scope with it.
|
||||||
|
*
|
||||||
|
* @param domainObject the selected object
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
ElementsController.prototype.refreshComposition = function (domainObject) {
|
||||||
|
var refreshTracker = {};
|
||||||
|
this.currentRefresh = refreshTracker;
|
||||||
|
|
||||||
|
var selectedObjectComposition = domainObject && domainObject.useCapability('composition');
|
||||||
|
if (selectedObjectComposition) {
|
||||||
|
selectedObjectComposition.then(function (composition) {
|
||||||
|
if (this.currentRefresh === refreshTracker) {
|
||||||
|
this.scope.composition = composition;
|
||||||
|
}
|
||||||
|
}.bind(this));
|
||||||
|
} else {
|
||||||
|
this.scope.composition = [];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds position of object with given ID in Composition
|
||||||
|
*
|
||||||
|
* @param {String} id
|
||||||
|
* @param {Array} composition
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
function findObjectInCompositionFromId(id, composition) {
|
||||||
|
var mapped = composition.map(function (element) {
|
||||||
|
return element.id;
|
||||||
|
});
|
||||||
|
|
||||||
|
return mapped.indexOf(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ElementsController;
|
||||||
|
}
|
||||||
|
);
|
133
platform/commonUI/edit/src/creation/AddAction.js
Normal file
133
platform/commonUI/edit/src/creation/AddAction.js
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2014-2018, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module defining AddAction. Created by ahenry on 01/21/16.
|
||||||
|
*/
|
||||||
|
define(
|
||||||
|
[
|
||||||
|
'./CreateWizard'
|
||||||
|
],
|
||||||
|
function (CreateWizard) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Add Action is performed to create new instances of
|
||||||
|
* domain objects of a specific type that are subobjects of an
|
||||||
|
* object being edited. This is the action that is performed when a
|
||||||
|
* user uses the Add menu option.
|
||||||
|
*
|
||||||
|
* @memberof platform/commonUI/browse
|
||||||
|
* @implements {Action}
|
||||||
|
* @constructor
|
||||||
|
*
|
||||||
|
* @param {Type} type the type of domain object to create
|
||||||
|
* @param {DomainObject} parent the domain object that should
|
||||||
|
* act as a container for the newly-created object
|
||||||
|
* (note that the user will have an opportunity to
|
||||||
|
* override this)
|
||||||
|
* @param {ActionContext} context the context in which the
|
||||||
|
* action is being performed
|
||||||
|
* @param {DialogService} dialogService
|
||||||
|
*/
|
||||||
|
function AddAction(type, parent, context, $q, dialogService, policyService) {
|
||||||
|
this.metadata = {
|
||||||
|
key: 'add',
|
||||||
|
cssClass: type.getCssClass(),
|
||||||
|
name: type.getName(),
|
||||||
|
type: type.getKey(),
|
||||||
|
description: type.getDescription(),
|
||||||
|
context: context
|
||||||
|
};
|
||||||
|
|
||||||
|
this.type = type;
|
||||||
|
this.parent = parent;
|
||||||
|
this.$q = $q;
|
||||||
|
this.dialogService = dialogService;
|
||||||
|
this.policyService = policyService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Create a new object of the given type.
|
||||||
|
* This will prompt for user input first.
|
||||||
|
*
|
||||||
|
* @returns {Promise} that will be resolved with the object that the
|
||||||
|
* action was originally invoked on (ie. the 'parent')
|
||||||
|
*/
|
||||||
|
AddAction.prototype.perform = function () {
|
||||||
|
var newModel = this.type.getInitialModel(),
|
||||||
|
newObject,
|
||||||
|
parentObject = this.parent,
|
||||||
|
wizard;
|
||||||
|
|
||||||
|
newModel.type = this.type.getKey();
|
||||||
|
newObject = parentObject.getCapability('instantiation').instantiate(newModel);
|
||||||
|
newObject.useCapability('mutation', function (model) {
|
||||||
|
model.location = parentObject.getId();
|
||||||
|
});
|
||||||
|
|
||||||
|
wizard = new CreateWizard(newObject, this.parent, this.policyService);
|
||||||
|
|
||||||
|
function populateObjectFromInput(formValue) {
|
||||||
|
return wizard.populateObjectFromInput(formValue, newObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
function persistAndReturn(domainObject) {
|
||||||
|
return domainObject.getCapability('persistence')
|
||||||
|
.persist()
|
||||||
|
.then(function () {
|
||||||
|
return domainObject;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function addToParent(populatedObject) {
|
||||||
|
parentObject.getCapability('composition').add(populatedObject);
|
||||||
|
return persistAndReturn(parentObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.dialogService
|
||||||
|
.getUserInput(wizard.getFormStructure(false), wizard.getInitialFormValue())
|
||||||
|
.then(populateObjectFromInput)
|
||||||
|
.then(persistAndReturn)
|
||||||
|
.then(addToParent);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Metadata associated with a Add action.
|
||||||
|
* @typedef {ActionMetadata} AddActionMetadata
|
||||||
|
* @property {string} type the key for the type of domain object
|
||||||
|
* to be created
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get metadata about this action.
|
||||||
|
* @returns {AddActionMetadata} metadata about this action
|
||||||
|
*/
|
||||||
|
AddAction.prototype.getMetadata = function () {
|
||||||
|
return this.metadata;
|
||||||
|
};
|
||||||
|
|
||||||
|
return AddAction;
|
||||||
|
}
|
||||||
|
);
|
82
platform/commonUI/edit/src/creation/AddActionProvider.js
Normal file
82
platform/commonUI/edit/src/creation/AddActionProvider.js
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2014-2018, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module defining AddActionProvider.js. Created by ahenry on 01/21/16.
|
||||||
|
*/
|
||||||
|
define(
|
||||||
|
["./AddAction"],
|
||||||
|
function (AddAction) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The AddActionProvider is an ActionProvider which introduces
|
||||||
|
* an Add action for creating sub objects.
|
||||||
|
*
|
||||||
|
* @memberof platform/commonUI/browse
|
||||||
|
* @constructor
|
||||||
|
* @implements {ActionService}
|
||||||
|
*
|
||||||
|
* @param {TypeService} typeService the type service, used to discover
|
||||||
|
* available types
|
||||||
|
* @param {DialogService} dialogService the dialog service, used by
|
||||||
|
* specific Create actions to get user input to populate the
|
||||||
|
* model of the newly-created domain object.
|
||||||
|
* @param {CreationService} creationService the creation service (also
|
||||||
|
* introduced in this bundle), responsible for handling actual
|
||||||
|
* object creation.
|
||||||
|
*/
|
||||||
|
function AddActionProvider($q, typeService, dialogService, policyService) {
|
||||||
|
this.typeService = typeService;
|
||||||
|
this.dialogService = dialogService;
|
||||||
|
this.$q = $q;
|
||||||
|
this.policyService = policyService;
|
||||||
|
}
|
||||||
|
|
||||||
|
AddActionProvider.prototype.getActions = function (actionContext) {
|
||||||
|
var context = actionContext || {},
|
||||||
|
key = context.key,
|
||||||
|
destination = context.domainObject;
|
||||||
|
|
||||||
|
// We only provide Add actions, and we need a
|
||||||
|
// domain object to serve as the container for the
|
||||||
|
// newly-created object (although the user may later
|
||||||
|
// make a different selection)
|
||||||
|
if (key !== 'add' || !destination) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Introduce one create action per type
|
||||||
|
return ['timeline', 'activity'].map(function (type) {
|
||||||
|
return new AddAction(
|
||||||
|
this.typeService.getType(type),
|
||||||
|
destination,
|
||||||
|
context,
|
||||||
|
this.$q,
|
||||||
|
this.dialogService,
|
||||||
|
this.policyService
|
||||||
|
);
|
||||||
|
}, this);
|
||||||
|
};
|
||||||
|
|
||||||
|
return AddActionProvider;
|
||||||
|
}
|
||||||
|
);
|
@ -44,7 +44,7 @@ define(
|
|||||||
* @param {ActionContext} context the context in which the
|
* @param {ActionContext} context the context in which the
|
||||||
* action is being performed
|
* action is being performed
|
||||||
*/
|
*/
|
||||||
function CreateAction(type, parent, context, openmct) {
|
function CreateAction(type, parent, context) {
|
||||||
this.metadata = {
|
this.metadata = {
|
||||||
key: 'create',
|
key: 'create',
|
||||||
cssClass: type.getCssClass(),
|
cssClass: type.getCssClass(),
|
||||||
@ -55,7 +55,6 @@ define(
|
|||||||
};
|
};
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
this.openmct = openmct;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -64,28 +63,37 @@ define(
|
|||||||
*/
|
*/
|
||||||
CreateAction.prototype.perform = function () {
|
CreateAction.prototype.perform = function () {
|
||||||
var newModel = this.type.getInitialModel(),
|
var newModel = this.type.getInitialModel(),
|
||||||
openmct = this.openmct,
|
|
||||||
newObject,
|
newObject,
|
||||||
editAction;
|
editAction,
|
||||||
|
editorCapability;
|
||||||
|
|
||||||
|
function closeEditor() {
|
||||||
|
return editorCapability.finish();
|
||||||
|
}
|
||||||
|
|
||||||
function onSave() {
|
function onSave() {
|
||||||
openmct.editor.save();
|
return editorCapability.save()
|
||||||
|
.then(closeEditor);
|
||||||
}
|
}
|
||||||
|
|
||||||
function onCancel() {
|
function onCancel() {
|
||||||
openmct.editor.cancel();
|
return closeEditor();
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
|
editorCapability = newObject.hasCapability('editor') && newObject.getCapability("editor");
|
||||||
|
|
||||||
openmct.editor.edit();
|
|
||||||
editAction = newObject.getCapability("action").getActions("edit")[0];
|
editAction = newObject.getCapability("action").getActions("edit")[0];
|
||||||
newObject.getCapability("action").perform("save-as").then(onSave, onCancel);
|
//If an edit action is available, perform it
|
||||||
// TODO: support editing object without saving object first.
|
if (editAction) {
|
||||||
// Which means we have to toggle createwizard afterwards. For now,
|
return editAction.perform();
|
||||||
// We will disable this.
|
} else if (editorCapability) {
|
||||||
|
//otherwise, use the save as action
|
||||||
|
editorCapability.edit();
|
||||||
|
return newObject.getCapability("action").perform("save-as").then(onSave, onCancel);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -34,13 +34,13 @@ define(
|
|||||||
* @memberof platform/commonUI/browse
|
* @memberof platform/commonUI/browse
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function CreateWizard(domainObject, parent, openmct) {
|
function CreateWizard(domainObject, parent, policyService) {
|
||||||
this.type = domainObject.getCapability('type');
|
this.type = domainObject.getCapability('type');
|
||||||
this.model = domainObject.getModel();
|
this.model = domainObject.getModel();
|
||||||
this.domainObject = domainObject;
|
this.domainObject = domainObject;
|
||||||
this.properties = this.type.getProperties();
|
this.properties = this.type.getProperties();
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
this.openmct = openmct;
|
this.policyService = policyService;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -56,10 +56,15 @@ define(
|
|||||||
*/
|
*/
|
||||||
CreateWizard.prototype.getFormStructure = function (includeLocation) {
|
CreateWizard.prototype.getFormStructure = function (includeLocation) {
|
||||||
var sections = [],
|
var sections = [],
|
||||||
domainObject = this.domainObject;
|
domainObject = this.domainObject,
|
||||||
|
policyService = this.policyService;
|
||||||
|
|
||||||
function validateLocation(parent) {
|
function validateLocation(parent) {
|
||||||
return parent && this.openmct.composition.checkPolicy(parent.useCapability('adapter'), domainObject.useCapability('adapter'));
|
return parent && policyService.allow(
|
||||||
|
"composition",
|
||||||
|
parent,
|
||||||
|
domainObject
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
sections.push({
|
sections.push({
|
||||||
@ -88,7 +93,7 @@ define(
|
|||||||
rows: [{
|
rows: [{
|
||||||
name: "Save In",
|
name: "Save In",
|
||||||
control: "locator",
|
control: "locator",
|
||||||
validate: validateLocation.bind(this),
|
validate: validateLocation,
|
||||||
key: "createParent"
|
key: "createParent"
|
||||||
}]
|
}]
|
||||||
});
|
});
|
||||||
|
@ -55,19 +55,16 @@ define(
|
|||||||
navigatedObject = this.navigationService.getNavigation(),
|
navigatedObject = this.navigationService.getNavigation(),
|
||||||
actionMetadata = action.getMetadata ? action.getMetadata() : {};
|
actionMetadata = action.getMetadata ? action.getMetadata() : {};
|
||||||
|
|
||||||
// FIXME: need to restore support for changing contextual actions
|
|
||||||
// based on edit mode.
|
|
||||||
// if (navigatedObject.hasCapability("editor") && navigatedObject.getCapability("editor").isEditContextRoot()) {
|
// if (navigatedObject.hasCapability("editor") && navigatedObject.getCapability("editor").isEditContextRoot()) {
|
||||||
// if (selectedObject.hasCapability("editor") && selectedObject.getCapability("editor").inEditContext()) {
|
if (selectedObject.hasCapability("editor") && selectedObject.getCapability("editor").inEditContext()) {
|
||||||
// return this.editModeBlacklist.indexOf(actionMetadata.key) === -1;
|
return this.editModeBlacklist.indexOf(actionMetadata.key) === -1;
|
||||||
// } else {
|
} else {
|
||||||
// //Target is in the context menu
|
//Target is in the context menu
|
||||||
// return this.nonEditContextBlacklist.indexOf(actionMetadata.key) === -1;
|
return this.nonEditContextBlacklist.indexOf(actionMetadata.key) === -1;
|
||||||
// }
|
}
|
||||||
// } else {
|
// } else {
|
||||||
// return true;
|
// return true;
|
||||||
// }
|
// }
|
||||||
return true;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return EditContextualActionPolicy;
|
return EditContextualActionPolicy;
|
||||||
|
254
platform/commonUI/edit/src/representers/EditToolbar.js
Normal file
254
platform/commonUI/edit/src/representers/EditToolbar.js
Normal file
@ -0,0 +1,254 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* 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/api/objects/object-utils',
|
||||||
|
'lodash'
|
||||||
|
],
|
||||||
|
function (
|
||||||
|
objectUtils,
|
||||||
|
_
|
||||||
|
) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides initial structure and state (as suitable for provision
|
||||||
|
* to the `mct-toolbar` directive) for a view's toolbar, based on
|
||||||
|
* that view's declaration of what belongs in its toolbar and on
|
||||||
|
* the current selection.
|
||||||
|
*
|
||||||
|
* @param $scope the Angular scope
|
||||||
|
* @param {Object} openmct the openmct object
|
||||||
|
* @param structure the toolbar structure
|
||||||
|
* @memberof platform/commonUI/edit
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function EditToolbar($scope, openmct, structure) {
|
||||||
|
this.toolbarStructure = [];
|
||||||
|
this.properties = [];
|
||||||
|
this.toolbarState = [];
|
||||||
|
this.openmct = openmct;
|
||||||
|
this.domainObjectsById = {};
|
||||||
|
this.unobserveObjects = [];
|
||||||
|
this.stateTracker = [];
|
||||||
|
|
||||||
|
$scope.$watchCollection(this.getState.bind(this), this.handleStateChanges.bind(this));
|
||||||
|
$scope.$on("$destroy", this.destroy.bind(this));
|
||||||
|
|
||||||
|
this.updateToolbar(structure);
|
||||||
|
this.registerListeners(structure);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the toolbar with a new structure.
|
||||||
|
*
|
||||||
|
* @param {Array} structure the toolbar structure
|
||||||
|
*/
|
||||||
|
EditToolbar.prototype.updateToolbar = function (structure) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
function addKey(item) {
|
||||||
|
self.stateTracker.push({
|
||||||
|
id: objectUtils.makeKeyString(item.domainObject.identifier),
|
||||||
|
domainObject: item.domainObject,
|
||||||
|
property: item.property
|
||||||
|
});
|
||||||
|
self.properties.push(item.property);
|
||||||
|
|
||||||
|
return self.properties.length - 1; // Return index of property
|
||||||
|
}
|
||||||
|
|
||||||
|
function convertItem(item) {
|
||||||
|
var converted = Object.create(item || {});
|
||||||
|
|
||||||
|
if (item.property) {
|
||||||
|
converted.key = addKey(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.method) {
|
||||||
|
converted.click = function (value) {
|
||||||
|
item.method(value);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return converted;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get initial value for a given property
|
||||||
|
function initializeState(property) {
|
||||||
|
var result;
|
||||||
|
structure.forEach(function (item) {
|
||||||
|
if (item.property === property) {
|
||||||
|
result = _.get(item.domainObject, item.property);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tracks the domain object and property for every element in the state array
|
||||||
|
this.stateTracker = [];
|
||||||
|
this.toolbarStructure = structure.map(convertItem);
|
||||||
|
this.toolbarState = this.properties.map(initializeState);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the structure of the toolbar, as appropriate to
|
||||||
|
* pass to `mct-toolbar`.
|
||||||
|
*
|
||||||
|
* @returns {Array} the toolbar structure
|
||||||
|
*/
|
||||||
|
EditToolbar.prototype.getStructure = function () {
|
||||||
|
return this.toolbarStructure;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the current state of the toolbar, as appropriate
|
||||||
|
* to two-way bind to the state handled by `mct-toolbar`.
|
||||||
|
*
|
||||||
|
* @returns {Array} state of the toolbar
|
||||||
|
*/
|
||||||
|
EditToolbar.prototype.getState = function () {
|
||||||
|
return this.toolbarState;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mutates the domain object's property with a new value.
|
||||||
|
*
|
||||||
|
* @param {Object} dominObject the domain object
|
||||||
|
* @param {string} property the domain object's property to update
|
||||||
|
* @param value the property's new value
|
||||||
|
*/
|
||||||
|
EditToolbar.prototype.updateDomainObject = function (domainObject, property, value) {
|
||||||
|
this.openmct.objects.mutate(domainObject, property, value);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates state with the new value.
|
||||||
|
*
|
||||||
|
* @param {number} index the index of the corresponding
|
||||||
|
* element in the state array
|
||||||
|
* @param value the new value to update the state array with
|
||||||
|
*/
|
||||||
|
EditToolbar.prototype.updateState = function (index, value) {
|
||||||
|
this.toolbarState[index] = value;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register listeners for domain objects to watch for updates.
|
||||||
|
*
|
||||||
|
* @param {Array} the toolbar structure
|
||||||
|
*/
|
||||||
|
EditToolbar.prototype.registerListeners = function (structure) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
function observeObject(domainObject, id) {
|
||||||
|
var unobserveObject = self.openmct.objects.observe(domainObject, '*', function (newObject) {
|
||||||
|
self.domainObjectsById[id].newObject = JSON.parse(JSON.stringify(newObject));
|
||||||
|
self.scheduleStateUpdate();
|
||||||
|
});
|
||||||
|
self.unobserveObjects.push(unobserveObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
structure.forEach(function (item) {
|
||||||
|
var domainObject = item.domainObject;
|
||||||
|
var id = objectUtils.makeKeyString(domainObject.identifier);
|
||||||
|
|
||||||
|
if (!self.domainObjectsById[id]) {
|
||||||
|
self.domainObjectsById[id] = {
|
||||||
|
domainObject: domainObject,
|
||||||
|
properties: []
|
||||||
|
};
|
||||||
|
observeObject(domainObject, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.domainObjectsById[id].properties.push(item.property);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delays updating the state.
|
||||||
|
*/
|
||||||
|
EditToolbar.prototype.scheduleStateUpdate = function () {
|
||||||
|
if (this.stateUpdateScheduled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.stateUpdateScheduled = true;
|
||||||
|
setTimeout(this.updateStateAfterMutation.bind(this));
|
||||||
|
};
|
||||||
|
|
||||||
|
EditToolbar.prototype.updateStateAfterMutation = function () {
|
||||||
|
this.stateTracker.forEach(function (state, index) {
|
||||||
|
if (!this.domainObjectsById[state.id].newObject) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var domainObject = this.domainObjectsById[state.id].domainObject;
|
||||||
|
var newObject = this.domainObjectsById[state.id].newObject;
|
||||||
|
var currentValue = _.get(domainObject, state.property);
|
||||||
|
var newValue = _.get(newObject, state.property);
|
||||||
|
|
||||||
|
state.domainObject = newObject;
|
||||||
|
|
||||||
|
if (currentValue !== newValue) {
|
||||||
|
this.updateState(index, newValue);
|
||||||
|
}
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
Object.values(this.domainObjectsById).forEach(function (tracker) {
|
||||||
|
if (tracker.newObject) {
|
||||||
|
tracker.domainObject = tracker.newObject;
|
||||||
|
}
|
||||||
|
delete tracker.newObject;
|
||||||
|
});
|
||||||
|
this.stateUpdateScheduled = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the listeners.
|
||||||
|
*/
|
||||||
|
EditToolbar.prototype.deregisterListeners = function () {
|
||||||
|
this.unobserveObjects.forEach(function (unobserveObject) {
|
||||||
|
unobserveObject();
|
||||||
|
});
|
||||||
|
this.unobserveObjects = [];
|
||||||
|
};
|
||||||
|
|
||||||
|
EditToolbar.prototype.handleStateChanges = function (state) {
|
||||||
|
(state || []).map(function (newValue, index) {
|
||||||
|
var domainObject = this.stateTracker[index].domainObject;
|
||||||
|
var property = this.stateTracker[index].property;
|
||||||
|
var currentValue = _.get(domainObject, property);
|
||||||
|
|
||||||
|
if (currentValue !== newValue) {
|
||||||
|
this.updateDomainObject(domainObject, property, newValue);
|
||||||
|
}
|
||||||
|
}, this);
|
||||||
|
};
|
||||||
|
|
||||||
|
EditToolbar.prototype.destroy = function () {
|
||||||
|
this.deregisterListeners();
|
||||||
|
};
|
||||||
|
|
||||||
|
return EditToolbar;
|
||||||
|
}
|
||||||
|
);
|
@ -0,0 +1,184 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2014-2018, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
/*global describe,it,expect,beforeEach,jasmine*/
|
||||||
|
|
||||||
|
define(
|
||||||
|
["../../src/controllers/ElementsController"],
|
||||||
|
function (ElementsController) {
|
||||||
|
|
||||||
|
describe("The Elements Pane controller", function () {
|
||||||
|
var mockScope,
|
||||||
|
mockOpenMCT,
|
||||||
|
mockSelection,
|
||||||
|
mockDomainObject,
|
||||||
|
mockMutationCapability,
|
||||||
|
mockCompositionCapability,
|
||||||
|
mockCompositionObjects,
|
||||||
|
mockComposition,
|
||||||
|
mockUnlisten,
|
||||||
|
selectable = [],
|
||||||
|
controller;
|
||||||
|
|
||||||
|
function mockPromise(value) {
|
||||||
|
return {
|
||||||
|
then: function (thenFunc) {
|
||||||
|
return mockPromise(thenFunc(value));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function createDomainObject() {
|
||||||
|
return {
|
||||||
|
useCapability: function () {
|
||||||
|
return mockCompositionCapability;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
mockComposition = ["a", "b"];
|
||||||
|
mockCompositionObjects = mockComposition.map(createDomainObject);
|
||||||
|
mockCompositionCapability = mockPromise(mockCompositionObjects);
|
||||||
|
|
||||||
|
mockUnlisten = jasmine.createSpy('unlisten');
|
||||||
|
mockMutationCapability = jasmine.createSpyObj("mutationCapability", [
|
||||||
|
"listen"
|
||||||
|
]);
|
||||||
|
mockMutationCapability.listen.and.returnValue(mockUnlisten);
|
||||||
|
mockDomainObject = jasmine.createSpyObj("domainObject", [
|
||||||
|
"getCapability",
|
||||||
|
"useCapability"
|
||||||
|
]);
|
||||||
|
mockDomainObject.useCapability.and.returnValue(mockCompositionCapability);
|
||||||
|
mockDomainObject.getCapability.and.returnValue(mockMutationCapability);
|
||||||
|
|
||||||
|
mockScope = jasmine.createSpyObj("$scope", ['$on']);
|
||||||
|
mockSelection = jasmine.createSpyObj("selection", [
|
||||||
|
'on',
|
||||||
|
'off',
|
||||||
|
'get'
|
||||||
|
]);
|
||||||
|
mockSelection.get.and.returnValue([]);
|
||||||
|
mockOpenMCT = {
|
||||||
|
selection: mockSelection
|
||||||
|
};
|
||||||
|
|
||||||
|
selectable[0] = {
|
||||||
|
context: {
|
||||||
|
oldItem: mockDomainObject
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
spyOn(ElementsController.prototype, 'refreshComposition').and.callThrough();
|
||||||
|
|
||||||
|
controller = new ElementsController(mockScope, mockOpenMCT);
|
||||||
|
});
|
||||||
|
|
||||||
|
function getModel(model) {
|
||||||
|
return function () {
|
||||||
|
return model;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
it("filters objects in elements pool based on input text and" +
|
||||||
|
" object name", function () {
|
||||||
|
var objects = [
|
||||||
|
{
|
||||||
|
getModel: getModel({name: "first element"})
|
||||||
|
},
|
||||||
|
{
|
||||||
|
getModel: getModel({name: "second element"})
|
||||||
|
},
|
||||||
|
{
|
||||||
|
getModel: getModel({name: "third element"})
|
||||||
|
},
|
||||||
|
{
|
||||||
|
getModel: getModel({name: "THIRD Element 1"})
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
mockScope.filterBy("third element");
|
||||||
|
expect(objects.filter(mockScope.searchElements).length).toBe(2);
|
||||||
|
mockScope.filterBy("element");
|
||||||
|
expect(objects.filter(mockScope.searchElements).length).toBe(4);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("refreshes composition on selection", function () {
|
||||||
|
mockOpenMCT.selection.on.calls.mostRecent().args[1](selectable);
|
||||||
|
|
||||||
|
expect(ElementsController.prototype.refreshComposition).toHaveBeenCalledWith(mockDomainObject);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("listens on mutation and refreshes composition", function () {
|
||||||
|
mockOpenMCT.selection.on.calls.mostRecent().args[1](selectable);
|
||||||
|
|
||||||
|
expect(mockDomainObject.getCapability).toHaveBeenCalledWith('mutation');
|
||||||
|
expect(mockMutationCapability.listen).toHaveBeenCalled();
|
||||||
|
expect(ElementsController.prototype.refreshComposition.calls.count()).toBe(1);
|
||||||
|
|
||||||
|
mockMutationCapability.listen.calls.mostRecent().args[0](mockDomainObject);
|
||||||
|
|
||||||
|
expect(ElementsController.prototype.refreshComposition.calls.count()).toBe(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("cleans up mutation listener when selection changes", function () {
|
||||||
|
mockOpenMCT.selection.on.calls.mostRecent().args[1](selectable);
|
||||||
|
|
||||||
|
expect(mockMutationCapability.listen).toHaveBeenCalled();
|
||||||
|
|
||||||
|
mockOpenMCT.selection.on.calls.mostRecent().args[1](selectable);
|
||||||
|
|
||||||
|
expect(mockUnlisten).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not listen on mutation for element proxy selectable", function () {
|
||||||
|
selectable[0] = {
|
||||||
|
context: {
|
||||||
|
elementProxy: {}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
mockOpenMCT.selection.on.calls.mostRecent().args[1](selectable);
|
||||||
|
|
||||||
|
expect(mockDomainObject.getCapability).not.toHaveBeenCalledWith('mutation');
|
||||||
|
});
|
||||||
|
|
||||||
|
it("checks concurrent changes to composition", function () {
|
||||||
|
var secondMockComposition = ["a", "b", "c"],
|
||||||
|
secondMockCompositionObjects = secondMockComposition.map(createDomainObject),
|
||||||
|
firstCompositionCallback,
|
||||||
|
secondCompositionCallback;
|
||||||
|
|
||||||
|
spyOn(mockCompositionCapability, "then").and.callThrough();
|
||||||
|
|
||||||
|
controller.refreshComposition(mockDomainObject);
|
||||||
|
controller.refreshComposition(mockDomainObject);
|
||||||
|
|
||||||
|
firstCompositionCallback = mockCompositionCapability.then.calls.all()[0].args[0];
|
||||||
|
secondCompositionCallback = mockCompositionCapability.then.calls.all()[1].args[0];
|
||||||
|
secondCompositionCallback(secondMockCompositionObjects);
|
||||||
|
firstCompositionCallback(mockCompositionObjects);
|
||||||
|
|
||||||
|
expect(mockScope.composition).toBe(secondMockCompositionObjects);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
105
platform/commonUI/edit/test/creation/AddActionProviderSpec.js
Normal file
105
platform/commonUI/edit/test/creation/AddActionProviderSpec.js
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2014-2018, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MCTRepresentationSpec. Created by ahenry on 01/21/14.
|
||||||
|
*/
|
||||||
|
define(
|
||||||
|
["../../src/creation/AddActionProvider"],
|
||||||
|
function (AddActionProvider) {
|
||||||
|
|
||||||
|
describe("The add action provider", function () {
|
||||||
|
var mockTypeService,
|
||||||
|
mockDialogService,
|
||||||
|
mockPolicyService,
|
||||||
|
mockTypeMap,
|
||||||
|
mockTypes,
|
||||||
|
mockDomainObject,
|
||||||
|
mockQ,
|
||||||
|
provider;
|
||||||
|
|
||||||
|
function createMockType(name) {
|
||||||
|
var mockType = jasmine.createSpyObj(
|
||||||
|
"type" + name,
|
||||||
|
[
|
||||||
|
"getKey",
|
||||||
|
"getGlyph",
|
||||||
|
"getCssClass",
|
||||||
|
"getName",
|
||||||
|
"getDescription",
|
||||||
|
"getProperties",
|
||||||
|
"getInitialModel",
|
||||||
|
"hasFeature"
|
||||||
|
]
|
||||||
|
);
|
||||||
|
mockType.hasFeature.and.returnValue(true);
|
||||||
|
mockType.getName.and.returnValue(name);
|
||||||
|
mockType.getKey.and.returnValue(name);
|
||||||
|
return mockType;
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
mockTypeService = jasmine.createSpyObj(
|
||||||
|
"typeService",
|
||||||
|
["getType"]
|
||||||
|
);
|
||||||
|
mockDialogService = {};
|
||||||
|
mockPolicyService = {};
|
||||||
|
mockDomainObject = {};
|
||||||
|
|
||||||
|
mockTypes = [
|
||||||
|
"timeline",
|
||||||
|
"activity",
|
||||||
|
"other"
|
||||||
|
].map(createMockType);
|
||||||
|
mockTypeMap = {};
|
||||||
|
|
||||||
|
mockTypes.forEach(function (type) {
|
||||||
|
mockTypeMap[type.getKey()] = type;
|
||||||
|
});
|
||||||
|
|
||||||
|
mockTypeService.getType.and.callFake(function (key) {
|
||||||
|
return mockTypeMap[key];
|
||||||
|
});
|
||||||
|
|
||||||
|
provider = new AddActionProvider(
|
||||||
|
mockQ,
|
||||||
|
mockTypeService,
|
||||||
|
mockDialogService,
|
||||||
|
mockPolicyService
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("provides actions for timeline and activity", function () {
|
||||||
|
var actions = provider.getActions({
|
||||||
|
key: "add",
|
||||||
|
domainObject: mockDomainObject
|
||||||
|
});
|
||||||
|
expect(actions.length).toBe(2);
|
||||||
|
expect(actions[0].metadata.type).toBe('timeline');
|
||||||
|
expect(actions[1].metadata.type).toBe('activity');
|
||||||
|
|
||||||
|
// Make sure it was creation which was used to check
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
75
platform/commonUI/edit/test/representers/EditToolbarSpec.js
Normal file
75
platform/commonUI/edit/test/representers/EditToolbarSpec.js
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* 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/representers/EditToolbar'],
|
||||||
|
function (EditToolbar) {
|
||||||
|
|
||||||
|
describe("An Edit mode toolbar", function () {
|
||||||
|
var mockOpenMCT,
|
||||||
|
mockScope,
|
||||||
|
mockObjects,
|
||||||
|
mockDomainObject,
|
||||||
|
testStructure,
|
||||||
|
toolbar;
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
mockOpenMCT = jasmine.createSpy('openmct', ['objects']);
|
||||||
|
mockObjects = jasmine.createSpyObj('objects', ['observe']);
|
||||||
|
mockObjects.observe.and.returnValue();
|
||||||
|
mockOpenMCT.objects = mockObjects;
|
||||||
|
mockScope = jasmine.createSpyObj("$scope", [
|
||||||
|
"$watchCollection",
|
||||||
|
"$on"
|
||||||
|
]);
|
||||||
|
mockScope.$watchCollection.and.returnValue();
|
||||||
|
mockDomainObject = jasmine.createSpyObj("domainObject", [
|
||||||
|
'identifier'
|
||||||
|
]);
|
||||||
|
|
||||||
|
testStructure = [
|
||||||
|
{ name: "A", property: "a", domainObject: mockDomainObject },
|
||||||
|
{ name: "B", property: "b", domainObject: mockDomainObject },
|
||||||
|
{ name: "C", property: "c", domainObject: mockDomainObject },
|
||||||
|
{ name: "X", property: "x", domainObject: mockDomainObject },
|
||||||
|
{ name: "Y", property: "y", domainObject: mockDomainObject },
|
||||||
|
{ name: "Z", property: "z", domainObject: mockDomainObject },
|
||||||
|
{ name: "M", method: "m", domainObject: mockDomainObject }
|
||||||
|
];
|
||||||
|
|
||||||
|
toolbar = new EditToolbar(mockScope, mockOpenMCT, testStructure);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("adds click functions when a method is specified", function () {
|
||||||
|
var structure = toolbar.getStructure();
|
||||||
|
expect(structure[6].click).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("adds key for controls that define a property", function () {
|
||||||
|
var structure = toolbar.getStructure();
|
||||||
|
expect(structure[0].key).toEqual(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
|||||||
<span class="l-progress-bar s-progress-bar"
|
<span class="l-progress-bar s-progress-bar"
|
||||||
ng-class="{ indeterminate:ngModel.progressPerc === 'unknown' }">
|
ng-class="{ indeterminate:ngModel.unknownProgress }">
|
||||||
<span class="progress-amt-holder">
|
<span class="progress-amt-holder">
|
||||||
<span class="progress-amt" style="width: {{ngModel.progressPerc === 'unknown' ? 100 : ngModel.progressPerc}}%"></span>
|
<span class="progress-amt" style="width: {{ngModel.progress}}%"></span>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
<div class="progress-info hint" ng-hide="ngModel.progressText === undefined">
|
<div class="progress-info hint" ng-hide="ngModel.progressText === undefined">
|
||||||
<span class="progress-amt-text" ng-show="ngModel.progressPerc !== 'unknown' && ngModel.progressPerc > 0">{{ngModel.progressPerc}}% complete. </span>
|
<span class="progress-amt-text" ng-show="ngModel.progress > 0">{{ngModel.progress}}% complete. </span>
|
||||||
{{ngModel.progressText}}
|
{{ngModel.progressText}}
|
||||||
</div>
|
</div>
|
||||||
|
@ -50,7 +50,7 @@ define(
|
|||||||
};
|
};
|
||||||
$scope.dismiss = function (notification, $event) {
|
$scope.dismiss = function (notification, $event) {
|
||||||
$event.stopPropagation();
|
$event.stopPropagation();
|
||||||
notification.dismiss();
|
notification.dismissOrMinimize();
|
||||||
};
|
};
|
||||||
$scope.maximize = function (notification) {
|
$scope.maximize = function (notification) {
|
||||||
if (notification.model.severity !== "info") {
|
if (notification.model.severity !== "info") {
|
||||||
|
@ -23,13 +23,11 @@
|
|||||||
define([
|
define([
|
||||||
"./src/NotificationIndicatorController",
|
"./src/NotificationIndicatorController",
|
||||||
"./src/NotificationIndicator",
|
"./src/NotificationIndicator",
|
||||||
"./src/NotificationService",
|
|
||||||
"./res/notification-indicator.html",
|
"./res/notification-indicator.html",
|
||||||
'legacyRegistry'
|
'legacyRegistry'
|
||||||
], function (
|
], function (
|
||||||
NotificationIndicatorController,
|
NotificationIndicatorController,
|
||||||
NotificationIndicator,
|
NotificationIndicator,
|
||||||
NotificationService,
|
|
||||||
notificationIndicatorTemplate,
|
notificationIndicatorTemplate,
|
||||||
legacyRegistry
|
legacyRegistry
|
||||||
) {
|
) {
|
||||||
@ -48,7 +46,7 @@ define([
|
|||||||
"implementation": NotificationIndicatorController,
|
"implementation": NotificationIndicatorController,
|
||||||
"depends": [
|
"depends": [
|
||||||
"$scope",
|
"$scope",
|
||||||
"openmct",
|
"notificationService",
|
||||||
"dialogService"
|
"dialogService"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -63,7 +61,7 @@ define([
|
|||||||
{
|
{
|
||||||
"key": "notificationService",
|
"key": "notificationService",
|
||||||
"implementation": function (openmct) {
|
"implementation": function (openmct) {
|
||||||
return new NotificationService.default(openmct);
|
return openmct.notifications;
|
||||||
},
|
},
|
||||||
"depends": [
|
"depends": [
|
||||||
"openmct"
|
"openmct"
|
||||||
|
@ -35,9 +35,9 @@ define(
|
|||||||
* @param dialogService
|
* @param dialogService
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function NotificationIndicatorController($scope, openmct, dialogService) {
|
function NotificationIndicatorController($scope, notificationService, dialogService) {
|
||||||
$scope.notifications = openmct.notifications.notifications;
|
$scope.notifications = notificationService.notifications;
|
||||||
$scope.highest = openmct.notifications.highest;
|
$scope.highest = notificationService.highest;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Launch a dialog showing a list of current notifications.
|
* Launch a dialog showing a list of current notifications.
|
||||||
@ -48,7 +48,7 @@ define(
|
|||||||
title: "Messages",
|
title: "Messages",
|
||||||
//Launch the message list dialog with the models
|
//Launch the message list dialog with the models
|
||||||
// from the notifications
|
// from the notifications
|
||||||
messages: openmct.notifications.notifications
|
messages: notificationService.notifications
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,64 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2014-2018, United States Government
|
|
||||||
* as represented by the Administrator of the National Aeronautics and Space
|
|
||||||
* Administration. All rights reserved.
|
|
||||||
*
|
|
||||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
* License for the specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*
|
|
||||||
* Open MCT includes source code licensed under additional open source
|
|
||||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
|
||||||
* this source code distribution or the Licensing information page available
|
|
||||||
* at runtime from the About dialog for additional information.
|
|
||||||
*****************************************************************************/
|
|
||||||
export default class NotificationService {
|
|
||||||
constructor(openmct) {
|
|
||||||
this.openmct = openmct;
|
|
||||||
}
|
|
||||||
info(message) {
|
|
||||||
if (typeof message === 'string') {
|
|
||||||
return this.openmct.notifications.info(message);
|
|
||||||
} else {
|
|
||||||
if (message.hasOwnProperty('progress')) {
|
|
||||||
return this.openmct.notifications.progress(message.title, message.progress, message.progressText);
|
|
||||||
} else {
|
|
||||||
return this.openmct.notifications.info(message.title);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
alert(message) {
|
|
||||||
if (typeof message === 'string') {
|
|
||||||
return this.openmct.notifications.alert(message);
|
|
||||||
} else {
|
|
||||||
return this.openmct.notifications.alert(message.title);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
error(message) {
|
|
||||||
if (typeof message === 'string') {
|
|
||||||
return this.openmct.notifications.error(message);
|
|
||||||
} else {
|
|
||||||
return this.openmct.notifications.error(message.title);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
notify(options) {
|
|
||||||
switch (options.severity) {
|
|
||||||
case 'info':
|
|
||||||
return this.info(options);
|
|
||||||
case 'alert':
|
|
||||||
return this.alert(options);
|
|
||||||
case 'error':
|
|
||||||
return this.error(options);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
getAllNotifications() {
|
|
||||||
return this.openmct.notifications.notifications;
|
|
||||||
}
|
|
||||||
}
|
|
@ -58,8 +58,7 @@ define([
|
|||||||
"category": "action",
|
"category": "action",
|
||||||
"implementation": ComposeActionPolicy,
|
"implementation": ComposeActionPolicy,
|
||||||
"depends": [
|
"depends": [
|
||||||
"$injector",
|
"$injector"
|
||||||
"openmct"
|
|
||||||
],
|
],
|
||||||
"message": "Objects of this type cannot contain objects of that type."
|
"message": "Objects of this type cannot contain objects of that type."
|
||||||
},
|
},
|
||||||
|
@ -36,11 +36,10 @@ define(
|
|||||||
* @memberof platform/containment
|
* @memberof platform/containment
|
||||||
* @implements {Policy.<Action, ActionContext>}
|
* @implements {Policy.<Action, ActionContext>}
|
||||||
*/
|
*/
|
||||||
function ComposeActionPolicy($injector, openmct) {
|
function ComposeActionPolicy($injector) {
|
||||||
this.getPolicyService = function () {
|
this.getPolicyService = function () {
|
||||||
return $injector.get('policyService');
|
return $injector.get('policyService');
|
||||||
};
|
};
|
||||||
this.openmct = openmct;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ComposeActionPolicy.prototype.allowComposition = function (containerObject, selectedObject) {
|
ComposeActionPolicy.prototype.allowComposition = function (containerObject, selectedObject) {
|
||||||
@ -50,8 +49,11 @@ define(
|
|||||||
|
|
||||||
// ...and delegate to the composition policy
|
// ...and delegate to the composition policy
|
||||||
return containerObject.getId() !== selectedObject.getId() &&
|
return containerObject.getId() !== selectedObject.getId() &&
|
||||||
this.openmct.composition.checkPolicy(containerObject.useCapability('adapter'),
|
this.policyService.allow(
|
||||||
selectedObject.useCapability('adapter'));
|
'composition',
|
||||||
|
containerObject,
|
||||||
|
selectedObject
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -170,7 +170,7 @@ define([
|
|||||||
"description": "Provides a service for moving objects",
|
"description": "Provides a service for moving objects",
|
||||||
"implementation": MoveService,
|
"implementation": MoveService,
|
||||||
"depends": [
|
"depends": [
|
||||||
"openmct",
|
"policyService",
|
||||||
"linkService",
|
"linkService",
|
||||||
"$q"
|
"$q"
|
||||||
]
|
]
|
||||||
@ -181,7 +181,7 @@ define([
|
|||||||
"description": "Provides a service for linking objects",
|
"description": "Provides a service for linking objects",
|
||||||
"implementation": LinkService,
|
"implementation": LinkService,
|
||||||
"depends": [
|
"depends": [
|
||||||
"openmct"
|
"policyService"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -192,7 +192,7 @@ define([
|
|||||||
"depends": [
|
"depends": [
|
||||||
"$q",
|
"$q",
|
||||||
"policyService",
|
"policyService",
|
||||||
"openmct"
|
"now"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -33,10 +33,9 @@ define(
|
|||||||
* @memberof platform/entanglement
|
* @memberof platform/entanglement
|
||||||
* @implements {platform/entanglement.AbstractComposeService}
|
* @implements {platform/entanglement.AbstractComposeService}
|
||||||
*/
|
*/
|
||||||
function CopyService($q, policyService, openmct) {
|
function CopyService($q, policyService) {
|
||||||
this.$q = $q;
|
this.$q = $q;
|
||||||
this.policyService = policyService;
|
this.policyService = policyService;
|
||||||
this.openmct = openmct;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CopyService.prototype.validate = function (object, parentCandidate) {
|
CopyService.prototype.validate = function (object, parentCandidate) {
|
||||||
@ -46,7 +45,11 @@ define(
|
|||||||
if (parentCandidate.getId() === object.getId()) {
|
if (parentCandidate.getId() === object.getId()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return this.openmct.composition.checkPolicy(parentCandidate.useCapability('adapter'), object.useCapability('adapter'));
|
return this.policyService.allow(
|
||||||
|
"composition",
|
||||||
|
parentCandidate,
|
||||||
|
object
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -32,8 +32,8 @@ define(
|
|||||||
* @memberof platform/entanglement
|
* @memberof platform/entanglement
|
||||||
* @implements {platform/entanglement.AbstractComposeService}
|
* @implements {platform/entanglement.AbstractComposeService}
|
||||||
*/
|
*/
|
||||||
function LinkService(openmct) {
|
function LinkService(policyService) {
|
||||||
this.openmct = openmct;
|
this.policyService = policyService;
|
||||||
}
|
}
|
||||||
|
|
||||||
LinkService.prototype.validate = function (object, parentCandidate) {
|
LinkService.prototype.validate = function (object, parentCandidate) {
|
||||||
@ -49,7 +49,11 @@ define(
|
|||||||
if (parentCandidate.getModel().composition.indexOf(object.getId()) !== -1) {
|
if (parentCandidate.getModel().composition.indexOf(object.getId()) !== -1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return this.openmct.composition.checkPolicy(parentCandidate.useCapability('adapter'), object.useCapability('adapter'));
|
return this.policyService.allow(
|
||||||
|
"composition",
|
||||||
|
parentCandidate,
|
||||||
|
object
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
LinkService.prototype.perform = function (object, parentObject) {
|
LinkService.prototype.perform = function (object, parentObject) {
|
||||||
|
@ -31,8 +31,8 @@ define(
|
|||||||
* @memberof platform/entanglement
|
* @memberof platform/entanglement
|
||||||
* @implements {platform/entanglement.AbstractComposeService}
|
* @implements {platform/entanglement.AbstractComposeService}
|
||||||
*/
|
*/
|
||||||
function MoveService(openmct, linkService) {
|
function MoveService(policyService, linkService) {
|
||||||
this.openmct = openmct;
|
this.policyService = policyService;
|
||||||
this.linkService = linkService;
|
this.linkService = linkService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,9 +53,10 @@ define(
|
|||||||
if (parentCandidate.getModel().composition.indexOf(object.getId()) !== -1) {
|
if (parentCandidate.getModel().composition.indexOf(object.getId()) !== -1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return this.openmct.composition.checkPolicy(
|
return this.policyService.allow(
|
||||||
parentCandidate.useCapability('adapter'),
|
"composition",
|
||||||
object.useCapability('adapter')
|
parentCandidate,
|
||||||
|
object
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ define([
|
|||||||
{
|
{
|
||||||
key: "exportService",
|
key: "exportService",
|
||||||
implementation: function () {
|
implementation: function () {
|
||||||
return new ExportService(saveAs.saveAs);
|
return new ExportService(saveAs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
399
platform/features/fixed/bundle.js
Normal file
399
platform/features/fixed/bundle.js
Normal file
@ -0,0 +1,399 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* 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([
|
||||||
|
"../layout/res/templates/fixed.html",
|
||||||
|
'legacyRegistry'
|
||||||
|
], function (
|
||||||
|
fixedTemplate,
|
||||||
|
legacyRegistry
|
||||||
|
) {
|
||||||
|
|
||||||
|
legacyRegistry.register("platform/features/fixed", {
|
||||||
|
"name": "Fixed position components.",
|
||||||
|
"description": "Plug in adding Fixed Position object type.",
|
||||||
|
"extensions": {
|
||||||
|
"views": [
|
||||||
|
{
|
||||||
|
"key": "fixed-display",
|
||||||
|
"name": "Fixed Position Display",
|
||||||
|
"cssClass": "icon-box-with-dashed-lines",
|
||||||
|
"type": "telemetry.fixed",
|
||||||
|
"template": fixedTemplate,
|
||||||
|
"uses": [],
|
||||||
|
"editable": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"toolbars": [
|
||||||
|
{
|
||||||
|
name: "Fixed Position Toolbar",
|
||||||
|
key: "fixed.position",
|
||||||
|
description: "Toolbar for the selected element inside a fixed position display.",
|
||||||
|
forSelection: function (selection) {
|
||||||
|
if (!selection) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
selection[0] && selection[0].context.elementProxy &&
|
||||||
|
selection[1] && selection[1].context.item.type === 'telemetry.fixed' ||
|
||||||
|
selection[0] && selection[0].context.item.type === 'telemetry.fixed'
|
||||||
|
);
|
||||||
|
},
|
||||||
|
toolbar: function (selection) {
|
||||||
|
var imageProperties = ["add", "remove", "order", "stroke", "useGrid", "x", "y", "height", "width", "url"];
|
||||||
|
var boxProperties = ["add", "remove", "order", "stroke", "useGrid", "x", "y", "height", "width", "fill"];
|
||||||
|
var textProperties = ["add", "remove", "order", "stroke", "useGrid", "x", "y", "height", "width", "fill", "color", "size", "text"];
|
||||||
|
var lineProperties = ["add", "remove", "order", "stroke", "useGrid", "x", "y", "x2", "y2"];
|
||||||
|
var telemetryProperties = ["add", "remove", "order", "stroke", "useGrid", "x", "y", "height", "width", "fill", "color", "size", "titled"];
|
||||||
|
var fixedPageProperties = ["add"];
|
||||||
|
|
||||||
|
var properties = [],
|
||||||
|
fixedItem = selection[0] && selection[0].context.item,
|
||||||
|
elementProxy = selection[0] && selection[0].context.elementProxy,
|
||||||
|
domainObject = selection[1] && selection[1].context.item,
|
||||||
|
path;
|
||||||
|
|
||||||
|
if (elementProxy) {
|
||||||
|
var type = elementProxy.element.type;
|
||||||
|
path = "configuration['fixed-display'].elements[" + elementProxy.index + "]";
|
||||||
|
properties =
|
||||||
|
type === 'fixed.image' ? imageProperties :
|
||||||
|
type === 'fixed.text' ? textProperties :
|
||||||
|
type === 'fixed.box' ? boxProperties :
|
||||||
|
type === 'fixed.line' ? lineProperties :
|
||||||
|
type === 'fixed.telemetry' ? telemetryProperties : [];
|
||||||
|
} else if (fixedItem) {
|
||||||
|
properties = domainObject && domainObject.type === 'layout' ? [] : fixedPageProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
control: "menu-button",
|
||||||
|
domainObject: domainObject || selection[0].context.item,
|
||||||
|
method: function (value) {
|
||||||
|
selection[0].context.fixedController.add(value);
|
||||||
|
},
|
||||||
|
key: "add",
|
||||||
|
cssClass: "icon-plus",
|
||||||
|
text: "Add",
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
"name": "Box",
|
||||||
|
"cssClass": "icon-box",
|
||||||
|
"key": "fixed.box"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Line",
|
||||||
|
"cssClass": "icon-line-horz",
|
||||||
|
"key": "fixed.line"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Text",
|
||||||
|
"cssClass": "icon-T",
|
||||||
|
"key": "fixed.text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Image",
|
||||||
|
"cssClass": "icon-image",
|
||||||
|
"key": "fixed.image"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
control: "menu-button",
|
||||||
|
domainObject: domainObject,
|
||||||
|
method: function (value) {
|
||||||
|
selection[0].context.fixedController.order(
|
||||||
|
selection[0].context.elementProxy,
|
||||||
|
value
|
||||||
|
);
|
||||||
|
},
|
||||||
|
key: "order",
|
||||||
|
cssClass: "icon-layers",
|
||||||
|
title: "Layering",
|
||||||
|
description: "Move the selected object above or below other objects",
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
"name": "Move to Top",
|
||||||
|
"cssClass": "icon-arrow-double-up",
|
||||||
|
"key": "top"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Move Up",
|
||||||
|
"cssClass": "icon-arrow-up",
|
||||||
|
"key": "up"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Move Down",
|
||||||
|
"cssClass": "icon-arrow-down",
|
||||||
|
"key": "down"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Move to Bottom",
|
||||||
|
"cssClass": "icon-arrow-double-down",
|
||||||
|
"key": "bottom"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
control: "color",
|
||||||
|
domainObject: domainObject,
|
||||||
|
property: path + ".fill",
|
||||||
|
cssClass: "icon-paint-bucket",
|
||||||
|
title: "Fill color",
|
||||||
|
description: "Set fill color",
|
||||||
|
key: 'fill'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
control: "color",
|
||||||
|
domainObject: domainObject,
|
||||||
|
property: path + ".stroke",
|
||||||
|
cssClass: "icon-line-horz",
|
||||||
|
title: "Border color",
|
||||||
|
description: "Set border color",
|
||||||
|
key: 'stroke'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
control: "dialog-button",
|
||||||
|
domainObject: domainObject,
|
||||||
|
property: path + ".url",
|
||||||
|
cssClass: "icon-image",
|
||||||
|
title: "Image Properties",
|
||||||
|
description: "Edit image properties",
|
||||||
|
key: 'url',
|
||||||
|
dialog: {
|
||||||
|
control: "textfield",
|
||||||
|
name: "Image URL",
|
||||||
|
cssClass: "l-input-lg",
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
control: "color",
|
||||||
|
domainObject: domainObject,
|
||||||
|
property: path + ".color",
|
||||||
|
cssClass: "icon-T",
|
||||||
|
title: "Text color",
|
||||||
|
mandatory: true,
|
||||||
|
description: "Set text color",
|
||||||
|
key: 'color'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
control: "select",
|
||||||
|
domainObject: domainObject,
|
||||||
|
property: path + ".size",
|
||||||
|
title: "Text size",
|
||||||
|
description: "Set text size",
|
||||||
|
"options": [9, 10, 11, 12, 13, 14, 15, 16, 20, 24, 30, 36, 48, 72, 96].map(function (size) {
|
||||||
|
return { "name": size + " px", "value": size + "px" };
|
||||||
|
}),
|
||||||
|
key: 'size'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
control: "numberfield",
|
||||||
|
domainObject: domainObject,
|
||||||
|
property: path + ".x",
|
||||||
|
text: "X",
|
||||||
|
name: "X",
|
||||||
|
key: "x",
|
||||||
|
cssClass: "l-input-sm",
|
||||||
|
min: "0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
control: "numberfield",
|
||||||
|
domainObject: domainObject,
|
||||||
|
property: path + ".y",
|
||||||
|
text: "Y",
|
||||||
|
name: "Y",
|
||||||
|
key: "y",
|
||||||
|
cssClass: "l-input-sm",
|
||||||
|
min: "0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
control: "numberfield",
|
||||||
|
domainObject: domainObject,
|
||||||
|
property: path + ".x",
|
||||||
|
text: "X1",
|
||||||
|
name: "X1",
|
||||||
|
key: "x1",
|
||||||
|
cssClass: "l-input-sm",
|
||||||
|
min: "0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
control: "numberfield",
|
||||||
|
domainObject: domainObject,
|
||||||
|
property: path + ".y",
|
||||||
|
text: "Y1",
|
||||||
|
name: "Y1",
|
||||||
|
key: "y1",
|
||||||
|
cssClass: "l-input-sm",
|
||||||
|
min: "0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
control: "numberfield",
|
||||||
|
domainObject: domainObject,
|
||||||
|
property: path + ".x2",
|
||||||
|
text: "X2",
|
||||||
|
name: "X2",
|
||||||
|
key: "x2",
|
||||||
|
cssClass: "l-input-sm",
|
||||||
|
min: "0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
control: "numberfield",
|
||||||
|
domainObject: domainObject,
|
||||||
|
property: path + ".y2",
|
||||||
|
text: "Y2",
|
||||||
|
name: "Y2",
|
||||||
|
key: "y2",
|
||||||
|
cssClass: "l-input-sm",
|
||||||
|
min: "0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
control: "numberfield",
|
||||||
|
domainObject: domainObject,
|
||||||
|
property: path + ".height",
|
||||||
|
text: "H",
|
||||||
|
name: "H",
|
||||||
|
key: "height",
|
||||||
|
cssClass: "l-input-sm",
|
||||||
|
description: "Resize object height",
|
||||||
|
min: "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
control: "numberfield",
|
||||||
|
domainObject: domainObject,
|
||||||
|
property: path + ".width",
|
||||||
|
text: "W",
|
||||||
|
name: "W",
|
||||||
|
key: "width",
|
||||||
|
cssClass: "l-input-sm",
|
||||||
|
description: "Resize object width",
|
||||||
|
min: "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
control: "checkbox",
|
||||||
|
domainObject: domainObject,
|
||||||
|
property: path + ".useGrid",
|
||||||
|
name: "Snap to Grid",
|
||||||
|
key: "useGrid"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
control: "dialog-button",
|
||||||
|
domainObject: domainObject,
|
||||||
|
property: path + ".text",
|
||||||
|
cssClass: "icon-gear",
|
||||||
|
title: "Text Properties",
|
||||||
|
description: "Edit text properties",
|
||||||
|
key: "text",
|
||||||
|
dialog: {
|
||||||
|
control: "textfield",
|
||||||
|
name: "Text",
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
control: "checkbox",
|
||||||
|
domainObject: domainObject,
|
||||||
|
property: path + ".titled",
|
||||||
|
name: "Show Title",
|
||||||
|
key: "titled"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
control: "button",
|
||||||
|
domainObject: domainObject,
|
||||||
|
method: function () {
|
||||||
|
selection[0].context.fixedController.remove(
|
||||||
|
selection[0].context.elementProxy
|
||||||
|
);
|
||||||
|
},
|
||||||
|
key: "remove",
|
||||||
|
cssClass: "icon-trash"
|
||||||
|
}
|
||||||
|
].filter(function (item) {
|
||||||
|
var filtered;
|
||||||
|
|
||||||
|
properties.forEach(function (property) {
|
||||||
|
if (item.property && item.key === property ||
|
||||||
|
item.method && item.key === property) {
|
||||||
|
filtered = item;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return filtered;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"types": [
|
||||||
|
{
|
||||||
|
"key": "telemetry.fixed",
|
||||||
|
"name": "Fixed Position Display",
|
||||||
|
"cssClass": "icon-box-with-dashed-lines",
|
||||||
|
"description": "Collect and display telemetry elements in " +
|
||||||
|
"alphanumeric format in a simple canvas workspace. " +
|
||||||
|
"Elements can be positioned and sized. " +
|
||||||
|
"Lines, boxes and images can be added as well.",
|
||||||
|
"priority": 899,
|
||||||
|
"delegates": [
|
||||||
|
"telemetry"
|
||||||
|
],
|
||||||
|
"features": "creation",
|
||||||
|
"contains": [
|
||||||
|
{
|
||||||
|
"has": "telemetry"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"model": {
|
||||||
|
"layoutGrid": [64, 16],
|
||||||
|
"composition": []
|
||||||
|
},
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"name": "Layout Grid",
|
||||||
|
"control": "composite",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"name": "Horizontal grid (px)",
|
||||||
|
"control": "textfield",
|
||||||
|
"cssClass": "l-input-sm l-numeric"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Vertical grid (px)",
|
||||||
|
"control": "textfield",
|
||||||
|
"cssClass": "l-input-sm l-numeric"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"pattern": "^(\\d*[1-9]\\d*)?$",
|
||||||
|
"property": "layoutGrid",
|
||||||
|
"conversion": "number[]"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"views": [
|
||||||
|
"fixed-display"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
@ -1,475 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2014-2018, United States Government
|
|
||||||
* as represented by the Administrator of the National Aeronautics and Space
|
|
||||||
* Administration. All rights reserved.
|
|
||||||
*
|
|
||||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
* License for the specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*
|
|
||||||
* Open MCT includes source code licensed under additional open source
|
|
||||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
|
||||||
* this source code distribution or the Licensing information page available
|
|
||||||
* at runtime from the About dialog for additional information.
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
define([
|
|
||||||
"./src/FixedController",
|
|
||||||
"./templates/fixed.html",
|
|
||||||
"./templates/frame.html",
|
|
||||||
"./templates/elements/telemetry.html",
|
|
||||||
"./templates/elements/box.html",
|
|
||||||
"./templates/elements/line.html",
|
|
||||||
"./templates/elements/text.html",
|
|
||||||
"./templates/elements/image.html",
|
|
||||||
"legacyRegistry"
|
|
||||||
], function (
|
|
||||||
FixedController,
|
|
||||||
fixedTemplate,
|
|
||||||
frameTemplate,
|
|
||||||
telemetryTemplate,
|
|
||||||
boxTemplate,
|
|
||||||
lineTemplate,
|
|
||||||
textTemplate,
|
|
||||||
imageTemplate,
|
|
||||||
legacyRegistry
|
|
||||||
) {
|
|
||||||
return function() {
|
|
||||||
return function (openmct) {
|
|
||||||
openmct.legacyRegistry.register("platform/features/fixed", {
|
|
||||||
"name": "Fixed position components.",
|
|
||||||
"description": "Plug in adding Fixed Position object type.",
|
|
||||||
"extensions": {
|
|
||||||
"views": [
|
|
||||||
{
|
|
||||||
"key": "fixed-display",
|
|
||||||
"name": "Fixed Position Display",
|
|
||||||
"cssClass": "icon-box-with-dashed-lines",
|
|
||||||
"type": "telemetry.fixed",
|
|
||||||
"template": fixedTemplate,
|
|
||||||
"uses": ["composition"],
|
|
||||||
"editable": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"templates": [
|
|
||||||
{
|
|
||||||
"key": "fixed.telemetry",
|
|
||||||
"template": telemetryTemplate
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "fixed.box",
|
|
||||||
"template": boxTemplate
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "fixed.line",
|
|
||||||
"template": lineTemplate
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "fixed.text",
|
|
||||||
"template": textTemplate
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "fixed.image",
|
|
||||||
"template": imageTemplate
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"controllers": [
|
|
||||||
{
|
|
||||||
"key": "FixedController",
|
|
||||||
"implementation": FixedController,
|
|
||||||
"depends": [
|
|
||||||
"$scope",
|
|
||||||
"$q",
|
|
||||||
"dialogService",
|
|
||||||
"openmct",
|
|
||||||
"$element"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"toolbars": [
|
|
||||||
{
|
|
||||||
name: "Fixed Position Toolbar",
|
|
||||||
key: "fixed.position",
|
|
||||||
description: "Toolbar for the selected element inside a fixed position display.",
|
|
||||||
forSelection: function (selection) {
|
|
||||||
if (!selection) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (openmct.editor.isEditing() &&
|
|
||||||
selection[0] && selection[0].context.elementProxy &&
|
|
||||||
((selection[1] && selection[1].context.item.type === 'telemetry.fixed') ||
|
|
||||||
(selection[0] && selection[0].context.item && selection[0].context.item.type === 'telemetry.fixed')));
|
|
||||||
},
|
|
||||||
toolbar: function (selection) {
|
|
||||||
var imageProperties = ["add", "remove", "order", "stroke", "useGrid", "x", "y", "height", "width", "url"];
|
|
||||||
var boxProperties = ["add", "remove", "order", "stroke", "useGrid", "x", "y", "height", "width", "fill"];
|
|
||||||
var textProperties = ["add", "remove", "order", "stroke", "useGrid", "x", "y", "height", "width", "fill", "color", "size", "text"];
|
|
||||||
var lineProperties = ["add", "remove", "order", "stroke", "useGrid", "x", "y", "x2", "y2"];
|
|
||||||
var telemetryProperties = ["add", "remove", "order", "stroke", "useGrid", "x", "y", "height", "width", "fill", "color", "size", "titled"];
|
|
||||||
var fixedPageProperties = ["add"];
|
|
||||||
|
|
||||||
var properties = [],
|
|
||||||
fixedItem = selection[0] && selection[0].context.item,
|
|
||||||
elementProxy = selection[0] && selection[0].context.elementProxy,
|
|
||||||
domainObject = selection[1] && selection[1].context.item,
|
|
||||||
path;
|
|
||||||
|
|
||||||
if (elementProxy) {
|
|
||||||
var type = elementProxy.element.type;
|
|
||||||
path = "configuration['fixed-display'].elements[" + elementProxy.index + "]";
|
|
||||||
properties =
|
|
||||||
type === 'fixed.image' ? imageProperties :
|
|
||||||
type === 'fixed.text' ? textProperties :
|
|
||||||
type === 'fixed.box' ? boxProperties :
|
|
||||||
type === 'fixed.line' ? lineProperties :
|
|
||||||
type === 'fixed.telemetry' ? telemetryProperties : [];
|
|
||||||
} else if (fixedItem) {
|
|
||||||
properties = domainObject && domainObject.type === 'layout' ? [] : fixedPageProperties;
|
|
||||||
}
|
|
||||||
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
control: "menu",
|
|
||||||
domainObject: domainObject || selection[0].context.item,
|
|
||||||
method: function (option) {
|
|
||||||
selection[0].context.fixedController.add(option.key);
|
|
||||||
},
|
|
||||||
key: "add",
|
|
||||||
icon: "icon-plus",
|
|
||||||
label: "Add",
|
|
||||||
options: [
|
|
||||||
{
|
|
||||||
"name": "Box",
|
|
||||||
"class": "icon-box",
|
|
||||||
"key": "fixed.box"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Line",
|
|
||||||
"class": "icon-line-horz",
|
|
||||||
"key": "fixed.line"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Text",
|
|
||||||
"class": "icon-T",
|
|
||||||
"key": "fixed.text"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Image",
|
|
||||||
"class": "icon-image",
|
|
||||||
"key": "fixed.image"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
control: "menu",
|
|
||||||
domainObject: domainObject,
|
|
||||||
method: function (option) {
|
|
||||||
console.log('option', option)
|
|
||||||
selection[0].context.fixedController.order(
|
|
||||||
selection[0].context.elementProxy,
|
|
||||||
option.key
|
|
||||||
);
|
|
||||||
},
|
|
||||||
key: "order",
|
|
||||||
icon: "icon-layers",
|
|
||||||
title: "Move the selected object above or below other objects",
|
|
||||||
options: [
|
|
||||||
{
|
|
||||||
"name": "Move to Top",
|
|
||||||
"class": "icon-arrow-double-up",
|
|
||||||
"key": "top"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Move Up",
|
|
||||||
"class": "icon-arrow-up",
|
|
||||||
"key": "up"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Move Down",
|
|
||||||
"class": "icon-arrow-down",
|
|
||||||
"key": "down"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Move to Bottom",
|
|
||||||
"class": "icon-arrow-double-down",
|
|
||||||
"key": "bottom"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
control: "color-picker",
|
|
||||||
domainObject: domainObject,
|
|
||||||
property: path + ".fill",
|
|
||||||
icon: "icon-paint-bucket",
|
|
||||||
title: "Set fill color",
|
|
||||||
key: 'fill'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
control: "color-picker",
|
|
||||||
domainObject: domainObject,
|
|
||||||
property: path + ".stroke",
|
|
||||||
icon: "icon-line-horz",
|
|
||||||
title: "Set border color",
|
|
||||||
key: 'stroke'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
control: "button",
|
|
||||||
domainObject: domainObject,
|
|
||||||
property: path + ".url",
|
|
||||||
icon: "icon-image",
|
|
||||||
title: "Edit image properties",
|
|
||||||
key: 'url',
|
|
||||||
dialog: {
|
|
||||||
control: "input",
|
|
||||||
type: "text",
|
|
||||||
name: "Image URL",
|
|
||||||
class: "l-input-lg",
|
|
||||||
required: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
control: "color-picker",
|
|
||||||
domainObject: domainObject,
|
|
||||||
property: path + ".color",
|
|
||||||
icon: "icon-T",
|
|
||||||
mandatory: true,
|
|
||||||
title: "Set text color",
|
|
||||||
key: 'color'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
control: "select-menu",
|
|
||||||
domainObject: domainObject,
|
|
||||||
property: path + ".size",
|
|
||||||
title: "Set text size",
|
|
||||||
key: 'size',
|
|
||||||
options: [9, 10, 11, 12, 13, 14, 15, 16, 20, 24, 30, 36, 48, 72, 96].map(function (size) {
|
|
||||||
return { "value": size + "px"};
|
|
||||||
})
|
|
||||||
},
|
|
||||||
{
|
|
||||||
control: "input",
|
|
||||||
type: "number",
|
|
||||||
domainObject: domainObject,
|
|
||||||
property: path + ".x",
|
|
||||||
label: "X",
|
|
||||||
title: "X position",
|
|
||||||
key: "x",
|
|
||||||
class: "l-input-sm",
|
|
||||||
min: "0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
control: "input",
|
|
||||||
type: "number",
|
|
||||||
domainObject: domainObject,
|
|
||||||
property: path + ".y",
|
|
||||||
label: "Y",
|
|
||||||
title: "Y position",
|
|
||||||
key: "y",
|
|
||||||
class: "l-input-sm",
|
|
||||||
min: "0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
control: "input",
|
|
||||||
type: "number",
|
|
||||||
domainObject: domainObject,
|
|
||||||
property: path + ".x",
|
|
||||||
label: "X1",
|
|
||||||
title: "X1 position",
|
|
||||||
key: "x1",
|
|
||||||
class: "l-input-sm",
|
|
||||||
min: "0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
control: "input",
|
|
||||||
type: "number",
|
|
||||||
domainObject: domainObject,
|
|
||||||
property: path + ".y",
|
|
||||||
label: "Y1",
|
|
||||||
title: "Y1 position",
|
|
||||||
key: "y1",
|
|
||||||
class: "l-input-sm",
|
|
||||||
min: "0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
control: "input",
|
|
||||||
type: "number",
|
|
||||||
domainObject: domainObject,
|
|
||||||
property: path + ".x2",
|
|
||||||
label: "X2",
|
|
||||||
title: "X2 position",
|
|
||||||
key: "x2",
|
|
||||||
class: "l-input-sm",
|
|
||||||
min: "0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
control: "input",
|
|
||||||
type: "number",
|
|
||||||
domainObject: domainObject,
|
|
||||||
property: path + ".y2",
|
|
||||||
label: "Y2",
|
|
||||||
title: "Y2 position",
|
|
||||||
key: "y2",
|
|
||||||
class: "l-input-sm",
|
|
||||||
min: "0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
control: "input",
|
|
||||||
type: "number",
|
|
||||||
domainObject: domainObject,
|
|
||||||
property: path + ".height",
|
|
||||||
label: "H",
|
|
||||||
title: "Resize object height",
|
|
||||||
key: "height",
|
|
||||||
class: "l-input-sm",
|
|
||||||
min: "1"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
control: "input",
|
|
||||||
type: "number",
|
|
||||||
domainObject: domainObject,
|
|
||||||
property: path + ".width",
|
|
||||||
label: "W",
|
|
||||||
title: "Resize object width",
|
|
||||||
key: "width",
|
|
||||||
class: "l-input-sm",
|
|
||||||
min: "1"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
control: "toggle-button",
|
|
||||||
domainObject: domainObject,
|
|
||||||
property: path + ".useGrid",
|
|
||||||
key: "useGrid",
|
|
||||||
options: [
|
|
||||||
{
|
|
||||||
value: true,
|
|
||||||
icon: 'icon-grid-snap-to',
|
|
||||||
title: 'Snap to grid'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: false,
|
|
||||||
icon: 'icon-grid-snap-no',
|
|
||||||
title: "Do not snap to grid"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
control: "button",
|
|
||||||
domainObject: domainObject,
|
|
||||||
property: path + ".text",
|
|
||||||
icon: "icon-gear",
|
|
||||||
title: "Edit text properties",
|
|
||||||
key: "text",
|
|
||||||
dialog: {
|
|
||||||
control: "input",
|
|
||||||
type: "text",
|
|
||||||
name: "Text",
|
|
||||||
required: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
control: "toggle-button",
|
|
||||||
domainObject: domainObject,
|
|
||||||
property: path + ".titled",
|
|
||||||
key: "titled",
|
|
||||||
options: [
|
|
||||||
{
|
|
||||||
value: true,
|
|
||||||
icon: 'icon-two-parts-both',
|
|
||||||
title: 'Show label'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: false,
|
|
||||||
icon: 'icon-two-parts-one-only',
|
|
||||||
title: "Hide label"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
control: "button",
|
|
||||||
domainObject: domainObject,
|
|
||||||
method: function () {
|
|
||||||
selection[0].context.fixedController.remove(
|
|
||||||
selection[0].context.elementProxy
|
|
||||||
);
|
|
||||||
},
|
|
||||||
key: "remove",
|
|
||||||
icon: "icon-trash"
|
|
||||||
}
|
|
||||||
].filter(function (item) {
|
|
||||||
var filtered;
|
|
||||||
|
|
||||||
properties.forEach(function (property) {
|
|
||||||
if (item.property && item.key === property ||
|
|
||||||
item.method && item.key === property) {
|
|
||||||
filtered = item;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return filtered;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"types": [
|
|
||||||
{
|
|
||||||
"key": "telemetry.fixed",
|
|
||||||
"name": "Fixed Position Display",
|
|
||||||
"cssClass": "icon-box-with-dashed-lines",
|
|
||||||
"description": "Collect and display telemetry elements in " +
|
|
||||||
"alphanumeric format in a simple canvas workspace. " +
|
|
||||||
"Elements can be positioned and sized. " +
|
|
||||||
"Lines, boxes and images can be added as well.",
|
|
||||||
"priority": 899,
|
|
||||||
"delegates": [
|
|
||||||
"telemetry"
|
|
||||||
],
|
|
||||||
"features": "creation",
|
|
||||||
"contains": [
|
|
||||||
{
|
|
||||||
"has": "telemetry"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"model": {
|
|
||||||
"layoutGrid": [64, 16],
|
|
||||||
"composition": []
|
|
||||||
},
|
|
||||||
"properties": [
|
|
||||||
{
|
|
||||||
"name": "Layout Grid",
|
|
||||||
"control": "composite",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"name": "Horizontal grid (px)",
|
|
||||||
"control": "textfield",
|
|
||||||
"cssClass": "l-input-sm l-numeric"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Vertical grid (px)",
|
|
||||||
"control": "textfield",
|
|
||||||
"cssClass": "l-input-sm l-numeric"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"pattern": "^(\\d*[1-9]\\d*)?$",
|
|
||||||
"property": "layoutGrid",
|
|
||||||
"conversion": "number[]"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"views": [
|
|
||||||
"fixed-display"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
});
|
|
||||||
openmct.legacyRegistry.enable("platform/features/fixed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
356
platform/features/layout/bundle.js
Normal file
356
platform/features/layout/bundle.js
Normal file
@ -0,0 +1,356 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* 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/LayoutController",
|
||||||
|
"./src/FixedController",
|
||||||
|
"./src/LayoutCompositionPolicy",
|
||||||
|
'./src/MCTTriggerModal',
|
||||||
|
"./res/templates/layout.html",
|
||||||
|
"./res/templates/fixed.html",
|
||||||
|
"./res/templates/frame.html",
|
||||||
|
"./res/templates/elements/telemetry.html",
|
||||||
|
"./res/templates/elements/box.html",
|
||||||
|
"./res/templates/elements/line.html",
|
||||||
|
"./res/templates/elements/text.html",
|
||||||
|
"./res/templates/elements/image.html",
|
||||||
|
'legacyRegistry'
|
||||||
|
], function (
|
||||||
|
LayoutController,
|
||||||
|
FixedController,
|
||||||
|
LayoutCompositionPolicy,
|
||||||
|
MCTTriggerModal,
|
||||||
|
layoutTemplate,
|
||||||
|
fixedTemplate,
|
||||||
|
frameTemplate,
|
||||||
|
telemetryTemplate,
|
||||||
|
boxTemplate,
|
||||||
|
lineTemplate,
|
||||||
|
textTemplate,
|
||||||
|
imageTemplate,
|
||||||
|
legacyRegistry
|
||||||
|
) {
|
||||||
|
|
||||||
|
legacyRegistry.register("platform/features/layout", {
|
||||||
|
"name": "Layout components.",
|
||||||
|
"description": "Plug in adding Layout capabilities.",
|
||||||
|
"extensions": {
|
||||||
|
"views": [
|
||||||
|
{
|
||||||
|
"key": "layout",
|
||||||
|
"name": "Display Layout",
|
||||||
|
"cssClass": "icon-layout",
|
||||||
|
"type": "layout",
|
||||||
|
"template": layoutTemplate,
|
||||||
|
"editable": true,
|
||||||
|
"uses": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "fixed",
|
||||||
|
"name": "Fixed Position",
|
||||||
|
"cssClass": "icon-box-with-dashed-lines",
|
||||||
|
"type": "telemetry.panel",
|
||||||
|
"template": fixedTemplate,
|
||||||
|
"uses": [
|
||||||
|
"composition"
|
||||||
|
],
|
||||||
|
"toolbar": {
|
||||||
|
"sections": [
|
||||||
|
{
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"method": "add",
|
||||||
|
"cssClass": "icon-plus",
|
||||||
|
"control": "menu-button",
|
||||||
|
"text": "Add",
|
||||||
|
"title": "Add",
|
||||||
|
"description": "Add new items",
|
||||||
|
"options": [
|
||||||
|
{
|
||||||
|
"name": "Box",
|
||||||
|
"cssClass": "icon-box",
|
||||||
|
"key": "fixed.box"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Line",
|
||||||
|
"cssClass": "icon-line-horz",
|
||||||
|
"key": "fixed.line"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Text",
|
||||||
|
"cssClass": "icon-T",
|
||||||
|
"key": "fixed.text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Image",
|
||||||
|
"cssClass": "icon-image",
|
||||||
|
"key": "fixed.image"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"method": "order",
|
||||||
|
"cssClass": "icon-layers",
|
||||||
|
"control": "menu-button",
|
||||||
|
"title": "Layering",
|
||||||
|
"description": "Move the selected object above or below other objects",
|
||||||
|
"options": [
|
||||||
|
{
|
||||||
|
"name": "Move to Top",
|
||||||
|
"cssClass": "icon-arrow-double-up",
|
||||||
|
"key": "top"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Move Up",
|
||||||
|
"cssClass": "icon-arrow-up",
|
||||||
|
"key": "up"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Move Down",
|
||||||
|
"cssClass": "icon-arrow-down",
|
||||||
|
"key": "down"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Move to Bottom",
|
||||||
|
"cssClass": "icon-arrow-double-down",
|
||||||
|
"key": "bottom"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"property": "fill",
|
||||||
|
"cssClass": "icon-paint-bucket",
|
||||||
|
"title": "Fill color",
|
||||||
|
"description": "Set fill color",
|
||||||
|
"control": "color"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"property": "stroke",
|
||||||
|
"cssClass": "icon-line-horz",
|
||||||
|
"title": "Border color",
|
||||||
|
"description": "Set border color",
|
||||||
|
"control": "color"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"property": "color",
|
||||||
|
"cssClass": "icon-T",
|
||||||
|
"title": "Text color",
|
||||||
|
"description": "Set text color",
|
||||||
|
"mandatory": true,
|
||||||
|
"control": "color"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"property": "url",
|
||||||
|
"cssClass": "icon-image",
|
||||||
|
"control": "dialog-button",
|
||||||
|
"title": "Image Properties",
|
||||||
|
"description": "Edit image properties",
|
||||||
|
"dialog": {
|
||||||
|
"control": "textfield",
|
||||||
|
"name": "Image URL",
|
||||||
|
"cssClass": "l-input-lg",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"property": "text",
|
||||||
|
"cssClass": "icon-gear",
|
||||||
|
"control": "dialog-button",
|
||||||
|
"title": "Text Properties",
|
||||||
|
"description": "Edit text properties",
|
||||||
|
"dialog": {
|
||||||
|
"control": "textfield",
|
||||||
|
"name": "Text",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "showTitle",
|
||||||
|
"cssClass": "icon-two-parts-both",
|
||||||
|
"control": "button",
|
||||||
|
"title": "Show title",
|
||||||
|
"description": "Show telemetry element title"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "hideTitle",
|
||||||
|
"cssClass": "icon-two-parts-one-only",
|
||||||
|
"control": "button",
|
||||||
|
"title": "Hide title",
|
||||||
|
"description": "Hide telemetry element title"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"method": "remove",
|
||||||
|
"control": "button",
|
||||||
|
"cssClass": "icon-trash",
|
||||||
|
"title": "Delete",
|
||||||
|
"description": "Delete the selected item"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"representations": [
|
||||||
|
{
|
||||||
|
"key": "frame",
|
||||||
|
"template": frameTemplate
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"directives": [
|
||||||
|
{
|
||||||
|
"key": "mctTriggerModal",
|
||||||
|
"implementation": MCTTriggerModal,
|
||||||
|
"depends": [
|
||||||
|
"$document"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"controllers": [
|
||||||
|
{
|
||||||
|
"key": "LayoutController",
|
||||||
|
"implementation": LayoutController,
|
||||||
|
"depends": [
|
||||||
|
"$scope",
|
||||||
|
"$element",
|
||||||
|
"openmct"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "FixedController",
|
||||||
|
"implementation": FixedController,
|
||||||
|
"depends": [
|
||||||
|
"$scope",
|
||||||
|
"$q",
|
||||||
|
"dialogService",
|
||||||
|
"openmct",
|
||||||
|
"$element"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"templates": [
|
||||||
|
{
|
||||||
|
"key": "fixed.telemetry",
|
||||||
|
"template": telemetryTemplate
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "fixed.box",
|
||||||
|
"template": boxTemplate
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "fixed.line",
|
||||||
|
"template": lineTemplate
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "fixed.text",
|
||||||
|
"template": textTemplate
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "fixed.image",
|
||||||
|
"template": imageTemplate
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"policies": [
|
||||||
|
{
|
||||||
|
"category": "composition",
|
||||||
|
"implementation": LayoutCompositionPolicy
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"toolbars": [
|
||||||
|
{
|
||||||
|
name: "Display Layout Toolbar",
|
||||||
|
key: "layout",
|
||||||
|
description: "A toolbar for objects inside a display layout.",
|
||||||
|
forSelection: function (selection) {
|
||||||
|
// Apply the layout toolbar if the selected object is inside a layout.
|
||||||
|
return (selection && selection[1] && selection[1].context.item.type === 'layout');
|
||||||
|
},
|
||||||
|
toolbar: function (selection) {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
control: "checkbox",
|
||||||
|
name: "Show frame",
|
||||||
|
domainObject: selection[1].context.item,
|
||||||
|
property: "configuration.layout.panels[" + selection[0].context.oldItem.id + "].hasFrame"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"types": [
|
||||||
|
{
|
||||||
|
"key": "layout",
|
||||||
|
"name": "Display Layout",
|
||||||
|
"cssClass": "icon-layout",
|
||||||
|
"description": "Assemble other objects and components together into a reusable screen layout. Working in a simple canvas workspace, simply drag in the objects you want, position and size them. Save your design and view or edit it at any time.",
|
||||||
|
"priority": 900,
|
||||||
|
"features": "creation",
|
||||||
|
"model": {
|
||||||
|
"composition": [],
|
||||||
|
configuration: {
|
||||||
|
layout: {
|
||||||
|
panels: {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"name": "Layout Grid",
|
||||||
|
"control": "composite",
|
||||||
|
"pattern": "^(\\d*[1-9]\\d*)?$",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"name": "Horizontal grid (px)",
|
||||||
|
"control": "textfield",
|
||||||
|
"cssClass": "l-input-sm l-numeric"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Vertical grid (px)",
|
||||||
|
"control": "textfield",
|
||||||
|
"cssClass": "l-input-sm l-numeric"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"key": "layoutGrid",
|
||||||
|
"conversion": "number[]"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Advanced",
|
||||||
|
"control": "textfield",
|
||||||
|
"key": "layoutAdvancedCss",
|
||||||
|
"cssClass": "l-input-lg"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
@ -23,18 +23,18 @@
|
|||||||
ng-controller="FixedController as controller">
|
ng-controller="FixedController as controller">
|
||||||
|
|
||||||
<!-- Background grid -->
|
<!-- Background grid -->
|
||||||
<div class="l-fixed-position__grid-holder l-grid-holder c-grid" ng-click="controller.bypassSelection($event)">
|
<div class="l-grid-holder" ng-click="controller.bypassSelection($event)">
|
||||||
<div class="c-grid__x l-grid l-grid-x"
|
<div class="l-grid l-grid-x"
|
||||||
ng-if="!controller.getGridSize()[0] < 3"
|
ng-if="!controller.getGridSize()[0] < 3"
|
||||||
ng-style="{ 'background-size': controller.getGridSize() [0] + 'px 100%' }"></div>
|
ng-style="{ 'background-size': controller.getGridSize() [0] + 'px 100%' }"></div>
|
||||||
<div class="c-grid__y l-grid l-grid-y"
|
<div class="l-grid l-grid-y"
|
||||||
ng-if="!controller.getGridSize()[1] < 3"
|
ng-if="!controller.getGridSize()[1] < 3"
|
||||||
ng-style="{ 'background-size': '100% ' + controller.getGridSize() [1] + 'px' }"></div>
|
ng-style="{ 'background-size': '100% ' + controller.getGridSize() [1] + 'px' }"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Fixed position elements -->
|
<!-- Fixed position elements -->
|
||||||
<div ng-repeat="element in controller.getElements()"
|
<div ng-repeat="element in controller.getElements()"
|
||||||
class="l-fixed-position-item s-selectable s-moveable is-selectable is-moveable"
|
class="l-fixed-position-item s-selectable s-moveable s-hover-border"
|
||||||
ng-style="element.style"
|
ng-style="element.style"
|
||||||
mct-selectable="controller.getContext(element)"
|
mct-selectable="controller.getContext(element)"
|
||||||
mct-init-select="controller.shouldSelect(element)">
|
mct-init-select="controller.shouldSelect(element)">
|
||||||
@ -44,15 +44,15 @@
|
|||||||
</mct-include>
|
</mct-include>
|
||||||
</div>
|
</div>
|
||||||
<!-- Selection highlight, handles -->
|
<!-- Selection highlight, handles -->
|
||||||
<span class="c-frame-edit" ng-if="controller.isElementSelected()">
|
<span class="s-selected s-moveable" ng-if="controller.isElementSelected()">
|
||||||
<div class="c-frame-edit__move"
|
<div class="l-fixed-position-item t-edit-handle-holder"
|
||||||
mct-drag-down="controller.moveHandle().startDrag()"
|
mct-drag-down="controller.moveHandle().startDrag()"
|
||||||
mct-drag="controller.moveHandle().continueDrag(delta)"
|
mct-drag="controller.moveHandle().continueDrag(delta)"
|
||||||
mct-drag-up="controller.endDrag()"
|
mct-drag-up="controller.endDrag()"
|
||||||
ng-style="controller.getSelectedElementStyle()">
|
ng-style="controller.getSelectedElementStyle()">
|
||||||
</div>
|
</div>
|
||||||
<div ng-repeat="handle in controller.handles()"
|
<div ng-repeat="handle in controller.handles()"
|
||||||
class="c-frame-edit__handle c-frame-edit__handle--nwse"
|
class="l-fixed-position-item-handle edit-corner"
|
||||||
ng-style="handle.style()"
|
ng-style="handle.style()"
|
||||||
mct-drag-down="handle.startDrag()"
|
mct-drag-down="handle.startDrag()"
|
||||||
mct-drag="handle.continueDrag(delta)"
|
mct-drag="handle.continueDrag(delta)"
|
@ -225,8 +225,6 @@ define(
|
|||||||
this.openmct.time.on("bounds", updateDisplayBounds);
|
this.openmct.time.on("bounds", updateDisplayBounds);
|
||||||
|
|
||||||
this.openmct.selection.on('change', this.setSelection.bind(this));
|
this.openmct.selection.on('change', this.setSelection.bind(this));
|
||||||
this.openmct.editor.on('isEditing', this.handleEditing.bind(this));
|
|
||||||
|
|
||||||
this.$element.on('click', this.bypassSelection.bind(this));
|
this.$element.on('click', this.bypassSelection.bind(this));
|
||||||
this.unlisten = this.openmct.objects.observe(this.newDomainObject, '*', function (obj) {
|
this.unlisten = this.openmct.objects.observe(this.newDomainObject, '*', function (obj) {
|
||||||
this.newDomainObject = JSON.parse(JSON.stringify(obj));
|
this.newDomainObject = JSON.parse(JSON.stringify(obj));
|
||||||
@ -423,7 +421,6 @@ define(
|
|||||||
this.openmct.selection.off("change", this.setSelection);
|
this.openmct.selection.off("change", this.setSelection);
|
||||||
this.composition.off('add', this.onCompositionAdd, this);
|
this.composition.off('add', this.onCompositionAdd, this);
|
||||||
this.composition.off('remove', this.onCompositionRemove, this);
|
this.composition.off('remove', this.onCompositionRemove, this);
|
||||||
this.openmct.editor.off('isEditing', this.handleEditing, this);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -709,12 +706,6 @@ define(
|
|||||||
this.openmct.objects.mutate(this.newDomainObject, path, value);
|
this.openmct.objects.mutate(this.newDomainObject, path, value);
|
||||||
};
|
};
|
||||||
|
|
||||||
FixedController.prototype.handleEditing = function (isEditing) {
|
|
||||||
// Listen for edit mode changes and update selection if necessary.
|
|
||||||
// Mainly to ensure fixedController is on the selection context when editing.
|
|
||||||
this.setSelection(this.openmct.selection.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
return FixedController;
|
return FixedController;
|
||||||
}
|
}
|
||||||
);
|
);
|
@ -20,39 +20,32 @@
|
|||||||
* at runtime from the About dialog for additional information.
|
* at runtime from the About dialog for additional information.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
<template>
|
define(
|
||||||
<div>
|
[],
|
||||||
<div class="c-drop-hint c-drop-hint--always-show"
|
function () {
|
||||||
:class="{'is-mouse-over': isMouseOver}"
|
|
||||||
@dragenter="dragenter"
|
|
||||||
@dragleave="dragleave"
|
|
||||||
@drop="dropHandler">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style lang="scss">
|
/**
|
||||||
|
* Defines composition policy for Display Layout objects.
|
||||||
|
* They cannot contain folders.
|
||||||
|
* @constructor
|
||||||
|
* @memberof platform/features/layout
|
||||||
|
* @implements {Policy.<View, DomainObject>}
|
||||||
|
*/
|
||||||
|
function LayoutCompositionPolicy() {
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
LayoutCompositionPolicy.prototype.allow = function (parent, child) {
|
||||||
|
var parentType = parent.getCapability('type');
|
||||||
|
if (parentType.instanceOf('layout') &&
|
||||||
|
child.getCapability('type').instanceOf('folder')) {
|
||||||
|
|
||||||
<script>
|
return false;
|
||||||
export default {
|
|
||||||
props:['index'],
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
isMouseOver: false
|
|
||||||
}
|
}
|
||||||
},
|
|
||||||
methods: {
|
return true;
|
||||||
dragenter() {
|
};
|
||||||
this.isMouseOver = true;
|
|
||||||
},
|
return LayoutCompositionPolicy;
|
||||||
dragleave() {
|
|
||||||
this.isMouseOver = false;
|
|
||||||
},
|
|
||||||
dropHandler(event) {
|
|
||||||
this.$emit('object-drop-to', event, this.index);
|
|
||||||
}
|
}
|
||||||
}
|
);
|
||||||
}
|
|
||||||
</script>
|
|
@ -42,8 +42,7 @@ define(
|
|||||||
},
|
},
|
||||||
"fixed.text": {
|
"fixed.text": {
|
||||||
fill: "transparent",
|
fill: "transparent",
|
||||||
stroke: "transparent",
|
stroke: "transparent"
|
||||||
size: "13px"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
DIALOGS = {
|
DIALOGS = {
|
@ -67,6 +67,10 @@ define(
|
|||||||
*/
|
*/
|
||||||
proxy.size = new AccessorMutator(element, 'size');
|
proxy.size = new AccessorMutator(element, 'size');
|
||||||
|
|
||||||
|
if (proxy.size() === undefined) {
|
||||||
|
proxy.size("13px");
|
||||||
|
}
|
||||||
|
|
||||||
return proxy;
|
return proxy;
|
||||||
}
|
}
|
||||||
|
|
82
platform/features/layout/test/LayoutCompositionPolicySpec.js
Normal file
82
platform/features/layout/test/LayoutCompositionPolicySpec.js
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* 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/LayoutCompositionPolicy"],
|
||||||
|
function (LayoutCompositionPolicy) {
|
||||||
|
describe("Layout's composition policy", function () {
|
||||||
|
var mockChild,
|
||||||
|
mockCandidateObj,
|
||||||
|
mockCandidate,
|
||||||
|
mockContext,
|
||||||
|
candidateType,
|
||||||
|
contextType,
|
||||||
|
policy;
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
mockChild = jasmine.createSpyObj(
|
||||||
|
'childObject',
|
||||||
|
['getCapability']
|
||||||
|
);
|
||||||
|
mockCandidate =
|
||||||
|
jasmine.createSpyObj('candidateType', ['instanceOf']);
|
||||||
|
mockContext =
|
||||||
|
jasmine.createSpyObj('contextType', ['instanceOf']);
|
||||||
|
|
||||||
|
mockCandidateObj = jasmine.createSpyObj('domainObj', [
|
||||||
|
'getCapability'
|
||||||
|
]);
|
||||||
|
mockCandidateObj.getCapability.and.returnValue(mockCandidate);
|
||||||
|
|
||||||
|
mockChild.getCapability.and.returnValue(mockContext);
|
||||||
|
|
||||||
|
mockCandidate.instanceOf.and.callFake(function (t) {
|
||||||
|
return t === candidateType;
|
||||||
|
});
|
||||||
|
mockContext.instanceOf.and.callFake(function (t) {
|
||||||
|
return t === contextType;
|
||||||
|
});
|
||||||
|
|
||||||
|
policy = new LayoutCompositionPolicy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("disallows folders in layouts", function () {
|
||||||
|
candidateType = 'layout';
|
||||||
|
contextType = 'folder';
|
||||||
|
expect(policy.allow(mockCandidateObj, mockChild)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not disallow folders elsewhere", function () {
|
||||||
|
candidateType = 'nonlayout';
|
||||||
|
contextType = 'folder';
|
||||||
|
expect(policy.allow(mockCandidateObj, mockChild)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("allows things other than folders in layouts", function () {
|
||||||
|
candidateType = 'layout';
|
||||||
|
contextType = 'nonfolder';
|
||||||
|
expect(policy.allow(mockCandidateObj, mockChild)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
define([
|
define([
|
||||||
"./src/MCTForm",
|
"./src/MCTForm",
|
||||||
|
"./src/MCTToolbar",
|
||||||
"./src/MCTControl",
|
"./src/MCTControl",
|
||||||
"./src/MCTFileInput",
|
"./src/MCTFileInput",
|
||||||
"./src/FileInputService",
|
"./src/FileInputService",
|
||||||
@ -47,6 +48,7 @@ define([
|
|||||||
'legacyRegistry'
|
'legacyRegistry'
|
||||||
], function (
|
], function (
|
||||||
MCTForm,
|
MCTForm,
|
||||||
|
MCTToolbar,
|
||||||
MCTControl,
|
MCTControl,
|
||||||
MCTFileInput,
|
MCTFileInput,
|
||||||
FileInputService,
|
FileInputService,
|
||||||
@ -81,6 +83,10 @@ define([
|
|||||||
"key": "mctForm",
|
"key": "mctForm",
|
||||||
"implementation": MCTForm
|
"implementation": MCTForm
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"key": "mctToolbar",
|
||||||
|
"implementation": MCTToolbar
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"key": "mctControl",
|
"key": "mctControl",
|
||||||
"implementation": MCTControl,
|
"implementation": MCTControl,
|
||||||
|
49
platform/forms/res/templates/toolbar.html
Normal file
49
platform/forms/res/templates/toolbar.html
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
<!--
|
||||||
|
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.
|
||||||
|
-->
|
||||||
|
<form novalidate>
|
||||||
|
<div class="tool-bar btn-bar contents abs">
|
||||||
|
<span ng-repeat="item in structure">
|
||||||
|
<span ng-if="item.control === 'divider'" class="l-control-group">
|
||||||
|
</span>
|
||||||
|
<ng-form ng-class="{ 'input-labeled': item.name }"
|
||||||
|
ng-hide="item.hidden"
|
||||||
|
ng-if="item.control !== 'divider'"
|
||||||
|
class="inline"
|
||||||
|
title="{{item.description}}"
|
||||||
|
name="mctFormInner">
|
||||||
|
|
||||||
|
<label ng-if="item.name">
|
||||||
|
{{item.name}}:
|
||||||
|
</label>
|
||||||
|
<mct-control key="item.control"
|
||||||
|
ng-class="{ disabled: item.disabled }"
|
||||||
|
ng-model="ngModel"
|
||||||
|
ng-required="item.required"
|
||||||
|
ng-pattern="getRegExp(item.pattern)"
|
||||||
|
options="item.options"
|
||||||
|
structure="item"
|
||||||
|
field="item.key">
|
||||||
|
</mct-control>
|
||||||
|
</ng-form>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</form>
|
69
platform/forms/src/MCTToolbar.js
Normal file
69
platform/forms/src/MCTToolbar.js
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2014-2018, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module defining MCTForm. Created by vwoeltje on 11/10/14.
|
||||||
|
*/
|
||||||
|
define(
|
||||||
|
[
|
||||||
|
"./MCTForm",
|
||||||
|
"../res/templates/toolbar.html",
|
||||||
|
"./controllers/ToolbarController"
|
||||||
|
],
|
||||||
|
function (
|
||||||
|
MCTForm,
|
||||||
|
toolbarTemplate,
|
||||||
|
ToolbarController
|
||||||
|
) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The mct-toolbar directive allows generation of displayable
|
||||||
|
* forms based on a declarative description of the form's
|
||||||
|
* structure.
|
||||||
|
*
|
||||||
|
* This directive accepts three attributes:
|
||||||
|
*
|
||||||
|
* * `ng-model`: The model for the form; where user input
|
||||||
|
* will be stored.
|
||||||
|
* * `structure`: The declarative structure of the toolbar.
|
||||||
|
* Describes what controls should be shown and where
|
||||||
|
* their values should be read/written in the model.
|
||||||
|
* * `name`: The name under which to expose the form's
|
||||||
|
* dirty/valid state. This is similar to ng-form's use
|
||||||
|
* of name, except this will be made available in the
|
||||||
|
* parent scope.
|
||||||
|
*
|
||||||
|
* @memberof platform/forms
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function MCTToolbar() {
|
||||||
|
// Use Directive Definition Object from mct-form,
|
||||||
|
// but use the toolbar's template and controller instead.
|
||||||
|
var ddo = new MCTForm();
|
||||||
|
ddo.template = toolbarTemplate;
|
||||||
|
ddo.controller = ['$scope', 'openmct', ToolbarController];
|
||||||
|
return ddo;
|
||||||
|
}
|
||||||
|
|
||||||
|
return MCTToolbar;
|
||||||
|
}
|
||||||
|
);
|
84
platform/forms/src/controllers/ToolbarController.js
Normal file
84
platform/forms/src/controllers/ToolbarController.js
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
define(
|
||||||
|
[
|
||||||
|
'../../../commonUI/edit/src/representers/EditToolbar'
|
||||||
|
],
|
||||||
|
function (EditToolbar) {
|
||||||
|
|
||||||
|
// Default ng-pattern; any non whitespace
|
||||||
|
var NON_WHITESPACE = /\S/;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controller for mct-toolbar directive.
|
||||||
|
*
|
||||||
|
* @memberof platform/forms
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function ToolbarController($scope, openmct) {
|
||||||
|
var regexps = [];
|
||||||
|
|
||||||
|
// ng-pattern seems to want a RegExp, and not a
|
||||||
|
// string (despite what documentation says) but
|
||||||
|
// we want toolbar structure to be JSON-expressible,
|
||||||
|
// so we make RegExp's from strings as-needed
|
||||||
|
function getRegExp(pattern) {
|
||||||
|
// If undefined, don't apply a pattern
|
||||||
|
if (!pattern) {
|
||||||
|
return NON_WHITESPACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Just echo if it's already a regexp
|
||||||
|
if (pattern instanceof RegExp) {
|
||||||
|
return pattern;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, assume a string
|
||||||
|
// Cache for easy lookup later (so we don't
|
||||||
|
// creat a new RegExp every digest cycle)
|
||||||
|
if (!regexps[pattern]) {
|
||||||
|
regexps[pattern] = new RegExp(pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
return regexps[pattern];
|
||||||
|
}
|
||||||
|
|
||||||
|
this.openmct = openmct;
|
||||||
|
this.$scope = $scope;
|
||||||
|
$scope.editToolbar = {};
|
||||||
|
$scope.getRegExp = getRegExp;
|
||||||
|
|
||||||
|
$scope.$on("$destroy", this.destroy.bind(this));
|
||||||
|
openmct.selection.on('change', this.handleSelection.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
ToolbarController.prototype.handleSelection = function (selection) {
|
||||||
|
var domainObject = selection[0].context.oldItem;
|
||||||
|
var element = selection[0].context.elementProxy;
|
||||||
|
|
||||||
|
if ((domainObject && domainObject === this.selectedObject) || (element && element === this.selectedObject)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.selectedObject = domainObject || element;
|
||||||
|
|
||||||
|
if (this.editToolbar) {
|
||||||
|
this.editToolbar.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
var structure = this.openmct.toolbars.get(selection) || [];
|
||||||
|
this.editToolbar = new EditToolbar(this.$scope, this.openmct, structure);
|
||||||
|
this.$scope.$parent.editToolbar = this.editToolbar;
|
||||||
|
this.$scope.$parent.editToolbar.structure = this.editToolbar.getStructure();
|
||||||
|
this.$scope.$parent.editToolbar.state = this.editToolbar.getState();
|
||||||
|
|
||||||
|
setTimeout(function () {
|
||||||
|
this.$scope.$apply();
|
||||||
|
}.bind(this));
|
||||||
|
};
|
||||||
|
|
||||||
|
ToolbarController.prototype.destroy = function () {
|
||||||
|
this.openmct.selection.off("change", this.handleSelection);
|
||||||
|
};
|
||||||
|
|
||||||
|
return ToolbarController;
|
||||||
|
}
|
||||||
|
);
|
112
platform/forms/test/MCTToolbarSpec.js
Normal file
112
platform/forms/test/MCTToolbarSpec.js
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* 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/MCTToolbar"],
|
||||||
|
function (MCTToolbar) {
|
||||||
|
|
||||||
|
describe("The mct-toolbar directive", function () {
|
||||||
|
var mockScope,
|
||||||
|
mockOpenMCT,
|
||||||
|
mockSelection,
|
||||||
|
mctToolbar;
|
||||||
|
|
||||||
|
function installController() {
|
||||||
|
var Controller = mctToolbar.controller[2];
|
||||||
|
return new Controller(mockScope, mockOpenMCT);
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
mockScope = jasmine.createSpyObj("$scope", [
|
||||||
|
"$watch",
|
||||||
|
"$on"
|
||||||
|
]);
|
||||||
|
mockScope.$parent = {};
|
||||||
|
mockSelection = jasmine.createSpyObj("selection", [
|
||||||
|
'on',
|
||||||
|
'off'
|
||||||
|
]);
|
||||||
|
mockOpenMCT = {
|
||||||
|
selection: mockSelection
|
||||||
|
};
|
||||||
|
mctToolbar = new MCTToolbar();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("is restricted to elements", function () {
|
||||||
|
expect(mctToolbar.restrict).toEqual("E");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("listens for selection change event", function () {
|
||||||
|
installController();
|
||||||
|
|
||||||
|
expect(mockOpenMCT.selection.on).toHaveBeenCalledWith(
|
||||||
|
"change",
|
||||||
|
jasmine.any(Function)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("allows strings to be converted to RegExps", function () {
|
||||||
|
// This is needed to support ng-pattern in the template
|
||||||
|
installController();
|
||||||
|
|
||||||
|
// Should have added getRegExp to the scope,
|
||||||
|
// to convert strings to regular expressions
|
||||||
|
expect(mockScope.getRegExp("^\\d+$")).toEqual(/^\d+$/);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("returns the same regexp instance for the same string", function () {
|
||||||
|
// Don't want new instances each digest cycle, for performance
|
||||||
|
var strRegExp = "^[a-z]\\d+$",
|
||||||
|
regExp;
|
||||||
|
|
||||||
|
// Add getRegExp to scope
|
||||||
|
installController();
|
||||||
|
regExp = mockScope.getRegExp(strRegExp);
|
||||||
|
|
||||||
|
// Same object instance each time...
|
||||||
|
expect(mockScope.getRegExp(strRegExp)).toBe(regExp);
|
||||||
|
expect(mockScope.getRegExp(strRegExp)).toBe(regExp);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("passes RegExp objects through untouched", function () {
|
||||||
|
// Permit using forms to simply provide their own RegExp object
|
||||||
|
var regExp = /^\d+[a-d]$/;
|
||||||
|
|
||||||
|
// Add getRegExp to scope
|
||||||
|
installController();
|
||||||
|
|
||||||
|
// Should have added getRegExp to the scope,
|
||||||
|
// to convert strings to regular expressions
|
||||||
|
expect(mockScope.getRegExp(regExp)).toBe(regExp);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("passes a non-whitespace regexp when no pattern is defined", function () {
|
||||||
|
// If no pattern is supplied, ng-pattern should match anything
|
||||||
|
installController();
|
||||||
|
expect(mockScope.getRegExp()).toEqual(/\S/);
|
||||||
|
expect(mockScope.getRegExp(undefined)).toEqual(/\S/);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
59
src/MCT.js
59
src/MCT.js
@ -26,7 +26,6 @@ define([
|
|||||||
'uuid',
|
'uuid',
|
||||||
'./defaultRegistry',
|
'./defaultRegistry',
|
||||||
'./api/api',
|
'./api/api',
|
||||||
'./api/overlays/OverlayAPI',
|
|
||||||
'./selection/Selection',
|
'./selection/Selection',
|
||||||
'./api/objects/object-utils',
|
'./api/objects/object-utils',
|
||||||
'./plugins/plugins',
|
'./plugins/plugins',
|
||||||
@ -41,8 +40,7 @@ define([
|
|||||||
'./styles-new/core.scss',
|
'./styles-new/core.scss',
|
||||||
'./styles-new/notebook.scss',
|
'./styles-new/notebook.scss',
|
||||||
'./ui/components/layout/Layout.vue',
|
'./ui/components/layout/Layout.vue',
|
||||||
'../platform/core/src/objects/DomainObjectImpl',
|
'./ui/overlayService/overlayService',
|
||||||
'../platform/core/src/capabilities/ContextualDomainObject',
|
|
||||||
'vue'
|
'vue'
|
||||||
], function (
|
], function (
|
||||||
EventEmitter,
|
EventEmitter,
|
||||||
@ -50,7 +48,6 @@ define([
|
|||||||
uuid,
|
uuid,
|
||||||
defaultRegistry,
|
defaultRegistry,
|
||||||
api,
|
api,
|
||||||
OverlayAPI,
|
|
||||||
Selection,
|
Selection,
|
||||||
objectUtils,
|
objectUtils,
|
||||||
plugins,
|
plugins,
|
||||||
@ -65,8 +62,7 @@ define([
|
|||||||
coreStyles,
|
coreStyles,
|
||||||
NotebookStyles,
|
NotebookStyles,
|
||||||
Layout,
|
Layout,
|
||||||
DomainObjectImpl,
|
OverlayService,
|
||||||
ContextualDomainObject,
|
|
||||||
Vue
|
Vue
|
||||||
) {
|
) {
|
||||||
/**
|
/**
|
||||||
@ -189,6 +185,15 @@ define([
|
|||||||
*/
|
*/
|
||||||
this.types = new api.TypeRegistry();
|
this.types = new api.TypeRegistry();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utilities for attaching common behaviors to views.
|
||||||
|
*
|
||||||
|
* @type {module:openmct.GestureAPI}
|
||||||
|
* @memberof module:openmct.MCT#
|
||||||
|
* @name gestures
|
||||||
|
*/
|
||||||
|
this.gestures = new api.GestureAPI();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An interface for interacting with domain objects and the domain
|
* An interface for interacting with domain objects and the domain
|
||||||
* object hierarchy.
|
* object hierarchy.
|
||||||
@ -220,11 +225,11 @@ define([
|
|||||||
|
|
||||||
this.notifications = new api.NotificationAPI();
|
this.notifications = new api.NotificationAPI();
|
||||||
|
|
||||||
|
this.Dialog = api.Dialog;
|
||||||
|
|
||||||
this.editor = new api.EditorAPI.default(this);
|
this.editor = new api.EditorAPI.default(this);
|
||||||
|
|
||||||
this.overlays = new OverlayAPI.default();
|
this.OverlayService = new OverlayService();
|
||||||
|
|
||||||
this.contextMenu = new api.ContextMenuRegistry();
|
|
||||||
|
|
||||||
this.legacyRegistry = defaultRegistry;
|
this.legacyRegistry = defaultRegistry;
|
||||||
this.install(this.plugins.Plot());
|
this.install(this.plugins.Plot());
|
||||||
@ -247,42 +252,6 @@ define([
|
|||||||
this.legacyBundle.extensions[category].push(extension);
|
this.legacyBundle.extensions[category].push(extension);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Return a legacy object, for compatibility purposes only. This method
|
|
||||||
* will be deprecated and removed in the future.
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
MCT.prototype.legacyObject = function (domainObject) {
|
|
||||||
let capabilityService = this.$injector.get('capabilityService');
|
|
||||||
|
|
||||||
function instantiate(model, keyString) {
|
|
||||||
var capabilities = capabilityService.getCapabilities(model, keyString);
|
|
||||||
model.id = keyString;
|
|
||||||
return new DomainObjectImpl(keyString, model, capabilities);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Array.isArray(domainObject)) {
|
|
||||||
// an array of domain objects. [object, ...ancestors] representing
|
|
||||||
// a single object with a given chain of ancestors. We instantiate
|
|
||||||
// as a single contextual domain object.
|
|
||||||
return domainObject
|
|
||||||
.map((o) => {
|
|
||||||
let keyString = objectUtils.makeKeyString(o.identifier);
|
|
||||||
let oldModel = objectUtils.toOldFormat(o);
|
|
||||||
return instantiate(oldModel, keyString);
|
|
||||||
})
|
|
||||||
.reverse()
|
|
||||||
.reduce((parent, child) => {
|
|
||||||
return new ContextualDomainObject(child, parent);
|
|
||||||
});
|
|
||||||
|
|
||||||
} else {
|
|
||||||
let keyString = objectUtils.makeKeyString(domainObject.identifier);
|
|
||||||
let oldModel = objectUtils.toOldFormat(domainObject);
|
|
||||||
return instantiate(oldModel, keyString);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set path to where assets are hosted. This should be the path to main.js.
|
* Set path to where assets are hosted. This should be the path to main.js.
|
||||||
* @memberof module:openmct.MCT#
|
* @memberof module:openmct.MCT#
|
||||||
|
@ -1,57 +0,0 @@
|
|||||||
import { timingSafeEqual } from "crypto";
|
|
||||||
|
|
||||||
/*****************************************************************************
|
|
||||||
* 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.
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
export default class LegacyContextMenuAction {
|
|
||||||
constructor(openmct, LegacyAction) {
|
|
||||||
this.openmct = openmct;
|
|
||||||
this.name = LegacyAction.definition.name;
|
|
||||||
this.description = LegacyAction.definition.description;
|
|
||||||
this.cssClass = LegacyAction.definition.cssClass;
|
|
||||||
this.LegacyAction = LegacyAction;
|
|
||||||
}
|
|
||||||
|
|
||||||
appliesTo(objectPath) {
|
|
||||||
let legacyObject = this.openmct.legacyObject(objectPath);
|
|
||||||
return this.LegacyAction.appliesTo({
|
|
||||||
domainObject: legacyObject
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
invoke(objectPath) {
|
|
||||||
let context = {
|
|
||||||
category: 'contextual',
|
|
||||||
domainObject: this.openmct.legacyObject(objectPath)
|
|
||||||
}
|
|
||||||
let legacyAction = new this.LegacyAction(context);
|
|
||||||
|
|
||||||
if (!legacyAction.getMetadata) {
|
|
||||||
let metadata = Object.create(this.LegacyAction.definition);
|
|
||||||
metadata.context = context;
|
|
||||||
legacyAction.getMetadata = function () {
|
|
||||||
return metadata;
|
|
||||||
}.bind(legacyAction);
|
|
||||||
}
|
|
||||||
legacyAction.perform();
|
|
||||||
}
|
|
||||||
}
|
|
@ -28,6 +28,7 @@ define([
|
|||||||
'./services/Instantiate',
|
'./services/Instantiate',
|
||||||
'./services/MissingModelCompatibilityDecorator',
|
'./services/MissingModelCompatibilityDecorator',
|
||||||
'./capabilities/APICapabilityDecorator',
|
'./capabilities/APICapabilityDecorator',
|
||||||
|
'./policies/AdapterCompositionPolicy',
|
||||||
'./policies/AdaptedViewPolicy',
|
'./policies/AdaptedViewPolicy',
|
||||||
'./runs/AlternateCompositionInitializer',
|
'./runs/AlternateCompositionInitializer',
|
||||||
'./runs/TimeSettingsURLHandler',
|
'./runs/TimeSettingsURLHandler',
|
||||||
@ -35,9 +36,7 @@ define([
|
|||||||
'./runs/LegacyTelemetryProvider',
|
'./runs/LegacyTelemetryProvider',
|
||||||
'./runs/RegisterLegacyTypes',
|
'./runs/RegisterLegacyTypes',
|
||||||
'./services/LegacyObjectAPIInterceptor',
|
'./services/LegacyObjectAPIInterceptor',
|
||||||
'./views/installLegacyViews',
|
'./views/installLegacyViews'
|
||||||
'./policies/legacyCompositionPolicyAdapter',
|
|
||||||
'./actions/LegacyActionAdapter'
|
|
||||||
], function (
|
], function (
|
||||||
legacyRegistry,
|
legacyRegistry,
|
||||||
ActionDialogDecorator,
|
ActionDialogDecorator,
|
||||||
@ -46,6 +45,7 @@ define([
|
|||||||
Instantiate,
|
Instantiate,
|
||||||
MissingModelCompatibilityDecorator,
|
MissingModelCompatibilityDecorator,
|
||||||
APICapabilityDecorator,
|
APICapabilityDecorator,
|
||||||
|
AdapterCompositionPolicy,
|
||||||
AdaptedViewPolicy,
|
AdaptedViewPolicy,
|
||||||
AlternateCompositionInitializer,
|
AlternateCompositionInitializer,
|
||||||
TimeSettingsURLHandler,
|
TimeSettingsURLHandler,
|
||||||
@ -53,9 +53,7 @@ define([
|
|||||||
LegacyTelemetryProvider,
|
LegacyTelemetryProvider,
|
||||||
RegisterLegacyTypes,
|
RegisterLegacyTypes,
|
||||||
LegacyObjectAPIInterceptor,
|
LegacyObjectAPIInterceptor,
|
||||||
installLegacyViews,
|
installLegacyViews
|
||||||
legacyCompositionPolicyAdapter,
|
|
||||||
LegacyActionAdapter
|
|
||||||
) {
|
) {
|
||||||
legacyRegistry.register('src/adapter', {
|
legacyRegistry.register('src/adapter', {
|
||||||
"extensions": {
|
"extensions": {
|
||||||
@ -119,6 +117,11 @@ define([
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
policies: [
|
policies: [
|
||||||
|
{
|
||||||
|
category: "composition",
|
||||||
|
implementation: AdapterCompositionPolicy,
|
||||||
|
depends: ["openmct"]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
category: "view",
|
category: "view",
|
||||||
implementation: AdaptedViewPolicy,
|
implementation: AdaptedViewPolicy,
|
||||||
@ -165,19 +168,6 @@ define([
|
|||||||
"types[]",
|
"types[]",
|
||||||
"openmct"
|
"openmct"
|
||||||
]
|
]
|
||||||
},
|
|
||||||
{
|
|
||||||
implementation: legacyCompositionPolicyAdapter.default,
|
|
||||||
depends: [
|
|
||||||
"openmct"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
implementation: LegacyActionAdapter.default,
|
|
||||||
depends: [
|
|
||||||
"openmct",
|
|
||||||
"actions[]"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
licenses: [
|
licenses: [
|
||||||
|
@ -20,23 +20,20 @@
|
|||||||
* at runtime from the About dialog for additional information.
|
* at runtime from the About dialog for additional information.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
define([
|
define([], function () {
|
||||||
'./tabs'
|
function AdapterCompositionPolicy(openmct) {
|
||||||
], function (
|
this.openmct = openmct;
|
||||||
Tabs
|
|
||||||
) {
|
|
||||||
return function plugin() {
|
|
||||||
return function install(openmct) {
|
|
||||||
openmct.objectViews.addProvider(new Tabs(openmct));
|
|
||||||
|
|
||||||
openmct.types.addType('tabs', {
|
|
||||||
name: "Tabs View",
|
|
||||||
creatable: true,
|
|
||||||
cssClass: 'icon-tabs-view',
|
|
||||||
initialize(domainObject) {
|
|
||||||
domainObject.composition = [];
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
};
|
AdapterCompositionPolicy.prototype.allow = function (
|
||||||
|
parent,
|
||||||
|
child
|
||||||
|
) {
|
||||||
|
return this.openmct.composition.checkPolicy(
|
||||||
|
parent,
|
||||||
|
child
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
return AdapterCompositionPolicy;
|
||||||
});
|
});
|
@ -1,42 +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.
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
export default function legacyCompositionPolicyAdapter(openmct) {
|
|
||||||
const instantiate = this.openmct.$injector.get('instantiate');
|
|
||||||
const policyService = this.openmct.$injector.get('policyService');
|
|
||||||
|
|
||||||
openmct.composition.addPolicy((parent, child) => {
|
|
||||||
|
|
||||||
let parentId = this.openmct.objects.makeKeyString(parent.identifier);
|
|
||||||
let childId = this.openmct.objects.makeKeyString(child.identifier);
|
|
||||||
|
|
||||||
let legacyParent = instantiate(parent, parentId);
|
|
||||||
let legacyChild = instantiate(child, childId);
|
|
||||||
let result = policyService.allow(
|
|
||||||
'composition',
|
|
||||||
legacyParent,
|
|
||||||
legacyChild
|
|
||||||
);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
});
|
|
||||||
}
|
|
@ -36,9 +36,6 @@ export default class Editor extends EventEmitter {
|
|||||||
* or finish() are called.
|
* or finish() are called.
|
||||||
*/
|
*/
|
||||||
edit() {
|
edit() {
|
||||||
if (this.editing === true) {
|
|
||||||
throw "Already editing";
|
|
||||||
}
|
|
||||||
this.editing = true;
|
this.editing = true;
|
||||||
this.getTransactionService().startTransaction();
|
this.getTransactionService().startTransaction();
|
||||||
this.emit('isEditing', true);
|
this.emit('isEditing', true);
|
||||||
|
@ -25,10 +25,11 @@ define([
|
|||||||
'./objects/ObjectAPI',
|
'./objects/ObjectAPI',
|
||||||
'./composition/CompositionAPI',
|
'./composition/CompositionAPI',
|
||||||
'./types/TypeRegistry',
|
'./types/TypeRegistry',
|
||||||
|
'./ui/Dialog',
|
||||||
|
'./ui/GestureAPI',
|
||||||
'./telemetry/TelemetryAPI',
|
'./telemetry/TelemetryAPI',
|
||||||
'./indicators/IndicatorAPI',
|
'./indicators/IndicatorAPI',
|
||||||
'./notifications/NotificationAPI',
|
'./notifications/NotificationAPI',
|
||||||
'./contextMenu/ContextMenuAPI',
|
|
||||||
'./Editor'
|
'./Editor'
|
||||||
|
|
||||||
], function (
|
], function (
|
||||||
@ -36,21 +37,23 @@ define([
|
|||||||
ObjectAPI,
|
ObjectAPI,
|
||||||
CompositionAPI,
|
CompositionAPI,
|
||||||
TypeRegistry,
|
TypeRegistry,
|
||||||
|
Dialog,
|
||||||
|
GestureAPI,
|
||||||
TelemetryAPI,
|
TelemetryAPI,
|
||||||
IndicatorAPI,
|
IndicatorAPI,
|
||||||
NotificationAPI,
|
NotificationAPI,
|
||||||
ContextMenuAPI,
|
|
||||||
EditorAPI
|
EditorAPI
|
||||||
) {
|
) {
|
||||||
return {
|
return {
|
||||||
TimeAPI: TimeAPI,
|
TimeAPI: TimeAPI,
|
||||||
ObjectAPI: ObjectAPI,
|
ObjectAPI: ObjectAPI,
|
||||||
CompositionAPI: CompositionAPI,
|
CompositionAPI: CompositionAPI,
|
||||||
|
Dialog: Dialog,
|
||||||
TypeRegistry: TypeRegistry,
|
TypeRegistry: TypeRegistry,
|
||||||
|
GestureAPI: GestureAPI,
|
||||||
TelemetryAPI: TelemetryAPI,
|
TelemetryAPI: TelemetryAPI,
|
||||||
IndicatorAPI: IndicatorAPI,
|
IndicatorAPI: IndicatorAPI,
|
||||||
NotificationAPI: NotificationAPI.default,
|
NotificationAPI: NotificationAPI.default,
|
||||||
EditorAPI: EditorAPI,
|
EditorAPI: EditorAPI
|
||||||
ContextMenuRegistry: ContextMenuAPI.default
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
@ -44,7 +44,7 @@ define([
|
|||||||
function CompositionAPI(publicAPI) {
|
function CompositionAPI(publicAPI) {
|
||||||
this.registry = [];
|
this.registry = [];
|
||||||
this.policies = [];
|
this.policies = [];
|
||||||
this.addProvider(new DefaultCompositionProvider(publicAPI, this));
|
this.addProvider(new DefaultCompositionProvider(publicAPI));
|
||||||
this.publicAPI = publicAPI;
|
this.publicAPI = publicAPI;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,11 +177,7 @@ define([
|
|||||||
CompositionCollection.prototype.load = function () {
|
CompositionCollection.prototype.load = function () {
|
||||||
return this.provider.load(this.domainObject)
|
return this.provider.load(this.domainObject)
|
||||||
.then(function (children) {
|
.then(function (children) {
|
||||||
return Promise.all(children.map((c) => this.publicAPI.objects.get(c)));
|
return Promise.all(children.map(this.onProviderAdd, this));
|
||||||
}.bind(this))
|
|
||||||
.then(function (childObjects) {
|
|
||||||
childObjects.forEach(c => this.add(c, true));
|
|
||||||
return childObjects;
|
|
||||||
}.bind(this))
|
}.bind(this))
|
||||||
.then(function (children) {
|
.then(function (children) {
|
||||||
this.emit('load');
|
this.emit('load');
|
||||||
|
@ -43,34 +43,9 @@ define([
|
|||||||
* @memberof module:openmct
|
* @memberof module:openmct
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function DefaultCompositionProvider(publicAPI, compositionAPI) {
|
function DefaultCompositionProvider(publicAPI) {
|
||||||
this.publicAPI = publicAPI;
|
this.publicAPI = publicAPI;
|
||||||
this.listeningTo = {};
|
this.listeningTo = {};
|
||||||
|
|
||||||
this.cannotContainDuplicates = this.cannotContainDuplicates.bind(this);
|
|
||||||
this.cannotContainItself = this.cannotContainItself.bind(this);
|
|
||||||
|
|
||||||
compositionAPI.addPolicy(this.cannotContainDuplicates);
|
|
||||||
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
|
|
||||||
*/
|
|
||||||
DefaultCompositionProvider.prototype.cannotContainItself = function (parent, child) {
|
|
||||||
return !(parent.identifier.namespace === child.identifier.namespace &&
|
|
||||||
parent.identifier.key === child.identifier.key);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -228,7 +203,7 @@ define([
|
|||||||
}
|
}
|
||||||
|
|
||||||
var oldComposition = listeners.composition.map(objectUtils.makeKeyString);
|
var oldComposition = listeners.composition.map(objectUtils.makeKeyString);
|
||||||
var newComposition = oldDomainObject.getModel().composition.map(objectUtils.makeKeyString);
|
var newComposition = oldDomainObject.getModel().composition;
|
||||||
|
|
||||||
var added = _.difference(newComposition, oldComposition).map(objectUtils.parseKeyString);
|
var added = _.difference(newComposition, oldComposition).map(objectUtils.parseKeyString);
|
||||||
var removed = _.difference(oldComposition, newComposition).map(objectUtils.parseKeyString);
|
var removed = _.difference(oldComposition, newComposition).map(objectUtils.parseKeyString);
|
||||||
|
@ -1,20 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="c-menu">
|
|
||||||
<ul>
|
|
||||||
<li v-for="action in actions"
|
|
||||||
:key="action.name"
|
|
||||||
:class="action.cssClass"
|
|
||||||
:title="action.description"
|
|
||||||
@click="action.invoke(objectPath)">
|
|
||||||
{{ action.name }}
|
|
||||||
</li>
|
|
||||||
<li v-if="actions.length === 0">No actions defined.</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
inject: ['actions', 'objectPath']
|
|
||||||
}
|
|
||||||
</script>
|
|
@ -1,141 +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 ContextMenuComponent from './ContextMenu.vue';
|
|
||||||
import Vue from 'vue';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The ContextMenuAPI allows the addition of new context menu actions, and for the context menu to be launched from
|
|
||||||
* custom HTML elements.
|
|
||||||
* @interface ContextMenuAPI
|
|
||||||
* @memberof module:openmct
|
|
||||||
*/
|
|
||||||
class ContextMenuAPI {
|
|
||||||
constructor() {
|
|
||||||
this._allActions = [];
|
|
||||||
this._activeContextMenu = undefined;
|
|
||||||
|
|
||||||
this._hideActiveContextMenu = this._hideActiveContextMenu.bind(this);
|
|
||||||
this.registerAction = this.registerAction.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Defines an item to be added to context menus. Allows specification of text, appearance, and behavior when
|
|
||||||
* selected. Applicabilioty can be restricted by specification of an `appliesTo` function.
|
|
||||||
*
|
|
||||||
* @interface ContextMenuAction
|
|
||||||
* @memberof module:openmct
|
|
||||||
* @property {string} name the human-readable name of this view
|
|
||||||
* @property {string} description a longer-form description (typically
|
|
||||||
* a single sentence or short paragraph) of this kind of view
|
|
||||||
* @property {string} cssClass the CSS class to apply to labels for this
|
|
||||||
* view (to add icons, for instance)
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* @method appliesTo
|
|
||||||
* @memberof module:openmct.ContextMenuAction#
|
|
||||||
* @param {DomainObject[]} objectPath the path of the object that the context menu has been invoked on.
|
|
||||||
* @returns {boolean} true if the action applies to the objects specified in the 'objectPath', otherwise false.
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* Code to be executed when the action is selected from a context menu
|
|
||||||
* @method invoke
|
|
||||||
* @memberof module:openmct.ContextMenuAction#
|
|
||||||
* @param {DomainObject[]} objectPath the path of the object to invoke the action on.
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* @param {ContextMenuAction} actionDefinition
|
|
||||||
*/
|
|
||||||
registerAction(actionDefinition) {
|
|
||||||
this._allActions.push(actionDefinition);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_showContextMenuForObjectPath(objectPath, x, y) {
|
|
||||||
let applicableActions = this._allActions.filter(
|
|
||||||
(action) => action.appliesTo(objectPath));
|
|
||||||
|
|
||||||
if (this._activeContextMenu) {
|
|
||||||
this._hideActiveContextMenu();
|
|
||||||
}
|
|
||||||
|
|
||||||
this._activeContextMenu = this._createContextMenuForObject(objectPath, applicableActions);
|
|
||||||
this._activeContextMenu.$mount();
|
|
||||||
document.body.appendChild(this._activeContextMenu.$el);
|
|
||||||
|
|
||||||
let position = this._calculatePopupPosition(x, y, this._activeContextMenu.$el);
|
|
||||||
this._activeContextMenu.$el.style.left = `${position.x}px`;
|
|
||||||
this._activeContextMenu.$el.style.top = `${position.y}px`;
|
|
||||||
|
|
||||||
document.addEventListener('click', this._hideActiveContextMenu);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_calculatePopupPosition(eventPosX, eventPosY, menuElement) {
|
|
||||||
let menuDimensions = menuElement.getBoundingClientRect();
|
|
||||||
let overflowX = (eventPosX + menuDimensions.width) - document.body.clientWidth;
|
|
||||||
let overflowY = (eventPosY + menuDimensions.height) - document.body.clientHeight;
|
|
||||||
|
|
||||||
if (overflowX > 0) {
|
|
||||||
eventPosX = eventPosX - overflowX;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (overflowY > 0) {
|
|
||||||
eventPosY = eventPosY - overflowY;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
x: eventPosX,
|
|
||||||
y: eventPosY
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_hideActiveContextMenu() {
|
|
||||||
document.removeEventListener('click', this._hideActiveContextMenu);
|
|
||||||
document.body.removeChild(this._activeContextMenu.$el);
|
|
||||||
this._activeContextMenu.$destroy();
|
|
||||||
this._activeContextMenu = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_createContextMenuForObject(objectPath, actions) {
|
|
||||||
return new Vue({
|
|
||||||
components: {
|
|
||||||
ContextMenu: ContextMenuComponent
|
|
||||||
},
|
|
||||||
provide: {
|
|
||||||
actions: actions,
|
|
||||||
objectPath: objectPath
|
|
||||||
},
|
|
||||||
template: '<ContextMenu></ContextMenu>'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export default ContextMenuAPI;
|
|
@ -20,18 +20,29 @@
|
|||||||
* at runtime from the About dialog for additional information.
|
* at runtime from the About dialog for additional information.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
import LegacyContextMenuAction from './LegacyContextMenuAction';
|
import EventEmitter from 'EventEmitter';
|
||||||
|
export default class MCTNotification extends EventEmitter {
|
||||||
|
|
||||||
export default function LegacyActionAdapter(openmct, legacyActions) {
|
constructor(notificationModel, notificationAPI) {
|
||||||
function contextualCategoryOnly(action) {
|
super();
|
||||||
if (action.category === 'contextual') {
|
this.notifications = notificationAPI;
|
||||||
return true;
|
this.model = notificationModel;
|
||||||
}
|
this.initializeModel();
|
||||||
console.warn(`DEPRECATION WARNING: Action ${action.definition.key} in bundle ${action.bundle.path} is non-contextual and should be migrated.`);
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
legacyActions.filter(contextualCategoryOnly)
|
minimize() {
|
||||||
.map(LegacyAction => new LegacyContextMenuAction(openmct, LegacyAction))
|
this.notifications.minimize(this);
|
||||||
.forEach(openmct.contextMenu.registerAction);
|
}
|
||||||
|
|
||||||
|
dismiss() {
|
||||||
|
this.notifications.dismiss(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
dismissOrMinimize() {
|
||||||
|
this.notifications.dismissOrMinimize(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
initializeModel() {
|
||||||
|
this.model.minimized = this.model.minimized || false;
|
||||||
|
}
|
||||||
}
|
}
|
@ -32,6 +32,7 @@
|
|||||||
*/
|
*/
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import EventEmitter from 'EventEmitter';
|
import EventEmitter from 'EventEmitter';
|
||||||
|
import MCTNotification from './MCTNotification.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A representation of a banner notification. Banner notifications
|
* A representation of a banner notification. Banner notifications
|
||||||
@ -41,11 +42,20 @@ import EventEmitter from 'EventEmitter';
|
|||||||
* and then minimized to a banner notification if needed, or vice-versa.
|
* and then minimized to a banner notification if needed, or vice-versa.
|
||||||
*
|
*
|
||||||
* @typedef {object} NotificationModel
|
* @typedef {object} NotificationModel
|
||||||
* @property {string} message The message to be displayed by the notification
|
* @property {string} title The title of the message
|
||||||
* @property {number | 'unknown'} [progress] The progres of some ongoing task. Should be a number between 0 and 100, or
|
* @property {string} severity The importance of the message (one of
|
||||||
* with the string literal 'unknown'.
|
* 'info', 'alert', or 'error' where info < alert <error)
|
||||||
* @property {string} [progressText] A message conveying progress of some ongoing task.
|
* @property {number} [progress] The completion status of a task
|
||||||
|
* represented numerically
|
||||||
|
* @property {boolean} [unknownProgress] a boolean indicating that the
|
||||||
|
* progress of the underlying task is unknown. This will result in a
|
||||||
|
* visually distinct progress bar.
|
||||||
|
* @property {boolean} [autoDismiss] If truthy, dialog will
|
||||||
|
* be automatically minimized or dismissed (depending on severity).
|
||||||
|
* Additionally, if the provided value is a number, it will be used
|
||||||
|
* as the delay period before being dismissed.
|
||||||
|
* @property {boolean} [dismissable=true] If true, notification will
|
||||||
|
* include an option to dismiss it completely.
|
||||||
* @see DialogModel
|
* @see DialogModel
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -55,9 +65,14 @@ const MINIMIZE_ANIMATION_TIMEOUT = 300;
|
|||||||
/**
|
/**
|
||||||
* The notification service is responsible for informing the user of
|
* The notification service is responsible for informing the user of
|
||||||
* events via the use of banner notifications.
|
* events via the use of banner notifications.
|
||||||
* @memberof ui/notification
|
* @memberof platform/commonUI/notification
|
||||||
* @constructor */
|
* @constructor
|
||||||
|
* @param defaultAutoDismissTimeout The period of time that an
|
||||||
|
* auto-dismissed message will be displayed for.
|
||||||
|
* @param minimizeAnimationTimeout When notifications are minimized, a brief
|
||||||
|
* animation is shown. This animation requires some time to execute,
|
||||||
|
* so a timeout is required before the notification is hidden
|
||||||
|
*/
|
||||||
export default class NotificationAPI extends EventEmitter {
|
export default class NotificationAPI extends EventEmitter {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
@ -71,72 +86,16 @@ export default class NotificationAPI extends EventEmitter {
|
|||||||
this.activeNotification = undefined;
|
this.activeNotification = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Info notifications are low priority informational messages for the user. They will be auto-destroy after a brief
|
|
||||||
* period of time.
|
|
||||||
* @param {string} message The message to display to the user
|
|
||||||
* @returns {InfoNotification}
|
|
||||||
*/
|
|
||||||
info(message) {
|
|
||||||
let notificationModel = {
|
|
||||||
message: message,
|
|
||||||
autoDismiss: true,
|
|
||||||
severity: "info"
|
|
||||||
}
|
|
||||||
return this._notify(notificationModel);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Present an alert to the user.
|
|
||||||
* @param {string} message The message to display to the user.
|
|
||||||
* @returns {Notification}
|
|
||||||
*/
|
|
||||||
alert(message) {
|
|
||||||
let notificationModel = {
|
|
||||||
message: message,
|
|
||||||
severity: "alert"
|
|
||||||
}
|
|
||||||
return this._notify(notificationModel);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Present an error message to the user
|
|
||||||
* @param {string} message
|
|
||||||
* @returns {Notification}
|
|
||||||
*/
|
|
||||||
error(message) {
|
|
||||||
let notificationModel = {
|
|
||||||
message: message,
|
|
||||||
severity: "error"
|
|
||||||
}
|
|
||||||
return this._notify(notificationModel);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new progress notification. These notifications will contain a progress bar.
|
|
||||||
* @param {string} message
|
|
||||||
* @param {number | 'unknown'} progressPerc A value between 0 and 100, or the string 'unknown'.
|
|
||||||
* @param {string} [progressText] Text description of progress (eg. "10 of 20 objects copied").
|
|
||||||
*/
|
|
||||||
progress(message, progressPerc, progressText) {
|
|
||||||
let notificationModel = {
|
|
||||||
message: message,
|
|
||||||
progressPerc: progressPerc,
|
|
||||||
progressText: progressText,
|
|
||||||
severity: "info"
|
|
||||||
}
|
|
||||||
return this._notify(notificationModel);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Minimize a notification. The notification will still be available
|
* Minimize a notification. The notification will still be available
|
||||||
* from the notification list. Typically notifications with a
|
* from the notification list. Typically notifications with a
|
||||||
* severity of 'info' should not be minimized, but rather
|
* severity of 'info' should not be minimized, but rather
|
||||||
* dismissed.
|
* dismissed. If you're not sure which is appropriate,
|
||||||
|
* use {@link Notification#dismissOrMinimize}
|
||||||
*
|
*
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_minimize(notification) {
|
minimize(notification) {
|
||||||
//Check this is a known notification
|
//Check this is a known notification
|
||||||
let index = this.notifications.indexOf(notification);
|
let index = this.notifications.indexOf(notification);
|
||||||
|
|
||||||
@ -155,12 +114,11 @@ export default class NotificationAPI extends EventEmitter {
|
|||||||
|
|
||||||
if (index >= 0) {
|
if (index >= 0) {
|
||||||
notification.model.minimized = true;
|
notification.model.minimized = true;
|
||||||
notification.emit('minimized');
|
|
||||||
//Add a brief timeout before showing the next notification
|
//Add a brief timeout before showing the next notification
|
||||||
// in order to allow the minimize animation to run through.
|
// in order to allow the minimize animation to run through.
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
notification.emit('destroy');
|
notification.emit('destroy');
|
||||||
this._setActiveNotification(this._selectNextNotification());
|
this.setActiveNotification(this.selectNextNotification());
|
||||||
}, MINIMIZE_ANIMATION_TIMEOUT);
|
}, MINIMIZE_ANIMATION_TIMEOUT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -175,7 +133,7 @@ export default class NotificationAPI extends EventEmitter {
|
|||||||
*
|
*
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_dismiss(notification) {
|
dismiss(notification) {
|
||||||
//Check this is a known notification
|
//Check this is a known notification
|
||||||
let index = this.notifications.indexOf(notification);
|
let index = this.notifications.indexOf(notification);
|
||||||
|
|
||||||
@ -195,8 +153,8 @@ export default class NotificationAPI extends EventEmitter {
|
|||||||
if (index >= 0) {
|
if (index >= 0) {
|
||||||
this.notifications.splice(index, 1);
|
this.notifications.splice(index, 1);
|
||||||
}
|
}
|
||||||
this._setActiveNotification(this._selectNextNotification());
|
this.setActiveNotification(this.selectNextNotification());
|
||||||
this._setHighestSeverity();
|
this.setHighestSeverity();
|
||||||
notification.emit('destroy');
|
notification.emit('destroy');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -206,19 +164,81 @@ export default class NotificationAPI extends EventEmitter {
|
|||||||
*
|
*
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_dismissOrMinimize(notification) {
|
dismissOrMinimize(notification) {
|
||||||
let model = notification.model;
|
let model = notification.model;
|
||||||
if (model.severity === "info") {
|
if (model.severity === "info") {
|
||||||
this._dismiss(notification);
|
if (model.autoDismiss === false) {
|
||||||
|
this.minimize(notification);
|
||||||
} else {
|
} else {
|
||||||
this._minimize(notification);
|
this.dismiss(notification);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
this.minimize(notification);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the notification that is currently visible in the banner area
|
||||||
|
* @returns {Notification}
|
||||||
|
*/
|
||||||
|
getActiveNotification() {
|
||||||
|
return this.activeNotification;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A convenience method for info notifications. Notifications
|
||||||
|
* created via this method will be auto-destroy after a default
|
||||||
|
* wait period unless explicitly forbidden by the caller through
|
||||||
|
* the {autoDismiss} property on the {NotificationModel}, in which
|
||||||
|
* case the notification will be minimized after the wait.
|
||||||
|
* @param {NotificationModel | string} message either a string for
|
||||||
|
* the title of the notification message, or a {@link NotificationModel}
|
||||||
|
* defining the options notification to display
|
||||||
|
* @returns {Notification} the provided notification decorated with
|
||||||
|
* functions to dismiss or minimize
|
||||||
|
*/
|
||||||
|
info(message) {
|
||||||
|
let notificationModel = typeof message === "string" ? {title: message} : message;
|
||||||
|
notificationModel.severity = "info";
|
||||||
|
return this.notify(notificationModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A convenience method for alert notifications. Notifications
|
||||||
|
* created via this method will will have severity of "alert" enforced
|
||||||
|
* @param {NotificationModel | string} message either a string for
|
||||||
|
* the title of the alert message with default options, or a
|
||||||
|
* {@link NotificationModel} defining the options notification to
|
||||||
|
* display
|
||||||
|
* @returns {Notification} the provided notification decorated with
|
||||||
|
* functions to dismiss or minimize
|
||||||
|
*/
|
||||||
|
alert(message) {
|
||||||
|
let notificationModel = typeof message === "string" ? {title: message} : message;
|
||||||
|
notificationModel.severity = "alert";
|
||||||
|
return this.notify(notificationModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A convenience method for error notifications. Notifications
|
||||||
|
* created via this method will will have severity of "error" enforced
|
||||||
|
* @param {NotificationModel | string} message either a string for
|
||||||
|
* the title of the error message with default options, or a
|
||||||
|
* {@link NotificationModel} defining the options of the notification to
|
||||||
|
* display
|
||||||
|
* @returns {Notification} the provided notification decorated with
|
||||||
|
* functions to dismiss or minimize
|
||||||
|
*/
|
||||||
|
error(message) {
|
||||||
|
let notificationModel = typeof message === "string" ? {title: message} : message;
|
||||||
|
notificationModel.severity = "error";
|
||||||
|
return this.notify(notificationModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_setHighestSeverity() {
|
setHighestSeverity() {
|
||||||
let severity = {
|
let severity = {
|
||||||
"info": 1,
|
"info": 1,
|
||||||
"alert": 2,
|
"alert": 2,
|
||||||
@ -243,23 +263,23 @@ export default class NotificationAPI extends EventEmitter {
|
|||||||
* @returns {Notification} the provided notification decorated with
|
* @returns {Notification} the provided notification decorated with
|
||||||
* functions to {@link Notification#dismiss} or {@link Notification#minimize}
|
* functions to {@link Notification#dismiss} or {@link Notification#minimize}
|
||||||
*/
|
*/
|
||||||
_notify(notificationModel) {
|
notify(notificationModel) {
|
||||||
let notification;
|
let notification;
|
||||||
let activeNotification = this.activeNotification;
|
let activeNotification = this.activeNotification;
|
||||||
|
|
||||||
notificationModel.severity = notificationModel.severity || "info";
|
notificationModel.severity = notificationModel.severity || "info";
|
||||||
notificationModel.timestamp = moment.utc().format('YYYY-MM-DD hh:mm:ss.ms');
|
notificationModel.timestamp = moment.utc().format('YYYY-MM-DD hh:mm:ss.ms');
|
||||||
|
|
||||||
notification = this._createNotification(notificationModel);
|
notification = new MCTNotification(notificationModel, this);
|
||||||
|
|
||||||
this.notifications.push(notification);
|
this.notifications.push(notification);
|
||||||
this._setHighestSeverity();
|
this.setHighestSeverity();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Check if there is already an active (ie. visible) notification
|
Check if there is already an active (ie. visible) notification
|
||||||
*/
|
*/
|
||||||
if (!this.activeNotification) {
|
if (!this.activeNotification) {
|
||||||
this._setActiveNotification(notification);
|
this.setActiveNotification(notification);
|
||||||
} else if (!this.activeTimeout) {
|
} else if (!this.activeTimeout) {
|
||||||
/*
|
/*
|
||||||
If there is already an active notification, time it out. If it's
|
If there is already an active notification, time it out. If it's
|
||||||
@ -272,7 +292,7 @@ export default class NotificationAPI extends EventEmitter {
|
|||||||
serviced as soon as possible.
|
serviced as soon as possible.
|
||||||
*/
|
*/
|
||||||
this.activeTimeout = setTimeout(() => {
|
this.activeTimeout = setTimeout(() => {
|
||||||
this._dismissOrMinimize(activeNotification);
|
this.dismissOrMinimize(activeNotification);
|
||||||
}, DEFAULT_AUTO_DISMISS_TIMEOUT);
|
}, DEFAULT_AUTO_DISMISS_TIMEOUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -280,30 +300,11 @@ export default class NotificationAPI extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Used internally by the NotificationService
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_createNotification(notificationModel) {
|
setActiveNotification(notification) {
|
||||||
let notification = new EventEmitter();
|
let shouldAutoDismiss;
|
||||||
notification.model = notificationModel;
|
|
||||||
notification.dismiss = () => {
|
|
||||||
this._dismiss(notification);
|
|
||||||
};
|
|
||||||
|
|
||||||
if (notificationModel.hasOwnProperty('progressPerc')) {
|
|
||||||
notification.progress = (progressPerc, progressText) => {
|
|
||||||
notification.model.progressPerc = progressPerc;
|
|
||||||
notification.model.progressText = progressText;
|
|
||||||
notification.emit('progress', progressPerc, progressText);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return notification;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_setActiveNotification(notification) {
|
|
||||||
this.activeNotification = notification;
|
this.activeNotification = notification;
|
||||||
|
|
||||||
if (!notification) {
|
if (!notification) {
|
||||||
@ -312,9 +313,15 @@ export default class NotificationAPI extends EventEmitter {
|
|||||||
}
|
}
|
||||||
this.emit('notification', notification);
|
this.emit('notification', notification);
|
||||||
|
|
||||||
if (notification.model.autoDismiss || this._selectNextNotification()) {
|
if (notification.model.severity === "info") {
|
||||||
|
shouldAutoDismiss = true;
|
||||||
|
} else {
|
||||||
|
shouldAutoDismiss = notification.model.autoDismiss;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldAutoDismiss || this.selectNextNotification()) {
|
||||||
this.activeTimeout = setTimeout(() => {
|
this.activeTimeout = setTimeout(() => {
|
||||||
this._dismissOrMinimize(notification);
|
this.dismissOrMinimize(notification);
|
||||||
}, DEFAULT_AUTO_DISMISS_TIMEOUT);
|
}, DEFAULT_AUTO_DISMISS_TIMEOUT);
|
||||||
} else {
|
} else {
|
||||||
delete this.activeTimeout;
|
delete this.activeTimeout;
|
||||||
@ -326,7 +333,7 @@ export default class NotificationAPI extends EventEmitter {
|
|||||||
*
|
*
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_selectNextNotification() {
|
selectNextNotification() {
|
||||||
let notification;
|
let notification;
|
||||||
let i = 0;
|
let i = 0;
|
||||||
|
|
||||||
|
@ -1,33 +0,0 @@
|
|||||||
import DialogComponent from './components/DialogComponent.vue';
|
|
||||||
import Overlay from './Overlay';
|
|
||||||
import Vue from 'vue';
|
|
||||||
|
|
||||||
class Dialog extends Overlay {
|
|
||||||
constructor({iconClass, message, title, ...options}) {
|
|
||||||
|
|
||||||
let component = new Vue({
|
|
||||||
provide: {
|
|
||||||
iconClass,
|
|
||||||
message,
|
|
||||||
title
|
|
||||||
},
|
|
||||||
components: {
|
|
||||||
DialogComponent: DialogComponent
|
|
||||||
},
|
|
||||||
template: '<dialog-component></dialog-component>'
|
|
||||||
}).$mount();
|
|
||||||
|
|
||||||
super({
|
|
||||||
element: component.$el,
|
|
||||||
size: 'fit',
|
|
||||||
notDismissable: true,
|
|
||||||
...options
|
|
||||||
});
|
|
||||||
|
|
||||||
this.once('destroy', () => {
|
|
||||||
component.$destroy();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Dialog;
|
|
@ -1,51 +0,0 @@
|
|||||||
import OverlayComponent from './components/OverlayComponent.vue';
|
|
||||||
import EventEmitter from 'EventEmitter';
|
|
||||||
import Vue from 'vue';
|
|
||||||
|
|
||||||
const cssClasses = {
|
|
||||||
large: 'l-overlay-large',
|
|
||||||
small: 'l-overlay-small',
|
|
||||||
fit: 'l-overlay-fit'
|
|
||||||
};
|
|
||||||
|
|
||||||
class Overlay extends EventEmitter {
|
|
||||||
constructor(options) {
|
|
||||||
super();
|
|
||||||
|
|
||||||
this.container = document.createElement('div');
|
|
||||||
this.container.classList.add('l-overlay-wrapper', cssClasses[options.size]);
|
|
||||||
|
|
||||||
this.component = new Vue({
|
|
||||||
provide: {
|
|
||||||
dismiss: this.dismiss.bind(this),
|
|
||||||
element: options.element,
|
|
||||||
buttons: options.buttons,
|
|
||||||
notDismissable: options.notDismissable ? true : false
|
|
||||||
},
|
|
||||||
components: {
|
|
||||||
OverlayComponent: OverlayComponent
|
|
||||||
},
|
|
||||||
template: '<overlay-component></overlay-component>'
|
|
||||||
});
|
|
||||||
|
|
||||||
if (options.onDestroy) {
|
|
||||||
this.once('destroy', options.onDestroy);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dismiss() {
|
|
||||||
this.emit('destroy');
|
|
||||||
this.component.$destroy();
|
|
||||||
document.body.removeChild(this.container);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
**/
|
|
||||||
show() {
|
|
||||||
document.body.appendChild(this.container);
|
|
||||||
this.container.appendChild(this.component.$mount().$el);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Overlay;
|
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user