mirror of
https://github.com/nasa/openmct.git
synced 2025-06-25 10:44:21 +00:00
Compare commits
3 Commits
new-tree-i
...
tables-rem
Author | SHA1 | Date | |
---|---|---|---|
49eba13f0d | |||
89e97cfadc | |||
dec95a5a18 |
@ -99,10 +99,10 @@ define([
|
||||
|
||||
GeneratorMetadataProvider.prototype.getMetadata = function (domainObject) {
|
||||
return _.extend(
|
||||
{},
|
||||
domainObject.telemetry,
|
||||
METADATA_BY_TYPE[domainObject.type]
|
||||
);
|
||||
{},
|
||||
domainObject.telemetry,
|
||||
METADATA_BY_TYPE[domainObject.type]
|
||||
);
|
||||
};
|
||||
|
||||
return GeneratorMetadataProvider;
|
||||
|
@ -43,14 +43,15 @@ define([
|
||||
form: [
|
||||
{
|
||||
name: "State Duration (seconds)",
|
||||
control: "numberfield",
|
||||
control: "textfield",
|
||||
cssClass: "l-input-sm l-numeric",
|
||||
key: "duration",
|
||||
required: true,
|
||||
property: [
|
||||
"telemetry",
|
||||
"duration"
|
||||
]
|
||||
],
|
||||
pattern: "^\\d*(\\.\\d*)?$"
|
||||
}
|
||||
],
|
||||
initialize: function (object) {
|
||||
|
@ -1,9 +1,9 @@
|
||||
<span class="h-indicator" ng-controller="DialogLaunchController">
|
||||
<!-- DO NOT ADD SPACES BETWEEN THE SPANS - IT ADDS WHITE SPACE!! -->
|
||||
<div class="c-indicator c-indicator--clickable icon-box-with-arrow s-status-available"><span class="label c-indicator__label">
|
||||
<button ng-click="launchProgress(true)">Known</button>
|
||||
<button ng-click="launchProgress(false)">Unknown</button>
|
||||
<button ng-click="launchError()">Error</button>
|
||||
<button ng-click="launchInfo()">Info</button>
|
||||
<div class="ls-indicator icon-box-with-arrow s-status-available"><span class="label">
|
||||
<a ng-click="launchProgress(true)">Known</a>
|
||||
<a ng-click="launchProgress(false)">Unknown</a>
|
||||
<a ng-click="launchError()">Error</a>
|
||||
<a ng-click="launchInfo()">Info</a>
|
||||
</span></div>
|
||||
</span>
|
||||
|
@ -1,9 +1,9 @@
|
||||
<span class="h-indicator" ng-controller="NotificationLaunchController">
|
||||
<!-- DO NOT ADD SPACES BETWEEN THE SPANS - IT ADDS WHITE SPACE!! -->
|
||||
<div class="c-indicator c-indicator--clickable icon-bell s-status-available"><span class="label c-indicator__label">
|
||||
<button ng-click="newInfo()">Success</button>
|
||||
<button ng-click="newError()">Error</button>
|
||||
<button ng-click="newAlert()">Alert</button>
|
||||
<button ng-click="newProgress()">Progress</button>
|
||||
<div class="ls-indicator icon-bell s-status-available"><span class="label">
|
||||
<a ng-click="newInfo()">Success</a>
|
||||
<a ng-click="newError()">Error</a>
|
||||
<a ng-click="newAlert()">Alert</a>
|
||||
<a ng-click="newProgress()">Progress</a>
|
||||
</span></div>
|
||||
</span>
|
||||
|
227
index.html
227
index.html
@ -27,16 +27,16 @@
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<title></title>
|
||||
<script src="dist/openmct.js"></script>
|
||||
<link rel="icon" type="image/png" href="dist/favicons/favicon-96x96.png" sizes="96x96" type="image/x-icon">
|
||||
<link rel="icon" type="image/png" href="dist/favicons/favicon-32x32.png" sizes="32x32" type="image/x-icon">
|
||||
<link rel="icon" type="image/png" href="dist/favicons/favicon-16x16.png" sizes="16x16" type="image/x-icon">
|
||||
<link rel="stylesheet" href="dist/openmct.css">
|
||||
<link rel="icon" type="image/png" href="dist/favicons/favicon-32x32.png" sizes="32x32">
|
||||
<link rel="icon" type="image/png" href="dist/favicons/favicon-96x96.png" sizes="96x96">
|
||||
<link rel="icon" type="image/png" href="dist/favicons/favicon-16x16.png" sizes="16x16">
|
||||
<link rel="shortcut icon" href="dist/favicons/favicon.ico">
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
<script>
|
||||
const FIVE_MINUTES = 5 * 60 * 1000;
|
||||
const THIRTY_MINUTES = 30 * 60 * 1000;
|
||||
|
||||
var THIRTY_MINUTES = 30 * 60 * 1000;
|
||||
[
|
||||
'example/eventGenerator',
|
||||
'example/styleguide'
|
||||
@ -48,12 +48,11 @@
|
||||
openmct.install(openmct.plugins.Generator());
|
||||
openmct.install(openmct.plugins.ExampleImagery());
|
||||
openmct.install(openmct.plugins.UTCTimeSystem());
|
||||
openmct.install(openmct.plugins.ImportExport());
|
||||
openmct.install(openmct.plugins.FixedView());
|
||||
openmct.install(openmct.plugins.AutoflowView({
|
||||
type: "telemetry.panel"
|
||||
}));
|
||||
openmct.install(openmct.plugins.DisplayLayout({
|
||||
showAsView: ['summary-widget', 'example.imagery']
|
||||
}));
|
||||
openmct.install(openmct.plugins.Conductor({
|
||||
menuOptions: [
|
||||
{
|
||||
@ -69,18 +68,218 @@
|
||||
timeSystem: 'utc',
|
||||
clock: 'local',
|
||||
clockOffsets: {
|
||||
start: - THIRTY_MINUTES,
|
||||
end: FIVE_MINUTES
|
||||
start: -25 * 60 * 1000,
|
||||
end: 5 * 60 * 1000
|
||||
}
|
||||
}
|
||||
]
|
||||
}));
|
||||
openmct.install(openmct.plugins.SummaryWidget());
|
||||
openmct.install(openmct.plugins.Notebook());
|
||||
openmct.install(openmct.plugins.FolderView());
|
||||
openmct.install(openmct.plugins.Tabs());
|
||||
openmct.install(openmct.plugins.FlexibleLayout());
|
||||
openmct.install(openmct.plugins.LADTable());
|
||||
openmct.install(openmct.plugins.Filters(['table', 'telemetry.plot.overlay']));
|
||||
openmct.install(openmct.plugins.ObjectMigration());
|
||||
openmct.install(openmct.plugins.ClearData(['table', 'telemetry.plot.overlay', 'telemetry.plot.stacked']));
|
||||
openmct.time.clock('local', {start: -THIRTY_MINUTES, end: 0});
|
||||
openmct.time.timeSystem('utc');
|
||||
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>
|
||||
</html>
|
||||
|
@ -23,9 +23,9 @@
|
||||
/*global module,process*/
|
||||
|
||||
const devMode = process.env.NODE_ENV !== 'production';
|
||||
const browsers = [process.env.NODE_ENV === 'debug' ? 'ChromeDebugging' : 'ChromeHeadless'];
|
||||
|
||||
module.exports = (config) => {
|
||||
|
||||
const webpackConfig = require('./webpack.config.js');
|
||||
delete webpackConfig.output;
|
||||
|
||||
@ -50,17 +50,11 @@ module.exports = (config) => {
|
||||
'coverage',
|
||||
'html'
|
||||
],
|
||||
browsers: browsers,
|
||||
customLaunchers: {
|
||||
ChromeDebugging: {
|
||||
base: 'Chrome',
|
||||
flags: ['--remote-debugging-port=9222'],
|
||||
debug: true
|
||||
}
|
||||
},
|
||||
browsers: ['ChromeHeadless'],
|
||||
colors: true,
|
||||
logLevel: config.LOG_INFO,
|
||||
autoWatch: true,
|
||||
|
||||
coverageReporter: {
|
||||
dir: process.env.CIRCLE_ARTIFACTS ?
|
||||
process.env.CIRCLE_ARTIFACTS + '/coverage' :
|
||||
@ -72,18 +66,22 @@ module.exports = (config) => {
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// HTML test reporting.
|
||||
htmlReporter: {
|
||||
outputDir: "dist/reports/tests",
|
||||
preserveDescribeNesting: true,
|
||||
foldAll: false
|
||||
},
|
||||
|
||||
preprocessors: {
|
||||
// add webpack as preprocessor
|
||||
'platform/**/*Spec.js': [ 'webpack', 'sourcemap' ],
|
||||
'src/**/*Spec.js': [ 'webpack', 'sourcemap' ]
|
||||
'platform/**/*Spec.js': [ 'webpack' ],
|
||||
'src/**/*Spec.js': [ 'webpack' ]
|
||||
},
|
||||
|
||||
webpack: webpackConfig,
|
||||
|
||||
webpackMiddleware: {
|
||||
stats: 'errors-only',
|
||||
logLevel: 'warn'
|
||||
@ -91,3 +89,4 @@ module.exports = (config) => {
|
||||
singleRun: true
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,7 @@
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
/*global module*/
|
||||
/*global module,BUILD_CONSTANTS*/
|
||||
|
||||
const matcher = /\/openmct.js$/;
|
||||
if (document.currentScript) {
|
||||
|
@ -1,10 +1,9 @@
|
||||
{
|
||||
"name": "openmct",
|
||||
"version": "1.0.0-beta",
|
||||
"version": "0.14.0-SNAPSHOT",
|
||||
"description": "The Open MCT core platform",
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"acorn": "6.2.0",
|
||||
"angular": "1.4.14",
|
||||
"angular-route": "1.4.14",
|
||||
"babel-eslint": "8.2.6",
|
||||
@ -26,7 +25,7 @@
|
||||
"eventemitter3": "^1.2.0",
|
||||
"exports-loader": "^0.7.0",
|
||||
"express": "^4.13.1",
|
||||
"fast-sass-loader": "1.4.6",
|
||||
"fast-sass-loader": "^1.4.5",
|
||||
"file-loader": "^1.1.11",
|
||||
"file-saver": "^1.3.8",
|
||||
"git-rev-sync": "^1.4.0",
|
||||
@ -43,7 +42,6 @@
|
||||
"karma-coverage": "^1.1.2",
|
||||
"karma-html-reporter": "^0.2.7",
|
||||
"karma-jasmine": "^1.1.2",
|
||||
"karma-sourcemap-loader": "^0.3.7",
|
||||
"karma-webpack": "^3.0.0",
|
||||
"location-bar": "^3.0.1",
|
||||
"lodash": "^3.10.1",
|
||||
@ -57,7 +55,7 @@
|
||||
"node-bourbon": "^4.2.3",
|
||||
"node-sass": "^4.9.2",
|
||||
"painterro": "^0.2.65",
|
||||
"printj": "^1.2.1",
|
||||
"printj": "^1.1.0",
|
||||
"raw-loader": "^0.5.1",
|
||||
"request": "^2.69.0",
|
||||
"split": "^1.0.0",
|
||||
@ -80,7 +78,6 @@
|
||||
"build:dev": "webpack",
|
||||
"build:watch": "webpack --watch",
|
||||
"test": "karma start --single-run",
|
||||
"test-debug": "NODE_ENV=debug karma start --no-single-run",
|
||||
"test:watch": "karma start --no-single-run",
|
||||
"verify": "concurrently 'npm:test' 'npm:lint'",
|
||||
"jsdoc": "jsdoc -c jsdoc.json -R API.md -r -d dist/docs/api",
|
||||
|
@ -21,10 +21,17 @@
|
||||
*****************************************************************************/
|
||||
|
||||
define([
|
||||
"./src/BrowseController",
|
||||
"./src/PaneController",
|
||||
"./src/InspectorPaneController",
|
||||
"./src/BrowseObjectController",
|
||||
"./src/MenuArrowController",
|
||||
"./src/ObjectHeaderController",
|
||||
"./src/navigation/NavigationService",
|
||||
"./src/navigation/NavigateAction",
|
||||
"./src/navigation/OrphanNavigationHandler",
|
||||
"./src/windowing/NewTabAction",
|
||||
"./src/windowing/WindowTitler",
|
||||
"./res/templates/browse.html",
|
||||
"./res/templates/browse-object.html",
|
||||
"./res/templates/browse/object-header.html",
|
||||
@ -35,10 +42,17 @@ define([
|
||||
"./res/templates/browse/inspector-region.html",
|
||||
'legacyRegistry'
|
||||
], function (
|
||||
BrowseController,
|
||||
PaneController,
|
||||
InspectorPaneController,
|
||||
BrowseObjectController,
|
||||
MenuArrowController,
|
||||
ObjectHeaderController,
|
||||
NavigationService,
|
||||
NavigateAction,
|
||||
OrphanNavigationHandler,
|
||||
NewTabAction,
|
||||
WindowTitler,
|
||||
browseTemplate,
|
||||
browseObjectTemplate,
|
||||
objectHeaderTemplate,
|
||||
@ -61,6 +75,70 @@ define([
|
||||
"priority": "fallback"
|
||||
}
|
||||
],
|
||||
"controllers": [
|
||||
{
|
||||
"key": "BrowseController",
|
||||
"implementation": BrowseController,
|
||||
"depends": [
|
||||
"$scope",
|
||||
"$route",
|
||||
"$location",
|
||||
"objectService",
|
||||
"navigationService",
|
||||
"urlService",
|
||||
"DEFAULT_PATH"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "PaneController",
|
||||
"implementation": PaneController,
|
||||
"priority": "preferred",
|
||||
"depends": [
|
||||
"$scope",
|
||||
"agentService",
|
||||
"$window",
|
||||
"$location",
|
||||
"$attrs",
|
||||
"navigationService"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "BrowseObjectController",
|
||||
"implementation": BrowseObjectController,
|
||||
"depends": [
|
||||
"$scope",
|
||||
"$location",
|
||||
"$route"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "MenuArrowController",
|
||||
"implementation": MenuArrowController,
|
||||
"depends": [
|
||||
"$scope"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "InspectorPaneController",
|
||||
"implementation": InspectorPaneController,
|
||||
"priority": "preferred",
|
||||
"depends": [
|
||||
"$scope",
|
||||
"agentService",
|
||||
"$window",
|
||||
"navigationService",
|
||||
"$location",
|
||||
"$attrs"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "ObjectHeaderController",
|
||||
"implementation": ObjectHeaderController,
|
||||
"depends": [
|
||||
"$scope"
|
||||
]
|
||||
}
|
||||
],
|
||||
"representations": [
|
||||
{
|
||||
"key": "browse-object",
|
||||
@ -148,6 +226,14 @@ define([
|
||||
}
|
||||
],
|
||||
"runs": [
|
||||
{
|
||||
"implementation": WindowTitler,
|
||||
"depends": [
|
||||
"navigationService",
|
||||
"$rootScope",
|
||||
"$document"
|
||||
]
|
||||
},
|
||||
{
|
||||
"implementation": OrphanNavigationHandler,
|
||||
"depends": [
|
||||
|
215
platform/commonUI/browse/src/BrowseController.js
Normal file
215
platform/commonUI/browse/src/BrowseController.js
Normal file
@ -0,0 +1,215 @@
|
||||
/*****************************************************************************
|
||||
* 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.
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
* This bundle implements Browse mode.
|
||||
* @namespace platform/commonUI/browse
|
||||
*/
|
||||
define(
|
||||
['lodash'],
|
||||
function (_) {
|
||||
|
||||
/**
|
||||
* The BrowseController is used to populate the initial scope in Browse
|
||||
* mode. It loads the root object from the objectService and makes it
|
||||
* available in the scope for Angular template's; this is the point at
|
||||
* which Angular templates first have access to the domain object
|
||||
* hierarchy.
|
||||
*
|
||||
* @memberof platform/commonUI/browse
|
||||
* @constructor
|
||||
*/
|
||||
function BrowseController(
|
||||
$scope,
|
||||
$route,
|
||||
$location,
|
||||
objectService,
|
||||
navigationService,
|
||||
urlService,
|
||||
defaultPath
|
||||
) {
|
||||
window.browseScope = $scope;
|
||||
var initialPath = ($route.current.params.ids || defaultPath).split("/"),
|
||||
currentIds;
|
||||
|
||||
$scope.treeModel = {
|
||||
selectedObject: undefined,
|
||||
onSelection: function (object) {
|
||||
navigationService.setNavigation(object, true);
|
||||
},
|
||||
allowSelection: function (object) {
|
||||
var domainObjectInView = navigationService.getNavigation(),
|
||||
isInEditMode = domainObjectInView.getCapability('status').get('editing');
|
||||
|
||||
if (isInEditMode) {
|
||||
|
||||
var actions = object.getCapability('action'),
|
||||
previewAction = actions.getActions({key: 'mct-preview-action'})[0];
|
||||
|
||||
if (previewAction && previewAction.perform) {
|
||||
previewAction.perform();
|
||||
return false;
|
||||
} else {
|
||||
return navigationService.shouldNavigate();
|
||||
}
|
||||
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function idsForObject(domainObject) {
|
||||
return urlService
|
||||
.urlForLocation("", domainObject)
|
||||
.replace('/', '');
|
||||
}
|
||||
|
||||
// Find an object in an array of objects.
|
||||
function findObject(domainObjects, id) {
|
||||
var i;
|
||||
for (i = 0; i < domainObjects.length; i += 1) {
|
||||
if (domainObjects[i].getId() === id) {
|
||||
return domainObjects[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// helper, fetch a single object from the object service.
|
||||
function getObject(id) {
|
||||
return objectService.getObjects([id])
|
||||
.then(function (results) {
|
||||
return results[id];
|
||||
});
|
||||
}
|
||||
|
||||
// recursively locate and return an object inside of a container
|
||||
// via a path. If at any point in the recursion it fails to find
|
||||
// the next object, it will return the parent.
|
||||
function findViaComposition(containerObject, path) {
|
||||
var nextId = path.shift();
|
||||
if (!nextId) {
|
||||
return containerObject;
|
||||
}
|
||||
return containerObject.useCapability('composition')
|
||||
.then(function (composees) {
|
||||
var nextObject = findObject(composees, nextId);
|
||||
if (!nextObject) {
|
||||
return containerObject;
|
||||
}
|
||||
if (!nextObject.hasCapability('composition')) {
|
||||
return nextObject;
|
||||
}
|
||||
return findViaComposition(nextObject, path);
|
||||
});
|
||||
}
|
||||
|
||||
function navigateToObject(desiredObject) {
|
||||
$scope.navigatedObject = desiredObject;
|
||||
$scope.treeModel.selectedObject = desiredObject;
|
||||
currentIds = idsForObject(desiredObject);
|
||||
$route.current.pathParams.ids = currentIds;
|
||||
$location.path('/browse/' + currentIds);
|
||||
}
|
||||
|
||||
function getLastChildIfRoot(object) {
|
||||
if (object.getId() !== 'ROOT') {
|
||||
return object;
|
||||
}
|
||||
return object.useCapability('composition')
|
||||
.then(function (composees) {
|
||||
return composees[composees.length - 1];
|
||||
});
|
||||
}
|
||||
|
||||
function navigateToPath(path) {
|
||||
return getObject('ROOT')
|
||||
.then(function (root) {
|
||||
return findViaComposition(root, path);
|
||||
})
|
||||
.then(getLastChildIfRoot)
|
||||
.then(function (object) {
|
||||
navigationService.setNavigation(object);
|
||||
});
|
||||
}
|
||||
|
||||
getObject('ROOT')
|
||||
.then(function (root) {
|
||||
$scope.domainObject = root;
|
||||
navigateToPath(initialPath);
|
||||
});
|
||||
|
||||
// Handle navigation events from view service. Only navigates
|
||||
// if path has changed.
|
||||
function navigateDirectlyToModel(domainObject) {
|
||||
var newIds = idsForObject(domainObject);
|
||||
if (currentIds !== newIds) {
|
||||
currentIds = newIds;
|
||||
navigateToObject(domainObject);
|
||||
}
|
||||
}
|
||||
|
||||
// Listen for changes in navigation state.
|
||||
navigationService.addListener(navigateDirectlyToModel);
|
||||
|
||||
// Listen for route changes which are caused by browser events
|
||||
// (e.g. bookmarks to pages in OpenMCT) and prevent them. Instead,
|
||||
// navigate to the path ourselves, which results in it being
|
||||
// properly set.
|
||||
$scope.$on('$routeChangeStart', function (event, route, oldRoute) {
|
||||
if (route.$$route === $route.current.$$route) {
|
||||
if (route.pathParams.ids &&
|
||||
route.pathParams.ids !== $route.current.pathParams.ids) {
|
||||
|
||||
var otherParams = _.omit(route.params, 'ids');
|
||||
var oldOtherParams = _.omit(oldRoute.params, 'ids');
|
||||
var deletedParams = _.omit(oldOtherParams, _.keys(otherParams));
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
navigateToPath(route.pathParams.ids.split('/'))
|
||||
.then(function () {
|
||||
if (!_.isEqual(otherParams, oldOtherParams)) {
|
||||
_.forEach(otherParams, function (v, k) {
|
||||
$location.search(k, v);
|
||||
});
|
||||
_.forEach(deletedParams, function (k) {
|
||||
$location.search(k, null);
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
navigateToPath([]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Clean up when the scope is destroyed
|
||||
$scope.$on("$destroy", function () {
|
||||
navigationService.removeListener(navigateDirectlyToModel);
|
||||
});
|
||||
}
|
||||
|
||||
return BrowseController;
|
||||
}
|
||||
);
|
||||
|
72
platform/commonUI/browse/src/BrowseObjectController.js
Normal file
72
platform/commonUI/browse/src/BrowseObjectController.js
Normal file
@ -0,0 +1,72 @@
|
||||
/*****************************************************************************
|
||||
* 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 () {
|
||||
|
||||
/**
|
||||
* Controller for the `browse-object` representation of a domain
|
||||
* object (the right-hand side of Browse mode.)
|
||||
* @memberof platform/commonUI/browse
|
||||
* @constructor
|
||||
*/
|
||||
function BrowseObjectController($scope, $location, $route) {
|
||||
function setViewForDomainObject(domainObject) {
|
||||
|
||||
var locationViewKey = $location.search().view;
|
||||
|
||||
function selectViewIfMatching(view) {
|
||||
if (view.key === locationViewKey) {
|
||||
$scope.representation = $scope.representation || {};
|
||||
$scope.representation.selected = view;
|
||||
}
|
||||
}
|
||||
|
||||
if (locationViewKey) {
|
||||
((domainObject && domainObject.useCapability('view')) || [])
|
||||
.forEach(selectViewIfMatching);
|
||||
}
|
||||
}
|
||||
|
||||
function updateQueryParam(viewKey) {
|
||||
if (viewKey && $location.search().view !== viewKey) {
|
||||
$location.search('view', viewKey);
|
||||
}
|
||||
}
|
||||
|
||||
$scope.$watch('domainObject', setViewForDomainObject);
|
||||
$scope.$watch('representation.selected.key', updateQueryParam);
|
||||
$scope.$on('$locationChangeSuccess', function () {
|
||||
setViewForDomainObject($scope.domainObject);
|
||||
});
|
||||
|
||||
$scope.doAction = function (action) {
|
||||
return $scope[action] && $scope[action]();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
return BrowseObjectController;
|
||||
}
|
||||
);
|
||||
|
78
platform/commonUI/browse/src/InspectorPaneController.js
Normal file
78
platform/commonUI/browse/src/InspectorPaneController.js
Normal file
@ -0,0 +1,78 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT Web 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 Web 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(
|
||||
["./PaneController"],
|
||||
function (PaneController) {
|
||||
|
||||
/**
|
||||
* Pane controller that reveals inspector, if hidden, when object
|
||||
* switches to edit mode.
|
||||
*
|
||||
* @param $scope
|
||||
* @param agentService
|
||||
* @param $window
|
||||
* @param navigationService
|
||||
* @constructor
|
||||
*/
|
||||
function InspectorPaneController($scope, agentService, $window, navigationService, $location, $attrs) {
|
||||
PaneController.call(this, $scope, agentService, $window, $location, $attrs);
|
||||
var statusListener,
|
||||
self = this;
|
||||
|
||||
function showInspector(statuses) {
|
||||
if (statuses.indexOf('editing') !== -1 && !self.visible()) {
|
||||
self.toggle();
|
||||
}
|
||||
}
|
||||
|
||||
function attachStatusListener(domainObject) {
|
||||
// Remove existing status listener if existing
|
||||
if (statusListener) {
|
||||
statusListener();
|
||||
}
|
||||
|
||||
if (domainObject.hasCapability("status")) {
|
||||
statusListener = domainObject.getCapability("status").listen(showInspector);
|
||||
}
|
||||
return statusListener;
|
||||
}
|
||||
|
||||
var domainObject = navigationService.getNavigation();
|
||||
if (domainObject) {
|
||||
attachStatusListener(domainObject);
|
||||
}
|
||||
|
||||
navigationService.addListener(attachStatusListener);
|
||||
|
||||
$scope.$on("$destroy", function () {
|
||||
statusListener();
|
||||
navigationService.removeListener(attachStatusListener);
|
||||
});
|
||||
}
|
||||
|
||||
InspectorPaneController.prototype = Object.create(PaneController.prototype);
|
||||
|
||||
return InspectorPaneController;
|
||||
}
|
||||
);
|
59
platform/commonUI/browse/src/MenuArrowController.js
Normal file
59
platform/commonUI/browse/src/MenuArrowController.js
Normal file
@ -0,0 +1,59 @@
|
||||
/*****************************************************************************
|
||||
* 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 MenuArrowController. Created by shale on 06/30/2015.
|
||||
*/
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
|
||||
/**
|
||||
* A left-click on the menu arrow should display a
|
||||
* context menu. This controller launches the context
|
||||
* menu.
|
||||
* @memberof platform/commonUI/browse
|
||||
* @constructor
|
||||
*/
|
||||
function MenuArrowController($scope) {
|
||||
this.$scope = $scope;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a context menu for the domain object in this scope.
|
||||
*
|
||||
* @param event the browser event which caused this (used to
|
||||
* position the menu)
|
||||
*/
|
||||
MenuArrowController.prototype.showMenu = function (event) {
|
||||
var actionContext = {
|
||||
key: 'menu',
|
||||
domainObject: this.$scope.domainObject,
|
||||
event: event
|
||||
};
|
||||
|
||||
this.$scope.domainObject.getCapability('action').perform(actionContext);
|
||||
};
|
||||
|
||||
return MenuArrowController;
|
||||
}
|
||||
);
|
92
platform/commonUI/browse/src/ObjectHeaderController.js
Normal file
92
platform/commonUI/browse/src/ObjectHeaderController.js
Normal file
@ -0,0 +1,92 @@
|
||||
/*****************************************************************************
|
||||
* 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 () {
|
||||
|
||||
/**
|
||||
* Controller to provide the ability to inline edit an object name.
|
||||
*
|
||||
* @constructor
|
||||
* @memberof platform/commonUI/browse
|
||||
*/
|
||||
function ObjectHeaderController($scope) {
|
||||
this.$scope = $scope;
|
||||
this.domainObject = $scope.domainObject;
|
||||
this.editable = this.allowEdit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the object name on blur and enter keypress events.
|
||||
*
|
||||
* @param event the mouse event
|
||||
*/
|
||||
ObjectHeaderController.prototype.updateName = function (event) {
|
||||
if (!event || !event.currentTarget) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.type === 'blur') {
|
||||
this.updateModel(event);
|
||||
} else if (event.which === 13) {
|
||||
this.updateModel(event);
|
||||
event.currentTarget.blur();
|
||||
window.getSelection().removeAllRanges();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Updates the model.
|
||||
*
|
||||
* @param event the mouse event
|
||||
* @param private
|
||||
*/
|
||||
ObjectHeaderController.prototype.updateModel = function (event) {
|
||||
var name = event.currentTarget.textContent.replace(/\n/g, ' ');
|
||||
|
||||
if (name.length === 0) {
|
||||
name = "Unnamed " + this.domainObject.getCapability("type").typeDef.name;
|
||||
event.currentTarget.textContent = name;
|
||||
}
|
||||
|
||||
if (name !== this.domainObject.getModel().name) {
|
||||
this.domainObject.getCapability('mutation').mutate(function (model) {
|
||||
model.name = name;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks if the domain object is editable.
|
||||
*
|
||||
* @private
|
||||
* @return true if object is editable
|
||||
*/
|
||||
ObjectHeaderController.prototype.allowEdit = function () {
|
||||
var type = this.domainObject && this.domainObject.getCapability('type');
|
||||
return !!(type && type.hasFeature('creation'));
|
||||
};
|
||||
|
||||
return ObjectHeaderController;
|
||||
}
|
||||
);
|
88
platform/commonUI/browse/src/PaneController.js
Normal file
88
platform/commonUI/browse/src/PaneController.js
Normal file
@ -0,0 +1,88 @@
|
||||
/*****************************************************************************
|
||||
* 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 () {
|
||||
var navigationListenerAdded = false;
|
||||
/**
|
||||
* Controller to provide the ability to show/hide the tree in
|
||||
* Browse mode.
|
||||
* @constructor
|
||||
* @memberof platform/commonUI/browse
|
||||
*/
|
||||
function PaneController($scope, agentService, $window, $location, $attrs, navigationService) {
|
||||
var self = this;
|
||||
this.agentService = agentService;
|
||||
var hideParameterPresent = $location.search().hasOwnProperty($attrs.hideParameter);
|
||||
|
||||
if ($attrs.hideParameter && hideParameterPresent) {
|
||||
this.state = false;
|
||||
$location.search($attrs.hideParameter, undefined);
|
||||
} else {
|
||||
this.state = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback to invoke when any selection occurs in the tree.
|
||||
* This controller can be passed in as the `parameters` object
|
||||
* to the tree representation.
|
||||
*
|
||||
* @property {Function} callback
|
||||
* @memberof platform/commonUI/browse.PaneController#
|
||||
*/
|
||||
this.callback = function () {
|
||||
// Note that, since this is a callback to pass, this is not
|
||||
// declared as a method but as a property which happens to
|
||||
// be a function.
|
||||
if (agentService.isPhone() && agentService.isPortrait()) {
|
||||
// On phones, trees should collapse in portrait mode
|
||||
// when something is navigated-to.
|
||||
self.state = false;
|
||||
}
|
||||
};
|
||||
|
||||
if (navigationService && navigationService.addListener && !navigationListenerAdded) {
|
||||
navigationService.addListener(this.callback);
|
||||
navigationListenerAdded = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle the visibility of the pane.
|
||||
*/
|
||||
PaneController.prototype.toggle = function () {
|
||||
this.state = !this.state;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the desired visibility state of the pane.
|
||||
* @returns {boolean} true when visible
|
||||
*/
|
||||
PaneController.prototype.visible = function () {
|
||||
return !!this.state;
|
||||
};
|
||||
|
||||
return PaneController;
|
||||
}
|
||||
);
|
51
platform/commonUI/browse/src/windowing/WindowTitler.js
Normal file
51
platform/commonUI/browse/src/windowing/WindowTitler.js
Normal file
@ -0,0 +1,51 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2018, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
|
||||
/**
|
||||
* Updates the title of the current window to reflect the name
|
||||
* of the currently navigated-to domain object.
|
||||
* @memberof platform/commonUI/browse
|
||||
* @constructor
|
||||
*/
|
||||
function WindowTitler(navigationService, $rootScope, $document) {
|
||||
// Look up name of the navigated domain object...
|
||||
function getNavigatedObjectName() {
|
||||
var navigatedObject = navigationService.getNavigation();
|
||||
return navigatedObject && navigatedObject.getModel().name;
|
||||
}
|
||||
|
||||
// Set the window title...
|
||||
function setTitle(name) {
|
||||
$document[0].title = name;
|
||||
}
|
||||
|
||||
// Watch the former, and invoke the latter
|
||||
$rootScope.$watch(getNavigatedObjectName, setTitle);
|
||||
}
|
||||
|
||||
return WindowTitler;
|
||||
}
|
||||
);
|
266
platform/commonUI/browse/test/BrowseControllerSpec.js
Normal file
266
platform/commonUI/browse/test/BrowseControllerSpec.js
Normal file
@ -0,0 +1,266 @@
|
||||
/*****************************************************************************
|
||||
* 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 console*/
|
||||
|
||||
/**
|
||||
* MCTRepresentationSpec. Created by vwoeltje on 11/6/14.
|
||||
*/
|
||||
define(
|
||||
[
|
||||
"../src/BrowseController",
|
||||
"../src/navigation/NavigationService"
|
||||
],
|
||||
function (
|
||||
BrowseController,
|
||||
NavigationService
|
||||
) {
|
||||
|
||||
describe("The browse controller", function () {
|
||||
var mockScope,
|
||||
mockRoute,
|
||||
mockLocation,
|
||||
mockObjectService,
|
||||
mockNavigationService,
|
||||
mockRootObject,
|
||||
mockUrlService,
|
||||
mockDefaultRootObject,
|
||||
mockOtherDomainObject,
|
||||
mockNextObject,
|
||||
testDefaultRoot,
|
||||
controller;
|
||||
|
||||
function waitsForNavigation() {
|
||||
return new Promise(function (resolve) {
|
||||
mockNavigationService.setNavigation.and.callFake(function (obj) {
|
||||
var returnValue;
|
||||
try {
|
||||
returnValue = NavigationService.prototype.setNavigation.call(mockNavigationService, obj);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
//Not rejecting because 'setNavigation' has been called, which is what's being tested here.
|
||||
//Rejecting will fail tests.
|
||||
}
|
||||
resolve();
|
||||
return returnValue;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function instantiateController() {
|
||||
controller = new BrowseController(
|
||||
mockScope,
|
||||
mockRoute,
|
||||
mockLocation,
|
||||
mockObjectService,
|
||||
mockNavigationService,
|
||||
mockUrlService,
|
||||
testDefaultRoot
|
||||
);
|
||||
}
|
||||
|
||||
beforeEach(function () {
|
||||
testDefaultRoot = "some-root-level-domain-object";
|
||||
|
||||
mockScope = jasmine.createSpyObj(
|
||||
"$scope",
|
||||
["$on", "$watch"]
|
||||
);
|
||||
mockRoute = { current: { params: {}, pathParams: {} } };
|
||||
mockUrlService = jasmine.createSpyObj(
|
||||
"urlService",
|
||||
["urlForLocation"]
|
||||
);
|
||||
mockUrlService.urlForLocation.and.callFake(function (mode, object) {
|
||||
if (object === mockDefaultRootObject) {
|
||||
return [mode, testDefaultRoot].join('/');
|
||||
}
|
||||
if (object === mockOtherDomainObject) {
|
||||
return [mode, 'other'].join('/');
|
||||
}
|
||||
if (object === mockNextObject) {
|
||||
return [mode, testDefaultRoot, 'next'].join('/');
|
||||
}
|
||||
throw new Error('Tried to get url for unexpected object');
|
||||
});
|
||||
mockLocation = jasmine.createSpyObj(
|
||||
"$location",
|
||||
["path"]
|
||||
);
|
||||
mockObjectService = jasmine.createSpyObj(
|
||||
"objectService",
|
||||
["getObjects"]
|
||||
);
|
||||
mockNavigationService = new NavigationService({});
|
||||
[
|
||||
"getNavigation",
|
||||
"setNavigation",
|
||||
"addListener",
|
||||
"removeListener"
|
||||
].forEach(function (method) {
|
||||
spyOn(mockNavigationService, method)
|
||||
.and.callThrough();
|
||||
});
|
||||
mockRootObject = jasmine.createSpyObj(
|
||||
"rootObjectContainer",
|
||||
["getId", "getCapability", "getModel", "useCapability", "hasCapability"]
|
||||
);
|
||||
mockDefaultRootObject = jasmine.createSpyObj(
|
||||
"defaultRootObject",
|
||||
["getId", "getCapability", "getModel", "useCapability", "hasCapability"]
|
||||
);
|
||||
mockOtherDomainObject = jasmine.createSpyObj(
|
||||
"otherDomainObject",
|
||||
["getId", "getCapability", "getModel", "useCapability", "hasCapability"]
|
||||
);
|
||||
mockNextObject = jasmine.createSpyObj(
|
||||
"nestedDomainObject",
|
||||
["getId", "getCapability", "getModel", "useCapability", "hasCapability"]
|
||||
);
|
||||
mockObjectService.getObjects.and.returnValue(Promise.resolve({
|
||||
ROOT: mockRootObject
|
||||
}));
|
||||
mockRootObject.useCapability.and.returnValue(Promise.resolve([
|
||||
mockOtherDomainObject,
|
||||
mockDefaultRootObject
|
||||
]));
|
||||
mockRootObject.hasCapability.and.returnValue(true);
|
||||
mockDefaultRootObject.useCapability.and.returnValue(Promise.resolve([
|
||||
mockNextObject
|
||||
]));
|
||||
mockDefaultRootObject.hasCapability.and.returnValue(true);
|
||||
mockOtherDomainObject.hasCapability.and.returnValue(false);
|
||||
mockNextObject.useCapability.and.returnValue(undefined);
|
||||
mockNextObject.hasCapability.and.returnValue(false);
|
||||
mockNextObject.getId.and.returnValue("next");
|
||||
mockDefaultRootObject.getId.and.returnValue(testDefaultRoot);
|
||||
|
||||
instantiateController();
|
||||
return waitsForNavigation();
|
||||
});
|
||||
|
||||
it("uses composition to set the navigated object, if there is none", function () {
|
||||
instantiateController();
|
||||
return waitsForNavigation().then(function () {
|
||||
expect(mockNavigationService.setNavigation)
|
||||
.toHaveBeenCalledWith(mockDefaultRootObject);
|
||||
});
|
||||
});
|
||||
|
||||
it("navigates to a root-level object, even when default path is not found", function () {
|
||||
mockDefaultRootObject.getId
|
||||
.and.returnValue("something-other-than-the-" + testDefaultRoot);
|
||||
instantiateController();
|
||||
|
||||
return waitsForNavigation().then(function () {
|
||||
expect(mockNavigationService.setNavigation)
|
||||
.toHaveBeenCalledWith(mockDefaultRootObject);
|
||||
});
|
||||
});
|
||||
|
||||
it("does not try to override navigation", function () {
|
||||
mockNavigationService.getNavigation.and.returnValue(mockDefaultRootObject);
|
||||
instantiateController();
|
||||
return waitsForNavigation().then(function () {
|
||||
expect(mockScope.navigatedObject).toBe(mockDefaultRootObject);
|
||||
});
|
||||
});
|
||||
|
||||
it("updates scope when navigated object changes", function () {
|
||||
// Should have registered a listener - call it
|
||||
mockNavigationService.addListener.calls.mostRecent().args[0](
|
||||
mockOtherDomainObject
|
||||
);
|
||||
expect(mockScope.navigatedObject).toEqual(mockOtherDomainObject);
|
||||
});
|
||||
|
||||
|
||||
it("releases its navigation listener when its scope is destroyed", function () {
|
||||
expect(mockScope.$on).toHaveBeenCalledWith(
|
||||
"$destroy",
|
||||
jasmine.any(Function)
|
||||
);
|
||||
mockScope.$on.calls.mostRecent().args[1]();
|
||||
|
||||
// Should remove the listener it added earlier
|
||||
expect(mockNavigationService.removeListener).toHaveBeenCalledWith(
|
||||
mockNavigationService.addListener.calls.mostRecent().args[0]
|
||||
);
|
||||
});
|
||||
|
||||
it("uses route parameters to choose initially-navigated object", function () {
|
||||
mockRoute.current.params.ids = testDefaultRoot + "/next";
|
||||
instantiateController();
|
||||
return waitsForNavigation().then(function () {
|
||||
expect(mockScope.navigatedObject).toBe(mockNextObject);
|
||||
expect(mockNavigationService.setNavigation)
|
||||
.toHaveBeenCalledWith(mockNextObject);
|
||||
});
|
||||
});
|
||||
|
||||
it("handles invalid IDs by going as far as possible", function () {
|
||||
// Idea here is that if we get a bad path of IDs,
|
||||
// browse controller should traverse down it until
|
||||
// it hits an invalid ID.
|
||||
mockRoute.current.params.ids = testDefaultRoot + "/junk";
|
||||
instantiateController();
|
||||
return waitsForNavigation().then(function () {
|
||||
expect(mockScope.navigatedObject).toBe(mockDefaultRootObject);
|
||||
expect(mockNavigationService.setNavigation)
|
||||
.toHaveBeenCalledWith(mockDefaultRootObject);
|
||||
});
|
||||
});
|
||||
|
||||
it("handles compositionless objects by going as far as possible", function () {
|
||||
// Idea here is that if we get a path which passes
|
||||
// through an object without a composition, browse controller
|
||||
// should stop at it since remaining IDs cannot be loaded.
|
||||
mockRoute.current.params.ids = testDefaultRoot + "/next/junk";
|
||||
instantiateController();
|
||||
return waitsForNavigation().then(function () {
|
||||
expect(mockScope.navigatedObject).toBe(mockNextObject);
|
||||
expect(mockNavigationService.setNavigation)
|
||||
.toHaveBeenCalledWith(mockNextObject);
|
||||
});
|
||||
});
|
||||
|
||||
it("updates the displayed route to reflect current navigation", function () {
|
||||
// In order to trigger a route update and not a route change,
|
||||
// the current route must be updated before location.path is
|
||||
// called.
|
||||
expect(mockRoute.current.pathParams.ids)
|
||||
.not
|
||||
.toBe(testDefaultRoot + '/next');
|
||||
mockLocation.path.and.callFake(function () {
|
||||
expect(mockRoute.current.pathParams.ids)
|
||||
.toBe(testDefaultRoot + '/next');
|
||||
});
|
||||
mockNavigationService.addListener.calls.mostRecent().args[0](
|
||||
mockNextObject
|
||||
);
|
||||
expect(mockLocation.path).toHaveBeenCalledWith(
|
||||
'/browse/' + testDefaultRoot + '/next'
|
||||
);
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
);
|
93
platform/commonUI/browse/test/BrowseObjectControllerSpec.js
Normal file
93
platform/commonUI/browse/test/BrowseObjectControllerSpec.js
Normal file
@ -0,0 +1,93 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2018, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define(
|
||||
["../src/BrowseObjectController"],
|
||||
function (BrowseObjectController) {
|
||||
|
||||
describe("The browse object controller", function () {
|
||||
var mockScope,
|
||||
mockLocation,
|
||||
mockRoute,
|
||||
controller;
|
||||
|
||||
// Utility function; look for a $watch on scope and fire it
|
||||
function fireWatch(expr, value) {
|
||||
mockScope.$watch.calls.all().forEach(function (call) {
|
||||
if (call.args[0] === expr) {
|
||||
call.args[1](value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
beforeEach(function () {
|
||||
mockScope = jasmine.createSpyObj(
|
||||
"$scope",
|
||||
["$on", "$watch"]
|
||||
);
|
||||
mockRoute = { current: { params: {} } };
|
||||
mockLocation = jasmine.createSpyObj(
|
||||
"$location",
|
||||
["path", "search"]
|
||||
);
|
||||
mockLocation.search.and.returnValue({});
|
||||
|
||||
controller = new BrowseObjectController(
|
||||
mockScope,
|
||||
mockLocation,
|
||||
mockRoute
|
||||
);
|
||||
});
|
||||
|
||||
it("updates query parameters when selected view changes", function () {
|
||||
fireWatch("representation.selected.key", "xyz");
|
||||
expect(mockLocation.search).toHaveBeenCalledWith('view', "xyz");
|
||||
|
||||
// Allows the path index to be checked
|
||||
// prior to setting $route.current
|
||||
mockLocation.path.and.returnValue("/browse/");
|
||||
});
|
||||
|
||||
it("sets the active view from query parameters", function () {
|
||||
var mockDomainObject = jasmine.createSpyObj(
|
||||
"domainObject",
|
||||
['getId', 'getModel', 'getCapability', 'useCapability']
|
||||
),
|
||||
testViews = [
|
||||
{ key: 'abc' },
|
||||
{ key: 'def', someKey: 'some value' },
|
||||
{ key: 'xyz' }
|
||||
];
|
||||
|
||||
mockDomainObject.useCapability.and.callFake(function (c) {
|
||||
return (c === 'view') && testViews;
|
||||
});
|
||||
mockLocation.search.and.returnValue({ view: 'def' });
|
||||
|
||||
fireWatch('domainObject', mockDomainObject);
|
||||
expect(mockScope.representation.selected)
|
||||
.toEqual(testViews[1]);
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
);
|
103
platform/commonUI/browse/test/InspectorPaneControllerSpec.js
Normal file
103
platform/commonUI/browse/test/InspectorPaneControllerSpec.js
Normal file
@ -0,0 +1,103 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT Web 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 Web 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/InspectorPaneController"],
|
||||
function (InspectorPaneController) {
|
||||
|
||||
describe("The InspectorPaneController", function () {
|
||||
var mockScope,
|
||||
mockAgentService,
|
||||
mockDomainObject,
|
||||
mockWindow,
|
||||
mockStatusCapability,
|
||||
mockNavigationService,
|
||||
mockNavigationUnlistener,
|
||||
mockStatusUnlistener,
|
||||
controller,
|
||||
mockLocation,
|
||||
mockAttrs;
|
||||
|
||||
beforeEach(function () {
|
||||
mockScope = jasmine.createSpyObj("$scope", ["$on"]);
|
||||
mockWindow = jasmine.createSpyObj("$window", ["open"]);
|
||||
mockAgentService = jasmine.createSpyObj(
|
||||
"agentService",
|
||||
["isMobile", "isPhone", "isTablet", "isPortrait", "isLandscape"]
|
||||
);
|
||||
|
||||
mockNavigationUnlistener = jasmine.createSpy("navigationUnlistener");
|
||||
mockNavigationService = jasmine.createSpyObj(
|
||||
"navigationService",
|
||||
["getNavigation", "addListener"]
|
||||
);
|
||||
mockNavigationService.addListener.and.returnValue(mockNavigationUnlistener);
|
||||
|
||||
mockStatusUnlistener = jasmine.createSpy("statusUnlistener");
|
||||
mockStatusCapability = jasmine.createSpyObj(
|
||||
"statusCapability",
|
||||
["listen"]
|
||||
);
|
||||
mockStatusCapability.listen.and.returnValue(mockStatusUnlistener);
|
||||
|
||||
mockDomainObject = jasmine.createSpyObj(
|
||||
'domainObject',
|
||||
[
|
||||
'getId',
|
||||
'getModel',
|
||||
'getCapability',
|
||||
'hasCapability'
|
||||
]
|
||||
);
|
||||
mockDomainObject.getId.and.returnValue("domainObject");
|
||||
mockDomainObject.getModel.and.returnValue({});
|
||||
mockDomainObject.hasCapability.and.returnValue(true);
|
||||
mockDomainObject.getCapability.and.returnValue(mockStatusCapability);
|
||||
|
||||
mockLocation = jasmine.createSpyObj('location', ['search']);
|
||||
mockLocation.search.and.returnValue({});
|
||||
|
||||
mockAttrs = {};
|
||||
|
||||
controller = new InspectorPaneController(mockScope, mockAgentService, mockWindow, mockNavigationService, mockLocation, mockAttrs);
|
||||
});
|
||||
|
||||
it("listens for changes to navigation and attaches a status" +
|
||||
" listener", function () {
|
||||
expect(mockNavigationService.addListener).toHaveBeenCalledWith(jasmine.any(Function));
|
||||
mockNavigationService.addListener.calls.mostRecent().args[0](mockDomainObject);
|
||||
expect(mockStatusCapability.listen).toHaveBeenCalledWith(jasmine.any(Function));
|
||||
});
|
||||
|
||||
it("if hidden, shows the inspector when domain object switches to" +
|
||||
" edit mode", function () {
|
||||
controller.toggle();
|
||||
// test pre-condition that inspector is hidden
|
||||
expect(controller.visible()).toBe(false);
|
||||
mockNavigationService.addListener.calls.mostRecent().args[0](mockDomainObject);
|
||||
mockStatusCapability.listen.calls.mostRecent().args[0](["editing"]);
|
||||
expect(controller.visible()).toBe(true);
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
);
|
79
platform/commonUI/browse/test/MenuArrowControllerSpec.js
Normal file
79
platform/commonUI/browse/test/MenuArrowControllerSpec.js
Normal file
@ -0,0 +1,79 @@
|
||||
/*****************************************************************************
|
||||
* 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.
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
* MenuArrowControllerSpec. Created by shale on 07/02/2015.
|
||||
*/
|
||||
define(
|
||||
["../src/MenuArrowController"],
|
||||
function (MenuArrowController) {
|
||||
|
||||
describe("The menu arrow controller ", function () {
|
||||
var mockScope,
|
||||
mockDomainObject,
|
||||
mockEvent,
|
||||
mockContextMenuAction,
|
||||
mockActionContext,
|
||||
controller;
|
||||
|
||||
beforeEach(function () {
|
||||
mockScope = jasmine.createSpyObj(
|
||||
"$scope",
|
||||
[""]
|
||||
);
|
||||
mockDomainObject = jasmine.createSpyObj(
|
||||
"domainObject",
|
||||
["getCapability"]
|
||||
);
|
||||
mockEvent = jasmine.createSpyObj(
|
||||
"event",
|
||||
["preventDefault"]
|
||||
);
|
||||
mockContextMenuAction = jasmine.createSpyObj(
|
||||
"action",
|
||||
["perform", "getActions"]
|
||||
);
|
||||
mockActionContext = jasmine.createSpyObj(
|
||||
"actionContext",
|
||||
[""]
|
||||
);
|
||||
|
||||
mockActionContext.domainObject = mockDomainObject;
|
||||
mockActionContext.event = mockEvent;
|
||||
mockScope.domainObject = mockDomainObject;
|
||||
mockDomainObject.getCapability.and.returnValue(mockContextMenuAction);
|
||||
mockContextMenuAction.perform.and.returnValue(jasmine.any(Function));
|
||||
|
||||
controller = new MenuArrowController(mockScope);
|
||||
});
|
||||
|
||||
it("calls the context menu action when clicked", function () {
|
||||
// Simulate a click on the menu arrow
|
||||
controller.showMenu(mockEvent);
|
||||
|
||||
// Expect the menu action to be performed
|
||||
expect(mockDomainObject.getCapability).toHaveBeenCalledWith('action');
|
||||
expect(mockContextMenuAction.perform).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
137
platform/commonUI/browse/test/ObjectHeaderControllerSpec.js
Normal file
137
platform/commonUI/browse/test/ObjectHeaderControllerSpec.js
Normal file
@ -0,0 +1,137 @@
|
||||
/*****************************************************************************
|
||||
* 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/ObjectHeaderController"],
|
||||
function (ObjectHeaderController) {
|
||||
|
||||
describe("The object header controller", function () {
|
||||
var mockScope,
|
||||
mockDomainObject,
|
||||
mockCapabilities,
|
||||
mockMutationCapability,
|
||||
mockTypeCapability,
|
||||
mockEvent,
|
||||
mockCurrentTarget,
|
||||
model,
|
||||
controller;
|
||||
|
||||
beforeEach(function () {
|
||||
mockMutationCapability = jasmine.createSpyObj("mutation", ["mutate"]);
|
||||
mockTypeCapability = jasmine.createSpyObj("type", ["typeDef", "hasFeature"]);
|
||||
mockTypeCapability.typeDef = { name: ""};
|
||||
mockTypeCapability.hasFeature.and.callFake(function (feature) {
|
||||
return feature === 'creation';
|
||||
});
|
||||
|
||||
mockCapabilities = {
|
||||
mutation: mockMutationCapability,
|
||||
type: mockTypeCapability
|
||||
};
|
||||
|
||||
model = {
|
||||
name: "Test name"
|
||||
};
|
||||
mockDomainObject = jasmine.createSpyObj("domainObject", ["getCapability", "getModel"]);
|
||||
mockDomainObject.getModel.and.returnValue(model);
|
||||
mockDomainObject.getCapability.and.callFake(function (key) {
|
||||
return mockCapabilities[key];
|
||||
});
|
||||
|
||||
mockScope = {
|
||||
domainObject: mockDomainObject
|
||||
};
|
||||
|
||||
mockCurrentTarget = jasmine.createSpyObj("currentTarget", ["blur", "textContent"]);
|
||||
mockCurrentTarget.blur.and.returnValue(mockCurrentTarget);
|
||||
|
||||
mockEvent = {
|
||||
which: {},
|
||||
type: {},
|
||||
currentTarget: mockCurrentTarget
|
||||
};
|
||||
|
||||
controller = new ObjectHeaderController(mockScope);
|
||||
});
|
||||
|
||||
it("updates the model with new name on blur", function () {
|
||||
mockEvent.type = "blur";
|
||||
mockCurrentTarget.textContent = "New name";
|
||||
controller.updateName(mockEvent);
|
||||
|
||||
expect(mockMutationCapability.mutate).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("updates the model with a default for blank names", function () {
|
||||
mockEvent.type = "blur";
|
||||
mockCurrentTarget.textContent = "";
|
||||
controller.updateName(mockEvent);
|
||||
|
||||
expect(mockCurrentTarget.textContent.length).not.toEqual(0);
|
||||
expect(mockMutationCapability.mutate).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("does not update the model if the same name", function () {
|
||||
mockEvent.type = "blur";
|
||||
mockCurrentTarget.textContent = mockDomainObject.getModel().name;
|
||||
controller.updateName(mockEvent);
|
||||
|
||||
expect(mockMutationCapability.mutate).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("updates the model on enter keypress event only", function () {
|
||||
mockCurrentTarget.textContent = "New name";
|
||||
controller.updateName(mockEvent);
|
||||
|
||||
expect(mockMutationCapability.mutate).not.toHaveBeenCalled();
|
||||
|
||||
mockEvent.which = 13;
|
||||
controller.updateName(mockEvent);
|
||||
|
||||
expect(mockMutationCapability.mutate).toHaveBeenCalledWith(jasmine.any(Function));
|
||||
|
||||
mockMutationCapability.mutate.calls.mostRecent().args[0](model);
|
||||
|
||||
expect(mockDomainObject.getModel().name).toBe("New name");
|
||||
});
|
||||
|
||||
it("blurs the field on enter key press", function () {
|
||||
mockCurrentTarget.textContent = "New name";
|
||||
mockEvent.which = 13;
|
||||
controller.updateName(mockEvent);
|
||||
|
||||
expect(mockEvent.currentTarget.blur).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("allows editting name when object is creatable", function () {
|
||||
expect(controller.allowEdit()).toBe(true);
|
||||
});
|
||||
|
||||
it("disallows editting name when object is non-creatable", function () {
|
||||
mockTypeCapability.hasFeature.and.returnValue(false);
|
||||
|
||||
expect(controller.allowEdit()).toBe(false);
|
||||
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
106
platform/commonUI/browse/test/PaneControllerSpec.js
Normal file
106
platform/commonUI/browse/test/PaneControllerSpec.js
Normal file
@ -0,0 +1,106 @@
|
||||
/*****************************************************************************
|
||||
* 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/PaneController"],
|
||||
function (PaneController) {
|
||||
|
||||
describe("The PaneController", function () {
|
||||
var mockScope,
|
||||
mockAgentService,
|
||||
mockWindow,
|
||||
controller,
|
||||
mockLocation,
|
||||
mockAttrs;
|
||||
|
||||
// We want to reinstantiate for each test case
|
||||
// because device state can influence constructor-time behavior
|
||||
function instantiateController() {
|
||||
return new PaneController(
|
||||
mockScope,
|
||||
mockAgentService,
|
||||
mockWindow,
|
||||
mockLocation,
|
||||
mockAttrs
|
||||
);
|
||||
}
|
||||
|
||||
beforeEach(function () {
|
||||
mockScope = jasmine.createSpyObj("$scope", ["$on"]);
|
||||
mockAgentService = jasmine.createSpyObj(
|
||||
"agentService",
|
||||
["isMobile", "isPhone", "isTablet", "isPortrait", "isLandscape"]
|
||||
);
|
||||
mockWindow = jasmine.createSpyObj("$window", ["open"]);
|
||||
|
||||
mockLocation = jasmine.createSpyObj('location', ['search']);
|
||||
mockLocation.search.and.returnValue({});
|
||||
|
||||
mockAttrs = {};
|
||||
});
|
||||
|
||||
it("is initially visible", function () {
|
||||
expect(instantiateController().visible()).toBeTruthy();
|
||||
});
|
||||
|
||||
it("allows visibility to be toggled", function () {
|
||||
controller = instantiateController();
|
||||
controller.toggle();
|
||||
expect(controller.visible()).toBeFalsy();
|
||||
controller.toggle();
|
||||
expect(controller.visible()).toBeTruthy();
|
||||
});
|
||||
|
||||
it("collapses on navigation changes on portrait-oriented phones", function () {
|
||||
mockAgentService.isMobile.and.returnValue(true);
|
||||
mockAgentService.isPhone.and.returnValue(true);
|
||||
mockAgentService.isPortrait.and.returnValue(true);
|
||||
controller = instantiateController();
|
||||
expect(controller.visible()).toBeTruthy();
|
||||
|
||||
// Simulate a change from the tree by invoking controller's
|
||||
controller.callback();
|
||||
|
||||
// Tree should have collapsed
|
||||
expect(controller.visible()).toBeFalsy();
|
||||
});
|
||||
|
||||
describe("specifying hideParameter", function () {
|
||||
beforeEach(function () {
|
||||
mockAttrs = {hideParameter: 'hideTree'};
|
||||
});
|
||||
|
||||
it("sets pane state to false when in location.search", function () {
|
||||
mockLocation.search.and.returnValue({'hideTree': true});
|
||||
expect(instantiateController().visible()).toBe(false);
|
||||
expect(mockLocation.search).toHaveBeenCalledWith('hideTree', undefined);
|
||||
});
|
||||
|
||||
it("sets state to true when not found in location.search", function () {
|
||||
mockLocation.search.and.returnValue({});
|
||||
expect(instantiateController().visible()).toBe(true);
|
||||
expect(mockLocation.search).not.toHaveBeenCalledWith('hideTree', undefined);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
78
platform/commonUI/browse/test/windowing/WindowTitlerSpec.js
Normal file
78
platform/commonUI/browse/test/windowing/WindowTitlerSpec.js
Normal file
@ -0,0 +1,78 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2018, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
/**
|
||||
* WindowTitlerSpec. Created by vwoeltje on 11/6/14.
|
||||
*/
|
||||
define(
|
||||
["../../src/windowing/WindowTitler"],
|
||||
function (WindowTitler) {
|
||||
|
||||
describe("The window titler", function () {
|
||||
var mockNavigationService,
|
||||
mockRootScope,
|
||||
mockDocument,
|
||||
mockDomainObject,
|
||||
titler; // eslint-disable-line
|
||||
|
||||
beforeEach(function () {
|
||||
mockNavigationService = jasmine.createSpyObj(
|
||||
'navigationService',
|
||||
['getNavigation']
|
||||
);
|
||||
mockRootScope = jasmine.createSpyObj(
|
||||
'$rootScope',
|
||||
['$watch']
|
||||
);
|
||||
mockDomainObject = jasmine.createSpyObj(
|
||||
'domainObject',
|
||||
['getModel']
|
||||
);
|
||||
mockDocument = [{}];
|
||||
|
||||
mockDomainObject.getModel.and.returnValue({ name: 'Test name' });
|
||||
mockNavigationService.getNavigation.and.returnValue(mockDomainObject);
|
||||
|
||||
titler = new WindowTitler(
|
||||
mockNavigationService,
|
||||
mockRootScope,
|
||||
mockDocument
|
||||
);
|
||||
});
|
||||
|
||||
it("listens for changes to the name of the navigated object", function () {
|
||||
expect(mockRootScope.$watch).toHaveBeenCalledWith(
|
||||
jasmine.any(Function),
|
||||
jasmine.any(Function)
|
||||
);
|
||||
expect(mockRootScope.$watch.calls.mostRecent().args[0]())
|
||||
.toEqual('Test name');
|
||||
});
|
||||
|
||||
it("sets the title to the name of the navigated object", function () {
|
||||
mockRootScope.$watch.calls.mostRecent().args[1]("Some name");
|
||||
expect(mockDocument[0].title).toEqual("Some name");
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
);
|
@ -28,7 +28,6 @@ define([
|
||||
"./res/templates/dialog.html",
|
||||
"./res/templates/overlay-blocking-message.html",
|
||||
"./res/templates/message.html",
|
||||
"./res/templates/notification-message.html",
|
||||
"./res/templates/overlay-message-list.html",
|
||||
"./res/templates/overlay.html",
|
||||
'legacyRegistry'
|
||||
@ -40,7 +39,6 @@ define([
|
||||
dialogTemplate,
|
||||
overlayBlockingMessageTemplate,
|
||||
messageTemplate,
|
||||
notificationMessageTemplate,
|
||||
overlayMessageListTemplate,
|
||||
overlayTemplate,
|
||||
legacyRegistry
|
||||
@ -65,8 +63,7 @@ define([
|
||||
"depends": [
|
||||
"$document",
|
||||
"$compile",
|
||||
"$rootScope",
|
||||
"$timeout"
|
||||
"$rootScope"
|
||||
]
|
||||
}
|
||||
],
|
||||
@ -91,10 +88,6 @@ define([
|
||||
"key": "message",
|
||||
"template": messageTemplate
|
||||
},
|
||||
{
|
||||
"key": "notification-message",
|
||||
"template": notificationMessageTemplate
|
||||
},
|
||||
{
|
||||
"key": "overlay-message-list",
|
||||
"template": overlayMessageListTemplate
|
||||
|
@ -19,24 +19,24 @@
|
||||
this source code distribution or the Licensing information page available
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
<div class="c-overlay__top-bar">
|
||||
<div class="c-overlay__dialog-title">{{ngModel.title}}</div>
|
||||
<div class="c-overlay__dialog-hint hint">All fields marked <span class="req icon-asterisk"></span> are required.</div>
|
||||
<div class="abs top-bar">
|
||||
<div class="dialog-title">{{ngModel.title}}</div>
|
||||
<div class="hint">All fields marked <span class="req icon-asterisk"></span> are required.</div>
|
||||
</div>
|
||||
<div class='c-overlay__contents-main'>
|
||||
<div class='abs editor'>
|
||||
<mct-form ng-model="ngModel.value"
|
||||
structure="ngModel.structure"
|
||||
class="validates"
|
||||
name="createForm">
|
||||
</mct-form>
|
||||
</div>
|
||||
<div class="c-overlay__button-bar">
|
||||
<a class='c-button c-button--major'
|
||||
<div class="abs bottom-bar">
|
||||
<a class='s-button major'
|
||||
ng-class="{ disabled: !createForm.$valid }"
|
||||
ng-click="ngModel.confirm()">
|
||||
OK
|
||||
</a>
|
||||
<a class='c-button '
|
||||
<a class='s-button'
|
||||
ng-click="ngModel.cancel()">
|
||||
Cancel
|
||||
</a>
|
||||
|
@ -1,32 +1,15 @@
|
||||
<div class="c-message"
|
||||
<div class="l-message"
|
||||
ng-class="'message-severity-' + ngModel.severity">
|
||||
<div class="w-message-contents">
|
||||
<div class="c-message__top-bar">
|
||||
<div class="c-message__title">{{ngModel.title}}</div>
|
||||
</div>
|
||||
<div class="c-message__hint" ng-hide="ngModel.hint === undefined">
|
||||
{{ngModel.hint}}
|
||||
<span ng-if="ngModel.timestamp !== undefined">[{{ngModel.timestamp}}]</span>
|
||||
<div class="top-bar">
|
||||
<div class="title">{{ngModel.message}}</div>
|
||||
</div>
|
||||
<div class="message-body">
|
||||
<div class="message-action">
|
||||
{{ngModel.actionText}}
|
||||
</div>
|
||||
<mct-include key="'progress-bar'"
|
||||
ng-model="ngModel"
|
||||
ng-show="ngModel.progress !== undefined || ngModel.unknownProgress"></mct-include>
|
||||
ng-show="ngModel.progressPerc !== undefined"></mct-include>
|
||||
</div>
|
||||
<div class="c-overlay__button-bar">
|
||||
<button ng-repeat="dialogOption in ngModel.options"
|
||||
class="c-button"
|
||||
ng-click="dialogOption.callback()">
|
||||
{{dialogOption.label}}
|
||||
</button>
|
||||
<button class="c-button c-button--major"
|
||||
ng-if="ngModel.primaryOption"
|
||||
ng-click="ngModel.primaryOption.callback()">
|
||||
{{ngModel.primaryOption.label}}
|
||||
</button>
|
||||
<div class="bottom-bar">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,25 +0,0 @@
|
||||
<div class="c-message"
|
||||
ng-class="'message-severity-' + ngModel.severity">
|
||||
<div class="w-message-contents">
|
||||
<div class="c-message__top-bar">
|
||||
<div class="c-message__title">{{ngModel.message}}</div>
|
||||
</div>
|
||||
<div class="message-body">
|
||||
<mct-include key="'progress-bar'"
|
||||
ng-model="ngModel"
|
||||
ng-show="ngModel.progressPerc !== undefined"></mct-include>
|
||||
</div>
|
||||
</div>
|
||||
<div class="c-overlay__button-bar">
|
||||
<button ng-repeat="dialogOption in ngModel.options"
|
||||
class="c-button"
|
||||
ng-click="dialogOption.callback()">
|
||||
{{dialogOption.label}}
|
||||
</button>
|
||||
<button class="c-button c-button--major"
|
||||
ng-if="ngModel.primaryOption"
|
||||
ng-click="ngModel.primaryOption.callback()">
|
||||
{{ngModel.primaryOption.label}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
@ -1,23 +1,22 @@
|
||||
<mct-container key="overlay">
|
||||
<div class="t-message-list c-overlay__contents">
|
||||
<div class="c-overlay__top-bar">
|
||||
<div class="c-overlay__dialog-title">{{ngModel.dialog.title}}</div>
|
||||
<div class="c-overlay__dialog-hint">Displaying {{ngModel.dialog.messages.length}} message<span
|
||||
ng-show="ngModel.dialog.messages.length > 1 ||
|
||||
ngModel.dialog.messages.length == 0">s</span>
|
||||
<div class="t-message-list">
|
||||
<div class="top-bar">
|
||||
<div class="dialog-title">{{ngModel.dialog.title}}</div>
|
||||
<div class="hint">Displaying {{ngModel.dialog.messages.length}} message<span ng-show="ngModel.dialog.messages.length > 1 ||
|
||||
ngModel.dialog.messages.length == 0">s</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-messages c-overlay__messages">
|
||||
<div class="w-messages">
|
||||
<mct-include
|
||||
ng-repeat="msg in ngModel.dialog.messages | orderBy: '-'"
|
||||
key="'notification-message'" ng-model="msg.model"></mct-include>
|
||||
key="'message'" ng-model="msg.model"></mct-include>
|
||||
</div>
|
||||
<div class="c-overlay__bottom-bar">
|
||||
<button ng-repeat="dialogAction in ngModel.dialog.actions"
|
||||
class="c-button c-button--major"
|
||||
<div class="bottom-bar">
|
||||
<a ng-repeat="dialogAction in ngModel.dialog.actions"
|
||||
class="s-button major"
|
||||
ng-click="dialogAction.action()">
|
||||
{{dialogAction.label}}
|
||||
</button>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</mct-container>
|
||||
|
@ -19,18 +19,18 @@
|
||||
this source code distribution or the Licensing information page available
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
<mct-container key="c-overlay__contents">
|
||||
<div class=c-overlay__top-bar">
|
||||
<div class="c-overlay__dialog-title">{{ngModel.dialog.title}}</div>
|
||||
<div class="c-overlay__dialog-hint hint">{{ngModel.dialog.hint}}</div>
|
||||
<mct-container key="overlay">
|
||||
<div class="abs top-bar">
|
||||
<div class="dialog-title">{{ngModel.dialog.title}}</div>
|
||||
<div class="hint">{{ngModel.dialog.hint}}</div>
|
||||
</div>
|
||||
<div class='c-overlay__contents-main'>
|
||||
<div class='abs editor'>
|
||||
<mct-include key="ngModel.dialog.template"
|
||||
parameters="ngModel.dialog.parameters"
|
||||
ng-model="ngModel.dialog.model">
|
||||
</mct-include>
|
||||
</div>
|
||||
<div class="c-overlay__button-bar">
|
||||
<div class="abs bottom-bar">
|
||||
<a ng-repeat="option in ngModel.dialog.options"
|
||||
href=''
|
||||
class="s-button lg"
|
||||
|
@ -19,12 +19,12 @@
|
||||
this source code distribution or the Licensing information page available
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
<div class="c-overlay l-overlay-small" ng-class="{'delayEntry100ms' : ngModel.delay}">
|
||||
<div class="c-overlay__blocker"></div>
|
||||
<div class="c-overlay__outer">
|
||||
<button ng-click="ngModel.cancel()"
|
||||
<div class="abs overlay l-dialog" ng-class="{'delayEntry100ms' : ngModel.delay}">
|
||||
<div class="abs blocker"></div>
|
||||
<div class="abs outer-holder">
|
||||
<a ng-click="ngModel.cancel()"
|
||||
ng-if="ngModel.cancel"
|
||||
class="c-click-icon c-overlay__close-button icon-x-in-circle"></button>
|
||||
<div class="c-overlay__contents" ng-transclude></div>
|
||||
class="close icon-x-in-circle"></a>
|
||||
<div class="abs inner-holder contents" ng-transclude></div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -44,9 +44,8 @@ define(
|
||||
* @memberof platform/commonUI/dialog
|
||||
* @constructor
|
||||
*/
|
||||
function OverlayService($document, $compile, $rootScope, $timeout) {
|
||||
function OverlayService($document, $compile, $rootScope) {
|
||||
this.$compile = $compile;
|
||||
this.$timeout = $timeout;
|
||||
|
||||
// Don't include $document and $rootScope directly;
|
||||
// avoids https://docs.angularjs.org/error/ng/cpws
|
||||
@ -94,14 +93,12 @@ define(
|
||||
scope.key = key;
|
||||
scope.typeClass = typeClass || 't-dialog';
|
||||
|
||||
this.$timeout(() => {
|
||||
// Create the overlay element and add it to the document's body
|
||||
element = this.$compile(TEMPLATE)(scope);
|
||||
|
||||
// Append so that most recent dialog is last in DOM. This means the most recent dialog will be on top when
|
||||
// multiple overlays with the same z-index are active.
|
||||
this.findBody().append(element);
|
||||
});
|
||||
// Create the overlay element and add it to the document's body
|
||||
element = this.$compile(TEMPLATE)(scope);
|
||||
|
||||
// Append so that most recent dialog is last in DOM. This means the most recent dialog will be on top when
|
||||
// multiple overlays with the same z-index are active.
|
||||
this.findBody().append(element);
|
||||
|
||||
return {
|
||||
dismiss: dismiss
|
||||
|
@ -35,20 +35,16 @@ define(
|
||||
mockTemplate,
|
||||
mockElement,
|
||||
mockScope,
|
||||
mockTimeout,
|
||||
overlayService;
|
||||
|
||||
beforeEach(function () {
|
||||
mockDocument = jasmine.createSpyObj("$document", ["find"]);
|
||||
mockCompile = jasmine.createSpy("$compile");
|
||||
mockRootScope = jasmine.createSpyObj("$rootScope", ["$new"]);
|
||||
mockBody = jasmine.createSpyObj("body", ["append"]);
|
||||
mockBody = jasmine.createSpyObj("body", ["prepend"]);
|
||||
mockTemplate = jasmine.createSpy("template");
|
||||
mockElement = jasmine.createSpyObj("element", ["remove"]);
|
||||
mockScope = jasmine.createSpyObj("scope", ["$destroy"]);
|
||||
mockTimeout = function (callback) {
|
||||
callback();
|
||||
}
|
||||
|
||||
mockDocument.find.and.returnValue(mockBody);
|
||||
mockCompile.and.returnValue(mockTemplate);
|
||||
@ -58,8 +54,7 @@ define(
|
||||
overlayService = new OverlayService(
|
||||
mockDocument,
|
||||
mockCompile,
|
||||
mockRootScope,
|
||||
mockTimeout
|
||||
mockRootScope
|
||||
);
|
||||
});
|
||||
|
||||
@ -72,7 +67,7 @@ define(
|
||||
|
||||
it("adds the templated element to the body", function () {
|
||||
overlayService.createOverlay("test", {});
|
||||
expect(mockBody.append).toHaveBeenCalledWith(mockElement);
|
||||
expect(mockBody.prepend).toHaveBeenCalledWith(mockElement);
|
||||
});
|
||||
|
||||
it("places the provided model/key in its template's scope", function () {
|
||||
|
@ -27,6 +27,7 @@ define([
|
||||
"./src/actions/EditAndComposeAction",
|
||||
"./src/actions/EditAction",
|
||||
"./src/actions/PropertiesAction",
|
||||
"./src/actions/RemoveAction",
|
||||
"./src/actions/SaveAction",
|
||||
"./src/actions/SaveAndStopEditingAction",
|
||||
"./src/actions/SaveAsAction",
|
||||
@ -57,6 +58,7 @@ define([
|
||||
EditAndComposeAction,
|
||||
EditAction,
|
||||
PropertiesAction,
|
||||
RemoveAction,
|
||||
SaveAction,
|
||||
SaveAndStopEditingAction,
|
||||
SaveAsAction,
|
||||
@ -156,6 +158,18 @@ define([
|
||||
"dialogService"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "remove",
|
||||
"category": "contextual",
|
||||
"implementation": RemoveAction,
|
||||
"cssClass": "icon-trash",
|
||||
"name": "Remove",
|
||||
"description": "Remove this object from its containing object.",
|
||||
"depends": [
|
||||
"openmct",
|
||||
"navigationService"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "save-and-stop-editing",
|
||||
"category": "save",
|
||||
|
@ -49,7 +49,7 @@ define(
|
||||
name: "Properties",
|
||||
rows: this.properties.map(function (property, index) {
|
||||
// Property definition is same as form row definition
|
||||
var row = JSON.parse(JSON.stringify(property.getDefinition()));
|
||||
var row = Object.create(property.getDefinition());
|
||||
row.key = index;
|
||||
return row;
|
||||
}).filter(function (row) {
|
||||
|
140
platform/commonUI/edit/src/actions/RemoveAction.js
Normal file
140
platform/commonUI/edit/src/actions/RemoveAction.js
Normal file
@ -0,0 +1,140 @@
|
||||
/*****************************************************************************
|
||||
* 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 RemoveAction. Created by vwoeltje on 11/17/14.
|
||||
*/
|
||||
define([
|
||||
'./RemoveDialog'
|
||||
], function (
|
||||
RemoveDialog
|
||||
) {
|
||||
|
||||
/**
|
||||
* Construct an action which will remove the provided object manifestation.
|
||||
* The object will be removed from its parent's composition; the parent
|
||||
* is looked up via the "context" capability (so this will be the
|
||||
* immediate ancestor by which this specific object was reached.)
|
||||
*
|
||||
* @param {DialogService} dialogService a service which will show the dialog
|
||||
* @param {NavigationService} navigationService a service that maintains the current navigation state
|
||||
* @param {ActionContext} context the context in which this action is performed
|
||||
* @memberof platform/commonUI/edit
|
||||
* @constructor
|
||||
* @implements {Action}
|
||||
*/
|
||||
function RemoveAction(openmct, navigationService, context) {
|
||||
this.domainObject = (context || {}).domainObject;
|
||||
this.openmct = openmct;
|
||||
this.navigationService = navigationService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform this action.
|
||||
*/
|
||||
RemoveAction.prototype.perform = function () {
|
||||
var dialog,
|
||||
domainObject = this.domainObject,
|
||||
navigationService = this.navigationService;
|
||||
/*
|
||||
* Check whether an object ID matches the ID of the object being
|
||||
* removed (used to filter a parent's composition to handle the
|
||||
* removal.)
|
||||
*/
|
||||
function isNotObject(otherObjectId) {
|
||||
return otherObjectId !== domainObject.getId();
|
||||
}
|
||||
|
||||
/*
|
||||
* Mutate a parent object such that it no longer contains the object
|
||||
* which is being removed.
|
||||
*/
|
||||
function doMutate(model) {
|
||||
model.composition = model.composition.filter(isNotObject);
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks current object and ascendants of current
|
||||
* object with object being removed, if the current
|
||||
* object or any in the current object's path is being removed,
|
||||
* navigate back to parent of removed object.
|
||||
*/
|
||||
function checkObjectNavigation(object, parentObject) {
|
||||
// Traverse object starts at current location
|
||||
var traverseObject = (navigationService).getNavigation(),
|
||||
context;
|
||||
|
||||
// Stop when object is not defined (above ROOT)
|
||||
while (traverseObject) {
|
||||
// If object currently traversed to is object being removed
|
||||
// navigate to parent of current object and then exit loop
|
||||
if (traverseObject.getId() === object.getId()) {
|
||||
navigationService.setNavigation(parentObject);
|
||||
return;
|
||||
}
|
||||
// Traverses to parent of current object, moving
|
||||
// up the ascendant path
|
||||
context = traverseObject.getCapability('context');
|
||||
traverseObject = context && context.getParent();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove the object from its parent, as identified by its context
|
||||
* capability. Based on object's location and selected object's location
|
||||
* user may be navigated to existing parent object
|
||||
*/
|
||||
function removeFromContext() {
|
||||
var contextCapability = domainObject.getCapability('context'),
|
||||
parent = contextCapability.getParent();
|
||||
|
||||
// If currently within path of removed object(s),
|
||||
// navigates to existing object up tree
|
||||
checkObjectNavigation(domainObject, parent);
|
||||
|
||||
return parent.useCapability('mutation', doMutate);
|
||||
}
|
||||
|
||||
/*
|
||||
* Pass in the function to remove the domain object so it can be
|
||||
* associated with an 'OK' button press
|
||||
*/
|
||||
dialog = new RemoveDialog(this.openmct, domainObject, removeFromContext);
|
||||
dialog.show();
|
||||
};
|
||||
|
||||
// Object needs to have a parent for Remove to be applicable
|
||||
RemoveAction.appliesTo = function (context) {
|
||||
var object = (context || {}).domainObject,
|
||||
contextCapability = object && object.getCapability("context"),
|
||||
parent = contextCapability && contextCapability.getParent(),
|
||||
parentType = parent && parent.getCapability('type'),
|
||||
parentCreatable = parentType && parentType.hasFeature('creation');
|
||||
|
||||
// Only creatable types should be modifiable
|
||||
return parent !== undefined &&
|
||||
Array.isArray(parent.getModel().composition) &&
|
||||
parentCreatable;
|
||||
};
|
||||
|
||||
return RemoveAction;
|
||||
});
|
72
platform/commonUI/edit/src/actions/RemoveDialog.js
Normal file
72
platform/commonUI/edit/src/actions/RemoveDialog.js
Normal file
@ -0,0 +1,72 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2017, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define([], function () {
|
||||
|
||||
/**
|
||||
* @callback removeCallback
|
||||
* @param {DomainObject} domainObject the domain object to be removed
|
||||
*/
|
||||
|
||||
/**
|
||||
* Construct a new Remove dialog.
|
||||
*
|
||||
* @param {DialogService} dialogService the service that shows the dialog
|
||||
* @param {DomainObject} domainObject the domain object to be removed
|
||||
* @param {removeCallback} removeCallback callback that handles removal of the domain object
|
||||
* @memberof platform/commonUI/edit
|
||||
* @constructor
|
||||
*/
|
||||
function RemoveDialog(openmct, domainObject, removeCallback) {
|
||||
this.openmct = openmct;
|
||||
this.domainObject = domainObject;
|
||||
this.removeCallback = removeCallback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a dialog to confirm the removal of a domain object.
|
||||
*/
|
||||
RemoveDialog.prototype.show = function () {
|
||||
let dialog = this.openmct.overlays.dialog({
|
||||
title: 'Remove ' + this.domainObject.getModel().name,
|
||||
iconClass: 'alert',
|
||||
message: 'Warning! This action will permanently remove this object. Are you sure you want to continue?',
|
||||
buttons: [
|
||||
{
|
||||
label: 'OK',
|
||||
callback: () => {
|
||||
this.removeCallback();
|
||||
dialog.dismiss();
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Cancel',
|
||||
callback: () => {
|
||||
dialog.dismiss();
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
};
|
||||
|
||||
return RemoveDialog;
|
||||
});
|
@ -92,7 +92,16 @@ function (
|
||||
* @memberof platform/commonUI/edit.SaveAction#
|
||||
*/
|
||||
SaveAsAction.prototype.perform = function () {
|
||||
return this.save();
|
||||
// Discard the current root view (which will be the editing
|
||||
// UI, which will have been pushed atop the Browse UI.)
|
||||
function returnToBrowse(object) {
|
||||
if (object) {
|
||||
object.getCapability("action").perform("navigate");
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
return this.save().then(returnToBrowse);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -160,22 +169,15 @@ function (
|
||||
}
|
||||
|
||||
function saveAfterClone(clonedObject) {
|
||||
return this.openmct.editor.save().then(() => {
|
||||
// Force mutation for search indexing
|
||||
return clonedObject;
|
||||
})
|
||||
return domainObject.getCapability("editor").save()
|
||||
.then(resolveWith(clonedObject));
|
||||
}
|
||||
|
||||
function finishEditing(clonedObject) {
|
||||
return fetchObject(clonedObject.getId())
|
||||
}
|
||||
|
||||
function indexForSearch(savedObject) {
|
||||
savedObject.useCapability('mutation', (model) => {
|
||||
return model;
|
||||
});
|
||||
|
||||
return savedObject;
|
||||
return domainObject.getCapability("editor").finish()
|
||||
.then(function () {
|
||||
return fetchObject(clonedObject.getId());
|
||||
});
|
||||
}
|
||||
|
||||
function onSuccess(object) {
|
||||
@ -188,7 +190,7 @@ function (
|
||||
if (reason !== "user canceled") {
|
||||
self.notificationService.error("Save Failed");
|
||||
}
|
||||
throw reason;
|
||||
return false;
|
||||
}
|
||||
|
||||
return getParent(domainObject)
|
||||
@ -199,7 +201,6 @@ function (
|
||||
.then(undirtyOriginals)
|
||||
.then(saveAfterClone)
|
||||
.then(finishEditing)
|
||||
.then(indexForSearch)
|
||||
.then(hideBlockingDialog)
|
||||
.then(onSuccess)
|
||||
.catch(onFailure);
|
||||
|
@ -64,6 +64,7 @@ define(
|
||||
* @returns boolean
|
||||
*/
|
||||
EditorCapability.prototype.inEditContext = function () {
|
||||
console.warn('DEPRECATION WARNING: isEditing checks must be done via openmct.editor.');
|
||||
return this.openmct.editor.isEditing();
|
||||
};
|
||||
|
||||
@ -73,6 +74,7 @@ define(
|
||||
* @returns {*}
|
||||
*/
|
||||
EditorCapability.prototype.isEditContextRoot = function () {
|
||||
console.warn('DEPRECATION WARNING: isEditing checks must be done via openmct.editor.');
|
||||
return this.openmct.editor.isEditing();
|
||||
};
|
||||
|
||||
|
@ -65,40 +65,24 @@ define(
|
||||
CreateAction.prototype.perform = function () {
|
||||
var newModel = this.type.getInitialModel(),
|
||||
openmct = this.openmct,
|
||||
newObject;
|
||||
newObject,
|
||||
editAction;
|
||||
|
||||
function onSave() {
|
||||
openmct.editor.save();
|
||||
}
|
||||
|
||||
function onCancel() {
|
||||
openmct.editor.cancel();
|
||||
}
|
||||
|
||||
function isFirstViewEditable(domainObject) {
|
||||
let firstView = openmct.objectViews.get(domainObject)[0];
|
||||
|
||||
return firstView && firstView.canEdit && firstView.canEdit(domainObject);
|
||||
}
|
||||
|
||||
function navigateAndEdit(object) {
|
||||
let objectPath = object.getCapability('context').getPath(),
|
||||
url = '#/browse/' + objectPath
|
||||
.slice(1)
|
||||
.map(function (o) {
|
||||
return o && openmct.objects.makeKeyString(o.getId());
|
||||
})
|
||||
.join('/');
|
||||
|
||||
window.location.href = url;
|
||||
|
||||
if (isFirstViewEditable(object.useCapability('adapter'))) {
|
||||
openmct.editor.edit();
|
||||
}
|
||||
}
|
||||
|
||||
newModel.type = this.type.getKey();
|
||||
newModel.location = this.parent.getId();
|
||||
newObject = this.parent.useCapability('instantiation', newModel);
|
||||
|
||||
openmct.editor.edit();
|
||||
newObject.getCapability("action").perform("save-as").then(navigateAndEdit, onCancel);
|
||||
editAction = newObject.getCapability("action").getActions("edit")[0];
|
||||
newObject.getCapability("action").perform("save-as").then(onSave, onCancel);
|
||||
// TODO: support editing object without saving object first.
|
||||
// Which means we have to toggle createwizard afterwards. For now,
|
||||
// We will disable this.
|
||||
|
@ -66,7 +66,7 @@ define(
|
||||
name: "Properties",
|
||||
rows: this.properties.map(function (property, index) {
|
||||
// Property definition is same as form row definition
|
||||
var row = JSON.parse(JSON.stringify(property.getDefinition()));
|
||||
var row = Object.create(property.getDefinition());
|
||||
|
||||
// Use index as the key into the formValue;
|
||||
// this correlates to the indexing provided by
|
||||
|
@ -77,19 +77,14 @@ define([], function () {
|
||||
return promiseFn().then(nextFn);
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Clear any existing persistence calls for object with given ID. This ensures only the most recent persistence
|
||||
* call is executed. This should prevent stale objects being persisted and overwriting fresh ones.
|
||||
*/
|
||||
if (this.isScheduled(id)) {
|
||||
this.clearTransactionsFor(id);
|
||||
}
|
||||
|
||||
this.clearTransactionFns[id] =
|
||||
this.transactionService.addToTransaction(
|
||||
chain(onCommit, release),
|
||||
chain(onCancel, release)
|
||||
);
|
||||
if (!this.isScheduled(id)) {
|
||||
this.clearTransactionFns[id] =
|
||||
this.transactionService.addToTransaction(
|
||||
chain(onCommit, release),
|
||||
chain(onCancel, release)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
255
platform/commonUI/edit/test/actions/RemoveActionSpec.js
Normal file
255
platform/commonUI/edit/test/actions/RemoveActionSpec.js
Normal file
@ -0,0 +1,255 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2018, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define(
|
||||
["../../src/actions/RemoveAction"],
|
||||
function (RemoveAction) {
|
||||
|
||||
describe("The Remove action", function () {
|
||||
var action,
|
||||
actionContext,
|
||||
capabilities,
|
||||
mockContext,
|
||||
mockOverlayAPI,
|
||||
mockDomainObject,
|
||||
mockMutation,
|
||||
mockNavigationService,
|
||||
mockParent,
|
||||
mockType,
|
||||
model;
|
||||
|
||||
beforeEach(function () {
|
||||
mockDomainObject = jasmine.createSpyObj(
|
||||
"domainObject",
|
||||
["getId", "getCapability", "getModel"]
|
||||
);
|
||||
|
||||
mockMutation = jasmine.createSpyObj("mutation", ["invoke"]);
|
||||
mockType = jasmine.createSpyObj("type", ["hasFeature"]);
|
||||
mockType.hasFeature.and.returnValue(true);
|
||||
|
||||
capabilities = {
|
||||
mutation: mockMutation,
|
||||
type: mockType
|
||||
};
|
||||
|
||||
model = {
|
||||
composition: ["a", "test", "b"]
|
||||
};
|
||||
|
||||
mockParent = {
|
||||
getModel: function () {
|
||||
return model;
|
||||
},
|
||||
getCapability: function (k) {
|
||||
return capabilities[k];
|
||||
},
|
||||
useCapability: function (k, v) {
|
||||
return capabilities[k].invoke(v);
|
||||
}
|
||||
};
|
||||
|
||||
mockOverlayAPI = jasmine.createSpyObj(
|
||||
"overlayAPI",
|
||||
["dialog"]
|
||||
);
|
||||
|
||||
mockNavigationService = jasmine.createSpyObj(
|
||||
"navigationService",
|
||||
[
|
||||
"getNavigation",
|
||||
"setNavigation",
|
||||
"addListener",
|
||||
"removeListener"
|
||||
]
|
||||
);
|
||||
mockNavigationService.getNavigation.and.returnValue(mockDomainObject);
|
||||
|
||||
mockContext = jasmine.createSpyObj("context", ["getParent"]);
|
||||
mockContext.getParent.and.returnValue(mockParent);
|
||||
|
||||
mockDomainObject.getId.and.returnValue("test");
|
||||
mockDomainObject.getCapability.and.returnValue(mockContext);
|
||||
mockDomainObject.getModel.and.returnValue({name: 'test object'});
|
||||
|
||||
mockContext.getParent.and.returnValue(mockParent);
|
||||
mockType.hasFeature.and.returnValue(true);
|
||||
|
||||
actionContext = { domainObject: mockDomainObject };
|
||||
|
||||
action = new RemoveAction({overlays: mockOverlayAPI}, mockNavigationService, actionContext);
|
||||
});
|
||||
|
||||
it("only applies to objects with parents", function () {
|
||||
expect(RemoveAction.appliesTo(actionContext)).toBeTruthy();
|
||||
|
||||
mockContext.getParent.and.returnValue(undefined);
|
||||
|
||||
expect(RemoveAction.appliesTo(actionContext)).toBeFalsy();
|
||||
|
||||
// Also verify that creatability was checked
|
||||
expect(mockType.hasFeature).toHaveBeenCalledWith('creation');
|
||||
});
|
||||
|
||||
it("shows a blocking message dialog", function () {
|
||||
mockParent = jasmine.createSpyObj(
|
||||
"parent",
|
||||
["getModel", "getCapability", "useCapability"]
|
||||
);
|
||||
|
||||
action.perform();
|
||||
|
||||
expect(mockOverlayAPI.dialog).toHaveBeenCalled();
|
||||
|
||||
// Also check that no mutation happens at this point
|
||||
expect(mockParent.useCapability).not.toHaveBeenCalledWith("mutation", jasmine.any(Function));
|
||||
});
|
||||
|
||||
describe("after the remove callback is triggered", function () {
|
||||
var mockChildContext,
|
||||
mockChildObject,
|
||||
mockDialogHandle,
|
||||
mockGrandchildContext,
|
||||
mockGrandchildObject,
|
||||
mockRootContext,
|
||||
mockRootObject;
|
||||
|
||||
beforeEach(function () {
|
||||
mockChildObject = jasmine.createSpyObj(
|
||||
"domainObject",
|
||||
["getId", "getCapability"]
|
||||
);
|
||||
|
||||
mockDialogHandle = jasmine.createSpyObj(
|
||||
"dialogHandle",
|
||||
["dismiss"]
|
||||
);
|
||||
|
||||
mockGrandchildObject = jasmine.createSpyObj(
|
||||
"domainObject",
|
||||
["getId", "getCapability"]
|
||||
);
|
||||
|
||||
mockRootObject = jasmine.createSpyObj(
|
||||
"domainObject",
|
||||
["getId", "getCapability"]
|
||||
);
|
||||
|
||||
mockChildContext = jasmine.createSpyObj("context", ["getParent"]);
|
||||
mockGrandchildContext = jasmine.createSpyObj("context", ["getParent"]);
|
||||
mockRootContext = jasmine.createSpyObj("context", ["getParent"]);
|
||||
|
||||
mockOverlayAPI.dialog.and.returnValue(mockDialogHandle);
|
||||
});
|
||||
|
||||
it("mutates the parent when performed", function () {
|
||||
action.perform();
|
||||
mockOverlayAPI.dialog.calls.mostRecent().args[0]
|
||||
.buttons[0].callback();
|
||||
|
||||
expect(mockMutation.invoke)
|
||||
.toHaveBeenCalledWith(jasmine.any(Function));
|
||||
});
|
||||
|
||||
it("changes composition from its mutation function", function () {
|
||||
var mutator, result;
|
||||
|
||||
action.perform();
|
||||
mockOverlayAPI.dialog.calls.mostRecent().args[0]
|
||||
.buttons[0].callback();
|
||||
|
||||
mutator = mockMutation.invoke.calls.mostRecent().args[0];
|
||||
result = mutator(model);
|
||||
|
||||
// Should not have cancelled the mutation
|
||||
expect(result).not.toBe(false);
|
||||
|
||||
// Simulate mutate's behavior (remove can either return a
|
||||
// new model or modify this one in-place)
|
||||
result = result || model;
|
||||
|
||||
// Should have removed "test" - that was our
|
||||
// mock domain object's id.
|
||||
expect(result.composition).toEqual(["a", "b"]);
|
||||
});
|
||||
|
||||
it("removes parent of object currently navigated to", function () {
|
||||
// Navigates to child object
|
||||
mockNavigationService.getNavigation.and.returnValue(mockChildObject);
|
||||
|
||||
// Test is id of object being removed
|
||||
// Child object has different id
|
||||
mockDomainObject.getId.and.returnValue("test");
|
||||
mockChildObject.getId.and.returnValue("not test");
|
||||
|
||||
// Sets context for the child and domainObject
|
||||
mockDomainObject.getCapability.and.returnValue(mockContext);
|
||||
mockChildObject.getCapability.and.returnValue(mockChildContext);
|
||||
|
||||
// Parents of child and domainObject are set
|
||||
mockContext.getParent.and.returnValue(mockParent);
|
||||
mockChildContext.getParent.and.returnValue(mockDomainObject);
|
||||
|
||||
mockType.hasFeature.and.returnValue(true);
|
||||
|
||||
action.perform();
|
||||
mockOverlayAPI.dialog.calls.mostRecent().args[0]
|
||||
.buttons[0].callback();
|
||||
|
||||
// Expects navigation to parent of domainObject (removed object)
|
||||
expect(mockNavigationService.setNavigation).toHaveBeenCalledWith(mockParent);
|
||||
});
|
||||
|
||||
it("checks if removing object not in ascendent path (reaches ROOT)", function () {
|
||||
// Navigates to grandchild of ROOT
|
||||
mockNavigationService.getNavigation.and.returnValue(mockGrandchildObject);
|
||||
|
||||
// domainObject (grandparent) is set as ROOT, child and grandchild
|
||||
// are set objects not being removed
|
||||
mockDomainObject.getId.and.returnValue("test 1");
|
||||
mockRootObject.getId.and.returnValue("ROOT");
|
||||
mockChildObject.getId.and.returnValue("not test 2");
|
||||
mockGrandchildObject.getId.and.returnValue("not test 3");
|
||||
|
||||
// Sets context for the grandchild, child, and domainObject
|
||||
mockRootObject.getCapability.and.returnValue(mockRootContext);
|
||||
mockChildObject.getCapability.and.returnValue(mockChildContext);
|
||||
mockGrandchildObject.getCapability.and.returnValue(mockGrandchildContext);
|
||||
|
||||
// Parents of grandchild and child are set
|
||||
mockChildContext.getParent.and.returnValue(mockRootObject);
|
||||
mockGrandchildContext.getParent.and.returnValue(mockChildObject);
|
||||
|
||||
mockType.hasFeature.and.returnValue(true);
|
||||
|
||||
action.perform();
|
||||
mockOverlayAPI.dialog.calls.mostRecent().args[0]
|
||||
.buttons[0].callback();
|
||||
|
||||
// Expects no navigation to occur
|
||||
expect(mockNavigationService.setNavigation).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
@ -25,7 +25,7 @@ define(
|
||||
["../../src/actions/SaveAsAction"],
|
||||
function (SaveAsAction) {
|
||||
|
||||
xdescribe("The Save As action", function () {
|
||||
describe("The Save As action", function () {
|
||||
var mockDomainObject,
|
||||
mockClonedObject,
|
||||
mockEditorCapability,
|
||||
|
@ -24,7 +24,7 @@ define(
|
||||
["../../src/capabilities/EditorCapability"],
|
||||
function (EditorCapability) {
|
||||
|
||||
xdescribe("The editor capability", function () {
|
||||
describe("The editor capability", function () {
|
||||
var mockDomainObject,
|
||||
capabilities,
|
||||
mockParentObject,
|
||||
|
@ -27,7 +27,7 @@ define(
|
||||
["../../src/creation/CreateAction"],
|
||||
function (CreateAction) {
|
||||
|
||||
xdescribe("The create action", function () {
|
||||
describe("The create action", function () {
|
||||
var mockType,
|
||||
mockParent,
|
||||
mockContext,
|
||||
|
@ -27,7 +27,7 @@ define(
|
||||
["../../src/creation/CreateWizard"],
|
||||
function (CreateWizard) {
|
||||
|
||||
xdescribe("The create wizard", function () {
|
||||
describe("The create wizard", function () {
|
||||
var mockType,
|
||||
mockParent,
|
||||
mockProperties,
|
||||
|
@ -93,33 +93,24 @@ define(
|
||||
expect(mockOnCancel).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe("Adds callbacks to transaction", function () {
|
||||
beforeEach(function () {
|
||||
spyOn(manager, 'clearTransactionsFor');
|
||||
manager.clearTransactionsFor.and.callThrough();
|
||||
});
|
||||
it("ignores subsequent calls for the same object", function () {
|
||||
manager.addToTransaction(
|
||||
testId,
|
||||
jasmine.createSpy(),
|
||||
jasmine.createSpy()
|
||||
);
|
||||
expect(mockTransactionService.addToTransaction.calls.count())
|
||||
.toEqual(1);
|
||||
});
|
||||
|
||||
it("and clears pending calls if same object", function () {
|
||||
manager.addToTransaction(
|
||||
testId,
|
||||
jasmine.createSpy(),
|
||||
jasmine.createSpy()
|
||||
);
|
||||
expect(manager.clearTransactionsFor).toHaveBeenCalledWith(testId);
|
||||
});
|
||||
|
||||
it("and does not clear pending calls if different object", function () {
|
||||
manager.addToTransaction(
|
||||
'other-id',
|
||||
jasmine.createSpy(),
|
||||
jasmine.createSpy()
|
||||
);
|
||||
expect(manager.clearTransactionsFor).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
expect(mockTransactionService.addToTransaction.calls.count()).toEqual(2);
|
||||
});
|
||||
it("accepts subsequent calls for other objects", function () {
|
||||
manager.addToTransaction(
|
||||
'other-id',
|
||||
jasmine.createSpy(),
|
||||
jasmine.createSpy()
|
||||
);
|
||||
expect(mockTransactionService.addToTransaction.calls.count())
|
||||
.toEqual(2);
|
||||
});
|
||||
|
||||
it("does not remove callbacks from the transaction", function () {
|
||||
|
@ -20,7 +20,8 @@
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
<!-- DO NOT ADD SPACES BETWEEN THE SPANS - IT ADDS WHITE SPACE!! -->
|
||||
<div class="c-indicator {{ngModel.getCssClass()}}"
|
||||
<div class="ls-indicator {{ngModel.getCssClass()}}"
|
||||
title="{{ngModel.getDescription()}}"
|
||||
ng-show="ngModel.getText().length > 0">
|
||||
<span class="label c-indicator__label">{{ngModel.getText()}}</span>
|
||||
<span class="label">{{ngModel.getText()}}</span>
|
||||
</div>
|
||||
|
@ -19,7 +19,7 @@
|
||||
this source code distribution or the Licensing information page available
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
<div class="c-object-label">
|
||||
<div class="c-object-label__type-icon {{type.getCssClass()}}" ng-class="{ 'l-icon-link':location.isLink() }"></div>
|
||||
<div class='c-object-label__name'>{{model.name}}</div>
|
||||
<div class="t-object-label l-flex-row flex-elem grows">
|
||||
<div class="t-item-icon flex-elem {{type.getCssClass()}}" ng-class="{ 'l-icon-link':location.isLink() }"></div>
|
||||
<div class='t-title-label flex-elem grows'>{{model.name}}</div>
|
||||
</div>
|
||||
|
@ -1,13 +1,13 @@
|
||||
<div ng-controller="BannerController" ng-show="active.notification"
|
||||
class="c-message-banner {{active.notification.model.severity}}" ng-class="{
|
||||
class="l-message-banner s-message-banner {{active.notification.model.severity}}" ng-class="{
|
||||
'minimized': active.notification.model.minimized,
|
||||
'new': !active.notification.model.minimized}"
|
||||
ng-click="maximize(active.notification)">
|
||||
<span class="c-message-banner__message">
|
||||
<span class="banner-elem label">
|
||||
{{active.notification.model.title}}
|
||||
</span>
|
||||
<span ng-show="active.notification.model.progress !== undefined || active.notification.model.unknownProgress">
|
||||
<mct-include key="'progress-bar'" class="c-message-banner__progress-bar"
|
||||
<mct-include key="'progress-bar'" class="banner-elem"
|
||||
ng-model="active.notification.model">
|
||||
</mct-include>
|
||||
</span>
|
||||
@ -16,5 +16,5 @@
|
||||
ng-click="action(active.notification.model.primaryOption.callback, $event)">
|
||||
{{active.notification.model.primaryOption.label}}
|
||||
</a>
|
||||
<button class="c-message-banner__close-button c-click-icon icon-x-in-circle" ng-click="dismiss(active.notification, $event)"></button>
|
||||
<a class="banner-elem close icon-x" ng-click="dismiss(active.notification, $event)"></a>
|
||||
</div>
|
||||
|
@ -20,11 +20,14 @@
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
<span ng-controller="ToggleController as toggle">
|
||||
<div class="u-contents" ng-controller="TreeNodeController as treeNode">
|
||||
<div class="c-tree__item menus-to-left"
|
||||
ng-class="{selected: treeNode.isSelected()}">
|
||||
<span class='c-disclosure-triangle c-tree__item__view-control'
|
||||
ng-class="{ 'is-enabled': model.composition !== undefined, 'c-disclosure-triangle--expanded': toggle.isActive() }"
|
||||
<span ng-controller="TreeNodeController as treeNode">
|
||||
<span
|
||||
class="tree-item menus-to-left"
|
||||
ng-class="{selected: treeNode.isSelected()}"
|
||||
>
|
||||
<span
|
||||
class='ui-symbol view-control flex-elem'
|
||||
ng-class="{ 'has-children': model.composition !== undefined, expanded: toggle.isActive() }"
|
||||
ng-click="toggle.toggle(); treeNode.trackExpansion()"
|
||||
>
|
||||
</span>
|
||||
@ -36,15 +39,19 @@
|
||||
ng-click="treeNode.select()"
|
||||
>
|
||||
</mct-representation>
|
||||
</div>
|
||||
<div class="u-contents"
|
||||
</span>
|
||||
<span
|
||||
class="tree-item-subtree"
|
||||
ng-show="toggle.isActive()"
|
||||
ng-if="model.composition !== undefined">
|
||||
ng-if="model.composition !== undefined"
|
||||
>
|
||||
|
||||
<mct-representation key="'subtree'"
|
||||
ng-model="ngModel"
|
||||
parameters="parameters"
|
||||
mct-object="treeNode.hasBeenExpanded() && domainObject">
|
||||
</mct-representation>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
|
@ -19,8 +19,8 @@
|
||||
this source code distribution or the Licensing information page available
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
<ul class="c-tree">
|
||||
<li class="c-tree__item-h">
|
||||
<ul class="tree">
|
||||
<li>
|
||||
<mct-representation key="'tree-node'"
|
||||
mct-object="domainObject"
|
||||
ng-model="ngModel"
|
||||
|
@ -1,2 +1,4 @@
|
||||
<span class="c-tree__item js-tree__item"></span>
|
||||
<span class="c-tree__item-subtree"></span>
|
||||
<span class="tree-item menus-to-left">
|
||||
</span>
|
||||
<span class="tree-item-subtree">
|
||||
</span>
|
||||
|
@ -1 +1,2 @@
|
||||
<span class='c-disclosure-triangle c-tree__item__view-control'></span>
|
||||
<span class='ui-symbol view-control flex-elem'>
|
||||
</span>
|
||||
|
@ -1,4 +1,6 @@
|
||||
<div class="rep-object-label c-object-label c-tree__item__label">
|
||||
<div class="c-object-label__type-icon c-tree__item__type-icon t-item-icon"></div>
|
||||
<div class="c-object-label__name c-tree__item__name t-title-label"></div>
|
||||
</div>
|
||||
<span class="rep-object-label">
|
||||
<div class="t-object-label l-flex-row flex-elem grows">
|
||||
<div class="t-item-icon flex-elem"></div>
|
||||
<div class='t-title-label flex-elem grows'></div>
|
||||
</div>
|
||||
</span>
|
||||
|
@ -54,7 +54,6 @@ define(
|
||||
if (isDestroyed) {
|
||||
return;
|
||||
}
|
||||
|
||||
var removeSelectable = openmct.selection.selectable(
|
||||
element[0],
|
||||
scope.$eval(attrs.mctSelectable),
|
||||
|
@ -37,9 +37,9 @@ define([
|
||||
this.expanded = state;
|
||||
|
||||
if (state) {
|
||||
this.el.addClass('c-disclosure-triangle--expanded');
|
||||
this.el.addClass('expanded');
|
||||
} else {
|
||||
this.el.removeClass('c-disclosure-triangle--expanded');
|
||||
this.el.removeClass('expanded');
|
||||
}
|
||||
|
||||
this.callbacks.forEach(function (callback) {
|
||||
|
@ -28,7 +28,7 @@ define([
|
||||
], function ($, nodeTemplate, ToggleView, TreeLabelView) {
|
||||
|
||||
function TreeNodeView(gestureService, subtreeFactory, selectFn, openmct) {
|
||||
this.li = $('<li class="c-tree__item-h">');
|
||||
this.li = $('<li>');
|
||||
this.openmct = openmct;
|
||||
this.statusClasses = [];
|
||||
|
||||
@ -38,7 +38,7 @@ define([
|
||||
if (!this.subtreeView) {
|
||||
this.subtreeView = subtreeFactory();
|
||||
this.subtreeView.model(this.activeObject);
|
||||
this.li.find('.c-tree__item-subtree').eq(0)
|
||||
this.li.find('.tree-item-subtree').eq(0)
|
||||
.append($(this.subtreeView.elements()));
|
||||
}
|
||||
$(this.subtreeView.elements()).removeClass('hidden');
|
||||
@ -85,9 +85,9 @@ define([
|
||||
var obj = domainObject.useCapability('adapter');
|
||||
var hasComposition = this.openmct.composition.get(obj) !== undefined;
|
||||
if (hasComposition) {
|
||||
$(this.toggleView.elements()).addClass('is-enabled');
|
||||
$(this.toggleView.elements()).removeClass('no-children');
|
||||
} else {
|
||||
$(this.toggleView.elements()).removeClass('is-enabled');
|
||||
$(this.toggleView.elements()).addClass('no-children');
|
||||
}
|
||||
}
|
||||
|
||||
@ -120,7 +120,7 @@ define([
|
||||
selectedIdPath = getIdPath(domainObject);
|
||||
|
||||
if (this.onSelectionPath) {
|
||||
this.li.find('.js-tree__item').eq(0).removeClass('is-selected');
|
||||
this.li.find('.tree-item').eq(0).removeClass('selected');
|
||||
if (this.subtreeView) {
|
||||
this.subtreeView.value(undefined);
|
||||
}
|
||||
@ -136,7 +136,7 @@ define([
|
||||
|
||||
if (this.onSelectionPath) {
|
||||
if (activeIdPath.length === selectedIdPath.length) {
|
||||
this.li.find('.js-tree__item').eq(0).addClass('is-selected');
|
||||
this.li.find('.tree-item').eq(0).addClass('selected');
|
||||
} else {
|
||||
// Expand to reveal the selection
|
||||
this.toggleView.value(true);
|
||||
|
@ -27,7 +27,7 @@ define([
|
||||
], function ($, TreeNodeView, spinnerTemplate) {
|
||||
|
||||
function TreeView(gestureService, openmct, selectFn) {
|
||||
this.ul = $('<ul class="c-tree"></ul>');
|
||||
this.ul = $('<ul class="tree"></ul>');
|
||||
this.nodeViews = [];
|
||||
this.callbacks = [];
|
||||
this.selectFn = selectFn || this.value.bind(this);
|
||||
|
@ -26,7 +26,7 @@ define([
|
||||
'zepto'
|
||||
], function (TreeView, $) {
|
||||
|
||||
xdescribe("TreeView", function () {
|
||||
describe("TreeView", function () {
|
||||
var mockGestureService,
|
||||
mockGestureHandle,
|
||||
mockDomainObject,
|
||||
|
@ -1,8 +1,8 @@
|
||||
<!-- DO NOT ADD SPACES BETWEEN THE SPANS - IT ADDS WHITE SPACE!! -->
|
||||
<div ng-show="notifications.length > 0" class="c-indicator c-indicator--clickable s-status-{{highest.severity}} icon-bell"
|
||||
<div ng-show="notifications.length > 0" class="ls-indicator s-status-{{highest.severity}} icon-bell"
|
||||
ng-controller="NotificationIndicatorController">
|
||||
<span class="label c-indicator__label">
|
||||
<button ng-click="showNotificationsList()">
|
||||
{{notifications.length}} Notification<span ng-show="notifications.length > 1">s</span></button>
|
||||
</span><span class="c-indicator__count">{{notifications.length}}</span>
|
||||
<span class="label">
|
||||
<a ng-click="showNotificationsList()">
|
||||
{{notifications.length}} Notification<span ng-show="notifications.length > 1">s</span></a>
|
||||
</span><span class="count">{{notifications.length}}</span>
|
||||
</div>
|
||||
|
@ -43,25 +43,12 @@ define(
|
||||
* Launch a dialog showing a list of current notifications.
|
||||
*/
|
||||
$scope.showNotificationsList = function () {
|
||||
let notificationsList = openmct.notifications.notifications.map(notification => {
|
||||
if (notification.model.severity === 'alert' || notification.model.severity === 'info') {
|
||||
notification.model.primaryOption = {
|
||||
label: 'Dismiss',
|
||||
callback: () => {
|
||||
let currentIndex = notificationsList.indexOf(notification);
|
||||
notification.dismiss();
|
||||
notificationsList.splice(currentIndex, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return notification;
|
||||
})
|
||||
dialogService.getDialogResponse('overlay-message-list', {
|
||||
dialog: {
|
||||
title: "Messages",
|
||||
//Launch the message list dialog with the models
|
||||
// from the notifications
|
||||
messages: notificationsList
|
||||
messages: openmct.notifications.notifications
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -24,7 +24,7 @@ define(
|
||||
['../src/NotificationIndicatorController'],
|
||||
function (NotificationIndicatorController) {
|
||||
|
||||
xdescribe("The notification indicator controller ", function () {
|
||||
describe("The notification indicator controller ", function () {
|
||||
var mockNotificationService,
|
||||
mockScope,
|
||||
mockDialogService,
|
||||
|
@ -23,7 +23,7 @@
|
||||
define(
|
||||
["../src/ComposeActionPolicy"],
|
||||
function (ComposeActionPolicy) {
|
||||
xdescribe("The compose action policy", function () {
|
||||
describe("The compose action policy", function () {
|
||||
var mockInjector,
|
||||
mockPolicyService,
|
||||
mockTypes,
|
||||
|
@ -43,10 +43,23 @@ define([], function () {
|
||||
var mutationTopic = topic('mutation');
|
||||
mutationTopic.listen(function (domainObject) {
|
||||
var persistence = domainObject.getCapability('persistence');
|
||||
var wasActive = transactionService.isActive();
|
||||
cacheService.put(domainObject.getId(), domainObject.getModel());
|
||||
|
||||
if (hasChanged(domainObject)) {
|
||||
persistence.persist();
|
||||
|
||||
if (!wasActive) {
|
||||
transactionService.startTransaction();
|
||||
}
|
||||
|
||||
transactionService.addToTransaction(
|
||||
persistence.persist.bind(persistence),
|
||||
persistence.refresh.bind(persistence)
|
||||
);
|
||||
|
||||
if (!wasActive) {
|
||||
transactionService.commit();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -24,27 +24,22 @@ define(
|
||||
["../../src/runs/TransactingMutationListener"],
|
||||
function (TransactingMutationListener) {
|
||||
|
||||
describe("TransactingMutationListener", function () {
|
||||
xdescribe("TransactingMutationListener", function () {
|
||||
var mockTopic,
|
||||
mockMutationTopic,
|
||||
mockCacheService,
|
||||
mockTransactionService,
|
||||
mockDomainObject,
|
||||
mockModel,
|
||||
mockPersistence;
|
||||
|
||||
beforeEach(function () {
|
||||
mockTopic = jasmine.createSpy('topic');
|
||||
mockMutationTopic =
|
||||
jasmine.createSpyObj('mutation', ['listen']);
|
||||
mockCacheService =
|
||||
jasmine.createSpyObj('cacheService', [
|
||||
'put'
|
||||
]);
|
||||
mockTransactionService =
|
||||
jasmine.createSpyObj('transactionService', [
|
||||
'isActive',
|
||||
'startTransaction',
|
||||
'addToTransaction',
|
||||
'commit'
|
||||
]);
|
||||
mockDomainObject = jasmine.createSpyObj(
|
||||
@ -57,24 +52,18 @@ define(
|
||||
);
|
||||
|
||||
mockTopic.and.callFake(function (t) {
|
||||
expect(t).toBe('mutation');
|
||||
return mockMutationTopic;
|
||||
return (t === 'mutation') && mockMutationTopic;
|
||||
});
|
||||
|
||||
mockDomainObject.getId.and.returnValue('mockId');
|
||||
mockDomainObject.getCapability.and.callFake(function (c) {
|
||||
expect(c).toBe('persistence');
|
||||
return mockPersistence;
|
||||
return (c === 'persistence') && mockPersistence;
|
||||
});
|
||||
mockModel = {};
|
||||
mockDomainObject.getModel.and.returnValue(mockModel);
|
||||
|
||||
mockPersistence.persisted.and.returnValue(true);
|
||||
|
||||
return new TransactingMutationListener(
|
||||
mockTopic,
|
||||
mockTransactionService,
|
||||
mockCacheService
|
||||
mockTransactionService
|
||||
);
|
||||
});
|
||||
|
||||
@ -83,27 +72,48 @@ define(
|
||||
.toHaveBeenCalledWith(jasmine.any(Function));
|
||||
});
|
||||
|
||||
it("calls persist if the model has changed", function () {
|
||||
mockModel.persisted = Date.now();
|
||||
[false, true].forEach(function (isActive) {
|
||||
var verb = isActive ? "is" : "isn't";
|
||||
|
||||
//Mark the model dirty by setting the mutated date later than the last persisted date.
|
||||
mockModel.modified = mockModel.persisted + 1;
|
||||
function onlyWhenInactive(expectation) {
|
||||
return isActive ? expectation.not : expectation;
|
||||
}
|
||||
|
||||
mockMutationTopic.listen.calls.mostRecent()
|
||||
.args[0](mockDomainObject);
|
||||
describe("when a transaction " + verb + " active", function () {
|
||||
var innerVerb = isActive ? "does" : "doesn't";
|
||||
|
||||
expect(mockPersistence.persist).toHaveBeenCalled();
|
||||
});
|
||||
beforeEach(function () {
|
||||
mockTransactionService.isActive.and.returnValue(isActive);
|
||||
});
|
||||
|
||||
it("does not call persist if the model has not changed", function () {
|
||||
mockModel.persisted = Date.now();
|
||||
describe("and mutation occurs", function () {
|
||||
beforeEach(function () {
|
||||
mockMutationTopic.listen.calls.mostRecent()
|
||||
.args[0](mockDomainObject);
|
||||
});
|
||||
|
||||
mockModel.modified = mockModel.persisted;
|
||||
|
||||
mockMutationTopic.listen.calls.mostRecent()
|
||||
.args[0](mockDomainObject);
|
||||
it(innerVerb + " start a new transaction", function () {
|
||||
onlyWhenInactive(
|
||||
expect(mockTransactionService.startTransaction)
|
||||
).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
expect(mockPersistence.persist).not.toHaveBeenCalled();
|
||||
it("adds to the active transaction", function () {
|
||||
expect(mockTransactionService.addToTransaction)
|
||||
.toHaveBeenCalledWith(
|
||||
jasmine.any(Function),
|
||||
jasmine.any(Function)
|
||||
);
|
||||
});
|
||||
|
||||
it(innerVerb + " immediately commit", function () {
|
||||
onlyWhenInactive(
|
||||
expect(mockTransactionService.commit)
|
||||
).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ define([
|
||||
"./src/actions/MoveAction",
|
||||
"./src/actions/CopyAction",
|
||||
"./src/actions/LinkAction",
|
||||
"./src/actions/GoToOriginalAction",
|
||||
"./src/actions/SetPrimaryLocationAction",
|
||||
"./src/services/LocatingCreationDecorator",
|
||||
"./src/services/LocatingObjectDecorator",
|
||||
@ -40,6 +41,7 @@ define([
|
||||
MoveAction,
|
||||
CopyAction,
|
||||
LinkAction,
|
||||
GoToOriginalAction,
|
||||
SetPrimaryLocationAction,
|
||||
LocatingCreationDecorator,
|
||||
LocatingObjectDecorator,
|
||||
@ -102,6 +104,14 @@ define([
|
||||
"linkService"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "follow",
|
||||
"name": "Go To Original",
|
||||
"description": "Go to the original, un-linked instance of this object.",
|
||||
"cssClass": "",
|
||||
"category": "contextual",
|
||||
"implementation": GoToOriginalAction
|
||||
},
|
||||
{
|
||||
"key": "locate",
|
||||
"name": "Set Primary Location",
|
||||
|
60
platform/entanglement/src/actions/GoToOriginalAction.js
Normal file
60
platform/entanglement/src/actions/GoToOriginalAction.js
Normal file
@ -0,0 +1,60 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2018, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define(
|
||||
function () {
|
||||
|
||||
/**
|
||||
* Implements the "Go To Original" action, which follows a link back
|
||||
* to an original instance of an object.
|
||||
*
|
||||
* @implements {Action}
|
||||
* @constructor
|
||||
* @private
|
||||
* @memberof platform/entanglement
|
||||
* @param {ActionContext} context the context in which the action
|
||||
* will be performed
|
||||
*/
|
||||
function GoToOriginalAction(context) {
|
||||
this.domainObject = context.domainObject;
|
||||
}
|
||||
|
||||
GoToOriginalAction.prototype.perform = function () {
|
||||
return this.domainObject.getCapability("location").getOriginal()
|
||||
.then(function (originalObject) {
|
||||
var actionCapability =
|
||||
originalObject.getCapability("action");
|
||||
return actionCapability &&
|
||||
actionCapability.perform("navigate");
|
||||
});
|
||||
};
|
||||
|
||||
GoToOriginalAction.appliesTo = function (context) {
|
||||
var domainObject = context.domainObject;
|
||||
return domainObject && domainObject.hasCapability("location") &&
|
||||
domainObject.getCapability("location").isLink();
|
||||
};
|
||||
|
||||
return GoToOriginalAction;
|
||||
}
|
||||
);
|
||||
|
93
platform/entanglement/test/actions/GoToOriginalActionSpec.js
Normal file
93
platform/entanglement/test/actions/GoToOriginalActionSpec.js
Normal file
@ -0,0 +1,93 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2018, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
define(
|
||||
[
|
||||
'../../src/actions/GoToOriginalAction',
|
||||
'../DomainObjectFactory',
|
||||
'../ControlledPromise'
|
||||
],
|
||||
function (GoToOriginalAction, domainObjectFactory, ControlledPromise) {
|
||||
|
||||
describe("The 'go to original' action", function () {
|
||||
var testContext,
|
||||
originalDomainObject,
|
||||
mockLocationCapability,
|
||||
mockOriginalActionCapability,
|
||||
originalPromise,
|
||||
action;
|
||||
|
||||
beforeEach(function () {
|
||||
mockLocationCapability = jasmine.createSpyObj(
|
||||
'location',
|
||||
['isLink', 'isOriginal', 'getOriginal']
|
||||
);
|
||||
mockOriginalActionCapability = jasmine.createSpyObj(
|
||||
'action',
|
||||
['perform', 'getActions']
|
||||
);
|
||||
originalPromise = new ControlledPromise();
|
||||
mockLocationCapability.getOriginal.and.returnValue(originalPromise);
|
||||
mockLocationCapability.isLink.and.returnValue(true);
|
||||
mockLocationCapability.isOriginal.and.callFake(function () {
|
||||
return !mockLocationCapability.isLink();
|
||||
});
|
||||
testContext = {
|
||||
domainObject: domainObjectFactory({
|
||||
capabilities: {
|
||||
location: mockLocationCapability
|
||||
}
|
||||
})
|
||||
};
|
||||
originalDomainObject = domainObjectFactory({
|
||||
capabilities: {
|
||||
action: mockOriginalActionCapability
|
||||
}
|
||||
});
|
||||
|
||||
action = new GoToOriginalAction(testContext);
|
||||
});
|
||||
|
||||
it("is applicable to links", function () {
|
||||
expect(GoToOriginalAction.appliesTo(testContext))
|
||||
.toBeTruthy();
|
||||
});
|
||||
|
||||
it("is not applicable to originals", function () {
|
||||
mockLocationCapability.isLink.and.returnValue(false);
|
||||
expect(GoToOriginalAction.appliesTo(testContext))
|
||||
.toBeFalsy();
|
||||
});
|
||||
|
||||
it("navigates to original objects when performed", function () {
|
||||
expect(mockOriginalActionCapability.perform)
|
||||
.not.toHaveBeenCalled();
|
||||
action.perform();
|
||||
originalPromise.resolve(originalDomainObject);
|
||||
expect(mockOriginalActionCapability.perform)
|
||||
.toHaveBeenCalledWith('navigate');
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
);
|
@ -42,7 +42,7 @@ define(
|
||||
return promise;
|
||||
}
|
||||
|
||||
xdescribe("CopyService", function () {
|
||||
describe("CopyService", function () {
|
||||
var policyService;
|
||||
|
||||
beforeEach(function () {
|
||||
|
@ -29,7 +29,7 @@ define(
|
||||
],
|
||||
function (LinkService, domainObjectFactory, ControlledPromise) {
|
||||
|
||||
xdescribe("LinkService", function () {
|
||||
describe("LinkService", function () {
|
||||
|
||||
var linkService,
|
||||
mockPolicyService;
|
||||
|
@ -34,7 +34,7 @@ define(
|
||||
ControlledPromise
|
||||
) {
|
||||
|
||||
xdescribe("MoveService", function () {
|
||||
describe("MoveService", function () {
|
||||
|
||||
var moveService,
|
||||
policyService,
|
||||
|
@ -24,10 +24,10 @@
|
||||
<button ng-click="timer.clickStopButton()"
|
||||
ng-hide="timer.timerState == 'stopped'"
|
||||
title="Reset"
|
||||
class="c-timer__ctrl-reset c-icon-button c-icon-button--major icon-reset"></button>
|
||||
class="c-timer__ctrl-reset c-click-icon c-click-icon--major icon-reset"></button>
|
||||
<button ng-click="timer.clickButton()"
|
||||
title="{{timer.buttonText()}}"
|
||||
class="c-timer__ctrl-pause-play c-icon-button c-icon-button--major {{timer.buttonCssClass()}}"></button>
|
||||
class="c-timer__ctrl-pause-play c-click-icon c-click-icon--major {{timer.buttonCssClass()}}"></button>
|
||||
</div>
|
||||
<div class="c-timer__direction {{timer.signClass()}}"
|
||||
ng-hide="!timer.signClass()"></div>
|
||||
|
@ -49,7 +49,7 @@ define(
|
||||
};
|
||||
|
||||
ClockIndicator.prototype.getCssClass = function () {
|
||||
return "t-indicator-clock icon-clock no-minify c-indicator--not-clickable";
|
||||
return "t-indicator-clock icon-clock no-collapse float-right";
|
||||
};
|
||||
|
||||
ClockIndicator.prototype.getText = function () {
|
||||
|
@ -31,7 +31,7 @@ define([
|
||||
MCT,
|
||||
$
|
||||
) {
|
||||
xdescribe("The timer-following indicator", function () {
|
||||
describe("The timer-following indicator", function () {
|
||||
var timerService;
|
||||
var openmct;
|
||||
|
||||
|
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 && 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");
|
||||
}
|
||||
}
|
||||
});
|
720
platform/features/fixed/src/FixedController.js
Normal file
720
platform/features/fixed/src/FixedController.js
Normal file
@ -0,0 +1,720 @@
|
||||
/*****************************************************************************
|
||||
* 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(
|
||||
[
|
||||
'lodash',
|
||||
'./FixedProxy',
|
||||
'./elements/ElementProxies',
|
||||
'./FixedDragHandle',
|
||||
'../../../../src/api/objects/object-utils'
|
||||
],
|
||||
function (
|
||||
_,
|
||||
FixedProxy,
|
||||
ElementProxies,
|
||||
FixedDragHandle,
|
||||
objectUtils
|
||||
) {
|
||||
|
||||
var DEFAULT_DIMENSIONS = [2, 1];
|
||||
|
||||
// Convert from element x/y/width/height to an
|
||||
// appropriate ng-style argument, to position elements.
|
||||
function convertPosition(elementProxy) {
|
||||
if (elementProxy.getStyle) {
|
||||
return elementProxy.getStyle();
|
||||
}
|
||||
|
||||
var gridSize = elementProxy.getGridSize();
|
||||
|
||||
// Multiply position/dimensions by grid size
|
||||
return {
|
||||
left: (gridSize[0] * elementProxy.element.x) + 'px',
|
||||
top: (gridSize[1] * elementProxy.element.y) + 'px',
|
||||
width: (gridSize[0] * elementProxy.element.width) + 'px',
|
||||
height: (gridSize[1] * elementProxy.element.height) + 'px'
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* The FixedController is responsible for supporting the
|
||||
* Fixed Position view. It arranges frames according to saved
|
||||
* configuration and provides methods for updating these based on
|
||||
* mouse movement.
|
||||
* @memberof platform/features/layout
|
||||
* @constructor
|
||||
* @param {Scope} $scope the controller's Angular scope
|
||||
*/
|
||||
function FixedController($scope, $q, dialogService, openmct, $element) {
|
||||
this.names = {}; // Cache names by ID
|
||||
this.values = {}; // Cache values by ID
|
||||
this.elementProxiesById = {};
|
||||
this.telemetryObjects = {};
|
||||
this.subscriptions = {};
|
||||
this.openmct = openmct;
|
||||
this.$element = $element;
|
||||
this.$scope = $scope;
|
||||
this.dialogService = dialogService;
|
||||
this.$q = $q;
|
||||
this.newDomainObject = $scope.domainObject.useCapability('adapter');
|
||||
this.fixedViewSelectable = false;
|
||||
|
||||
var self = this;
|
||||
[
|
||||
'digest',
|
||||
'fetchHistoricalData',
|
||||
'getTelemetry',
|
||||
'setDisplayedValue',
|
||||
'subscribeToObject',
|
||||
'unsubscribe',
|
||||
'updateView'
|
||||
].forEach(function (name) {
|
||||
self[name] = self[name].bind(self);
|
||||
});
|
||||
|
||||
// Decorate an element for display
|
||||
function makeProxyElement(element, index, elements) {
|
||||
var ElementProxy = ElementProxies[element.type],
|
||||
e = ElementProxy && new ElementProxy(element, index, elements, self.gridSize);
|
||||
|
||||
if (e) {
|
||||
// Provide a displayable position (convert from grid to px)
|
||||
e.style = convertPosition(e);
|
||||
// Template names are same as type names, presently
|
||||
e.template = element.type;
|
||||
}
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
// Decorate elements in the current configuration
|
||||
function refreshElements() {
|
||||
var elements = (((self.newDomainObject.configuration || {})['fixed-display'] || {}).elements || []);
|
||||
|
||||
// Create the new proxies...
|
||||
self.elementProxies = elements.map(makeProxyElement);
|
||||
|
||||
if (self.selectedElementProxy) {
|
||||
// If selection is not in array, select parent.
|
||||
// Otherwise, set the element to select after refresh.
|
||||
var index = elements.indexOf(self.selectedElementProxy.element);
|
||||
if (index === -1) {
|
||||
self.$element[0].click();
|
||||
} else if (!self.elementToSelectAfterRefresh) {
|
||||
self.elementToSelectAfterRefresh = self.elementProxies[index].element;
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, rebuild lists of elements by id to
|
||||
// facilitate faster update when new telemetry comes in.
|
||||
self.elementProxiesById = {};
|
||||
self.elementProxies.forEach(function (elementProxy) {
|
||||
var id = elementProxy.id;
|
||||
if (elementProxy.element.type === 'fixed.telemetry') {
|
||||
// Provide it a cached name/value to avoid flashing
|
||||
elementProxy.name = self.names[id];
|
||||
elementProxy.value = self.values[id];
|
||||
self.elementProxiesById[id] = self.elementProxiesById[id] || [];
|
||||
self.elementProxiesById[id].push(elementProxy);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Trigger a new query for telemetry data
|
||||
function updateDisplayBounds(bounds, isTick) {
|
||||
if (!isTick) {
|
||||
//Reset values
|
||||
self.values = {};
|
||||
refreshElements();
|
||||
|
||||
//Fetch new data
|
||||
Object.values(self.telemetryObjects).forEach(function (object) {
|
||||
self.fetchHistoricalData(object);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Add an element to this view
|
||||
function addElement(element) {
|
||||
var index;
|
||||
var elements = (((self.newDomainObject.configuration || {})['fixed-display'] || {}).elements || []);
|
||||
elements.push(element);
|
||||
|
||||
if (self.selectedElementProxy) {
|
||||
index = elements.indexOf(self.selectedElementProxy.element);
|
||||
}
|
||||
|
||||
self.mutate("configuration['fixed-display'].elements", elements);
|
||||
elements = (self.newDomainObject.configuration)['fixed-display'].elements || [];
|
||||
self.elementToSelectAfterRefresh = elements[elements.length - 1];
|
||||
|
||||
if (self.selectedElementProxy) {
|
||||
// Update the selected element with the new
|
||||
// value since newDomainOject is mutated.
|
||||
self.selectedElementProxy.element = elements[index];
|
||||
}
|
||||
refreshElements();
|
||||
}
|
||||
|
||||
// Position a panel after a drop event
|
||||
function handleDrop(e, id, position) {
|
||||
// Don't handle this event if it has already been handled
|
||||
if (e.defaultPrevented) {
|
||||
return;
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
// Store the position of this element.
|
||||
// color is set to "" to let the CSS theme determine the default color
|
||||
addElement({
|
||||
type: "fixed.telemetry",
|
||||
x: Math.floor(position.x / self.gridSize[0]),
|
||||
y: Math.floor(position.y / self.gridSize[1]),
|
||||
id: id,
|
||||
stroke: "transparent",
|
||||
color: "",
|
||||
titled: true,
|
||||
width: DEFAULT_DIMENSIONS[0],
|
||||
height: DEFAULT_DIMENSIONS[1],
|
||||
useGrid: true
|
||||
});
|
||||
|
||||
// Subscribe to the new object to get telemetry
|
||||
self.openmct.objects.get(id).then(function (object) {
|
||||
self.getTelemetry(object);
|
||||
});
|
||||
}
|
||||
|
||||
this.elementProxies = [];
|
||||
this.addElement = addElement;
|
||||
this.refreshElements = refreshElements;
|
||||
this.fixedProxy = new FixedProxy(this.addElement, this.$q, this.dialogService);
|
||||
|
||||
this.composition = this.openmct.composition.get(this.newDomainObject);
|
||||
this.composition.on('add', this.onCompositionAdd, this);
|
||||
this.composition.on('remove', this.onCompositionRemove, this);
|
||||
this.composition.load();
|
||||
|
||||
// Position panes where they are dropped
|
||||
$scope.$on("mctDrop", handleDrop);
|
||||
|
||||
$scope.$on("$destroy", this.destroy.bind(this));
|
||||
|
||||
// Respond to external bounds changes
|
||||
this.openmct.time.on("bounds", updateDisplayBounds);
|
||||
|
||||
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.unlisten = this.openmct.objects.observe(this.newDomainObject, '*', function (obj) {
|
||||
this.newDomainObject = JSON.parse(JSON.stringify(obj));
|
||||
this.updateElementPositions(this.newDomainObject.layoutGrid);
|
||||
}.bind(this));
|
||||
|
||||
this.updateElementPositions(this.newDomainObject.layoutGrid);
|
||||
refreshElements();
|
||||
}
|
||||
|
||||
FixedController.prototype.updateElementPositions = function (layoutGrid) {
|
||||
this.gridSize = layoutGrid;
|
||||
|
||||
this.elementProxies.forEach(function (elementProxy) {
|
||||
elementProxy.setGridSize(this.gridSize);
|
||||
elementProxy.style = convertPosition(elementProxy);
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
FixedController.prototype.onCompositionAdd = function (object) {
|
||||
this.getTelemetry(object);
|
||||
};
|
||||
|
||||
FixedController.prototype.onCompositionRemove = function (identifier) {
|
||||
// Defer mutation of newDomainObject to prevent mutating an
|
||||
// outdated version since this is triggered by a composition change.
|
||||
setTimeout(function () {
|
||||
var id = objectUtils.makeKeyString(identifier);
|
||||
var elements = this.newDomainObject.configuration['fixed-display'].elements || [];
|
||||
var newElements = elements.filter(function (proxy) {
|
||||
return proxy.id !== id;
|
||||
});
|
||||
this.mutate("configuration['fixed-display'].elements", newElements);
|
||||
|
||||
if (this.subscriptions[id]) {
|
||||
this.subscriptions[id]();
|
||||
delete this.subscriptions[id];
|
||||
}
|
||||
|
||||
delete this.telemetryObjects[id];
|
||||
this.refreshElements();
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes an element from the view.
|
||||
*
|
||||
* @param {Object} elementProxy the element proxy to remove.
|
||||
*/
|
||||
FixedController.prototype.remove = function (elementProxy) {
|
||||
var element = elementProxy.element;
|
||||
var elements = this.newDomainObject.configuration['fixed-display'].elements || [];
|
||||
elements.splice(elements.indexOf(element), 1);
|
||||
|
||||
if (element.type === 'fixed.telemetry') {
|
||||
this.newDomainObject.composition = this.newDomainObject.composition.filter(function (identifier) {
|
||||
return objectUtils.makeKeyString(identifier) !== element.id;
|
||||
});
|
||||
}
|
||||
|
||||
this.mutate("configuration['fixed-display'].elements", elements);
|
||||
this.refreshElements();
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds a new element to the view.
|
||||
*
|
||||
* @param {string} type the type of element to add. Supported types are:
|
||||
* `fixed.image`
|
||||
* `fixed.box`
|
||||
* `fixed.text`
|
||||
* `fixed.line`
|
||||
*/
|
||||
FixedController.prototype.add = function (type) {
|
||||
this.fixedProxy.add(type);
|
||||
};
|
||||
|
||||
/**
|
||||
* Change the display order of the element proxy.
|
||||
*/
|
||||
FixedController.prototype.order = function (elementProxy, position) {
|
||||
var elements = elementProxy.order(position);
|
||||
|
||||
// Find the selected element index in the updated array.
|
||||
var selectedElemenetIndex = elements.indexOf(this.selectedElementProxy.element);
|
||||
|
||||
this.mutate("configuration['fixed-display'].elements", elements);
|
||||
elements = (this.newDomainObject.configuration)['fixed-display'].elements || [];
|
||||
|
||||
// Update the selected element with the new
|
||||
// value since newDomainOject is mutated.
|
||||
this.selectedElementProxy.element = elements[selectedElemenetIndex];
|
||||
this.refreshElements();
|
||||
};
|
||||
|
||||
FixedController.prototype.generateDragHandle = function (elementProxy, elementHandle) {
|
||||
var index = this.elementProxies.indexOf(elementProxy);
|
||||
|
||||
if (elementHandle) {
|
||||
elementHandle.element = elementProxy.element;
|
||||
elementProxy = elementHandle;
|
||||
}
|
||||
|
||||
return new FixedDragHandle(
|
||||
elementProxy,
|
||||
"configuration['fixed-display'].elements[" + index + "]",
|
||||
this
|
||||
);
|
||||
};
|
||||
|
||||
FixedController.prototype.generateDragHandles = function (elementProxy) {
|
||||
return elementProxy.handles().map(function (handle) {
|
||||
return this.generateDragHandle(elementProxy, handle);
|
||||
}, this);
|
||||
};
|
||||
|
||||
FixedController.prototype.updateSelectionStyle = function () {
|
||||
this.selectedElementProxy.style = convertPosition(this.selectedElementProxy);
|
||||
};
|
||||
|
||||
FixedController.prototype.setSelection = function (selectable) {
|
||||
var selection = selectable[0];
|
||||
|
||||
if (this.selectionListeners) {
|
||||
this.selectionListeners.forEach(function (l) {
|
||||
l();
|
||||
});
|
||||
}
|
||||
|
||||
this.selectionListeners = [];
|
||||
|
||||
if (!selection) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (selection.context.elementProxy) {
|
||||
this.selectedElementProxy = selection.context.elementProxy;
|
||||
this.attachSelectionListeners();
|
||||
this.mvHandle = this.generateDragHandle(this.selectedElementProxy);
|
||||
this.resizeHandles = this.generateDragHandles(this.selectedElementProxy);
|
||||
} else {
|
||||
// Make fixed view selectable if it's not already.
|
||||
if (!this.fixedViewSelectable && selectable.length === 1) {
|
||||
this.fixedViewSelectable = true;
|
||||
selection.context.fixedController = this;
|
||||
this.openmct.selection.select(selection);
|
||||
}
|
||||
|
||||
this.resizeHandles = [];
|
||||
this.mvHandle = undefined;
|
||||
this.selectedElementProxy = undefined;
|
||||
}
|
||||
};
|
||||
|
||||
FixedController.prototype.attachSelectionListeners = function () {
|
||||
var index = this.elementProxies.indexOf(this.selectedElementProxy);
|
||||
var path = "configuration['fixed-display'].elements[" + index + "]";
|
||||
|
||||
this.selectionListeners.push(this.openmct.objects.observe(this.newDomainObject, path + ".useGrid", function (newValue) {
|
||||
if (this.selectedElementProxy.useGrid() !== newValue) {
|
||||
this.selectedElementProxy.useGrid(newValue);
|
||||
this.updateSelectionStyle();
|
||||
this.openmct.objects.mutate(this.newDomainObject, path, this.selectedElementProxy.element);
|
||||
}
|
||||
}.bind(this)));
|
||||
[
|
||||
"width",
|
||||
"height",
|
||||
"stroke",
|
||||
"fill",
|
||||
"x",
|
||||
"y",
|
||||
"x1",
|
||||
"y1",
|
||||
"x2",
|
||||
"y2",
|
||||
"color",
|
||||
"size",
|
||||
"text",
|
||||
"titled"
|
||||
].forEach(function (property) {
|
||||
this.selectionListeners.push(this.openmct.objects.observe(this.newDomainObject, path + "." + property, function (newValue) {
|
||||
this.selectedElementProxy.element[property] = newValue;
|
||||
this.updateSelectionStyle();
|
||||
}.bind(this)));
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
FixedController.prototype.destroy = function () {
|
||||
this.unsubscribe();
|
||||
this.unlisten();
|
||||
this.openmct.time.off("bounds", this.updateDisplayBounds);
|
||||
this.openmct.selection.off("change", this.setSelection);
|
||||
this.composition.off('add', this.onCompositionAdd, this);
|
||||
this.composition.off('remove', this.onCompositionRemove, this);
|
||||
this.openmct.editor.off('isEditing', this.handleEditing, this);
|
||||
};
|
||||
|
||||
/**
|
||||
* A rate-limited digest function. Caps digests at 60Hz
|
||||
* @private
|
||||
*/
|
||||
FixedController.prototype.digest = function () {
|
||||
var self = this;
|
||||
|
||||
if (!this.digesting) {
|
||||
this.digesting = true;
|
||||
requestAnimationFrame(function () {
|
||||
self.$scope.$digest();
|
||||
self.digesting = false;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Unsubscribe all listeners
|
||||
* @private
|
||||
*/
|
||||
FixedController.prototype.unsubscribe = function () {
|
||||
Object.values(this.subscriptions).forEach(function (unsubscribeFunc) {
|
||||
unsubscribeFunc();
|
||||
});
|
||||
this.subscriptions = {};
|
||||
this.telemetryObjects = {};
|
||||
};
|
||||
|
||||
/**
|
||||
* Subscribe to the given domain object
|
||||
* @private
|
||||
* @param {object} object Domain object to subscribe to
|
||||
* @returns {object} The provided object, for chaining.
|
||||
*/
|
||||
FixedController.prototype.subscribeToObject = function (object) {
|
||||
var self = this;
|
||||
var timeAPI = this.openmct.time;
|
||||
var id = objectUtils.makeKeyString(object.identifier);
|
||||
this.subscriptions[id] = self.openmct.telemetry.subscribe(object, function (datum) {
|
||||
if (timeAPI.clock() !== undefined) {
|
||||
self.updateView(object, datum);
|
||||
}
|
||||
}, {});
|
||||
|
||||
return object;
|
||||
};
|
||||
|
||||
/**
|
||||
* Print the values from the given datum against the provided object in the view.
|
||||
* @private
|
||||
* @param {object} telemetryObject The domain object associated with the given telemetry data
|
||||
* @param {object} datum The telemetry datum containing the values to print
|
||||
*/
|
||||
FixedController.prototype.updateView = function (telemetryObject, datum) {
|
||||
var metadata = this.openmct.telemetry.getMetadata(telemetryObject);
|
||||
var valueMetadata = this.chooseValueMetadataToDisplay(metadata);
|
||||
var formattedTelemetryValue = this.getFormattedTelemetryValueForKey(valueMetadata, datum);
|
||||
var limitEvaluator = this.openmct.telemetry.limitEvaluator(telemetryObject);
|
||||
var alarm = limitEvaluator && limitEvaluator.evaluate(datum, valueMetadata);
|
||||
|
||||
this.setDisplayedValue(
|
||||
telemetryObject,
|
||||
formattedTelemetryValue,
|
||||
alarm && alarm.cssClass
|
||||
);
|
||||
this.digest();
|
||||
};
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
FixedController.prototype.getFormattedTelemetryValueForKey = function (valueMetadata, datum) {
|
||||
var formatter = this.openmct.telemetry.getValueFormatter(valueMetadata);
|
||||
|
||||
return formatter.format(datum);
|
||||
};
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
FixedController.prototype.chooseValueMetadataToDisplay = function (metadata) {
|
||||
// If there is a range value, show that preferentially
|
||||
var valueMetadata = metadata.valuesForHints(['range'])[0];
|
||||
|
||||
// If no range is defined, default to the highest priority non time-domain data.
|
||||
if (valueMetadata === undefined) {
|
||||
var valuesOrderedByPriority = metadata.values();
|
||||
valueMetadata = valuesOrderedByPriority.filter(function (values) {
|
||||
return !(values.hints.domain);
|
||||
})[0];
|
||||
}
|
||||
|
||||
return valueMetadata;
|
||||
};
|
||||
|
||||
/**
|
||||
* Request the last historical data point for the given domain object
|
||||
* @param {object} object
|
||||
* @returns {object} the provided object for chaining.
|
||||
*/
|
||||
FixedController.prototype.fetchHistoricalData = function (object) {
|
||||
var bounds = this.openmct.time.bounds();
|
||||
var self = this;
|
||||
|
||||
self.openmct.telemetry.request(object, {start: bounds.start, end: bounds.end, size: 1})
|
||||
.then(function (data) {
|
||||
if (data.length > 0) {
|
||||
self.updateView(object, data[data.length - 1]);
|
||||
}
|
||||
});
|
||||
|
||||
return object;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Print a value to the onscreen element associated with a given telemetry object.
|
||||
* @private
|
||||
* @param {object} telemetryObject The telemetry object associated with the value
|
||||
* @param {string | number} value The value to print to screen
|
||||
* @param {string} [cssClass] an optional CSS class to apply to the onscreen element.
|
||||
*/
|
||||
FixedController.prototype.setDisplayedValue = function (telemetryObject, value, cssClass) {
|
||||
var id = objectUtils.makeKeyString(telemetryObject.identifier);
|
||||
var self = this;
|
||||
|
||||
(self.elementProxiesById[id] || []).forEach(function (element) {
|
||||
self.names[id] = telemetryObject.name;
|
||||
self.values[id] = value;
|
||||
element.name = self.names[id];
|
||||
element.value = self.values[id];
|
||||
element.cssClass = cssClass;
|
||||
});
|
||||
};
|
||||
|
||||
FixedController.prototype.getTelemetry = function (domainObject) {
|
||||
var id = objectUtils.makeKeyString(domainObject.identifier);
|
||||
|
||||
if (this.subscriptions[id]) {
|
||||
this.subscriptions[id]();
|
||||
delete this.subscriptions[id];
|
||||
}
|
||||
delete this.telemetryObjects[id];
|
||||
|
||||
if (!this.openmct.telemetry.isTelemetryObject(domainObject)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize display
|
||||
this.telemetryObjects[id] = domainObject;
|
||||
this.setDisplayedValue(domainObject, "");
|
||||
|
||||
return Promise.resolve(domainObject)
|
||||
.then(this.fetchHistoricalData)
|
||||
.then(this.subscribeToObject);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the size of the grid, in pixels. The returned array
|
||||
* is in the form `[x, y]`.
|
||||
* @returns {number[]} the grid size
|
||||
* @memberof platform/features/layout.FixedController#
|
||||
*/
|
||||
FixedController.prototype.getGridSize = function () {
|
||||
return this.gridSize;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get an array of elements in this panel; these are
|
||||
* decorated proxies for both selection and display.
|
||||
* @returns {Array} elements in this panel
|
||||
*/
|
||||
FixedController.prototype.getElements = function () {
|
||||
return this.elementProxies;
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks if the element should be selected or not.
|
||||
*
|
||||
* @param elementProxy the element to check
|
||||
* @returns {boolean} true if the element should be selected.
|
||||
*/
|
||||
FixedController.prototype.shouldSelect = function (elementProxy) {
|
||||
if (elementProxy.element === this.elementToSelectAfterRefresh) {
|
||||
delete this.elementToSelectAfterRefresh;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks if an element is currently selected.
|
||||
*
|
||||
* @returns {boolean} true if an element is selected.
|
||||
*/
|
||||
FixedController.prototype.isElementSelected = function () {
|
||||
return (this.selectedElementProxy) ? true : false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the style for the selected element.
|
||||
*
|
||||
* @returns {string} element style
|
||||
*/
|
||||
FixedController.prototype.getSelectedElementStyle = function () {
|
||||
return (this.selectedElementProxy) ? this.selectedElementProxy.style : undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the selected element.
|
||||
*
|
||||
* @returns the selected element
|
||||
*/
|
||||
FixedController.prototype.getSelectedElement = function () {
|
||||
return this.selectedElementProxy;
|
||||
};
|
||||
|
||||
/**
|
||||
* Prevents the event from bubbling up if drag is in progress.
|
||||
*/
|
||||
FixedController.prototype.bypassSelection = function ($event) {
|
||||
if (this.dragInProgress) {
|
||||
if ($event) {
|
||||
$event.stopPropagation();
|
||||
}
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get drag handles.
|
||||
* @returns {platform/features/layout.FixedDragHandle[]}
|
||||
* drag handles for the current selection
|
||||
*/
|
||||
FixedController.prototype.handles = function () {
|
||||
return this.resizeHandles;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the handle to handle dragging to reposition an element.
|
||||
* @returns {platform/features/layout.FixedDragHandle} the drag handle
|
||||
*/
|
||||
FixedController.prototype.moveHandle = function () {
|
||||
return this.mvHandle;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the selection context.
|
||||
*
|
||||
* @param elementProxy the element proxy
|
||||
* @returns {object} the context object which includes elementProxy
|
||||
*/
|
||||
FixedController.prototype.getContext = function (elementProxy) {
|
||||
return {
|
||||
elementProxy: elementProxy,
|
||||
fixedController: this
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* End drag.
|
||||
*
|
||||
* @param handle the resize handle
|
||||
*/
|
||||
FixedController.prototype.endDrag = function (handle) {
|
||||
this.dragInProgress = true;
|
||||
|
||||
setTimeout(function () {
|
||||
this.dragInProgress = false;
|
||||
}.bind(this), 0);
|
||||
|
||||
if (handle) {
|
||||
handle.endDrag();
|
||||
} else {
|
||||
this.moveHandle().endDrag();
|
||||
}
|
||||
};
|
||||
|
||||
FixedController.prototype.mutate = function (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;
|
||||
}
|
||||
);
|
110
platform/features/fixed/src/FixedDragHandle.js
Normal file
110
platform/features/fixed/src/FixedDragHandle.js
Normal file
@ -0,0 +1,110 @@
|
||||
/*****************************************************************************
|
||||
* 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 () {
|
||||
|
||||
// Drag handle dimensions
|
||||
var DRAG_HANDLE_SIZE = [6, 6];
|
||||
|
||||
/**
|
||||
* Template-displayable drag handle for an element in fixed
|
||||
* position mode.
|
||||
*
|
||||
* @param elementHandle the element handle
|
||||
* @param configPath the configuration path of an element
|
||||
* @param {Object} fixedControl the fixed controller
|
||||
* @memberof platform/features/layout
|
||||
* @constructor
|
||||
*/
|
||||
function FixedDragHandle(elementHandle, configPath, fixedControl) {
|
||||
this.elementHandle = elementHandle;
|
||||
this.configPath = configPath;
|
||||
this.fixedControl = fixedControl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a CSS style to position this drag handle.
|
||||
*
|
||||
* @returns CSS style object (for `ng-style`)
|
||||
* @memberof platform/features/layout.FixedDragHandle#
|
||||
*/
|
||||
FixedDragHandle.prototype.style = function () {
|
||||
var gridSize = this.elementHandle.getGridSize();
|
||||
|
||||
// Adjust from grid to pixel coordinates
|
||||
var x = this.elementHandle.x() * gridSize[0],
|
||||
y = this.elementHandle.y() * gridSize[1];
|
||||
|
||||
// Convert to a CSS style centered on that point
|
||||
return {
|
||||
left: (x - DRAG_HANDLE_SIZE[0] / 2) + 'px',
|
||||
top: (y - DRAG_HANDLE_SIZE[1] / 2) + 'px',
|
||||
width: DRAG_HANDLE_SIZE[0] + 'px',
|
||||
height: DRAG_HANDLE_SIZE[1] + 'px'
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Start a drag gesture. This should be called when a drag
|
||||
* begins to track initial state.
|
||||
*/
|
||||
FixedDragHandle.prototype.startDrag = function () {
|
||||
// Cache initial x/y positions
|
||||
this.dragging = {
|
||||
x: this.elementHandle.x(),
|
||||
y: this.elementHandle.y()
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Continue a drag gesture; update x/y positions.
|
||||
*
|
||||
* @param {number[]} delta x/y pixel difference since drag started
|
||||
*/
|
||||
FixedDragHandle.prototype.continueDrag = function (delta) {
|
||||
var gridSize = this.elementHandle.getGridSize();
|
||||
|
||||
if (this.dragging) {
|
||||
// Update x/y positions (snapping to grid)
|
||||
var newX = this.dragging.x + Math.round(delta[0] / gridSize[0]);
|
||||
var newY = this.dragging.y + Math.round(delta[1] / gridSize[1]);
|
||||
|
||||
this.elementHandle.x(Math.max(0, newX));
|
||||
this.elementHandle.y(Math.max(0, newY));
|
||||
this.fixedControl.updateSelectionStyle();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* End a drag gesture. This should be called when a drag
|
||||
* concludes to trigger commit of changes.
|
||||
*/
|
||||
FixedDragHandle.prototype.endDrag = function () {
|
||||
this.dragging = undefined;
|
||||
this.fixedControl.mutate(this.configPath, this.elementHandle.element);
|
||||
};
|
||||
|
||||
return FixedDragHandle;
|
||||
}
|
||||
);
|
76
platform/features/fixed/src/FixedProxy.js
Normal file
76
platform/features/fixed/src/FixedProxy.js
Normal file
@ -0,0 +1,76 @@
|
||||
/*****************************************************************************
|
||||
* 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(
|
||||
['./elements/ElementFactory'],
|
||||
function (ElementFactory) {
|
||||
|
||||
/**
|
||||
* Proxy for configuring a fixed position view via the toolbar.
|
||||
* @memberof platform/features/layout
|
||||
* @constructor
|
||||
* @param {Function} addElementCallback callback to invoke when
|
||||
* elements are created
|
||||
* @param $q Angular's $q, for promise-handling
|
||||
* @param {DialogService} dialogService dialog service to use
|
||||
* when adding a new element will require user input
|
||||
*/
|
||||
function FixedProxy(addElementCallback, $q, dialogService) {
|
||||
this.factory = new ElementFactory(dialogService);
|
||||
this.$q = $q;
|
||||
this.addElementCallback = addElementCallback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new visual element to this view. Supported types are:
|
||||
*
|
||||
* * `fixed.image`
|
||||
* * `fixed.box`
|
||||
* * `fixed.text`
|
||||
* * `fixed.line`
|
||||
*
|
||||
* @param {string} type the type of element to add
|
||||
*/
|
||||
FixedProxy.prototype.add = function (type) {
|
||||
var addElementCallback = this.addElementCallback;
|
||||
|
||||
// Place a configured element into the view configuration
|
||||
function addElement(element) {
|
||||
// Configure common properties of the element
|
||||
element.x = element.x || 0;
|
||||
element.y = element.y || 0;
|
||||
element.width = element.width || 1;
|
||||
element.height = element.height || 1;
|
||||
element.type = type;
|
||||
element.useGrid = true;
|
||||
|
||||
// Finally, add it to the view's configuration
|
||||
addElementCallback(element);
|
||||
}
|
||||
|
||||
// Defer creation to the factory
|
||||
this.$q.when(this.factory.createElement(type)).then(addElement);
|
||||
};
|
||||
|
||||
return FixedProxy;
|
||||
}
|
||||
);
|
115
platform/features/fixed/src/LayoutDrag.js
Normal file
115
platform/features/fixed/src/LayoutDrag.js
Normal file
@ -0,0 +1,115 @@
|
||||
/*****************************************************************************
|
||||
* 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 () {
|
||||
|
||||
/**
|
||||
* Handles drag interactions on frames in layouts. This will
|
||||
* provides new positions/dimensions for frames based on
|
||||
* relative pixel positions provided; these will take into account
|
||||
* the grid size (in a snap-to sense) and will enforce some minimums
|
||||
* on both position and dimensions.
|
||||
*
|
||||
* The provided position and dimensions factors will determine
|
||||
* whether this is a move or a resize, and what type of resize it
|
||||
* will be. For instance, a position factor of [1, 1]
|
||||
* will move a frame along with the mouse as the drag
|
||||
* proceeds, while a dimension factor of [0, 0] will leave
|
||||
* dimensions unchanged. Combining these in different
|
||||
* ways results in different handles; a position factor of
|
||||
* [1, 0] and a dimensions factor of [-1, 0] will implement
|
||||
* a left-edge resize, as the horizontal position will move
|
||||
* with the mouse while the horizontal dimensions shrink in
|
||||
* kind (and vertical properties remain unmodified.)
|
||||
*
|
||||
* @param {object} rawPosition the initial position/dimensions
|
||||
* of the frame being interacted with
|
||||
* @param {number[]} posFactor the position factor
|
||||
* @param {number[]} dimFactor the dimensions factor
|
||||
* @param {number[]} the size of each grid element, in pixels
|
||||
* @constructor
|
||||
* @memberof platform/features/layout
|
||||
*/
|
||||
function LayoutDrag(rawPosition, posFactor, dimFactor, gridSize) {
|
||||
this.rawPosition = rawPosition;
|
||||
this.posFactor = posFactor;
|
||||
this.dimFactor = dimFactor;
|
||||
this.gridSize = gridSize;
|
||||
}
|
||||
|
||||
// Convert a delta from pixel coordinates to grid coordinates,
|
||||
// rounding to whole-number grid coordinates.
|
||||
function toGridDelta(gridSize, pixelDelta) {
|
||||
return pixelDelta.map(function (v, i) {
|
||||
return Math.round(v / gridSize[i]);
|
||||
});
|
||||
}
|
||||
|
||||
// Utility function to perform element-by-element multiplication
|
||||
function multiply(array, factors) {
|
||||
return array.map(function (v, i) {
|
||||
return v * factors[i];
|
||||
});
|
||||
}
|
||||
|
||||
// Utility function to perform element-by-element addition
|
||||
function add(array, other) {
|
||||
return array.map(function (v, i) {
|
||||
return v + other[i];
|
||||
});
|
||||
}
|
||||
|
||||
// Utility function to perform element-by-element max-choosing
|
||||
function max(array, other) {
|
||||
return array.map(function (v, i) {
|
||||
return Math.max(v, other[i]);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a new position object in grid coordinates, with
|
||||
* position and dimensions both offset appropriately
|
||||
* according to the factors supplied in the constructor.
|
||||
* @param {number[]} pixelDelta the offset from the
|
||||
* original position, in pixels
|
||||
*/
|
||||
LayoutDrag.prototype.getAdjustedPosition = function (pixelDelta) {
|
||||
var gridDelta = toGridDelta(this.gridSize, pixelDelta);
|
||||
return {
|
||||
position: max(add(
|
||||
this.rawPosition.position,
|
||||
multiply(gridDelta, this.posFactor)
|
||||
), [0, 0]),
|
||||
dimensions: max(add(
|
||||
this.rawPosition.dimensions,
|
||||
multiply(gridDelta, this.dimFactor)
|
||||
), [1, 1])
|
||||
};
|
||||
};
|
||||
|
||||
return LayoutDrag;
|
||||
|
||||
}
|
||||
);
|
105
platform/features/fixed/src/MCTTriggerModal.js
Normal file
105
platform/features/fixed/src/MCTTriggerModal.js
Normal file
@ -0,0 +1,105 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2016, 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',
|
||||
'../../../commonUI/general/src/services/Overlay'
|
||||
], function (
|
||||
$,
|
||||
Overlay
|
||||
) {
|
||||
/**
|
||||
* MCT Trigger Modal is intended for use in only one location: inside the
|
||||
* object-header to allow views in a layout to be popped out in a modal.
|
||||
* Users can close the modal and go back to normal, and everything generally
|
||||
* just works fine.
|
||||
*
|
||||
* This code is sensitive to how our html is constructed-- particularly with
|
||||
* how it locates the the container of an element in a layout. However, it
|
||||
* should be able to handle slight relocations so long as it is always a
|
||||
* descendent of a `.frame` element.
|
||||
*/
|
||||
function MCTTriggerModal($document) {
|
||||
|
||||
function link($scope, $element) {
|
||||
var actions = $scope.domainObject.getCapability('action'),
|
||||
notebookAction = actions.getActions({key: 'notebook-new-entry'})[0];
|
||||
|
||||
var frame = $element.parent();
|
||||
|
||||
for (var i = 0; i < 10; i++) {
|
||||
if (frame.hasClass('frame')) {
|
||||
break;
|
||||
}
|
||||
frame = frame.parent();
|
||||
}
|
||||
if (!frame.hasClass('frame')) {
|
||||
$element.remove();
|
||||
return;
|
||||
}
|
||||
|
||||
frame = frame[0];
|
||||
|
||||
var layoutContainer = frame.parentElement;
|
||||
|
||||
var notebookButton = notebookAction ?
|
||||
[
|
||||
{
|
||||
class: 'icon-notebook new-notebook-entry',
|
||||
title: 'New Notebook Entry',
|
||||
clickHandler: function (event) {
|
||||
event.stopPropagation();
|
||||
notebookAction.perform();
|
||||
}
|
||||
}
|
||||
] : [];
|
||||
|
||||
var overlayService = new Overlay ({
|
||||
$document: $document,
|
||||
$scope: $scope,
|
||||
$element: frame,
|
||||
overlayWillMount: function () {
|
||||
$(frame).removeClass('frame frame-template');
|
||||
layoutContainer.removeChild(frame);
|
||||
},
|
||||
overlayDidUnmount: function () {
|
||||
$(frame).addClass('frame frame-template');
|
||||
layoutContainer.appendChild(frame);
|
||||
},
|
||||
browseBarButtons: notebookButton
|
||||
});
|
||||
|
||||
$element.on('click', overlayService.toggleOverlay);
|
||||
$scope.$on('$destroy', function () {
|
||||
$element.off('click', overlayService.toggleOverlay);
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
restrict: 'A',
|
||||
link: link
|
||||
};
|
||||
}
|
||||
|
||||
return MCTTriggerModal;
|
||||
|
||||
});
|
58
platform/features/fixed/src/elements/AccessorMutator.js
Normal file
58
platform/features/fixed/src/elements/AccessorMutator.js
Normal file
@ -0,0 +1,58 @@
|
||||
/*****************************************************************************
|
||||
* 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 () {
|
||||
|
||||
/**
|
||||
* Utility function for creating getter-setter functions,
|
||||
* since these are frequently useful for element proxies.
|
||||
*
|
||||
* An optional third argument may be supplied in order to
|
||||
* constrain or modify arguments when using as a setter;
|
||||
* this argument is a function which takes two arguments
|
||||
* (the current value for the property, and the requested
|
||||
* new value.) This is useful when values need to be kept
|
||||
* in certain ranges; specifically, to keep x/y positions
|
||||
* non-negative in a fixed position view.
|
||||
*
|
||||
* @memberof platform/features/layout
|
||||
* @constructor
|
||||
* @param {Object} object the object to get/set values upon
|
||||
* @param {string} key the property to get/set
|
||||
* @param {function} [updater] function used to process updates
|
||||
*/
|
||||
function AccessorMutator(object, key, updater) {
|
||||
return function (value) {
|
||||
if (arguments.length > 0) {
|
||||
object[key] = updater ?
|
||||
updater(value, object[key]) :
|
||||
value;
|
||||
}
|
||||
return object[key];
|
||||
};
|
||||
}
|
||||
|
||||
return AccessorMutator;
|
||||
}
|
||||
);
|
61
platform/features/fixed/src/elements/BoxProxy.js
Normal file
61
platform/features/fixed/src/elements/BoxProxy.js
Normal file
@ -0,0 +1,61 @@
|
||||
/*****************************************************************************
|
||||
* 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(
|
||||
['./ElementProxy', './AccessorMutator'],
|
||||
function (ElementProxy, AccessorMutator) {
|
||||
|
||||
/**
|
||||
* Selection proxy for Box elements in a fixed position view.
|
||||
* Also serves as a superclass for Text elements, since those
|
||||
* elements have a superset of Box properties.
|
||||
*
|
||||
* Note that arguments here are meant to match those expected
|
||||
* by `Array.prototype.map`
|
||||
*
|
||||
* @memberof platform/features/layout
|
||||
* @constructor
|
||||
* @param element the fixed position element, as stored in its
|
||||
* configuration
|
||||
* @param index the element's index within its array
|
||||
* @param {number[]} gridSize the current layout grid size in [x,y] from
|
||||
* @param {Array} elements the full array of elements
|
||||
*/
|
||||
function BoxProxy(element, index, elements, gridSize) {
|
||||
var proxy = new ElementProxy(element, index, elements, gridSize);
|
||||
|
||||
/**
|
||||
* Get/set this element's fill color. (Omitting the
|
||||
* argument makes this act as a getter.)
|
||||
* @method
|
||||
* @param {string} fill the new fill color
|
||||
* @returns {string} the fill color
|
||||
* @memberof platform/features/layout.BoxProxy#
|
||||
*/
|
||||
proxy.fill = new AccessorMutator(element, 'fill');
|
||||
|
||||
return proxy;
|
||||
}
|
||||
|
||||
return BoxProxy;
|
||||
}
|
||||
);
|
115
platform/features/fixed/src/elements/ElementFactory.js
Normal file
115
platform/features/fixed/src/elements/ElementFactory.js
Normal file
@ -0,0 +1,115 @@
|
||||
/*****************************************************************************
|
||||
* 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 () {
|
||||
|
||||
var INITIAL_STATES = {
|
||||
"fixed.image": {
|
||||
stroke: "transparent"
|
||||
},
|
||||
"fixed.box": {
|
||||
fill: "#717171",
|
||||
border: "transparent",
|
||||
stroke: "transparent"
|
||||
},
|
||||
"fixed.line": {
|
||||
x: 5,
|
||||
y: 9,
|
||||
x2: 6,
|
||||
y2: 6,
|
||||
stroke: "#717171"
|
||||
},
|
||||
"fixed.text": {
|
||||
fill: "transparent",
|
||||
stroke: "transparent",
|
||||
size: "13px"
|
||||
}
|
||||
},
|
||||
DIALOGS = {
|
||||
"fixed.image": {
|
||||
name: "Image Properties",
|
||||
sections: [
|
||||
{
|
||||
rows: [
|
||||
{
|
||||
key: "url",
|
||||
control: "textfield",
|
||||
name: "Image URL",
|
||||
"cssClass": "l-input-lg",
|
||||
required: true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"fixed.text": {
|
||||
name: "Text Element Properties",
|
||||
sections: [
|
||||
{
|
||||
rows: [
|
||||
{
|
||||
key: "text",
|
||||
control: "textfield",
|
||||
name: "Text",
|
||||
required: true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The ElementFactory creates new instances of elements for the
|
||||
* fixed position view, prompting for user input where necessary.
|
||||
* @param {DialogService} dialogService service to request user input
|
||||
* @memberof platform/features/layout
|
||||
* @constructor
|
||||
*/
|
||||
function ElementFactory(dialogService) {
|
||||
this.dialogService = dialogService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new element for the fixed position view.
|
||||
* @param {string} type the type of element to create
|
||||
* @returns {Promise|object} the created element, or a promise
|
||||
* for that element
|
||||
*/
|
||||
ElementFactory.prototype.createElement = function (type) {
|
||||
var initialState = INITIAL_STATES[type] || {};
|
||||
|
||||
// Clone that state
|
||||
initialState = JSON.parse(JSON.stringify(initialState));
|
||||
|
||||
// Show a dialog to configure initial state, if appropriate
|
||||
return DIALOGS[type] ? this.dialogService.getUserInput(
|
||||
DIALOGS[type],
|
||||
initialState
|
||||
) : initialState;
|
||||
};
|
||||
|
||||
return ElementFactory;
|
||||
}
|
||||
);
|
35
platform/features/fixed/src/elements/ElementProxies.js
Normal file
35
platform/features/fixed/src/elements/ElementProxies.js
Normal file
@ -0,0 +1,35 @@
|
||||
/*****************************************************************************
|
||||
* 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(
|
||||
['./TelemetryProxy', './ImageProxy', './LineProxy', './BoxProxy', './TextProxy'],
|
||||
function (TelemetryProxy, ImageProxy, LineProxy, BoxProxy, TextProxy) {
|
||||
|
||||
return {
|
||||
"fixed.telemetry": TelemetryProxy,
|
||||
"fixed.line": LineProxy,
|
||||
"fixed.box": BoxProxy,
|
||||
"fixed.image": ImageProxy,
|
||||
"fixed.text": TextProxy
|
||||
};
|
||||
}
|
||||
);
|
209
platform/features/fixed/src/elements/ElementProxy.js
Normal file
209
platform/features/fixed/src/elements/ElementProxy.js
Normal file
@ -0,0 +1,209 @@
|
||||
/*****************************************************************************
|
||||
* 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(
|
||||
['./AccessorMutator', './ResizeHandle', './UnitAccessorMutator'],
|
||||
function (AccessorMutator, ResizeHandle, UnitAccessorMutator) {
|
||||
|
||||
// Index deltas for changes in order
|
||||
var ORDERS = {
|
||||
top: Number.POSITIVE_INFINITY,
|
||||
up: 1,
|
||||
down: -1,
|
||||
bottom: Number.NEGATIVE_INFINITY
|
||||
};
|
||||
|
||||
// Mininmum pixel height and width for objects
|
||||
var MIN_WIDTH = 10;
|
||||
var MIN_HEIGHT = 10;
|
||||
|
||||
// Ensure a value is non-negative (for x/y setters)
|
||||
function clamp(value) {
|
||||
return Math.max(value, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstract superclass for other classes which provide useful
|
||||
* interfaces upon an elements in a fixed position view.
|
||||
* This handles the generic operations (e.g. remove) so that
|
||||
* subclasses only need to implement element-specific behaviors.
|
||||
*
|
||||
* Note that arguments here are meant to match those expected
|
||||
* by `Array.prototype.map`
|
||||
*
|
||||
* @memberof platform/features/layout
|
||||
* @constructor
|
||||
* @param element the fixed position element, as stored in its
|
||||
* configuration
|
||||
* @param index the element's index within its array
|
||||
* @param {Array} elements the full array of elements
|
||||
* @param {number[]} gridSize the current layout grid size in [x,y] from
|
||||
*/
|
||||
function ElementProxy(element, index, elements, gridSize) {
|
||||
/**
|
||||
* The element as stored in the view configuration.
|
||||
* @memberof platform/features/layout.ElementProxy#
|
||||
*/
|
||||
this.element = element;
|
||||
|
||||
/**
|
||||
* The current grid size of the layout.
|
||||
* @memberof platform/features/layout.ElementProxy#
|
||||
*/
|
||||
this.gridSize = gridSize || [1,1]; //Ensure a reasonable default
|
||||
|
||||
/**
|
||||
* Get and/or set the x position of this element.
|
||||
* Units are in fixed position grid space.
|
||||
* @param {number} [x] the new x position (if setting)
|
||||
* @returns {number} the x position
|
||||
* @memberof platform/features/layout.ElementProxy#
|
||||
*/
|
||||
this.x = new AccessorMutator(element, 'x', clamp);
|
||||
|
||||
/**
|
||||
* Get and/or set the y position of this element.
|
||||
* Units are in fixed position grid space.
|
||||
* @param {number} [y] the new y position (if setting)
|
||||
* @returns {number} the y position
|
||||
* @memberof platform/features/layout.ElementProxy#
|
||||
*/
|
||||
this.y = new AccessorMutator(element, 'y', clamp);
|
||||
|
||||
/**
|
||||
* Get and/or set the stroke color of this element.
|
||||
* @param {string} [stroke] the new stroke color (if setting)
|
||||
* @returns {string} the stroke color
|
||||
* @memberof platform/features/layout.ElementProxy#
|
||||
*/
|
||||
this.stroke = new AccessorMutator(element, 'stroke');
|
||||
|
||||
/**
|
||||
* Get and/or set the width of this element.
|
||||
* Units are in fixed position grid space.
|
||||
* @param {number} [w] the new width (if setting)
|
||||
* @returns {number} the width
|
||||
* @memberof platform/features/layout.ElementProxy#
|
||||
*/
|
||||
this.width = new AccessorMutator(element, 'width');
|
||||
|
||||
/**
|
||||
* Get and/or set the height of this element.
|
||||
* Units are in fixed position grid space.
|
||||
* @param {number} [h] the new height (if setting)
|
||||
* @returns {number} the height
|
||||
* @memberof platform/features/layout.ElementProxy#
|
||||
*/
|
||||
this.height = new AccessorMutator(element, 'height');
|
||||
|
||||
this.useGrid = new UnitAccessorMutator(this);
|
||||
this.index = index;
|
||||
this.elements = elements;
|
||||
this.resizeHandles = [new ResizeHandle(this, this.element)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the display order of this element.
|
||||
* @param {string} o where to move this element;
|
||||
* one of "top", "up", "down", or "bottom"
|
||||
* @return {Array} the full array of elements
|
||||
*/
|
||||
ElementProxy.prototype.order = function (o) {
|
||||
var index = this.index,
|
||||
elements = this.elements,
|
||||
element = this.element,
|
||||
delta = ORDERS[o] || 0,
|
||||
desired = Math.max(
|
||||
Math.min(index + delta, elements.length - 1),
|
||||
0
|
||||
);
|
||||
// Move to the desired index, if this is a change
|
||||
if ((desired !== index) && (elements[index] === element)) {
|
||||
// Splice out the current element
|
||||
elements.splice(index, 1);
|
||||
// Splice it back in at the correct index
|
||||
elements.splice(desired, 0, element);
|
||||
// Track change in index (proxy should be recreated
|
||||
// anyway, but be consistent)
|
||||
this.index = desired;
|
||||
}
|
||||
|
||||
return elements;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get handles to control specific features of this element,
|
||||
* e.g. corner size.
|
||||
* @return {platform/features/layout.ElementHandle[]} handles
|
||||
* for moving/resizing this element
|
||||
*/
|
||||
ElementProxy.prototype.handles = function () {
|
||||
return this.resizeHandles;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns which grid size the element is currently using.
|
||||
* @return {number[]} The current grid size in [x,y] form if the element
|
||||
* is currently using the grid, [1,1] if it is using
|
||||
* pixels.
|
||||
*/
|
||||
ElementProxy.prototype.getGridSize = function () {
|
||||
var gridSize;
|
||||
// Default to using the grid if useGrid was not defined
|
||||
if (typeof this.element.useGrid === 'undefined') {
|
||||
this.element.useGrid = true;
|
||||
}
|
||||
if (this.element.useGrid) {
|
||||
gridSize = this.gridSize;
|
||||
} else {
|
||||
gridSize = [1,1];
|
||||
}
|
||||
return gridSize;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the current grid size stored by this element proxy
|
||||
* @param {number[]} gridSize The current layout grid size in [x,y] form
|
||||
*/
|
||||
ElementProxy.prototype.setGridSize = function (gridSize) {
|
||||
this.gridSize = gridSize;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the current minimum element width in grid units
|
||||
* @return {number} The current minimum element width
|
||||
*/
|
||||
ElementProxy.prototype.getMinWidth = function () {
|
||||
return Math.ceil(MIN_WIDTH / this.getGridSize()[0]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the current minimum element height in grid units
|
||||
* @return {number} The current minimum element height
|
||||
*/
|
||||
ElementProxy.prototype.getMinHeight = function () {
|
||||
return Math.ceil(MIN_HEIGHT / this.getGridSize()[1]);
|
||||
};
|
||||
|
||||
return ElementProxy;
|
||||
}
|
||||
);
|
58
platform/features/fixed/src/elements/ImageProxy.js
Normal file
58
platform/features/fixed/src/elements/ImageProxy.js
Normal file
@ -0,0 +1,58 @@
|
||||
/*****************************************************************************
|
||||
* 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(
|
||||
['./ElementProxy', './AccessorMutator'],
|
||||
function (ElementProxy, AccessorMutator) {
|
||||
|
||||
/**
|
||||
* Selection proxy for Image elements in a fixed position view.
|
||||
*
|
||||
* Note that arguments here are meant to match those expected
|
||||
* by `Array.prototype.map`
|
||||
*
|
||||
* @memberof platform/features/layout
|
||||
* @constructor
|
||||
* @param element the fixed position element, as stored in its
|
||||
* configuration
|
||||
* @param index the element's index within its array
|
||||
* @param {Array} elements the full array of elements
|
||||
* @param {number[]} gridSize the current layout grid size in [x,y] from
|
||||
* @augments {platform/features/layout.ElementProxy}
|
||||
*/
|
||||
function ImageProxy(element, index, elements, gridSize) {
|
||||
var proxy = new ElementProxy(element, index, elements, gridSize);
|
||||
|
||||
/**
|
||||
* Get and/or set the displayed text of this element.
|
||||
* @param {string} [text] the new text (if setting)
|
||||
* @returns {string} the text
|
||||
* @memberof platform/features/layout.ImageProxy#
|
||||
*/
|
||||
proxy.url = new AccessorMutator(element, 'url');
|
||||
|
||||
return proxy;
|
||||
}
|
||||
|
||||
return ImageProxy;
|
||||
}
|
||||
);
|
94
platform/features/fixed/src/elements/LineHandle.js
Normal file
94
platform/features/fixed/src/elements/LineHandle.js
Normal file
@ -0,0 +1,94 @@
|
||||
/*****************************************************************************
|
||||
* 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 () {
|
||||
|
||||
/**
|
||||
* Handle for changing x/y position of a line's end point.
|
||||
* This is used to support drag handles for line elements
|
||||
* in a fixed position view. Field names for opposite ends
|
||||
* are provided to avoid zero-length lines.
|
||||
* @memberof platform/features/layout
|
||||
* @constructor
|
||||
* @param element the line element
|
||||
* @param {string} xProperty field which stores x position
|
||||
* @param {string} yProperty field which stores y position
|
||||
* @param {string} xOther field which stores x of other end
|
||||
* @param {string} yOther field which stores y of other end
|
||||
* @implements {platform/features/layout.ElementHandle}
|
||||
*/
|
||||
function LineHandle(element, elementProxy, xProperty, yProperty, xOther, yOther) {
|
||||
this.elementProxy = elementProxy;
|
||||
this.element = element;
|
||||
this.xProperty = xProperty;
|
||||
this.yProperty = yProperty;
|
||||
this.xOther = xOther;
|
||||
this.yOther = yOther;
|
||||
}
|
||||
|
||||
LineHandle.prototype.x = function (value) {
|
||||
var element = this.element,
|
||||
xProperty = this.xProperty,
|
||||
yProperty = this.yProperty,
|
||||
xOther = this.xOther,
|
||||
yOther = this.yOther;
|
||||
|
||||
if (arguments.length > 0) {
|
||||
// Ensure we stay in view
|
||||
value = Math.max(value, 0);
|
||||
// Make sure end points will still be different
|
||||
if (element[yOther] !== element[yProperty] ||
|
||||
element[xOther] !== value) {
|
||||
element[xProperty] = value;
|
||||
}
|
||||
}
|
||||
return element[xProperty];
|
||||
};
|
||||
|
||||
LineHandle.prototype.y = function (value) {
|
||||
var element = this.element,
|
||||
xProperty = this.xProperty,
|
||||
yProperty = this.yProperty,
|
||||
xOther = this.xOther,
|
||||
yOther = this.yOther;
|
||||
|
||||
if (arguments.length > 0) {
|
||||
// Ensure we stay in view
|
||||
value = Math.max(value, 0);
|
||||
// Make sure end points will still be different
|
||||
if (element[xOther] !== element[xProperty] ||
|
||||
element[yOther] !== value) {
|
||||
element[yProperty] = value;
|
||||
}
|
||||
}
|
||||
return element[yProperty];
|
||||
};
|
||||
|
||||
LineHandle.prototype.getGridSize = function () {
|
||||
return this.elementProxy.getGridSize();
|
||||
};
|
||||
|
||||
return LineHandle;
|
||||
|
||||
}
|
||||
);
|
171
platform/features/fixed/src/elements/LineProxy.js
Normal file
171
platform/features/fixed/src/elements/LineProxy.js
Normal file
@ -0,0 +1,171 @@
|
||||
/*****************************************************************************
|
||||
* 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(
|
||||
['./ElementProxy', './LineHandle', './AccessorMutator'],
|
||||
function (ElementProxy, LineHandle, AccessorMutator) {
|
||||
|
||||
/**
|
||||
* Selection/diplay proxy for line elements of a fixed position
|
||||
* view.
|
||||
* @memberof platform/features/layout
|
||||
* @constructor
|
||||
* @param element the fixed position element, as stored in its
|
||||
* configuration
|
||||
* @param index the element's index within its array
|
||||
* @param {Array} elements the full array of elements
|
||||
* @param {number[]} gridSize the current layout grid size in [x,y] from
|
||||
* @augments {platform/features/layout.ElementProxy}
|
||||
*/
|
||||
function LineProxy(element, index, elements, gridSize) {
|
||||
var proxy = new ElementProxy(element, index, elements, gridSize),
|
||||
handles = [
|
||||
new LineHandle(element, proxy, 'x', 'y', 'x2', 'y2'),
|
||||
new LineHandle(element, proxy, 'x2', 'y2', 'x', 'y')
|
||||
];
|
||||
|
||||
/**
|
||||
* Gets style specific to line proxy.
|
||||
*/
|
||||
proxy.getStyle = function () {
|
||||
var layoutGridSize = proxy.getGridSize();
|
||||
|
||||
return {
|
||||
left: (layoutGridSize[0] * proxy.x()) + 'px',
|
||||
top: (layoutGridSize[1] * proxy.y()) + 'px',
|
||||
width: (layoutGridSize[0] * proxy.width()) + 'px',
|
||||
height: (layoutGridSize[1] * proxy.height()) + 'px'
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the top-left x coordinate, in grid space, of
|
||||
* this line's bounding box.
|
||||
* @returns {number} the x coordinate
|
||||
* @memberof platform/features/layout.LineProxy#
|
||||
*/
|
||||
proxy.x = function (v) {
|
||||
var x = Math.min(element.x, element.x2),
|
||||
delta = Math.max(v, 0) - x;
|
||||
if (arguments.length > 0 && delta) {
|
||||
element.x += delta;
|
||||
element.x2 += delta;
|
||||
}
|
||||
return x;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the top-left y coordinate, in grid space, of
|
||||
* this line's bounding box.
|
||||
* @returns {number} the y coordinate
|
||||
* @memberof platform/features/layout.LineProxy#
|
||||
*/
|
||||
proxy.y = function (v) {
|
||||
var y = Math.min(element.y, element.y2),
|
||||
delta = Math.max(v, 0) - y;
|
||||
if (arguments.length > 0 && delta) {
|
||||
element.y += delta;
|
||||
element.y2 += delta;
|
||||
}
|
||||
return y;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the width, in grid space, of
|
||||
* this line's bounding box.
|
||||
* @returns {number} the width
|
||||
* @memberof platform/features/layout.LineProxy#
|
||||
*/
|
||||
proxy.width = function () {
|
||||
return Math.max(Math.abs(element.x - element.x2), 1);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the height, in grid space, of
|
||||
* this line's bounding box.
|
||||
* @returns {number} the height
|
||||
* @memberof platform/features/layout.LineProxy#
|
||||
*/
|
||||
proxy.height = function () {
|
||||
return Math.max(Math.abs(element.y - element.y2), 1);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the x position, in grid units relative to
|
||||
* the top-left corner, of the first point in this line
|
||||
* segment.
|
||||
* @returns {number} the x position of the first point
|
||||
* @memberof platform/features/layout.LineProxy#
|
||||
*/
|
||||
proxy.x1 = function () {
|
||||
return element.x - proxy.x();
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the y position, in grid units relative to
|
||||
* the top-left corner, of the first point in this line
|
||||
* segment.
|
||||
* @returns {number} the y position of the first point
|
||||
* @memberof platform/features/layout.LineProxy#
|
||||
*/
|
||||
proxy.y1 = function () {
|
||||
return element.y - proxy.y();
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the x position, in grid units relative to
|
||||
* the top-left corner, of the second point in this line
|
||||
* segment.
|
||||
* @returns {number} the x position of the second point
|
||||
* @memberof platform/features/layout.LineProxy#
|
||||
*/
|
||||
proxy.x2 = function () {
|
||||
return element.x2 - proxy.x();
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the y position, in grid units relative to
|
||||
* the top-left corner, of the second point in this line
|
||||
* segment.
|
||||
* @returns {number} the y position of the second point
|
||||
* @memberof platform/features/layout.LineProxy#
|
||||
*/
|
||||
proxy.y2 = function () {
|
||||
return element.y2 - proxy.y();
|
||||
};
|
||||
|
||||
/**
|
||||
* Get element handles for changing the position of end
|
||||
* points of this line.
|
||||
* @returns {LineHandle[]} line handles for both end points
|
||||
* @memberof platform/features/layout.LineProxy#
|
||||
*/
|
||||
proxy.handles = function () {
|
||||
return handles;
|
||||
};
|
||||
|
||||
return proxy;
|
||||
}
|
||||
|
||||
return LineProxy;
|
||||
}
|
||||
);
|
72
platform/features/fixed/src/elements/ResizeHandle.js
Normal file
72
platform/features/fixed/src/elements/ResizeHandle.js
Normal file
@ -0,0 +1,72 @@
|
||||
/*****************************************************************************
|
||||
* 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 () {
|
||||
|
||||
/**
|
||||
* @interface platform/features/layout.ElementHandle
|
||||
* @private
|
||||
*/
|
||||
|
||||
/**
|
||||
* Handle for changing width/height properties of an element.
|
||||
* This is used to support drag handles for different
|
||||
* element types in a fixed position view.
|
||||
* @memberof platform/features/layout
|
||||
* @constructor
|
||||
*/
|
||||
function ResizeHandle(elementProxy, element) {
|
||||
this.elementProxy = elementProxy;
|
||||
this.element = element;
|
||||
}
|
||||
|
||||
ResizeHandle.prototype.x = function (value) {
|
||||
var element = this.element;
|
||||
if (arguments.length > 0) {
|
||||
element.width = Math.max(
|
||||
this.elementProxy.getMinWidth(),
|
||||
value - element.x
|
||||
);
|
||||
}
|
||||
return element.x + element.width;
|
||||
};
|
||||
|
||||
ResizeHandle.prototype.y = function (value) {
|
||||
var element = this.element;
|
||||
if (arguments.length > 0) {
|
||||
element.height = Math.max(
|
||||
this.elementProxy.getMinHeight(),
|
||||
value - element.y
|
||||
);
|
||||
}
|
||||
return element.y + element.height;
|
||||
};
|
||||
|
||||
ResizeHandle.prototype.getGridSize = function () {
|
||||
return this.elementProxy.getGridSize();
|
||||
};
|
||||
|
||||
return ResizeHandle;
|
||||
|
||||
}
|
||||
);
|
@ -20,34 +20,37 @@
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
import Migrations from './Migrations.js'
|
||||
define(
|
||||
['./TextProxy'],
|
||||
function (TextProxy) {
|
||||
|
||||
export default function () {
|
||||
return function (openmct) {
|
||||
let migrations = Migrations(openmct);
|
||||
/**
|
||||
* Selection proxy for telemetry elements in a fixed position view.
|
||||
*
|
||||
* Note that arguments here are meant to match those expected
|
||||
* by `Array.prototype.map`
|
||||
*
|
||||
* @memberof platform/features/layout
|
||||
* @constructor
|
||||
* @param element the fixed position element, as stored in its
|
||||
* configuration
|
||||
* @param index the element's index within its array
|
||||
* @param {Array} elements the full array of elements
|
||||
* @param {number[]} gridSize the current layout grid size in [x,y] form
|
||||
* @augments {platform/features/layout.ElementProxy}
|
||||
*/
|
||||
function TelemetryProxy(element, index, elements, gridSize) {
|
||||
var proxy = new TextProxy(element, index, elements, gridSize);
|
||||
|
||||
function needsMigration(domainObject) {
|
||||
return migrations.some(m => m.check(domainObject));
|
||||
// Expose the domain object identifier
|
||||
proxy.id = element.id;
|
||||
|
||||
// Don't expose text configuration
|
||||
delete proxy.text;
|
||||
|
||||
return proxy;
|
||||
}
|
||||
|
||||
function migrateObject(domainObject) {
|
||||
return migrations.filter(m => m.check(domainObject))[0]
|
||||
.migrate(domainObject);
|
||||
}
|
||||
|
||||
let wrappedFunction = openmct.objects.get;
|
||||
openmct.objects.get = function migrate(identifier) {
|
||||
return wrappedFunction.apply(openmct.objects, [identifier])
|
||||
.then(function (object) {
|
||||
if (needsMigration(object)) {
|
||||
migrateObject(object)
|
||||
.then(newObject => {
|
||||
openmct.objects.mutate(newObject, 'persisted', Date.now());
|
||||
return newObject;
|
||||
});
|
||||
}
|
||||
return object;
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
return TelemetryProxy;
|
||||
}
|
||||
);
|
75
platform/features/fixed/src/elements/TextProxy.js
Normal file
75
platform/features/fixed/src/elements/TextProxy.js
Normal file
@ -0,0 +1,75 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2018, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define(
|
||||
['./BoxProxy', './AccessorMutator'],
|
||||
function (BoxProxy, AccessorMutator) {
|
||||
|
||||
/**
|
||||
* Selection proxy for Text elements in a fixed position view.
|
||||
*
|
||||
* Note that arguments here are meant to match those expected
|
||||
* by `Array.prototype.map`
|
||||
*
|
||||
* @memberof platform/features/layout
|
||||
* @constructor
|
||||
* @param element the fixed position element, as stored in its
|
||||
* configuration
|
||||
* @param index the element's index within its array
|
||||
* @param {Array} elements the full array of elements
|
||||
* @param {number[]} gridSize the current layout grid size in [x,y] from
|
||||
* @augments {platform/features/layout.ElementProxy}
|
||||
*/
|
||||
function TextProxy(element, index, elements, gridSize) {
|
||||
var proxy = new BoxProxy(element, index, elements, gridSize);
|
||||
|
||||
/**
|
||||
* Get and/or set the text color of this element.
|
||||
* @param {string} [color] the new text color (if setting)
|
||||
* @returns {string} the text color
|
||||
* @memberof platform/features/layout.TextProxy#
|
||||
*/
|
||||
proxy.color = new AccessorMutator(element, 'color');
|
||||
|
||||
/**
|
||||
* Get and/or set the displayed text of this element.
|
||||
* @param {string} [text] the new text (if setting)
|
||||
* @returns {string} the text
|
||||
* @memberof platform/features/layout.TextProxy#
|
||||
*/
|
||||
proxy.text = new AccessorMutator(element, 'text');
|
||||
|
||||
/**
|
||||
* Get and/or set the text size of this element.
|
||||
*
|
||||
* @param {string} [size] the new text size (if setting)
|
||||
* @returns {string} the text size
|
||||
* @memberof platform/features/layout.TextProxy#
|
||||
*/
|
||||
proxy.size = new AccessorMutator(element, 'size');
|
||||
|
||||
return proxy;
|
||||
}
|
||||
|
||||
return TextProxy;
|
||||
}
|
||||
);
|
92
platform/features/fixed/src/elements/UnitAccessorMutator.js
Normal file
92
platform/features/fixed/src/elements/UnitAccessorMutator.js
Normal file
@ -0,0 +1,92 @@
|
||||
/*****************************************************************************
|
||||
* 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 () {
|
||||
|
||||
/**
|
||||
* Variant of AccessorMutator to handle the specific case of updating
|
||||
* useGrid, in order update the positions appropriately from within
|
||||
* the scope of UnitAccessorMutator
|
||||
*
|
||||
* @memberof platform/features/layout
|
||||
* @constructor
|
||||
* @param {ElementProxy} proxy ElementProxy object to perform the update
|
||||
* upon
|
||||
*/
|
||||
function UnitAccessorMutator(elementProxy) {
|
||||
var self = this;
|
||||
|
||||
this.elementProxy = elementProxy;
|
||||
return function (useGrid) {
|
||||
var current = elementProxy.element.useGrid;
|
||||
if (arguments.length > 0) {
|
||||
elementProxy.element.useGrid = useGrid;
|
||||
if (useGrid && !current) {
|
||||
self.convertCoordsTo('grid');
|
||||
} else if (!useGrid && current) {
|
||||
self.convertCoordsTo('px');
|
||||
}
|
||||
}
|
||||
|
||||
return elementProxy.element.useGrid;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* For the elementProxy object called upon, convert its element's
|
||||
* coordinates and size from pixels to grid units, or vice-versa.
|
||||
* @param {string} unit When called with 'px', converts grid units to
|
||||
* pixels; when called with 'grid', snaps element
|
||||
* to grid units
|
||||
*/
|
||||
UnitAccessorMutator.prototype.convertCoordsTo = function (unit) {
|
||||
var proxy = this.elementProxy,
|
||||
gridSize = proxy.gridSize,
|
||||
element = proxy.element,
|
||||
minWidth = proxy.getMinWidth(),
|
||||
minHeight = proxy.getMinHeight();
|
||||
if (unit === 'px') {
|
||||
element.x = element.x * gridSize[0];
|
||||
element.y = element.y * gridSize[1];
|
||||
element.width = element.width * gridSize[0];
|
||||
element.height = element.height * gridSize[1];
|
||||
if (element.x2 && element.y2) {
|
||||
element.x2 = element.x2 * gridSize[0];
|
||||
element.y2 = element.y2 * gridSize[1];
|
||||
}
|
||||
} else if (unit === 'grid') {
|
||||
element.x = Math.round(element.x / gridSize[0]);
|
||||
element.y = Math.round(element.y / gridSize[1]);
|
||||
element.width = Math.max(Math.round(element.width / gridSize[0]), minWidth);
|
||||
element.height = Math.max(Math.round(element.height / gridSize[1]), minHeight);
|
||||
if (element.x2 && element.y2) {
|
||||
element.x2 = Math.round(element.x2 / gridSize[0]);
|
||||
element.y2 = Math.round(element.y2 / gridSize[1]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return UnitAccessorMutator;
|
||||
}
|
||||
);
|
26
platform/features/fixed/templates/elements/box.html
Normal file
26
platform/features/fixed/templates/elements/box.html
Normal file
@ -0,0 +1,26 @@
|
||||
<!--
|
||||
Open MCT, Copyright (c) 2014-2018, United States Government
|
||||
as represented by the Administrator of the National Aeronautics and Space
|
||||
Administration. All rights reserved.
|
||||
|
||||
Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0.
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
License for the specific language governing permissions and limitations
|
||||
under the License.
|
||||
|
||||
Open MCT includes source code licensed under additional open source
|
||||
licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
this source code distribution or the Licensing information page available
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
<div
|
||||
class="l-fixed-position-box"
|
||||
ng-style="{ background: ngModel.fill(), border: '1px ' + ngModel.stroke() + ' solid' }"
|
||||
>
|
||||
</div>
|
26
platform/features/fixed/templates/elements/image.html
Normal file
26
platform/features/fixed/templates/elements/image.html
Normal file
@ -0,0 +1,26 @@
|
||||
<!--
|
||||
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-style="{ 'background-image': 'url(' + ngModel.element.url + ')', border: '1px solid ' + ngModel.stroke() }"
|
||||
class="l-fixed-position-image"
|
||||
>
|
||||
</div>
|
31
platform/features/fixed/templates/elements/line.html
Normal file
31
platform/features/fixed/templates/elements/line.html
Normal file
@ -0,0 +1,31 @@
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<svg ng-attr-width="{{ngModel.getGridSize()[0] * ngModel.width()}}"
|
||||
ng-attr-height="{{ngModel.getGridSize()[1] * ngModel.height()}}">
|
||||
<line ng-attr-x1="{{ngModel.getGridSize()[0] * ngModel.x1() + 1}}"
|
||||
ng-attr-y1="{{ngModel.getGridSize()[1] * ngModel.y1() + 1}}"
|
||||
ng-attr-x2="{{ngModel.getGridSize()[0] * ngModel.x2() + 1}}"
|
||||
ng-attr-y2="{{ngModel.getGridSize()[1] * ngModel.y2() + 1}}"
|
||||
ng-attr-stroke="{{ngModel.stroke()}}"
|
||||
stroke-width="2">
|
||||
</line>
|
||||
</svg>
|
After Width: | Height: | Size: 1.5 KiB |
39
platform/features/fixed/templates/elements/telemetry.html
Normal file
39
platform/features/fixed/templates/elements/telemetry.html
Normal file
@ -0,0 +1,39 @@
|
||||
<!--
|
||||
Open MCT, Copyright (c) 2014-2018, United States Government
|
||||
as represented by the Administrator of the National Aeronautics and Space
|
||||
Administration. All rights reserved.
|
||||
|
||||
Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0.
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
License for the specific language governing permissions and limitations
|
||||
under the License.
|
||||
|
||||
Open MCT includes source code licensed under additional open source
|
||||
licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
this source code distribution or the Licensing information page available
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
<div
|
||||
class="l-fixed-position-text l-telemetry"
|
||||
ng-style="{ background: ngModel.fill(), 'border-color': ngModel.stroke(), color: ngModel.color(), 'font-size': ngModel.size() }"
|
||||
>
|
||||
<span
|
||||
class="l-elem l-value l-obj-val-format"
|
||||
data-value="{{ngModel.value}}"
|
||||
ng-class="ngModel.cssClass"
|
||||
>
|
||||
{{ngModel.value}}
|
||||
</span>
|
||||
<span
|
||||
class="l-elem l-title"
|
||||
ng-show="ngModel.element.titled"
|
||||
>
|
||||
{{ngModel.name}}
|
||||
</span>
|
||||
</div>
|
27
platform/features/fixed/templates/elements/text.html
Normal file
27
platform/features/fixed/templates/elements/text.html
Normal file
@ -0,0 +1,27 @@
|
||||
<!--
|
||||
Open MCT, Copyright (c) 2014-2018, United States Government
|
||||
as represented by the Administrator of the National Aeronautics and Space
|
||||
Administration. All rights reserved.
|
||||
|
||||
Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0.
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
License for the specific language governing permissions and limitations
|
||||
under the License.
|
||||
|
||||
Open MCT includes source code licensed under additional open source
|
||||
licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
this source code distribution or the Licensing information page available
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
<div
|
||||
class="l-fixed-position-text l-static-text"
|
||||
ng-style="{ background: ngModel.fill(), 'border-color': ngModel.stroke(), color: ngModel.color(), 'font-size': ngModel.size() }"
|
||||
>
|
||||
{{ngModel.element.text}}
|
||||
</div>
|
62
platform/features/fixed/templates/fixed.html
Normal file
62
platform/features/fixed/templates/fixed.html
Normal file
@ -0,0 +1,62 @@
|
||||
<!--
|
||||
Open MCT, Copyright (c) 2014-2018, United States Government
|
||||
as represented by the Administrator of the National Aeronautics and Space
|
||||
Administration. All rights reserved.
|
||||
|
||||
Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0.
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
License for the specific language governing permissions and limitations
|
||||
under the License.
|
||||
|
||||
Open MCT includes source code licensed under additional open source
|
||||
licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
this source code distribution or the Licensing information page available
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
<div class="t-fixed-position l-fixed-position"
|
||||
ng-controller="FixedController as controller">
|
||||
|
||||
<!-- Background grid -->
|
||||
<div class="l-fixed-position__grid-holder l-grid-holder c-grid" ng-click="controller.bypassSelection($event)">
|
||||
<div class="c-grid__x l-grid l-grid-x"
|
||||
ng-if="!controller.getGridSize()[0] < 3"
|
||||
ng-style="{ 'background-size': controller.getGridSize() [0] + 'px 100%' }"></div>
|
||||
<div class="c-grid__y l-grid l-grid-y"
|
||||
ng-if="!controller.getGridSize()[1] < 3"
|
||||
ng-style="{ 'background-size': '100% ' + controller.getGridSize() [1] + 'px' }"></div>
|
||||
</div>
|
||||
|
||||
<!-- Fixed position elements -->
|
||||
<div ng-repeat="element in controller.getElements()"
|
||||
class="l-fixed-position-item s-selectable s-moveable is-selectable is-moveable"
|
||||
ng-style="element.style"
|
||||
mct-selectable="controller.getContext(element)"
|
||||
mct-init-select="controller.shouldSelect(element)">
|
||||
<mct-include key="element.template"
|
||||
parameters="{ gridSize: controller.getGridSize() }"
|
||||
ng-model="element">
|
||||
</mct-include>
|
||||
</div>
|
||||
<!-- Selection highlight, handles -->
|
||||
<span class="c-frame-edit" ng-if="controller.isElementSelected()">
|
||||
<div class="c-frame-edit__move"
|
||||
mct-drag-down="controller.moveHandle().startDrag()"
|
||||
mct-drag="controller.moveHandle().continueDrag(delta)"
|
||||
mct-drag-up="controller.endDrag()"
|
||||
ng-style="controller.getSelectedElementStyle()">
|
||||
</div>
|
||||
<div ng-repeat="handle in controller.handles()"
|
||||
class="c-frame-edit__handle c-frame-edit__handle--nwse"
|
||||
ng-style="handle.style()"
|
||||
mct-drag-down="handle.startDrag()"
|
||||
mct-drag="handle.continueDrag(delta)"
|
||||
mct-drag-up="controller.endDrag(handle)">
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
49
platform/features/fixed/templates/frame.html
Normal file
49
platform/features/fixed/templates/frame.html
Normal file
@ -0,0 +1,49 @@
|
||||
<!--
|
||||
Open MCT, Copyright (c) 2014-2018, United States Government
|
||||
as represented by the Administrator of the National Aeronautics and Space
|
||||
Administration. All rights reserved.
|
||||
|
||||
Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0.
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
License for the specific language governing permissions and limitations
|
||||
under the License.
|
||||
|
||||
Open MCT includes source code licensed under additional open source
|
||||
licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
this source code distribution or the Licensing information page available
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
<div class="frame frame-template t-frame-inner abs has-local-controls t-object-type-{{ domainObject.getModel().type }}">
|
||||
<div class="abs object-browse-bar l-flex-row">
|
||||
<div class="left flex-elem l-flex-row grows">
|
||||
<mct-representation
|
||||
key="'object-header-frame'"
|
||||
mct-object="domainObject"
|
||||
class="l-flex-row flex-elem object-header grows">
|
||||
</mct-representation>
|
||||
</div>
|
||||
<div class="btn-bar right l-flex-row flex-elem flex-justify-end flex-fixed h-local-controls local-controls-hidden">
|
||||
<mct-representation
|
||||
key="'switcher'"
|
||||
ng-model="representation"
|
||||
mct-object="domainObject">
|
||||
</mct-representation>
|
||||
<a class="s-button icon-expand t-btn-view-large"
|
||||
title="View large"
|
||||
mct-trigger-modal>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="abs object-holder">
|
||||
<mct-representation
|
||||
key="representation.selected.key"
|
||||
mct-object="representation.selected.key && domainObject">
|
||||
</mct-representation>
|
||||
</div>
|
||||
</div>
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user