Compare commits

..

2 Commits

Author SHA1 Message Date
Deep Tailor
1dbcdb618b add dynamic bars according to numnber of telemetry sources 2018-06-19 14:32:18 -07:00
Deep Tailor
dabe4e700c register BarGraph plugin plus working view 2018-06-12 13:44:05 -07:00
1015 changed files with 37924 additions and 32501 deletions

View File

@@ -1,36 +0,0 @@
version: 2
jobs:
build:
docker:
- image: circleci/node:8-browsers
environment:
CHROME_BIN: "/usr/bin/google-chrome"
steps:
- checkout
- run:
name: Update npm
command: 'sudo npm install -g npm@latest'
- restore_cache:
key: dependency-cache-{{ checksum "package.json" }}
- run:
name: Installing dependencies (npm install)
command: npm install
- save_cache:
key: dependency-cache-{{ checksum "package.json" }}
paths:
- node_modules
- run:
name: npm run test
command: npm run test
- run:
name: npm run lint
command: npm run lint
- store_artifacts:
path: dist
prefix: dist
workflows:
version: 2
test:
jobs:
- build

View File

@@ -1,79 +0,0 @@
module.exports = {
"env": {
"browser": true,
"es6": true,
"jasmine": true,
"amd": true
},
"extends": "eslint:recommended",
"parser": "babel-eslint",
"parserOptions": {
"allowImportExportEverywhere": true,
"ecmaVersion": 2015,
"ecmaFeatures": {
"impliedStrict": true
}
},
"rules": {
"no-bitwise": "error",
"curly": "error",
"eqeqeq": "error",
"guard-for-in": "error",
"no-extend-native": "error",
"no-inner-declarations": "off",
"no-use-before-define": ["error", "nofunc"],
"no-caller": "error",
"no-sequences": "error",
"no-irregular-whitespace": "error",
"no-new": "error",
"no-shadow": "error",
"no-undef": "error",
"no-unused-vars": [
"error",
{
"vars": "all",
"args": "none"
}
],
"no-console": "off",
"no-trailing-spaces": "error",
"space-before-function-paren": [
"error",
{
"anonymous": "always",
"asyncArrow": "always",
"named": "never",
}
],
"array-bracket-spacing": "error",
"space-in-parens": "error",
"space-before-blocks": "error",
"comma-dangle": "error",
"eol-last": "error",
"new-cap": [
"error",
{
"capIsNew": false,
"properties": false
}
],
"dot-notation": "error",
"indent": ["error", 4]
},
"overrides": [
{
"files": ["*Spec.js"],
"rules": {
"no-unused-vars": [
"warn",
{
"vars": "all",
"args": "none",
"varsIgnorePattern": "controller",
}
]
}
}
]
};

5
.jscsrc Normal file
View File

@@ -0,0 +1,5 @@
{
"preset": "crockford",
"requireMultipleVarDecl": false,
"requireVarDeclFirst": false
}

26
.jshintrc Normal file
View File

@@ -0,0 +1,26 @@
{
"bitwise": true,
"browser": true,
"curly": true,
"eqeqeq": true,
"forin": true,
"freeze": true,
"funcscope": false,
"futurehostile": true,
"latedef": true,
"noarg": true,
"nocomma": true,
"nonbsp": true,
"nonew": true,
"predef": [
"define",
"Promise",
"WeakMap",
"Map"
],
"shadow": "outer",
"strict": "implied",
"undef": true,
"unused": "vars",
"latedef": "nofunc"
}

88
API.md
View File

@@ -37,7 +37,7 @@
- [Time Systems and Bounds](#time-systems-and-bounds)
- [Defining and Registering Time Systems](#defining-and-registering-time-systems)
- [Getting and Setting the Active Time System](#getting-and-setting-the-active-time-system)
- [Time Bounds](#time-bounds)
- [Time Bounds](#time-bounds)
- [Clocks](#clocks)
- [Defining and registering clocks](#defining-and-registering-clocks)
- [Getting and setting active clock](#getting-and-setting-active-clock)
@@ -48,10 +48,6 @@
- [The Time Conductor](#the-time-conductor)
- [Time Conductor Configuration](#time-conductor-configuration)
- [Example conductor configuration](#example-conductor-configuration)
- [Indicators](#indicators)
- [The URL Status Indicator](#the-url-status-indicator)
- [Creating a Simple Indicator](#creating-a-simple-indicator)
- [Custom Indicators](#custom-indicators)
- [Included Plugins](#included-plugins)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
@@ -692,7 +688,7 @@ openmct.time.timeSystem(utcTimeSystem, bounds);
Setting the active time system will trigger a [`'timeSystem'`](#time-events)
event. If you supplied bounds, a [`'bounds'`](#time-events) event will be triggered afterwards with your newly supplied bounds.
#### Time Bounds
### Time Bounds
The TimeAPI provides a getter/setter for querying and setting time bounds. Time
bounds are simply an object with a `start` and an end `end` attribute.
@@ -981,72 +977,6 @@ openmct.install(openmct.plugins.Conductor({
}));
```
## Indicators
Indicators are small widgets that reside at the bottom of the screen and are visible from
every screen in Open MCT. They can be used to convey system state using an icon and text.
Typically an indicator will display an icon (customizable with a CSS class) that will
reveal additional information when the mouse cursor is hovered over it.
### The URL Status Indicator
A common use case for indicators is to convey the state of some external system such as a
persistence backend or HTTP server. So long as this system is accessible via HTTP request,
Open MCT provides a general purpose indicator to show whether the server is available and
returing a 2xx status code. The URL Status Indicator is made available as a default plugin. See
[Included Plugins](#included-plugins) below for details on how to install and configure the
URL Status Indicator.
### Creating a Simple Indicator
A simple indicator with an icon and some text can be created and added with minimal code. An indicator
of this type exposes functions for customizing the text, icon, and style of the indicator.
eg.
``` javascript
var myIndicator = openmct.indicators.simpleIndicator();
myIndicator.text("Hello World!");
openmct.indicators.add(myIndicator);
```
This will create a new indicator and add it to the bottom of the screen in Open MCT.
By default, the indicator will appear as an information icon. Hovering over the icon will
reveal the text set via the call to `.text()`. The Indicator object returned by the API
call exposes a number of functions for customizing the content and appearance of the indicator:
* `.text([text])`: Gets or sets the text shown when the user hovers over the indicator.
Accepts an __optional__ `string` argument that, if provided, will be used to set the text.
Hovering over the indicator will expand it to its full size, revealing this text alongside
the icon. Returns the currently set text as a `string`.
* `.description([description])`: Gets or sets the indicator's description. Accepts an
__optional__ `string` argument that, if provided, will be used to set the text. The description
allows for more detail to be provided in a tooltip when the user hovers over the indicator.
Returns the currently set text as a `string`.
* `.iconClass([className])`: Gets or sets the CSS class used to define the icon. Accepts an __optional__
`string` parameter to be used to set the class applied to the indicator. Any of
[the built-in glyphs](https://nasa.github.io/openmct/style-guide/#/browse/styleguide:home/glyphs?view=styleguide.glyphs)
may be used here, or a custom CSS class can be provided. Returns the currently defined CSS
class as a `string`.
* `.statusClass([className])`: Gets or sets the CSS class used to determine status. Accepts an __optional __
`string` parameter to be used to set a status class applied to the indicator. May be used to apply
different colors to indicate status.
### Custom Indicators
A completely custom indicator can be added by simple providing a DOM element to place alongside other indicators.
``` javascript
var domNode = document.createElement('div');
domNode.innerText = new Date().toString();
setInterval(function () {
domNode.innerText = new Date().toString();
}, 1000);
openmct.indicators.add({
element: domNode
});
```
## Included Plugins
Open MCT is packaged along with a few general-purpose plugins:
@@ -1070,18 +1000,18 @@ openmct.install(openmct.plugins.CouchDB('http://localhost:9200'))
* `openmct.plugins.Espresso` and `openmct.plugins.Snow` are two different
themes (dark and light) available for Open MCT. Note that at least one
of these themes must be installed for Open MCT to appear correctly.
* `openmct.plugins.URLIndicator` adds an indicator which shows the
* `openmct.plugins.URLIndicatorPlugin` adds an indicator which shows the
availability of a URL with the following options:
- `url` : URL to indicate the status of
- `iconClass`: Icon to show in the status bar, defaults to `icon-database`, [list of all icons](https://nasa.github.io/openmct/style-guide/#/browse/styleguide:home?view=items)
- `cssClass`: Icon to show in the status bar, defaults to `icon-database`, [list of all icons](https://nasa.github.io/openmct/style-guide/#/browse/styleguide:home?view=items)
- `interval`: Interval between checking the connection, defaults to `10000`
- `label` Name showing up as text in the status bar, defaults to url
```javascript
openmct.install(openmct.plugins.URLIndicator({
url: 'http://localhost:8080',
iconClass: 'check',
interval: 10000,
label: 'Localhost'
openmct.install(openmct.plugins.URLIndicatorPlugin({
url: 'http://google.com',
cssClass: 'check',
interval: 10000,
label: 'Google'
})
);
```

View File

@@ -84,6 +84,7 @@ Documentation will be generated in `target/docs`.
## Deploying Open MCT
Open MCT is built using [`npm`](http://npmjs.com/)
and [`gulp`](http://gulpjs.com/).
To build Open MCT for deployment:
@@ -93,13 +94,32 @@ This will compile and minify JavaScript sources, as well as copy over assets.
The contents of the `dist` folder will contain a runnable Open MCT
instance (e.g. by starting an HTTP server in that directory), including:
* `openmct.js` - Open MCT source code.
* `openmct.css` - Basic styles to load to prevent a FOUC.
* `index.html`, an example to run Open MCT in the basic configuration.
* A `main.js` file containing Open MCT source code.
* Various assets in the `example` and `platform` directories.
* An `index.html` that runs Open MCT in its default configuration.
Additional `gulp` tasks are defined in [the gulpfile](gulpfile.js).
## Bundles
A bundle is a group of software components (including source code, declared
as AMD modules, as well as resources such as images and HTML templates)
that is intended to be added or removed as a single unit. A plug-in for
Open MCT will be expressed as a bundle; platform components are also
expressed as bundles.
A bundle is also just a directory which contains a file `bundle.json`,
which declares its contents.
The file `bundles.json` (note the plural), at the top level of the
repository, is a JSON file containing an array of all bundles (expressed as
directory names) to include in a running instance of Open MCT. Adding or
removing paths from this list will add or remove bundles from the running
application.
## Tests
Tests are written for [Jasmine 3](http://jasmine.github.io/)
Tests are written for [Jasmine 1.3](http://jasmine.github.io/1.3/introduction.html)
and run by [Karma](http://karma-runner.github.io). To run:
`npm test`

128
app.js
View File

@@ -7,72 +7,78 @@
* node app.js [options]
*/
(function () {
"use strict";
const options = require('minimist')(process.argv.slice(2));
const express = require('express');
const app = express();
const fs = require('fs');
const request = require('request');
var BUNDLE_FILE = 'bundles.json',
options = require('minimist')(process.argv.slice(2)),
express = require('express'),
app = express(),
fs = require('fs'),
request = require('request');
// Defaults
options.port = options.port || options.p || 8080;
options.host = options.host || options.h || 'localhost';
options.directory = options.directory || options.D || '.';
// Defaults
options.port = options.port || options.p || 8080;
options.directory = options.directory || options.D || '.';
['include', 'exclude', 'i', 'x'].forEach(function (opt) {
options[opt] = options[opt] || [];
// Make sure includes/excludes always end up as arrays
options[opt] = Array.isArray(options[opt]) ?
options[opt] : [options[opt]];
});
options.include = options.include.concat(options.i);
options.exclude = options.exclude.concat(options.x);
// Show command line options
if (options.help || options.h) {
console.log("\nUsage: node app.js [options]\n");
console.log("Options:");
console.log(" --help, -h Show this message.");
console.log(" --port, -p <number> Specify port.");
console.log(" --directory, -D <bundle> Serve files from specified directory.");
console.log("");
process.exit(0);
}
app.disable('x-powered-by');
app.use('/proxyUrl', function proxyRequest(req, res, next) {
console.log('Proxying request to: ', req.query.url);
req.pipe(request({
url: req.query.url,
strictSSL: false
}).on('error', next)).pipe(res);
});
const webpack = require('webpack');
const webpackConfig = require('./webpack.config.js');
webpackConfig.plugins.push(new webpack.HotModuleReplacementPlugin());
webpackConfig.plugins.push(function() { this.plugin('watch-run', function(watching, callback) { console.log('Begin compile at ' + new Date()); callback(); }) });
webpackConfig.entry.openmct = [
'webpack-hot-middleware/client?reload=true',
webpackConfig.entry.openmct
];
const compiler = webpack(webpackConfig);
app.use(require('webpack-dev-middleware')(
compiler,
{
publicPath: '/dist',
logLevel: 'warn'
// Show command line options
if (options.help || options.h) {
console.log("\nUsage: node app.js [options]\n");
console.log("Options:");
console.log(" --help, -h Show this message.");
console.log(" --port, -p <number> Specify port.");
console.log(" --include, -i <bundle> Include the specified bundle.");
console.log(" --exclude, -x <bundle> Exclude the specified bundle.");
console.log(" --directory, -D <bundle> Serve files from specified directory.");
console.log("");
process.exit(0);
}
));
app.use(require('webpack-hot-middleware')(
compiler,
{
app.disable('x-powered-by');
}
));
// Override bundles.json for HTTP requests
app.use('/' + BUNDLE_FILE, function (req, res) {
var bundles;
// Expose index.html for development users.
app.get('/', function (req, res) {
fs.createReadStream('index.html').pipe(res);
});
try {
bundles = JSON.parse(fs.readFileSync(BUNDLE_FILE, 'utf8'));
} catch (e) {
bundles = [];
}
// Finally, open the HTTP server and log the instance to the console
app.listen(options.port, options.host, function() {
console.log('Open MCT application running at %s:%s', options.host, options.port)
});
// Handle command line inclusions/exclusions
bundles = bundles.concat(options.include);
bundles = bundles.filter(function (bundle) {
return options.exclude.indexOf(bundle) === -1;
});
bundles = bundles.filter(function (bundle, index) { // Uniquify
return bundles.indexOf(bundle) === index;
});
res.send(JSON.stringify(bundles));
});
app.use('/proxyUrl', function proxyRequest(req, res, next) {
console.log('Proxying request to: ', req.query.url);
req.pipe(request({
url: req.query.url,
strictSSL: false
}).on('error', next)).pipe(res);
});
// Expose everything else as static files
app.use(express['static'](options.directory));
// Finally, open the HTTP server and log the instance to the console
app.listen(options.port, function() {
console.log('Open MCT application running at localhost:' + options.port)
});
}());

28
bower.json Normal file
View File

@@ -0,0 +1,28 @@
{
"name": "openmct",
"description": "The Open MCT core platform",
"main": "",
"license": "Apache-2.0",
"moduleType": [],
"homepage": "http://nasa.github.io/openmct/",
"private": true,
"dependencies": {
"angular": "1.4.4",
"angular-route": "1.4.4",
"moment": "^2.11.1",
"moment-duration-format": "^1.3.0",
"requirejs": "~2.1.22",
"text": "requirejs-text#^2.0.14",
"es6-promise": "^3.3.0",
"screenfull": "^3.0.0",
"node-uuid": "^1.4.7",
"comma-separated-values": "^3.6.4",
"file-saver": "1.3.3",
"zepto": "^1.1.6",
"eventemitter3": "^1.2.0",
"lodash": "3.10.1",
"almond": "~0.3.2",
"html2canvas": "^0.4.1",
"moment-timezone": "^0.5.13"
}
}

27
circle.yml Normal file
View File

@@ -0,0 +1,27 @@
machine:
node:
version: 8.11.0
dependencies:
pre:
- npm install -g npm@latest
deployment:
production:
branch: master
commands:
- npm install canvas nomnoml
- ./build-docs.sh
openmctweb-staging-deux:
branch: mobile
heroku:
appname: openmctweb-staging-deux
test:
post:
- gulp lint
- gulp checkstyle
general:
branches:
ignore:
- gh-pages

View File

@@ -1,21 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2018, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/

View File

@@ -0,0 +1,8 @@
This bundle is intended to serve as an example of registering
extensions which are mapped directly to built-in Angular features.
These are:
* Controllers
* Directives
* Routes
* Services

View File

@@ -0,0 +1,74 @@
/*****************************************************************************
* 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.
*****************************************************************************/
/*global define*/
define([
"./src/ExampleController",
"./src/ExampleDirective",
"./src/ExampleService",
'legacyRegistry'
], function (
ExampleController,
ExampleDirective,
ExampleService,
legacyRegistry
) {
"use strict";
legacyRegistry.register("example/builtins", {
"name": "Angular Built-ins Example",
"description": "Example showing how to declare extensions with built-in support from Angular.",
"sources": "src",
"extensions": {
"controllers": [
{
"key": "ExampleController",
"implementation": ExampleController,
"depends": [
"$scope",
"exampleService"
]
}
],
"directives": [
{
"key": "exampleDirective",
"implementation": ExampleDirective,
"depends": [
"examples[]"
]
}
],
"routes": [
{
"templateUrl": "templates/example.html"
}
],
"services": [
{
"key": "exampleService",
"implementation": ExampleService
}
]
}
});
});

View File

@@ -0,0 +1,24 @@
<!--
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.
-->
<p>Hello, world! I am the default route.</p>
<p ng-controller="ExampleController">My controller has told me: "{{phrase}}"</p>
<span example-directive></span>

View File

@@ -19,7 +19,24 @@
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
$output-bourbon-deprecation-warnings: false;
@import "bourbon";
/*global define,Promise*/
@import "notebook-thematic";
/**
* Module defining ExampleController. Created by vwoeltje on 11/4/14.
*/
define(
[],
function () {
"use strict";
/**
*
* @constructor
*/
function ExampleController($scope, exampleService) {
$scope.phrase = exampleService.getMessage();
}
return ExampleController;
}
);

View File

@@ -0,0 +1,66 @@
/*****************************************************************************
* 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.
*****************************************************************************/
/*global define,Promise*/
/**
* Module defining ExampleDirective. Created by vwoeltje on 11/4/14.
*/
define(
[],
function () {
"use strict";
var HAS_EXTENSIONS = "A directive loaded these message from " +
"example extensions.",
NO_EXTENSIONS = "A directive tried to load example extensions," +
" but found none.",
MESSAGE = "I heard this from my partial constructor.";
/**
*
* @constructor
*/
function ExampleDirective(examples) {
// Build up a template from example extensions
var template = examples.length > 0 ?
HAS_EXTENSIONS : NO_EXTENSIONS;
template += "<ul>";
examples.forEach(function (E) {
template += "<li>";
if (typeof E === 'function') {
template += (new E(MESSAGE)).getText();
} else {
template += E.text;
}
template += "</li>";
});
template += "</ul>";
return {
template: template
};
}
return ExampleDirective;
}
);

View File

@@ -1,5 +1,5 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2018, United States Government
* Open MCT, Copyright (c) 2014-2017, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
@@ -19,22 +19,28 @@
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define,Promise*/
/**
* Module defining ExampleService. Created by vwoeltje on 11/4/14.
*/
define(
[],
function () {
function MCTIndicators(openmct) {
"use strict";
/**
*
* @constructor
*/
function ExampleService() {
return {
restrict: "E",
link: function link(scope, element) {
openmct.indicators.indicatorElements
.forEach(function (indicatorElement) {
element.append(indicatorElement);
});
getMessage: function () {
return "I heard this from a service";
}
};
}
return MCTIndicators;
return ExampleService;
}
);

View File

@@ -0,0 +1,82 @@
/*****************************************************************************
* 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.
*****************************************************************************/
/*global define*/
define([
"./src/SomeProvider",
"./src/SomeOtherProvider",
"./src/SomeDecorator",
"./src/SomeOtherDecorator",
"./src/SomeAggregator",
"./src/SomeOtherExample",
'legacyRegistry'
], function (
SomeProvider,
SomeOtherProvider,
SomeDecorator,
SomeOtherDecorator,
SomeAggregator,
SomeOtherExample,
legacyRegistry
) {
"use strict";
legacyRegistry.register("example/composite", {
"extensions": {
"components": [
{
"implementation": SomeProvider,
"provides": "someService",
"type": "provider"
},
{
"implementation": SomeOtherProvider,
"provides": "someService",
"type": "provider"
},
{
"implementation": SomeDecorator,
"provides": "someService",
"type": "decorator"
},
{
"implementation": SomeOtherDecorator,
"provides": "someService",
"type": "decorator"
},
{
"implementation": SomeAggregator,
"provides": "someService",
"type": "aggregator"
}
],
"examples": [
{
"implementation": SomeOtherExample,
"depends": [
"someService"
]
}
]
}
});
});

View File

@@ -0,0 +1,50 @@
/*****************************************************************************
* 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.
*****************************************************************************/
/*global define,Promise*/
/**
* Module defining SomeAggregator. Created by vwoeltje on 11/5/14.
*/
define(
[],
function () {
"use strict";
/**
*
* @constructor
*/
function SomeAggregator(someProviders) {
return {
getMessages: function () {
return someProviders.map(function (provider) {
return provider.getMessages();
}).reduce(function (a, b) {
return a.concat(b);
}, []);
}
};
}
return SomeAggregator;
}
);

View File

@@ -0,0 +1,48 @@
/*****************************************************************************
* 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.
*****************************************************************************/
/*global define,Promise*/
/**
* Module defining SomeDecorator. Created by vwoeltje on 11/5/14.
*/
define(
[],
function () {
"use strict";
/**
*
* @constructor
*/
function SomeDecorator(someProvider) {
return {
getMessages: function () {
return someProvider.getMessages().map(function (msg) {
return msg.toLocaleUpperCase();
});
}
};
}
return SomeDecorator;
}
);

View File

@@ -0,0 +1,48 @@
/*****************************************************************************
* 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.
*****************************************************************************/
/*global define,Promise*/
/**
* Module defining SomeOtherDecorator. Created by vwoeltje on 11/5/14.
*/
define(
[],
function () {
"use strict";
/**
*
* @constructor
*/
function SomeOtherDecorator(someProvider) {
return {
getMessages: function () {
return someProvider.getMessages().map(function (msg) {
return msg + "...";
});
}
};
}
return SomeOtherDecorator;
}
);

View File

@@ -1,5 +1,5 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2018, United States Government
* Open MCT, Copyright (c) 2014-2017, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
@@ -19,19 +19,28 @@
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define,Promise*/
define(function () {
return {
name: 'Telemetry Table',
description: 'Display telemetry values for the current time bounds in tabular form. Supports filtering and sorting.',
creatable: true,
cssClass: 'icon-tabular-realtime',
initialize(domainObject) {
domainObject.composition = [];
domainObject.configuration = {
columnWidths: {},
hiddenColumns: {}
/**
* Module defining SomeOtherExample. Created by vwoeltje on 11/5/14.
*/
define(
[],
function () {
"use strict";
/**
*
* @constructor
*/
function SomeOtherExample(someService) {
return {
getText: function () {
return someService.getMessages().join(" | ");
}
};
}
};
});
return SomeOtherExample;
}
);

View File

@@ -0,0 +1,48 @@
/*****************************************************************************
* 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.
*****************************************************************************/
/*global define,Promise*/
/**
* Module defining SomeOtherProvider. Created by vwoeltje on 11/5/14.
*/
define(
[],
function () {
"use strict";
/**
*
* @constructor
*/
function SomeOtherProvider() {
return {
getMessages: function () {
return [
"I am a message from some other provider."
];
}
};
}
return SomeOtherProvider;
}
);

View File

@@ -0,0 +1,48 @@
/*****************************************************************************
* 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.
*****************************************************************************/
/*global define,Promise*/
/**
* Module defining SomeProvider. Created by vwoeltje on 11/5/14.
*/
define(
[],
function () {
"use strict";
/**
*
* @constructor
*/
function SomeProvider() {
return {
getMessages: function () {
return [
"I am a message from some provider."
];
}
};
}
return SomeProvider;
}
);

View File

@@ -49,7 +49,7 @@ define([
{
"key": "eventGenerator",
"name": "Event Message Generator",
"cssClass": "icon-generator-events",
"cssClass": "icon-folder-new",
"description": "For development use. Creates sample event message data that mimics a live data stream.",
"priority": 10,
"features": "creation",
@@ -60,8 +60,8 @@ define([
"source": "eventGenerator",
"domains": [
{
"key": "utc",
"name": "Timestamp",
"key": "time",
"name": "Time",
"format": "utc"
}
],

View File

@@ -22,23 +22,24 @@
/*global define */
/**
* Module defining EventTelemetry.
* Module defining EventTelemetry.
* Created by chacskaylo on 06/18/2015.
* Modified by shale on 06/23/2015.
* Modified by shale on 06/23/2015.
*/
define(
['../data/transcript.json'],
function (messages) {
['text!../data/transcript.json'],
function (transcript) {
"use strict";
var firstObservedTime = Date.now();
var firstObservedTime = Date.now(),
messages = JSON.parse(transcript);
function EventTelemetry(request, interval) {
var latestObservedTime = Date.now(),
count = Math.floor((latestObservedTime - firstObservedTime) / interval),
generatorData = {};
generatorData.getPointCount = function () {
return count;
};
@@ -47,13 +48,13 @@ define(
return i * interval +
(domain !== 'delta' ? firstObservedTime : 0);
};
generatorData.getRangeValue = function (i, range) {
var domainDelta = this.getDomainValue(i) - firstObservedTime,
ind = i % messages.length;
return messages[ind] + " - [" + domainDelta.toString() + "]";
};
return generatorData;
}

View File

@@ -0,0 +1,51 @@
/*****************************************************************************
* 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.
*****************************************************************************/
/*global define*/
define([
"./src/SomeExample",
'legacyRegistry'
], function (
SomeExample,
legacyRegistry
) {
"use strict";
legacyRegistry.register("example/extensions", {
"name": "Custom Extensions Examples",
"description": "Example showing how to declare custom extensions.",
"sources": "src",
"extensions": {
"examples": [
{
"text": "I came from example/extensions"
},
{
"implementation": SomeExample,
"depends": [
"exampleService"
]
}
]
}
});
});

View File

@@ -0,0 +1,52 @@
/*****************************************************************************
* 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.
*****************************************************************************/
/*global define,Promise*/
/**
* Module defining SomeExample. Created by vwoeltje on 11/5/14.
*/
define(
[],
function () {
"use strict";
/**
*
* @constructor
*/
function SomeExample(exampleService, message) {
return {
getText: function () {
return [
'"',
exampleService.getMessage(),
'" and "',
message,
'"'
].join("");
}
};
}
return SomeExample;
}
);

View File

@@ -30,7 +30,6 @@ define([
{
key: "sin",
name: "Sine",
formatString: '%0.2f',
hints: {
range: 1
}
@@ -38,7 +37,6 @@ define([
{
key: "cos",
name: "Cosine",
formatString: '%0.2f',
hints: {
range: 2
}

View File

@@ -27,14 +27,8 @@ define([
) {
var RED = {
sin: 0.9,
cos: 0.9
},
YELLOW = {
sin: 0.5,
cos: 0.5
},
var RED = 0.9,
YELLOW = 0.5,
LIMITS = {
rh: {
cssClass: "s-limit-upr s-limit-red",
@@ -73,18 +67,17 @@ define([
SinewaveLimitProvider.prototype.getLimitEvaluator = function (domainObject) {
return {
evaluate: function (datum, valueMetadata) {
var range = valueMetadata && valueMetadata.key;
if (datum[range] > RED[range]) {
var range = valueMetadata ? valueMetadata.key : 'sin'
if (datum[range] > RED) {
return LIMITS.rh;
}
if (datum[range] < -RED[range]) {
if (datum[range] < -RED) {
return LIMITS.rl;
}
if (datum[range] > YELLOW[range]) {
if (datum[range] > YELLOW) {
return LIMITS.yh;
}
if (datum[range] < -YELLOW[range]) {
if (datum[range] < -YELLOW) {
return LIMITS.yl;
}
}

View File

@@ -72,7 +72,7 @@ define([
var data = [];
while (start <= end && data.length < 5000) {
data.push(pointForTimestamp(start, duration, domainObject.name));
start += duration;
start += 5000;
}
return Promise.resolve(data);
};

View File

@@ -21,7 +21,7 @@
*****************************************************************************/
define([
'raw-loader!./generatorWorker.js',
'text!./generatorWorker.js',
'uuid'
], function (
workerText,

View File

@@ -38,7 +38,7 @@ define([
openmct.types.addType("example.state-generator", {
name: "State Generator",
description: "For development use. Generates test enumerated telemetry by cycling through a given set of states",
cssClass: "icon-generator-telemetry",
cssClass: "icon-telemetry",
creatable: true,
form: [
{
@@ -66,7 +66,7 @@ define([
openmct.types.addType("generator", {
name: "Sine Wave Generator",
description: "For development use. Generates example streaming telemetry data using a simple sine wave algorithm.",
cssClass: "icon-generator-telemetry",
cssClass: "icon-telemetry",
creatable: true,
form: [
{

View File

@@ -38,8 +38,7 @@ define([
"provides": "identityService",
"type": "provider",
"depends": [
"dialogService",
"$q"
"dialogService"
]
}
]

View File

@@ -55,37 +55,21 @@ define(
* @implements {IdentityService}
* @memberof platform/identity
*/
function ExampleIdentityProvider(dialogService, $q) {
this.dialogService = dialogService;
this.$q = $q;
function ExampleIdentityProvider(dialogService) {
// Handle rejected dialog messages by treating the
// current user as undefined.
function echo(v) { return v; }
function giveUndefined() { return undefined; }
this.returnUser = this.returnUser.bind(this);
this.returnUndefined = this.returnUndefined.bind(this);
this.userPromise =
dialogService.getUserInput(DIALOG_STRUCTURE, DEFAULT_IDENTITY)
.then(echo, giveUndefined);
}
ExampleIdentityProvider.prototype.getUser = function () {
if (this.user) {
return this.$q.when(this.user);
} else {
return this.dialogService.getUserInput(DIALOG_STRUCTURE, DEFAULT_IDENTITY)
.then(this.returnUser, this.returnUndefined);
}
return this.userPromise;
};
/**
* @private
*/
ExampleIdentityProvider.prototype.returnUser = function (user) {
return this.user = user;
}
/**
* @private
*/
ExampleIdentityProvider.prototype.returnUndefined = function () {
return undefined;
}
return ExampleIdentityProvider;
}
);

View File

@@ -26,16 +26,12 @@ define([
"./src/NotificationLaunchController",
"./src/DialogLaunchIndicator",
"./src/NotificationLaunchIndicator",
"./res/dialog-launch.html",
"./res/notification-launch.html",
'legacyRegistry'
], function (
DialogLaunchController,
NotificationLaunchController,
DialogLaunchIndicator,
NotificationLaunchIndicator,
DialogLaunch,
NotificationLaunch,
legacyRegistry
) {
"use strict";
@@ -45,11 +41,11 @@ define([
"templates": [
{
"key": "dialogLaunchTemplate",
"template": DialogLaunch
"templateUrl": "dialog-launch.html"
},
{
"key": "notificationLaunchTemplate",
"template": NotificationLaunch
"templateUrl": "notification-launch.html"
}
],
"controllers": [

View File

@@ -1,9 +1,9 @@
<span class="h-indicator" ng-controller="DialogLaunchController">
<span class="status block" ng-controller="DialogLaunchController">
<!-- DO NOT ADD SPACES BETWEEN THE SPANS - IT ADDS WHITE SPACE!! -->
<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>
<span class="status-indicator icon-box-with-arrow"></span><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><span class="count"></span>
</span>

View File

@@ -1,9 +1,9 @@
<span class="h-indicator" ng-controller="NotificationLaunchController">
<span class="status block" ng-controller="NotificationLaunchController">
<!-- DO NOT ADD SPACES BETWEEN THE SPANS - IT ADDS WHITE SPACE!! -->
<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>
<span class="status-indicator icon-bell"></span><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><span class="count"></span>
</span>

View File

@@ -51,26 +51,76 @@ define(
return actionTexts[Math.floor(Math.random()*3)];
}
function getExampleActions() {
var actions = [
{
label: "Try Again",
callback: function () {
$log.debug("Try Again pressed");
}
},
{
label: "Remove",
callback: function () {
$log.debug("Remove pressed");
}
},
{
label: "Cancel",
callback: function () {
$log.debug("Cancel pressed");
}
}
];
// Randomly remove some actions off the top; leave at least one
actions.splice(0,Math.floor(Math.random() * actions.length));
return actions;
}
function getExampleSeverity() {
var severities = [
"info",
"alert",
"error"
];
return severities[Math.floor(Math.random() * severities.length)];
}
/**
* Launch a new notification with a severity level of 'Error'.
*/
$scope.newError = function () {
$scope.newError = function(){
notificationService.notify({
title: "Example error notification " + messageCounter++,
hint: "An error has occurred",
severity: "error"
});
severity: "error",
primaryOption: {
label: 'Retry',
callback: function() {
$log.info('Retry clicked');
}
},
options: getExampleActions()});
};
/**
* Launch a new notification with a severity of 'Alert'.
*/
$scope.newAlert = function () {
$scope.newAlert = function(){
notificationService.notify({
title: "Alert notification " + (messageCounter++),
hint: "This is an alert message",
severity: "alert",
autoDismiss: true
});
primaryOption: {
label: 'Retry',
callback: function() {
$log.info('Retry clicked');
}
},
options: getExampleActions()});
};
@@ -78,42 +128,39 @@ define(
* Launch a new notification with a progress bar that is updated
* periodically, tracking an ongoing process.
*/
$scope.newProgress = function () {
let progress = 0;
$scope.newProgress = function(){
var notificationModel = {
title: "Progress notification example",
severity: "info",
progress: progress,
actionText: getExampleActionText()
progress: 0,
actionText: getExampleActionText(),
unknownProgress: false
};
let notification;
/**
* Simulate an ongoing process and update the progress bar.
* @param notification
*/
function incrementProgress() {
progress = Math.min(100, Math.floor(progress + Math.random() * 30))
let progressText = ["Estimated time" +
function incrementProgress(notificationModel) {
notificationModel.progress = Math.min(100, Math.floor(notificationModel.progress + Math.random() * 30));
notificationModel.progressText = ["Estimated time" +
" remaining:" +
" about ", 60 - Math.floor((progress / 100) * 60), " seconds"].join(" ");
notification.progress(progress, progressText);
if (progress < 100) {
$timeout(function () {
incrementProgress(notificationModel);
}, 1000);
" about ", 60 - Math.floor((notificationModel.progress / 100) * 60), " seconds"].join(" ");
if (notificationModel.progress < 100) {
$timeout(function(){incrementProgress(notificationModel);}, 1000);
}
}
notification = notificationService.notify(notificationModel);
incrementProgress();
notificationService.notify(notificationModel);
incrementProgress(notificationModel);
};
/**
* Launch a new notification with severity level of INFO.
*/
$scope.newInfo = function () {
$scope.newInfo = function(){
notificationService.info({
title: "Example Info notification " + messageCounter++
});

View File

@@ -1,19 +0,0 @@
<template>
<div class="example">{{ msg }}</div>
</template>
<script>
export default {
data () {
return {
msg: 'Hello world!'
}
}
}
</script>
<style>
.example {
color: red;
}
</style>

View File

@@ -1,37 +0,0 @@
import Vue from 'Vue';
import HelloWorld from './HelloWorld.vue';
function SimpleVuePlugin () {
return function install(openmct) {
var views = (openmct.mainViews || openmct.objectViews);
openmct.types.addType('hello-world', {
name: 'Hello World',
description: 'An introduction object',
creatable: true
});
openmct.objectViews.addProvider({
name: "demo-provider",
key: "hello-world",
cssClass: "icon-packet",
canView: function (d) {
return d.type === 'hello-world';
},
view: function (domainObject) {
var vm;
return {
show: function (container) {
vm = new Vue(HelloWorld);
container.appendChild(vm.$mount().$el);
},
destroy: function (container) {
vm.$destroy();
}
};
}
});
}
}
export default SimpleVuePlugin

View File

@@ -1,26 +1,10 @@
define([
"./src/ExampleStyleGuideModelProvider",
"./src/MCTExample",
"./res/templates/intro.html",
"./res/templates/standards.html",
"./res/templates/colors.html",
"./res/templates/status.html",
"./res/templates/glyphs.html",
"./res/templates/controls.html",
"./res/templates/input.html",
"./res/templates/menus.html",
'legacyRegistry'
], function (
ExampleStyleGuideModelProvider,
MCTExample,
introTemplate,
standardsTemplate,
colorsTemplate,
statusTemplate,
glyphsTemplate,
controlsTemplate,
inputTemplate,
menusTemplate,
legacyRegistry
) {
legacyRegistry.register("example/styleguide", {
@@ -39,14 +23,14 @@ define([
{ "key": "styleguide.menus", "name": "Menus", "cssClass": "icon-page", "description": "Context menus, dropdowns" }
],
"views": [
{ "key": "styleguide.intro", "type": "styleguide.intro", "template": introTemplate, "editable": false },
{ "key": "styleguide.standards", "type": "styleguide.standards", "template": standardsTemplate, "editable": false },
{ "key": "styleguide.colors", "type": "styleguide.colors", "template": colorsTemplate, "editable": false },
{ "key": "styleguide.status", "type": "styleguide.status", "template": statusTemplate, "editable": false },
{ "key": "styleguide.glyphs", "type": "styleguide.glyphs", "template": glyphsTemplate, "editable": false },
{ "key": "styleguide.controls", "type": "styleguide.controls", "template": controlsTemplate, "editable": false },
{ "key": "styleguide.input", "type": "styleguide.input", "template": inputTemplate, "editable": false },
{ "key": "styleguide.menus", "type": "styleguide.menus", "template": menusTemplate, "editable": false }
{ "key": "styleguide.intro", "type": "styleguide.intro", "templateUrl": "templates/intro.html", "editable": false },
{ "key": "styleguide.standards", "type": "styleguide.standards", "templateUrl": "templates/standards.html", "editable": false },
{ "key": "styleguide.colors", "type": "styleguide.colors", "templateUrl": "templates/colors.html", "editable": false },
{ "key": "styleguide.status", "type": "styleguide.status", "templateUrl": "templates/status.html", "editable": false },
{ "key": "styleguide.glyphs", "type": "styleguide.glyphs", "templateUrl": "templates/glyphs.html", "editable": false },
{ "key": "styleguide.controls", "type": "styleguide.controls", "templateUrl": "templates/controls.html", "editable": false },
{ "key": "styleguide.input", "type": "styleguide.input", "templateUrl": "templates/input.html", "editable": false },
{ "key": "styleguide.menus", "type": "styleguide.menus", "templateUrl": "templates/menus.html", "editable": false }
],
"roots": [
{
@@ -101,6 +85,16 @@ define([
"$q"
]
}
],
"stylesheets": [
{
"stylesheetUrl": "css/style-guide-espresso.css",
"theme": "espresso"
},
{
"stylesheetUrl": "css/style-guide-snow.css",
"theme": "snow"
}
]
}
});

View File

@@ -58,10 +58,7 @@
position: relative;
}
.w-mct-example {
color: #ccc;
> div { margin-bottom: $interiorMarginLg; }
}
.w-mct-example > div { margin-bottom: $interiorMarginLg; }
code,
pre {

View File

@@ -20,6 +20,12 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
@import "bourbon";
@import "../../../../platform/commonUI/general/res/sass/constants";
@import "../../../../platform/commonUI/general/res/sass/mixins";
@import "../../../../platform/commonUI/themes/espresso/res/sass/constants";
@import "../../../../platform/commonUI/themes/espresso/res/sass/mixins";
@import "../../../../platform/commonUI/general/res/sass/glyphs";
@import "../../../../platform/commonUI/general/res/sass/icons";
// Thematic constants
$colorCode: rgba(black, 0.2);

View File

@@ -20,6 +20,12 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
@import "bourbon";
@import "../../../../platform/commonUI/general/res/sass/constants";
@import "../../../../platform/commonUI/general/res/sass/mixins";
@import "../../../../platform/commonUI/themes/snow/res/sass/constants";
@import "../../../../platform/commonUI/themes/snow/res/sass/mixins";
@import "../../../../platform/commonUI/general/res/sass/glyphs";
@import "../../../../platform/commonUI/general/res/sass/icons";
// Thematic constants
$colorCode: rgba(black, 0.1);
@@ -28,4 +34,4 @@ $colorGlyphExample: darken($colorBodyBg, 30%);
@import "style-guide-base";
div.themed.snow { display: block; }
span.themed.snow { display: inline; }
span.themed.snow { display: inline; }

View File

@@ -149,21 +149,12 @@
<h2>Local Controls</h2>
<div class="cols cols1-1">
<div class="col">
<p>Local controls are typically buttons and selects that provide actions in close proximity to a component.</p>
<p>These controls can optionally be hidden to reduce clutter until the user hovers their cursor over an enclosing element. To use this approach, apply the class <code>.has-local-controls</code> to the element that should be aware of the hover and ensure that element encloses <code>.h-local-controls</code>.</p>
<p>Local controls are typically buttons and selects that provide local control to an individual element. Typically, these controls are hidden in order to not block data display until the user hovers their cursor over an element, when the controls are displayed using a transition fade. Mousing out of the element fades the controls from view.</p>
</div>
<mct-example><div class="plot-display-area" style="padding: 10px; position: relative;">
Some content in here
<div class="h-local-controls h-local-controls-overlay-content l-btn-set">
<mct-example><div class="plot-display-area" style="height: 100px; padding: 10px; position: relative;">Hover over me
<div class="l-local-controls gl-plot-local-controls t-plot-display-controls">
<a class="s-button icon-arrow-left" title="Restore previous pan/zoom"></a>
<a class="s-button icon-reset" title="Reset pan/zoom"></a>
</div>
</div>
<div class="plot-display-area has-local-controls" style="padding: 10px; position: relative;">
Hover here
<div class="h-local-controls h-local-controls-overlay-content local-controls-hidden l-btn-set">
<a class="s-button icon-arrow-left" title="Restore previous pan/zoom"></a>
<a class="s-button icon-reset" title="Reset pan/zoom"></a>
<a class="s-button icon-arrows-out" title="Reset pan/zoom"></a>
</div>
</div></mct-example>
</div>

View File

@@ -34,7 +34,7 @@
<p>As you develop plugins for Open MCT, consider how a generalized component might be combined with others when designing to create a rich and powerful larger object, rather than adding a single monolithic, non-modular plugin. To solve a particular problem or allow a new feature in Open MCT, you may need to introduce more than just one new object type.</p>
</div>
<div class="col">
<img src="../images/diagram-objects.svg" />
<img src="/example/styleguide/res/images/diagram-objects.svg" />
</div>
</div>
</div>
@@ -48,7 +48,7 @@
<p>The types of objects that a container can hold should be based on the purpose of the container and the views that it affords. For example, a Folders purpose is to allow a user to conceptually organize objects of all other types; a Folder must therefore be able to contain an object of any type.</p>
</div>
<div class="col">
<img src="../images/diagram-containment.svg" />
<img src="/example/styleguide/res/images/diagram-containment.svg" />
</div>
</div>
</div>
@@ -60,7 +60,7 @@
<p>Views are simply different ways to view the content of a given object. For example, telemetry data could be viewed as a plot or a table. A clock can display its time in analog fashion or with digital numbers. In each view, all of the content is present; its just represented differently. When providing views for an object, all the content of the object should be present in each view.</p>
</div>
<div class="col">
<img src="../images/diagram-views.svg" />
<img src="/example/styleguide/res/images/diagram-views.svg" />
</div>
</div>
</div>
@@ -70,4 +70,4 @@
<p></p>
<p></p>
<p></p>
</div>
</div>

View File

@@ -20,12 +20,12 @@
at runtime from the About dialog for additional information.
-->
<style>
.w-mct-example div[class*="s-status"],
.w-mct-example span[class*="s-status"],
.w-mct-example div[class*="s-limit"],
.w-mct-example div[class*="s-status"],
.w-mct-example div[class*="s-unsynced"],
.w-mct-example span[class*="s-limit"] {
border-radius: 3px;
padding: 2px 5px;
border-radius: 4px;
padding: 3px 7px;
}
.w-mct-example table {
width: 100%;
@@ -36,12 +36,65 @@
<h1>Status Indication</h1>
<div class="l-section">
<h2>Status Classes</h2>
<h2>Overview</h2>
<p>Many elements in Open MCT need to articulate a dynamic status; Open MCT provides the following styles and conventions to handle this:</p>
<ul>
<li><strong>Limits</strong>: when telemetry values exceed minimum or maximum values, they can be violating limits. Limit styles include both color and iconography; color is used to indicate severity while icons are used to indicate direction, upper or lower.</li>
<li><strong>Status</strong>: Open MCT also provides a number or built-in Status styles allowing telemetry or other displayed information to be visually classified by type. Common uses for these classes are to visually denote event records.</li>
<li><strong>Synchronization</strong>: When the system is displaying real-time data, it is very important that displays clearly indicate when they are not doing so, such as when a plot if frozen while panning or zooming. Open MCT provides a style for this.</li>
</ul>
</div>
<div class="l-section">
<h2>Limits</h2>
<div class="cols cols1-1">
<div class="col">
<p>Status classes allow any block or inline-block element to be decorated in order to articulate a
status. Provided classes include color-only and color plus icon; custom icons can easily be
employed by using a color-only status class in combination with an <a class="link" href="#/browse/styleguide:home/glyphs?tc.mode=local&tc.timeSystem=utc&tc.startDelta=1800000&tc.endDelta=0&view=styleguide.glyphs">glyph</a>.</p>
<p>Limit CSS classes can be applied to any block or inline element. Open MCT limit classes set color and optionally an icon, but don't effect other properties. Yellow and red limit classes can be used as is, or allow the application of any custom icon available in Open MCT's glyphs library. &quot;Level&quot; limit classes - upper and lower - always use an icon in addition to a color; Open MCT doesn't support level limits without color.</p>
<ul>
<li>Color only</li>
<ul>
<li><code>s-limit-yellow</code>: A yellow limit.</li>
<li><code>s-limit-red</code>: A red limit.</li>
</ul>
<li>Color and icon</li>
<ul>
<li><code>s-limit-yellow-icon</code>: A yellow limit with icon.</li>
<li><code>s-limit-red-icon</code>: A red limit with icon.</li>
</ul>
<li>Upper and lower limit indicators. Must be used with a color limit class to be visible.</li>
<ul>
<li><code>s-limit-upr</code>: Upper limit.
</li>
<li><code>s-limit-lwr</code>: Lower limit.
</li>
</ul>
</ul>
</div>
<mct-example><div class="s-limit-yellow">Yellow limit</div>
<div class="s-limit-red">Red limit</div>
<div class="s-limit-yellow-icon">Yellow limit with icon</div>
<div class="s-limit-red-icon">Red limit with icon</div>
<div class="s-limit-yellow s-limit-lwr">Lower yellow limit</div>
<div class="s-limit-red s-limit-upr">Upper red limit</div>
<div class="s-limit-red icon-bell">Red Limit with a custom icon</div>
<div>Some text with an <span class="s-limit-yellow-icon">inline element</span> showing a yellow limit.</div>
<!-- Limits applied in a table -->
<table>
<tr class='header'><td>Name</td><td>Value 1</td><td>Value 2</td></tr>
<tr><td>ENG_PWR 4991</td><td>7.023</td><td class="s-limit-yellow s-limit-upr">70.23</td></tr>
<tr><td>ENG_PWR 4992</td><td>49.784</td><td class="s-limit-red s-limit-lwr">-121.22</td></tr>
<tr><td>ENG_PWR 4993</td><td class="s-limit-yellow icon-bell">0.451</td><td>1.007</td></tr>
</table>
</mct-example>
</div>
</div>
<div class="l-section">
<h2>Status</h2>
<div class="cols cols1-1">
<div class="col">
<p>Classes here can be applied to elements as needed.</p>
<ul>
<li>Color only</li>
<ul>
@@ -53,175 +106,37 @@
</ul>
<li>Color and icon</li>
<ul>
<li><code>s-status-icon-warning-hi</code></li>
<li><code>s-status-icon-warning-lo</code></li>
<li><code>s-status-icon-diagnostic</code></li>
<li><code>s-status-icon-info</code></li>
<li><code>s-status-icon-ok</code></li>
<li><code>s-status-warning-hi-icon</code></li>
<li><code>s-status-warning-lo-icon</code></li>
<li><code>s-status-diagnostic-icon</code></li>
<li><code>s-status-info-icon</code></li>
<li><code>s-status-ok-icon</code></li>
</ul>
</ul>
</div>
<mct-example><!-- Color alone examples -->
<div class="s-status-warning-hi">WARNING HI</div>
<mct-example><div class="s-status-warning-hi">WARNING HI</div>
<div class="s-status-warning-lo">WARNING LOW</div>
<div class="s-status-diagnostic">DIAGNOSTIC</div>
<div class="s-status-info">INFO</div>
<div class="s-status-ok">OK</div>
<!-- Color and icon examples -->
<div class="s-status-icon-warning-hi">WARNING HI with icon</div>
<div class="s-status-icon-warning-lo">WARNING LOW with icon</div>
<div class="s-status-icon-diagnostic">DIAGNOSTIC with icon</div>
<div class="s-status-icon-info">INFO with icon</div>
<div class="s-status-icon-ok">OK with icon</div>
<div class="s-status-warning-hi icon-alert-triangle">WARNING HI with custom icon</div>
<div>Some text with an <span class="s-status-icon-diagnostic">inline element</span> showing a Diagnostic status.</div>
<div class="s-status-warning-hi-icon">WARNING HI with icon</div>
<div class="s-status-warning-lo-icon">WARNING LOW with icon</div>
<div class="s-status-diagnostic-icon">DIAGNOSTIC with icon</div>
<div class="s-status-info-icon">INFO with icon</div>
<div class="s-status-ok-icon">OK with icon</div>
<div class="s-status-warning-hi icon-gear">WARNING HI with custom icon</div>
</mct-example>
</div>
</div>
<div class="l-section">
<h2>Limit Classes</h2>
<h2>Synchronization</h2>
<div class="cols cols1-1">
<div class="col">
<p>Limit classes are a specialized form of status, specifically meant to be applied to telemetry
displays to indicate that a limit threshold has been violated. Open MCT provides both severity
and direction classes; severity (yellow and red) can be used alone or in combination
with direction (upper or lower). Direction classes cannot be used on their own.</p>
<p>Like Status classes, Limits can be used as color-only, or color plus icon. Custom icons can
be applied in the same fashion as described above.</p>
<ul>
<li>Severity color alone</li>
<ul>
<li><code>s-limit-yellow</code>: A yellow limit.</li>
<li><code>s-limit-red</code>: A red limit.</li>
</ul>
<li>Severity color and icon</li>
<ul>
<li><code>s-limit-icon-yellow</code>: A yellow limit with icon.</li>
<li><code>s-limit-icon-red</code>: A red limit with icon.</li>
</ul>
<li>Direction indicators. MUST be used with a &quot;color alone&quot; limit class. See
examples for more.</li>
<ul>
<li><code>s-limit-upr</code>: Upper limit.</li>
<li><code>s-limit-lwr</code>: Lower limit.</li>
</ul>
</ul>
<p>When the system is operating in real-time streaming mode, it is important for views that display real-time data to clearly articulate when they are not, such as when a user zooms or pans a plot view, freezing that view. In that case, the CSS class <code>s-unsynced</code> should be applied to that view.</p>
</div>
<mct-example><!-- Color alone examples -->
<div class="s-limit-yellow">Yellow limit</div>
<div class="s-limit-red">Red limit</div>
<!-- Color and icon examples -->
<div class="s-limit-icon-yellow">Yellow limit with icon</div>
<div class="s-limit-icon-red">Red limit with icon</div>
<div class="s-limit-red icon-alert-rect">Red Limit with a custom icon</div>
<div>Some text with an <span class="s-limit-icon-yellow">inline element</span> showing a yellow limit.</div>
<!-- Severity and direction examples -->
<div class="s-limit-yellow s-limit-lwr">Lower yellow limit</div>
<div class="s-limit-red s-limit-upr">Upper red limit</div>
<!-- Limits applied in a table -->
<table>
<tr class='header'><td>Name</td><td>Value 1</td><td>Value 2</td></tr>
<tr><td>ENG_PWR 4991</td><td>7.023</td><td class="s-limit-yellow s-limit-upr">70.23</td></tr>
<tr><td>ENG_PWR 4992</td><td>49.784</td><td class="s-limit-red s-limit-lwr">-121.22</td></tr>
<tr><td>ENG_PWR 4993</td><td class="s-limit-yellow icon-alert-triangle">0.451</td><td>1.007</td></tr>
</table>
<mct-example><div class="s-unsynced">This element is unsynced</div>
</mct-example>
</div>
</div>
<div class="l-section">
<h2>Status Bar Indicators</h2>
<div class="cols cols1-1">
<div class="col">
<p>Indicators are small iconic notification elements that appear in the Status Bar area of
the application at the window's bottom. Indicators should be used to articulate the state of a
system and optionally provide gestures related to that system. They use a combination of icon and
color to identify themselves and articulate a state respectively.</p>
<h3>Recommendations</h3>
<ul>
<li><strong>Keep the icon consistent</strong>. The icon is the principal identifier of the system and is a valuable
recall aid for the user. Don't change the icon as a system's state changes, use color and
text for that purpose.</li>
<li><strong>Don't use the same icon more than once</strong>. Select meaningful and distinct icons so the user
will be able to quickly identify what they're looking for.</li>
</ul>
<h3>States</h3>
<ul>
<li><strong>Disabled</strong>: The system is not available to the user.</li>
<li><strong>Off / Available</strong>: The system is accessible to the user but is not currently
&quot;On&quot; or has not been configured. If the Indicator directly provides gestures
related to the system, such as opening a configuration dialog box, then use
&quot;Available&quot;; if the user must act elsewhere or the system isn't user-controllable,
use &quot;Off&quot;.</li>
<li><strong>On</strong>: The system is enabled or configured; it is having an effect on the larger application.</li>
<li><strong>Alert / Error</strong>: There has been a problem with the system. Generally, &quot;Alert&quot;
should be used to call attention to an issue that isn't critical, while &quot;Error&quot;
should be used to call attention to a problem that the user should really be aware of or do
something about.</li>
</ul>
<h3>Structure</h3>
<p>Indicators consist of a <code>.ls-indicator</code>
wrapper element with <code>.icon-*</code> classes for the type of thing they represent and
<code>.s-status-*</code> classes to articulate the current state. Title attributes should be used
to provide more verbose information about the thing and/or its status.</p>
<p>The wrapper encloses a <code>.label</code> element that is displayed on hover. This element should
include a brief statement of the current status, and can also include clickable elements
as <code>&lt;a&gt;</code> tags. An optional <code>.count</code> element can be included to display
information such as a number of messages.</p>
<p>Icon classes are as defined on the
<a class="link" href="#/browse/styleguide:home/glyphs?tc.mode=local&tc.timeSystem=utc&tc.startDelta=1800000&tc.endDelta=0&view=styleguide.glyphs">
Glyphs page</a>. Status classes applicable to Indicators are as follows:</p>
<ul>
<li><code>s-status-disabled</code></li>
<li><code>s-status-off</code></li>
<li><code>s-status-available</code></li>
<li><code>s-status-on</code></li>
<li><code>s-status-alert</code></li>
<li><code>s-status-error</code></li>
</ul>
</div>
<mct-example><div class="s-ue-bottom-bar status-holder s-status-bar">
<span class="ls-indicator icon-database s-status-disabled" title="The system is currently disabled.">
<span class="label">System not enabled.</span>
</span>
</div>
<div class="s-ue-bottom-bar status-holder s-status-bar">
<span class="ls-indicator icon-database s-status-available" title="Configure data connection.">
<span class="label">Data connection available
<a class="icon-gear">Configure</a>
</span>
</span>
</div>
<div class="s-ue-bottom-bar status-holder s-status-bar">
<span class="ls-indicator icon-database s-status-on" title="Data connected.">
<span class="label">Connected to Skynet
<a class="icon-gear">Change</a>
<a>Disconnect</a>
</span>
</span>
</div>
<div class="s-ue-bottom-bar status-holder s-status-bar">
<span class="ls-indicator icon-database s-status-alert" title="System is self-aware.">
<span class="label">Skynet at Turing Level 5</span>
</span>
<span class="ls-indicator icon-bell s-status-error" title="You have alerts.">
<span class="label">
<a class="icon-alert-triangle">View Alerts</a>
</span>
<span class="count">495</span>
</span>
</div>
</mct-example>
</div>
</div>
</div>
</div>

View File

@@ -1,5 +1,5 @@
define([
'../res/templates/mct-example.html'
'text!../res/templates/mct-example.html'
], function (
MCTExampleTemplate
) {

View File

@@ -0,0 +1,68 @@
/*****************************************************************************
* 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.
*****************************************************************************/
/*global define*/
define([
"./src/ExampleTaxonomyModelProvider",
'legacyRegistry'
], function (
ExampleTaxonomyModelProvider,
legacyRegistry
) {
"use strict";
legacyRegistry.register("example/taxonomy", {
"name": "Example taxonomy",
"description": "Example illustrating the addition of a static top-level hierarchy",
"extensions": {
"roots": [
{
"id": "exampleTaxonomy"
}
],
"models": [
{
"id": "exampleTaxonomy",
"model": {
"type": "folder",
"name": "Stub Subsystems",
"composition": [
"examplePacket0",
"examplePacket1",
"examplePacket2"
]
}
}
],
"components": [
{
"provides": "modelService",
"type": "provider",
"implementation": ExampleTaxonomyModelProvider,
"depends": [
"$q"
]
}
]
}
});
});

View File

@@ -0,0 +1,69 @@
/*****************************************************************************
* 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.
*****************************************************************************/
/*global define*/
define(
[],
function () {
"use strict";
function ExampleTaxonomyModelProvider($q) {
var models = {},
packetId,
telemetryId,
i,
j;
// Add some "subsystems"
for (i = 0; i < 3; i += 1) {
packetId = "examplePacket" + i;
models[packetId] = {
name: "Stub Subsystem " + (i + 1),
type: "telemetry.panel",
composition: []
};
// Add some "telemetry points"
for (j = 0; j < 100 * (i + 1); j += 1) {
telemetryId = "exampleTelemetry" + j;
models[telemetryId] = {
name: "SWG" + i + "." + j,
type: "generator",
telemetry: {
period: 10 + i + j
}
};
models[packetId].composition.push(telemetryId);
}
}
return {
getModels: function () {
return $q.when(models);
}
};
}
return ExampleTaxonomyModelProvider;
}
);

1
example/worker/README.md Normal file
View File

@@ -0,0 +1 @@
Example of running a Web Worker using the `workerService`.

52
example/worker/bundle.js Normal file
View File

@@ -0,0 +1,52 @@
/*****************************************************************************
* 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.
*****************************************************************************/
/*global define*/
define([
"./src/FibonacciIndicator",
'legacyRegistry'
], function (
FibonacciIndicator,
legacyRegistry
) {
"use strict";
legacyRegistry.register("example/worker", {
"extensions": {
"indicators": [
{
"implementation": FibonacciIndicator,
"depends": [
"workerService",
"$rootScope"
]
}
],
"workers": [
{
"key": "example.fibonacci",
"scriptUrl": "FibonacciWorker.js"
}
]
}
});
});

View File

@@ -0,0 +1,67 @@
/*****************************************************************************
* 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.
*****************************************************************************/
/*global define*/
define(
[],
function () {
"use strict";
/**
* Displays Fibonacci numbers in the status area.
* @constructor
*/
function FibonacciIndicator(workerService, $rootScope) {
var latest,
counter = 0,
worker = workerService.run('example.fibonacci');
function requestNext() {
worker.postMessage([counter]);
counter += 1;
}
function handleResponse(event) {
latest = event.data;
$rootScope.$apply();
requestNext();
}
worker.onmessage = handleResponse;
requestNext();
return {
getCssClass: function () {
return "icon-object-unknown";
},
getText: function () {
return latest;
},
getDescription: function () {
return "";
}
};
}
return FibonacciIndicator;
}
);

View File

@@ -0,0 +1,15 @@
/*global self*/
(function () {
"use strict";
// Calculate fibonacci numbers inefficiently.
// We can do this because we're on a background thread, and
// won't halt the UI.
function fib(n) {
return n < 2 ? n : (fib(n - 1) + fib(n - 2));
}
self.onmessage = function (event) {
self.postMessage(fib(event.data));
};
}());

182
gulpfile.js Normal file
View File

@@ -0,0 +1,182 @@
/*****************************************************************************
* 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.
*****************************************************************************/
/*global require,__dirname*/
require("v8-compile-cache");
var gulp = require('gulp'),
sourcemaps = require('gulp-sourcemaps'),
path = require('path'),
fs = require('fs'),
git = require('git-rev-sync'),
moment = require('moment'),
project = require('./package.json'),
_ = require('lodash'),
paths = {
main: 'openmct.js',
dist: 'dist',
reports: 'dist/reports',
scss: ['./platform/**/*.scss', './example/**/*.scss'],
assets: [
'./{example,platform}/**/*.{css,css.map,png,svg,ico,woff,eot,ttf}'
],
scripts: [ 'openmct.js', 'platform/**/*.js', 'src/**/*.js' ],
specs: [ 'platform/**/*Spec.js', 'src/**/*Spec.js' ],
},
options = {
requirejsOptimize: {
name: 'bower_components/almond/almond.js',
include: paths.main.replace('.js', ''),
wrap: {
start: (function () {
var buildVariables = {
version: project.version,
timestamp: moment.utc(Date.now()).format(),
revision: fs.existsSync('.git') ? git.long() : 'Unknown',
branch: fs.existsSync('.git') ? git.branch() : 'Unknown'
};
return fs.readFileSync("src/start.frag", 'utf-8')
.replace(/@@(\w+)/g, function (match, key) {
return buildVariables[key];
});;
}()),
endFile: "src/end.frag"
},
optimize: 'uglify2',
uglify2: { output: { comments: /@preserve/ } },
mainConfigFile: paths.main,
wrapShim: true
},
karma: {
configFile: path.resolve(__dirname, 'karma.conf.js'),
singleRun: true
},
sass: {
sourceComments: true
}
};
if (process.env.NODE_ENV === 'development') {
options.requirejsOptimize.optimize = 'none';
}
gulp.task('scripts', function () {
var requirejsOptimize = require('gulp-requirejs-optimize');
return gulp.src(paths.main)
.pipe(sourcemaps.init())
.pipe(requirejsOptimize(options.requirejsOptimize))
.pipe(sourcemaps.write('.'))
.pipe(gulp.dest(paths.dist));
});
gulp.task('test', function (done) {
var karma = require('karma');
new karma.Server(options.karma, done).start();
});
gulp.task('stylesheets', function () {
var sass = require('gulp-sass');
var rename = require('gulp-rename');
var bourbon = require('node-bourbon');
options.sass.includePaths = bourbon.includePaths;
return gulp.src(paths.scss, {base: '.'})
.pipe(sourcemaps.init())
.pipe(sass(options.sass).on('error', sass.logError))
.pipe(rename(function (file) {
file.dirname =
file.dirname.replace(path.sep + 'sass', path.sep + 'css');
return file;
}))
.pipe(sourcemaps.write('.'))
.pipe(gulp.dest(__dirname));
});
gulp.task('lint', function () {
var jshint = require('gulp-jshint');
var merge = require('merge-stream');
var nonspecs = paths.specs.map(function (glob) {
return "!" + glob;
}),
scriptLint = gulp.src(paths.scripts.concat(nonspecs))
.pipe(jshint()),
specLint = gulp.src(paths.specs)
.pipe(jshint({ jasmine: true }));
return merge(scriptLint, specLint)
.pipe(jshint.reporter('gulp-jshint-html-reporter', {
filename: paths.reports + '/lint/jshint-report.html',
createMissingFolders : true
}))
.pipe(jshint.reporter('default'))
.pipe(jshint.reporter('fail'));
});
gulp.task('checkstyle', function () {
var jscs = require('gulp-jscs');
var mkdirp = require('mkdirp');
var reportName = 'jscs-html-report.html';
var reportPath = path.resolve(paths.reports, 'checkstyle', reportName);
var moveReport = fs.rename.bind(fs, reportName, reportPath, _.noop);
mkdirp.sync(path.resolve(paths.reports, 'checkstyle'));
return gulp.src(paths.scripts)
.pipe(jscs())
.pipe(jscs.reporter())
.pipe(jscs.reporter('jscs-html-reporter')).on('finish', moveReport)
.pipe(jscs.reporter('fail'));
});
gulp.task('fixstyle', function () {
var jscs = require('gulp-jscs');
return gulp.src(paths.scripts, { base: '.' })
.pipe(jscs({ fix: true }))
.pipe(gulp.dest('.'));
});
gulp.task('assets', ['stylesheets'], function () {
return gulp.src(paths.assets)
.pipe(gulp.dest(paths.dist));
});
gulp.task('watch', function () {
return gulp.watch(paths.scss, ['stylesheets', 'assets']);
});
gulp.task('serve', function () {
console.log('Running development server with all defaults');
var app = require('./app.js');
});
gulp.task('develop', ['serve', 'stylesheets', 'watch']);
gulp.task('install', [ 'assets', 'scripts' ]);
gulp.task('verify', [ 'lint', 'test', 'checkstyle' ]);
gulp.task('build', [ 'verify', 'install' ]);

View File

@@ -26,259 +26,68 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0, shrink-to-fit=no">
<meta name="apple-mobile-web-app-capable" content="yes">
<title></title>
<script src="dist/openmct.js"></script>
<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">
<script src="bower_components/requirejs/require.js"> </script>
<script>
var THIRTY_MINUTES = 30 * 60 * 1000;
require(['openmct'], function (openmct) {
[
'example/eventGenerator',
'example/styleguide'
].forEach(
openmct.legacyRegistry.enable.bind(openmct.legacyRegistry)
);
openmct.install(openmct.plugins.MyItems());
openmct.install(openmct.plugins.LocalStorage());
openmct.install(openmct.plugins.Espresso());
openmct.install(openmct.plugins.Generator());
openmct.install(openmct.plugins.ExampleImagery());
openmct.install(openmct.plugins.UTCTimeSystem());
openmct.install(openmct.plugins.ImportExport());
openmct.install(openmct.plugins.AutoflowView({
type: "telemetry.panel"
}));
openmct.install(openmct.plugins.Conductor({
menuOptions: [
{
name: "Fixed",
timeSystem: 'utc',
bounds: {
start: Date.now() - THIRTY_MINUTES,
end: Date.now()
}
},
{
name: "Realtime",
timeSystem: 'utc',
clock: 'local',
clockOffsets: {
start: -25 * 60 * 1000,
end: 5 * 60 * 1000
}
}
]
}));
openmct.install(openmct.plugins.SummaryWidget());
openmct.install(openmct.plugins.BarGraph());
openmct.time.clock('local', {start: -THIRTY_MINUTES, end: 0});
openmct.time.timeSystem('utc');
openmct.start();
});
</script>
<link rel="stylesheet" href="platform/commonUI/general/res/css/startup-base.css">
<link rel="stylesheet" href="platform/commonUI/general/res/css/openmct.css">
<link rel="icon" type="image/png" href="platform/commonUI/general/res/images/favicons/favicon-32x32.png" sizes="32x32">
<link rel="icon" type="image/png" href="platform/commonUI/general/res/images/favicons/favicon-96x96.png" sizes="96x96">
<link rel="icon" type="image/png" href="platform/commonUI/general/res/images/favicons/favicon-16x16.png" sizes="16x16">
<link rel="shortcut icon" href="platform/commonUI/general/res/images/favicons/favicon.ico">
<link rel="stylesheet" href="src/plugins/barGraph/res/styles/barGraph.css">
</head>
<body>
<div class="l-splash-holder s-splash-holder">
<div class="l-splash s-splash"></div>
</div>
</body>
<script>
var THIRTY_MINUTES = 30 * 60 * 1000;
[
'example/eventGenerator',
'example/styleguide'
].forEach(
openmct.legacyRegistry.enable.bind(openmct.legacyRegistry)
);
openmct.install(openmct.plugins.MyItems());
openmct.install(openmct.plugins.LocalStorage());
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.Conductor({
menuOptions: [
{
name: "Fixed",
timeSystem: 'utc',
bounds: {
start: Date.now() - THIRTY_MINUTES,
end: Date.now()
}
},
{
name: "Realtime",
timeSystem: 'utc',
clock: 'local',
clockOffsets: {
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.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>

View File

@@ -21,40 +21,67 @@
*****************************************************************************/
/*global module,process*/
const devMode = process.env.NODE_ENV !== 'production';
module.exports = (config) => {
const webpackConfig = require('./webpack.config.js');
delete webpackConfig.output;
if (!devMode) {
webpackConfig.module.rules.push({
test: /\.js$/,
exclude: /node_modules|example/,
use: 'istanbul-instrumenter-loader'
});
}
module.exports = function(config) {
config.set({
// Base path that will be used to resolve all file patterns.
basePath: '',
frameworks: ['jasmine'],
// Frameworks to use
// Available frameworks: https://npmjs.org/browse/keyword/karma-adapter
frameworks: ['jasmine', 'requirejs'],
// List of files / patterns to load in the browser.
// By default, files are also included in a script tag.
files: [
'platform/**/*Spec.js',
'src/**/*Spec.js'
{pattern: 'bower_components/**/*.js', included: false},
{pattern: 'node_modules/d3-*/**/*.js', included: false},
{pattern: 'node_modules/vue/**/*.js', included: false},
{pattern: 'src/**/*', included: false},
{pattern: 'example/**/*.html', included: false},
{pattern: 'example/**/*.js', included: false},
{pattern: 'example/**/*.json', included: false},
{pattern: 'platform/**/*.js', included: false},
{pattern: 'warp/**/*.js', included: false},
{pattern: 'platform/**/*.html', included: false},
'test-main.js'
],
// List of files to exclude.
exclude: [
'platform/framework/src/Main.js'
],
// Preprocess matching files before serving them to the browser.
// https://npmjs.org/browse/keyword/karma-preprocessor
preprocessors: {
'src/**/!(*Spec).js': [ 'coverage' ],
'platform/**/src/**/!(*Spec).js': [ 'coverage' ]
},
// Test results reporter to use
// Possible values: 'dots', 'progress'
// Available reporters: https://npmjs.org/browse/keyword/karma-reporter
reporters: ['progress', 'coverage', 'html', 'junit'],
// Web server port.
port: 9876,
reporters: [
'progress',
'coverage',
'html'
],
browsers: ['ChromeHeadless'],
// Wnable / disable colors in the output (reporters and logs).
colors: true,
logLevel: config.LOG_INFO,
// Rerun tests when any file changes.
autoWatch: true,
// Specify browsers to run tests in.
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
browsers: [
'Chrome'
],
// Code coverage reporting.
coverageReporter: {
dir: process.env.CIRCLE_ARTIFACTS ?
process.env.CIRCLE_ARTIFACTS + '/coverage' :
@@ -74,19 +101,12 @@ module.exports = (config) => {
foldAll: false
},
preprocessors: {
// add webpack as preprocessor
'platform/**/*Spec.js': [ 'webpack' ],
'src/**/*Spec.js': [ 'webpack' ]
junitReporter: {
outputDir: process.env.CIRCLE_TEST_REPORTS || 'dist/reports/junit'
},
webpack: webpackConfig,
webpackMiddleware: {
stats: 'errors-only',
logLevel: 'warn'
},
// Continuous Integration mode.
// If true, Karma captures browsers, runs the tests and exits.
singleRun: true
});
}
};

View File

@@ -19,19 +19,97 @@
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global module,BUILD_CONSTANTS*/
/*global requirejs,BUILD_CONSTANTS*/
const matcher = /\/openmct.js$/;
if (document.currentScript) {
let src = document.currentScript.src;
if (src && matcher.test(src)) {
// eslint-disable-next-line no-undef
__webpack_public_path__ = src.replace(matcher, '') + '/';
requirejs.config({
"paths": {
"legacyRegistry": "src/legacyRegistry",
"angular": "bower_components/angular/angular.min",
"angular-route": "bower_components/angular-route/angular-route.min",
"csv": "bower_components/comma-separated-values/csv.min",
"EventEmitter": "bower_components/eventemitter3/index",
"es6-promise": "bower_components/es6-promise/es6-promise.min",
"html2canvas": "bower_components/html2canvas/build/html2canvas.min",
"moment": "bower_components/moment/moment",
"moment-duration-format": "bower_components/moment-duration-format/lib/moment-duration-format",
"moment-timezone": "bower_components/moment-timezone/builds/moment-timezone-with-data",
"saveAs": "bower_components/file-saver/FileSaver.min",
"screenfull": "bower_components/screenfull/dist/screenfull.min",
"text": "bower_components/text/text",
"uuid": "bower_components/node-uuid/uuid",
"vue": "node_modules/vue/dist/vue.min",
"zepto": "bower_components/zepto/zepto.min",
"lodash": "bower_components/lodash/lodash",
"d3-selection": "node_modules/d3-selection/dist/d3-selection.min",
"d3-scale": "node_modules/d3-scale/build/d3-scale.min",
"d3-axis": "node_modules/d3-axis/build/d3-axis.min",
"d3-array": "node_modules/d3-array/build/d3-array.min",
"d3-collection": "node_modules/d3-collection/build/d3-collection.min",
"d3-color": "node_modules/d3-color/build/d3-color.min",
"d3-format": "node_modules/d3-format/build/d3-format.min",
"d3-interpolate": "node_modules/d3-interpolate/build/d3-interpolate.min",
"d3-time": "node_modules/d3-time/build/d3-time.min",
"d3-time-format": "node_modules/d3-time-format/build/d3-time-format.min"
},
"shim": {
"angular": {
"exports": "angular"
},
"angular-route": {
"deps": ["angular"]
},
"EventEmitter": {
"exports": "EventEmitter"
},
"html2canvas": {
"exports": "html2canvas"
},
"moment-duration-format": {
"deps": ["moment"]
},
"saveAs": {
"exports": "saveAs"
},
"screenfull": {
"exports": "screenfull"
},
"zepto": {
"exports": "Zepto"
},
"lodash": {
"exports": "lodash"
},
"d3-selection": {
"exports": "d3-selection"
},
"d3-scale": {
"deps": ["d3-array", "d3-collection", "d3-color", "d3-format", "d3-interpolate", "d3-time", "d3-time-format"],
"exports": "d3-scale"
},
"d3-axis": {
"exports": "d3-axis"
}
}
}
});
const MCT = require('./src/MCT');
define([
'./platform/framework/src/Main',
'./src/defaultRegistry',
'./src/MCT',
'./src/plugins/buildInfo/plugin'
], function (Main, defaultRegistry, MCT, buildInfo) {
var openmct = new MCT();
var openmct = new MCT();
openmct.legacyRegistry = defaultRegistry;
openmct.install(openmct.plugins.Plot());
module.exports = openmct;
if (typeof BUILD_CONSTANTS !== 'undefined') {
openmct.install(buildInfo(BUILD_CONSTANTS));
}
openmct.on('start', function () {
return new Main().run(defaultRegistry);
});
return openmct;
});

View File

@@ -2,15 +2,7 @@
"name": "openmct",
"version": "0.14.0-SNAPSHOT",
"description": "The Open MCT core platform",
"dependencies": {},
"devDependencies": {
"angular": "1.4.14",
"angular-route": "1.4.14",
"babel-eslint": "8.2.6",
"comma-separated-values": "^3.6.4",
"concurrently": "^3.6.1",
"copy-webpack-plugin": "^4.5.2",
"css-loader": "^1.0.0",
"dependencies": {
"d3-array": "1.2.x",
"d3-axis": "1.0.x",
"d3-collection": "1.0.x",
@@ -21,69 +13,55 @@
"d3-selection": "1.3.x",
"d3-time": "1.0.x",
"d3-time-format": "2.1.x",
"eslint": "5.2.0",
"eventemitter3": "^1.2.0",
"exports-loader": "^0.7.0",
"express": "^4.13.1",
"fast-sass-loader": "^1.4.5",
"file-loader": "^1.1.11",
"file-saver": "^1.3.8",
"minimist": "^1.1.1",
"request": "^2.69.0",
"vue": "^2.5.6"
},
"devDependencies": {
"bower": "^1.7.7",
"git-rev-sync": "^1.4.0",
"glob": ">= 3.0.0",
"html-loader": "^0.5.5",
"html2canvas": "^1.0.0-alpha.12",
"imports-loader": "^0.8.0",
"istanbul-instrumenter-loader": "^3.0.1",
"jasmine-core": "^3.1.0",
"gulp": "^3.9.1",
"gulp-jscs": "^3.0.2",
"gulp-jshint": "^2.0.0",
"gulp-jshint-html-reporter": "^0.1.3",
"gulp-rename": "^1.2.2",
"gulp-requirejs-optimize": "^0.3.1",
"gulp-sass": "^3.1.0",
"gulp-sourcemaps": "^1.6.0",
"jasmine-core": "^2.3.0",
"jscs-html-reporter": "^0.1.0",
"jsdoc": "^3.3.2",
"karma": "^2.0.3",
"karma-chrome-launcher": "^2.2.0",
"karma-cli": "^1.0.1",
"karma-coverage": "^1.1.2",
"jshint": "^2.7.0",
"karma": "^0.13.3",
"karma-chrome-launcher": "^0.1.12",
"karma-cli": "0.0.4",
"karma-coverage": "^0.5.3",
"karma-html-reporter": "^0.2.7",
"karma-jasmine": "^1.1.2",
"karma-webpack": "^3.0.0",
"location-bar": "^3.0.1",
"karma-jasmine": "^0.1.5",
"karma-junit-reporter": "^0.3.8",
"karma-requirejs": "^0.2.2",
"lodash": "^3.10.1",
"markdown-toc": "^0.11.7",
"marked": "^0.3.5",
"mini-css-extract-plugin": "^0.4.1",
"minimist": "^1.1.1",
"merge-stream": "^1.0.0",
"mkdirp": "^0.5.1",
"moment": "^2.11.1",
"moment-duration-format": "^2.2.2",
"moment-timezone": "^0.5.21",
"node-bourbon": "^4.2.3",
"node-sass": "^4.9.2",
"painterro": "^0.2.65",
"printj": "^1.1.0",
"raw-loader": "^0.5.1",
"request": "^2.69.0",
"requirejs": "2.1.x",
"split": "^1.0.0",
"style-loader": "^0.21.0",
"v8-compile-cache": "^1.1.0",
"vue": "2.5.6",
"vue-loader": "^15.2.6",
"vue-template-compiler": "2.5.6",
"webpack": "^4.16.2",
"webpack-cli": "^3.1.0",
"webpack-dev-middleware": "^3.1.3",
"webpack-hot-middleware": "^2.22.3",
"zepto": "^1.2.0"
"v8-compile-cache": "^1.1.0"
},
"scripts": {
"start": "node app.js",
"lint": "eslint platform src openmct.js",
"lint:fix": "eslint platform src openmct.js --fix",
"build:prod": "NODE_ENV=production webpack",
"build:dev": "webpack",
"build:watch": "webpack --watch",
"test": "karma start --single-run",
"test:watch": "karma start --no-single-run",
"verify": "concurrently 'npm:test' 'npm:lint'",
"jshint": "jshint platform example",
"watch": "karma start",
"jsdoc": "jsdoc -c jsdoc.json -R API.md -r -d dist/docs/api",
"otherdoc": "node docs/gendocs.js --in docs/src --out dist/docs --suppress-toc 'docs/src/index.md|docs/src/process/index.md'",
"docs": "npm run jsdoc ; npm run otherdoc",
"prepare": "npm run build:prod"
"prepare": "node ./node_modules/bower/bin/bower install && node ./node_modules/gulp/bin/gulp.js install"
},
"repository": {
"type": "git",

View File

@@ -21,17 +21,17 @@
*****************************************************************************/
define([
"./res/templates/about-dialog.html",
"text!./res/templates/about-dialog.html",
"./src/LogoController",
"./src/AboutController",
"./src/LicenseController",
"./res/templates/app-logo.html",
"./res/templates/about-logo.html",
"./res/templates/overlay-about.html",
"./res/templates/license-apache.html",
"./res/templates/license-mit.html",
"./res/templates/licenses.html",
"./res/templates/licenses-export-md.html",
"text!./res/templates/app-logo.html",
"text!./res/templates/about-logo.html",
"text!./res/templates/overlay-about.html",
"text!./res/templates/license-apache.html",
"text!./res/templates/license-mit.html",
"text!./res/templates/licenses.html",
"text!./res/templates/licenses-export-md.html",
'legacyRegistry'
], function (
aboutDialogTemplate,

View File

@@ -31,15 +31,18 @@ define([
"./src/navigation/NavigateAction",
"./src/navigation/OrphanNavigationHandler",
"./src/windowing/NewTabAction",
"./src/windowing/FullscreenAction",
"./src/windowing/WindowTitler",
"./res/templates/browse.html",
"./res/templates/browse-object.html",
"./res/templates/browse/object-header.html",
"./res/templates/browse/object-header-frame.html",
"./res/templates/menu-arrow.html",
"./res/templates/back-arrow.html",
"./res/templates/browse/object-properties.html",
"./res/templates/browse/inspector-region.html",
"text!./res/templates/browse.html",
"text!./res/templates/browse-object.html",
"text!./res/templates/items/grid-item.html",
"text!./res/templates/browse/object-header.html",
"text!./res/templates/browse/object-header-frame.html",
"text!./res/templates/menu-arrow.html",
"text!./res/templates/back-arrow.html",
"text!./res/templates/items/items.html",
"text!./res/templates/browse/object-properties.html",
"text!./res/templates/browse/inspector-region.html",
'legacyRegistry'
], function (
BrowseController,
@@ -52,13 +55,16 @@ define([
NavigateAction,
OrphanNavigationHandler,
NewTabAction,
FullscreenAction,
WindowTitler,
browseTemplate,
browseObjectTemplate,
gridItemTemplate,
objectHeaderTemplate,
objectHeaderFrameTemplate,
menuArrowTemplate,
backArrowTemplate,
itemsTemplate,
objectPropertiesTemplate,
inspectorRegionTemplate,
legacyRegistry
@@ -67,6 +73,15 @@ define([
legacyRegistry.register("platform/commonUI/browse", {
"extensions": {
"routes": [
{
"when": "/browse/:ids*?",
"template": browseTemplate,
"reloadOnSearch": false
},
{
"when": "",
"redirectTo": "/browse/"
}
],
"constants": [
{
@@ -150,6 +165,19 @@ define([
"view"
]
},
{
"key": "grid-item",
"template": gridItemTemplate,
"uses": [
"type",
"action",
"location"
],
"gestures": [
"info",
"menu"
]
},
{
"key": "object-header",
"template": objectHeaderTemplate,
@@ -223,6 +251,30 @@ define([
"group": "windowing",
"cssClass": "icon-new-window",
"priority": "preferred"
},
{
"key": "fullscreen",
"implementation": FullscreenAction,
"category": "view-control",
"group": "windowing",
"priority": "default"
}
],
"views": [
{
"key": "items",
"name": "Grid",
"cssClass": "icon-thumbs-strip",
"description": "Grid of available items",
"template": itemsTemplate,
"uses": [
"composition"
],
"gestures": [
"drop"
],
"type": "folder",
"editable": false
}
],
"runs": [
@@ -243,18 +295,16 @@ define([
]
}
],
"templates": [
"licenses": [
{
key: "browseRoot",
template: browseTemplate
},
{
key: "browseObject",
template: browseObjectTemplate
},
{
key: "inspectorRegion",
template: inspectorRegionTemplate
"name": "screenfull.js",
"version": "1.2.0",
"description": "Wrapper for cross-browser usage of fullscreen API",
"author": "Sindre Sorhus",
"website": "https://github.com/sindresorhus/screenfull.js/",
"copyright": "Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)",
"license": "license-mit",
"link": "https://github.com/sindresorhus/screenfull.js/blob/gh-pages/license"
}
]
}

View File

@@ -66,4 +66,5 @@
</mct-representation>
</div>
</div>
<mct-include key="'conductor'" class="abs holder flex-elem flex-fixed l-flex-row l-time-conductor-holder"></mct-include>
</div>

View File

@@ -65,7 +65,7 @@
<div class='split-pane-component t-object pane primary-pane left'>
<mct-representation mct-object="navigatedObject"
key="navigatedObject.getCapability('status').get('editing') ? 'edit-object' : 'browse-object'"
class="abs holder holder-object t-main-view">
class="abs holder holder-object">
</mct-representation>
<a class="mini-tab-icon anchor-right mobile-hide toggle-pane toggle-inspect flush-right"
title="{{ modelPaneInspect.visible()? 'Hide' : 'Show' }} the Inspection pane"

View File

@@ -19,46 +19,41 @@
this source code distribution or the Licensing information page available
at runtime from the About dialog for additional information.
-->
<div ng-controller="ObjectInspectorController as controller" class="grid-properties">
<ul class="l-inspector-part">
<h2 class="first">Properties</h2>
<li class="t-repeat grid-row"
ng-repeat="data in metadata"
ng-class="{ first:$index === 0 }">
<div class="grid-cell label">{{ data.name }}</div>
<div class="grid-cell value">{{ data.value }}</div>
</li>
</ul>
<ul class="l-inspector-part" ng-if="contextutalParents.length > 0">
<h2 title="The location of this linked object.">Location</h2>
<li class="grid-row">
<div class="label" ng-if="primaryParents.length > 0">This Link</div>
<div class="grid-cell value">
<div class="t-repeat inspector-location"
ng-repeat="parent in contextutalParents"
ng-class="{ last:($index + 1) === contextualParents.length }">
<mct-representation key="'label'"
mct-object="parent"
ng-click="parent.getCapability('action').perform('navigate')"
class="location-item">
</mct-representation>
</div>
<div ng-controller="ObjectInspectorController as controller">
<ul class="flex-elem grows l-inspector-part">
<li>
<em class="t-inspector-part-header">Properties</em>
<div class="inspector-properties"
ng-repeat="data in metadata"
ng-class="{ first:$index === 0 }">
<div class="label">{{ data.name }}</div>
<div class="value">{{ data.value }}</div>
</div>
</li>
<li class="grid-row" ng-if="primaryParents.length > 0">
<div class="grid-cell label">Original</div>
<div class="grid-cell value">
<div class="t-repeat inspector-location value"
ng-repeat="parent in primaryParents"
ng-class="{ last:($index + 1) === primaryParents.length }">
<mct-representation key="'label'"
mct-object="parent"
ng-click="parent.getCapability('action').perform('navigate')"
class="location-item">
</mct-representation>
</div>
</div>
<li ng-if="contextutalParents.length > 0">
<em class="t-inspector-part-header" title="The location of this linked object.">Location</em>
<div ng-if="primaryParents.length > 0" class="section-header">This Object</div>
<span class="inspector-location"
ng-repeat="parent in contextutalParents"
ng-class="{ last:($index + 1) === contextualParents.length }">
<mct-representation key="'label'"
mct-object="parent"
ng-click="parent.getCapability('action').perform('navigate')"
class="location-item">
</mct-representation>
</span>
</li>
<li ng-if="primaryParents.length > 0">
<div class="section-header">Object's Original</div>
<span class="inspector-location"
ng-repeat="parent in primaryParents"
ng-class="{ last:($index + 1) === primaryParents.length }">
<mct-representation key="'label'"
mct-object="parent"
ng-click="parent.getCapability('action').perform('navigate')"
class="location-item">
</mct-representation>
</span>
</li>
</ul>
</div>

View File

@@ -0,0 +1,45 @@
<!--
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.
-->
<!-- For selected, add class 'selected' to outer div -->
<div class='item grid-item' ng-click='action.perform("navigate")'>
<div class='contents abs'>
<div class='top-bar bar abs'>
<span class='icon-people' title='Shared'></span>
<mct-representation class="desktop-hide" key="'info-button'" mct-object="domainObject"></mct-representation>
</div>
<div class='item-main abs lg'>
<span class="t-item-icon" ng-class="{ 'l-icon-link':location.isLink() }">
<span class="t-item-icon-glyph ng-binding {{type.getCssClass()}}"></span>
</span>
<div class='abs item-open icon-pointer-right'></div>
</div>
<div class='bottom-bar bar abs'>
<div class='title'>{{model.name}}</div>
<div class='details'>
<span>{{type.getName()}}</span>
<span ng-show="model.composition !== undefined">
- {{model.composition.length}} Item<span ng-show="model.composition.length > 1">s</span>
</span>
</div>
</div>
</div>
</div>

View File

@@ -18,4 +18,10 @@
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='items-holder grid abs'>
<mct-representation key="'grid-item'"
ng-repeat="childObject in composition"
mct-object="childObject">
</mct-representation>
</div>

View File

@@ -47,9 +47,8 @@ define(
urlService,
defaultPath
) {
window.browseScope = $scope;
var initialPath = ($route.current.params.ids || defaultPath).split("/"),
currentIds;
var initialPath = ($route.current.params.ids || defaultPath).split("/");
var currentIds;
$scope.treeModel = {
selectedObject: undefined,
@@ -57,24 +56,7 @@ define(
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;
}
return navigationService.shouldNavigate();
}
};

View File

@@ -31,6 +31,7 @@ define(
* @constructor
*/
function BrowseObjectController($scope, $location, $route) {
var navigatedObject;
function setViewForDomainObject(domainObject) {
var locationViewKey = $location.search().view;
@@ -46,6 +47,7 @@ define(
((domainObject && domainObject.useCapability('view')) || [])
.forEach(selectViewIfMatching);
}
navigatedObject = domainObject;
}
function updateQueryParam(viewKey) {

View File

@@ -162,6 +162,7 @@ define(
*/
NavigationService.prototype.shouldWarnBeforeNavigate = function () {
var reasons = [];
this.checks.forEach(function (checkFn) {
var reason = checkFn();
if (reason) {

View File

@@ -58,7 +58,7 @@ define([], function () {
function checkNavigation() {
var navigatedObject = navigationService.getNavigation();
if (navigatedObject && navigatedObject.hasCapability('context')) {
if (navigatedObject.hasCapability('context')) {
if (!navigatedObject.getCapability('editor').isEditContextRoot()) {
preventOrphanNavigation(navigatedObject);
}

View File

@@ -0,0 +1,64 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2018, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/**
* Module defining FullscreenAction. Created by vwoeltje on 11/18/14.
*/
define(
["screenfull"],
function (screenfull) {
var ENTER_FULLSCREEN = "Enter full screen mode",
EXIT_FULLSCREEN = "Exit full screen mode";
/**
* The fullscreen action toggles between fullscreen display
* and regular in-window display.
* @memberof platform/commonUI/browse
* @constructor
* @implements {Action}
*/
function FullscreenAction(context) {
this.context = context;
}
FullscreenAction.prototype.perform = function () {
screenfull.toggle();
};
FullscreenAction.prototype.getMetadata = function () {
// We override getMetadata, because the icon cssClass and
// description need to be determined at run-time
// based on whether or not we are currently
// full screen.
var metadata = Object.create(FullscreenAction);
metadata.cssClass = screenfull.isFullscreen ? "icon-fullscreen-expand" : "icon-fullscreen-collapse";
metadata.description = screenfull.isFullscreen ?
EXIT_FULLSCREEN : ENTER_FULLSCREEN;
metadata.group = "windowing";
metadata.context = this.context;
return metadata;
};
return FullscreenAction;
}
);

View File

@@ -19,7 +19,6 @@
* 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.
@@ -49,19 +48,9 @@ define(
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;
});
var calls = mockNavigationService.setNavigation.calls.length;
waitsFor(function () {
return mockNavigationService.setNavigation.calls.length > calls;
});
}
@@ -89,7 +78,7 @@ define(
"urlService",
["urlForLocation"]
);
mockUrlService.urlForLocation.and.callFake(function (mode, object) {
mockUrlService.urlForLocation.andCallFake(function (mode, object) {
if (object === mockDefaultRootObject) {
return [mode, testDefaultRoot].join('/');
}
@@ -117,7 +106,7 @@ define(
"removeListener"
].forEach(function (method) {
spyOn(mockNavigationService, method)
.and.callThrough();
.andCallThrough();
});
mockRootObject = jasmine.createSpyObj(
"rootObjectContainer",
@@ -135,31 +124,32 @@ define(
"nestedDomainObject",
["getId", "getCapability", "getModel", "useCapability", "hasCapability"]
);
mockObjectService.getObjects.and.returnValue(Promise.resolve({
mockObjectService.getObjects.andReturn(Promise.resolve({
ROOT: mockRootObject
}));
mockRootObject.useCapability.and.returnValue(Promise.resolve([
mockRootObject.useCapability.andReturn(Promise.resolve([
mockOtherDomainObject,
mockDefaultRootObject
]));
mockRootObject.hasCapability.and.returnValue(true);
mockDefaultRootObject.useCapability.and.returnValue(Promise.resolve([
mockRootObject.hasCapability.andReturn(true);
mockDefaultRootObject.useCapability.andReturn(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);
mockDefaultRootObject.hasCapability.andReturn(true);
mockOtherDomainObject.hasCapability.andReturn(false);
mockNextObject.useCapability.andReturn(undefined);
mockNextObject.hasCapability.andReturn(false);
mockNextObject.getId.andReturn("next");
mockDefaultRootObject.getId.andReturn(testDefaultRoot);
instantiateController();
return waitsForNavigation();
waitsForNavigation();
});
it("uses composition to set the navigated object, if there is none", function () {
instantiateController();
return waitsForNavigation().then(function () {
waitsForNavigation();
runs(function () {
expect(mockNavigationService.setNavigation)
.toHaveBeenCalledWith(mockDefaultRootObject);
});
@@ -167,26 +157,27 @@ define(
it("navigates to a root-level object, even when default path is not found", function () {
mockDefaultRootObject.getId
.and.returnValue("something-other-than-the-" + testDefaultRoot);
.andReturn("something-other-than-the-" + testDefaultRoot);
instantiateController();
return waitsForNavigation().then(function () {
waitsForNavigation();
runs(function () {
expect(mockNavigationService.setNavigation)
.toHaveBeenCalledWith(mockDefaultRootObject);
});
});
});
//
it("does not try to override navigation", function () {
mockNavigationService.getNavigation.and.returnValue(mockDefaultRootObject);
mockNavigationService.getNavigation.andReturn(mockDefaultRootObject);
instantiateController();
return waitsForNavigation().then(function () {
expect(mockScope.navigatedObject).toBe(mockDefaultRootObject);
});
waitsForNavigation();
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](
mockNavigationService.addListener.mostRecentCall.args[0](
mockOtherDomainObject
);
expect(mockScope.navigatedObject).toEqual(mockOtherDomainObject);
@@ -198,18 +189,19 @@ define(
"$destroy",
jasmine.any(Function)
);
mockScope.$on.calls.mostRecent().args[1]();
mockScope.$on.mostRecentCall.args[1]();
// Should remove the listener it added earlier
expect(mockNavigationService.removeListener).toHaveBeenCalledWith(
mockNavigationService.addListener.calls.mostRecent().args[0]
mockNavigationService.addListener.mostRecentCall.args[0]
);
});
it("uses route parameters to choose initially-navigated object", function () {
mockRoute.current.params.ids = testDefaultRoot + "/next";
instantiateController();
return waitsForNavigation().then(function () {
waitsForNavigation();
runs(function () {
expect(mockScope.navigatedObject).toBe(mockNextObject);
expect(mockNavigationService.setNavigation)
.toHaveBeenCalledWith(mockNextObject);
@@ -222,10 +214,12 @@ define(
// it hits an invalid ID.
mockRoute.current.params.ids = testDefaultRoot + "/junk";
instantiateController();
return waitsForNavigation().then(function () {
waitsForNavigation();
runs(function () {
expect(mockScope.navigatedObject).toBe(mockDefaultRootObject);
expect(mockNavigationService.setNavigation)
.toHaveBeenCalledWith(mockDefaultRootObject);
});
});
@@ -235,7 +229,8 @@ define(
// should stop at it since remaining IDs cannot be loaded.
mockRoute.current.params.ids = testDefaultRoot + "/next/junk";
instantiateController();
return waitsForNavigation().then(function () {
waitsForNavigation();
runs(function () {
expect(mockScope.navigatedObject).toBe(mockNextObject);
expect(mockNavigationService.setNavigation)
.toHaveBeenCalledWith(mockNextObject);
@@ -249,11 +244,11 @@ define(
expect(mockRoute.current.pathParams.ids)
.not
.toBe(testDefaultRoot + '/next');
mockLocation.path.and.callFake(function () {
mockLocation.path.andCallFake(function () {
expect(mockRoute.current.pathParams.ids)
.toBe(testDefaultRoot + '/next');
});
mockNavigationService.addListener.calls.mostRecent().args[0](
mockNavigationService.addListener.mostRecentCall.args[0](
mockNextObject
);
expect(mockLocation.path).toHaveBeenCalledWith(

View File

@@ -20,6 +20,7 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
define(
["../src/BrowseObjectController"],
function (BrowseObjectController) {
@@ -32,7 +33,7 @@ define(
// Utility function; look for a $watch on scope and fire it
function fireWatch(expr, value) {
mockScope.$watch.calls.all().forEach(function (call) {
mockScope.$watch.calls.forEach(function (call) {
if (call.args[0] === expr) {
call.args[1](value);
}
@@ -49,7 +50,7 @@ define(
"$location",
["path", "search"]
);
mockLocation.search.and.returnValue({});
mockLocation.search.andReturn({});
controller = new BrowseObjectController(
mockScope,
@@ -64,7 +65,7 @@ define(
// Allows the path index to be checked
// prior to setting $route.current
mockLocation.path.and.returnValue("/browse/");
mockLocation.path.andReturn("/browse/");
});
it("sets the active view from query parameters", function () {
@@ -78,10 +79,10 @@ define(
{ key: 'xyz' }
];
mockDomainObject.useCapability.and.callFake(function (c) {
mockDomainObject.useCapability.andCallFake(function (c) {
return (c === 'view') && testViews;
});
mockLocation.search.and.returnValue({ view: 'def' });
mockLocation.search.andReturn({ view: 'def' });
fireWatch('domainObject', mockDomainObject);
expect(mockScope.representation.selected)

View File

@@ -50,14 +50,14 @@ define(
"navigationService",
["getNavigation", "addListener"]
);
mockNavigationService.addListener.and.returnValue(mockNavigationUnlistener);
mockNavigationService.addListener.andReturn(mockNavigationUnlistener);
mockStatusUnlistener = jasmine.createSpy("statusUnlistener");
mockStatusCapability = jasmine.createSpyObj(
"statusCapability",
["listen"]
);
mockStatusCapability.listen.and.returnValue(mockStatusUnlistener);
mockStatusCapability.listen.andReturn(mockStatusUnlistener);
mockDomainObject = jasmine.createSpyObj(
'domainObject',
@@ -68,13 +68,13 @@ define(
'hasCapability'
]
);
mockDomainObject.getId.and.returnValue("domainObject");
mockDomainObject.getModel.and.returnValue({});
mockDomainObject.hasCapability.and.returnValue(true);
mockDomainObject.getCapability.and.returnValue(mockStatusCapability);
mockDomainObject.getId.andReturn("domainObject");
mockDomainObject.getModel.andReturn({});
mockDomainObject.hasCapability.andReturn(true);
mockDomainObject.getCapability.andReturn(mockStatusCapability);
mockLocation = jasmine.createSpyObj('location', ['search']);
mockLocation.search.and.returnValue({});
mockLocation.search.andReturn({});
mockAttrs = {};
@@ -84,7 +84,7 @@ define(
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);
mockNavigationService.addListener.mostRecentCall.args[0](mockDomainObject);
expect(mockStatusCapability.listen).toHaveBeenCalledWith(jasmine.any(Function));
});
@@ -93,8 +93,8 @@ define(
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"]);
mockNavigationService.addListener.mostRecentCall.args[0](mockDomainObject);
mockStatusCapability.listen.mostRecentCall.args[0](["editing"]);
expect(controller.visible()).toBe(true);
});

View File

@@ -60,8 +60,8 @@ define(
mockActionContext.domainObject = mockDomainObject;
mockActionContext.event = mockEvent;
mockScope.domainObject = mockDomainObject;
mockDomainObject.getCapability.and.returnValue(mockContextMenuAction);
mockContextMenuAction.perform.and.returnValue(jasmine.any(Function));
mockDomainObject.getCapability.andReturn(mockContextMenuAction);
mockContextMenuAction.perform.andReturn(jasmine.any(Function));
controller = new MenuArrowController(mockScope);
});

View File

@@ -39,7 +39,7 @@ define(
mockMutationCapability = jasmine.createSpyObj("mutation", ["mutate"]);
mockTypeCapability = jasmine.createSpyObj("type", ["typeDef", "hasFeature"]);
mockTypeCapability.typeDef = { name: ""};
mockTypeCapability.hasFeature.and.callFake(function (feature) {
mockTypeCapability.hasFeature.andCallFake(function (feature) {
return feature === 'creation';
});
@@ -52,8 +52,8 @@ define(
name: "Test name"
};
mockDomainObject = jasmine.createSpyObj("domainObject", ["getCapability", "getModel"]);
mockDomainObject.getModel.and.returnValue(model);
mockDomainObject.getCapability.and.callFake(function (key) {
mockDomainObject.getModel.andReturn(model);
mockDomainObject.getCapability.andCallFake(function (key) {
return mockCapabilities[key];
});
@@ -62,7 +62,7 @@ define(
};
mockCurrentTarget = jasmine.createSpyObj("currentTarget", ["blur", "textContent"]);
mockCurrentTarget.blur.and.returnValue(mockCurrentTarget);
mockCurrentTarget.blur.andReturn(mockCurrentTarget);
mockEvent = {
which: {},
@@ -109,7 +109,7 @@ define(
expect(mockMutationCapability.mutate).toHaveBeenCalledWith(jasmine.any(Function));
mockMutationCapability.mutate.calls.mostRecent().args[0](model);
mockMutationCapability.mutate.mostRecentCall.args[0](model);
expect(mockDomainObject.getModel().name).toBe("New name");
});
@@ -127,7 +127,7 @@ define(
});
it("disallows editting name when object is non-creatable", function () {
mockTypeCapability.hasFeature.and.returnValue(false);
mockTypeCapability.hasFeature.andReturn(false);
expect(controller.allowEdit()).toBe(false);

View File

@@ -27,6 +27,7 @@ define(
describe("The PaneController", function () {
var mockScope,
mockAgentService,
mockDomainObjects,
mockWindow,
controller,
mockLocation,
@@ -46,6 +47,17 @@ define(
beforeEach(function () {
mockScope = jasmine.createSpyObj("$scope", ["$on"]);
mockDomainObjects = ['a', 'b'].map(function (id) {
var mockDomainObject = jasmine.createSpyObj(
'domainObject-' + id,
['getId', 'getModel', 'getCapability']
);
mockDomainObject.getId.andReturn(id);
mockDomainObject.getModel.andReturn({});
return mockDomainObject;
});
mockAgentService = jasmine.createSpyObj(
"agentService",
["isMobile", "isPhone", "isTablet", "isPortrait", "isLandscape"]
@@ -53,7 +65,7 @@ define(
mockWindow = jasmine.createSpyObj("$window", ["open"]);
mockLocation = jasmine.createSpyObj('location', ['search']);
mockLocation.search.and.returnValue({});
mockLocation.search.andReturn({});
mockAttrs = {};
});
@@ -71,9 +83,9 @@ define(
});
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);
mockAgentService.isMobile.andReturn(true);
mockAgentService.isPhone.andReturn(true);
mockAgentService.isPortrait.andReturn(true);
controller = instantiateController();
expect(controller.visible()).toBeTruthy();
@@ -90,13 +102,13 @@ define(
});
it("sets pane state to false when in location.search", function () {
mockLocation.search.and.returnValue({'hideTree': true});
mockLocation.search.andReturn({'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({});
mockLocation.search.andReturn({});
expect(instantiateController().visible()).toBe(true);
expect(mockLocation.search).not.toHaveBeenCalledWith('hideTree', undefined);
});

View File

@@ -34,6 +34,17 @@ define([
mockDomainObject,
action;
function waitForCall() {
var called = false;
waitsFor(function () {
return called;
});
return function () {
called = true;
};
}
beforeEach(function () {
mockNavigationService = jasmine.createSpyObj(
"navigationService",
@@ -52,24 +63,26 @@ define([
});
it("sets navigation if it is allowed", function () {
mockNavigationService.shouldNavigate.and.returnValue(true);
return action.perform()
.then(function () {
expect(mockNavigationService.setNavigation)
.toHaveBeenCalledWith(mockDomainObject, true);
});
mockNavigationService.shouldNavigate.andReturn(true);
action.perform()
.then(waitForCall());
runs(function () {
expect(mockNavigationService.setNavigation)
.toHaveBeenCalledWith(mockDomainObject, true);
});
});
it("does not set navigation if it is not allowed", function () {
mockNavigationService.shouldNavigate.and.returnValue(false);
mockNavigationService.shouldNavigate.andReturn(false);
var onSuccess = jasmine.createSpy('onSuccess');
return action.perform()
.then(onSuccess, function () {
expect(onSuccess).not.toHaveBeenCalled();
expect(mockNavigationService.setNavigation)
.not
.toHaveBeenCalledWith(mockDomainObject);
});
action.perform()
.then(onSuccess, waitForCall());
runs(function () {
expect(onSuccess).not.toHaveBeenCalled();
expect(mockNavigationService.setNavigation)
.not
.toHaveBeenCalledWith(mockDomainObject);
});
});
it("is only applicable when a domain object is in context", function () {

View File

@@ -69,7 +69,7 @@ define(
navigationService.addListener(callback);
navigationService.setNavigation(testObject);
navigationService.setNavigation(testObject);
expect(callback.calls.count()).toEqual(1);
expect(callback.calls.length).toEqual(1);
});
it("stops notifying listeners after removal", function () {

View File

@@ -65,35 +65,34 @@ define([
mockActionCapability = jasmine.createSpyObj('action', ['perform']);
mockEditor = jasmine.createSpyObj('editor', ['isEditContextRoot']);
mockThrottle.and.callFake(function (fn) {
mockThrottle.andCallFake(function (fn) {
var mockThrottledFn =
jasmine.createSpy('throttled-' + mockThrottledFns.length);
mockThrottledFn.and.callFake(fn);
mockThrottledFn.andCallFake(fn);
mockThrottledFns.push(mockThrottledFn);
return mockThrottledFn;
});
mockTopic.and.returnValue(mockMutationTopic);
mockDomainObject.getId.and.returnValue(testId);
mockDomainObject.getCapability.and.callFake(function (c) {
mockTopic.andReturn(mockMutationTopic);
mockDomainObject.getId.andReturn(testId);
mockDomainObject.getCapability.andCallFake(function (c) {
return {
context: mockContext,
editor: mockEditor
}[c];
});
mockDomainObject.hasCapability.and.callFake(function (c) {
mockDomainObject.hasCapability.andCallFake(function (c) {
return !!mockDomainObject.getCapability(c);
});
mockParentObject.getCapability.and.callFake(function (c) {
mockParentObject.getCapability.andCallFake(function (c) {
return {
action: mockActionCapability
}[c];
});
testParentComposition = [];
mockParentObject.useCapability.and.returnValue(Promise.resolve(testParentComposition));
mockContext.getParent.and.returnValue(mockParentObject);
mockNavigationService.getNavigation.and.returnValue(mockDomainObject);
mockEditor.isEditContextRoot.and.returnValue(false);
mockParentObject.useCapability.andReturn(Promise.resolve(testParentComposition));
mockContext.getParent.andReturn(mockParentObject);
mockNavigationService.getNavigation.andReturn(mockDomainObject);
mockEditor.isEditContextRoot.andReturn(false);
return new OrphanNavigationHandler(
mockThrottle,
@@ -107,7 +106,7 @@ define([
expect(mockMutationTopic.listen)
.toHaveBeenCalledWith(jasmine.any(Function));
expect(mockThrottledFns.indexOf(
mockMutationTopic.listen.calls.mostRecent().args[0]
mockMutationTopic.listen.mostRecentCall.args[0]
)).not.toEqual(-1);
});
@@ -115,7 +114,7 @@ define([
expect(mockNavigationService.addListener)
.toHaveBeenCalledWith(jasmine.any(Function));
expect(mockThrottledFns.indexOf(
mockNavigationService.addListener.calls.mostRecent().args[0]
mockNavigationService.addListener.mostRecentCall.args[0]
)).not.toEqual(-1);
});
@@ -135,14 +134,28 @@ define([
function itNavigatesAsExpected() {
if (isOrphan && !isEditRoot) {
it("navigates to the parent", function () {
return Promise.resolve().then(function () {
var done = false;
waitsFor(function () {
return done;
});
setTimeout(function () {
done = true;
}, 5);
runs(function () {
expect(mockActionCapability.perform)
.toHaveBeenCalledWith('navigate');
});
});
} else {
it("does nothing", function () {
return Promise.resolve().then(function () {
var done = false;
waitsFor(function () {
return done;
});
setTimeout(function () {
done = true;
}, 5);
runs(function () {
expect(mockActionCapability.perform)
.not.toHaveBeenCalled();
});
@@ -152,12 +165,12 @@ define([
describe(caseName, function () {
beforeEach(function () {
mockEditor.isEditContextRoot.and.returnValue(isEditRoot);
mockEditor.isEditContextRoot.andReturn(isEditRoot);
});
describe("when navigation changes", function () {
beforeEach(function () {
mockNavigationService.addListener.calls.mostRecent()
mockNavigationService.addListener.mostRecentCall
.args[0](mockDomainObject);
});
itNavigatesAsExpected();
@@ -165,7 +178,7 @@ define([
describe("when mutation occurs", function () {
beforeEach(function () {
mockMutationTopic.listen.calls.mostRecent()
mockMutationTopic.listen.mostRecentCall
.args[0](mockParentObject);
});

View File

@@ -20,36 +20,40 @@
* at runtime from the About dialog for additional information.
*****************************************************************************/
define([
'./flexibleLayoutViewProvider',
'./utils/container',
'./toolbarProvider'
], function (
FlexibleLayoutViewProvider,
Container,
ToolBarProvider
) {
return function plugin() {
/**
* MCTRepresentationSpec. Created by vwoeltje on 11/6/14.
*/
define(
["../../src/windowing/FullscreenAction", "screenfull"],
function (FullscreenAction, screenfull) {
return function install(openmct) {
openmct.objectViews.addProvider(new FlexibleLayoutViewProvider(openmct));
describe("The fullscreen action", function () {
var action,
oldToggle;
openmct.types.addType('flexible-layout', {
name: "Flexible Layout",
creatable: true,
description: "A fluid, flexible layout canvas that can display multiple objects in rows or columns.",
cssClass: 'icon-flexible-layout',
initialize: function (domainObject) {
domainObject.configuration = {
containers: [new Container.default(50), new Container.default(50)],
rowsLayout: false
};
}
beforeEach(function () {
// Screenfull is not shimmed or injected, so
// we need to spy on it in the global scope.
oldToggle = screenfull.toggle;
screenfull.toggle = jasmine.createSpy("toggle");
action = new FullscreenAction({});
});
let toolbar = ToolBarProvider.default(openmct);
afterEach(function () {
screenfull.toggle = oldToggle;
});
openmct.toolbars.addProvider(toolbar);
};
};
});
it("toggles fullscreen mode when performed", function () {
action.perform();
expect(window.screenfull.toggle).toHaveBeenCalled();
});
it("provides displayable metadata", function () {
expect(action.getMetadata().cssClass).toBeDefined();
});
});
}
);

View File

@@ -46,7 +46,7 @@ define(
// tree is opened in a new tab using the
// context menu
mockContextSelected = jasmine.createSpyObj("context", ["selectedObject",
"domainObject"]);
"domainObject"]);
// Mocks the urlService used to make the new tab's url from a
// domainObject and mode
@@ -54,11 +54,11 @@ define(
// Action done using the current context or mockContextCurrent
actionCurrent = new NewTabAction(mockUrlService, mockWindow,
mockContextCurrent);
mockContextCurrent);
// Action done using the selected context or mockContextSelected
actionSelected = new NewTabAction(mockUrlService, mockWindow,
mockContextSelected);
mockContextSelected);
});

View File

@@ -32,7 +32,7 @@ define(
mockRootScope,
mockDocument,
mockDomainObject,
titler; // eslint-disable-line
titler;
beforeEach(function () {
mockNavigationService = jasmine.createSpyObj(
@@ -49,8 +49,8 @@ define(
);
mockDocument = [{}];
mockDomainObject.getModel.and.returnValue({ name: 'Test name' });
mockNavigationService.getNavigation.and.returnValue(mockDomainObject);
mockDomainObject.getModel.andReturn({ name: 'Test name' });
mockNavigationService.getNavigation.andReturn(mockDomainObject);
titler = new WindowTitler(
mockNavigationService,
@@ -64,12 +64,12 @@ define(
jasmine.any(Function),
jasmine.any(Function)
);
expect(mockRootScope.$watch.calls.mostRecent().args[0]())
expect(mockRootScope.$watch.mostRecentCall.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");
mockRootScope.$watch.mostRecentCall.args[1]("Some name");
expect(mockDocument[0].title).toEqual("Some name");
});

View File

@@ -23,13 +23,13 @@
define([
"./src/DialogService",
"./src/OverlayService",
"./res/templates/overlay-dialog.html",
"./res/templates/overlay-options.html",
"./res/templates/dialog.html",
"./res/templates/overlay-blocking-message.html",
"./res/templates/message.html",
"./res/templates/overlay-message-list.html",
"./res/templates/overlay.html",
"text!./res/templates/overlay-dialog.html",
"text!./res/templates/overlay-options.html",
"text!./res/templates/dialog.html",
"text!./res/templates/overlay-blocking-message.html",
"text!./res/templates/message.html",
"text!./res/templates/overlay-message-list.html",
"text!./res/templates/overlay.html",
'legacyRegistry'
], function (
DialogService,

View File

@@ -2,14 +2,28 @@
ng-class="'message-severity-' + ngModel.severity">
<div class="w-message-contents">
<div class="top-bar">
<div class="title">{{ngModel.message}}</div>
<div class="title">{{ngModel.title}}</div>
</div>
<div class="hint" ng-hide="ngModel.hint === undefined">{{ngModel.hint}}</div>
<div class="message-body">
<div class="message-action">
{{ngModel.actionText}}
</div>
<mct-include key="'progress-bar'"
ng-model="ngModel"
ng-show="ngModel.progressPerc !== undefined"></mct-include>
ng-show="ngModel.progress !== undefined || ngModel.unknownProgress"></mct-include>
</div>
<div class="bottom-bar">
<a ng-repeat="dialogOption in ngModel.options"
class="s-button"
ng-click="dialogOption.callback()">
{{dialogOption.label}}
</a>
<a class="s-button major"
ng-if="ngModel.primaryOption"
ng-click="ngModel.primaryOption.callback()">
{{ngModel.primaryOption.label}}
</a>
</div>
</div>
</div>

View File

@@ -95,10 +95,7 @@ define(
// 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);
this.findBody().prepend(element);
return {
dismiss: dismiss

View File

@@ -59,16 +59,16 @@ define(
["resolve", "reject"]
);
mockDocument = jasmine.createSpyObj(
"$document",
["find"]
"$document",
["find"]
);
mockBody = jasmine.createSpyObj('body', ['on', 'off']);
mockDocument.find.and.returnValue(mockBody);
mockDocument.find.andReturn(mockBody);
mockDeferred.promise = "mock promise";
mockQ.defer.and.returnValue(mockDeferred);
mockOverlayService.createOverlay.and.returnValue(mockOverlay);
mockQ.defer.andReturn(mockDeferred);
mockOverlayService.createOverlay.andReturn(mockOverlay);
dialogService = new DialogService(
mockOverlayService,
@@ -85,7 +85,7 @@ define(
it("allows user input to be canceled", function () {
dialogService.getUserInput({}, { someKey: "some value" });
mockOverlayService.createOverlay.calls.mostRecent().args[1].cancel();
mockOverlayService.createOverlay.mostRecentCall.args[1].cancel();
expect(mockDeferred.reject).toHaveBeenCalled();
expect(mockDeferred.resolve).not.toHaveBeenCalled();
});
@@ -93,7 +93,7 @@ define(
it("passes back the result of user input when confirmed", function () {
var value = { someKey: 42 };
dialogService.getUserInput({}, value);
mockOverlayService.createOverlay.calls.mostRecent().args[1].confirm();
mockOverlayService.createOverlay.mostRecentCall.args[1].confirm();
expect(mockDeferred.reject).not.toHaveBeenCalled();
expect(mockDeferred.resolve).toHaveBeenCalledWith(value);
});
@@ -109,7 +109,7 @@ define(
it("can show multiple dialogs if prior ones are dismissed", function () {
dialogService.getUserInput({}, {});
expect(mockLog.warn).not.toHaveBeenCalled();
mockOverlayService.createOverlay.calls.mostRecent().args[1].confirm();
mockOverlayService.createOverlay.mostRecentCall.args[1].confirm();
dialogService.getUserInput({}, {});
expect(mockLog.warn).not.toHaveBeenCalled();
expect(mockDeferred.reject).not.toHaveBeenCalled();
@@ -148,13 +148,13 @@ define(
it("destroys the event listener when the dialog is cancelled", function () {
dialogService.getUserInput({}, {});
mockOverlayService.createOverlay.calls.mostRecent().args[1].cancel();
mockOverlayService.createOverlay.mostRecentCall.args[1].cancel();
expect(mockBody.off).toHaveBeenCalledWith("keydown", jasmine.any(Function));
});
it("cancels the dialog when an escape keydown event is triggered", function () {
dialogService.getUserInput({}, {});
mockBody.on.calls.mostRecent().args[1]({
mockBody.on.mostRecentCall.args[1]({
keyCode: 27
});
expect(mockDeferred.reject).toHaveBeenCalled();
@@ -163,7 +163,7 @@ define(
it("ignores non escape keydown events", function () {
dialogService.getUserInput({}, {});
mockBody.on.calls.mostRecent().args[1]({
mockBody.on.mostRecentCall.args[1]({
keyCode: 13
});
expect(mockDeferred.reject).not.toHaveBeenCalled();
@@ -197,7 +197,7 @@ define(
"overlay",
["dismiss"]
);
mockOverlayService.createOverlay.and.returnValue(secondMockOverlay);
mockOverlayService.createOverlay.andReturn(secondMockOverlay);
secondDialogHandle = dialogService.showBlockingMessage(dialogModel);
//Dismiss the first dialog. It should only dismiss if it

View File

@@ -46,10 +46,10 @@ define(
mockElement = jasmine.createSpyObj("element", ["remove"]);
mockScope = jasmine.createSpyObj("scope", ["$destroy"]);
mockDocument.find.and.returnValue(mockBody);
mockCompile.and.returnValue(mockTemplate);
mockRootScope.$new.and.returnValue(mockScope);
mockTemplate.and.returnValue(mockElement);
mockDocument.find.andReturn(mockBody);
mockCompile.andReturn(mockTemplate);
mockRootScope.$new.andReturn(mockScope);
mockTemplate.andReturn(mockElement);
overlayService = new OverlayService(
mockDocument,
@@ -61,7 +61,7 @@ define(
it("prepends an mct-include to create overlays", function () {
overlayService.createOverlay("test", {});
expect(mockCompile).toHaveBeenCalled();
expect(mockCompile.calls.mostRecent().args[0].indexOf("mct-include"))
expect(mockCompile.mostRecentCall.args[0].indexOf("mct-include"))
.not.toEqual(-1);
});

View File

@@ -23,6 +23,7 @@
define([
"./src/controllers/EditActionController",
"./src/controllers/EditPanesController",
"./src/controllers/ElementsController",
"./src/controllers/EditObjectController",
"./src/actions/EditAndComposeAction",
"./src/actions/EditAction",
@@ -34,7 +35,11 @@ define([
"./src/actions/CancelAction",
"./src/policies/EditActionPolicy",
"./src/policies/EditPersistableObjectsPolicy",
"./src/policies/EditableLinkPolicy",
"./src/policies/EditableMovePolicy",
"./src/policies/EditContextualActionPolicy",
"./src/representers/EditRepresenter",
"./src/representers/EditToolbarRepresenter",
"./src/capabilities/EditorCapability",
"./src/capabilities/TransactionCapabilityDecorator",
"./src/services/TransactionManager",
@@ -43,18 +48,21 @@ define([
"./src/creation/LocatorController",
"./src/creation/CreationPolicy",
"./src/creation/CreateActionProvider",
"./src/creation/AddActionProvider",
"./src/creation/CreationService",
"./res/templates/create/locator.html",
"./res/templates/create/create-button.html",
"./res/templates/create/create-menu.html",
"./res/templates/library.html",
"./res/templates/edit-object.html",
"./res/templates/edit-action-buttons.html",
"./res/templates/topbar-edit.html",
"text!./res/templates/create/locator.html",
"text!./res/templates/create/create-button.html",
"text!./res/templates/create/create-menu.html",
"text!./res/templates/library.html",
"text!./res/templates/edit-object.html",
"text!./res/templates/edit-action-buttons.html",
"text!./res/templates/elements.html",
"text!./res/templates/topbar-edit.html",
'legacyRegistry'
], function (
EditActionController,
EditPanesController,
ElementsController,
EditObjectController,
EditAndComposeAction,
EditAction,
@@ -66,7 +74,11 @@ define([
CancelAction,
EditActionPolicy,
EditPersistableObjectsPolicy,
EditableLinkPolicy,
EditableMovePolicy,
EditContextualActionPolicy,
EditRepresenter,
EditToolbarRepresenter,
EditorCapability,
TransactionCapabilityDecorator,
TransactionManager,
@@ -75,6 +87,7 @@ define([
LocatorController,
CreationPolicy,
CreateActionProvider,
AddActionProvider,
CreationService,
locatorTemplate,
createButtonTemplate,
@@ -82,6 +95,7 @@ define([
libraryTemplate,
editObjectTemplate,
editActionButtonsTemplate,
elementsTemplate,
topbarEditTemplate,
legacyRegistry
) {
@@ -103,6 +117,14 @@ define([
"$scope"
]
},
{
"key": "ElementsController",
"implementation": ElementsController,
"depends": [
"$scope",
"openmct"
]
},
{
"key": "EditObjectController",
"implementation": EditObjectController,
@@ -168,7 +190,6 @@ define([
"name": "Remove",
"description": "Remove this object from its containing object.",
"depends": [
"openmct",
"navigationService"
]
},
@@ -205,10 +226,10 @@ define([
"description": "Save changes made to these objects.",
"depends": [
"$injector",
"policyService",
"dialogService",
"copyService",
"notificationService",
"openmct"
"notificationService"
],
"priority": "mandatory"
},
@@ -234,6 +255,19 @@ define([
"implementation": EditPersistableObjectsPolicy,
"depends": ["openmct"]
},
{
"category": "action",
"implementation": EditContextualActionPolicy,
"depends": ["navigationService", "editModeBlacklist", "nonEditContextBlacklist"]
},
{
"category": "action",
"implementation": EditableMovePolicy
},
{
"category": "action",
"implementation": EditableLinkPolicy
},
{
"implementation": CreationPolicy,
"category": "creation"
@@ -263,6 +297,13 @@ define([
"action"
]
},
{
"key": "edit-elements",
"template": elementsTemplate,
"gestures": [
"drop"
]
},
{
"key": "topbar-edit",
"template": topbarEditTemplate
@@ -310,6 +351,18 @@ define([
"policyService"
]
},
{
"key": "AddActionProvider",
"provides": "actionService",
"type": "provider",
"implementation": AddActionProvider,
"depends": [
"$q",
"typeService",
"dialogService",
"policyService"
]
},
{
"key": "CreationService",
"provides": "creationService",
@@ -328,6 +381,22 @@ define([
"depends": [
"$log"
]
},
{
"implementation": EditToolbarRepresenter,
"depends": [
"openmct"
]
}
],
"constants": [
{
"key": "editModeBlacklist",
"value": ["copy", "follow", "link", "locate"]
},
{
"key": "nonEditContextBlacklist",
"value": ["copy", "follow", "properties", "move", "link", "remove", "locate"]
}
],
"capabilities": [
@@ -337,8 +406,7 @@ define([
"description": "Provides transactional editing capabilities",
"implementation": EditorCapability,
"depends": [
"transactionService",
"openmct"
"transactionService"
]
}
],
@@ -356,17 +424,6 @@ define([
"transactionService"
]
}
],
"runs": [
{
depends: [
"toolbars[]",
"openmct"
],
implementation: function (toolbars, openmct) {
toolbars.forEach(openmct.toolbars.addProvider, openmct.toolbars);
}
}
]
}
});

View File

@@ -24,8 +24,7 @@
<div class="items-select left flex-elem l-flex-row grows">
<mct-representation key="'back-arrow'"
mct-object="domainObject"
class="flex-elem l-back">
</mct-representation>
class="flex-elem l-back"></mct-representation>
<mct-representation key="'object-header'"
mct-object="domainObject"
class="l-flex-row flex-elem grows object-header">
@@ -49,8 +48,8 @@
<!-- Toolbar and Save/Cancel buttons -->
<div class="l-edit-controls flex-elem l-flex-row flex-align-end">
<mct-toolbar name="mctToolbar"
structure="editToolbar.structure"
ng-model="editToolbar.state"
structure="toolbar.structure"
ng-model="toolbar.state"
class="flex-elem grows">
</mct-toolbar>
<mct-representation key="'edit-action-buttons'"
@@ -62,6 +61,7 @@
<mct-representation key="representation.selected.key"
mct-object="representation.selected.key && domainObject"
class="abs flex-elem grows object-holder-main scroll"
toolbar="toolbar"
mct-selectable="{
item: domainObject.useCapability('adapter'),
oldItem: domainObject

View File

@@ -0,0 +1,49 @@
<!--
Open MCT, Copyright (c) 2014-2018, United States Government
as represented by the Administrator of the National Aeronautics and Space
Administration. All rights reserved.
Open MCT is licensed under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations
under the License.
Open MCT includes source code licensed under additional open source
licenses. See the Open Source Licenses file (LICENSES.md) included with
this source code distribution or the Licensing information page available
at runtime from the About dialog for additional information.
-->
<div ng-controller="ElementsController" class="flex-elem l-flex-col holder grows">
<mct-include key="'input-filter'"
class="flex-elem holder"
ng-model="filterBy">
</mct-include>
<div class="flex-elem grows vscroll">
<ul class="tree" id="inspector-elements-tree"
ng-if="composition.length > 0">
<li ng-repeat="containedObject in composition | filter:searchElements">
<span class="tree-item">
<span class="grippy-sm"
ng-if="composition.length > 1"
data-id="{{ containedObject.id }}"
mct-drag-down="dragDown($event)"
mct-drag="drag($event)"
mct-drag-up="dragUp($event)">
</span>
<mct-representation
class="rep-object-label"
key="'label'"
mct-object="containedObject">
</mct-representation>
</span>
</li>
</ul>
<div ng-if="composition.length === 0">No contained elements</div>
</div>
</div>

View File

@@ -23,118 +23,111 @@
/**
* Module defining RemoveAction. Created by vwoeltje on 11/17/14.
*/
define([
'./RemoveDialog'
], function (
RemoveDialog
) {
define(
[],
function () {
/**
* 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.)
/**
* 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 {DomainObject} object the object to be removed
* @param {ActionContext} context the context in which this action is performed
* @memberof platform/commonUI/edit
* @constructor
* @implements {Action}
*/
function isNotObject(otherObjectId) {
return otherObjectId !== domainObject.getId();
function RemoveAction(navigationService, context) {
this.domainObject = (context || {}).domainObject;
this.navigationService = navigationService;
}
/*
* Mutate a parent object such that it no longer contains the object
* which is being removed.
/**
* Perform this action.
* @return {Promise} a promise which will be
* fulfilled when the action has completed.
*/
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();
RemoveAction.prototype.perform = function () {
var navigationService = this.navigationService,
domainObject = this.domainObject;
/*
* 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();
}
}
/*
* 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();
/*
* 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);
}
// If currently within path of removed object(s),
// navigates to existing object up tree
checkObjectNavigation(domainObject, parent);
/*
* 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;
return parent.useCapability('mutation', doMutate);
}
// 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();
}
}
/*
* 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();
};
/*
* 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(object) {
var contextCapability = object.getCapability('context'),
parent = contextCapability.getParent();
// 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');
// If currently within path of removed object(s),
// navigates to existing object up tree
checkObjectNavigation(object, parent);
// Only creatable types should be modifiable
return parent !== undefined &&
Array.isArray(parent.getModel().composition) &&
parentCreatable;
};
return parent.useCapability('mutation', doMutate);
}
return RemoveAction;
});
return removeFromContext(domainObject);
};
// 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;
}
);

View File

@@ -1,72 +0,0 @@
/*****************************************************************************
* 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;
});

View File

@@ -25,12 +25,12 @@ define([
'../creation/CreateWizard',
'./SaveInProgressDialog'
],
function (
CreateWizard,
SaveInProgressDialog
) {
function (
CreateWizard,
SaveInProgressDialog
) {
/**
/**
* The "Save" action; the action triggered by clicking Save from
* Edit Mode. Exits the editing user interface and invokes object
* capabilities to persist the changes that have been made.
@@ -38,189 +38,189 @@ function (
* @implements {Action}
* @memberof platform/commonUI/edit
*/
function SaveAsAction(
$injector,
dialogService,
copyService,
notificationService,
openmct,
context
) {
this.domainObject = (context || {}).domainObject;
this.injectObjectService = function () {
this.objectService = $injector.get("objectService");
};
this.dialogService = dialogService;
this.copyService = copyService;
this.notificationService = notificationService;
this.openmct = openmct;
}
/**
* @private
*/
SaveAsAction.prototype.createWizard = function (parent) {
return new CreateWizard(
this.domainObject,
parent,
this.openmct
);
};
/**
* @private
*/
SaveAsAction.prototype.getObjectService = function () {
// Lazily acquire object service (avoids cyclical dependency)
if (!this.objectService) {
this.injectObjectService();
function SaveAsAction(
$injector,
policyService,
dialogService,
copyService,
notificationService,
context
) {
this.domainObject = (context || {}).domainObject;
this.injectObjectService = function () {
this.objectService = $injector.get("objectService");
};
this.policyService = policyService;
this.dialogService = dialogService;
this.copyService = copyService;
this.notificationService = notificationService;
}
return this.objectService;
};
function resolveWith(object) {
return function () {
return object;
/**
* @private
*/
SaveAsAction.prototype.createWizard = function (parent) {
return new CreateWizard(
this.domainObject,
parent,
this.policyService
);
};
}
/**
/**
* @private
*/
SaveAsAction.prototype.getObjectService = function () {
// Lazily acquire object service (avoids cyclical dependency)
if (!this.objectService) {
this.injectObjectService();
}
return this.objectService;
};
function resolveWith(object) {
return function () {
return object;
};
}
/**
* Save changes and conclude editing.
*
* @returns {Promise} a promise that will be fulfilled when
* cancellation has completed
* @memberof platform/commonUI/edit.SaveAction#
*/
SaveAsAction.prototype.perform = function () {
// 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");
SaveAsAction.prototype.perform = function () {
// 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 object;
}
return this.save().then(returnToBrowse);
};
return this.save().then(returnToBrowse);
};
/**
/**
* @private
*/
SaveAsAction.prototype.save = function () {
var self = this,
domainObject = this.domainObject,
copyService = this.copyService,
dialog = new SaveInProgressDialog(this.dialogService),
toUndirty = [];
SaveAsAction.prototype.save = function () {
var self = this,
domainObject = this.domainObject,
copyService = this.copyService,
dialog = new SaveInProgressDialog(this.dialogService),
toUndirty = [];
function doWizardSave(parent) {
var wizard = self.createWizard(parent);
function doWizardSave(parent) {
var wizard = self.createWizard(parent);
return self.dialogService
.getUserInput(wizard.getFormStructure(true),
wizard.getInitialFormValue())
.then(wizard.populateObjectFromInput.bind(wizard), function (failureReason) {
return Promise.reject("user canceled");
return self.dialogService
.getUserInput(wizard.getFormStructure(true),
wizard.getInitialFormValue())
.then(wizard.populateObjectFromInput.bind(wizard), function (failureReason) {
return Promise.reject("user canceled");
});
}
function showBlockingDialog(object) {
dialog.show();
return object;
}
function hideBlockingDialog(object) {
dialog.hide();
return object;
}
function fetchObject(objectId) {
return self.getObjectService().getObjects([objectId]).then(function (objects) {
return objects[objectId];
});
}
}
function showBlockingDialog(object) {
dialog.show();
return object;
}
function getParent(object) {
return fetchObject(object.getModel().location);
}
function hideBlockingDialog(object) {
dialog.hide();
return object;
}
function fetchObject(objectId) {
return self.getObjectService().getObjects([objectId]).then(function (objects) {
return objects[objectId];
});
}
function getParent(object) {
return fetchObject(object.getModel().location);
}
function allowClone(objectToClone) {
var allowed =
function allowClone(objectToClone) {
var allowed =
(objectToClone.getId() === domainObject.getId()) ||
objectToClone.getCapability('location').isOriginal();
if (allowed) {
toUndirty.push(objectToClone);
if (allowed) {
toUndirty.push(objectToClone);
}
return allowed;
}
return allowed;
}
function cloneIntoParent(parent) {
return copyService.perform(domainObject, parent, allowClone);
}
function undirty(object) {
return object.getCapability('persistence').refresh();
}
function undirtyOriginals(object) {
return Promise.all(toUndirty.map(undirty))
.then(resolveWith(object));
}
function saveAfterClone(clonedObject) {
return domainObject.getCapability("editor").save()
.then(resolveWith(clonedObject));
}
function finishEditing(clonedObject) {
return domainObject.getCapability("editor").finish()
.then(function () {
return fetchObject(clonedObject.getId());
});
}
function onSuccess(object) {
self.notificationService.info("Save Succeeded");
return object;
}
function onFailure(reason) {
hideBlockingDialog();
if (reason !== "user canceled") {
self.notificationService.error("Save Failed");
function cloneIntoParent(parent) {
return copyService.perform(domainObject, parent, allowClone);
}
return false;
}
return getParent(domainObject)
.then(doWizardSave)
.then(showBlockingDialog)
.then(getParent)
.then(cloneIntoParent)
.then(undirtyOriginals)
.then(saveAfterClone)
.then(finishEditing)
.then(hideBlockingDialog)
.then(onSuccess)
.catch(onFailure);
};
function undirty(object) {
return object.getCapability('persistence').refresh();
}
function undirtyOriginals(object) {
return Promise.all(toUndirty.map(undirty))
.then(resolveWith(object));
}
function saveAfterClone(clonedObject) {
return domainObject.getCapability("editor").save()
.then(resolveWith(clonedObject));
}
function finishEditing(clonedObject) {
return domainObject.getCapability("editor").finish()
.then(function () {
return fetchObject(clonedObject.getId());
});
}
function onSuccess(object) {
self.notificationService.info("Save Succeeded");
return object;
}
function onFailure(reason) {
hideBlockingDialog();
if (reason !== "user canceled") {
self.notificationService.error("Save Failed");
}
return false;
}
return getParent(domainObject)
.then(doWizardSave)
.then(showBlockingDialog)
.then(getParent)
.then(cloneIntoParent)
.then(undirtyOriginals)
.then(saveAfterClone)
.then(finishEditing)
.then(hideBlockingDialog)
.then(onSuccess)
.catch(onFailure);
};
/**
/**
* Check if this action is applicable in a given context.
* This will ensure that a domain object is present in the context,
* and that this domain object is in Edit mode.
* @returns true if applicable
*/
SaveAsAction.appliesTo = function (context) {
var domainObject = (context || {}).domainObject;
return domainObject !== undefined &&
SaveAsAction.appliesTo = function (context) {
var domainObject = (context || {}).domainObject;
return domainObject !== undefined &&
domainObject.hasCapability('editor') &&
domainObject.getCapability('editor').isEditContextRoot() &&
domainObject.getModel().persisted === undefined;
};
};
return SaveAsAction;
}
return SaveAsAction;
}
);

View File

@@ -36,11 +36,9 @@ define(
*/
function EditorCapability(
transactionService,
openmct,
domainObject
) {
this.transactionService = transactionService;
this.openmct = openmct;
this.domainObject = domainObject;
}
@@ -50,22 +48,27 @@ define(
* or finish() are called.
*/
EditorCapability.prototype.edit = function () {
console.warn('DEPRECATED: cannot edit via edit capability, use openmct.editor instead.');
if (!this.openmct.editor.isEditing()) {
this.openmct.editor.edit();
this.domainObject.getCapability('status').set('editing', true);
}
this.transactionService.startTransaction();
this.domainObject.getCapability('status').set('editing', true);
};
function isEditContextRoot(domainObject) {
return domainObject.getCapability('status').get('editing');
}
function isEditing(domainObject) {
return isEditContextRoot(domainObject) ||
domainObject.hasCapability('context') &&
isEditing(domainObject.getCapability('context').getParent());
}
/**
* Determines whether this object, or any of its ancestors are
* currently being edited.
* @returns boolean
*/
EditorCapability.prototype.inEditContext = function () {
console.warn('DEPRECATION WARNING: isEditing checks must be done via openmct.editor.');
return this.openmct.editor.isEditing();
return isEditing(this.domainObject);
};
/**
@@ -74,8 +77,7 @@ define(
* @returns {*}
*/
EditorCapability.prototype.isEditContextRoot = function () {
console.warn('DEPRECATION WARNING: isEditing checks must be done via openmct.editor.');
return this.openmct.editor.isEditing();
return isEditContextRoot(this.domainObject);
};
/**
@@ -84,8 +86,10 @@ define(
* @returns {*}
*/
EditorCapability.prototype.save = function () {
console.warn('DEPRECATED: cannot save via edit capability, use openmct.editor instead.');
return Promise.resolve();
var transactionService = this.transactionService;
return transactionService.commit().then(function () {
transactionService.startTransaction();
});
};
EditorCapability.prototype.invoke = EditorCapability.prototype.edit;
@@ -96,8 +100,16 @@ define(
* @returns {*}
*/
EditorCapability.prototype.finish = function () {
console.warn('DEPRECATED: cannot finish via edit capability, use openmct.editor instead.');
return Promise.resolve();
var domainObject = this.domainObject;
if (this.transactionService.isActive()) {
return this.transactionService.cancel().then(function () {
domainObject.getCapability("status").set("editing", false);
return domainObject;
});
} else {
return Promise.resolve(domainObject);
}
};
/**

View File

@@ -49,8 +49,8 @@ define(
// present context.
function updateActions() {
$scope.saveActions = $scope.action ?
$scope.action.getActions(SAVE_ACTION_CONTEXT) :
[];
$scope.action.getActions(SAVE_ACTION_CONTEXT) :
[];
$scope.saveActionsAsMenuOptions = $scope.saveActions.map(actionToMenuOption);
@@ -59,8 +59,8 @@ define(
};
$scope.otherEditActions = $scope.action ?
$scope.action.getActions(OTHERS_ACTION_CONTEXT) :
[];
$scope.action.getActions(OTHERS_ACTION_CONTEXT) :
[];
// Required because Angular does not allow 'bind'
// in expressions.

View File

@@ -0,0 +1,197 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2018, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
define(
['zepto'],
function ($) {
/**
* The ElementsController prepares the elements view for display
*
* @constructor
*/
function ElementsController($scope, openmct) {
this.scope = $scope;
this.scope.composition = [];
this.openmct = openmct;
this.dragDown = this.dragDown.bind(this);
this.dragUp = this.dragUp.bind(this);
var self = this;
function filterBy(text) {
if (typeof text === 'undefined') {
return $scope.searchText;
} else {
$scope.searchText = text;
}
}
function searchElements(value) {
if ($scope.searchText) {
return value.getModel().name.toLowerCase().search(
$scope.searchText.toLowerCase()) !== -1;
} else {
return true;
}
}
function setSelection(selection) {
if (!selection[0]) {
return;
}
if (self.mutationListener) {
self.mutationListener();
delete self.mutationListener;
}
var domainObject = selection[0].context.oldItem;
self.refreshComposition(domainObject);
if (domainObject) {
self.mutationListener = domainObject.getCapability('mutation')
.listen(self.refreshComposition.bind(self, domainObject));
}
}
$scope.filterBy = filterBy;
$scope.searchElements = searchElements;
openmct.selection.on('change', setSelection);
setSelection(openmct.selection.get());
$scope.dragDown = this.dragDown;
$scope.drag = this.drag;
$scope.dragUp = this.dragUp;
$scope.$on("$destroy", function () {
openmct.selection.off("change", setSelection);
});
}
/**
* Invoked on DragStart - Adds reordering class to parent UL element
* Sets selected object ID, to be used on Drag End
*
* @param {object} event | Mouse Event
*/
ElementsController.prototype.dragDown = function (event) {
if (!this.parentUL) {
this.parentUL = $(document).find('#inspector-elements-tree');
}
this.selectedTreeItem = $(event.target).parent();
this.selectedObjectId = event.target.getAttribute('data-id');
this.parentUL.addClass('reordering');
this.selectedTreeItem.addClass('reorder-actor');
};
/**
* Invoked on dragEnd - Removes selected object from position in composition
* and replaces it at the target position. Composition is then updated with current
* scope
*
* @param {object} event - Mouse Event
*/
ElementsController.prototype.dragUp = function (event) {
this.targetObjectId = event.target.getAttribute('data-id');
if (this.targetObjectId && this.selectedObjectId) {
var selectedObjectPosition,
targetObjectPosition;
selectedObjectPosition = findObjectInCompositionFromId(this.selectedObjectId, this.scope.composition);
targetObjectPosition = findObjectInCompositionFromId(this.targetObjectId, this.scope.composition);
if ((selectedObjectPosition !== -1) && (targetObjectPosition !== -1)) {
var selectedObject = this.scope.composition.splice(selectedObjectPosition, 1),
selection = this.openmct.selection.get(),
domainObject = selection ? selection[0].context.oldItem : undefined;
this.scope.composition.splice(targetObjectPosition, 0, selectedObject[0]);
if (domainObject) {
domainObject.getCapability('mutation').mutate(function (model) {
model.composition = this.scope.composition.map(function (dObject) {
return dObject.id;
});
}.bind(this));
}
}
}
if (this.parentUL) {
this.parentUL.removeClass('reordering');
}
if (this.selectedTreeItem) {
this.selectedTreeItem.removeClass('reorder-actor');
}
};
ElementsController.prototype.drag = function (event) {
};
/**
* Gets the composition for the selected object and populates the scope with it.
*
* @param domainObject the selected object
* @private
*/
ElementsController.prototype.refreshComposition = function (domainObject) {
var refreshTracker = {};
this.currentRefresh = refreshTracker;
var selectedObjectComposition = domainObject && domainObject.useCapability('composition');
if (selectedObjectComposition) {
selectedObjectComposition.then(function (composition) {
if (this.currentRefresh === refreshTracker) {
this.scope.composition = composition;
}
}.bind(this));
} else {
this.scope.composition = [];
}
};
/**
* Finds position of object with given ID in Composition
*
* @param {String} id
* @param {Array} composition
* @private
*/
function findObjectInCompositionFromId(id, composition) {
var mapped = composition.map(function (element) {
return element.id;
});
return mapped.indexOf(id);
}
return ElementsController;
}
);

View File

@@ -0,0 +1,133 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2018, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/**
* Module defining AddAction. Created by ahenry on 01/21/16.
*/
define(
[
'./CreateWizard'
],
function (CreateWizard) {
/**
* The Add Action is performed to create new instances of
* domain objects of a specific type that are subobjects of an
* object being edited. This is the action that is performed when a
* user uses the Add menu option.
*
* @memberof platform/commonUI/browse
* @implements {Action}
* @constructor
*
* @param {Type} type the type of domain object to create
* @param {DomainObject} parent the domain object that should
* act as a container for the newly-created object
* (note that the user will have an opportunity to
* override this)
* @param {ActionContext} context the context in which the
* action is being performed
* @param {DialogService} dialogService
*/
function AddAction(type, parent, context, $q, dialogService, policyService) {
this.metadata = {
key: 'add',
cssClass: type.getCssClass(),
name: type.getName(),
type: type.getKey(),
description: type.getDescription(),
context: context
};
this.type = type;
this.parent = parent;
this.$q = $q;
this.dialogService = dialogService;
this.policyService = policyService;
}
/**
*
* Create a new object of the given type.
* This will prompt for user input first.
*
* @returns {Promise} that will be resolved with the object that the
* action was originally invoked on (ie. the 'parent')
*/
AddAction.prototype.perform = function () {
var newModel = this.type.getInitialModel(),
newObject,
parentObject = this.parent,
wizard;
newModel.type = this.type.getKey();
newObject = parentObject.getCapability('instantiation').instantiate(newModel);
newObject.useCapability('mutation', function (model) {
model.location = parentObject.getId();
});
wizard = new CreateWizard(newObject, this.parent, this.policyService);
function populateObjectFromInput(formValue) {
return wizard.populateObjectFromInput(formValue, newObject);
}
function persistAndReturn(domainObject) {
return domainObject.getCapability('persistence')
.persist()
.then(function () {
return domainObject;
});
}
function addToParent(populatedObject) {
parentObject.getCapability('composition').add(populatedObject);
return persistAndReturn(parentObject);
}
return this.dialogService
.getUserInput(wizard.getFormStructure(false), wizard.getInitialFormValue())
.then(populateObjectFromInput)
.then(persistAndReturn)
.then(addToParent);
};
/**
* Metadata associated with a Add action.
* @typedef {ActionMetadata} AddActionMetadata
* @property {string} type the key for the type of domain object
* to be created
*/
/**
* Get metadata about this action.
* @returns {AddActionMetadata} metadata about this action
*/
AddAction.prototype.getMetadata = function () {
return this.metadata;
};
return AddAction;
}
);

View File

@@ -0,0 +1,82 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2018, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/**
* Module defining AddActionProvider.js. Created by ahenry on 01/21/16.
*/
define(
["./AddAction"],
function (AddAction) {
/**
* The AddActionProvider is an ActionProvider which introduces
* an Add action for creating sub objects.
*
* @memberof platform/commonUI/browse
* @constructor
* @implements {ActionService}
*
* @param {TypeService} typeService the type service, used to discover
* available types
* @param {DialogService} dialogService the dialog service, used by
* specific Create actions to get user input to populate the
* model of the newly-created domain object.
* @param {CreationService} creationService the creation service (also
* introduced in this bundle), responsible for handling actual
* object creation.
*/
function AddActionProvider($q, typeService, dialogService, policyService) {
this.typeService = typeService;
this.dialogService = dialogService;
this.$q = $q;
this.policyService = policyService;
}
AddActionProvider.prototype.getActions = function (actionContext) {
var context = actionContext || {},
key = context.key,
destination = context.domainObject;
// We only provide Add actions, and we need a
// domain object to serve as the container for the
// newly-created object (although the user may later
// make a different selection)
if (key !== 'add' || !destination) {
return [];
}
// Introduce one create action per type
return ['timeline', 'activity'].map(function (type) {
return new AddAction(
this.typeService.getType(type),
destination,
context,
this.$q,
this.dialogService,
this.policyService
);
}, this);
};
return AddActionProvider;
}
);

View File

@@ -44,7 +44,7 @@ define(
* @param {ActionContext} context the context in which the
* action is being performed
*/
function CreateAction(type, parent, context, openmct) {
function CreateAction(type, parent, context) {
this.metadata = {
key: 'create',
cssClass: type.getCssClass(),
@@ -55,7 +55,6 @@ define(
};
this.type = type;
this.parent = parent;
this.openmct = openmct;
}
/**
@@ -64,28 +63,37 @@ define(
*/
CreateAction.prototype.perform = function () {
var newModel = this.type.getInitialModel(),
openmct = this.openmct,
newObject,
editAction;
editAction,
editorCapability;
function closeEditor() {
return editorCapability.finish();
}
function onSave() {
openmct.editor.save();
return editorCapability.save()
.then(closeEditor);
}
function onCancel() {
openmct.editor.cancel();
return closeEditor();
}
newModel.type = this.type.getKey();
newModel.location = this.parent.getId();
newObject = this.parent.useCapability('instantiation', newModel);
editorCapability = newObject.hasCapability('editor') && newObject.getCapability("editor");
openmct.editor.edit();
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.
//If an edit action is available, perform it
if (editAction) {
return editAction.perform();
} else if (editorCapability) {
//otherwise, use the save as action
editorCapability.edit();
return newObject.getCapability("action").perform("save-as").then(onSave, onCancel);
}
};

Some files were not shown because too many files have changed in this diff Show More