mirror of
https://github.com/nasa/openmct.git
synced 2025-06-27 19:38:53 +00:00
Compare commits
33 Commits
context-me
...
gauges
Author | SHA1 | Date | |
---|---|---|---|
d7a3510f34 | |||
0519824109 | |||
4380f88a08 | |||
20d5db6e44 | |||
5978b8e19d | |||
a0b71f92b8 | |||
7c3f7ff384 | |||
6f2a567299 | |||
746badd065 | |||
55d3ab5e8a | |||
c073a21ba6 | |||
ed8137726d | |||
7d99877eb9 | |||
3eac91a6d9 | |||
4d426580ae | |||
9270f02ca4 | |||
3ebdab5e51 | |||
815b1449f4 | |||
0874ada4d2 | |||
03812437d3 | |||
2b8272cf05 | |||
35d1b894e2 | |||
71a2f27e0c | |||
5460ca2009 | |||
7c54ec4f9f | |||
cbcfd44016 | |||
a296bc2b81 | |||
06b9e0fa97 | |||
4374a6fa28 | |||
67883519ee | |||
6f1b5b4ae3 | |||
c3b7e7869e | |||
d48cc2deee |
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',
|
'webpack-hot-middleware/client?reload=true',
|
||||||
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-folder-new",
|
"cssClass": "icon-generator-events",
|
||||||
"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-telemetry",
|
cssClass: "icon-generator-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-telemetry",
|
cssClass: "icon-generator-telemetry",
|
||||||
creatable: true,
|
creatable: true,
|
||||||
form: [
|
form: [
|
||||||
{
|
{
|
||||||
|
@ -79,30 +79,34 @@ 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: 0,
|
progress: progress,
|
||||||
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() {
|
||||||
notificationModel.progress = Math.min(100, Math.floor(notificationModel.progress + Math.random() * 30));
|
progress = Math.min(100, Math.floor(progress + Math.random() * 30))
|
||||||
notificationModel.progressText = ["Estimated time" +
|
let progressText = ["Estimated time" +
|
||||||
" remaining:" +
|
" remaining:" +
|
||||||
" about ", 60 - Math.floor((notificationModel.progress / 100) * 60), " seconds"].join(" ");
|
" about ", 60 - Math.floor((progress / 100) * 60), " seconds"].join(" ");
|
||||||
if (notificationModel.progress < 100) {
|
notification.progress(progress, progressText);
|
||||||
|
|
||||||
|
if (progress < 100) {
|
||||||
$timeout(function () {
|
$timeout(function () {
|
||||||
incrementProgress(notificationModel);
|
incrementProgress(notificationModel);
|
||||||
}, 1000);
|
}, 1000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
notificationService.notify(notificationModel);
|
notification = notificationService.notify(notificationModel);
|
||||||
incrementProgress();
|
incrementProgress();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
201
index.html
201
index.html
@ -49,6 +49,7 @@
|
|||||||
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"
|
||||||
}));
|
}));
|
||||||
@ -76,8 +77,208 @@
|
|||||||
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.Gauge());
|
||||||
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,31 +2,14 @@
|
|||||||
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.title}}</div>
|
<div class="title">{{ngModel.message}}</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.progress !== undefined || ngModel.unknownProgress"></mct-include>
|
ng-show="ngModel.progressPerc !== undefined"></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,7 +23,6 @@
|
|||||||
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",
|
||||||
@ -47,7 +46,6 @@ 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",
|
||||||
@ -55,13 +53,11 @@ 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,
|
||||||
@ -85,7 +81,6 @@ define([
|
|||||||
LocatorController,
|
LocatorController,
|
||||||
CreationPolicy,
|
CreationPolicy,
|
||||||
CreateActionProvider,
|
CreateActionProvider,
|
||||||
AddActionProvider,
|
|
||||||
CreationService,
|
CreationService,
|
||||||
locatorTemplate,
|
locatorTemplate,
|
||||||
createButtonTemplate,
|
createButtonTemplate,
|
||||||
@ -93,7 +88,6 @@ define([
|
|||||||
libraryTemplate,
|
libraryTemplate,
|
||||||
editObjectTemplate,
|
editObjectTemplate,
|
||||||
editActionButtonsTemplate,
|
editActionButtonsTemplate,
|
||||||
elementsTemplate,
|
|
||||||
topbarEditTemplate,
|
topbarEditTemplate,
|
||||||
legacyRegistry
|
legacyRegistry
|
||||||
) {
|
) {
|
||||||
@ -115,14 +109,6 @@ define([
|
|||||||
"$scope"
|
"$scope"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"key": "ElementsController",
|
|
||||||
"implementation": ElementsController,
|
|
||||||
"depends": [
|
|
||||||
"$scope",
|
|
||||||
"openmct"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"key": "EditObjectController",
|
"key": "EditObjectController",
|
||||||
"implementation": EditObjectController,
|
"implementation": EditObjectController,
|
||||||
@ -225,10 +211,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"
|
||||||
},
|
},
|
||||||
@ -296,13 +282,6 @@ define([
|
|||||||
"action"
|
"action"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"key": "edit-elements",
|
|
||||||
"template": elementsTemplate,
|
|
||||||
"gestures": [
|
|
||||||
"drop"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"key": "topbar-edit",
|
"key": "topbar-edit",
|
||||||
"template": topbarEditTemplate
|
"template": topbarEditTemplate
|
||||||
@ -319,12 +298,6 @@ define([
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"templates": [
|
|
||||||
{
|
|
||||||
key: "elementsPool",
|
|
||||||
template: elementsTemplate
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"components": [
|
"components": [
|
||||||
{
|
{
|
||||||
"type": "decorator",
|
"type": "decorator",
|
||||||
@ -356,18 +329,6 @@ define([
|
|||||||
"policyService"
|
"policyService"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"key": "AddActionProvider",
|
|
||||||
"provides": "actionService",
|
|
||||||
"type": "provider",
|
|
||||||
"implementation": AddActionProvider,
|
|
||||||
"depends": [
|
|
||||||
"$q",
|
|
||||||
"typeService",
|
|
||||||
"dialogService",
|
|
||||||
"policyService"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"key": "CreationService",
|
"key": "CreationService",
|
||||||
"provides": "creationService",
|
"provides": "creationService",
|
||||||
|
@ -1,49 +0,0 @@
|
|||||||
<!--
|
|
||||||
Open MCT, Copyright (c) 2014-2018, United States Government
|
|
||||||
as represented by the Administrator of the National Aeronautics and Space
|
|
||||||
Administration. All rights reserved.
|
|
||||||
|
|
||||||
Open MCT is licensed under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0.
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
License for the specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
|
|
||||||
Open MCT includes source code licensed under additional open source
|
|
||||||
licenses. See the Open Source Licenses file (LICENSES.md) included with
|
|
||||||
this source code distribution or the Licensing information page available
|
|
||||||
at runtime from the About dialog for additional information.
|
|
||||||
-->
|
|
||||||
<div 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>
|
|
@ -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.policyService
|
this.openmct
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -51,8 +51,11 @@ 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.');
|
||||||
this.openmct.editor.edit();
|
|
||||||
this.domainObject.getCapability('status').set('editing', true);
|
if (!this.openmct.editor.isEditing()) {
|
||||||
|
this.openmct.editor.edit();
|
||||||
|
this.domainObject.getCapability('status').set('editing', true);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -82,6 +85,7 @@ 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;
|
||||||
@ -93,6 +97,7 @@ 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();
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,197 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2014-2018, United States Government
|
|
||||||
* as represented by the Administrator of the National Aeronautics and Space
|
|
||||||
* Administration. All rights reserved.
|
|
||||||
*
|
|
||||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
* License for the specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*
|
|
||||||
* Open MCT includes source code licensed under additional open source
|
|
||||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
|
||||||
* this source code distribution or the Licensing information page available
|
|
||||||
* at runtime from the About dialog for additional information.
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
define(
|
|
||||||
['zepto'],
|
|
||||||
function ($) {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
);
|
|
@ -1,133 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2014-2018, United States Government
|
|
||||||
* as represented by the Administrator of the National Aeronautics and Space
|
|
||||||
* Administration. All rights reserved.
|
|
||||||
*
|
|
||||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
* License for the specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*
|
|
||||||
* Open MCT includes source code licensed under additional open source
|
|
||||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
|
||||||
* this source code distribution or the Licensing information page available
|
|
||||||
* at runtime from the About dialog for additional information.
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Module defining 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;
|
|
||||||
}
|
|
||||||
);
|
|
@ -1,82 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2014-2018, United States Government
|
|
||||||
* as represented by the Administrator of the National Aeronautics and Space
|
|
||||||
* Administration. All rights reserved.
|
|
||||||
*
|
|
||||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
* License for the specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*
|
|
||||||
* Open MCT includes source code licensed under additional open source
|
|
||||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
|
||||||
* this source code distribution or the Licensing information page available
|
|
||||||
* at runtime from the About dialog for additional information.
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Module defining 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) {
|
function CreateAction(type, parent, context, openmct) {
|
||||||
this.metadata = {
|
this.metadata = {
|
||||||
key: 'create',
|
key: 'create',
|
||||||
cssClass: type.getCssClass(),
|
cssClass: type.getCssClass(),
|
||||||
@ -55,6 +55,7 @@ define(
|
|||||||
};
|
};
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
|
this.openmct = openmct;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -63,37 +64,28 @@ 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() {
|
||||||
return editorCapability.save()
|
openmct.editor.save();
|
||||||
.then(closeEditor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function onCancel() {
|
function onCancel() {
|
||||||
return closeEditor();
|
openmct.editor.cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
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];
|
||||||
//If an edit action is available, perform it
|
newObject.getCapability("action").perform("save-as").then(onSave, onCancel);
|
||||||
if (editAction) {
|
// TODO: support editing object without saving object first.
|
||||||
return editAction.perform();
|
// Which means we have to toggle createwizard afterwards. For now,
|
||||||
} else if (editorCapability) {
|
// We will disable this.
|
||||||
//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, policyService) {
|
function CreateWizard(domainObject, parent, openmct) {
|
||||||
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.policyService = policyService;
|
this.openmct = openmct;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -56,15 +56,10 @@ 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 && policyService.allow(
|
return parent && this.openmct.composition.checkPolicy(parent.useCapability('adapter'), domainObject.useCapability('adapter'));
|
||||||
"composition",
|
|
||||||
parent,
|
|
||||||
domainObject
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sections.push({
|
sections.push({
|
||||||
@ -93,7 +88,7 @@ define(
|
|||||||
rows: [{
|
rows: [{
|
||||||
name: "Save In",
|
name: "Save In",
|
||||||
control: "locator",
|
control: "locator",
|
||||||
validate: validateLocation,
|
validate: validateLocation.bind(this),
|
||||||
key: "createParent"
|
key: "createParent"
|
||||||
}]
|
}]
|
||||||
});
|
});
|
||||||
|
@ -1,254 +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/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;
|
|
||||||
}
|
|
||||||
);
|
|
@ -1,184 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2014-2018, United States Government
|
|
||||||
* as represented by the Administrator of the National Aeronautics and Space
|
|
||||||
* Administration. All rights reserved.
|
|
||||||
*
|
|
||||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
* License for the specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*
|
|
||||||
* Open MCT includes source code licensed under additional open source
|
|
||||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
|
||||||
* this source code distribution or the Licensing information page available
|
|
||||||
* at runtime from the About dialog for additional information.
|
|
||||||
*****************************************************************************/
|
|
||||||
/*global describe,it,expect,beforeEach,jasmine*/
|
|
||||||
|
|
||||||
define(
|
|
||||||
["../../src/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);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
@ -1,105 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2014-2018, United States Government
|
|
||||||
* as represented by the Administrator of the National Aeronautics and Space
|
|
||||||
* Administration. All rights reserved.
|
|
||||||
*
|
|
||||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
* License for the specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*
|
|
||||||
* Open MCT includes source code licensed under additional open source
|
|
||||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
|
||||||
* this source code distribution or the Licensing information page available
|
|
||||||
* at runtime from the About dialog for additional information.
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* MCTRepresentationSpec. Created by 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
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
@ -1,75 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2014-2018, United States Government
|
|
||||||
* as represented by the Administrator of the National Aeronautics and Space
|
|
||||||
* Administration. All rights reserved.
|
|
||||||
*
|
|
||||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
* License for the specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*
|
|
||||||
* Open MCT includes source code licensed under additional open source
|
|
||||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
|
||||||
* this source code distribution or the Licensing information page available
|
|
||||||
* at runtime from the About dialog for additional information.
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
define(
|
|
||||||
['../../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.unknownProgress }">
|
ng-class="{ indeterminate:ngModel.progressPerc === 'unknown' }">
|
||||||
<span class="progress-amt-holder">
|
<span class="progress-amt-holder">
|
||||||
<span class="progress-amt" style="width: {{ngModel.progress}}%"></span>
|
<span class="progress-amt" style="width: {{ngModel.progressPerc === 'unknown' ? 100 : ngModel.progressPerc}}%"></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.progress > 0">{{ngModel.progress}}% complete. </span>
|
<span class="progress-amt-text" ng-show="ngModel.progressPerc !== 'unknown' && ngModel.progressPerc > 0">{{ngModel.progressPerc}}% 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.dismissOrMinimize();
|
notification.dismiss();
|
||||||
};
|
};
|
||||||
$scope.maximize = function (notification) {
|
$scope.maximize = function (notification) {
|
||||||
if (notification.model.severity !== "info") {
|
if (notification.model.severity !== "info") {
|
||||||
|
@ -23,11 +23,13 @@
|
|||||||
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
|
||||||
) {
|
) {
|
||||||
@ -46,7 +48,7 @@ define([
|
|||||||
"implementation": NotificationIndicatorController,
|
"implementation": NotificationIndicatorController,
|
||||||
"depends": [
|
"depends": [
|
||||||
"$scope",
|
"$scope",
|
||||||
"notificationService",
|
"openmct",
|
||||||
"dialogService"
|
"dialogService"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -61,7 +63,7 @@ define([
|
|||||||
{
|
{
|
||||||
"key": "notificationService",
|
"key": "notificationService",
|
||||||
"implementation": function (openmct) {
|
"implementation": function (openmct) {
|
||||||
return openmct.notifications;
|
return new NotificationService.default(openmct);
|
||||||
},
|
},
|
||||||
"depends": [
|
"depends": [
|
||||||
"openmct"
|
"openmct"
|
||||||
|
@ -35,9 +35,9 @@ define(
|
|||||||
* @param dialogService
|
* @param dialogService
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function NotificationIndicatorController($scope, notificationService, dialogService) {
|
function NotificationIndicatorController($scope, openmct, dialogService) {
|
||||||
$scope.notifications = notificationService.notifications;
|
$scope.notifications = openmct.notifications.notifications;
|
||||||
$scope.highest = notificationService.highest;
|
$scope.highest = openmct.notifications.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: notificationService.notifications
|
messages: openmct.notifications.notifications
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
64
platform/commonUI/notification/src/NotificationService.js
Normal file
64
platform/commonUI/notification/src/NotificationService.js
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* 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,7 +58,8 @@ 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,10 +36,11 @@ define(
|
|||||||
* @memberof platform/containment
|
* @memberof platform/containment
|
||||||
* @implements {Policy.<Action, ActionContext>}
|
* @implements {Policy.<Action, ActionContext>}
|
||||||
*/
|
*/
|
||||||
function ComposeActionPolicy($injector) {
|
function ComposeActionPolicy($injector, openmct) {
|
||||||
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) {
|
||||||
@ -49,11 +50,8 @@ define(
|
|||||||
|
|
||||||
// ...and delegate to the composition policy
|
// ...and delegate to the composition policy
|
||||||
return containerObject.getId() !== selectedObject.getId() &&
|
return containerObject.getId() !== selectedObject.getId() &&
|
||||||
this.policyService.allow(
|
this.openmct.composition.checkPolicy(containerObject.useCapability('adapter'),
|
||||||
'composition',
|
selectedObject.useCapability('adapter'));
|
||||||
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": [
|
||||||
"policyService",
|
"openmct",
|
||||||
"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": [
|
||||||
"policyService"
|
"openmct"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -192,7 +192,7 @@ define([
|
|||||||
"depends": [
|
"depends": [
|
||||||
"$q",
|
"$q",
|
||||||
"policyService",
|
"policyService",
|
||||||
"now"
|
"openmct"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -33,9 +33,10 @@ define(
|
|||||||
* @memberof platform/entanglement
|
* @memberof platform/entanglement
|
||||||
* @implements {platform/entanglement.AbstractComposeService}
|
* @implements {platform/entanglement.AbstractComposeService}
|
||||||
*/
|
*/
|
||||||
function CopyService($q, policyService) {
|
function CopyService($q, policyService, openmct) {
|
||||||
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) {
|
||||||
@ -45,11 +46,7 @@ define(
|
|||||||
if (parentCandidate.getId() === object.getId()) {
|
if (parentCandidate.getId() === object.getId()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return this.policyService.allow(
|
return this.openmct.composition.checkPolicy(parentCandidate.useCapability('adapter'), object.useCapability('adapter'));
|
||||||
"composition",
|
|
||||||
parentCandidate,
|
|
||||||
object
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -32,8 +32,8 @@ define(
|
|||||||
* @memberof platform/entanglement
|
* @memberof platform/entanglement
|
||||||
* @implements {platform/entanglement.AbstractComposeService}
|
* @implements {platform/entanglement.AbstractComposeService}
|
||||||
*/
|
*/
|
||||||
function LinkService(policyService) {
|
function LinkService(openmct) {
|
||||||
this.policyService = policyService;
|
this.openmct = openmct;
|
||||||
}
|
}
|
||||||
|
|
||||||
LinkService.prototype.validate = function (object, parentCandidate) {
|
LinkService.prototype.validate = function (object, parentCandidate) {
|
||||||
@ -49,11 +49,7 @@ define(
|
|||||||
if (parentCandidate.getModel().composition.indexOf(object.getId()) !== -1) {
|
if (parentCandidate.getModel().composition.indexOf(object.getId()) !== -1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return this.policyService.allow(
|
return this.openmct.composition.checkPolicy(parentCandidate.useCapability('adapter'), object.useCapability('adapter'));
|
||||||
"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(policyService, linkService) {
|
function MoveService(openmct, linkService) {
|
||||||
this.policyService = policyService;
|
this.openmct = openmct;
|
||||||
this.linkService = linkService;
|
this.linkService = linkService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,10 +53,9 @@ define(
|
|||||||
if (parentCandidate.getModel().composition.indexOf(object.getId()) !== -1) {
|
if (parentCandidate.getModel().composition.indexOf(object.getId()) !== -1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return this.policyService.allow(
|
return this.openmct.composition.checkPolicy(
|
||||||
"composition",
|
parentCandidate.useCapability('adapter'),
|
||||||
parentCandidate,
|
object.useCapability('adapter')
|
||||||
object
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,399 +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([
|
|
||||||
"../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"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
475
platform/features/fixed/plugin.js
Normal file
475
platform/features/fixed/plugin.js
Normal file
@ -0,0 +1,475 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* 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.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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
@ -225,6 +225,8 @@ 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));
|
||||||
@ -421,6 +423,7 @@ 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);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -706,6 +709,12 @@ 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;
|
||||||
}
|
}
|
||||||
);
|
);
|
@ -42,7 +42,8 @@ define(
|
|||||||
},
|
},
|
||||||
"fixed.text": {
|
"fixed.text": {
|
||||||
fill: "transparent",
|
fill: "transparent",
|
||||||
stroke: "transparent"
|
stroke: "transparent",
|
||||||
|
size: "13px"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
DIALOGS = {
|
DIALOGS = {
|
@ -67,10 +67,6 @@ define(
|
|||||||
*/
|
*/
|
||||||
proxy.size = new AccessorMutator(element, 'size');
|
proxy.size = new AccessorMutator(element, 'size');
|
||||||
|
|
||||||
if (proxy.size() === undefined) {
|
|
||||||
proxy.size("13px");
|
|
||||||
}
|
|
||||||
|
|
||||||
return proxy;
|
return proxy;
|
||||||
}
|
}
|
||||||
|
|
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-grid-holder" ng-click="controller.bypassSelection($event)">
|
<div class="l-fixed-position__grid-holder l-grid-holder c-grid" ng-click="controller.bypassSelection($event)">
|
||||||
<div class="l-grid l-grid-x"
|
<div class="c-grid__x 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="l-grid l-grid-y"
|
<div class="c-grid__y 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 s-hover-border"
|
class="l-fixed-position-item s-selectable s-moveable is-selectable is-moveable"
|
||||||
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="s-selected s-moveable" ng-if="controller.isElementSelected()">
|
<span class="c-frame-edit" ng-if="controller.isElementSelected()">
|
||||||
<div class="l-fixed-position-item t-edit-handle-holder"
|
<div class="c-frame-edit__move"
|
||||||
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="l-fixed-position-item-handle edit-corner"
|
class="c-frame-edit__handle c-frame-edit__handle--nwse"
|
||||||
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)"
|
@ -1,356 +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/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"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,82 +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/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,7 +22,6 @@
|
|||||||
|
|
||||||
define([
|
define([
|
||||||
"./src/MCTForm",
|
"./src/MCTForm",
|
||||||
"./src/MCTToolbar",
|
|
||||||
"./src/MCTControl",
|
"./src/MCTControl",
|
||||||
"./src/MCTFileInput",
|
"./src/MCTFileInput",
|
||||||
"./src/FileInputService",
|
"./src/FileInputService",
|
||||||
@ -48,7 +47,6 @@ define([
|
|||||||
'legacyRegistry'
|
'legacyRegistry'
|
||||||
], function (
|
], function (
|
||||||
MCTForm,
|
MCTForm,
|
||||||
MCTToolbar,
|
|
||||||
MCTControl,
|
MCTControl,
|
||||||
MCTFileInput,
|
MCTFileInput,
|
||||||
FileInputService,
|
FileInputService,
|
||||||
@ -83,10 +81,6 @@ define([
|
|||||||
"key": "mctForm",
|
"key": "mctForm",
|
||||||
"implementation": MCTForm
|
"implementation": MCTForm
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"key": "mctToolbar",
|
|
||||||
"implementation": MCTToolbar
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"key": "mctControl",
|
"key": "mctControl",
|
||||||
"implementation": MCTControl,
|
"implementation": MCTControl,
|
||||||
|
@ -1,49 +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.
|
|
||||||
-->
|
|
||||||
<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>
|
|
@ -1,69 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2014-2018, United States Government
|
|
||||||
* as represented by the Administrator of the National Aeronautics and Space
|
|
||||||
* Administration. All rights reserved.
|
|
||||||
*
|
|
||||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
* License for the specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*
|
|
||||||
* Open MCT includes source code licensed under additional open source
|
|
||||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
|
||||||
* this source code distribution or the Licensing information page available
|
|
||||||
* at runtime from the About dialog for additional information.
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Module defining 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;
|
|
||||||
}
|
|
||||||
);
|
|
@ -1,84 +0,0 @@
|
|||||||
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;
|
|
||||||
}
|
|
||||||
);
|
|
@ -1,112 +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/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/);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
17
src/MCT.js
17
src/MCT.js
@ -26,6 +26,7 @@ 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',
|
||||||
@ -40,7 +41,6 @@ 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',
|
||||||
'./ui/overlayService/overlayService',
|
|
||||||
'vue'
|
'vue'
|
||||||
], function (
|
], function (
|
||||||
EventEmitter,
|
EventEmitter,
|
||||||
@ -48,6 +48,7 @@ define([
|
|||||||
uuid,
|
uuid,
|
||||||
defaultRegistry,
|
defaultRegistry,
|
||||||
api,
|
api,
|
||||||
|
OverlayAPI,
|
||||||
Selection,
|
Selection,
|
||||||
objectUtils,
|
objectUtils,
|
||||||
plugins,
|
plugins,
|
||||||
@ -62,7 +63,6 @@ define([
|
|||||||
coreStyles,
|
coreStyles,
|
||||||
NotebookStyles,
|
NotebookStyles,
|
||||||
Layout,
|
Layout,
|
||||||
OverlayService,
|
|
||||||
Vue
|
Vue
|
||||||
) {
|
) {
|
||||||
/**
|
/**
|
||||||
@ -185,15 +185,6 @@ 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.
|
||||||
@ -225,11 +216,9 @@ 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.OverlayService = new OverlayService();
|
this.overlays = new OverlayAPI.default();
|
||||||
|
|
||||||
this.legacyRegistry = defaultRegistry;
|
this.legacyRegistry = defaultRegistry;
|
||||||
this.install(this.plugins.Plot());
|
this.install(this.plugins.Plot());
|
||||||
|
@ -28,7 +28,6 @@ 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',
|
||||||
@ -36,7 +35,8 @@ define([
|
|||||||
'./runs/LegacyTelemetryProvider',
|
'./runs/LegacyTelemetryProvider',
|
||||||
'./runs/RegisterLegacyTypes',
|
'./runs/RegisterLegacyTypes',
|
||||||
'./services/LegacyObjectAPIInterceptor',
|
'./services/LegacyObjectAPIInterceptor',
|
||||||
'./views/installLegacyViews'
|
'./views/installLegacyViews',
|
||||||
|
'./policies/legacyCompositionPolicyAdapter'
|
||||||
], function (
|
], function (
|
||||||
legacyRegistry,
|
legacyRegistry,
|
||||||
ActionDialogDecorator,
|
ActionDialogDecorator,
|
||||||
@ -45,7 +45,6 @@ define([
|
|||||||
Instantiate,
|
Instantiate,
|
||||||
MissingModelCompatibilityDecorator,
|
MissingModelCompatibilityDecorator,
|
||||||
APICapabilityDecorator,
|
APICapabilityDecorator,
|
||||||
AdapterCompositionPolicy,
|
|
||||||
AdaptedViewPolicy,
|
AdaptedViewPolicy,
|
||||||
AlternateCompositionInitializer,
|
AlternateCompositionInitializer,
|
||||||
TimeSettingsURLHandler,
|
TimeSettingsURLHandler,
|
||||||
@ -53,7 +52,8 @@ define([
|
|||||||
LegacyTelemetryProvider,
|
LegacyTelemetryProvider,
|
||||||
RegisterLegacyTypes,
|
RegisterLegacyTypes,
|
||||||
LegacyObjectAPIInterceptor,
|
LegacyObjectAPIInterceptor,
|
||||||
installLegacyViews
|
installLegacyViews,
|
||||||
|
legacyCompositionPolicyAdapter
|
||||||
) {
|
) {
|
||||||
legacyRegistry.register('src/adapter', {
|
legacyRegistry.register('src/adapter', {
|
||||||
"extensions": {
|
"extensions": {
|
||||||
@ -117,11 +117,6 @@ define([
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
policies: [
|
policies: [
|
||||||
{
|
|
||||||
category: "composition",
|
|
||||||
implementation: AdapterCompositionPolicy,
|
|
||||||
depends: ["openmct"]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
category: "view",
|
category: "view",
|
||||||
implementation: AdaptedViewPolicy,
|
implementation: AdaptedViewPolicy,
|
||||||
@ -168,6 +163,12 @@ define([
|
|||||||
"types[]",
|
"types[]",
|
||||||
"openmct"
|
"openmct"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
implementation: legacyCompositionPolicyAdapter.default,
|
||||||
|
depends: [
|
||||||
|
"openmct"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
licenses: [
|
licenses: [
|
||||||
|
@ -20,32 +20,23 @@
|
|||||||
* at runtime from the About dialog for additional information.
|
* at runtime from the About dialog for additional information.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
define(
|
export default function legacyCompositionPolicyAdapter(openmct) {
|
||||||
[],
|
const instantiate = this.openmct.$injector.get('instantiate');
|
||||||
function () {
|
const policyService = this.openmct.$injector.get('policyService');
|
||||||
|
|
||||||
/**
|
openmct.composition.addPolicy((parent, child) => {
|
||||||
* Defines composition policy for Display Layout objects.
|
|
||||||
* They cannot contain folders.
|
|
||||||
* @constructor
|
|
||||||
* @memberof platform/features/layout
|
|
||||||
* @implements {Policy.<View, DomainObject>}
|
|
||||||
*/
|
|
||||||
function LayoutCompositionPolicy() {
|
|
||||||
}
|
|
||||||
|
|
||||||
LayoutCompositionPolicy.prototype.allow = function (parent, child) {
|
let parentId = this.openmct.objects.makeKeyString(parent.identifier);
|
||||||
var parentType = parent.getCapability('type');
|
let childId = this.openmct.objects.makeKeyString(child.identifier);
|
||||||
if (parentType.instanceOf('layout') &&
|
|
||||||
child.getCapability('type').instanceOf('folder')) {
|
|
||||||
|
|
||||||
return false;
|
let legacyParent = instantiate(parent, parentId);
|
||||||
}
|
let legacyChild = instantiate(child, childId);
|
||||||
|
let result = policyService.allow(
|
||||||
return true;
|
'composition',
|
||||||
};
|
legacyParent,
|
||||||
|
legacyChild
|
||||||
return LayoutCompositionPolicy;
|
);
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
}
|
@ -36,6 +36,9 @@ 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,8 +25,6 @@ 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',
|
||||||
@ -37,8 +35,6 @@ define([
|
|||||||
ObjectAPI,
|
ObjectAPI,
|
||||||
CompositionAPI,
|
CompositionAPI,
|
||||||
TypeRegistry,
|
TypeRegistry,
|
||||||
Dialog,
|
|
||||||
GestureAPI,
|
|
||||||
TelemetryAPI,
|
TelemetryAPI,
|
||||||
IndicatorAPI,
|
IndicatorAPI,
|
||||||
NotificationAPI,
|
NotificationAPI,
|
||||||
@ -48,9 +44,7 @@ define([
|
|||||||
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,
|
||||||
|
@ -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.addProvider(new DefaultCompositionProvider(publicAPI, this));
|
||||||
this.publicAPI = publicAPI;
|
this.publicAPI = publicAPI;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,9 +43,34 @@ define([
|
|||||||
* @memberof module:openmct
|
* @memberof module:openmct
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function DefaultCompositionProvider(publicAPI) {
|
function DefaultCompositionProvider(publicAPI, compositionAPI) {
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -203,7 +228,7 @@ define([
|
|||||||
}
|
}
|
||||||
|
|
||||||
var oldComposition = listeners.composition.map(objectUtils.makeKeyString);
|
var oldComposition = listeners.composition.map(objectUtils.makeKeyString);
|
||||||
var newComposition = oldDomainObject.getModel().composition;
|
var newComposition = oldDomainObject.getModel().composition.map(objectUtils.makeKeyString);
|
||||||
|
|
||||||
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);
|
||||||
|
@ -32,7 +32,6 @@
|
|||||||
*/
|
*/
|
||||||
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
|
||||||
@ -42,20 +41,11 @@ import MCTNotification from './MCTNotification.js';
|
|||||||
* 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} title The title of the message
|
* @property {string} message The message to be displayed by the notification
|
||||||
* @property {string} severity The importance of the message (one of
|
* @property {number | 'unknown'} [progress] The progres of some ongoing task. Should be a number between 0 and 100, or
|
||||||
* 'info', 'alert', or 'error' where info < alert <error)
|
* with the string literal 'unknown'.
|
||||||
* @property {number} [progress] The completion status of a task
|
* @property {string} [progressText] A message conveying progress of some ongoing 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
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -65,14 +55,9 @@ 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 platform/commonUI/notification
|
* @memberof ui/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();
|
||||||
@ -86,16 +71,72 @@ 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. If you're not sure which is appropriate,
|
* dismissed.
|
||||||
* 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);
|
||||||
|
|
||||||
@ -114,11 +155,12 @@ 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -133,7 +175,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);
|
||||||
|
|
||||||
@ -153,8 +195,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');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,81 +206,19 @@ 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") {
|
||||||
if (model.autoDismiss === false) {
|
this._dismiss(notification);
|
||||||
this.minimize(notification);
|
|
||||||
} else {
|
|
||||||
this.dismiss(notification);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
this.minimize(notification);
|
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,
|
||||||
@ -263,23 +243,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 = new MCTNotification(notificationModel, this);
|
notification = this._createNotification(notificationModel);
|
||||||
|
|
||||||
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
|
||||||
@ -292,19 +272,38 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
return notification;
|
return notification;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used internally by the NotificationService
|
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
setActiveNotification(notification) {
|
_createNotification(notificationModel) {
|
||||||
let shouldAutoDismiss;
|
let notification = new EventEmitter();
|
||||||
|
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) {
|
||||||
@ -313,15 +312,9 @@ export default class NotificationAPI extends EventEmitter {
|
|||||||
}
|
}
|
||||||
this.emit('notification', notification);
|
this.emit('notification', notification);
|
||||||
|
|
||||||
if (notification.model.severity === "info") {
|
if (notification.model.autoDismiss || this._selectNextNotification()) {
|
||||||
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;
|
||||||
@ -333,7 +326,7 @@ export default class NotificationAPI extends EventEmitter {
|
|||||||
*
|
*
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
selectNextNotification() {
|
_selectNextNotification() {
|
||||||
let notification;
|
let notification;
|
||||||
let i = 0;
|
let i = 0;
|
||||||
|
|
||||||
|
33
src/api/overlays/Dialog.js
Normal file
33
src/api/overlays/Dialog.js
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
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;
|
51
src/api/overlays/Overlay.js
Normal file
51
src/api/overlays/Overlay.js
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
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;
|
115
src/api/overlays/OverlayAPI.js
Normal file
115
src/api/overlays/OverlayAPI.js
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
import Overlay from './Overlay';
|
||||||
|
import Dialog from './Dialog';
|
||||||
|
import ProgressDialog from './ProgressDialog';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The OverlayAPI is responsible for pre-pending templates to
|
||||||
|
* the body of the document, which is useful for displaying templates
|
||||||
|
* which need to block the full screen.
|
||||||
|
*
|
||||||
|
* @memberof api/overlays
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
|
||||||
|
class OverlayAPI {
|
||||||
|
constructor() {
|
||||||
|
this.activeOverlays = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* private
|
||||||
|
*/
|
||||||
|
showOverlay(overlay) {
|
||||||
|
if (this.activeOverlays.length) {
|
||||||
|
this.activeOverlays[this.activeOverlays.length - 1].container.classList.add('invisible');
|
||||||
|
}
|
||||||
|
|
||||||
|
this.activeOverlays.push(overlay);
|
||||||
|
|
||||||
|
overlay.once('destroy', () => {
|
||||||
|
this.activeOverlays.splice(this.activeOverlays.indexOf(overlay), 1);
|
||||||
|
|
||||||
|
if (this.activeOverlays.length) {
|
||||||
|
this.activeOverlays[this.activeOverlays.length - 1].container.classList.remove('invisible');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
overlay.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
] * A description of option properties that can be passed into the overlay
|
||||||
|
* @typedef options
|
||||||
|
* @property {object} element DOMElement that is to be inserted/shown on the overlay
|
||||||
|
* @property {string} size prefered size of the overlay (large, small, fit)
|
||||||
|
* @property {array} buttons optional button objects with label and callback properties
|
||||||
|
* @property {function} onDestroy callback to be called when overlay is destroyed
|
||||||
|
* @property {boolean} notDismissable to prevent user from dismissing the overlay, calling code
|
||||||
|
* will need to explicitly dismiss the overlay.
|
||||||
|
*/
|
||||||
|
overlay(options) {
|
||||||
|
let overlay = new Overlay(options);
|
||||||
|
|
||||||
|
this.showOverlay(overlay);
|
||||||
|
|
||||||
|
return overlay;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays a blocking (modal) dialog. This dialog can be used for
|
||||||
|
* displaying messages that require the user's
|
||||||
|
* immediate attention.
|
||||||
|
* @param {model} options defines options for the dialog
|
||||||
|
* @returns {object} with an object with a dismiss function that can be called from the calling code
|
||||||
|
* to dismiss/destroy the dialog
|
||||||
|
*
|
||||||
|
* A description of the model options that may be passed to the
|
||||||
|
* dialog method. Note that the DialogModel described
|
||||||
|
* here is shared with the Notifications framework.
|
||||||
|
* @see NotificationService
|
||||||
|
*
|
||||||
|
* @typedef options
|
||||||
|
* @property {string} title the title to use for the dialog
|
||||||
|
* @property {string} iconClass class to apply to icon that is shown on dialog
|
||||||
|
* @property {string} message text that indicates a current message,
|
||||||
|
* @property {buttons[]} buttons a list of buttons with title and callback properties that will
|
||||||
|
* be added to the dialog.
|
||||||
|
*/
|
||||||
|
dialog(options) {
|
||||||
|
let dialog = new Dialog(options);
|
||||||
|
|
||||||
|
this.showOverlay(dialog);
|
||||||
|
|
||||||
|
return dialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays a blocking (modal) progress dialog. This dialog can be used for
|
||||||
|
* displaying messages that require the user's attention, and show progress
|
||||||
|
* @param {model} options defines options for the dialog
|
||||||
|
* @returns {object} with an object with a dismiss function that can be called from the calling code
|
||||||
|
* to dismiss/destroy the dialog and an updateProgress function that takes progressPercentage(Number 0-100)
|
||||||
|
* and progressText (string)
|
||||||
|
*
|
||||||
|
* A description of the model options that may be passed to the
|
||||||
|
* dialog method. Note that the DialogModel described
|
||||||
|
* here is shared with the Notifications framework.
|
||||||
|
* @see NotificationService
|
||||||
|
*
|
||||||
|
* @typedef options
|
||||||
|
* @property {number} progressPerc the initial progress value (0-100) or {string} 'unknown' for anonymous progress
|
||||||
|
* @property {string} progressText the initial text to be shown under the progress bar
|
||||||
|
* @property {buttons[]} buttons a list of buttons with title and callback properties that will
|
||||||
|
* be added to the dialog.
|
||||||
|
*/
|
||||||
|
progressDialog(options) {
|
||||||
|
let progressDialog = new ProgressDialog(options);
|
||||||
|
|
||||||
|
this.showOverlay(progressDialog);
|
||||||
|
|
||||||
|
return progressDialog;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default OverlayAPI;
|
43
src/api/overlays/ProgressDialog.js
Normal file
43
src/api/overlays/ProgressDialog.js
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import ProgressComponent from '../../ui/components/layout/ProgressBar.vue';
|
||||||
|
import Overlay from './Overlay';
|
||||||
|
import Vue from 'vue';
|
||||||
|
|
||||||
|
var component;
|
||||||
|
|
||||||
|
class ProgressDialog extends Overlay {
|
||||||
|
constructor({progressPerc, progressText, ...options}) {
|
||||||
|
|
||||||
|
component = new Vue({
|
||||||
|
components: {
|
||||||
|
ProgressComponent: ProgressComponent
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
model: {
|
||||||
|
progressPerc: progressPerc || 0,
|
||||||
|
progressText: progressText
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
template: '<progress-component :model="model"></progress-component>'
|
||||||
|
}).$mount();
|
||||||
|
|
||||||
|
super({
|
||||||
|
element: component.$el,
|
||||||
|
size: 'fit',
|
||||||
|
notDismissable: true,
|
||||||
|
...options
|
||||||
|
});
|
||||||
|
|
||||||
|
this.once('destroy', () => {
|
||||||
|
component.$destroy();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
updateProgress(progressPerc, progressText) {
|
||||||
|
component.model.progressPerc = progressPerc;
|
||||||
|
component.model.progressText = progressText;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ProgressDialog;
|
71
src/api/overlays/components/DialogComponent.vue
Normal file
71
src/api/overlays/components/DialogComponent.vue
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
<template>
|
||||||
|
<div class="c-message">
|
||||||
|
<!--Uses flex-row -->
|
||||||
|
<div class="c-message__icon"
|
||||||
|
:class="['u-icon-bg-color-' + iconClass]"></div>
|
||||||
|
<div class="c-message__text">
|
||||||
|
<!-- Uses flex-column -->
|
||||||
|
<div class="c-message__title"
|
||||||
|
v-if="title">
|
||||||
|
{{title}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="c-message__hint"
|
||||||
|
v-if="hint">
|
||||||
|
{{hint}}
|
||||||
|
<span v-if="timestamp">[{{timestamp}}]</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="c-message__action-text"
|
||||||
|
v-if="message">
|
||||||
|
{{message}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@import "~styles/sass-base";
|
||||||
|
|
||||||
|
.c-message {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: $interiorMarginLg;
|
||||||
|
|
||||||
|
> * + * {
|
||||||
|
margin-left: $interiorMarginLg;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__icon {
|
||||||
|
// Holds a background SVG graphic
|
||||||
|
$s: 50px;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
min-width: $s;
|
||||||
|
min-height: $s;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__text {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex: 1 1 auto;
|
||||||
|
|
||||||
|
> * + * {
|
||||||
|
@include test();
|
||||||
|
margin-top: $interiorMargin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// __text elements
|
||||||
|
&__title,
|
||||||
|
&__action-text {
|
||||||
|
font-size: 1.2em; // TEMP
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
inject:['iconClass', 'title', 'hint', 'timestamp', 'message']
|
||||||
|
}
|
||||||
|
</script>
|
148
src/api/overlays/components/OverlayComponent.vue
Normal file
148
src/api/overlays/components/OverlayComponent.vue
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
<template>
|
||||||
|
<div class="c-overlay">
|
||||||
|
<div class="c-overlay__blocker"
|
||||||
|
@click="destroy">
|
||||||
|
</div>
|
||||||
|
<div class="c-overlay__outer">
|
||||||
|
<button class="c-click-icon c-overlay__close-button icon-x-in-circle"
|
||||||
|
v-if="!notDismissable"
|
||||||
|
@click="destroy">
|
||||||
|
</button>
|
||||||
|
<div class="c-overlay__contents" ref="element"></div>
|
||||||
|
<div class="c-overlay__button-bar" v-if="buttons">
|
||||||
|
<button class="c-button"
|
||||||
|
v-for="(button, index) in buttons"
|
||||||
|
:key="index"
|
||||||
|
:class="{'c-button--major': button.emphasis}"
|
||||||
|
@click="buttonClickHandler(button.callback)">
|
||||||
|
{{button.label}}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@import "~styles/sass-base";
|
||||||
|
|
||||||
|
@mixin overlaySizing($marginTB: 5%, $marginLR: $marginTB, $width: auto, $height: auto) {
|
||||||
|
position: absolute;
|
||||||
|
top: $marginTB; right: $marginLR; bottom: $marginTB; left: $marginLR;
|
||||||
|
width: $width;
|
||||||
|
height: $height;
|
||||||
|
}
|
||||||
|
|
||||||
|
.l-overlay-wrapper {
|
||||||
|
// Created by overlayService.js, contains this template.
|
||||||
|
// Acts as an anchor for one or more overlays.
|
||||||
|
display: contents;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c-overlay {
|
||||||
|
@include abs();
|
||||||
|
z-index: 100;
|
||||||
|
|
||||||
|
&__blocker {
|
||||||
|
display: none; // Mobile-first
|
||||||
|
}
|
||||||
|
|
||||||
|
&__outer {
|
||||||
|
@include abs();
|
||||||
|
background: $overlayColorBg;
|
||||||
|
color: $overlayColorFg;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding: $overlayInnerMargin;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__close-button {
|
||||||
|
$p: $interiorMarginSm;
|
||||||
|
border-radius: 100% !important;
|
||||||
|
display: inline-block;
|
||||||
|
position: absolute;
|
||||||
|
top: $p; right: $p;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__contents {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__button-bar {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
margin-top: $interiorMargin;
|
||||||
|
|
||||||
|
> * + * {
|
||||||
|
margin-left: $interiorMargin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.c-button,
|
||||||
|
.c-click-icon {
|
||||||
|
filter: $overlayBrightnessAdjust;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
body.desktop {
|
||||||
|
.c-overlay {
|
||||||
|
&__blocker {
|
||||||
|
@include abs();
|
||||||
|
background: rgba(black, 0.7);
|
||||||
|
cursor: pointer;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__outer {
|
||||||
|
border-radius: $overlayCr;
|
||||||
|
box-shadow: rgba(black, 0.5) 0 2px 25px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overlay types, styling for desktop. Appended to .l-overlay-wrapper element.
|
||||||
|
.l-overlay-large {
|
||||||
|
// Default
|
||||||
|
.c-overlay__outer {
|
||||||
|
@include overlaySizing($overlayOuterMarginLg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.l-overlay-small {
|
||||||
|
.c-overlay__outer {
|
||||||
|
@include overlaySizing($overlayOuterMarginDialog);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.l-overlay-fit {
|
||||||
|
.c-overlay__outer {
|
||||||
|
@include overlaySizing(auto);
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
min-width: 20%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
inject: ['dismiss', 'element', 'buttons', 'notDismissable'],
|
||||||
|
mounted() {
|
||||||
|
this.$refs.element.appendChild(this.element);
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
destroy: function () {
|
||||||
|
if (!this.notDismissable) {
|
||||||
|
this.dismiss();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
buttonClickHandler: function (method) {
|
||||||
|
method();
|
||||||
|
this.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
@ -1,107 +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(['./dialog.html', 'zepto'], function (dialogTemplate, $) {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A dialog may be displayed to show blocking content to users.
|
|
||||||
* @param {module:openmct.View} view the view to show in the dialog
|
|
||||||
* @param {string} [title] the title for this dialog
|
|
||||||
* @constructor
|
|
||||||
* @memberof module:openmct
|
|
||||||
*/
|
|
||||||
function Dialog(view, title) {
|
|
||||||
this.view = view;
|
|
||||||
this.title = title;
|
|
||||||
this.showing = false;
|
|
||||||
this.enabledState = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Display this dialog.
|
|
||||||
* @returns {Promise} a promise that will be resolved if the user
|
|
||||||
* chooses "OK", an rejected if the user chooses "cancel"
|
|
||||||
* @method show
|
|
||||||
* @memberof module:openmct.Dialog#
|
|
||||||
*/
|
|
||||||
Dialog.prototype.show = function () {
|
|
||||||
if (this.showing) {
|
|
||||||
throw new Error("Dialog already showing.");
|
|
||||||
}
|
|
||||||
|
|
||||||
var $body = $('body');
|
|
||||||
var $dialog = $(dialogTemplate);
|
|
||||||
var $contents = $dialog.find('.contents .editor');
|
|
||||||
var $close = $dialog.find('.close');
|
|
||||||
|
|
||||||
var $ok = $dialog.find('.ok');
|
|
||||||
var $cancel = $dialog.find('.cancel');
|
|
||||||
|
|
||||||
if (this.title) {
|
|
||||||
$dialog.find('.title').text(this.title);
|
|
||||||
}
|
|
||||||
|
|
||||||
$body.append($dialog);
|
|
||||||
this.view.show($contents[0]);
|
|
||||||
this.$dialog = $dialog;
|
|
||||||
this.$ok = $ok;
|
|
||||||
this.showing = true;
|
|
||||||
|
|
||||||
[$ok, $cancel, $close].forEach(function ($button) {
|
|
||||||
$button.on('click', this.hide.bind(this));
|
|
||||||
}.bind(this));
|
|
||||||
|
|
||||||
return new Promise(function (resolve, reject) {
|
|
||||||
$ok.on('click', resolve);
|
|
||||||
$cancel.on('click', reject);
|
|
||||||
$close.on('click', reject);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
Dialog.prototype.hide = function () {
|
|
||||||
if (!this.showing) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.$dialog.remove();
|
|
||||||
this.view.destroy();
|
|
||||||
this.showing = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get or set the "enabled" state of the OK button for this dialog.
|
|
||||||
* @param {boolean} [state] true to enable, false to disable
|
|
||||||
* @returns {boolean} true if enabled, false if disabled
|
|
||||||
* @method enabled
|
|
||||||
* @memberof module:openmct.Dialog#
|
|
||||||
*/
|
|
||||||
Dialog.prototype.enabled = function (state) {
|
|
||||||
if (state !== undefined) {
|
|
||||||
this.enabledState = state;
|
|
||||||
if (this.showing) {
|
|
||||||
this.$ok.toggleClass('disabled', !state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return this.enabledState;
|
|
||||||
};
|
|
||||||
|
|
||||||
return Dialog;
|
|
||||||
});
|
|
@ -1,68 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2014-2018, United States Government
|
|
||||||
* as represented by the Administrator of the National Aeronautics and Space
|
|
||||||
* Administration. All rights reserved.
|
|
||||||
*
|
|
||||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
* License for the specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*
|
|
||||||
* Open MCT includes source code licensed under additional open source
|
|
||||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
|
||||||
* this source code distribution or the Licensing information page available
|
|
||||||
* at runtime from the About dialog for additional information.
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
define([], function () {
|
|
||||||
/**
|
|
||||||
* Allows support for common user actions to be attached to views.
|
|
||||||
* @interface GestureAPI
|
|
||||||
* @memberof module:openmct
|
|
||||||
*/
|
|
||||||
function GestureAPI(selectGesture, contextMenuGesture) {
|
|
||||||
this.selectGesture = selectGesture;
|
|
||||||
this.contextMenuGesture = contextMenuGesture;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Designate an HTML element as selectable, and associated with a
|
|
||||||
* particular object.
|
|
||||||
*
|
|
||||||
* @param {HTMLElement} htmlElement the element to make selectable
|
|
||||||
* @param {*} item the object which should become selected when this
|
|
||||||
* element is clicked.
|
|
||||||
* @returns {Function} a function to remove selectability from this
|
|
||||||
* HTML element.
|
|
||||||
* @method selectable
|
|
||||||
* @memberof module:openmct.GestureAPI#
|
|
||||||
*/
|
|
||||||
GestureAPI.prototype.selectable = function (htmlElement, item) {
|
|
||||||
return this.selectGesture.apply(htmlElement, item);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Designate an HTML element as having a context menu associated with
|
|
||||||
* the provided item.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
* @param {HTMLElement} htmlElement the element to make selectable
|
|
||||||
* @param {*} item the object for which a context menu should appear
|
|
||||||
* @returns {Function} a function to remove this geture from this
|
|
||||||
* HTML element.
|
|
||||||
* @method selectable
|
|
||||||
* @memberof module:openmct.GestureAPI#
|
|
||||||
*/
|
|
||||||
GestureAPI.prototype.contextMenu = function (htmlElement, item) {
|
|
||||||
return this.contextMenuGesture.apply(htmlElement, item);
|
|
||||||
};
|
|
||||||
|
|
||||||
return GestureAPI;
|
|
||||||
});
|
|
@ -1,18 +0,0 @@
|
|||||||
<div class="abs overlay l-dialog">
|
|
||||||
<div class="abs blocker"></div>
|
|
||||||
<div class="abs outer-holder">
|
|
||||||
<a class="close icon-x-in-circle"></a>
|
|
||||||
<div class="abs inner-holder contents">
|
|
||||||
<div class="abs top-bar">
|
|
||||||
<div class="dialog-title"></div>
|
|
||||||
<div class="hint"></div>
|
|
||||||
</div>
|
|
||||||
<div class='abs editor'>
|
|
||||||
</div>
|
|
||||||
<div class="abs bottom-bar">
|
|
||||||
<a class='s-button major'>OK</a>
|
|
||||||
<a class='s-button'>Cancel</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
@ -54,7 +54,6 @@ define([
|
|||||||
'../platform/execution/bundle',
|
'../platform/execution/bundle',
|
||||||
'../platform/exporters/bundle',
|
'../platform/exporters/bundle',
|
||||||
'../platform/features/clock/bundle',
|
'../platform/features/clock/bundle',
|
||||||
'../platform/features/fixed/bundle',
|
|
||||||
'../platform/features/imagery/bundle',
|
'../platform/features/imagery/bundle',
|
||||||
'../platform/features/my-items/bundle',
|
'../platform/features/my-items/bundle',
|
||||||
'../platform/features/pages/bundle',
|
'../platform/features/pages/bundle',
|
||||||
@ -96,7 +95,6 @@ define([
|
|||||||
'platform/exporters',
|
'platform/exporters',
|
||||||
'platform/telemetry',
|
'platform/telemetry',
|
||||||
'platform/features/clock',
|
'platform/features/clock',
|
||||||
'platform/features/fixed',
|
|
||||||
'platform/features/imagery',
|
'platform/features/imagery',
|
||||||
'platform/features/pages',
|
'platform/features/pages',
|
||||||
'platform/features/hyperlink',
|
'platform/features/hyperlink',
|
||||||
|
@ -53,14 +53,8 @@
|
|||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import "~styles/sass-base";
|
@import "~styles/sass-base";
|
||||||
|
|
||||||
.l-layout,
|
|
||||||
.c-grid,
|
|
||||||
.c-grid__x,
|
|
||||||
.c-grid__y {
|
|
||||||
@include abs();
|
|
||||||
}
|
|
||||||
|
|
||||||
.l-layout {
|
.l-layout {
|
||||||
|
@include abs();
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
||||||
@ -78,42 +72,23 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.c-grid {
|
.l-shell__main-container {
|
||||||
pointer-events: none;
|
> .l-layout {
|
||||||
|
[s-selected] {
|
||||||
&__x { @include bgTicks($colorGridLines, 'x'); }
|
border: $browseBorderSelected;
|
||||||
&__y { @include bgTicks($colorGridLines, 'y'); }
|
|
||||||
}
|
|
||||||
|
|
||||||
.is-editing {
|
|
||||||
.l-shell__main-container > .l-layout {
|
|
||||||
// Target the top-most layout container and color its background
|
|
||||||
background: rgba($editColor, 0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.s-selected,
|
|
||||||
.s-selected-parent {
|
|
||||||
.l-layout {
|
|
||||||
// Show the layout grid for the top-most child of the current selection,
|
|
||||||
// and hide the grid for deeper nested levels.
|
|
||||||
[class*="__grid-holder"] {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.l-layout [class*="__grid-holder"] {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Styles moved to _global.scss;
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import LayoutFrame from './LayoutFrame.vue';
|
import LayoutFrame from './LayoutFrame.vue';
|
||||||
|
|
||||||
const DEFAULT_GRID_SIZE = [32, 32],
|
const DEFAULT_GRID_SIZE = [5, 5],
|
||||||
DEFAULT_DIMENSIONS = [12, 8],
|
DEFAULT_DIMENSIONS = [50, 50],
|
||||||
DEFAULT_POSITION = [0, 0],
|
DEFAULT_POSITION = [0, 0],
|
||||||
MINIMUM_FRAME_SIZE = [320, 180],
|
MINIMUM_FRAME_SIZE = [320, 180],
|
||||||
DEFAULT_HIDDEN_FRAME_TYPES = [
|
DEFAULT_HIDDEN_FRAME_TYPES = [
|
||||||
@ -128,7 +103,6 @@
|
|||||||
frames: [],
|
frames: [],
|
||||||
frameStyles: [],
|
frameStyles: [],
|
||||||
rawPositions: {},
|
rawPositions: {},
|
||||||
initSelect: true,
|
|
||||||
drilledIn: undefined
|
drilledIn: undefined
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -141,6 +115,7 @@
|
|||||||
this.newDomainObject = this.domainObject;
|
this.newDomainObject = this.domainObject;
|
||||||
this.gridSize = this.newDomainObject.layoutGrid || DEFAULT_GRID_SIZE;
|
this.gridSize = this.newDomainObject.layoutGrid || DEFAULT_GRID_SIZE;
|
||||||
this.composition = this.openmct.composition.get(this.newDomainObject);
|
this.composition = this.openmct.composition.get(this.newDomainObject);
|
||||||
|
this.Listeners = [];
|
||||||
let panels = (((this.newDomainObject.configuration || {}).layout || {}).panels || {});
|
let panels = (((this.newDomainObject.configuration || {}).layout || {}).panels || {});
|
||||||
|
|
||||||
if (this.composition !== undefined) {
|
if (this.composition !== undefined) {
|
||||||
@ -237,8 +212,27 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.removeListeners();
|
||||||
|
let domainObject = selection[0].context.item;
|
||||||
|
|
||||||
|
if (selection[1] && domainObject) {
|
||||||
|
this.attachSelectionListeners(domainObject.identifier);
|
||||||
|
}
|
||||||
|
|
||||||
this.updateDrilledInState();
|
this.updateDrilledInState();
|
||||||
},
|
},
|
||||||
|
attachSelectionListeners(identifier) {
|
||||||
|
let id = this.openmct.objects.makeKeyString(identifier);
|
||||||
|
let path = "configuration.layout.panels[" + id + "]";
|
||||||
|
this.listeners.push(this.openmct.objects.observe(this.newDomainObject, path + ".hasFrame", function (newValue) {
|
||||||
|
this.frameItems.forEach(function (item) {
|
||||||
|
if (item.id === id) {
|
||||||
|
item.hasFrame = newValue;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.frames[id] = newValue;
|
||||||
|
}.bind(this)));
|
||||||
|
},
|
||||||
updateDrilledInState(id) {
|
updateDrilledInState(id) {
|
||||||
this.drilledIn = id;
|
this.drilledIn = id;
|
||||||
this.frameItems.forEach(function (item) {
|
this.frameItems.forEach(function (item) {
|
||||||
@ -284,33 +278,23 @@
|
|||||||
$event.preventDefault();
|
$event.preventDefault();
|
||||||
|
|
||||||
let child = JSON.parse($event.dataTransfer.getData('domainObject'));
|
let child = JSON.parse($event.dataTransfer.getData('domainObject'));
|
||||||
let duplicates = [];
|
|
||||||
let composition = this.newDomainObject.composition;
|
|
||||||
composition.forEach((object) => {
|
|
||||||
if (this.openmct.objects.makeKeyString(JSON.parse(JSON.stringify(object))) ===
|
|
||||||
this.openmct.objects.makeKeyString(child.identifier)) {
|
|
||||||
duplicates.push(object);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Disallow adding a duplicate object to the composition
|
|
||||||
if (duplicates.length !== 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let elementRect = this.$el.getBoundingClientRect();
|
let elementRect = this.$el.getBoundingClientRect();
|
||||||
this.droppedObjectPosition = {
|
this.droppedObjectPosition = {
|
||||||
x: $event.pageX - elementRect.left,
|
x: $event.pageX - elementRect.left,
|
||||||
y: $event.pageY - elementRect.top
|
y: $event.pageY - elementRect.top
|
||||||
}
|
}
|
||||||
// TODO: use the composition API to add child once the default composition
|
|
||||||
// provider supports it instead of mutating the composition directly.
|
|
||||||
// this.composition.add(child).
|
|
||||||
composition.push(child.identifier);
|
|
||||||
this.mutate('composition', composition);
|
|
||||||
},
|
},
|
||||||
handleDragOver($event){
|
handleDragOver($event){
|
||||||
$event.preventDefault();
|
$event.preventDefault();
|
||||||
|
},
|
||||||
|
removeListeners() {
|
||||||
|
if (this.listeners) {
|
||||||
|
this.listeners.forEach(function (l) {
|
||||||
|
l();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.listeners = [];
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
@ -321,6 +305,7 @@
|
|||||||
this.composition.off('remove', this.onRemoveComposition);
|
this.composition.off('remove', this.onRemoveComposition);
|
||||||
this.openmct.off('change', this.selection);
|
this.openmct.off('change', this.selection);
|
||||||
this.unlisten();
|
this.unlisten();
|
||||||
|
this.removeListeners();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,13 +41,13 @@
|
|||||||
<div class="c-frame-edit">
|
<div class="c-frame-edit">
|
||||||
<div class="c-frame-edit__move"
|
<div class="c-frame-edit__move"
|
||||||
@mousedown="startDrag([1,1], [0,0], $event)"></div>
|
@mousedown="startDrag([1,1], [0,0], $event)"></div>
|
||||||
<div class="c-frame-edit__handle --nw"
|
<div class="c-frame-edit__handle c-frame-edit__handle--nw"
|
||||||
@mousedown="startDrag([1,1], [-1,-1], $event)"></div>
|
@mousedown="startDrag([1,1], [-1,-1], $event)"></div>
|
||||||
<div class="c-frame-edit__handle --ne"
|
<div class="c-frame-edit__handle c-frame-edit__handle--ne"
|
||||||
@mousedown="startDrag([0,1], [1,-1], $event)"></div>
|
@mousedown="startDrag([0,1], [1,-1], $event)"></div>
|
||||||
<div class="c-frame-edit__handle --sw"
|
<div class="c-frame-edit__handle c-frame-edit__handle--sw"
|
||||||
@mousedown="startDrag([1,0], [-1,1], $event)"></div>
|
@mousedown="startDrag([1,0], [-1,1], $event)"></div>
|
||||||
<div class="c-frame-edit__handle --se"
|
<div class="c-frame-edit__handle c-frame-edit__handle--se"
|
||||||
@mousedown="startDrag([0,0], [1,1], $event)"></div>
|
@mousedown="startDrag([0,0], [1,1], $event)"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -97,7 +97,7 @@
|
|||||||
&__name {
|
&__name {
|
||||||
@include ellipsize();
|
@include ellipsize();
|
||||||
flex: 0 1 auto;
|
flex: 0 1 auto;
|
||||||
font-size: 1.2em;
|
@include headerFont($size: 1.2em);
|
||||||
|
|
||||||
&:before {
|
&:before {
|
||||||
// Object type icon
|
// Object type icon
|
||||||
@ -132,110 +132,8 @@
|
|||||||
padding: $interiorMargin;
|
padding: $interiorMargin;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*************************** SELECTION */
|
// Styles moved to _global.scss;
|
||||||
&.is-selectable {
|
|
||||||
&:hover {
|
|
||||||
box-shadow: $browseShdwSelectableHov;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.s-selected, // LEGACY
|
|
||||||
&.is-selected {
|
|
||||||
border: $browseBorderSelected;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*************************** EDITING */
|
|
||||||
.is-editing {
|
|
||||||
.c-frame {
|
|
||||||
&:not(.is-drilled-in).is-selectable {
|
|
||||||
border: $editBorderSelectable;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
border: $editBorderSelectableHov;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.s-selected,
|
|
||||||
&.is-selected {
|
|
||||||
border: $editBorderSelected;
|
|
||||||
|
|
||||||
> .c-frame-edit {
|
|
||||||
display: block; // Show the editing rect and handles
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.is-drilled-in {
|
|
||||||
border: $editBorderDrilledIn;
|
|
||||||
}
|
|
||||||
|
|
||||||
.u-links {
|
|
||||||
// Applied in markup to objects that provide links. Disable while editing.
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.c-frame-edit {
|
|
||||||
// The editing rect and handles
|
|
||||||
$z: 10;
|
|
||||||
|
|
||||||
@include abs();
|
|
||||||
box-shadow: rgba($editColor, 0.5) 0 0 10px;
|
|
||||||
display: none;
|
|
||||||
|
|
||||||
&__move {
|
|
||||||
@include abs();
|
|
||||||
cursor: move;
|
|
||||||
z-index: $z;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__handle {
|
|
||||||
$d: 8px;
|
|
||||||
$o: floor($d * -0.5);
|
|
||||||
background: rgba($editColor, 0.3);
|
|
||||||
border: 1px solid $editColor;
|
|
||||||
position: absolute;
|
|
||||||
width: $d; height: $d;
|
|
||||||
top: auto; right: auto; bottom: auto; left: auto;
|
|
||||||
z-index: $z + 1;
|
|
||||||
|
|
||||||
&:before {
|
|
||||||
// Extended hit area
|
|
||||||
$m: -5px;
|
|
||||||
content: '';
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
top: $m; right: $m; bottom: $m; left: $m;
|
|
||||||
z-index: -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background: $editColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.--nw {
|
|
||||||
cursor: nw-resize;
|
|
||||||
left: $o; top: $o;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.--ne {
|
|
||||||
cursor: ne-resize;
|
|
||||||
right: $o; top: $o;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.--se {
|
|
||||||
cursor: se-resize;
|
|
||||||
right: $o; bottom: $o;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.--sw {
|
|
||||||
cursor: sw-resize;
|
|
||||||
left: $o; bottom: $o;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user