Compare commits

..

15 Commits

Author SHA1 Message Date
737ccc26b5 Mutate correct path for plot range
Mutate correct path on object for axis range.  Fixes #2182.
2018-11-06 17:34:20 -08:00
e9643ad07f Added brief readmes for all plugins. (#2184) 2018-10-03 18:55:27 -07:00
ca16892237 [cleanup] remove npm lodash (#2155)
remove npm lodash and unused scripts directory.  Removes usage of
lodash 3.10 in node files.
2018-08-31 12:04:16 -07:00
a2b0d350d8 Merge pull request #2151 from nasa/update-d3-deps
Updated d3 dependency paths
2018-08-27 13:17:19 -07:00
534bdbae50 Updated d3 dependency paths 2018-08-27 10:19:39 -07:00
831873e7de Updated README to remove misleading references to instabilities in API. (#2150) 2018-08-21 10:38:12 -07:00
622d246fdd Merge pull request #2129 from nasa/fixed-position-2125
[Fixed Position] Cannot add on objects when creating Fixed Position for the first time
2018-08-10 10:58:05 -07:00
4a1ca9f299 Remove stray characters 2018-08-10 10:10:15 -07:00
4e1de2678c Merge pull request #2134 from nasa/tables-2132
Change table row layout to use flex fixes #2132
2018-08-10 10:07:34 -07:00
33a4792531 do not show warning dialog when user moves an object from one location to another (#2142)
* dont show error dialog when user moves an object from one location to another

* add test for not showing blocking message on remove action

Fixes #2141
2018-08-10 10:06:40 -07:00
37dd4856a6 Merge pull request #2145 from nasa/import-export-links
Fixes Import / Export to work correctly with links and contained objects.
2018-08-10 10:05:28 -07:00
6a9cf3389d Fixes #2144. Identifiers for objects and links now exported as identifier objects.
Use keystring as map key on import. Also removed redundant step to re-add imported objects to parent composition.
2018-08-10 07:09:59 -07:00
2da2395473 Change table row layout to use flex
Fixes #2132
- flex styles applied;
- CSS reorganized for better DRY;
- Set height on <tr> so that <td>'s won't collapse when
all cells of a row have empty values. This can occur when columns are
hidden in a Telemetry Table.
2018-07-27 18:04:06 -07:00
00ecd27bb3 fixes #2130
fix lingering event listener that was caused by function (setSelection) being stored in two different locations, causing pointer mis match
2018-07-26 12:21:10 -07:00
0fa4486dcf force a click on the fixed position element after initialize to initialise Fixed Position controller on the selection API 2018-07-25 16:31:31 -07:00
554 changed files with 14196 additions and 19679 deletions

View File

@ -11,20 +11,24 @@ jobs:
name: Update npm name: Update npm
command: 'sudo npm install -g npm@latest' command: 'sudo npm install -g npm@latest'
- restore_cache: - restore_cache:
key: dependency-cache-{{ checksum "package.json" }} key: dependency-cache-{{ checksum "package.json" }}-{{ checksum "bower.json" }}
- run: - run:
name: Installing dependencies (npm install) name: Installing dependencies (npm install)
command: npm install command: npm install
- save_cache: - save_cache:
key: dependency-cache-{{ checksum "package.json" }} key: dependency-cache-{{ checksum "package.json" }}-{{ checksum "bower.json" }}
paths: paths:
- node_modules - node_modules
- bower_components
- run: - run:
name: npm run test name: npm run test
command: npm run test command: npm run test
- run: - run:
name: npm run lint name: npm run lint
command: npm run lint command: npm run lint
- run:
name: npm run checkstyle
command: npm run checkstyle
- store_artifacts: - store_artifacts:
path: dist path: dist
prefix: dist prefix: dist

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"
}

59
API.md
View File

@ -52,7 +52,6 @@
- [The URL Status Indicator](#the-url-status-indicator) - [The URL Status Indicator](#the-url-status-indicator)
- [Creating a Simple Indicator](#creating-a-simple-indicator) - [Creating a Simple Indicator](#creating-a-simple-indicator)
- [Custom Indicators](#custom-indicators) - [Custom Indicators](#custom-indicators)
- [Included Plugins](#included-plugins)
<!-- END doctoc generated TOC please keep comment here to allow auto update --> <!-- END doctoc generated TOC please keep comment here to allow auto update -->
@ -994,7 +993,7 @@ A common use case for indicators is to convey the state of some external system
persistence backend or HTTP server. So long as this system is accessible via HTTP request, 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 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 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 the [documentation](./src/plugins/URLIndicatorPlugin) for details on how to install and configure the
URL Status Indicator. URL Status Indicator.
### Creating a Simple Indicator ### Creating a Simple Indicator
@ -1046,59 +1045,3 @@ A completely custom indicator can be added by simple providing a DOM element to
element: domNode element: domNode
}); });
``` ```
## Included Plugins
Open MCT is packaged along with a few general-purpose plugins:
* `openmct.plugins.Conductor` provides a user interface for working with time
within the application. If activated, configuration must be provided. This is
detailed in the section on [Time Conductor Configuration](#time-conductor-configuration).
* `openmct.plugins.CouchDB` is an adapter for using CouchDB for persistence
of user-created objects. This is a constructor that takes the URL for the
CouchDB database as a parameter, e.g.
```javascript
openmct.install(openmct.plugins.CouchDB('http://localhost:5984/openmct'))
```
* `openmct.plugins.Elasticsearch` is an adapter for using Elasticsearch for
persistence of user-created objects. This is a
constructor that takes the URL for the Elasticsearch instance as a
parameter. eg.
```javascript
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
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)
- `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.plugins.LocalStorage` provides persistence of user-created
objects in browser-local storage. This is particularly useful in
development environments.
* `openmct.plugins.MyItems` adds a top-level folder named "My Items"
when the application is first started, providing a place for a
user to store created items.
* `openmct.plugins.UTCTimeSystem` provides a default time system for Open MCT.
Generally, you will want to either install these plugins, or install
different plugins that provide persistence and an initial folder
hierarchy.
eg.
```javascript
openmct.install(openmct.plugins.LocalStorage());
openmct.install(openmct.plugins.MyItems());
```

View File

@ -20,14 +20,8 @@ API. Open MCT is also being refactored to minimize the dependencies that using
Open MCT imposes on developers, such as the current requirement to use Open MCT imposes on developers, such as the current requirement to use
AngularJS. AngularJS.
This new API has not yet been heavily used and is likely to contain defects.
You can help by trying it out, and reporting any issues you encounter
using our GitHub issue tracker. Such issues may include bugs, suggestions,
missing documentation, or even just requests for help if you're having
trouble.
We want Open MCT to be as easy to use, install, run, and develop for as We want Open MCT to be as easy to use, install, run, and develop for as
possible, and your feedback will help us get there! possible, and your feedback will help us get there! Feedback can be provided via [GitHub issues](https://github.com/nasa/openmct/issues), or by emailing us at [arc-dl-openmct@nasa.gov](mailto:arc-dl-openmct@nasa.gov).
## Building and Running Open MCT Locally ## Building and Running Open MCT Locally
@ -84,6 +78,7 @@ Documentation will be generated in `target/docs`.
## Deploying Open MCT ## Deploying Open MCT
Open MCT is built using [`npm`](http://npmjs.com/) Open MCT is built using [`npm`](http://npmjs.com/)
and [`gulp`](http://gulpjs.com/).
To build Open MCT for deployment: To build Open MCT for deployment:
@ -93,13 +88,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 The contents of the `dist` folder will contain a runnable Open MCT
instance (e.g. by starting an HTTP server in that directory), including: instance (e.g. by starting an HTTP server in that directory), including:
* `openmct.js` - Open MCT source code. * A `main.js` file containing Open MCT source code.
* `openmct.css` - Basic styles to load to prevent a FOUC. * Various assets in the `example` and `platform` directories.
* `index.html`, an example to run Open MCT in the basic configuration. * 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
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: and run by [Karma](http://karma-runner.github.io). To run:
`npm test` `npm test`

129
app.js
View File

@ -7,72 +7,79 @@
* node app.js [options] * node app.js [options]
*/ */
(function () {
"use strict";
const options = require('minimist')(process.argv.slice(2)); var BUNDLE_FILE = 'bundles.json',
const express = require('express'); options = require('minimist')(process.argv.slice(2)),
const app = express(); express = require('express'),
const fs = require('fs'); app = express(),
const request = require('request'); fs = require('fs'),
request = require('request');
// Defaults // Defaults
options.port = options.port || options.p || 8080; options.port = options.port || options.p || 8080;
options.host = options.host || options.h || 'localhost'; options.host = options.host || options.h || 'localhost'
options.directory = options.directory || options.D || '.'; 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 // Show command line options
if (options.help || options.h) { if (options.help || options.h) {
console.log("\nUsage: node app.js [options]\n"); console.log("\nUsage: node app.js [options]\n");
console.log("Options:"); console.log("Options:");
console.log(" --help, -h Show this message."); console.log(" --help, -h Show this message.");
console.log(" --port, -p <number> Specify port."); console.log(" --port, -p <number> Specify port.");
console.log(" --directory, -D <bundle> Serve files from specified directory."); console.log(" --include, -i <bundle> Include the specified bundle.");
console.log(""); console.log(" --exclude, -x <bundle> Exclude the specified bundle.");
process.exit(0); 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',
webpackConfig.entry.openmct
];
const compiler = webpack(webpackConfig);
app.use(require('webpack-dev-middleware')(
compiler,
{
publicPath: '/dist',
logLevel: 'warn'
} }
));
app.use(require('webpack-hot-middleware')( app.disable('x-powered-by');
compiler,
{
} // Override bundles.json for HTTP requests
)); app.use('/' + BUNDLE_FILE, function (req, res) {
var bundles;
// Expose index.html for development users. try {
app.get('/', function (req, res) { bundles = JSON.parse(fs.readFileSync(BUNDLE_FILE, 'utf8'));
fs.createReadStream('index.html').pipe(res); } catch (e) {
}); bundles = [];
}
// Finally, open the HTTP server and log the instance to the console // Handle command line inclusions/exclusions
app.listen(options.port, options.host, function() { bundles = bundles.concat(options.include);
console.log('Open MCT application running at %s:%s', options.host, options.port) 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, options.host, function() {
console.log('Open MCT application running at %s:%s', options.host, options.port)
});
}());

27
bower.json Normal file
View File

@ -0,0 +1,27 @@
{
"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",
"moment-timezone": "^0.5.13"
}
}

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

@ -1,41 +1,24 @@
<!-- <!--
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 as represented by the Administrator of the National Aeronautics and Space
Administration. All rights reserved. Administration. All rights reserved.
Open MCT is licensed under the Apache License, Version 2.0 (the 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. "License"); you may not use this file except in compliance with the License.
You may obtain a copy of the License at You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0. http://www.apache.org/licenses/LICENSE-2.0.
Unless required by applicable law or agreed to in writing, software Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations License for the specific language governing permissions and limitations
under the License. under the License.
Open MCT includes source code licensed under additional open source Open MCT includes source code licensed under additional open source
licenses. See the Open Source Licenses file (LICENSES.md) included with licenses. See the Open Source Licenses file (LICENSES.md) included with
this source code distribution or the Licensing information page available this source code distribution or the Licensing information page available
at runtime from the About dialog for additional information. at runtime from the About dialog for additional information.
--> -->
<template> <p>Hello, world! I am the default route.</p>
<span id='status' class='status-holder'></span> <p ng-controller="ExampleController">My controller has told me: "{{phrase}}"</p>
</template> <span example-directive></span>
<style lang="scss">
</style>
<script>
export default {
inject: ['openmct'],
mounted() {
this.openmct.indicators.indicatorObjects.forEach((indicator) => {
// So that we can consistently position indicator elements,
// guarantee that they are wrapped in an element we control
var wrapperNode = document.createElement('span');
wrapperNode.className = 'l-indicator';
wrapperNode.appendChild(indicator.element);
this.$el.appendChild(wrapperNode);
});
}
}
</script>

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 * as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved. * Administration. All rights reserved.
* *
@ -19,16 +19,24 @@
* this source code distribution or the Licensing information page available * this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information. * at runtime from the About dialog for additional information.
*****************************************************************************/ *****************************************************************************/
/*global define*/ /*global define,Promise*/
define([ /**
<%= implPaths %> * Module defining ExampleController. Created by vwoeltje on 11/4/14.
'legacyRegistry' */
], function ( define(
<%= implNames %> [],
legacyRegistry function () {
) { "use strict";
"use strict";
legacyRegistry.register("<%= bundleName %>", <%= bundleContents %>); /**
}); *
* @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 * as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved. * Administration. All rights reserved.
* *
@ -19,23 +19,28 @@
* this source code distribution or the Licensing information page available * this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information. * at runtime from the About dialog for additional information.
*****************************************************************************/ *****************************************************************************/
/*global define,Promise*/
define(function () { /**
function DisplayLayoutType() { * Module defining ExampleService. Created by vwoeltje on 11/4/14.
return { */
name: "Display Layout", define(
creatable: true, [],
cssClass: 'icon-layout', function () {
initialize(domainObject) { "use strict";
domainObject.composition = [];
domainObject.configuration = { /**
layout: { *
panels: {} * @constructor
} */
}; function ExampleService() {
} return {
getMessage: function () {
return "I heard this from a service";
}
};
} }
}
return DisplayLayoutType; 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

@ -0,0 +1,46 @@
/*****************************************************************************
* 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 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

@ -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 * as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved. * Administration. All rights reserved.
* *
@ -19,19 +19,30 @@
* this source code distribution or the Licensing information page available * this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information. * at runtime from the About dialog for additional information.
*****************************************************************************/ *****************************************************************************/
/*global define,Promise*/
import CSV from 'comma-separated-values'; /**
import {saveAs} from 'file-saver/FileSaver'; * Module defining SomeProvider. Created by vwoeltje on 11/5/14.
*/
define(
[],
function () {
"use strict";
class CSVExporter { /**
export(rows, options) { *
let headers = (options && options.headers) || * @constructor
(Object.keys((rows[0] || {})).sort()); */
let filename = (options && options.filename) || "export.csv"; function SomeProvider() {
let csvText = new CSV(rows, { header: headers }).encode(); return {
let blob = new Blob([csvText], { type: "text/csv" }); getMessages: function () {
saveAs(blob, filename); return [
"I am a message from some provider."
];
}
};
}
return SomeProvider;
} }
}; );
export default CSVExporter;

View File

@ -27,11 +27,12 @@
* Modified by shale on 06/23/2015. * Modified by shale on 06/23/2015.
*/ */
define( define(
['../data/transcript.json'], ['text!../data/transcript.json'],
function (messages) { function (transcript) {
"use strict"; "use strict";
var firstObservedTime = Date.now(); var firstObservedTime = Date.now(),
messages = JSON.parse(transcript);
function EventTelemetry(request, interval) { function EventTelemetry(request, interval) {

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

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

View File

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

View File

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

View File

@ -51,26 +51,76 @@ define(
return actionTexts[Math.floor(Math.random()*3)]; 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'. * Launch a new notification with a severity level of 'Error'.
*/ */
$scope.newError = function () { $scope.newError = function(){
notificationService.notify({ notificationService.notify({
title: "Example error notification " + messageCounter++, title: "Example error notification " + messageCounter++,
hint: "An error has occurred", 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'. * Launch a new notification with a severity of 'Alert'.
*/ */
$scope.newAlert = function () { $scope.newAlert = function(){
notificationService.notify({ notificationService.notify({
title: "Alert notification " + (messageCounter++), title: "Alert notification " + (messageCounter++),
hint: "This is an alert message", hint: "This is an alert message",
severity: "alert", severity: "alert",
autoDismiss: true primaryOption: {
}); label: 'Retry',
callback: function() {
$log.info('Retry clicked');
}
},
options: getExampleActions()});
}; };
@ -78,38 +128,39 @@ define(
* Launch a new notification with a progress bar that is updated * Launch a new notification with a progress bar that is updated
* periodically, tracking an ongoing process. * periodically, tracking an ongoing process.
*/ */
$scope.newProgress = function () { $scope.newProgress = function(){
var notificationModel = { var notificationModel = {
title: "Progress notification example", title: "Progress notification example",
severity: "info", severity: "info",
progress: 0, progress: 0,
actionText: getExampleActionText() actionText: getExampleActionText(),
unknownProgress: false
}; };
/** /**
* Simulate an ongoing process and update the progress bar. * Simulate an ongoing process and update the progress bar.
* @param notification * @param notification
*/ */
function incrementProgress() { function incrementProgress(notificationModel) {
notificationModel.progress = Math.min(100, Math.floor(notificationModel.progress + Math.random() * 30)); notificationModel.progress = Math.min(100, Math.floor(notificationModel.progress + Math.random() * 30));
notificationModel.progressText = ["Estimated time" + notificationModel.progressText = ["Estimated time" +
" remaining:" + " remaining:" +
" about ", 60 - Math.floor((notificationModel.progress / 100) * 60), " seconds"].join(" "); " about ", 60 - Math.floor((notificationModel.progress / 100) * 60), " seconds"].join(" ");
if (notificationModel.progress < 100) { if (notificationModel.progress < 100) {
$timeout(function () { $timeout(function(){incrementProgress(notificationModel);}, 1000);
incrementProgress(notificationModel);
}, 1000);
} }
} }
notificationService.notify(notificationModel); notificationService.notify(notificationModel);
incrementProgress(); incrementProgress(notificationModel);
}; };
/** /**
* Launch a new notification with severity level of INFO. * Launch a new notification with severity level of INFO.
*/ */
$scope.newInfo = function () { $scope.newInfo = function(){
notificationService.info({ notificationService.info({
title: "Example Info notification " + messageCounter++ 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([ define([
"./src/ExampleStyleGuideModelProvider", "./src/ExampleStyleGuideModelProvider",
"./src/MCTExample", "./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' 'legacyRegistry'
], function ( ], function (
ExampleStyleGuideModelProvider, ExampleStyleGuideModelProvider,
MCTExample, MCTExample,
introTemplate,
standardsTemplate,
colorsTemplate,
statusTemplate,
glyphsTemplate,
controlsTemplate,
inputTemplate,
menusTemplate,
legacyRegistry legacyRegistry
) { ) {
legacyRegistry.register("example/styleguide", { legacyRegistry.register("example/styleguide", {
@ -39,14 +23,14 @@ define([
{ "key": "styleguide.menus", "name": "Menus", "cssClass": "icon-page", "description": "Context menus, dropdowns" } { "key": "styleguide.menus", "name": "Menus", "cssClass": "icon-page", "description": "Context menus, dropdowns" }
], ],
"views": [ "views": [
{ "key": "styleguide.intro", "type": "styleguide.intro", "template": introTemplate, "editable": false }, { "key": "styleguide.intro", "type": "styleguide.intro", "templateUrl": "templates/intro.html", "editable": false },
{ "key": "styleguide.standards", "type": "styleguide.standards", "template": standardsTemplate, "editable": false }, { "key": "styleguide.standards", "type": "styleguide.standards", "templateUrl": "templates/standards.html", "editable": false },
{ "key": "styleguide.colors", "type": "styleguide.colors", "template": colorsTemplate, "editable": false }, { "key": "styleguide.colors", "type": "styleguide.colors", "templateUrl": "templates/colors.html", "editable": false },
{ "key": "styleguide.status", "type": "styleguide.status", "template": statusTemplate, "editable": false }, { "key": "styleguide.status", "type": "styleguide.status", "templateUrl": "templates/status.html", "editable": false },
{ "key": "styleguide.glyphs", "type": "styleguide.glyphs", "template": glyphsTemplate, "editable": false }, { "key": "styleguide.glyphs", "type": "styleguide.glyphs", "templateUrl": "templates/glyphs.html", "editable": false },
{ "key": "styleguide.controls", "type": "styleguide.controls", "template": controlsTemplate, "editable": false }, { "key": "styleguide.controls", "type": "styleguide.controls", "templateUrl": "templates/controls.html", "editable": false },
{ "key": "styleguide.input", "type": "styleguide.input", "template": inputTemplate, "editable": false }, { "key": "styleguide.input", "type": "styleguide.input", "templateUrl": "templates/input.html", "editable": false },
{ "key": "styleguide.menus", "type": "styleguide.menus", "template": menusTemplate, "editable": false } { "key": "styleguide.menus", "type": "styleguide.menus", "templateUrl": "templates/menus.html", "editable": false }
], ],
"roots": [ "roots": [
{ {
@ -101,6 +85,16 @@ define([
"$q" "$q"
] ]
} }
],
"stylesheets": [
{
"stylesheetUrl": "css/style-guide-espresso.css",
"theme": "espresso"
},
{
"stylesheetUrl": "css/style-guide-snow.css",
"theme": "snow"
}
] ]
} }
}); });

View File

@ -20,6 +20,12 @@
* at runtime from the About dialog for additional information. * at runtime from the About dialog for additional information.
*****************************************************************************/ *****************************************************************************/
@import "bourbon"; @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 // Thematic constants
$colorCode: rgba(black, 0.2); $colorCode: rgba(black, 0.2);

View File

@ -20,6 +20,12 @@
* at runtime from the About dialog for additional information. * at runtime from the About dialog for additional information.
*****************************************************************************/ *****************************************************************************/
@import "bourbon"; @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 // Thematic constants
$colorCode: rgba(black, 0.1); $colorCode: rgba(black, 0.1);

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> <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>
<div class="col"> <div class="col">
<img src="../images/diagram-objects.svg" /> <img src="/example/styleguide/res/images/diagram-objects.svg" />
</div> </div>
</div> </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> <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>
<div class="col"> <div class="col">
<img src="../images/diagram-containment.svg" /> <img src="/example/styleguide/res/images/diagram-containment.svg" />
</div> </div>
</div> </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> <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>
<div class="col"> <div class="col">
<img src="../images/diagram-views.svg" /> <img src="/example/styleguide/res/images/diagram-views.svg" />
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,5 +1,5 @@
define([ define([
'../res/templates/mct-example.html' 'text!../res/templates/mct-example.html'
], function ( ], function (
MCTExampleTemplate 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

@ -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 * as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved. * Administration. All rights reserved.
* *
@ -19,44 +19,49 @@
* this source code distribution or the Licensing information page available * this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information. * at runtime from the About dialog for additional information.
*****************************************************************************/ *****************************************************************************/
define(function () { /*global define*/
class TelemetryTableColumn {
constructor (openmct, metadatum) {
this.metadatum = metadatum;
this.formatter = openmct.telemetry.getValueFormatter(metadatum);
this.titleValue = this.metadatum.name;
}
getKey() { define(
return this.metadatum.key; [],
} function () {
"use strict";
getTitle() { /**
return this.metadatum.name; * Displays Fibonacci numbers in the status area.
} * @constructor
*/
function FibonacciIndicator(workerService, $rootScope) {
var latest,
counter = 0,
worker = workerService.run('example.fibonacci');
getMetadatum() { function requestNext() {
return this.metadatum; worker.postMessage([counter]);
} counter += 1;
hasValueForDatum(telemetryDatum) {
return telemetryDatum.hasOwnProperty(this.metadatum.source);
}
getRawValue(telemetryDatum) {
return telemetryDatum[this.metadatum.source];
}
getFormattedValue(telemetryDatum) {
let formattedValue = this.formatter.format(telemetryDatum);
if (typeof formattedValue !== 'string') {
return formattedValue.toString();
} else {
return formattedValue;
} }
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;
}
return TelemetryTableColumn; );
});

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));
};
}());

181
gulpfile.js Normal file
View File

@ -0,0 +1,181 @@
/*****************************************************************************
* 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'),
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, function () {});
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,58 +26,66 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0, shrink-to-fit=no"> <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"> <meta name="apple-mobile-web-app-capable" content="yes">
<title></title> <title></title>
<script src="dist/openmct.js"></script> <script src="bower_components/requirejs/require.js"> </script>
<link rel="stylesheet" href="dist/openmct.css"> <script>
<link rel="icon" type="image/png" href="dist/favicons/favicon-32x32.png" sizes="32x32"> var THIRTY_MINUTES = 30 * 60 * 1000;
<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"> require(['openmct'], function (openmct) {
<link rel="shortcut icon" href="dist/favicons/favicon.ico"> [
'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.Notebook());
openmct.time.clock('local', {start: -THIRTY_MINUTES, end: 0});
openmct.time.timeSystem('utc');
openmct.start();
window.openmct = openmct;
});
</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">
</head> </head>
<body> <body>
<div class="l-splash-holder s-splash-holder">
<div class="l-splash s-splash"></div>
</div>
</body> </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.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.time.clock('local', {start: -THIRTY_MINUTES, end: 0});
openmct.time.timeSystem('utc');
openmct.start();
</script>
</html> </html>

View File

@ -21,40 +21,70 @@
*****************************************************************************/ *****************************************************************************/
/*global module,process*/ /*global module,process*/
module.exports = function(config) {
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'
});
}
config.set({ config.set({
// Base path that will be used to resolve all file patterns.
basePath: '', 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: [ files: [
'platform/**/*Spec.js', {pattern: 'bower_components/**/*.js', included: false},
'src/**/*Spec.js' {pattern: 'node_modules/d3-*/**/*.js', included: false},
{pattern: 'node_modules/vue/**/*.js', included: false},
{pattern: 'node_modules/printj/dist/*.js', included: false},
{pattern: 'src/**/*', included: false},
{pattern: 'node_modules/painterro/build/*.js', included: false},
{pattern: 'node_modules/html2canvas/dist/*', 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'],
// Web server port.
port: 9876, port: 9876,
reporters: [
'progress', // Wnable / disable colors in the output (reporters and logs).
'coverage',
'html'
],
browsers: ['ChromeHeadless'],
colors: true, colors: true,
logLevel: config.LOG_INFO, logLevel: config.LOG_INFO,
// Rerun tests when any file changes.
autoWatch: true, autoWatch: true,
// Specify browsers to run tests in.
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
browsers: [
'ChromeHeadless'
],
// Code coverage reporting.
coverageReporter: { coverageReporter: {
dir: process.env.CIRCLE_ARTIFACTS ? dir: process.env.CIRCLE_ARTIFACTS ?
process.env.CIRCLE_ARTIFACTS + '/coverage' : process.env.CIRCLE_ARTIFACTS + '/coverage' :
@ -74,19 +104,8 @@ module.exports = (config) => {
foldAll: false foldAll: false
}, },
preprocessors: { // Continuous Integration mode.
// add webpack as preprocessor // If true, Karma captures browsers, runs the tests and exits.
'platform/**/*Spec.js': [ 'webpack' ],
'src/**/*Spec.js': [ 'webpack' ]
},
webpack: webpackConfig,
webpackMiddleware: {
stats: 'errors-only',
logLevel: 'warn'
},
singleRun: true singleRun: true
}); });
} };

View File

@ -19,19 +19,102 @@
* this source code distribution or the Licensing information page available * this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information. * at runtime from the About dialog for additional information.
*****************************************************************************/ *****************************************************************************/
/*global module,BUILD_CONSTANTS*/ /*global requirejs,BUILD_CONSTANTS*/
const matcher = /\/openmct.js$/; requirejs.config({
if (document.currentScript) { "paths": {
let src = document.currentScript.src; "legacyRegistry": "src/legacyRegistry",
if (src && matcher.test(src)) { "angular": "bower_components/angular/angular.min",
// eslint-disable-next-line no-undef "angular-route": "bower_components/angular-route/angular-route.min",
__webpack_public_path__ = src.replace(matcher, '') + '/'; "csv": "bower_components/comma-separated-values/csv.min",
"EventEmitter": "bower_components/eventemitter3/index",
"es6-promise": "bower_components/es6-promise/es6-promise.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/dist/d3-axis.min",
"d3-array": "node_modules/d3-array/dist/d3-array.min",
"d3-collection": "node_modules/d3-collection/dist/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/dist/d3-time.min",
"d3-time-format": "node_modules/d3-time-format/dist/d3-time-format.min",
"html2canvas": "node_modules/html2canvas/dist/html2canvas.min",
"painterro": "node_modules/painterro/build/painterro.min",
"printj": "node_modules/printj/dist/printj.min"
},
"shim": {
"angular": {
"exports": "angular"
},
"angular-route": {
"deps": ["angular"]
},
"EventEmitter": {
"exports": "EventEmitter"
},
"moment-duration-format": {
"deps": ["moment"]
},
"painterro": {
"exports": "Painterro"
},
"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"
},
"dom-to-image": {
"exports": "domtoimage"
}
} }
} });
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

@ -1,16 +1,8 @@
{ {
"name": "openmct", "name": "openmct",
"version": "0.14.0-SNAPSHOT", "version": "0.14.0-SNAPSHOT",
"description": "The Open MCT core platform", "description": "The Open MCT core platform.",
"dependencies": {}, "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",
"d3-array": "1.2.x", "d3-array": "1.2.x",
"d3-axis": "1.0.x", "d3-axis": "1.0.x",
"d3-collection": "1.0.x", "d3-collection": "1.0.x",
@ -21,70 +13,58 @@
"d3-selection": "1.3.x", "d3-selection": "1.3.x",
"d3-time": "1.0.x", "d3-time": "1.0.x",
"d3-time-format": "2.1.x", "d3-time-format": "2.1.x",
"eslint": "5.2.0",
"eventemitter3": "^1.2.0",
"exports-loader": "^0.7.0",
"express": "^4.13.1", "express": "^4.13.1",
"fast-sass-loader": "^1.4.5", "minimist": "^1.1.1",
"file-loader": "^1.1.11", "painterro": "^0.2.65",
"file-saver": "^1.3.8", "request": "^2.69.0",
"vue": "^2.5.6"
},
"devDependencies": {
"bower": "^1.7.7",
"git-rev-sync": "^1.4.0", "git-rev-sync": "^1.4.0",
"glob": ">= 3.0.0", "glob": ">= 3.0.0",
"html-loader": "^0.5.5", "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",
"html2canvas": "^1.0.0-alpha.12", "html2canvas": "^1.0.0-alpha.12",
"imports-loader": "^0.8.0",
"istanbul-instrumenter-loader": "^3.0.1",
"jasmine-core": "^3.1.0", "jasmine-core": "^3.1.0",
"jscs-html-reporter": "^0.1.0",
"jsdoc": "^3.3.2", "jsdoc": "^3.3.2",
"jshint": "^2.7.0",
"karma": "^2.0.3", "karma": "^2.0.3",
"karma-chrome-launcher": "^2.2.0", "karma-chrome-launcher": "^2.2.0",
"karma-cli": "^1.0.1", "karma-cli": "^1.0.1",
"karma-coverage": "^1.1.2", "karma-coverage": "^1.1.2",
"karma-html-reporter": "^0.2.7", "karma-html-reporter": "^0.2.7",
"karma-jasmine": "^1.1.2", "karma-jasmine": "^1.1.2",
"karma-webpack": "^3.0.0", "karma-requirejs": "^1.1.0",
"location-bar": "^3.0.1",
"lodash": "^3.10.1",
"markdown-toc": "^0.11.7", "markdown-toc": "^0.11.7",
"marked": "^0.3.5", "marked": "^0.3.5",
"mini-css-extract-plugin": "^0.4.1", "merge-stream": "^1.0.0",
"minimist": "^1.1.1", "mkdirp": "^0.5.1",
"moment": "^2.11.1", "moment": "^2.11.1",
"moment-duration-format": "^2.2.2",
"moment-timezone": "^0.5.21",
"node-bourbon": "^4.2.3", "node-bourbon": "^4.2.3",
"node-sass": "^4.9.2",
"painterro": "^0.2.65",
"printj": "^1.1.0", "printj": "^1.1.0",
"raw-loader": "^0.5.1", "requirejs": "2.1.x",
"request": "^2.69.0",
"screenfull": "^3.3.2",
"split": "^1.0.0", "split": "^1.0.0",
"style-loader": "^0.21.0", "v8-compile-cache": "^1.1.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"
}, },
"scripts": { "scripts": {
"start": "node app.js", "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": "karma start --single-run",
"test:watch": "karma start --no-single-run", "jshint": "jshint platform example",
"verify": "concurrently 'npm:test' 'npm:lint'", "lint": "./node_modules/gulp/bin/gulp.js lint",
"checkstyle": "./node_modules/gulp/bin/gulp.js checkstyle",
"watch": "karma start",
"jsdoc": "jsdoc -c jsdoc.json -R API.md -r -d dist/docs/api", "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'", "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", "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": { "repository": {
"type": "git", "type": "git",

View File

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

View File

@ -33,14 +33,16 @@ define([
"./src/windowing/NewTabAction", "./src/windowing/NewTabAction",
"./src/windowing/FullscreenAction", "./src/windowing/FullscreenAction",
"./src/windowing/WindowTitler", "./src/windowing/WindowTitler",
"./res/templates/browse.html", "text!./res/templates/browse.html",
"./res/templates/browse-object.html", "text!./res/templates/browse-object.html",
"./res/templates/browse/object-header.html", "text!./res/templates/items/grid-item.html",
"./res/templates/browse/object-header-frame.html", "text!./res/templates/browse/object-header.html",
"./res/templates/menu-arrow.html", "text!./res/templates/browse/object-header-frame.html",
"./res/templates/back-arrow.html", "text!./res/templates/menu-arrow.html",
"./res/templates/browse/object-properties.html", "text!./res/templates/back-arrow.html",
"./res/templates/browse/inspector-region.html", "text!./res/templates/items/items.html",
"text!./res/templates/browse/object-properties.html",
"text!./res/templates/browse/inspector-region.html",
'legacyRegistry' 'legacyRegistry'
], function ( ], function (
BrowseController, BrowseController,
@ -57,10 +59,12 @@ define([
WindowTitler, WindowTitler,
browseTemplate, browseTemplate,
browseObjectTemplate, browseObjectTemplate,
gridItemTemplate,
objectHeaderTemplate, objectHeaderTemplate,
objectHeaderFrameTemplate, objectHeaderFrameTemplate,
menuArrowTemplate, menuArrowTemplate,
backArrowTemplate, backArrowTemplate,
itemsTemplate,
objectPropertiesTemplate, objectPropertiesTemplate,
inspectorRegionTemplate, inspectorRegionTemplate,
legacyRegistry legacyRegistry
@ -69,6 +73,15 @@ define([
legacyRegistry.register("platform/commonUI/browse", { legacyRegistry.register("platform/commonUI/browse", {
"extensions": { "extensions": {
"routes": [ "routes": [
{
"when": "/browse/:ids*?",
"template": browseTemplate,
"reloadOnSearch": false
},
{
"when": "",
"redirectTo": "/browse/"
}
], ],
"constants": [ "constants": [
{ {
@ -152,6 +165,19 @@ define([
"view" "view"
] ]
}, },
{
"key": "grid-item",
"template": gridItemTemplate,
"uses": [
"type",
"action",
"location"
],
"gestures": [
"info",
"menu"
]
},
{ {
"key": "object-header", "key": "object-header",
"template": objectHeaderTemplate, "template": objectHeaderTemplate,
@ -234,6 +260,23 @@ define([
"priority": "default" "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": [ "runs": [
{ {
"implementation": WindowTitler, "implementation": WindowTitler,
@ -252,20 +295,6 @@ define([
] ]
} }
], ],
"templates": [
{
key: "browseRoot",
template: browseTemplate
},
{
key: "browseObject",
template: browseObjectTemplate
},
{
key: "inspectorRegion",
template: inspectorRegionTemplate
}
],
"licenses": [ "licenses": [
{ {
"name": "screenfull.js", "name": "screenfull.js",

View File

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

@ -19,3 +19,9 @@
this source code distribution or the Licensing information page available this source code distribution or the Licensing information page available
at runtime from the About dialog for additional information. at runtime from the About dialog for additional information.
--> -->
<div class='items-holder grid abs'>
<mct-representation key="'grid-item'"
ng-repeat="childObject in composition"
mct-object="childObject">
</mct-representation>
</div>

View File

@ -47,7 +47,6 @@ define(
urlService, urlService,
defaultPath defaultPath
) { ) {
window.browseScope = $scope;
var initialPath = ($route.current.params.ids || defaultPath).split("/"), var initialPath = ($route.current.params.ids || defaultPath).split("/"),
currentIds; currentIds;

View File

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

View File

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

View File

@ -161,7 +161,7 @@ define(
instantiateController(); instantiateController();
return waitsForNavigation().then(function () { return waitsForNavigation().then(function () {
expect(mockNavigationService.setNavigation) expect(mockNavigationService.setNavigation)
.toHaveBeenCalledWith(mockDefaultRootObject); .toHaveBeenCalledWith(mockDefaultRootObject);
}); });
}); });
@ -172,7 +172,7 @@ define(
return waitsForNavigation().then(function () { return waitsForNavigation().then(function () {
expect(mockNavigationService.setNavigation) expect(mockNavigationService.setNavigation)
.toHaveBeenCalledWith(mockDefaultRootObject); .toHaveBeenCalledWith(mockDefaultRootObject);
}); });
}); });

View File

@ -27,6 +27,7 @@ define(
describe("The PaneController", function () { describe("The PaneController", function () {
var mockScope, var mockScope,
mockAgentService, mockAgentService,
mockDomainObjects,
mockWindow, mockWindow,
controller, controller,
mockLocation, mockLocation,
@ -46,6 +47,17 @@ define(
beforeEach(function () { beforeEach(function () {
mockScope = jasmine.createSpyObj("$scope", ["$on"]); mockScope = jasmine.createSpyObj("$scope", ["$on"]);
mockDomainObjects = ['a', 'b'].map(function (id) {
var mockDomainObject = jasmine.createSpyObj(
'domainObject-' + id,
['getId', 'getModel', 'getCapability']
);
mockDomainObject.getId.and.returnValue(id);
mockDomainObject.getModel.and.returnValue({});
return mockDomainObject;
});
mockAgentService = jasmine.createSpyObj( mockAgentService = jasmine.createSpyObj(
"agentService", "agentService",
["isMobile", "isPhone", "isTablet", "isPortrait", "isLandscape"] ["isMobile", "isPhone", "isTablet", "isPortrait", "isLandscape"]

View File

@ -56,7 +56,7 @@ define([
return action.perform() return action.perform()
.then(function () { .then(function () {
expect(mockNavigationService.setNavigation) expect(mockNavigationService.setNavigation)
.toHaveBeenCalledWith(mockDomainObject, true); .toHaveBeenCalledWith(mockDomainObject, true);
}); });
}); });

View File

@ -47,7 +47,7 @@ define(
it("toggles fullscreen mode when performed", function () { it("toggles fullscreen mode when performed", function () {
action.perform(); action.perform();
expect(screenfull.toggle).toHaveBeenCalled(); expect(window.screenfull.toggle).toHaveBeenCalled();
}); });
it("provides displayable metadata", function () { it("provides displayable metadata", function () {

View File

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

View File

@ -32,7 +32,7 @@ define(
mockRootScope, mockRootScope,
mockDocument, mockDocument,
mockDomainObject, mockDomainObject,
titler; // eslint-disable-line titler;
beforeEach(function () { beforeEach(function () {
mockNavigationService = jasmine.createSpyObj( mockNavigationService = jasmine.createSpyObj(

View File

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

View File

@ -59,8 +59,8 @@ define(
["resolve", "reject"] ["resolve", "reject"]
); );
mockDocument = jasmine.createSpyObj( mockDocument = jasmine.createSpyObj(
"$document", "$document",
["find"] ["find"]
); );
mockBody = jasmine.createSpyObj('body', ['on', 'off']); mockBody = jasmine.createSpyObj('body', ['on', 'off']);
mockDocument.find.and.returnValue(mockBody); mockDocument.find.and.returnValue(mockBody);

View File

@ -49,14 +49,14 @@ define([
"./src/creation/CreateActionProvider", "./src/creation/CreateActionProvider",
"./src/creation/AddActionProvider", "./src/creation/AddActionProvider",
"./src/creation/CreationService", "./src/creation/CreationService",
"./res/templates/create/locator.html", "text!./res/templates/create/locator.html",
"./res/templates/create/create-button.html", "text!./res/templates/create/create-button.html",
"./res/templates/create/create-menu.html", "text!./res/templates/create/create-menu.html",
"./res/templates/library.html", "text!./res/templates/library.html",
"./res/templates/edit-object.html", "text!./res/templates/edit-object.html",
"./res/templates/edit-action-buttons.html", "text!./res/templates/edit-action-buttons.html",
"./res/templates/elements.html", "text!./res/templates/elements.html",
"./res/templates/topbar-edit.html", "text!./res/templates/topbar-edit.html",
'legacyRegistry' 'legacyRegistry'
], function ( ], function (
EditActionController, EditActionController,
@ -319,12 +319,6 @@ define([
] ]
} }
], ],
"templates": [
{
key: "elementsPool",
template: elementsTemplate
}
],
"components": [ "components": [
{ {
"type": "decorator", "type": "decorator",
@ -405,8 +399,7 @@ define([
"description": "Provides transactional editing capabilities", "description": "Provides transactional editing capabilities",
"implementation": EditorCapability, "implementation": EditorCapability,
"depends": [ "depends": [
"transactionService", "transactionService"
"openmct"
] ]
} }
], ],

View File

@ -51,7 +51,7 @@ define([
/** /**
* Perform this action. * Perform this action.
*/ */
RemoveAction.prototype.perform = function () { RemoveAction.prototype.perform = function (skipWarning) {
var dialog, var dialog,
dialogService = this.dialogService, dialogService = this.dialogService,
domainObject = this.domainObject, domainObject = this.domainObject,
@ -115,12 +115,18 @@ define([
return parent.useCapability('mutation', doMutate); return parent.useCapability('mutation', doMutate);
} }
/* if (skipWarning) {
* Pass in the function to remove the domain object so it can be
* associated with an 'OK' button press removeFromContext(domainObject);
*/
dialog = new RemoveDialog(dialogService, domainObject, removeFromContext); } else {
dialog.show(); /*
* Pass in the function to remove the domain object so it can be
* associated with an 'OK' button press
*/
dialog = new RemoveDialog(dialogService, domainObject, removeFromContext);
dialog.show();
}
}; };
// Object needs to have a parent for Remove to be applicable // Object needs to have a parent for Remove to be applicable

View File

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

View File

@ -36,11 +36,9 @@ define(
*/ */
function EditorCapability( function EditorCapability(
transactionService, transactionService,
openmct,
domainObject domainObject
) { ) {
this.transactionService = transactionService; this.transactionService = transactionService;
this.openmct = openmct;
this.domainObject = domainObject; this.domainObject = domainObject;
} }
@ -50,19 +48,27 @@ define(
* or finish() are called. * or finish() are called.
*/ */
EditorCapability.prototype.edit = function () { EditorCapability.prototype.edit = function () {
console.warn('DEPRECATED: cannot edit via edit capability, use openmct.editor instead.'); this.transactionService.startTransaction();
this.openmct.editor.edit();
this.domainObject.getCapability('status').set('editing', true); 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 * Determines whether this object, or any of its ancestors are
* currently being edited. * currently being edited.
* @returns boolean * @returns boolean
*/ */
EditorCapability.prototype.inEditContext = function () { EditorCapability.prototype.inEditContext = function () {
console.warn('DEPRECATION WARNING: isEditing checks must be done via openmct.editor.'); return isEditing(this.domainObject);
return this.openmct.editor.isEditing();
}; };
/** /**
@ -71,8 +77,7 @@ define(
* @returns {*} * @returns {*}
*/ */
EditorCapability.prototype.isEditContextRoot = function () { EditorCapability.prototype.isEditContextRoot = function () {
console.warn('DEPRECATION WARNING: isEditing checks must be done via openmct.editor.'); return isEditContextRoot(this.domainObject);
return this.openmct.editor.isEditing();
}; };
/** /**
@ -81,7 +86,10 @@ define(
* @returns {*} * @returns {*}
*/ */
EditorCapability.prototype.save = function () { EditorCapability.prototype.save = function () {
console.warn('DEPRECATED: cannot save via edit capability, use openmct.editor instead.'); var transactionService = this.transactionService;
return transactionService.commit().then(function () {
transactionService.startTransaction();
});
}; };
EditorCapability.prototype.invoke = EditorCapability.prototype.edit; EditorCapability.prototype.invoke = EditorCapability.prototype.edit;
@ -92,7 +100,16 @@ define(
* @returns {*} * @returns {*}
*/ */
EditorCapability.prototype.finish = function () { EditorCapability.prototype.finish = function () {
console.warn('DEPRECATED: cannot finish via edit capability, use openmct.editor instead.'); 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. // present context.
function updateActions() { function updateActions() {
$scope.saveActions = $scope.action ? $scope.saveActions = $scope.action ?
$scope.action.getActions(SAVE_ACTION_CONTEXT) : $scope.action.getActions(SAVE_ACTION_CONTEXT) :
[]; [];
$scope.saveActionsAsMenuOptions = $scope.saveActions.map(actionToMenuOption); $scope.saveActionsAsMenuOptions = $scope.saveActions.map(actionToMenuOption);
@ -59,8 +59,8 @@ define(
}; };
$scope.otherEditActions = $scope.action ? $scope.otherEditActions = $scope.action ?
$scope.action.getActions(OTHERS_ACTION_CONTEXT) : $scope.action.getActions(OTHERS_ACTION_CONTEXT) :
[]; [];
// Required because Angular does not allow 'bind' // Required because Angular does not allow 'bind'
// in expressions. // in expressions.

View File

@ -49,7 +49,7 @@ define(
function searchElements(value) { function searchElements(value) {
if ($scope.searchText) { if ($scope.searchText) {
return value.getModel().name.toLowerCase().search( return value.getModel().name.toLowerCase().search(
$scope.searchText.toLowerCase()) !== -1; $scope.searchText.toLowerCase()) !== -1;
} else { } else {
return true; return true;
} }

View File

@ -39,8 +39,8 @@ define(
// Update the set of Create actions // Update the set of Create actions
function refreshActions() { function refreshActions() {
$scope.createActions = $scope.action ? $scope.createActions = $scope.action ?
$scope.action.getActions('create') : $scope.action.getActions('create') :
[]; [];
} }
// Listen for new instances of the represented object's // Listen for new instances of the represented object's

View File

@ -55,23 +55,15 @@ define(
// A view is editable unless explicitly flagged as not // A view is editable unless explicitly flagged as not
(views || []).forEach(function (view) { (views || []).forEach(function (view) {
if (isEditable(view) || if (view.editable === true ||
(view.key === 'plot' && type.getKey() === 'telemetry.panel') || (view.key === 'plot' && type.getKey() === 'telemetry.panel') ||
(view.key === 'table' && type.getKey() === 'table') || (view.key === 'table' && type.getKey() === 'table') ||
(view.key === 'rt-table' && type.getKey() === 'rttable') (view.key === 'rt-table' && type.getKey() === 'rttable')
) { ) {
count++; count++;
} }
}); });
function isEditable(view) {
if (typeof view.editable === Function) {
return view.editable(domainObject.useCapability('adapter'));
} else {
return view.editable === true;
}
}
return count; return count;
}; };

View File

@ -55,16 +55,16 @@ define(
navigatedObject = this.navigationService.getNavigation(), navigatedObject = this.navigationService.getNavigation(),
actionMetadata = action.getMetadata ? action.getMetadata() : {}; actionMetadata = action.getMetadata ? action.getMetadata() : {};
// if (navigatedObject.hasCapability("editor") && navigatedObject.getCapability("editor").isEditContextRoot()) { if (navigatedObject.hasCapability("editor") && navigatedObject.getCapability("editor").isEditContextRoot()) {
if (selectedObject.hasCapability("editor") && selectedObject.getCapability("editor").inEditContext()) { if (selectedObject.hasCapability("editor") && selectedObject.getCapability("editor").inEditContext()) {
return this.editModeBlacklist.indexOf(actionMetadata.key) === -1; return this.editModeBlacklist.indexOf(actionMetadata.key) === -1;
} else { } else {
//Target is in the context menu //Target is in the context menu
return this.nonEditContextBlacklist.indexOf(actionMetadata.key) === -1; return this.nonEditContextBlacklist.indexOf(actionMetadata.key) === -1;
} }
// } else { } else {
// return true; return true;
// } }
}; };
return EditContextualActionPolicy; return EditContextualActionPolicy;

View File

@ -25,7 +25,8 @@ define(
function (EditAndComposeAction) { function (EditAndComposeAction) {
describe("The Link action", function () { describe("The Link action", function () {
var mockDomainObject, var mockQ,
mockDomainObject,
mockParent, mockParent,
mockContext, mockContext,
mockComposition, mockComposition,
@ -46,10 +47,13 @@ define(
} }
beforeEach(function () { beforeEach(function () {
mockDomainObject = jasmine.createSpyObj( mockDomainObject = jasmine.createSpyObj(
"domainObject", "domainObject",
["getId", "getCapability"] ["getId", "getCapability"]
); );
mockQ = { when: mockPromise };
mockParent = { mockParent = {
getModel: function () { getModel: function () {
return model; return model;

View File

@ -124,6 +124,17 @@ define(
expect(mockParent.useCapability).not.toHaveBeenCalledWith("mutation", jasmine.any(Function)); expect(mockParent.useCapability).not.toHaveBeenCalledWith("mutation", jasmine.any(Function));
}); });
it("does not show a blocking message dialog when true is passed to perform", function () {
mockParent = jasmine.createSpyObj(
"parent",
["getModel", "getCapability", "useCapability"]
);
action.perform(true);
expect(mockDialogService.showBlockingMessage).not.toHaveBeenCalled();
});
describe("after the remove callback is triggered", function () { describe("after the remove callback is triggered", function () {
var mockChildContext, var mockChildContext,
mockChildObject, mockChildObject,

View File

@ -34,6 +34,7 @@ define(
mockDomainObject, mockDomainObject,
capabilities = {}, capabilities = {},
mockEditAction, mockEditAction,
mockSaveAction,
action; action;
function mockPromise(value) { function mockPromise(value) {
@ -82,6 +83,12 @@ define(
mockDomainObject.getCapability.and.callFake(function (name) { mockDomainObject.getCapability.and.callFake(function (name) {
return capabilities[name]; return capabilities[name];
}); });
mockSaveAction = jasmine.createSpyObj(
"saveAction",
[
"perform"
]
);
capabilities.action = jasmine.createSpyObj( capabilities.action = jasmine.createSpyObj(
"actionCapability", "actionCapability",

View File

@ -142,11 +142,11 @@ define(
it("populates the model on the associated object", function () { it("populates the model on the associated object", function () {
var formValue = { var formValue = {
"A": "ValueA", "A": "ValueA",
"B": "ValueB", "B": "ValueB",
"C": "ValueC" "C": "ValueC"
}, },
compareModel = wizard.createModel(formValue); compareModel = wizard.createModel(formValue);
//populateObjectFromInput adds a .location attribute that is not added by createModel. //populateObjectFromInput adds a .location attribute that is not added by createModel.
compareModel.location = undefined; compareModel.location = undefined;
wizard.populateObjectFromInput(formValue); wizard.populateObjectFromInput(formValue);

View File

@ -114,7 +114,7 @@ define(
mockNewObject.getId.and.returnValue('newId'); mockNewObject.getId.and.returnValue('newId');
mockNewObject.getCapability.and.callFake(function (c) { mockNewObject.getCapability.and.callFake(function (c) {
return c === 'persistence' ? return c === 'persistence' ?
mockNewPersistenceCapability : undefined; mockNewPersistenceCapability : undefined;
}); });
mockPersistenceCapability.persist mockPersistenceCapability.persist

View File

@ -76,66 +76,66 @@ define(
describe("when context is available", function () { describe("when context is available", function () {
beforeEach(function () { beforeEach(function () {
mockContext.getRoot.and.returnValue(mockRootObject); mockContext.getRoot.and.returnValue(mockRootObject);
controller = new LocatorController(mockScope, mockTimeout, mockObjectService); controller = new LocatorController(mockScope, mockTimeout, mockObjectService);
}); });
it("adds a treeModel to scope", function () { it("adds a treeModel to scope", function () {
expect(mockScope.treeModel).toBeDefined(); expect(mockScope.treeModel).toBeDefined();
}); });
it("watches for changes to treeModel", function () { it("watches for changes to treeModel", function () {
// This is what the embedded tree representation // This is what the embedded tree representation
// will be modifying. // will be modifying.
expect(mockScope.$watch).toHaveBeenCalledWith( expect(mockScope.$watch).toHaveBeenCalledWith(
"treeModel.selectedObject", "treeModel.selectedObject",
jasmine.any(Function) jasmine.any(Function)
); );
}); });
it("changes its own model on embedded model updates", function () { it("changes its own model on embedded model updates", function () {
// Need to pass on selection changes as updates to // Need to pass on selection changes as updates to
// the control's value // the control's value
mockScope.$watch.calls.mostRecent().args[1](mockDomainObject); mockScope.$watch.calls.mostRecent().args[1](mockDomainObject);
mockTimeout.calls.mostRecent().args[0](); mockTimeout.calls.mostRecent().args[0]();
expect(mockScope.ngModel.someField).toEqual(mockDomainObject); expect(mockScope.ngModel.someField).toEqual(mockDomainObject);
expect(mockScope.rootObject).toEqual(mockRootObject); expect(mockScope.rootObject).toEqual(mockRootObject);
// Verify that the capability we expect to have been used // Verify that the capability we expect to have been used
// was used. // was used.
expect(mockDomainObject.getCapability) expect(mockDomainObject.getCapability)
.toHaveBeenCalledWith("context"); .toHaveBeenCalledWith("context");
}); });
it("rejects changes which fail validation", function () { it("rejects changes which fail validation", function () {
mockScope.structure = { validate: jasmine.createSpy('validate') }; mockScope.structure = { validate: jasmine.createSpy('validate') };
mockScope.structure.validate.and.returnValue(false); mockScope.structure.validate.and.returnValue(false);
// Pass selection change // Pass selection change
mockScope.$watch.calls.mostRecent().args[1](mockDomainObject); mockScope.$watch.calls.mostRecent().args[1](mockDomainObject);
mockTimeout.calls.mostRecent().args[0](); mockTimeout.calls.mostRecent().args[0]();
expect(mockScope.structure.validate).toHaveBeenCalled(); expect(mockScope.structure.validate).toHaveBeenCalled();
// Change should have been rejected // Change should have been rejected
expect(mockScope.ngModel.someField).not.toEqual(mockDomainObject); expect(mockScope.ngModel.someField).not.toEqual(mockDomainObject);
}); });
it("treats a lack of a selection as invalid", function () { it("treats a lack of a selection as invalid", function () {
mockScope.ngModelController = jasmine.createSpyObj( mockScope.ngModelController = jasmine.createSpyObj(
'ngModelController', 'ngModelController',
['$setValidity'] ['$setValidity']
); );
mockScope.$watch.calls.mostRecent().args[1](mockDomainObject); mockScope.$watch.calls.mostRecent().args[1](mockDomainObject);
mockTimeout.calls.mostRecent().args[0](); mockTimeout.calls.mostRecent().args[0]();
expect(mockScope.ngModelController.$setValidity) expect(mockScope.ngModelController.$setValidity)
.toHaveBeenCalledWith(jasmine.any(String), true); .toHaveBeenCalledWith(jasmine.any(String), true);
mockScope.$watch.calls.mostRecent().args[1](undefined); mockScope.$watch.calls.mostRecent().args[1](undefined);
mockTimeout.calls.mostRecent().args[0](); mockTimeout.calls.mostRecent().args[0]();
expect(mockScope.ngModelController.$setValidity) expect(mockScope.ngModelController.$setValidity)
.toHaveBeenCalledWith(jasmine.any(String), false); .toHaveBeenCalledWith(jasmine.any(String), false);
}); });
}); });
describe("when no context is available", function () { describe("when no context is available", function () {
var defaultRoot = "DEFAULT_ROOT"; var defaultRoot = "DEFAULT_ROOT";

View File

@ -27,6 +27,7 @@ define(
describe("The Edit action policy", function () { describe("The Edit action policy", function () {
var editableView, var editableView,
nonEditableView, nonEditableView,
undefinedView,
testViews, testViews,
testContext, testContext,
mockDomainObject, mockDomainObject,
@ -66,6 +67,7 @@ define(
editableView = { editable: true }; editableView = { editable: true };
nonEditableView = { editable: false }; nonEditableView = { editable: false };
undefinedView = { someKey: "some value" };
plotView = { key: "plot", editable: false }; plotView = { key: "plot", editable: false };
testViews = []; testViews = [];

View File

@ -75,25 +75,25 @@ define(
it('Allows "remove" action when navigated object in edit mode,' + it('Allows "remove" action when navigated object in edit mode,' +
' and selected object not editable, but its parent is.', ' and selected object not editable, but its parent is.',
function () { function () {
var mockParent = jasmine.createSpyObj("parentObject", ["hasCapability"]), var mockParent = jasmine.createSpyObj("parentObject", ["hasCapability"]),
mockContextCapability = jasmine.createSpyObj("contextCapability", ["getParent"]); mockContextCapability = jasmine.createSpyObj("contextCapability", ["getParent"]);
mockParent.hasCapability.and.returnValue(true); mockParent.hasCapability.and.returnValue(true);
mockContextCapability.getParent.and.returnValue(mockParent); mockContextCapability.getParent.and.returnValue(mockParent);
navigatedObject.hasCapability.and.returnValue(true); navigatedObject.hasCapability.and.returnValue(true);
mockDomainObject.getCapability.and.returnValue(mockContextCapability); mockDomainObject.getCapability.and.returnValue(mockContextCapability);
mockDomainObject.hasCapability.and.callFake(function (capability) { mockDomainObject.hasCapability.and.callFake(function (capability) {
switch (capability) { switch (capability) {
case "editor": return false; case "editor": return false;
case "context": return true; case "context": return true;
} }
});
metadata.key = "remove";
expect(policy.allow(mockAction, context)).toBe(true);
}); });
metadata.key = "remove";
expect(policy.allow(mockAction, context)).toBe(true);
});
it('Disallows "move" action when navigated object in edit mode,' + it('Disallows "move" action when navigated object in edit mode,' +
' but selected object not in edit mode ', function () { ' but selected object not in edit mode ', function () {

View File

@ -37,8 +37,8 @@ define(
); );
mockDomainObject.getCapability.and.returnValue({ mockDomainObject.getCapability.and.returnValue({
inEditContext: function () { inEditContext: function () {
return true; return true;
} }
}); });
mockDomainObject.hasCapability.and.callFake(function (c) { mockDomainObject.hasCapability.and.callFake(function (c) {
return (c === 'editor') && testMode; return (c === 'editor') && testMode;

View File

@ -30,6 +30,12 @@ define(
mockObjects, mockObjects,
mockDomainObject, mockDomainObject,
testStructure, testStructure,
testAB,
testABC,
testABC2,
testABCXYZ,
testABCYZ,
testM,
toolbar; toolbar;
beforeEach(function () { beforeEach(function () {
@ -47,15 +53,22 @@ define(
]); ]);
testStructure = [ testStructure = [
{ name: "A", property: "a", domainObject: mockDomainObject }, { name: "A", property: "a", domainObject: mockDomainObject },
{ name: "B", property: "b", domainObject: mockDomainObject }, { name: "B", property: "b", domainObject: mockDomainObject },
{ name: "C", property: "c", domainObject: mockDomainObject }, { name: "C", property: "c", domainObject: mockDomainObject },
{ name: "X", property: "x", domainObject: mockDomainObject }, { name: "X", property: "x", domainObject: mockDomainObject },
{ name: "Y", property: "y", domainObject: mockDomainObject }, { name: "Y", property: "y", domainObject: mockDomainObject },
{ name: "Z", property: "z", domainObject: mockDomainObject }, { name: "Z", property: "z", domainObject: mockDomainObject },
{ name: "M", method: "m", domainObject: mockDomainObject } { name: "M", method: "m", domainObject: mockDomainObject }
]; ];
testAB = { a: 0, b: 1 };
testABC = { a: 0, b: 1, c: 2 };
testABC2 = { a: 4, b: 1, c: 2 }; // For inconsistent-state checking
testABCXYZ = { a: 0, b: 1, c: 2, x: 'X!', y: 'Y!', z: 'Z!' };
testABCYZ = { a: 0, b: 1, c: 2, y: 'Y!', z: 'Z!' };
testM = { m: jasmine.createSpy("method") };
toolbar = new EditToolbar(mockScope, mockOpenMCT, testStructure); toolbar = new EditToolbar(mockScope, mockOpenMCT, testStructure);
}); });

View File

@ -43,12 +43,13 @@ define(["../../src/services/NestedTransaction"], function (NestedTransaction) {
describe("when callbacks are added", function () { describe("when callbacks are added", function () {
var mockCommit, var mockCommit,
mockCancel; mockCancel,
remove;
beforeEach(function () { beforeEach(function () {
mockCommit = jasmine.createSpy('commit'); mockCommit = jasmine.createSpy('commit');
mockCancel = jasmine.createSpy('cancel'); mockCancel = jasmine.createSpy('cancel');
nestedTransaction.add(mockCommit, mockCancel); remove = nestedTransaction.add(mockCommit, mockCancel);
}); });
it("does not interact with its parent transaction", function () { it("does not interact with its parent transaction", function () {

View File

@ -76,8 +76,8 @@ define(
beforeEach(function () { beforeEach(function () {
onCommits = [0, 1, 2].map(function (val) { onCommits = [0, 1, 2].map(function (val) {
return jasmine.createSpy("onCommit" + val); return jasmine.createSpy("onCommit" + val);
}); });
transactionService.startTransaction(); transactionService.startTransaction();
onCommits.forEach(transactionService.addToTransaction.bind(transactionService)); onCommits.forEach(transactionService.addToTransaction.bind(transactionService));

View File

@ -56,7 +56,7 @@ define([
}; };
DurationFormat.prototype.validate = function (text) { DurationFormat.prototype.validate = function (text) {
return moment.utc(text, DATE_FORMATS, true).isValid(); return moment.utc(text, DATE_FORMATS).isValid();
}; };
return DurationFormat; return DurationFormat;

View File

@ -29,7 +29,6 @@ define([
var DATE_FORMAT = "YYYY-MM-DD HH:mm:ss.SSS", var DATE_FORMAT = "YYYY-MM-DD HH:mm:ss.SSS",
DATE_FORMATS = [ DATE_FORMATS = [
DATE_FORMAT, DATE_FORMAT,
DATE_FORMAT + "Z",
"YYYY-MM-DD HH:mm:ss", "YYYY-MM-DD HH:mm:ss",
"YYYY-MM-DD HH:mm", "YYYY-MM-DD HH:mm",
"YYYY-MM-DD" "YYYY-MM-DD"
@ -53,14 +52,70 @@ define([
this.key = "utc"; this.key = "utc";
} }
/**
* Returns an appropriate time format based on the provided value and
* the threshold required.
* @private
*/
function getScaledFormat(d) {
var momentified = moment.utc(d);
/**
* Uses logic from d3 Time-Scales, v3 of the API. See
* https://github.com/d3/d3-3.x-api-reference/blob/master/Time-Scales.md
*
* Licensed
*/
var format = [
[".SSS", function (m) {
return m.milliseconds();
}],
[":ss", function (m) {
return m.seconds();
}],
["HH:mm", function (m) {
return m.minutes();
}],
["HH", function (m) {
return m.hours();
}],
["ddd DD", function (m) {
return m.days() &&
m.date() !== 1;
}],
["MMM DD", function (m) {
return m.date() !== 1;
}],
["MMMM", function (m) {
return m.month();
}],
["YYYY", function () {
return true;
}]
].filter(function (row) {
return row[1](momentified);
})[0][0];
if (format !== undefined) {
return moment.utc(d).format(format);
}
}
/** /**
* @param {number} value The value to format. * @param {number} value The value to format.
* @param {number} [minValue] Contextual information for scaled formatting used in linear scales such as conductor
* and plot axes. Specifies the smallest number on the scale.
* @param {number} [maxValue] Contextual information for scaled formatting used in linear scales such as conductor
* and plot axes. Specifies the largest number on the scale
* @param {number} [count] Contextual information for scaled formatting used in linear scales such as conductor
* and plot axes. The number of labels on the scale.
* @returns {string} the formatted date(s). If multiple values were requested, then an array of * @returns {string} the formatted date(s). If multiple values were requested, then an array of
* formatted values will be returned. Where a value could not be formatted, `undefined` will be returned at its position * formatted values will be returned. Where a value could not be formatted, `undefined` will be returned at its position
* in the array. * in the array.
*/ */
UTCTimeFormat.prototype.format = function (value) { UTCTimeFormat.prototype.format = function (value) {
if (value !== undefined) { if (arguments.length > 1) {
return getScaledFormat(value);
} else if (value !== undefined) {
return moment.utc(value).format(DATE_FORMAT) + "Z"; return moment.utc(value).format(DATE_FORMAT) + "Z";
} else { } else {
return value; return value;
@ -75,7 +130,7 @@ define([
}; };
UTCTimeFormat.prototype.validate = function (text) { UTCTimeFormat.prototype.validate = function (text) {
return moment.utc(text, DATE_FORMATS, true).isValid(); return moment.utc(text, DATE_FORMATS).isValid();
}; };
return UTCTimeFormat; return UTCTimeFormat;

View File

@ -0,0 +1,62 @@
/*****************************************************************************
* Open MCT Web, Copyright (c) 2014-2015, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT Web includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
define([
"../src/UTCTimeFormat",
"moment"
], function (
UTCTimeFormat,
moment
) {
describe("The UTCTimeFormat class", function () {
var format;
var scale;
beforeEach(function () {
format = new UTCTimeFormat();
scale = {min: 0, max: 0};
});
it("Provides an appropriately scaled time format based on the input" +
" time", function () {
var TWO_HUNDRED_MS = 200;
var THREE_SECONDS = 3000;
var FIVE_MINUTES = 5 * 60 * 1000;
var ONE_HOUR_TWENTY_MINS = (1 * 60 * 60 * 1000) + (20 * 60 * 1000);
var TEN_HOURS = (10 * 60 * 60 * 1000);
var JUNE_THIRD = moment.utc("2016-06-03", "YYYY-MM-DD");
var APRIL = moment.utc("2016-04", "YYYY-MM");
var TWENTY_SIXTEEN = moment.utc("2016", "YYYY");
expect(format.format(TWO_HUNDRED_MS, scale)).toBe(".200");
expect(format.format(THREE_SECONDS, scale)).toBe(":03");
expect(format.format(FIVE_MINUTES, scale)).toBe("00:05");
expect(format.format(ONE_HOUR_TWENTY_MINS, scale)).toBe("01:20");
expect(format.format(TEN_HOURS, scale)).toBe("10");
expect(format.format(JUNE_THIRD, scale)).toBe("Fri 03");
expect(format.format(APRIL, scale)).toBe("April");
expect(format.format(TWENTY_SIXTEEN, scale)).toBe("2016");
});
});
});

View File

@ -52,26 +52,26 @@ define([
"./src/directives/MCTPreview", "./src/directives/MCTPreview",
"./src/actions/MCTPreviewAction", "./src/actions/MCTPreviewAction",
"./src/filters/ReverseFilter", "./src/filters/ReverseFilter",
"./res/templates/bottombar.html", "text!./res/templates/bottombar.html",
"./res/templates/controls/action-button.html", "text!./res/templates/controls/action-button.html",
"./res/templates/controls/input-filter.html", "text!./res/templates/controls/input-filter.html",
"./res/templates/angular-indicator.html", "text!./res/templates/angular-indicator.html",
"./res/templates/message-banner.html", "text!./res/templates/message-banner.html",
"./res/templates/progress-bar.html", "text!./res/templates/progress-bar.html",
"./res/templates/controls/time-controller.html", "text!./res/templates/controls/time-controller.html",
"./res/templates/containers/accordion.html", "text!./res/templates/containers/accordion.html",
"./res/templates/subtree.html", "text!./res/templates/subtree.html",
"./res/templates/tree.html", "text!./res/templates/tree.html",
"./res/templates/tree-node.html", "text!./res/templates/tree-node.html",
"./res/templates/label.html", "text!./res/templates/label.html",
"./res/templates/controls/action-group.html", "text!./res/templates/controls/action-group.html",
"./res/templates/menu/context-menu.html", "text!./res/templates/menu/context-menu.html",
"./res/templates/controls/switcher.html", "text!./res/templates/controls/switcher.html",
"./res/templates/object-inspector.html", "text!./res/templates/object-inspector.html",
"./res/templates/controls/selector.html", "text!./res/templates/controls/selector.html",
"./res/templates/controls/datetime-picker.html", "text!./res/templates/controls/datetime-picker.html",
"./res/templates/controls/datetime-field.html", "text!./res/templates/controls/datetime-field.html",
"./res/templates/preview.html", "text!./res/templates/preview.html",
'legacyRegistry' 'legacyRegistry'
], function ( ], function (
UrlService, UrlService,
@ -173,6 +173,12 @@ define([
"key": "reverse" "key": "reverse"
} }
], ],
"stylesheets": [
{
"stylesheetUrl": "css/normalize.min.css",
"priority": "mandatory"
}
],
"templates": [ "templates": [
{ {
"key": "bottombar", "key": "bottombar",
@ -412,11 +418,11 @@ define([
"description": "Preview in large dialog", "description": "Preview in large dialog",
"category": [ "category": [
"contextual", "contextual",
"view-control" "view-control"
], ],
"depends": [ "depends": [
"$compile", "$compile",
"$rootScope" "$rootScope"
], ],
"priority": "preferred" "priority": "preferred"
} }

View File

@ -0,0 +1,48 @@
/* http://meyerweb.com/eric/tools/css/reset/
v2.0 | 20110126
License: none (public domain)
*/
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
display: block;
}
body {
line-height: 1;
}
ol, ul {
list-style: none;
}
blockquote, q {
quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
content: '';
content: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}

View File

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 44 KiB

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