Compare commits

..

2 Commits

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

View File

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

View File

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

5
.jscsrc Normal file
View File

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

26
.jshintrc Normal file
View File

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

88
API.md
View File

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

View File

@@ -84,6 +84,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 +94,32 @@ This will compile and minify JavaScript sources, as well as copy over assets.
The contents of the `dist` folder will contain a runnable Open MCT 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`

128
app.js
View File

@@ -7,72 +7,78 @@
* 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.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, function() {
console.log('Open MCT application running at localhost:' + options.port)
});
}());

28
bower.json Normal file
View File

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

27
circle.yml Normal file
View File

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

View File

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

View File

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

View File

@@ -0,0 +1,74 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2017, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define*/
define([
"./src/ExampleController",
"./src/ExampleDirective",
"./src/ExampleService",
'legacyRegistry'
], function (
ExampleController,
ExampleDirective,
ExampleService,
legacyRegistry
) {
"use strict";
legacyRegistry.register("example/builtins", {
"name": "Angular Built-ins Example",
"description": "Example showing how to declare extensions with built-in support from Angular.",
"sources": "src",
"extensions": {
"controllers": [
{
"key": "ExampleController",
"implementation": ExampleController,
"depends": [
"$scope",
"exampleService"
]
}
],
"directives": [
{
"key": "exampleDirective",
"implementation": ExampleDirective,
"depends": [
"examples[]"
]
}
],
"routes": [
{
"templateUrl": "templates/example.html"
}
],
"services": [
{
"key": "exampleService",
"implementation": ExampleService
}
]
}
});
});

View File

@@ -19,11 +19,6 @@
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='form-control select' ng-controller="selectSnapshotController"> <p>Hello, world! I am the default route.</p>
<select <p ng-controller="ExampleController">My controller has told me: "{{phrase}}"</p>
ng-model="selectModel" <span example-directive></span>
ng-options="opt.value as opt.name for opt in options"
ng-required="ngRequired"
name="mctControl">
</select>
</div>

View File

@@ -19,7 +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.
*****************************************************************************/ *****************************************************************************/
$output-bourbon-deprecation-warnings: false; /*global define,Promise*/
@import "bourbon";
@import "notebook-thematic"; /**
* Module defining ExampleController. Created by vwoeltje on 11/4/14.
*/
define(
[],
function () {
"use strict";
/**
*
* @constructor
*/
function ExampleController($scope, exampleService) {
$scope.phrase = exampleService.getMessage();
}
return ExampleController;
}
);

View File

@@ -0,0 +1,66 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2017, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define,Promise*/
/**
* Module defining ExampleDirective. Created by vwoeltje on 11/4/14.
*/
define(
[],
function () {
"use strict";
var HAS_EXTENSIONS = "A directive loaded these message from " +
"example extensions.",
NO_EXTENSIONS = "A directive tried to load example extensions," +
" but found none.",
MESSAGE = "I heard this from my partial constructor.";
/**
*
* @constructor
*/
function ExampleDirective(examples) {
// Build up a template from example extensions
var template = examples.length > 0 ?
HAS_EXTENSIONS : NO_EXTENSIONS;
template += "<ul>";
examples.forEach(function (E) {
template += "<li>";
if (typeof E === 'function') {
template += (new E(MESSAGE)).getText();
} else {
template += E.text;
}
template += "</li>";
});
template += "</ul>";
return {
template: template
};
}
return ExampleDirective;
}
);

View File

@@ -1,5 +1,5 @@
/***************************************************************************** /*****************************************************************************
* Open MCT, Copyright (c) 2014-2018, United States Government * Open MCT, Copyright (c) 2014-2017, United States Government
* as represented by the Administrator of the National Aeronautics and Space * as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved. * Administration. All rights reserved.
* *
@@ -19,22 +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*/
/**
* Module defining ExampleService. Created by vwoeltje on 11/4/14.
*/
define( define(
[], [],
function () { function () {
function MCTIndicators(openmct) { "use strict";
/**
*
* @constructor
*/
function ExampleService() {
return { return {
restrict: "E", getMessage: function () {
link: function link(scope, element) { return "I heard this from a service";
openmct.indicators.indicatorElements
.forEach(function (indicatorElement) {
element.append(indicatorElement);
});
} }
}; };
} }
return MCTIndicators; return ExampleService;
} }
); );

View File

@@ -0,0 +1,82 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2017, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define*/
define([
"./src/SomeProvider",
"./src/SomeOtherProvider",
"./src/SomeDecorator",
"./src/SomeOtherDecorator",
"./src/SomeAggregator",
"./src/SomeOtherExample",
'legacyRegistry'
], function (
SomeProvider,
SomeOtherProvider,
SomeDecorator,
SomeOtherDecorator,
SomeAggregator,
SomeOtherExample,
legacyRegistry
) {
"use strict";
legacyRegistry.register("example/composite", {
"extensions": {
"components": [
{
"implementation": SomeProvider,
"provides": "someService",
"type": "provider"
},
{
"implementation": SomeOtherProvider,
"provides": "someService",
"type": "provider"
},
{
"implementation": SomeDecorator,
"provides": "someService",
"type": "decorator"
},
{
"implementation": SomeOtherDecorator,
"provides": "someService",
"type": "decorator"
},
{
"implementation": SomeAggregator,
"provides": "someService",
"type": "aggregator"
}
],
"examples": [
{
"implementation": SomeOtherExample,
"depends": [
"someService"
]
}
]
}
});
});

View File

@@ -0,0 +1,50 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2017, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define,Promise*/
/**
* Module defining SomeAggregator. Created by vwoeltje on 11/5/14.
*/
define(
[],
function () {
"use strict";
/**
*
* @constructor
*/
function SomeAggregator(someProviders) {
return {
getMessages: function () {
return someProviders.map(function (provider) {
return provider.getMessages();
}).reduce(function (a, b) {
return a.concat(b);
}, []);
}
};
}
return SomeAggregator;
}
);

View File

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

View File

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

View File

@@ -19,26 +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*/
/** /**
* Module defining SelectSnapshotController. */ * Module defining SomeOtherExample. Created by vwoeltje on 11/5/14.
*/
define( define(
[], [],
function () { function () {
"use strict";
function SelectSnapshotController($scope,$rootScope) { /**
*
$scope.selectModel = true; * @constructor
*/
function selectprint(value) { function SomeOtherExample(someService) {
$rootScope.selValue = value; return {
$scope.$parent.$parent.ngModel[$scope.$parent.$parent.field] = value; getText: function () {
} return someService.getMessages().join(" | ");
}
$scope.$watch("selectModel", selectprint); };
} }
return SelectSnapshotController; return SomeOtherExample;
} }
); );

View File

@@ -0,0 +1,48 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2017, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define,Promise*/
/**
* Module defining SomeOtherProvider. Created by vwoeltje on 11/5/14.
*/
define(
[],
function () {
"use strict";
/**
*
* @constructor
*/
function SomeOtherProvider() {
return {
getMessages: function () {
return [
"I am a message from some other provider."
];
}
};
}
return SomeOtherProvider;
}
);

View File

@@ -0,0 +1,48 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2017, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global define,Promise*/
/**
* Module defining SomeProvider. Created by vwoeltje on 11/5/14.
*/
define(
[],
function () {
"use strict";
/**
*
* @constructor
*/
function SomeProvider() {
return {
getMessages: function () {
return [
"I am a message from some provider."
];
}
};
}
return SomeProvider;
}
);

View File

@@ -60,8 +60,8 @@ define([
"source": "eventGenerator", "source": "eventGenerator",
"domains": [ "domains": [
{ {
"key": "utc", "key": "time",
"name": "Timestamp", "name": "Time",
"format": "utc" "format": "utc"
} }
], ],

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

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

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

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

View File

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

View File

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

View File

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

View File

@@ -1,9 +1,9 @@
<span class="h-indicator" ng-controller="DialogLaunchController"> <span class="status block" ng-controller="DialogLaunchController">
<!-- DO NOT ADD SPACES BETWEEN THE SPANS - IT ADDS WHITE SPACE!! --> <!-- DO NOT ADD SPACES BETWEEN THE SPANS - IT ADDS WHITE SPACE!! -->
<div class="ls-indicator icon-box-with-arrow s-status-available"><span class="label"> <span class="status-indicator icon-box-with-arrow"></span><span class="label">
<a ng-click="launchProgress(true)">Known</a> <a ng-click="launchProgress(true)">Known</a> |
<a ng-click="launchProgress(false)">Unknown</a> <a ng-click="launchProgress(false)">Unknown</a> |
<a ng-click="launchError()">Error</a> <a ng-click="launchError()">Error</a> |
<a ng-click="launchInfo()">Info</a> <a ng-click="launchInfo()">Info</a>
</span></div> </span><span class="count"></span>
</span> </span>

View File

@@ -1,9 +1,9 @@
<span class="h-indicator" ng-controller="NotificationLaunchController"> <span class="status block" ng-controller="NotificationLaunchController">
<!-- DO NOT ADD SPACES BETWEEN THE SPANS - IT ADDS WHITE SPACE!! --> <!-- DO NOT ADD SPACES BETWEEN THE SPANS - IT ADDS WHITE SPACE!! -->
<div class="ls-indicator icon-bell s-status-available"><span class="label"> <span class="status-indicator icon-bell"></span><span class="label">
<a ng-click="newInfo()">Success</a> <a ng-click="newInfo()">Success</a> |
<a ng-click="newError()">Error</a> <a ng-click="newError()">Error</a> |
<a ng-click="newAlert()">Alert</a> <a ng-click="newAlert()">Alert</a> |
<a ng-click="newProgress()">Progress</a> <a ng-click="newProgress()">Progress</a>
</span></div> </span><span class="count"></span>
</span> </span>

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

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

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

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

View File

@@ -34,7 +34,7 @@
<p>As you develop plugins for Open MCT, consider how a generalized component might be combined with others when designing to create a rich and powerful larger object, rather than adding a single monolithic, non-modular plugin. To solve a particular problem or allow a new feature in Open MCT, you may need to introduce more than just one new object type.</p> <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

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

@@ -19,37 +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.
*****************************************************************************/ *****************************************************************************/
/*global define*/
define( define(
[], [],
function () { function () {
"use strict";
var PREVIEW_TEMPLATE = '<mct-representation key="\'mct-preview\'"' + /**
'class="t-rep-frame holder"' + * Displays Fibonacci numbers in the status area.
'mct-object="domainObject">' + * @constructor
'</mct-representation>'; */
function FibonacciIndicator(workerService, $rootScope) {
var latest,
counter = 0,
worker = workerService.run('example.fibonacci');
function MCTPreviewAction($compile, $rootScope, context) { function requestNext() {
context = context || {}; worker.postMessage([counter]);
this.domainObject = context.selectedObject || context.domainObject; counter += 1;
this.$rootScope = $rootScope; }
this.$compile = $compile;
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 "";
}
};
} }
MCTPreviewAction.prototype.perform = function () { return FibonacciIndicator;
var newScope = this.$rootScope.$new();
newScope.domainObject = this.domainObject;
this.$compile(PREVIEW_TEMPLATE)(newScope);
};
MCTPreviewAction.appliesTo = function (context) {
var domainObject = (context || {}).domainObject,
status = domainObject.getCapability('status');
return !(status && status.get('editing'));
};
return MCTPreviewAction;
} }
); );

View File

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

182
gulpfile.js Normal file
View File

@@ -0,0 +1,182 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2017, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
/*global require,__dirname*/
require("v8-compile-cache");
var gulp = require('gulp'),
sourcemaps = require('gulp-sourcemaps'),
path = require('path'),
fs = require('fs'),
git = require('git-rev-sync'),
moment = require('moment'),
project = require('./package.json'),
_ = require('lodash'),
paths = {
main: 'openmct.js',
dist: 'dist',
reports: 'dist/reports',
scss: ['./platform/**/*.scss', './example/**/*.scss'],
assets: [
'./{example,platform}/**/*.{css,css.map,png,svg,ico,woff,eot,ttf}'
],
scripts: [ 'openmct.js', 'platform/**/*.js', 'src/**/*.js' ],
specs: [ 'platform/**/*Spec.js', 'src/**/*Spec.js' ],
},
options = {
requirejsOptimize: {
name: 'bower_components/almond/almond.js',
include: paths.main.replace('.js', ''),
wrap: {
start: (function () {
var buildVariables = {
version: project.version,
timestamp: moment.utc(Date.now()).format(),
revision: fs.existsSync('.git') ? git.long() : 'Unknown',
branch: fs.existsSync('.git') ? git.branch() : 'Unknown'
};
return fs.readFileSync("src/start.frag", 'utf-8')
.replace(/@@(\w+)/g, function (match, key) {
return buildVariables[key];
});;
}()),
endFile: "src/end.frag"
},
optimize: 'uglify2',
uglify2: { output: { comments: /@preserve/ } },
mainConfigFile: paths.main,
wrapShim: true
},
karma: {
configFile: path.resolve(__dirname, 'karma.conf.js'),
singleRun: true
},
sass: {
sourceComments: true
}
};
if (process.env.NODE_ENV === 'development') {
options.requirejsOptimize.optimize = 'none';
}
gulp.task('scripts', function () {
var requirejsOptimize = require('gulp-requirejs-optimize');
return gulp.src(paths.main)
.pipe(sourcemaps.init())
.pipe(requirejsOptimize(options.requirejsOptimize))
.pipe(sourcemaps.write('.'))
.pipe(gulp.dest(paths.dist));
});
gulp.task('test', function (done) {
var karma = require('karma');
new karma.Server(options.karma, done).start();
});
gulp.task('stylesheets', function () {
var sass = require('gulp-sass');
var rename = require('gulp-rename');
var bourbon = require('node-bourbon');
options.sass.includePaths = bourbon.includePaths;
return gulp.src(paths.scss, {base: '.'})
.pipe(sourcemaps.init())
.pipe(sass(options.sass).on('error', sass.logError))
.pipe(rename(function (file) {
file.dirname =
file.dirname.replace(path.sep + 'sass', path.sep + 'css');
return file;
}))
.pipe(sourcemaps.write('.'))
.pipe(gulp.dest(__dirname));
});
gulp.task('lint', function () {
var jshint = require('gulp-jshint');
var merge = require('merge-stream');
var nonspecs = paths.specs.map(function (glob) {
return "!" + glob;
}),
scriptLint = gulp.src(paths.scripts.concat(nonspecs))
.pipe(jshint()),
specLint = gulp.src(paths.specs)
.pipe(jshint({ jasmine: true }));
return merge(scriptLint, specLint)
.pipe(jshint.reporter('gulp-jshint-html-reporter', {
filename: paths.reports + '/lint/jshint-report.html',
createMissingFolders : true
}))
.pipe(jshint.reporter('default'))
.pipe(jshint.reporter('fail'));
});
gulp.task('checkstyle', function () {
var jscs = require('gulp-jscs');
var mkdirp = require('mkdirp');
var reportName = 'jscs-html-report.html';
var reportPath = path.resolve(paths.reports, 'checkstyle', reportName);
var moveReport = fs.rename.bind(fs, reportName, reportPath, _.noop);
mkdirp.sync(path.resolve(paths.reports, 'checkstyle'));
return gulp.src(paths.scripts)
.pipe(jscs())
.pipe(jscs.reporter())
.pipe(jscs.reporter('jscs-html-reporter')).on('finish', moveReport)
.pipe(jscs.reporter('fail'));
});
gulp.task('fixstyle', function () {
var jscs = require('gulp-jscs');
return gulp.src(paths.scripts, { base: '.' })
.pipe(jscs({ fix: true }))
.pipe(gulp.dest('.'));
});
gulp.task('assets', ['stylesheets'], function () {
return gulp.src(paths.assets)
.pipe(gulp.dest(paths.dist));
});
gulp.task('watch', function () {
return gulp.watch(paths.scss, ['stylesheets', 'assets']);
});
gulp.task('serve', function () {
console.log('Running development server with all defaults');
var app = require('./app.js');
});
gulp.task('develop', ['serve', 'stylesheets', 'watch']);
gulp.task('install', [ 'assets', 'scripts' ]);
gulp.task('verify', [ 'lint', 'test', 'checkstyle' ]);
gulp.task('build', [ 'verify', 'install' ]);

View File

@@ -26,58 +26,68 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0, shrink-to-fit=no"> <meta name="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.BarGraph());
openmct.time.clock('local', {start: -THIRTY_MINUTES, end: 0});
openmct.time.timeSystem('utc');
openmct.start();
});
</script>
<link rel="stylesheet" href="platform/commonUI/general/res/css/startup-base.css">
<link rel="stylesheet" href="platform/commonUI/general/res/css/openmct.css">
<link rel="icon" type="image/png" href="platform/commonUI/general/res/images/favicons/favicon-32x32.png" sizes="32x32">
<link rel="icon" type="image/png" href="platform/commonUI/general/res/images/favicons/favicon-96x96.png" sizes="96x96">
<link rel="icon" type="image/png" href="platform/commonUI/general/res/images/favicons/favicon-16x16.png" sizes="16x16">
<link rel="shortcut icon" href="platform/commonUI/general/res/images/favicons/favicon.ico">
<link rel="stylesheet" href="src/plugins/barGraph/res/styles/barGraph.css">
</head> </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,67 @@
*****************************************************************************/ *****************************************************************************/
/*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: 'src/**/*', included: false},
{pattern: 'example/**/*.html', included: false},
{pattern: 'example/**/*.js', included: false},
{pattern: 'example/**/*.json', included: false},
{pattern: 'platform/**/*.js', included: false},
{pattern: 'warp/**/*.js', included: false},
{pattern: 'platform/**/*.html', included: false},
'test-main.js'
], ],
// List of files to exclude.
exclude: [
'platform/framework/src/Main.js'
],
// Preprocess matching files before serving them to the browser.
// https://npmjs.org/browse/keyword/karma-preprocessor
preprocessors: {
'src/**/!(*Spec).js': [ 'coverage' ],
'platform/**/src/**/!(*Spec).js': [ 'coverage' ]
},
// Test results reporter to use
// Possible values: 'dots', 'progress'
// Available reporters: https://npmjs.org/browse/keyword/karma-reporter
reporters: ['progress', 'coverage', 'html', 'junit'],
// Web server port.
port: 9876, 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: [
'Chrome'
],
// 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 +101,12 @@ module.exports = (config) => {
foldAll: false foldAll: false
}, },
preprocessors: { junitReporter: {
// add webpack as preprocessor outputDir: process.env.CIRCLE_TEST_REPORTS || 'dist/reports/junit'
'platform/**/*Spec.js': [ 'webpack' ],
'src/**/*Spec.js': [ 'webpack' ]
}, },
webpack: webpackConfig, // Continuous Integration mode.
// If true, Karma captures browsers, runs the tests and exits.
webpackMiddleware: {
stats: 'errors-only',
logLevel: 'warn'
},
singleRun: true singleRun: true
}); });
} };

View File

@@ -19,19 +19,97 @@
* 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",
"html2canvas": "bower_components/html2canvas/build/html2canvas.min",
"moment": "bower_components/moment/moment",
"moment-duration-format": "bower_components/moment-duration-format/lib/moment-duration-format",
"moment-timezone": "bower_components/moment-timezone/builds/moment-timezone-with-data",
"saveAs": "bower_components/file-saver/FileSaver.min",
"screenfull": "bower_components/screenfull/dist/screenfull.min",
"text": "bower_components/text/text",
"uuid": "bower_components/node-uuid/uuid",
"vue": "node_modules/vue/dist/vue.min",
"zepto": "bower_components/zepto/zepto.min",
"lodash": "bower_components/lodash/lodash",
"d3-selection": "node_modules/d3-selection/dist/d3-selection.min",
"d3-scale": "node_modules/d3-scale/build/d3-scale.min",
"d3-axis": "node_modules/d3-axis/build/d3-axis.min",
"d3-array": "node_modules/d3-array/build/d3-array.min",
"d3-collection": "node_modules/d3-collection/build/d3-collection.min",
"d3-color": "node_modules/d3-color/build/d3-color.min",
"d3-format": "node_modules/d3-format/build/d3-format.min",
"d3-interpolate": "node_modules/d3-interpolate/build/d3-interpolate.min",
"d3-time": "node_modules/d3-time/build/d3-time.min",
"d3-time-format": "node_modules/d3-time-format/build/d3-time-format.min"
},
"shim": {
"angular": {
"exports": "angular"
},
"angular-route": {
"deps": ["angular"]
},
"EventEmitter": {
"exports": "EventEmitter"
},
"html2canvas": {
"exports": "html2canvas"
},
"moment-duration-format": {
"deps": ["moment"]
},
"saveAs": {
"exports": "saveAs"
},
"screenfull": {
"exports": "screenfull"
},
"zepto": {
"exports": "Zepto"
},
"lodash": {
"exports": "lodash"
},
"d3-selection": {
"exports": "d3-selection"
},
"d3-scale": {
"deps": ["d3-array", "d3-collection", "d3-color", "d3-format", "d3-interpolate", "d3-time", "d3-time-format"],
"exports": "d3-scale"
},
"d3-axis": {
"exports": "d3-axis"
}
} }
} });
const MCT = require('./src/MCT'); define([
'./platform/framework/src/Main',
'./src/defaultRegistry',
'./src/MCT',
'./src/plugins/buildInfo/plugin'
], function (Main, defaultRegistry, MCT, buildInfo) {
var openmct = new MCT();
var openmct = new MCT(); openmct.legacyRegistry = defaultRegistry;
openmct.install(openmct.plugins.Plot());
module.exports = openmct; if (typeof BUILD_CONSTANTS !== 'undefined') {
openmct.install(buildInfo(BUILD_CONSTANTS));
}
openmct.on('start', function () {
return new Main().run(defaultRegistry);
});
return openmct;
});

View File

@@ -2,15 +2,7 @@
"name": "openmct", "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,55 @@
"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", "request": "^2.69.0",
"file-saver": "^1.3.8", "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",
"html2canvas": "^1.0.0-alpha.12", "gulp-jscs": "^3.0.2",
"imports-loader": "^0.8.0", "gulp-jshint": "^2.0.0",
"istanbul-instrumenter-loader": "^3.0.1", "gulp-jshint-html-reporter": "^0.1.3",
"jasmine-core": "^3.1.0", "gulp-rename": "^1.2.2",
"gulp-requirejs-optimize": "^0.3.1",
"gulp-sass": "^3.1.0",
"gulp-sourcemaps": "^1.6.0",
"jasmine-core": "^2.3.0",
"jscs-html-reporter": "^0.1.0",
"jsdoc": "^3.3.2", "jsdoc": "^3.3.2",
"karma": "^2.0.3", "jshint": "^2.7.0",
"karma-chrome-launcher": "^2.2.0", "karma": "^0.13.3",
"karma-cli": "^1.0.1", "karma-chrome-launcher": "^0.1.12",
"karma-coverage": "^1.1.2", "karma-cli": "0.0.4",
"karma-coverage": "^0.5.3",
"karma-html-reporter": "^0.2.7", "karma-html-reporter": "^0.2.7",
"karma-jasmine": "^1.1.2", "karma-jasmine": "^0.1.5",
"karma-webpack": "^3.0.0", "karma-junit-reporter": "^0.3.8",
"location-bar": "^3.0.1", "karma-requirejs": "^0.2.2",
"lodash": "^3.10.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", "requirejs": "2.1.x",
"painterro": "^0.2.65",
"printj": "^1.1.0",
"raw-loader": "^0.5.1",
"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'", "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

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

View File

@@ -19,46 +19,41 @@
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 ng-controller="ObjectInspectorController as controller" class="grid-properties"> <div ng-controller="ObjectInspectorController as controller">
<ul class="l-inspector-part"> <ul class="flex-elem grows l-inspector-part">
<h2 class="first">Properties</h2> <li>
<li class="t-repeat grid-row" <em class="t-inspector-part-header">Properties</em>
ng-repeat="data in metadata" <div class="inspector-properties"
ng-class="{ first:$index === 0 }"> ng-repeat="data in metadata"
<div class="grid-cell label">{{ data.name }}</div> ng-class="{ first:$index === 0 }">
<div class="grid-cell value">{{ data.value }}</div> <div class="label">{{ data.name }}</div>
</li> <div class="value">{{ data.value }}</div>
</ul>
<ul class="l-inspector-part" ng-if="contextutalParents.length > 0">
<h2 title="The location of this linked object.">Location</h2>
<li class="grid-row">
<div class="label" ng-if="primaryParents.length > 0">This Link</div>
<div class="grid-cell value">
<div class="t-repeat inspector-location"
ng-repeat="parent in contextutalParents"
ng-class="{ last:($index + 1) === contextualParents.length }">
<mct-representation key="'label'"
mct-object="parent"
ng-click="parent.getCapability('action').perform('navigate')"
class="location-item">
</mct-representation>
</div>
</div> </div>
</li> </li>
<li class="grid-row" ng-if="primaryParents.length > 0"> <li ng-if="contextutalParents.length > 0">
<div class="grid-cell label">Original</div> <em class="t-inspector-part-header" title="The location of this linked object.">Location</em>
<div class="grid-cell value"> <div ng-if="primaryParents.length > 0" class="section-header">This Object</div>
<div class="t-repeat inspector-location value" <span class="inspector-location"
ng-repeat="parent in primaryParents" ng-repeat="parent in contextutalParents"
ng-class="{ last:($index + 1) === primaryParents.length }"> ng-class="{ last:($index + 1) === contextualParents.length }">
<mct-representation key="'label'" <mct-representation key="'label'"
mct-object="parent" mct-object="parent"
ng-click="parent.getCapability('action').perform('navigate')" ng-click="parent.getCapability('action').perform('navigate')"
class="location-item"> class="location-item">
</mct-representation> </mct-representation>
</div> </span>
</div> </li>
<li ng-if="primaryParents.length > 0">
<div class="section-header">Object's Original</div>
<span class="inspector-location"
ng-repeat="parent in primaryParents"
ng-class="{ last:($index + 1) === primaryParents.length }">
<mct-representation key="'label'"
mct-object="parent"
ng-click="parent.getCapability('action').perform('navigate')"
class="location-item">
</mct-representation>
</span>
</li> </li>
</ul> </ul>
</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,9 +47,8 @@ define(
urlService, urlService,
defaultPath defaultPath
) { ) {
window.browseScope = $scope; var initialPath = ($route.current.params.ids || defaultPath).split("/");
var initialPath = ($route.current.params.ids || defaultPath).split("/"), var currentIds;
currentIds;
$scope.treeModel = { $scope.treeModel = {
selectedObject: undefined, selectedObject: undefined,
@@ -57,24 +56,7 @@ define(
navigationService.setNavigation(object, true); navigationService.setNavigation(object, true);
}, },
allowSelection: function (object) { allowSelection: function (object) {
var domainObjectInView = navigationService.getNavigation(), return navigationService.shouldNavigate();
isInEditMode = domainObjectInView.getCapability('status').get('editing');
if (isInEditMode) {
var actions = object.getCapability('action'),
previewAction = actions.getActions({key: 'mct-preview-action'})[0];
if (previewAction && previewAction.perform) {
previewAction.perform();
return false;
} else {
return navigationService.shouldNavigate();
}
} else {
return true;
}
} }
}; };

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

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

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

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

View File

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

View File

@@ -50,14 +50,14 @@ define(
"navigationService", "navigationService",
["getNavigation", "addListener"] ["getNavigation", "addListener"]
); );
mockNavigationService.addListener.and.returnValue(mockNavigationUnlistener); mockNavigationService.addListener.andReturn(mockNavigationUnlistener);
mockStatusUnlistener = jasmine.createSpy("statusUnlistener"); mockStatusUnlistener = jasmine.createSpy("statusUnlistener");
mockStatusCapability = jasmine.createSpyObj( mockStatusCapability = jasmine.createSpyObj(
"statusCapability", "statusCapability",
["listen"] ["listen"]
); );
mockStatusCapability.listen.and.returnValue(mockStatusUnlistener); mockStatusCapability.listen.andReturn(mockStatusUnlistener);
mockDomainObject = jasmine.createSpyObj( mockDomainObject = jasmine.createSpyObj(
'domainObject', 'domainObject',
@@ -68,13 +68,13 @@ define(
'hasCapability' 'hasCapability'
] ]
); );
mockDomainObject.getId.and.returnValue("domainObject"); mockDomainObject.getId.andReturn("domainObject");
mockDomainObject.getModel.and.returnValue({}); mockDomainObject.getModel.andReturn({});
mockDomainObject.hasCapability.and.returnValue(true); mockDomainObject.hasCapability.andReturn(true);
mockDomainObject.getCapability.and.returnValue(mockStatusCapability); mockDomainObject.getCapability.andReturn(mockStatusCapability);
mockLocation = jasmine.createSpyObj('location', ['search']); mockLocation = jasmine.createSpyObj('location', ['search']);
mockLocation.search.and.returnValue({}); mockLocation.search.andReturn({});
mockAttrs = {}; mockAttrs = {};
@@ -84,7 +84,7 @@ define(
it("listens for changes to navigation and attaches a status" + it("listens for changes to navigation and attaches a status" +
" listener", function () { " listener", function () {
expect(mockNavigationService.addListener).toHaveBeenCalledWith(jasmine.any(Function)); expect(mockNavigationService.addListener).toHaveBeenCalledWith(jasmine.any(Function));
mockNavigationService.addListener.calls.mostRecent().args[0](mockDomainObject); mockNavigationService.addListener.mostRecentCall.args[0](mockDomainObject);
expect(mockStatusCapability.listen).toHaveBeenCalledWith(jasmine.any(Function)); expect(mockStatusCapability.listen).toHaveBeenCalledWith(jasmine.any(Function));
}); });
@@ -93,8 +93,8 @@ define(
controller.toggle(); controller.toggle();
// test pre-condition that inspector is hidden // test pre-condition that inspector is hidden
expect(controller.visible()).toBe(false); expect(controller.visible()).toBe(false);
mockNavigationService.addListener.calls.mostRecent().args[0](mockDomainObject); mockNavigationService.addListener.mostRecentCall.args[0](mockDomainObject);
mockStatusCapability.listen.calls.mostRecent().args[0](["editing"]); mockStatusCapability.listen.mostRecentCall.args[0](["editing"]);
expect(controller.visible()).toBe(true); expect(controller.visible()).toBe(true);
}); });

View File

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

View File

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

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.andReturn(id);
mockDomainObject.getModel.andReturn({});
return mockDomainObject;
});
mockAgentService = jasmine.createSpyObj( mockAgentService = jasmine.createSpyObj(
"agentService", "agentService",
["isMobile", "isPhone", "isTablet", "isPortrait", "isLandscape"] ["isMobile", "isPhone", "isTablet", "isPortrait", "isLandscape"]
@@ -53,7 +65,7 @@ define(
mockWindow = jasmine.createSpyObj("$window", ["open"]); mockWindow = jasmine.createSpyObj("$window", ["open"]);
mockLocation = jasmine.createSpyObj('location', ['search']); mockLocation = jasmine.createSpyObj('location', ['search']);
mockLocation.search.and.returnValue({}); mockLocation.search.andReturn({});
mockAttrs = {}; mockAttrs = {};
}); });
@@ -71,9 +83,9 @@ define(
}); });
it("collapses on navigation changes on portrait-oriented phones", function () { it("collapses on navigation changes on portrait-oriented phones", function () {
mockAgentService.isMobile.and.returnValue(true); mockAgentService.isMobile.andReturn(true);
mockAgentService.isPhone.and.returnValue(true); mockAgentService.isPhone.andReturn(true);
mockAgentService.isPortrait.and.returnValue(true); mockAgentService.isPortrait.andReturn(true);
controller = instantiateController(); controller = instantiateController();
expect(controller.visible()).toBeTruthy(); expect(controller.visible()).toBeTruthy();
@@ -90,13 +102,13 @@ define(
}); });
it("sets pane state to false when in location.search", function () { it("sets pane state to false when in location.search", function () {
mockLocation.search.and.returnValue({'hideTree': true}); mockLocation.search.andReturn({'hideTree': true});
expect(instantiateController().visible()).toBe(false); expect(instantiateController().visible()).toBe(false);
expect(mockLocation.search).toHaveBeenCalledWith('hideTree', undefined); expect(mockLocation.search).toHaveBeenCalledWith('hideTree', undefined);
}); });
it("sets state to true when not found in location.search", function () { it("sets state to true when not found in location.search", function () {
mockLocation.search.and.returnValue({}); mockLocation.search.andReturn({});
expect(instantiateController().visible()).toBe(true); expect(instantiateController().visible()).toBe(true);
expect(mockLocation.search).not.toHaveBeenCalledWith('hideTree', undefined); expect(mockLocation.search).not.toHaveBeenCalledWith('hideTree', undefined);
}); });

View File

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

View File

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

View File

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

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

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

@@ -4,10 +4,7 @@
<div class="top-bar"> <div class="top-bar">
<div class="title">{{ngModel.title}}</div> <div class="title">{{ngModel.title}}</div>
</div> </div>
<div class="hint" ng-hide="ngModel.hint === undefined"> <div class="hint" ng-hide="ngModel.hint === undefined">{{ngModel.hint}}</div>
{{ngModel.hint}}
<span ng-if="ngModel.timestamp !== undefined">[{{ngModel.timestamp}}]</span>
</div>
<div class="message-body"> <div class="message-body">
<div class="message-action"> <div class="message-action">
{{ngModel.actionText}} {{ngModel.actionText}}

View File

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

View File

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

View File

@@ -39,6 +39,7 @@ define([
"./src/policies/EditableMovePolicy", "./src/policies/EditableMovePolicy",
"./src/policies/EditContextualActionPolicy", "./src/policies/EditContextualActionPolicy",
"./src/representers/EditRepresenter", "./src/representers/EditRepresenter",
"./src/representers/EditToolbarRepresenter",
"./src/capabilities/EditorCapability", "./src/capabilities/EditorCapability",
"./src/capabilities/TransactionCapabilityDecorator", "./src/capabilities/TransactionCapabilityDecorator",
"./src/services/TransactionManager", "./src/services/TransactionManager",
@@ -49,14 +50,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,
@@ -77,6 +78,7 @@ define([
EditableMovePolicy, EditableMovePolicy,
EditContextualActionPolicy, EditContextualActionPolicy,
EditRepresenter, EditRepresenter,
EditToolbarRepresenter,
EditorCapability, EditorCapability,
TransactionCapabilityDecorator, TransactionCapabilityDecorator,
TransactionManager, TransactionManager,
@@ -188,7 +190,6 @@ define([
"name": "Remove", "name": "Remove",
"description": "Remove this object from its containing object.", "description": "Remove this object from its containing object.",
"depends": [ "depends": [
"dialogService",
"navigationService" "navigationService"
] ]
}, },
@@ -319,12 +320,6 @@ define([
] ]
} }
], ],
"templates": [
{
key: "elementsPool",
template: elementsTemplate
}
],
"components": [ "components": [
{ {
"type": "decorator", "type": "decorator",
@@ -386,6 +381,12 @@ define([
"depends": [ "depends": [
"$log" "$log"
] ]
},
{
"implementation": EditToolbarRepresenter,
"depends": [
"openmct"
]
} }
], ],
"constants": [ "constants": [
@@ -405,8 +406,7 @@ define([
"description": "Provides transactional editing capabilities", "description": "Provides transactional editing capabilities",
"implementation": EditorCapability, "implementation": EditorCapability,
"depends": [ "depends": [
"transactionService", "transactionService"
"openmct"
] ]
} }
], ],
@@ -424,17 +424,6 @@ define([
"transactionService" "transactionService"
] ]
} }
],
"runs": [
{
depends: [
"toolbars[]",
"openmct"
],
implementation: function (toolbars, openmct) {
toolbars.forEach(openmct.toolbars.addProvider, openmct.toolbars);
}
}
] ]
} }
}); });

View File

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

View File

@@ -24,7 +24,7 @@
class="flex-elem holder" class="flex-elem holder"
ng-model="filterBy"> ng-model="filterBy">
</mct-include> </mct-include>
<div class="flex-elem grows vscroll scroll-pad"> <div class="flex-elem grows vscroll">
<ul class="tree" id="inspector-elements-tree" <ul class="tree" id="inspector-elements-tree"
ng-if="composition.length > 0"> ng-if="composition.length > 0">
<li ng-repeat="containedObject in composition | filter:searchElements"> <li ng-repeat="containedObject in composition | filter:searchElements">

View File

@@ -23,119 +23,111 @@
/** /**
* Module defining RemoveAction. Created by vwoeltje on 11/17/14. * Module defining RemoveAction. Created by vwoeltje on 11/17/14.
*/ */
define([ define(
'./RemoveDialog' [],
], function ( function () {
RemoveDialog
) {
/** /**
* Construct an action which will remove the provided object manifestation. * Construct an action which will remove the provided object manifestation.
* The object will be removed from its parent's composition; the parent * The object will be removed from its parent's composition; the parent
* is looked up via the "context" capability (so this will be the * is looked up via the "context" capability (so this will be the
* immediate ancestor by which this specific object was reached.) * immediate ancestor by which this specific object was reached.)
* *
* @param {DialogService} dialogService a service which will show the dialog * @param {DomainObject} object the object to be removed
* @param {NavigationService} navigationService a service that maintains the current navigation state * @param {ActionContext} context the context in which this action is performed
* @param {ActionContext} context the context in which this action is performed * @memberof platform/commonUI/edit
* @memberof platform/commonUI/edit * @constructor
* @constructor * @implements {Action}
* @implements {Action}
*/
function RemoveAction(dialogService, navigationService, context) {
this.domainObject = (context || {}).domainObject;
this.dialogService = dialogService;
this.navigationService = navigationService;
}
/**
* Perform this action.
*/
RemoveAction.prototype.perform = function () {
var dialog,
dialogService = this.dialogService,
domainObject = this.domainObject,
navigationService = this.navigationService;
/*
* Check whether an object ID matches the ID of the object being
* removed (used to filter a parent's composition to handle the
* removal.)
*/ */
function isNotObject(otherObjectId) { function RemoveAction(navigationService, context) {
return otherObjectId !== domainObject.getId(); this.domainObject = (context || {}).domainObject;
this.navigationService = navigationService;
} }
/* /**
* Mutate a parent object such that it no longer contains the object * Perform this action.
* which is being removed. * @return {Promise} a promise which will be
* fulfilled when the action has completed.
*/ */
function doMutate(model) { RemoveAction.prototype.perform = function () {
model.composition = model.composition.filter(isNotObject); var navigationService = this.navigationService,
} domainObject = this.domainObject;
/*
/* * Check whether an object ID matches the ID of the object being
* Checks current object and ascendants of current * removed (used to filter a parent's composition to handle the
* object with object being removed, if the current * removal.)
* object or any in the current object's path is being removed, */
* navigate back to parent of removed object. function isNotObject(otherObjectId) {
*/ return otherObjectId !== domainObject.getId();
function checkObjectNavigation(object, parentObject) {
// Traverse object starts at current location
var traverseObject = (navigationService).getNavigation(),
context;
// Stop when object is not defined (above ROOT)
while (traverseObject) {
// If object currently traversed to is object being removed
// navigate to parent of current object and then exit loop
if (traverseObject.getId() === object.getId()) {
navigationService.setNavigation(parentObject);
return;
}
// Traverses to parent of current object, moving
// up the ascendant path
context = traverseObject.getCapability('context');
traverseObject = context && context.getParent();
} }
}
/* /*
* Remove the object from its parent, as identified by its context * Mutate a parent object such that it no longer contains the object
* capability. Based on object's location and selected object's location * which is being removed.
* user may be navigated to existing parent object */
*/ function doMutate(model) {
function removeFromContext(object) { model.composition = model.composition.filter(isNotObject);
var contextCapability = object.getCapability('context'), }
parent = contextCapability.getParent();
// If currently within path of removed object(s), /*
// navigates to existing object up tree * Checks current object and ascendants of current
checkObjectNavigation(object, parent); * object with object being removed, if the current
* object or any in the current object's path is being removed,
* navigate back to parent of removed object.
*/
function checkObjectNavigation(object, parentObject) {
// Traverse object starts at current location
var traverseObject = (navigationService).getNavigation(),
context;
return parent.useCapability('mutation', doMutate); // Stop when object is not defined (above ROOT)
} while (traverseObject) {
// If object currently traversed to is object being removed
// navigate to parent of current object and then exit loop
if (traverseObject.getId() === object.getId()) {
navigationService.setNavigation(parentObject);
return;
}
// Traverses to parent of current object, moving
// up the ascendant path
context = traverseObject.getCapability('context');
traverseObject = context && context.getParent();
}
}
/* /*
* Pass in the function to remove the domain object so it can be * Remove the object from its parent, as identified by its context
* associated with an 'OK' button press * capability. Based on object's location and selected object's location
*/ * user may be navigated to existing parent object
dialog = new RemoveDialog(dialogService, domainObject, removeFromContext); */
dialog.show(); function removeFromContext(object) {
}; var contextCapability = object.getCapability('context'),
parent = contextCapability.getParent();
// Object needs to have a parent for Remove to be applicable // If currently within path of removed object(s),
RemoveAction.appliesTo = function (context) { // navigates to existing object up tree
var object = (context || {}).domainObject, checkObjectNavigation(object, parent);
contextCapability = object && object.getCapability("context"),
parent = contextCapability && contextCapability.getParent(),
parentType = parent && parent.getCapability('type'),
parentCreatable = parentType && parentType.hasFeature('creation');
// Only creatable types should be modifiable return parent.useCapability('mutation', doMutate);
return parent !== undefined && }
Array.isArray(parent.getModel().composition) &&
parentCreatable;
};
return RemoveAction; return removeFromContext(domainObject);
}); };
// Object needs to have a parent for Remove to be applicable
RemoveAction.appliesTo = function (context) {
var object = (context || {}).domainObject,
contextCapability = object && object.getCapability("context"),
parent = contextCapability && contextCapability.getParent(),
parentType = parent && parent.getCapability('type'),
parentCreatable = parentType && parentType.hasFeature('creation');
// Only creatable types should be modifiable
return parent !== undefined &&
Array.isArray(parent.getModel().composition) &&
parentCreatable;
};
return RemoveAction;
}
);

View File

@@ -1,77 +0,0 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2017, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
define([], function () {
/**
* @callback removeCallback
* @param {DomainObject} domainObject the domain object to be removed
*/
/**
* Construct a new Remove dialog.
*
* @param {DialogService} dialogService the service that shows the dialog
* @param {DomainObject} domainObject the domain object to be removed
* @param {removeCallback} removeCallback callback that handles removal of the domain object
* @memberof platform/commonUI/edit
* @constructor
*/
function RemoveDialog(dialogService, domainObject, removeCallback) {
this.dialogService = dialogService;
this.domainObject = domainObject;
this.removeCallback = removeCallback;
}
/**
* Display a dialog to confirm the removal of a domain object.
*/
RemoveDialog.prototype.show = function () {
var dialog,
domainObject = this.domainObject,
removeCallback = this.removeCallback,
model = {
title: 'Remove ' + domainObject.getModel().name,
actionText: 'Warning! This action will permanently remove this object. Are you sure you want to continue?',
severity: 'alert',
primaryOption: {
label: 'OK',
callback: function () {
removeCallback(domainObject);
dialog.dismiss();
}
},
options: [
{
label: 'Cancel',
callback: function () {
dialog.dismiss();
}
}
]
};
dialog = this.dialogService.showBlockingMessage(model);
};
return RemoveDialog;
});

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

@@ -20,110 +20,192 @@
* at runtime from the About dialog for additional information. * at runtime from the About dialog for additional information.
*****************************************************************************/ *****************************************************************************/
define( define(
[ [],
'../../../../../src/api/objects/object-utils', function () {
'lodash'
], // Utility functions for reducing truth arrays
function ( function and(a, b) {
objectUtils, return a && b;
_ }
) { function or(a, b) {
return a || b;
}
/** /**
* Provides initial structure and state (as suitable for provision * Provides initial structure and state (as suitable for provision
* to the `mct-toolbar` directive) for a view's toolbar, based on * to the `mct-toolbar` directive) for a view's tool bar, based on
* that view's declaration of what belongs in its toolbar and on * that view's declaration of what belongs in its tool bar and on
* the current selection. * the current selection.
* *
* @param $scope the Angular scope * @param structure toolbar structure, as provided by view definition
* @param {Object} openmct the openmct object * @param {Function} commit callback to invoke after changes
* @param structure the toolbar structure
* @memberof platform/commonUI/edit * @memberof platform/commonUI/edit
* @constructor * @constructor
*/ */
function EditToolbar($scope, openmct, structure) { function EditToolbar(structure, commit) {
this.toolbarStructure = [];
this.properties = [];
this.toolbarState = [];
this.openmct = openmct;
this.domainObjectsById = {};
this.unobserveObjects = [];
this.stateTracker = [];
$scope.$watchCollection(this.getState.bind(this), this.handleStateChanges.bind(this));
$scope.$on("$destroy", this.destroy.bind(this));
this.updateToolbar(structure);
this.registerListeners(structure);
}
/**
* Updates the toolbar with a new structure.
*
* @param {Array} structure the toolbar structure
*/
EditToolbar.prototype.updateToolbar = function (structure) {
var self = this; var self = this;
function addKey(item) { // Generate a new key for an item's property
self.stateTracker.push({ function addKey(property) {
id: objectUtils.makeKeyString(item.domainObject.identifier), self.properties.push(property);
domainObject: item.domainObject,
property: item.property
});
self.properties.push(item.property);
return self.properties.length - 1; // Return index of property return self.properties.length - 1; // Return index of property
} }
// Invoke all functions in selections with the given name
function invoke(method, value) {
if (method) {
// Make the change in the selection
self.selection.forEach(function (selected) {
if (typeof selected[method] === 'function') {
selected[method](value);
}
});
// ...and commit!
commit();
}
}
// Prepare a toolbar item based on current selection
function convertItem(item) { function convertItem(item) {
var converted = Object.create(item || {}); var converted = Object.create(item || {});
if (item.property) { if (item.property) {
converted.key = addKey(item); converted.key = addKey(item.property);
} }
if (item.method) { if (item.method) {
converted.click = function (value) { converted.click = function (v) {
item.method(value); invoke(item.method, v);
}; };
} }
return converted; return converted;
} }
// Prepare a toolbar section
function convertSection(section) {
var converted = Object.create(section || {});
converted.items =
((section || {}).items || [])
.map(convertItem);
return converted;
}
this.toolbarState = [];
this.selection = undefined;
this.properties = [];
this.toolbarStructure = Object.create(structure || {});
this.toolbarStructure.sections =
((structure || {}).sections || []).map(convertSection);
}
// Check if all elements of the selection which have this
// property have the same value for this property.
EditToolbar.prototype.isConsistent = function (property) {
var self = this,
consistent = true,
observed = false,
state;
// Check if a given element of the selection is consistent
// with previously-observed elements for this property.
function checkConsistency(selected) {
var next;
// Ignore selections which don't have this property
if (selected[property] !== undefined) {
// Look up state of this element in the selection
next = self.lookupState(property, selected);
// Detect inconsistency
if (observed) {
consistent = consistent && (next === state);
}
// Track state for next iteration
state = next;
observed = true;
}
}
// Iterate through selections
self.selection.forEach(checkConsistency);
return consistent;
};
// Used to filter out items which are applicable (or not)
// to the current selection.
EditToolbar.prototype.isApplicable = function (item) {
var property = (item || {}).property,
method = (item || {}).method,
exclusive = !!(item || {}).exclusive;
// Check if a selected item defines this property
function hasProperty(selected) {
return (property && (selected[property] !== undefined)) ||
(method && (typeof selected[method] === 'function'));
}
return this.selection.map(hasProperty).reduce(
exclusive ? and : or,
exclusive
) && this.isConsistent(property);
};
// Look up the current value associated with a property
EditToolbar.prototype.lookupState = function (property, selected) {
var value = selected[property];
return (typeof value === 'function') ? value() : value;
};
/**
* Set the current selection. Visibility of sections
* and items in the toolbar will be updated to match this.
* @param {Array} s the new selection
*/
EditToolbar.prototype.setSelection = function (s) {
var self = this;
// Show/hide controls in this section per applicability
function refreshSectionApplicability(section) {
var count = 0;
// Show/hide each item
(section.items || []).forEach(function (item) {
item.hidden = !self.isApplicable(item);
count += item.hidden ? 0 : 1;
});
// Hide this section if there are no applicable items
section.hidden = !count;
}
// Get initial value for a given property // Get initial value for a given property
function initializeState(property) { function initializeState(property) {
var result; var result;
structure.forEach(function (item) { // Look through all selections for this property;
if (item.property === property) { // values should all match by the time we perform
result = _.get(item.domainObject, item.property); // this lookup anyway.
} self.selection.forEach(function (selected) {
result = (selected[property] !== undefined) ?
self.lookupState(property, selected) :
result;
}); });
return result; return result;
} }
// Tracks the domain object and property for every element in the state array this.selection = s;
this.stateTracker = []; this.toolbarStructure.sections.forEach(refreshSectionApplicability);
this.toolbarStructure = structure.map(convertItem);
this.toolbarState = this.properties.map(initializeState); this.toolbarState = this.properties.map(initializeState);
}; };
/** /**
* Gets the structure of the toolbar, as appropriate to * Get the structure of the toolbar, as appropriate to
* pass to `mct-toolbar`. * pass to `mct-toolbar`.
* * @returns the toolbar structure
* @returns {Array} the toolbar structure
*/ */
EditToolbar.prototype.getStructure = function () { EditToolbar.prototype.getStructure = function () {
return this.toolbarStructure; return this.toolbarStructure;
}; };
/** /**
* Gets the current state of the toolbar, as appropriate * Get the current state of the toolbar, as appropriate
* to two-way bind to the state handled by `mct-toolbar`. * to two-way bind to the state handled by `mct-toolbar`.
*
* @returns {Array} state of the toolbar * @returns {Array} state of the toolbar
*/ */
EditToolbar.prototype.getState = function () { EditToolbar.prototype.getState = function () {
@@ -131,124 +213,48 @@ define(
}; };
/** /**
* Mutates the domain object's property with a new value. * Update state within the current selection.
*
* @param {Object} dominObject the domain object
* @param {string} property the domain object's property to update
* @param value the property's new value
*/
EditToolbar.prototype.updateDomainObject = function (domainObject, property, value) {
this.openmct.objects.mutate(domainObject, property, value);
};
/**
* Updates state with the new value.
*
* @param {number} index the index of the corresponding * @param {number} index the index of the corresponding
* element in the state array * element in the state array
* @param value the new value to update the state array with * @param value the new value to convey to the selection
*/ */
EditToolbar.prototype.updateState = function (index, value) { EditToolbar.prototype.updateState = function (index, value) {
this.toolbarState[index] = value;
};
/**
* Register listeners for domain objects to watch for updates.
*
* @param {Array} the toolbar structure
*/
EditToolbar.prototype.registerListeners = function (structure) {
var self = this; var self = this;
function observeObject(domainObject, id) { // Update value for this property in all elements of the
var unobserveObject = self.openmct.objects.observe(domainObject, '*', function (newObject) { // selection which have this property.
self.domainObjectsById[id].newObject = JSON.parse(JSON.stringify(newObject)); function updateProperties(property, val) {
self.scheduleStateUpdate(); var changed = false;
});
self.unobserveObjects.push(unobserveObject); // Update property in a selected element
function updateProperty(selected) {
// Ignore selected elements which don't have this property
if (selected[property] !== undefined) {
// Check if this is a setter, or just assignable
if (typeof selected[property] === 'function') {
changed =
changed || (selected[property]() !== val);
selected[property](val);
} else {
changed =
changed || (selected[property] !== val);
selected[property] = val;
}
}
}
// Update property in all selected elements
self.selection.forEach(updateProperty);
// Return whether or not anything changed
return changed;
} }
structure.forEach(function (item) { return updateProperties(this.properties[index], value);
var domainObject = item.domainObject;
var id = objectUtils.makeKeyString(domainObject.identifier);
if (!self.domainObjectsById[id]) {
self.domainObjectsById[id] = {
domainObject: domainObject,
properties: []
};
observeObject(domainObject, id);
}
self.domainObjectsById[id].properties.push(item.property);
});
};
/**
* Delays updating the state.
*/
EditToolbar.prototype.scheduleStateUpdate = function () {
if (this.stateUpdateScheduled) {
return;
}
this.stateUpdateScheduled = true;
setTimeout(this.updateStateAfterMutation.bind(this));
};
EditToolbar.prototype.updateStateAfterMutation = function () {
this.stateTracker.forEach(function (state, index) {
if (!this.domainObjectsById[state.id].newObject) {
return;
}
var domainObject = this.domainObjectsById[state.id].domainObject;
var newObject = this.domainObjectsById[state.id].newObject;
var currentValue = _.get(domainObject, state.property);
var newValue = _.get(newObject, state.property);
state.domainObject = newObject;
if (currentValue !== newValue) {
this.updateState(index, newValue);
}
}, this);
Object.values(this.domainObjectsById).forEach(function (tracker) {
if (tracker.newObject) {
tracker.domainObject = tracker.newObject;
}
delete tracker.newObject;
});
this.stateUpdateScheduled = false;
};
/**
* Removes the listeners.
*/
EditToolbar.prototype.deregisterListeners = function () {
this.unobserveObjects.forEach(function (unobserveObject) {
unobserveObject();
});
this.unobserveObjects = [];
};
EditToolbar.prototype.handleStateChanges = function (state) {
(state || []).map(function (newValue, index) {
var domainObject = this.stateTracker[index].domainObject;
var property = this.stateTracker[index].property;
var currentValue = _.get(domainObject, property);
if (currentValue !== newValue) {
this.updateDomainObject(domainObject, property, newValue);
}
}, this);
};
EditToolbar.prototype.destroy = function () {
this.deregisterListeners();
}; };
return EditToolbar; return EditToolbar;
} }
); );

View File

@@ -0,0 +1,154 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2018, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
define(
['./EditToolbar', './EditToolbarSelection'],
function (EditToolbar, EditToolbarSelection) {
// No operation
var NOOP_REPRESENTER = {
represent: function () {},
destroy: function () {}
};
/**
* The EditToolbarRepresenter populates the toolbar in Edit mode
* based on a view's definition.
* @param {Scope} scope the Angular scope of the representation
* @memberof platform/commonUI/edit
* @constructor
* @implements {Representer}
*/
function EditToolbarRepresenter(openmct, scope, element, attrs) {
var self = this;
// Mark changes as ready to persist
function commit(message) {
if (scope.commit) {
scope.commit(message);
}
}
// Handle changes to the current selection
function updateSelection(selection) {
// Only update if there is a toolbar to update
if (self.toolbar) {
// Make sure selection is array-like
selection = Array.isArray(selection) ?
selection :
(selection ? [selection] : []);
// Update the toolbar's selection
self.toolbar.setSelection(selection);
// ...and expose its structure/state
self.toolbarObject.structure =
self.toolbar.getStructure();
self.toolbarObject.state =
self.toolbar.getState();
}
}
// Get state (to watch it)
function getState() {
return self.toolbarObject.state;
}
// Update selection models to match changed toolbar state
function updateState(state) {
// Update underlying state based on toolbar changes
var changed = (state || []).map(function (value, index) {
return self.toolbar.updateState(index, value);
}).reduce(function (a, b) {
return a || b;
}, false);
// Only commit if something actually changed
if (changed) {
// Commit the changes.
commit("Changes from toolbar.");
}
}
this.clearExposedToolbar = function () {
// Clear exposed toolbar state (if any)
if (attrs.toolbar) {
delete scope.$parent[attrs.toolbar];
}
};
this.exposeToolbar = function () {
scope.$parent[self.attrs.toolbar] = self.toolbarObject;
};
this.commit = commit;
this.attrs = attrs;
this.updateSelection = updateSelection;
this.toolbar = undefined;
this.toolbarObject = {};
this.openmct = openmct;
this.scope = scope;
// If this representation exposes a toolbar, set up watches
// to synchronize with it.
if (attrs && attrs.toolbar) {
// Detect and handle changes to state from the toolbar
scope.$watchCollection(getState, updateState);
// Watch for changes in the current selection state
scope.$watchCollection("selection.all()", updateSelection);
// Expose toolbar state under that name
scope.$parent[attrs.toolbar] = this.toolbarObject;
} else {
// No toolbar declared, so do nothing.
return NOOP_REPRESENTER;
}
}
// Represent a domain object using this definition
EditToolbarRepresenter.prototype.represent = function (representation) {
// Get the newest toolbar definition from the view
var definition = (representation || {}).toolbar || {};
// If we have been asked to expose toolbar state...
if (this.attrs.toolbar) {
// Initialize toolbar object
this.toolbar = new EditToolbar(definition, this.commit);
// Ensure toolbar state is exposed
this.exposeToolbar();
}
// Add toolbar selection to scope.
this.scope.selection = new EditToolbarSelection(
this.scope,
this.openmct
);
// Initialize toolbar to current selection
this.updateSelection(this.scope.selection.all());
};
// Destroy; remove toolbar object from parent scope
EditToolbarRepresenter.prototype.destroy = function () {
this.clearExposedToolbar();
};
return EditToolbarRepresenter;
}
);

View File

@@ -0,0 +1,157 @@
/*****************************************************************************
* Open MCT, Copyright (c) 2014-2018, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* Open MCT is licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Open MCT includes source code licensed under additional open source
* licenses. See the Open Source Licenses file (LICENSES.md) included with
* this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information.
*****************************************************************************/
define(
[],
function () {
/**
* Tracks selection state for editable views. Selection is
* implemented such that (from the toolbar's perspective)
* up to two objects can be "selected" at any given time:
*
* * The view proxy (see the `proxy` method), which provides
* an interface for interacting with the view itself (e.g.
* for buttons like "Add")
* * The selection, for single selected elements within the
* view.
*
* @memberof platform/commonUI/edit
* @constructor
*/
function EditToolbarSelection($scope, openmct) {
this.selection = [{}];
this.selecting = false;
this.selectedObj = undefined;
this.openmct = openmct;
var self = this;
function setSelection(selection) {
var selected = selection[0];
if (selected && selected.context.toolbar) {
self.select(selected.context.toolbar);
} else {
self.deselect();
}
if (selected && selected.context.viewProxy) {
self.proxy(selected.context.viewProxy);
}
setTimeout(function () {
$scope.$apply();
});
}
$scope.$on("$destroy", function () {
self.openmct.selection.off('change', setSelection);
});
this.openmct.selection.on('change', setSelection);
setSelection(this.openmct.selection.get());
}
/**
* Check if an object is currently selected.
* @param {*} obj the object to check for selection
* @returns {boolean} true if selected, otherwise false
*/
EditToolbarSelection.prototype.selected = function (obj) {
return (obj === this.selectedObj) || (obj === this.selection[0]);
};
/**
* Select an object.
* @param obj the object to select
* @returns {boolean} true if selection changed
*/
EditToolbarSelection.prototype.select = function (obj) {
// Proxy is always selected
if (obj === this.selection[0]) {
return false;
}
// Clear any existing selection
this.deselect();
// Note the current selection state
this.selectedObj = obj;
this.selecting = true;
// Add the selection
this.selection.push(obj);
};
/**
* Clear the current selection.
* @returns {boolean} true if selection changed
*/
EditToolbarSelection.prototype.deselect = function () {
// Nothing to do if we don't have a selected object
if (this.selecting) {
// Clear state tracking
this.selecting = false;
this.selectedObj = undefined;
// Remove the selection
this.selection.pop();
return true;
}
return false;
};
/**
* Get the currently-selected object.
* @returns the currently selected object
*/
EditToolbarSelection.prototype.get = function () {
return this.selectedObj;
};
/**
* Get/set the view proxy (for toolbar actions taken upon
* the view itself.)
* @param [proxy] the view proxy (if setting)
* @returns the current view proxy
*/
EditToolbarSelection.prototype.proxy = function (p) {
if (arguments.length > 0) {
this.selection[0] = p;
}
return this.selection[0];
};
/**
* Get an array containing all selections, including the
* selection proxy. It is generally not advisable to
* mutate this array directly.
* @returns {Array} all selections
*/
EditToolbarSelection.prototype.all = function () {
return this.selection;
};
return EditToolbarSelection;
}
);

View File

@@ -49,7 +49,7 @@ define(
"getModel" "getModel"
] ]
); );
mockDomainObject.getModel.and.returnValue({}); mockDomainObject.getModel.andReturn({});
mockParentObject = jasmine.createSpyObj( mockParentObject = jasmine.createSpyObj(
"parentObject", "parentObject",
@@ -57,7 +57,7 @@ define(
"getCapability" "getCapability"
] ]
); );
mockParentObject.getCapability.and.callFake(function (name) { mockParentObject.getCapability.andCallFake(function (name) {
return parentCapabilities[name]; return parentCapabilities[name];
}); });
@@ -77,14 +77,14 @@ define(
"getOriginal" "getOriginal"
] ]
); );
capabilities.location.getOriginal.and.returnValue(mockPromise(mockDomainObject)); capabilities.location.getOriginal.andReturn(mockPromise(mockDomainObject));
capabilities.context = jasmine.createSpyObj( capabilities.context = jasmine.createSpyObj(
"contextCapability", "contextCapability",
[ [
"getParent" "getParent"
] ]
); );
capabilities.context.getParent.and.returnValue(mockParentObject); capabilities.context.getParent.andReturn(mockParentObject);
parentCapabilities.action = jasmine.createSpyObj( parentCapabilities.action = jasmine.createSpyObj(
"actionCapability", "actionCapability",
@@ -97,37 +97,37 @@ define(
domainObject: mockDomainObject domainObject: mockDomainObject
}; };
mockDomainObject.getCapability.and.callFake(function (name) { mockDomainObject.getCapability.andCallFake(function (name) {
return capabilities[name]; return capabilities[name];
}); });
mockDomainObject.hasCapability.and.callFake(function (name) { mockDomainObject.hasCapability.andCallFake(function (name) {
return !!capabilities[name]; return !!capabilities[name];
}); });
capabilities.editor.finish.and.returnValue(mockPromise(true)); capabilities.editor.finish.andReturn(mockPromise(true));
action = new CancelAction(actionContext); action = new CancelAction(actionContext);
}); });
it("only applies to domain object that is being edited", function () { it("only applies to domain object that is being edited", function () {
capabilities.editor.isEditContextRoot.and.returnValue(true); capabilities.editor.isEditContextRoot.andReturn(true);
expect(CancelAction.appliesTo(actionContext)).toBeTruthy(); expect(CancelAction.appliesTo(actionContext)).toBeTruthy();
expect(mockDomainObject.hasCapability).toHaveBeenCalledWith("editor"); expect(mockDomainObject.hasCapability).toHaveBeenCalledWith("editor");
capabilities.editor.isEditContextRoot.and.returnValue(false); capabilities.editor.isEditContextRoot.andReturn(false);
expect(CancelAction.appliesTo(actionContext)).toBeFalsy(); expect(CancelAction.appliesTo(actionContext)).toBeFalsy();
mockDomainObject.hasCapability.and.returnValue(false); mockDomainObject.hasCapability.andReturn(false);
expect(CancelAction.appliesTo(actionContext)).toBeFalsy(); expect(CancelAction.appliesTo(actionContext)).toBeFalsy();
}); });
it("invokes the editor capability's cancel functionality when" + it("invokes the editor capability's cancel functionality when" +
" performed", function () { " performed", function () {
mockDomainObject.getModel.and.returnValue({persisted: 1}); mockDomainObject.getModel.andReturn({persisted: 1});
//Return true from navigate action //Return true from navigate action
capabilities.action.perform.and.returnValue(mockPromise(true)); capabilities.action.perform.andReturn(mockPromise(true));
action.perform(); action.perform();
// Should have called finish // Should have called finish
@@ -138,15 +138,15 @@ define(
}); });
it("navigates to object if existing using navigate action", function () { it("navigates to object if existing using navigate action", function () {
mockDomainObject.getModel.and.returnValue({persisted: 1}); mockDomainObject.getModel.andReturn({persisted: 1});
//Return true from navigate action //Return true from navigate action
capabilities.action.perform.and.returnValue(mockPromise(true)); capabilities.action.perform.andReturn(mockPromise(true));
action.perform(); action.perform();
expect(capabilities.action.perform).toHaveBeenCalledWith("navigate"); expect(capabilities.action.perform).toHaveBeenCalledWith("navigate");
}); });
it("navigates to parent if new using navigate action", function () { it("navigates to parent if new using navigate action", function () {
mockDomainObject.getModel.and.returnValue({persisted: undefined}); mockDomainObject.getModel.andReturn({persisted: undefined});
action.perform(); action.perform();
expect(parentCapabilities.action.perform).toHaveBeenCalledWith("navigate"); expect(parentCapabilities.action.perform).toHaveBeenCalledWith("navigate");
}); });

View File

@@ -66,11 +66,11 @@ define(
editor: mockEditor editor: mockEditor
}; };
mockDomainObject.getCapability.and.callFake(function (name) { mockDomainObject.getCapability.andCallFake(function (name) {
return capabilities[name]; return capabilities[name];
}); });
mockDomainObject.hasCapability.and.returnValue(true); mockDomainObject.hasCapability.andReturn(true);
mockType.hasFeature.and.returnValue(true); mockType.hasFeature.andReturn(true);
actionContext = { domainObject: mockDomainObject }; actionContext = { domainObject: mockDomainObject };
@@ -92,9 +92,9 @@ define(
}); });
it("is only applicable to objects not already in edit mode", function () { it("is only applicable to objects not already in edit mode", function () {
mockEditor.isEditContextRoot.and.returnValue(false); mockEditor.isEditContextRoot.andReturn(false);
expect(EditAction.appliesTo(actionContext)).toBe(true); expect(EditAction.appliesTo(actionContext)).toBe(true);
mockEditor.isEditContextRoot.and.returnValue(true); mockEditor.isEditContextRoot.andReturn(true);
expect(EditAction.appliesTo(actionContext)).toBe(false); expect(EditAction.appliesTo(actionContext)).toBe(false);
}); });

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