mirror of
https://github.com/nasa/openmct.git
synced 2025-06-26 19:12:02 +00:00
Compare commits
17 Commits
fix-text-d
...
vue-table-
Author | SHA1 | Date | |
---|---|---|---|
24fcad8152 | |||
a6f9e0420c | |||
ccfd9eed00 | |||
df0ee1f99b | |||
dacbf928a1 | |||
6153dce261 | |||
0fcddb3547 | |||
c6628b6e72 | |||
ec7889e5ff | |||
416d8f60fe | |||
74293d4fda | |||
73fc686851 | |||
d21abd95b1 | |||
eb5ef28a73 | |||
1bb1330cba | |||
78c731dbf7 | |||
0d53898af9 |
@ -11,24 +11,20 @@ jobs:
|
||||
name: Update npm
|
||||
command: 'sudo npm install -g npm@latest'
|
||||
- restore_cache:
|
||||
key: dependency-cache-{{ checksum "package.json" }}-{{ checksum "bower.json" }}
|
||||
key: dependency-cache-{{ checksum "package.json" }}
|
||||
- run:
|
||||
name: Installing dependencies (npm install)
|
||||
command: npm install
|
||||
- save_cache:
|
||||
key: dependency-cache-{{ checksum "package.json" }}-{{ checksum "bower.json" }}
|
||||
key: dependency-cache-{{ checksum "package.json" }}
|
||||
paths:
|
||||
- node_modules
|
||||
- bower_components
|
||||
- run:
|
||||
name: npm run test
|
||||
command: npm run test
|
||||
- run:
|
||||
name: npm run lint
|
||||
command: npm run lint
|
||||
- run:
|
||||
name: npm run checkstyle
|
||||
command: npm run checkstyle
|
||||
- store_artifacts:
|
||||
path: dist
|
||||
prefix: dist
|
||||
|
79
.eslintrc.js
Normal file
79
.eslintrc.js
Normal file
@ -0,0 +1,79 @@
|
||||
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
5
.jscsrc
@ -1,5 +0,0 @@
|
||||
{
|
||||
"preset": "crockford",
|
||||
"requireMultipleVarDecl": false,
|
||||
"requireVarDeclFirst": false
|
||||
}
|
26
.jshintrc
26
.jshintrc
@ -1,26 +0,0 @@
|
||||
{
|
||||
"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"
|
||||
}
|
28
README.md
28
README.md
@ -84,7 +84,6 @@ Documentation will be generated in `target/docs`.
|
||||
## Deploying Open MCT
|
||||
|
||||
Open MCT is built using [`npm`](http://npmjs.com/)
|
||||
and [`gulp`](http://gulpjs.com/).
|
||||
|
||||
To build Open MCT for deployment:
|
||||
|
||||
@ -94,32 +93,13 @@ This will compile and minify JavaScript sources, as well as copy over assets.
|
||||
The contents of the `dist` folder will contain a runnable Open MCT
|
||||
instance (e.g. by starting an HTTP server in that directory), including:
|
||||
|
||||
* A `main.js` file containing Open MCT source code.
|
||||
* Various assets in the `example` and `platform` directories.
|
||||
* An `index.html` that runs Open MCT in its default configuration.
|
||||
|
||||
Additional `gulp` tasks are defined in [the gulpfile](gulpfile.js).
|
||||
|
||||
## Bundles
|
||||
|
||||
A bundle is a group of software components (including source code, declared
|
||||
as AMD modules, as well as resources such as images and HTML templates)
|
||||
that is intended to be added or removed as a single unit. A plug-in for
|
||||
Open MCT will be expressed as a bundle; platform components are also
|
||||
expressed as bundles.
|
||||
|
||||
A bundle is also just a directory which contains a file `bundle.json`,
|
||||
which declares its contents.
|
||||
|
||||
The file `bundles.json` (note the plural), at the top level of the
|
||||
repository, is a JSON file containing an array of all bundles (expressed as
|
||||
directory names) to include in a running instance of Open MCT. Adding or
|
||||
removing paths from this list will add or remove bundles from the running
|
||||
application.
|
||||
* `openmct.js` - Open MCT source code.
|
||||
* `openmct.css` - Basic styles to load to prevent a FOUC.
|
||||
* `index.html`, an example to run Open MCT in the basic configuration.
|
||||
|
||||
## Tests
|
||||
|
||||
Tests are written for [Jasmine 1.3](http://jasmine.github.io/1.3/introduction.html)
|
||||
Tests are written for [Jasmine 3](http://jasmine.github.io/)
|
||||
and run by [Karma](http://karma-runner.github.io). To run:
|
||||
|
||||
`npm test`
|
||||
|
79
app.js
79
app.js
@ -7,28 +7,17 @@
|
||||
* node app.js [options]
|
||||
*/
|
||||
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
var BUNDLE_FILE = 'bundles.json',
|
||||
options = require('minimist')(process.argv.slice(2)),
|
||||
express = require('express'),
|
||||
app = express(),
|
||||
fs = require('fs'),
|
||||
request = require('request');
|
||||
const options = require('minimist')(process.argv.slice(2));
|
||||
const express = require('express');
|
||||
const app = express();
|
||||
const fs = require('fs');
|
||||
const request = require('request');
|
||||
|
||||
// Defaults
|
||||
options.port = options.port || options.p || 8080;
|
||||
options.host = options.host || options.h || 'localhost'
|
||||
options.directory = options.directory || options.D || '.';
|
||||
['include', 'exclude', 'i', 'x'].forEach(function (opt) {
|
||||
options[opt] = options[opt] || [];
|
||||
// Make sure includes/excludes always end up as arrays
|
||||
options[opt] = Array.isArray(options[opt]) ?
|
||||
options[opt] : [options[opt]];
|
||||
});
|
||||
options.include = options.include.concat(options.i);
|
||||
options.exclude = options.exclude.concat(options.x);
|
||||
|
||||
// Show command line options
|
||||
if (options.help || options.h) {
|
||||
@ -36,8 +25,6 @@
|
||||
console.log("Options:");
|
||||
console.log(" --help, -h Show this message.");
|
||||
console.log(" --port, -p <number> Specify port.");
|
||||
console.log(" --include, -i <bundle> Include the specified bundle.");
|
||||
console.log(" --exclude, -x <bundle> Exclude the specified bundle.");
|
||||
console.log(" --directory, -D <bundle> Serve files from specified directory.");
|
||||
console.log("");
|
||||
process.exit(0);
|
||||
@ -45,28 +32,6 @@
|
||||
|
||||
app.disable('x-powered-by');
|
||||
|
||||
// Override bundles.json for HTTP requests
|
||||
app.use('/' + BUNDLE_FILE, function (req, res) {
|
||||
var bundles;
|
||||
|
||||
try {
|
||||
bundles = JSON.parse(fs.readFileSync(BUNDLE_FILE, 'utf8'));
|
||||
} catch (e) {
|
||||
bundles = [];
|
||||
}
|
||||
|
||||
// Handle command line inclusions/exclusions
|
||||
bundles = bundles.concat(options.include);
|
||||
bundles = bundles.filter(function (bundle) {
|
||||
return options.exclude.indexOf(bundle) === -1;
|
||||
});
|
||||
bundles = bundles.filter(function (bundle, index) { // Uniquify
|
||||
return bundles.indexOf(bundle) === index;
|
||||
});
|
||||
|
||||
res.send(JSON.stringify(bundles));
|
||||
});
|
||||
|
||||
app.use('/proxyUrl', function proxyRequest(req, res, next) {
|
||||
console.log('Proxying request to: ', req.query.url);
|
||||
req.pipe(request({
|
||||
@ -75,11 +40,39 @@
|
||||
}).on('error', next)).pipe(res);
|
||||
});
|
||||
|
||||
// Expose everything else as static files
|
||||
app.use(express['static'](options.directory));
|
||||
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')(
|
||||
compiler,
|
||||
{
|
||||
|
||||
}
|
||||
));
|
||||
|
||||
// Expose index.html for development users.
|
||||
app.get('/', function (req, res) {
|
||||
fs.createReadStream('index.html').pipe(res);
|
||||
});
|
||||
|
||||
// Finally, open the HTTP server and log the instance to the console
|
||||
app.listen(options.port, options.host, function() {
|
||||
console.log('Open MCT application running at %s:%s', options.host, options.port)
|
||||
});
|
||||
}());
|
||||
|
27
bower.json
27
bower.json
@ -1,27 +0,0 @@
|
||||
{
|
||||
"name": "openmct",
|
||||
"description": "The Open MCT core platform",
|
||||
"main": "",
|
||||
"license": "Apache-2.0",
|
||||
"moduleType": [],
|
||||
"homepage": "http://nasa.github.io/openmct/",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"angular": "1.4.4",
|
||||
"angular-route": "1.4.4",
|
||||
"moment": "^2.11.1",
|
||||
"moment-duration-format": "^1.3.0",
|
||||
"requirejs": "~2.1.22",
|
||||
"text": "requirejs-text#^2.0.14",
|
||||
"es6-promise": "^3.3.0",
|
||||
"screenfull": "^3.0.0",
|
||||
"node-uuid": "^1.4.7",
|
||||
"comma-separated-values": "^3.6.4",
|
||||
"file-saver": "1.3.3",
|
||||
"zepto": "^1.1.6",
|
||||
"eventemitter3": "^1.2.0",
|
||||
"lodash": "3.10.1",
|
||||
"almond": "~0.3.2",
|
||||
"moment-timezone": "^0.5.13"
|
||||
}
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
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
|
@ -1,74 +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.
|
||||
*****************************************************************************/
|
||||
/*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
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
});
|
@ -1,24 +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.
|
||||
-->
|
||||
<p>Hello, world! I am the default route.</p>
|
||||
<p ng-controller="ExampleController">My controller has told me: "{{phrase}}"</p>
|
||||
<span example-directive></span>
|
@ -1,42 +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.
|
||||
*****************************************************************************/
|
||||
/*global define,Promise*/
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
);
|
@ -1,66 +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.
|
||||
*****************************************************************************/
|
||||
/*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;
|
||||
}
|
||||
);
|
@ -1,46 +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.
|
||||
*****************************************************************************/
|
||||
/*global define,Promise*/
|
||||
|
||||
/**
|
||||
* Module defining ExampleService. Created by vwoeltje on 11/4/14.
|
||||
*/
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
function ExampleService() {
|
||||
return {
|
||||
getMessage: function () {
|
||||
return "I heard this from a service";
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return ExampleService;
|
||||
}
|
||||
);
|
@ -1,82 +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.
|
||||
*****************************************************************************/
|
||||
/*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"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
});
|
@ -1,50 +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.
|
||||
*****************************************************************************/
|
||||
/*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;
|
||||
}
|
||||
);
|
@ -1,48 +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.
|
||||
*****************************************************************************/
|
||||
/*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;
|
||||
}
|
||||
);
|
@ -1,48 +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.
|
||||
*****************************************************************************/
|
||||
/*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;
|
||||
}
|
||||
);
|
@ -1,46 +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.
|
||||
*****************************************************************************/
|
||||
/*global define,Promise*/
|
||||
|
||||
/**
|
||||
* Module defining SomeOtherExample. Created by vwoeltje on 11/5/14.
|
||||
*/
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
function SomeOtherExample(someService) {
|
||||
return {
|
||||
getText: function () {
|
||||
return someService.getMessages().join(" | ");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return SomeOtherExample;
|
||||
}
|
||||
);
|
@ -1,48 +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.
|
||||
*****************************************************************************/
|
||||
/*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;
|
||||
}
|
||||
);
|
@ -27,12 +27,11 @@
|
||||
* Modified by shale on 06/23/2015.
|
||||
*/
|
||||
define(
|
||||
['text!../data/transcript.json'],
|
||||
function (transcript) {
|
||||
['../data/transcript.json'],
|
||||
function (messages) {
|
||||
"use strict";
|
||||
|
||||
var firstObservedTime = Date.now(),
|
||||
messages = JSON.parse(transcript);
|
||||
var firstObservedTime = Date.now();
|
||||
|
||||
function EventTelemetry(request, interval) {
|
||||
|
||||
|
@ -1,51 +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.
|
||||
*****************************************************************************/
|
||||
/*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"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
});
|
@ -1,52 +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.
|
||||
*****************************************************************************/
|
||||
/*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;
|
||||
}
|
||||
);
|
@ -27,8 +27,14 @@ define([
|
||||
|
||||
) {
|
||||
|
||||
var RED = 0.9,
|
||||
YELLOW = 0.5,
|
||||
var RED = {
|
||||
sin: 0.9,
|
||||
cos: 0.9
|
||||
},
|
||||
YELLOW = {
|
||||
sin: 0.5,
|
||||
cos: 0.5
|
||||
},
|
||||
LIMITS = {
|
||||
rh: {
|
||||
cssClass: "s-limit-upr s-limit-red",
|
||||
@ -67,17 +73,18 @@ define([
|
||||
SinewaveLimitProvider.prototype.getLimitEvaluator = function (domainObject) {
|
||||
return {
|
||||
evaluate: function (datum, valueMetadata) {
|
||||
var range = valueMetadata ? valueMetadata.key : 'sin'
|
||||
if (datum[range] > RED) {
|
||||
var range = valueMetadata && valueMetadata.key;
|
||||
|
||||
if (datum[range] > RED[range]) {
|
||||
return LIMITS.rh;
|
||||
}
|
||||
if (datum[range] < -RED) {
|
||||
if (datum[range] < -RED[range]) {
|
||||
return LIMITS.rl;
|
||||
}
|
||||
if (datum[range] > YELLOW) {
|
||||
if (datum[range] > YELLOW[range]) {
|
||||
return LIMITS.yh;
|
||||
}
|
||||
if (datum[range] < -YELLOW) {
|
||||
if (datum[range] < -YELLOW[range]) {
|
||||
return LIMITS.yl;
|
||||
}
|
||||
}
|
||||
|
@ -21,7 +21,7 @@
|
||||
*****************************************************************************/
|
||||
|
||||
define([
|
||||
'text!./generatorWorker.js',
|
||||
'raw-loader!./generatorWorker.js',
|
||||
'uuid'
|
||||
], function (
|
||||
workerText,
|
||||
|
19
example/simpleVuePlugin/HelloWorld.vue
Normal file
19
example/simpleVuePlugin/HelloWorld.vue
Normal file
@ -0,0 +1,19 @@
|
||||
<template>
|
||||
<div class="example">{{ msg }}</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
msg: 'Hello world!'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.example {
|
||||
color: red;
|
||||
}
|
||||
</style>
|
37
example/simpleVuePlugin/plugin.js
Normal file
37
example/simpleVuePlugin/plugin.js
Normal file
@ -0,0 +1,37 @@
|
||||
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
|
@ -1,10 +1,26 @@
|
||||
define([
|
||||
"./src/ExampleStyleGuideModelProvider",
|
||||
"./src/MCTExample",
|
||||
"./res/templates/intro.html",
|
||||
"./res/templates/standards.html",
|
||||
"./res/templates/colors.html",
|
||||
"./res/templates/status.html",
|
||||
"./res/templates/glyphs.html",
|
||||
"./res/templates/controls.html",
|
||||
"./res/templates/input.html",
|
||||
"./res/templates/menus.html",
|
||||
'legacyRegistry'
|
||||
], function (
|
||||
ExampleStyleGuideModelProvider,
|
||||
MCTExample,
|
||||
introTemplate,
|
||||
standardsTemplate,
|
||||
colorsTemplate,
|
||||
statusTemplate,
|
||||
glyphsTemplate,
|
||||
controlsTemplate,
|
||||
inputTemplate,
|
||||
menusTemplate,
|
||||
legacyRegistry
|
||||
) {
|
||||
legacyRegistry.register("example/styleguide", {
|
||||
@ -23,14 +39,14 @@ define([
|
||||
{ "key": "styleguide.menus", "name": "Menus", "cssClass": "icon-page", "description": "Context menus, dropdowns" }
|
||||
],
|
||||
"views": [
|
||||
{ "key": "styleguide.intro", "type": "styleguide.intro", "templateUrl": "templates/intro.html", "editable": false },
|
||||
{ "key": "styleguide.standards", "type": "styleguide.standards", "templateUrl": "templates/standards.html", "editable": false },
|
||||
{ "key": "styleguide.colors", "type": "styleguide.colors", "templateUrl": "templates/colors.html", "editable": false },
|
||||
{ "key": "styleguide.status", "type": "styleguide.status", "templateUrl": "templates/status.html", "editable": false },
|
||||
{ "key": "styleguide.glyphs", "type": "styleguide.glyphs", "templateUrl": "templates/glyphs.html", "editable": false },
|
||||
{ "key": "styleguide.controls", "type": "styleguide.controls", "templateUrl": "templates/controls.html", "editable": false },
|
||||
{ "key": "styleguide.input", "type": "styleguide.input", "templateUrl": "templates/input.html", "editable": false },
|
||||
{ "key": "styleguide.menus", "type": "styleguide.menus", "templateUrl": "templates/menus.html", "editable": false }
|
||||
{ "key": "styleguide.intro", "type": "styleguide.intro", "template": introTemplate, "editable": false },
|
||||
{ "key": "styleguide.standards", "type": "styleguide.standards", "template": standardsTemplate, "editable": false },
|
||||
{ "key": "styleguide.colors", "type": "styleguide.colors", "template": colorsTemplate, "editable": false },
|
||||
{ "key": "styleguide.status", "type": "styleguide.status", "template": statusTemplate, "editable": false },
|
||||
{ "key": "styleguide.glyphs", "type": "styleguide.glyphs", "template": glyphsTemplate, "editable": false },
|
||||
{ "key": "styleguide.controls", "type": "styleguide.controls", "template": controlsTemplate, "editable": false },
|
||||
{ "key": "styleguide.input", "type": "styleguide.input", "template": inputTemplate, "editable": false },
|
||||
{ "key": "styleguide.menus", "type": "styleguide.menus", "template": menusTemplate, "editable": false }
|
||||
],
|
||||
"roots": [
|
||||
{
|
||||
@ -85,16 +101,6 @@ define([
|
||||
"$q"
|
||||
]
|
||||
}
|
||||
],
|
||||
"stylesheets": [
|
||||
{
|
||||
"stylesheetUrl": "css/style-guide-espresso.css",
|
||||
"theme": "espresso"
|
||||
},
|
||||
{
|
||||
"stylesheetUrl": "css/style-guide-snow.css",
|
||||
"theme": "snow"
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
|
@ -34,7 +34,7 @@
|
||||
<p>As you develop plugins for Open MCT, consider how a generalized component might be combined with others when designing to create a rich and powerful larger object, rather than adding a single monolithic, non-modular plugin. To solve a particular problem or allow a new feature in Open MCT, you may need to introduce more than just one new object type.</p>
|
||||
</div>
|
||||
<div class="col">
|
||||
<img src="/example/styleguide/res/images/diagram-objects.svg" />
|
||||
<img src="../images/diagram-objects.svg" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -48,7 +48,7 @@
|
||||
<p>The types of objects that a container can hold should be based on the purpose of the container and the views that it affords. For example, a Folder’s purpose is to allow a user to conceptually organize objects of all other types; a Folder must therefore be able to contain an object of any type.</p>
|
||||
</div>
|
||||
<div class="col">
|
||||
<img src="/example/styleguide/res/images/diagram-containment.svg" />
|
||||
<img src="../images/diagram-containment.svg" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -60,7 +60,7 @@
|
||||
<p>Views are simply different ways to view the content of a given object. For example, telemetry data could be viewed as a plot or a table. A clock can display its time in analog fashion or with digital numbers. In each view, all of the content is present; it’s just represented differently. When providing views for an object, all the content of the object should be present in each view.</p>
|
||||
</div>
|
||||
<div class="col">
|
||||
<img src="/example/styleguide/res/images/diagram-views.svg" />
|
||||
<img src="../images/diagram-views.svg" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,5 +1,5 @@
|
||||
define([
|
||||
'text!../res/templates/mct-example.html'
|
||||
'../res/templates/mct-example.html'
|
||||
], function (
|
||||
MCTExampleTemplate
|
||||
) {
|
||||
|
@ -1,68 +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.
|
||||
*****************************************************************************/
|
||||
/*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"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
});
|
@ -1,69 +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.
|
||||
*****************************************************************************/
|
||||
/*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 +0,0 @@
|
||||
Example of running a Web Worker using the `workerService`.
|
@ -1,52 +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.
|
||||
*****************************************************************************/
|
||||
/*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"
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
});
|
@ -1,67 +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.
|
||||
*****************************************************************************/
|
||||
/*global define*/
|
||||
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Displays Fibonacci numbers in the status area.
|
||||
* @constructor
|
||||
*/
|
||||
function FibonacciIndicator(workerService, $rootScope) {
|
||||
var latest,
|
||||
counter = 0,
|
||||
worker = workerService.run('example.fibonacci');
|
||||
|
||||
function requestNext() {
|
||||
worker.postMessage([counter]);
|
||||
counter += 1;
|
||||
}
|
||||
|
||||
function handleResponse(event) {
|
||||
latest = event.data;
|
||||
$rootScope.$apply();
|
||||
requestNext();
|
||||
}
|
||||
|
||||
worker.onmessage = handleResponse;
|
||||
requestNext();
|
||||
|
||||
return {
|
||||
getCssClass: function () {
|
||||
return "icon-object-unknown";
|
||||
},
|
||||
getText: function () {
|
||||
return "" + latest;
|
||||
},
|
||||
getDescription: function () {
|
||||
return "";
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return FibonacciIndicator;
|
||||
}
|
||||
);
|
@ -1,15 +0,0 @@
|
||||
/*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
182
gulpfile.js
@ -1,182 +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.
|
||||
*****************************************************************************/
|
||||
|
||||
/*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' ]);
|
27
index.html
27
index.html
@ -26,11 +26,17 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0, shrink-to-fit=no">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<title></title>
|
||||
<script src="bower_components/requirejs/require.js"> </script>
|
||||
<script src="dist/openmct.js"></script>
|
||||
<link rel="stylesheet" href="dist/openmct.css">
|
||||
<link rel="icon" type="image/png" href="dist/favicons/favicon-32x32.png" sizes="32x32">
|
||||
<link rel="icon" type="image/png" href="dist/favicons/favicon-96x96.png" sizes="96x96">
|
||||
<link rel="icon" type="image/png" href="dist/favicons/favicon-16x16.png" sizes="16x16">
|
||||
<link rel="shortcut icon" href="dist/favicons/favicon.ico">
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
<script>
|
||||
var THIRTY_MINUTES = 30 * 60 * 1000;
|
||||
|
||||
require(['openmct'], function (openmct) {
|
||||
[
|
||||
'example/eventGenerator',
|
||||
'example/styleguide'
|
||||
@ -39,7 +45,6 @@
|
||||
);
|
||||
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());
|
||||
@ -73,19 +78,5 @@
|
||||
openmct.time.clock('local', {start: -THIRTY_MINUTES, end: 0});
|
||||
openmct.time.timeSystem('utc');
|
||||
openmct.start();
|
||||
window.openmct = openmct;
|
||||
});
|
||||
</script>
|
||||
<link rel="stylesheet" href="platform/commonUI/general/res/css/startup-base.css">
|
||||
<link rel="stylesheet" href="platform/commonUI/general/res/css/openmct.css">
|
||||
<link rel="icon" type="image/png" href="platform/commonUI/general/res/images/favicons/favicon-32x32.png" sizes="32x32">
|
||||
<link rel="icon" type="image/png" href="platform/commonUI/general/res/images/favicons/favicon-96x96.png" sizes="96x96">
|
||||
<link rel="icon" type="image/png" href="platform/commonUI/general/res/images/favicons/favicon-16x16.png" sizes="16x16">
|
||||
<link rel="shortcut icon" href="platform/commonUI/general/res/images/favicons/favicon.ico">
|
||||
</head>
|
||||
<body>
|
||||
<div class="l-splash-holder s-splash-holder">
|
||||
<div class="l-splash s-splash"></div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -21,70 +21,40 @@
|
||||
*****************************************************************************/
|
||||
|
||||
/*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({
|
||||
|
||||
// Base path that will be used to resolve all file patterns.
|
||||
basePath: '',
|
||||
|
||||
// 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.
|
||||
frameworks: ['jasmine'],
|
||||
files: [
|
||||
{pattern: 'bower_components/**/*.js', included: false},
|
||||
{pattern: 'node_modules/d3-*/**/*.js', included: false},
|
||||
{pattern: 'node_modules/vue/**/*.js', included: false},
|
||||
{pattern: 'node_modules/printj/dist/*.js', included: false},
|
||||
{pattern: 'src/**/*', included: false},
|
||||
{pattern: 'node_modules/painterro/build/*.js', included: false},
|
||||
{pattern: 'node_modules/html2canvas/dist/*', included: false},
|
||||
{pattern: 'example/**/*.html', included: false},
|
||||
{pattern: 'example/**/*.js', included: false},
|
||||
{pattern: 'example/**/*.json', included: false},
|
||||
{pattern: 'platform/**/*.js', included: false},
|
||||
{pattern: 'warp/**/*.js', included: false},
|
||||
{pattern: 'platform/**/*.html', included: false},
|
||||
'test-main.js'
|
||||
'platform/**/*Spec.js',
|
||||
'src/**/*Spec.js'
|
||||
],
|
||||
|
||||
// List of files to exclude.
|
||||
exclude: [
|
||||
'platform/framework/src/Main.js'
|
||||
],
|
||||
|
||||
// Preprocess matching files before serving them to the browser.
|
||||
// https://npmjs.org/browse/keyword/karma-preprocessor
|
||||
preprocessors: {
|
||||
'src/**/!(*Spec).js': [ 'coverage' ],
|
||||
'platform/**/src/**/!(*Spec).js': [ 'coverage' ]
|
||||
},
|
||||
|
||||
// Test results reporter to use
|
||||
// Possible values: 'dots', 'progress'
|
||||
// Available reporters: https://npmjs.org/browse/keyword/karma-reporter
|
||||
reporters: ['progress', 'coverage', 'html'],
|
||||
|
||||
// Web server port.
|
||||
port: 9876,
|
||||
|
||||
// Wnable / disable colors in the output (reporters and logs).
|
||||
reporters: [
|
||||
'progress',
|
||||
'coverage',
|
||||
'html'
|
||||
],
|
||||
browsers: ['ChromeHeadless'],
|
||||
colors: true,
|
||||
|
||||
logLevel: config.LOG_INFO,
|
||||
|
||||
// Rerun tests when any file changes.
|
||||
autoWatch: true,
|
||||
|
||||
// Specify browsers to run tests in.
|
||||
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
|
||||
browsers: [
|
||||
'ChromeHeadless'
|
||||
],
|
||||
|
||||
// Code coverage reporting.
|
||||
coverageReporter: {
|
||||
dir: process.env.CIRCLE_ARTIFACTS ?
|
||||
process.env.CIRCLE_ARTIFACTS + '/coverage' :
|
||||
@ -104,8 +74,19 @@ module.exports = function(config) {
|
||||
foldAll: false
|
||||
},
|
||||
|
||||
// Continuous Integration mode.
|
||||
// If true, Karma captures browsers, runs the tests and exits.
|
||||
preprocessors: {
|
||||
// add webpack as preprocessor
|
||||
'platform/**/*Spec.js': [ 'webpack' ],
|
||||
'src/**/*Spec.js': [ 'webpack' ]
|
||||
},
|
||||
|
||||
webpack: webpackConfig,
|
||||
|
||||
webpackMiddleware: {
|
||||
stats: 'errors-only',
|
||||
logLevel: 'warn'
|
||||
},
|
||||
singleRun: true
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
|
103
openmct.js
103
openmct.js
@ -19,102 +19,19 @@
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
/*global requirejs,BUILD_CONSTANTS*/
|
||||
/*global module,BUILD_CONSTANTS*/
|
||||
|
||||
requirejs.config({
|
||||
"paths": {
|
||||
"legacyRegistry": "src/legacyRegistry",
|
||||
"angular": "bower_components/angular/angular.min",
|
||||
"angular-route": "bower_components/angular-route/angular-route.min",
|
||||
"csv": "bower_components/comma-separated-values/csv.min",
|
||||
"EventEmitter": "bower_components/eventemitter3/index",
|
||||
"es6-promise": "bower_components/es6-promise/es6-promise.min",
|
||||
"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",
|
||||
"html2canvas": "node_modules/html2canvas/dist/html2canvas.min",
|
||||
"painterro": "node_modules/painterro/build/painterro.min",
|
||||
"printj": "node_modules/printj/dist/printj.min"
|
||||
},
|
||||
"shim": {
|
||||
"angular": {
|
||||
"exports": "angular"
|
||||
},
|
||||
"angular-route": {
|
||||
"deps": ["angular"]
|
||||
},
|
||||
"EventEmitter": {
|
||||
"exports": "EventEmitter"
|
||||
},
|
||||
"moment-duration-format": {
|
||||
"deps": ["moment"]
|
||||
},
|
||||
"painterro": {
|
||||
"exports": "Painterro"
|
||||
},
|
||||
"saveAs": {
|
||||
"exports": "saveAs"
|
||||
},
|
||||
"screenfull": {
|
||||
"exports": "screenfull"
|
||||
},
|
||||
"zepto": {
|
||||
"exports": "Zepto"
|
||||
},
|
||||
"lodash": {
|
||||
"exports": "lodash"
|
||||
},
|
||||
"d3-selection": {
|
||||
"exports": "d3-selection"
|
||||
},
|
||||
"d3-scale": {
|
||||
"deps": ["d3-array", "d3-collection", "d3-color", "d3-format", "d3-interpolate", "d3-time", "d3-time-format"],
|
||||
"exports": "d3-scale"
|
||||
},
|
||||
"d3-axis": {
|
||||
"exports": "d3-axis"
|
||||
},
|
||||
"dom-to-image": {
|
||||
"exports": "domtoimage"
|
||||
const matcher = /\/openmct.js$/;
|
||||
if (document.currentScript) {
|
||||
let src = document.currentScript.src;
|
||||
if (src && matcher.test(src)) {
|
||||
// eslint-disable-next-line no-undef
|
||||
__webpack_public_path__ = src.replace(matcher, '') + '/';
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
define([
|
||||
'./platform/framework/src/Main',
|
||||
'./src/defaultRegistry',
|
||||
'./src/MCT',
|
||||
'./src/plugins/buildInfo/plugin'
|
||||
], function (Main, defaultRegistry, MCT, buildInfo) {
|
||||
const MCT = require('./src/MCT');
|
||||
|
||||
var openmct = new MCT();
|
||||
|
||||
openmct.legacyRegistry = defaultRegistry;
|
||||
openmct.install(openmct.plugins.Plot());
|
||||
|
||||
if (typeof BUILD_CONSTANTS !== 'undefined') {
|
||||
openmct.install(buildInfo(BUILD_CONSTANTS));
|
||||
}
|
||||
|
||||
openmct.on('start', function () {
|
||||
return new Main().run(defaultRegistry);
|
||||
});
|
||||
|
||||
return openmct;
|
||||
});
|
||||
module.exports = openmct;
|
||||
|
75
package.json
75
package.json
@ -2,7 +2,15 @@
|
||||
"name": "openmct",
|
||||
"version": "0.14.0-SNAPSHOT",
|
||||
"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-axis": "1.0.x",
|
||||
"d3-collection": "1.0.x",
|
||||
@ -13,59 +21,70 @@
|
||||
"d3-selection": "1.3.x",
|
||||
"d3-time": "1.0.x",
|
||||
"d3-time-format": "2.1.x",
|
||||
"eslint": "5.2.0",
|
||||
"eventemitter3": "^1.2.0",
|
||||
"exports-loader": "^0.7.0",
|
||||
"express": "^4.13.1",
|
||||
"minimist": "^1.1.1",
|
||||
"painterro": "^0.2.65",
|
||||
"request": "^2.69.0",
|
||||
"vue": "^2.5.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"bower": "^1.7.7",
|
||||
"fast-sass-loader": "^1.4.5",
|
||||
"file-loader": "^1.1.11",
|
||||
"file-saver": "^1.3.8",
|
||||
"git-rev-sync": "^1.4.0",
|
||||
"glob": ">= 3.0.0",
|
||||
"gulp": "^3.9.1",
|
||||
"gulp-jscs": "^3.0.2",
|
||||
"gulp-jshint": "^2.0.0",
|
||||
"gulp-jshint-html-reporter": "^0.1.3",
|
||||
"gulp-rename": "^1.2.2",
|
||||
"gulp-requirejs-optimize": "^0.3.1",
|
||||
"gulp-sass": "^3.1.0",
|
||||
"gulp-sourcemaps": "^1.6.0",
|
||||
"html-loader": "^0.5.5",
|
||||
"html2canvas": "^1.0.0-alpha.12",
|
||||
"imports-loader": "^0.8.0",
|
||||
"istanbul-instrumenter-loader": "^3.0.1",
|
||||
"jasmine-core": "^3.1.0",
|
||||
"jscs-html-reporter": "^0.1.0",
|
||||
"jsdoc": "^3.3.2",
|
||||
"jshint": "^2.7.0",
|
||||
"karma": "^2.0.3",
|
||||
"karma-chrome-launcher": "^2.2.0",
|
||||
"karma-cli": "^1.0.1",
|
||||
"karma-coverage": "^1.1.2",
|
||||
"karma-html-reporter": "^0.2.7",
|
||||
"karma-jasmine": "^1.1.2",
|
||||
"karma-requirejs": "^1.1.0",
|
||||
"karma-webpack": "^3.0.0",
|
||||
"location-bar": "^3.0.1",
|
||||
"lodash": "^3.10.1",
|
||||
"markdown-toc": "^0.11.7",
|
||||
"marked": "^0.3.5",
|
||||
"merge-stream": "^1.0.0",
|
||||
"mkdirp": "^0.5.1",
|
||||
"mini-css-extract-plugin": "^0.4.1",
|
||||
"minimist": "^1.1.1",
|
||||
"moment": "^2.11.1",
|
||||
"moment-duration-format": "^2.2.2",
|
||||
"moment-timezone": "^0.5.21",
|
||||
"node-bourbon": "^4.2.3",
|
||||
"node-sass": "^4.9.2",
|
||||
"painterro": "^0.2.65",
|
||||
"printj": "^1.1.0",
|
||||
"requirejs": "2.1.x",
|
||||
"raw-loader": "^0.5.1",
|
||||
"request": "^2.69.0",
|
||||
"screenfull": "^3.3.2",
|
||||
"split": "^1.0.0",
|
||||
"v8-compile-cache": "^1.1.0"
|
||||
"style-loader": "^0.21.0",
|
||||
"v8-compile-cache": "^1.1.0",
|
||||
"vue": "2.5.6",
|
||||
"vue-loader": "^15.2.6",
|
||||
"vue-template-compiler": "2.5.6",
|
||||
"webpack": "^4.16.2",
|
||||
"webpack-cli": "^3.1.0",
|
||||
"webpack-dev-middleware": "^3.1.3",
|
||||
"webpack-hot-middleware": "^2.22.3",
|
||||
"zepto": "^1.2.0"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "node app.js",
|
||||
"lint": "eslint platform src openmct.js",
|
||||
"lint:fix": "eslint platform src openmct.js --fix",
|
||||
"build:prod": "NODE_ENV=production webpack",
|
||||
"build:dev": "webpack",
|
||||
"build:watch": "webpack --watch",
|
||||
"test": "karma start --single-run",
|
||||
"jshint": "jshint platform example",
|
||||
"lint": "./node_modules/gulp/bin/gulp.js lint",
|
||||
"checkstyle": "./node_modules/gulp/bin/gulp.js checkstyle",
|
||||
"watch": "karma start",
|
||||
"test:watch": "karma start --no-single-run",
|
||||
"verify": "concurrently 'npm:test' 'npm:lint'",
|
||||
"jsdoc": "jsdoc -c jsdoc.json -R API.md -r -d dist/docs/api",
|
||||
"otherdoc": "node docs/gendocs.js --in docs/src --out dist/docs --suppress-toc 'docs/src/index.md|docs/src/process/index.md'",
|
||||
"docs": "npm run jsdoc ; npm run otherdoc",
|
||||
"prepare": "node ./node_modules/bower/bin/bower install && node ./node_modules/gulp/bin/gulp.js install"
|
||||
"prepare": "npm run build:prod"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@ -21,17 +21,17 @@
|
||||
*****************************************************************************/
|
||||
|
||||
define([
|
||||
"text!./res/templates/about-dialog.html",
|
||||
"./res/templates/about-dialog.html",
|
||||
"./src/LogoController",
|
||||
"./src/AboutController",
|
||||
"./src/LicenseController",
|
||||
"text!./res/templates/app-logo.html",
|
||||
"text!./res/templates/about-logo.html",
|
||||
"text!./res/templates/overlay-about.html",
|
||||
"text!./res/templates/license-apache.html",
|
||||
"text!./res/templates/license-mit.html",
|
||||
"text!./res/templates/licenses.html",
|
||||
"text!./res/templates/licenses-export-md.html",
|
||||
"./res/templates/app-logo.html",
|
||||
"./res/templates/about-logo.html",
|
||||
"./res/templates/overlay-about.html",
|
||||
"./res/templates/license-apache.html",
|
||||
"./res/templates/license-mit.html",
|
||||
"./res/templates/licenses.html",
|
||||
"./res/templates/licenses-export-md.html",
|
||||
'legacyRegistry'
|
||||
], function (
|
||||
aboutDialogTemplate,
|
||||
|
@ -33,16 +33,16 @@ define([
|
||||
"./src/windowing/NewTabAction",
|
||||
"./src/windowing/FullscreenAction",
|
||||
"./src/windowing/WindowTitler",
|
||||
"text!./res/templates/browse.html",
|
||||
"text!./res/templates/browse-object.html",
|
||||
"text!./res/templates/items/grid-item.html",
|
||||
"text!./res/templates/browse/object-header.html",
|
||||
"text!./res/templates/browse/object-header-frame.html",
|
||||
"text!./res/templates/menu-arrow.html",
|
||||
"text!./res/templates/back-arrow.html",
|
||||
"text!./res/templates/items/items.html",
|
||||
"text!./res/templates/browse/object-properties.html",
|
||||
"text!./res/templates/browse/inspector-region.html",
|
||||
"./res/templates/browse.html",
|
||||
"./res/templates/browse-object.html",
|
||||
"./res/templates/items/grid-item.html",
|
||||
"./res/templates/browse/object-header.html",
|
||||
"./res/templates/browse/object-header-frame.html",
|
||||
"./res/templates/menu-arrow.html",
|
||||
"./res/templates/back-arrow.html",
|
||||
"./res/templates/items/items.html",
|
||||
"./res/templates/browse/object-properties.html",
|
||||
"./res/templates/browse/inspector-region.html",
|
||||
'legacyRegistry'
|
||||
], function (
|
||||
BrowseController,
|
||||
@ -73,15 +73,6 @@ define([
|
||||
legacyRegistry.register("platform/commonUI/browse", {
|
||||
"extensions": {
|
||||
"routes": [
|
||||
{
|
||||
"when": "/browse/:ids*?",
|
||||
"template": browseTemplate,
|
||||
"reloadOnSearch": false
|
||||
},
|
||||
{
|
||||
"when": "",
|
||||
"redirectTo": "/browse/"
|
||||
}
|
||||
],
|
||||
"constants": [
|
||||
{
|
||||
@ -295,6 +286,20 @@ define([
|
||||
]
|
||||
}
|
||||
],
|
||||
"templates": [
|
||||
{
|
||||
key: "browseRoot",
|
||||
template: browseTemplate
|
||||
},
|
||||
{
|
||||
key: "browseObject",
|
||||
template: browseObjectTemplate
|
||||
},
|
||||
{
|
||||
key: "inspectorRegion",
|
||||
template: inspectorRegionTemplate
|
||||
}
|
||||
],
|
||||
"licenses": [
|
||||
{
|
||||
"name": "screenfull.js",
|
||||
|
@ -47,6 +47,7 @@ define(
|
||||
urlService,
|
||||
defaultPath
|
||||
) {
|
||||
window.browseScope = $scope;
|
||||
var initialPath = ($route.current.params.ids || defaultPath).split("/"),
|
||||
currentIds;
|
||||
|
||||
|
@ -31,7 +31,6 @@ define(
|
||||
* @constructor
|
||||
*/
|
||||
function BrowseObjectController($scope, $location, $route) {
|
||||
var navigatedObject;
|
||||
function setViewForDomainObject(domainObject) {
|
||||
|
||||
var locationViewKey = $location.search().view;
|
||||
@ -47,7 +46,6 @@ define(
|
||||
((domainObject && domainObject.useCapability('view')) || [])
|
||||
.forEach(selectViewIfMatching);
|
||||
}
|
||||
navigatedObject = domainObject;
|
||||
}
|
||||
|
||||
function updateQueryParam(viewKey) {
|
||||
|
@ -27,7 +27,6 @@ define(
|
||||
describe("The PaneController", function () {
|
||||
var mockScope,
|
||||
mockAgentService,
|
||||
mockDomainObjects,
|
||||
mockWindow,
|
||||
controller,
|
||||
mockLocation,
|
||||
@ -47,17 +46,6 @@ define(
|
||||
|
||||
beforeEach(function () {
|
||||
mockScope = jasmine.createSpyObj("$scope", ["$on"]);
|
||||
mockDomainObjects = ['a', 'b'].map(function (id) {
|
||||
var mockDomainObject = jasmine.createSpyObj(
|
||||
'domainObject-' + id,
|
||||
['getId', 'getModel', 'getCapability']
|
||||
);
|
||||
|
||||
mockDomainObject.getId.and.returnValue(id);
|
||||
mockDomainObject.getModel.and.returnValue({});
|
||||
|
||||
return mockDomainObject;
|
||||
});
|
||||
mockAgentService = jasmine.createSpyObj(
|
||||
"agentService",
|
||||
["isMobile", "isPhone", "isTablet", "isPortrait", "isLandscape"]
|
||||
|
@ -47,7 +47,7 @@ define(
|
||||
|
||||
it("toggles fullscreen mode when performed", function () {
|
||||
action.perform();
|
||||
expect(window.screenfull.toggle).toHaveBeenCalled();
|
||||
expect(screenfull.toggle).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("provides displayable metadata", function () {
|
||||
|
@ -32,7 +32,7 @@ define(
|
||||
mockRootScope,
|
||||
mockDocument,
|
||||
mockDomainObject,
|
||||
titler;
|
||||
titler; // eslint-disable-line
|
||||
|
||||
beforeEach(function () {
|
||||
mockNavigationService = jasmine.createSpyObj(
|
||||
|
@ -23,13 +23,13 @@
|
||||
define([
|
||||
"./src/DialogService",
|
||||
"./src/OverlayService",
|
||||
"text!./res/templates/overlay-dialog.html",
|
||||
"text!./res/templates/overlay-options.html",
|
||||
"text!./res/templates/dialog.html",
|
||||
"text!./res/templates/overlay-blocking-message.html",
|
||||
"text!./res/templates/message.html",
|
||||
"text!./res/templates/overlay-message-list.html",
|
||||
"text!./res/templates/overlay.html",
|
||||
"./res/templates/overlay-dialog.html",
|
||||
"./res/templates/overlay-options.html",
|
||||
"./res/templates/dialog.html",
|
||||
"./res/templates/overlay-blocking-message.html",
|
||||
"./res/templates/message.html",
|
||||
"./res/templates/overlay-message-list.html",
|
||||
"./res/templates/overlay.html",
|
||||
'legacyRegistry'
|
||||
], function (
|
||||
DialogService,
|
||||
|
@ -49,14 +49,14 @@ define([
|
||||
"./src/creation/CreateActionProvider",
|
||||
"./src/creation/AddActionProvider",
|
||||
"./src/creation/CreationService",
|
||||
"text!./res/templates/create/locator.html",
|
||||
"text!./res/templates/create/create-button.html",
|
||||
"text!./res/templates/create/create-menu.html",
|
||||
"text!./res/templates/library.html",
|
||||
"text!./res/templates/edit-object.html",
|
||||
"text!./res/templates/edit-action-buttons.html",
|
||||
"text!./res/templates/elements.html",
|
||||
"text!./res/templates/topbar-edit.html",
|
||||
"./res/templates/create/locator.html",
|
||||
"./res/templates/create/create-button.html",
|
||||
"./res/templates/create/create-menu.html",
|
||||
"./res/templates/library.html",
|
||||
"./res/templates/edit-object.html",
|
||||
"./res/templates/edit-action-buttons.html",
|
||||
"./res/templates/elements.html",
|
||||
"./res/templates/topbar-edit.html",
|
||||
'legacyRegistry'
|
||||
], function (
|
||||
EditActionController,
|
||||
|
@ -55,7 +55,7 @@ define(
|
||||
|
||||
// A view is editable unless explicitly flagged as not
|
||||
(views || []).forEach(function (view) {
|
||||
if (view.editable === true ||
|
||||
if (isEditable(view) ||
|
||||
(view.key === 'plot' && type.getKey() === 'telemetry.panel') ||
|
||||
(view.key === 'table' && type.getKey() === 'table') ||
|
||||
(view.key === 'rt-table' && type.getKey() === 'rttable')
|
||||
@ -64,6 +64,14 @@ define(
|
||||
}
|
||||
});
|
||||
|
||||
function isEditable(view) {
|
||||
if (typeof view.editable === Function) {
|
||||
return view.editable(domainObject.useCapability('adapter'));
|
||||
} else {
|
||||
return view.editable === true;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
};
|
||||
|
||||
|
@ -55,16 +55,16 @@ define(
|
||||
navigatedObject = this.navigationService.getNavigation(),
|
||||
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()) {
|
||||
return this.editModeBlacklist.indexOf(actionMetadata.key) === -1;
|
||||
} else {
|
||||
//Target is in the context menu
|
||||
return this.nonEditContextBlacklist.indexOf(actionMetadata.key) === -1;
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
// } else {
|
||||
// return true;
|
||||
// }
|
||||
};
|
||||
|
||||
return EditContextualActionPolicy;
|
||||
|
@ -25,8 +25,7 @@ define(
|
||||
function (EditAndComposeAction) {
|
||||
|
||||
describe("The Link action", function () {
|
||||
var mockQ,
|
||||
mockDomainObject,
|
||||
var mockDomainObject,
|
||||
mockParent,
|
||||
mockContext,
|
||||
mockComposition,
|
||||
@ -47,13 +46,10 @@ define(
|
||||
}
|
||||
|
||||
beforeEach(function () {
|
||||
|
||||
|
||||
mockDomainObject = jasmine.createSpyObj(
|
||||
"domainObject",
|
||||
["getId", "getCapability"]
|
||||
);
|
||||
mockQ = { when: mockPromise };
|
||||
mockParent = {
|
||||
getModel: function () {
|
||||
return model;
|
||||
|
@ -34,7 +34,6 @@ define(
|
||||
mockDomainObject,
|
||||
capabilities = {},
|
||||
mockEditAction,
|
||||
mockSaveAction,
|
||||
action;
|
||||
|
||||
function mockPromise(value) {
|
||||
@ -83,12 +82,6 @@ define(
|
||||
mockDomainObject.getCapability.and.callFake(function (name) {
|
||||
return capabilities[name];
|
||||
});
|
||||
mockSaveAction = jasmine.createSpyObj(
|
||||
"saveAction",
|
||||
[
|
||||
"perform"
|
||||
]
|
||||
);
|
||||
|
||||
capabilities.action = jasmine.createSpyObj(
|
||||
"actionCapability",
|
||||
|
@ -27,7 +27,6 @@ define(
|
||||
describe("The Edit action policy", function () {
|
||||
var editableView,
|
||||
nonEditableView,
|
||||
undefinedView,
|
||||
testViews,
|
||||
testContext,
|
||||
mockDomainObject,
|
||||
@ -67,7 +66,6 @@ define(
|
||||
|
||||
editableView = { editable: true };
|
||||
nonEditableView = { editable: false };
|
||||
undefinedView = { someKey: "some value" };
|
||||
plotView = { key: "plot", editable: false };
|
||||
testViews = [];
|
||||
|
||||
|
@ -30,12 +30,6 @@ define(
|
||||
mockObjects,
|
||||
mockDomainObject,
|
||||
testStructure,
|
||||
testAB,
|
||||
testABC,
|
||||
testABC2,
|
||||
testABCXYZ,
|
||||
testABCYZ,
|
||||
testM,
|
||||
toolbar;
|
||||
|
||||
beforeEach(function () {
|
||||
@ -62,13 +56,6 @@ define(
|
||||
{ name: "M", method: "m", domainObject: mockDomainObject }
|
||||
];
|
||||
|
||||
testAB = { a: 0, b: 1 };
|
||||
testABC = { a: 0, b: 1, c: 2 };
|
||||
testABC2 = { a: 4, b: 1, c: 2 }; // For inconsistent-state checking
|
||||
testABCXYZ = { a: 0, b: 1, c: 2, x: 'X!', y: 'Y!', z: 'Z!' };
|
||||
testABCYZ = { a: 0, b: 1, c: 2, y: 'Y!', z: 'Z!' };
|
||||
testM = { m: jasmine.createSpy("method") };
|
||||
|
||||
toolbar = new EditToolbar(mockScope, mockOpenMCT, testStructure);
|
||||
});
|
||||
|
||||
|
@ -43,13 +43,12 @@ define(["../../src/services/NestedTransaction"], function (NestedTransaction) {
|
||||
|
||||
describe("when callbacks are added", function () {
|
||||
var mockCommit,
|
||||
mockCancel,
|
||||
remove;
|
||||
mockCancel;
|
||||
|
||||
beforeEach(function () {
|
||||
mockCommit = jasmine.createSpy('commit');
|
||||
mockCancel = jasmine.createSpy('cancel');
|
||||
remove = nestedTransaction.add(mockCommit, mockCancel);
|
||||
nestedTransaction.add(mockCommit, mockCancel);
|
||||
});
|
||||
|
||||
it("does not interact with its parent transaction", function () {
|
||||
|
@ -52,26 +52,26 @@ define([
|
||||
"./src/directives/MCTPreview",
|
||||
"./src/actions/MCTPreviewAction",
|
||||
"./src/filters/ReverseFilter",
|
||||
"text!./res/templates/bottombar.html",
|
||||
"text!./res/templates/controls/action-button.html",
|
||||
"text!./res/templates/controls/input-filter.html",
|
||||
"text!./res/templates/angular-indicator.html",
|
||||
"text!./res/templates/message-banner.html",
|
||||
"text!./res/templates/progress-bar.html",
|
||||
"text!./res/templates/controls/time-controller.html",
|
||||
"text!./res/templates/containers/accordion.html",
|
||||
"text!./res/templates/subtree.html",
|
||||
"text!./res/templates/tree.html",
|
||||
"text!./res/templates/tree-node.html",
|
||||
"text!./res/templates/label.html",
|
||||
"text!./res/templates/controls/action-group.html",
|
||||
"text!./res/templates/menu/context-menu.html",
|
||||
"text!./res/templates/controls/switcher.html",
|
||||
"text!./res/templates/object-inspector.html",
|
||||
"text!./res/templates/controls/selector.html",
|
||||
"text!./res/templates/controls/datetime-picker.html",
|
||||
"text!./res/templates/controls/datetime-field.html",
|
||||
"text!./res/templates/preview.html",
|
||||
"./res/templates/bottombar.html",
|
||||
"./res/templates/controls/action-button.html",
|
||||
"./res/templates/controls/input-filter.html",
|
||||
"./res/templates/angular-indicator.html",
|
||||
"./res/templates/message-banner.html",
|
||||
"./res/templates/progress-bar.html",
|
||||
"./res/templates/controls/time-controller.html",
|
||||
"./res/templates/containers/accordion.html",
|
||||
"./res/templates/subtree.html",
|
||||
"./res/templates/tree.html",
|
||||
"./res/templates/tree-node.html",
|
||||
"./res/templates/label.html",
|
||||
"./res/templates/controls/action-group.html",
|
||||
"./res/templates/menu/context-menu.html",
|
||||
"./res/templates/controls/switcher.html",
|
||||
"./res/templates/object-inspector.html",
|
||||
"./res/templates/controls/selector.html",
|
||||
"./res/templates/controls/datetime-picker.html",
|
||||
"./res/templates/controls/datetime-field.html",
|
||||
"./res/templates/preview.html",
|
||||
'legacyRegistry'
|
||||
], function (
|
||||
UrlService,
|
||||
@ -173,12 +173,6 @@ define([
|
||||
"key": "reverse"
|
||||
}
|
||||
],
|
||||
"stylesheets": [
|
||||
{
|
||||
"stylesheetUrl": "css/normalize.min.css",
|
||||
"priority": "mandatory"
|
||||
}
|
||||
],
|
||||
"templates": [
|
||||
{
|
||||
"key": "bottombar",
|
||||
|
@ -1,48 +0,0 @@
|
||||
/* http://meyerweb.com/eric/tools/css/reset/
|
||||
v2.0 | 20110126
|
||||
License: none (public domain)
|
||||
*/
|
||||
|
||||
html, body, div, span, applet, object, iframe,
|
||||
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
|
||||
a, abbr, acronym, address, big, cite, code,
|
||||
del, dfn, em, img, ins, kbd, q, s, samp,
|
||||
small, strike, strong, sub, sup, tt, var,
|
||||
b, u, i, center,
|
||||
dl, dt, dd, ol, ul, li,
|
||||
fieldset, form, label, legend,
|
||||
table, caption, tbody, tfoot, thead, tr, th, td,
|
||||
article, aside, canvas, details, embed,
|
||||
figure, figcaption, footer, header, hgroup,
|
||||
menu, nav, output, ruby, section, summary,
|
||||
time, mark, audio, video {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
font-size: 100%;
|
||||
font: inherit;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
/* HTML5 display-role reset for older browsers */
|
||||
article, aside, details, figcaption, figure,
|
||||
footer, header, hgroup, menu, nav, section {
|
||||
display: block;
|
||||
}
|
||||
body {
|
||||
line-height: 1;
|
||||
}
|
||||
ol, ul {
|
||||
list-style: none;
|
||||
}
|
||||
blockquote, q {
|
||||
quotes: none;
|
||||
}
|
||||
blockquote:before, blockquote:after,
|
||||
q:before, q:after {
|
||||
content: '';
|
||||
content: none;
|
||||
}
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
}
|
@ -45,6 +45,15 @@ define(
|
||||
|
||||
// Link; install event handlers.
|
||||
function link(scope, element, attrs) {
|
||||
var isDestroyed = false;
|
||||
scope.$on("$destroy", function () {
|
||||
isDestroyed = true;
|
||||
});
|
||||
|
||||
openmct.$injector.get('$timeout')(function () {
|
||||
if (isDestroyed) {
|
||||
return;
|
||||
}
|
||||
var removeSelectable = openmct.selection.selectable(
|
||||
element[0],
|
||||
scope.$eval(attrs.mctSelectable),
|
||||
@ -54,6 +63,9 @@ define(
|
||||
scope.$on("$destroy", function () {
|
||||
removeSelectable();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
return {
|
||||
|
@ -22,7 +22,7 @@
|
||||
|
||||
define([
|
||||
'zepto',
|
||||
'text!../../res/templates/tree/toggle.html'
|
||||
'../../res/templates/tree/toggle.html'
|
||||
], function ($, toggleTemplate) {
|
||||
function ToggleView(state) {
|
||||
this.expanded = !!state;
|
||||
|
@ -22,7 +22,7 @@
|
||||
|
||||
define([
|
||||
'zepto',
|
||||
'text!../../res/templates/tree/tree-label.html'
|
||||
'../../res/templates/tree/tree-label.html'
|
||||
], function ($, labelTemplate) {
|
||||
|
||||
function TreeLabelView(gestureService) {
|
||||
|
@ -22,7 +22,7 @@
|
||||
|
||||
define([
|
||||
'zepto',
|
||||
'text!../../res/templates/tree/node.html',
|
||||
'../../res/templates/tree/node.html',
|
||||
'./ToggleView',
|
||||
'./TreeLabelView'
|
||||
], function ($, nodeTemplate, ToggleView, TreeLabelView) {
|
||||
|
@ -23,7 +23,7 @@
|
||||
define([
|
||||
'zepto',
|
||||
'./TreeNodeView',
|
||||
'text!../../res/templates/tree/wait-node.html'
|
||||
'../../res/templates/tree/wait-node.html'
|
||||
], function ($, TreeNodeView, spinnerTemplate) {
|
||||
|
||||
function TreeView(gestureService, openmct, selectFn) {
|
||||
|
@ -31,7 +31,7 @@ define(
|
||||
mockHead,
|
||||
mockElement,
|
||||
testBundle,
|
||||
loader;
|
||||
loader; // eslint-disable-line
|
||||
|
||||
beforeEach(function () {
|
||||
testBundle = {
|
||||
|
@ -41,7 +41,6 @@ define(
|
||||
mockScope,
|
||||
mockElement,
|
||||
testAttrs,
|
||||
mockBody,
|
||||
mockTransclude,
|
||||
mockParentEl,
|
||||
mockNewElement,
|
||||
@ -59,8 +58,6 @@ define(
|
||||
jasmine.createSpyObj("$scope", ["$eval", "$apply", "$on"]);
|
||||
mockElement =
|
||||
jasmine.createSpyObj("element", JQLITE_METHODS);
|
||||
mockBody =
|
||||
jasmine.createSpyObj("body", JQLITE_METHODS);
|
||||
mockTransclude =
|
||||
jasmine.createSpy("transclude");
|
||||
mockParentEl =
|
||||
|
@ -24,10 +24,10 @@ define([
|
||||
"./src/gestures/InfoGesture",
|
||||
"./src/gestures/InfoButtonGesture",
|
||||
"./src/services/InfoService",
|
||||
"text!./res/info-table.html",
|
||||
"text!./res/info-bubble.html",
|
||||
"text!./res/bubble.html",
|
||||
"text!./res/templates/info-button.html",
|
||||
"./res/info-table.html",
|
||||
"./res/info-bubble.html",
|
||||
"./res/bubble.html",
|
||||
"./res/templates/info-button.html",
|
||||
'legacyRegistry'
|
||||
], function (
|
||||
InfoGesture,
|
||||
|
@ -25,8 +25,7 @@ define(
|
||||
function (InfoButtonGesture) {
|
||||
|
||||
describe("The info button gesture", function () {
|
||||
var mockTimeout,
|
||||
mockDocument,
|
||||
var mockDocument,
|
||||
mockBody,
|
||||
mockAgentService,
|
||||
mockInfoService,
|
||||
@ -42,7 +41,6 @@ define(
|
||||
fireDismissGesture;
|
||||
|
||||
beforeEach(function () {
|
||||
mockTimeout = jasmine.createSpy('$timeout');
|
||||
mockDocument = jasmine.createSpyObj('$document', ['find']);
|
||||
mockBody = jasmine.createSpyObj('body', ['on', 'off', 'scope', 'css', 'unbind']);
|
||||
mockDocument.find.and.returnValue(mockBody);
|
||||
|
@ -74,7 +74,7 @@ define(
|
||||
"device " + (trueMethods.join(", "));
|
||||
|
||||
describe("when " + summary, function () {
|
||||
var classifier;
|
||||
var classifier; // eslint-disable-line
|
||||
|
||||
beforeEach(function () {
|
||||
trueMethods.forEach(function (m) {
|
||||
|
@ -24,7 +24,7 @@ define([
|
||||
"./src/NotificationIndicatorController",
|
||||
"./src/NotificationIndicator",
|
||||
"./src/NotificationService",
|
||||
"text!./res/notification-indicator.html",
|
||||
"./res/notification-indicator.html",
|
||||
'legacyRegistry'
|
||||
], function (
|
||||
NotificationIndicatorController,
|
||||
|
@ -76,7 +76,7 @@ define(
|
||||
* @returns a domain object
|
||||
*/
|
||||
InspectorController.prototype.selectedItem = function () {
|
||||
return this.$scope.selection[0].context.oldItem;
|
||||
return this.$scope.selection[0] && this.$scope.selection[0].context.oldItem;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -48,10 +48,11 @@ define(
|
||||
});
|
||||
|
||||
it("throws exceptions on unrecognized conversions", function () {
|
||||
var caught = false, tmp;
|
||||
var caught = false;
|
||||
|
||||
try {
|
||||
tmp = new TypePropertyConversion("some-unknown-conversion");
|
||||
// eslint-disable-next-line
|
||||
new TypePropertyConversion("some-unknown-conversion");
|
||||
} catch (e) {
|
||||
caught = true;
|
||||
}
|
||||
|
@ -124,7 +124,6 @@ define(
|
||||
|
||||
var mockQ,
|
||||
mockDeferred,
|
||||
createObjectPromise,
|
||||
copyService,
|
||||
object,
|
||||
newParent,
|
||||
@ -138,7 +137,6 @@ define(
|
||||
resolvedValue;
|
||||
|
||||
beforeEach(function () {
|
||||
createObjectPromise = synchronousPromise(undefined);
|
||||
policyService.allow.and.returnValue(true);
|
||||
|
||||
persistObjectPromise = synchronousPromise(undefined);
|
||||
@ -275,8 +273,7 @@ define(
|
||||
describe("on domainObject with composition", function () {
|
||||
var childObject,
|
||||
objectClone,
|
||||
childObjectClone,
|
||||
compositionPromise;
|
||||
childObjectClone;
|
||||
|
||||
beforeEach(function () {
|
||||
var invocationCount = 0,
|
||||
@ -325,11 +322,6 @@ define(
|
||||
}
|
||||
});
|
||||
|
||||
compositionPromise = jasmine.createSpyObj(
|
||||
'compositionPromise',
|
||||
['then']
|
||||
);
|
||||
|
||||
compositionCapability
|
||||
.invoke
|
||||
.and.returnValue(synchronousPromise([childObject]));
|
||||
|
@ -178,7 +178,6 @@ define(
|
||||
type: { type: 'object' }
|
||||
}
|
||||
});
|
||||
|
||||
moveResult = moveService.perform(object, newParent);
|
||||
});
|
||||
|
||||
@ -189,6 +188,10 @@ define(
|
||||
);
|
||||
});
|
||||
|
||||
it("returns a promise", function () {
|
||||
expect(moveResult.then).toEqual(jasmine.any(Function));
|
||||
});
|
||||
|
||||
it("waits for result of link", function () {
|
||||
expect(linkService.perform.calls.mostRecent().promise.then)
|
||||
.toHaveBeenCalledWith(jasmine.any(Function));
|
||||
|
@ -34,8 +34,8 @@ define([
|
||||
"./src/actions/RestartTimerAction",
|
||||
"./src/actions/StopTimerAction",
|
||||
"./src/actions/PauseTimerAction",
|
||||
"text!./res/templates/clock.html",
|
||||
"text!./res/templates/timer.html",
|
||||
"./res/templates/clock.html",
|
||||
"./res/templates/timer.html",
|
||||
'legacyRegistry'
|
||||
], function (
|
||||
MomentTimezone,
|
||||
|
@ -29,10 +29,10 @@ define([
|
||||
"./src/ui/ConductorAxisDirective",
|
||||
"./src/ui/NumberFormat",
|
||||
"./src/ui/StringFormat",
|
||||
"text!./res/templates/time-conductor.html",
|
||||
"text!./res/templates/mode-selector/mode-selector.html",
|
||||
"text!./res/templates/mode-selector/mode-menu.html",
|
||||
"text!./res/templates/time-of-interest.html",
|
||||
"./res/templates/time-conductor.html",
|
||||
"./res/templates/mode-selector/mode-selector.html",
|
||||
"./res/templates/mode-selector/mode-menu.html",
|
||||
"./res/templates/time-of-interest.html",
|
||||
"legacyRegistry"
|
||||
], function (
|
||||
TimeConductorController,
|
||||
@ -97,16 +97,6 @@ define([
|
||||
"implementation": ConductorTOIDirective
|
||||
}
|
||||
],
|
||||
"stylesheets": [
|
||||
{
|
||||
"stylesheetUrl": "css/time-conductor-espresso.css",
|
||||
"theme": "espresso"
|
||||
},
|
||||
{
|
||||
"stylesheetUrl": "css/time-conductor-snow.css",
|
||||
"theme": "snow"
|
||||
}
|
||||
],
|
||||
"templates": [
|
||||
{
|
||||
"key": "conductor",
|
||||
|
@ -37,8 +37,6 @@ define([
|
||||
mockConductorViewService,
|
||||
mockFormatService,
|
||||
mockScope,
|
||||
mockElement,
|
||||
mockTarget,
|
||||
mockBounds,
|
||||
element,
|
||||
mockTimeSystem,
|
||||
@ -56,13 +54,6 @@ define([
|
||||
]);
|
||||
|
||||
//Add some HTML elements
|
||||
mockTarget = {
|
||||
offsetWidth: 0,
|
||||
offsetHeight: 0
|
||||
};
|
||||
mockElement = {
|
||||
firstChild: mockTarget
|
||||
};
|
||||
mockBounds = {
|
||||
start: 100,
|
||||
end: 200
|
||||
|
@ -376,7 +376,6 @@ define(['./TimeConductorController'], function (TimeConductorController) {
|
||||
describe("when the URL defines conductor state", function () {
|
||||
var urlBounds;
|
||||
var urlTimeSystem;
|
||||
var urlMode;
|
||||
var urlDeltas;
|
||||
|
||||
var mockDeltaFormat;
|
||||
@ -439,7 +438,6 @@ define(['./TimeConductorController'], function (TimeConductorController) {
|
||||
end: 200
|
||||
};
|
||||
urlTimeSystem = "otherTimeSystem";
|
||||
urlMode = "realtime";
|
||||
urlDeltas = {
|
||||
start: 300,
|
||||
end: 400
|
||||
|
@ -21,7 +21,7 @@
|
||||
*****************************************************************************/
|
||||
|
||||
define([
|
||||
"text!../layout/res/templates/fixed.html",
|
||||
"../layout/res/templates/fixed.html",
|
||||
'legacyRegistry'
|
||||
], function (
|
||||
fixedTemplate,
|
||||
|
@ -23,7 +23,7 @@
|
||||
define([
|
||||
'./src/HyperlinkController',
|
||||
'legacyRegistry',
|
||||
'text!./res/templates/hyperlink.html'
|
||||
'./res/templates/hyperlink.html'
|
||||
], function (
|
||||
HyperlinkController,
|
||||
legacyRegistry,
|
||||
|
@ -24,7 +24,7 @@ define([
|
||||
"./src/policies/ImageryViewPolicy",
|
||||
"./src/controllers/ImageryController",
|
||||
"./src/directives/MCTBackgroundImage",
|
||||
"text!./res/templates/imagery.html",
|
||||
"./res/templates/imagery.html",
|
||||
'legacyRegistry'
|
||||
], function (
|
||||
ImageryViewPolicy,
|
||||
|
@ -25,14 +25,14 @@ define([
|
||||
"./src/FixedController",
|
||||
"./src/LayoutCompositionPolicy",
|
||||
'./src/MCTTriggerModal',
|
||||
"text!./res/templates/layout.html",
|
||||
"text!./res/templates/fixed.html",
|
||||
"text!./res/templates/frame.html",
|
||||
"text!./res/templates/elements/telemetry.html",
|
||||
"text!./res/templates/elements/box.html",
|
||||
"text!./res/templates/elements/line.html",
|
||||
"text!./res/templates/elements/text.html",
|
||||
"text!./res/templates/elements/image.html",
|
||||
"./res/templates/layout.html",
|
||||
"./res/templates/fixed.html",
|
||||
"./res/templates/frame.html",
|
||||
"./res/templates/elements/telemetry.html",
|
||||
"./res/templates/elements/box.html",
|
||||
"./res/templates/elements/line.html",
|
||||
"./res/templates/elements/text.html",
|
||||
"./res/templates/elements/image.html",
|
||||
'legacyRegistry'
|
||||
], function (
|
||||
LayoutController,
|
||||
|
@ -23,7 +23,7 @@
|
||||
define([
|
||||
'./src/controllers/ListViewController',
|
||||
'./src/directives/MCTGesture',
|
||||
'text!./res/templates/listview.html',
|
||||
'./res/templates/listview.html',
|
||||
'legacyRegistry'
|
||||
], function (
|
||||
ListViewController,
|
||||
|
@ -13,13 +13,13 @@ define([
|
||||
"./src/actions/NewEntryContextual",
|
||||
"./src/capabilities/NotebookCapability",
|
||||
"./src/policies/CompositionPolicy",
|
||||
"text!./res/templates/notebook.html",
|
||||
"text!./res/templates/entry.html",
|
||||
"text!./res/templates/annotation.html",
|
||||
"text!./res/templates/notifications.html",
|
||||
"text!../layout/res/templates/frame.html",
|
||||
"text!./res/templates/controls/embedControl.html",
|
||||
"text!./res/templates/controls/snapSelect.html"
|
||||
"./res/templates/notebook.html",
|
||||
"./res/templates/entry.html",
|
||||
"./res/templates/annotation.html",
|
||||
"./res/templates/notifications.html",
|
||||
"../layout/res/templates/frame.html",
|
||||
"./res/templates/controls/embedControl.html",
|
||||
"./res/templates/controls/snapSelect.html"
|
||||
], function (
|
||||
legacyRegistry,
|
||||
NotebookController,
|
||||
@ -288,19 +288,6 @@ define([
|
||||
"key": "snapshot-select",
|
||||
"template": snapSelectTemplate
|
||||
}
|
||||
],
|
||||
"stylesheets": [
|
||||
{
|
||||
"stylesheetUrl": "css/notebook.css"
|
||||
},
|
||||
{
|
||||
"stylesheetUrl": "css/notebook-espresso.css",
|
||||
"theme": "espresso"
|
||||
},
|
||||
{
|
||||
"stylesheetUrl": "css/notebook-snow.css",
|
||||
"theme": "snow"
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
|
@ -38,7 +38,7 @@ var OVERLAY_TEMPLATE = '' +
|
||||
|
||||
define([
|
||||
'zepto',
|
||||
"text!../../res/templates/snapshotHeader.html"
|
||||
"../../res/templates/snapshotHeader.html"
|
||||
],
|
||||
function ($, headerTemplate) {
|
||||
|
||||
|
@ -310,8 +310,7 @@ define(
|
||||
initiatingEvent = agentService.isMobile() ?
|
||||
'touchstart' : 'mousedown',
|
||||
dismissExistingMenu,
|
||||
menu,
|
||||
popup;
|
||||
menu;
|
||||
|
||||
var container = $($event.currentTarget).parent().parent();
|
||||
|
||||
@ -333,7 +332,7 @@ define(
|
||||
// ...and record the presence of this menu.
|
||||
dismissExistingMenu = dismiss;
|
||||
|
||||
popup = popupService.display(menu, [$event.pageX,$event.pageY], {
|
||||
popupService.display(menu, [$event.pageX,$event.pageY], {
|
||||
marginX: 0,
|
||||
marginY: -50
|
||||
});
|
||||
|
@ -31,11 +31,9 @@ define(['zepto'], function ($) {
|
||||
var selectedModel = selectedObject.getModel();
|
||||
var cssClass = selectedObject.getCapability('type').typeDef.cssClass;
|
||||
var entryId = -1;
|
||||
var embedId = -1;
|
||||
$scope.clearSearch();
|
||||
if ($element[0].id === 'newEntry') {
|
||||
entryId = $scope.domainObject.model.entries.length;
|
||||
embedId = 0;
|
||||
var lastEntry = $scope.domainObject.model.entries[entryId - 1];
|
||||
if (lastEntry === undefined || lastEntry.text || lastEntry.embeds) {
|
||||
$scope.domainObject.useCapability('mutation', function (model) {
|
||||
@ -84,8 +82,6 @@ define(['zepto'], function ($) {
|
||||
});
|
||||
});
|
||||
|
||||
embedId = $scope.domainObject.model.entries[entryId].embeds.length - 1;
|
||||
|
||||
if (selectedObject) {
|
||||
e.preventDefault();
|
||||
|
||||
|
@ -22,7 +22,7 @@
|
||||
|
||||
define([
|
||||
"./src/EmbeddedPageController",
|
||||
"text!./res/iframe.html",
|
||||
"./res/iframe.html",
|
||||
'legacyRegistry'
|
||||
], function (
|
||||
EmbeddedPageController,
|
||||
|
@ -22,7 +22,7 @@
|
||||
|
||||
define([
|
||||
|
||||
"text!./res/markup.html",
|
||||
"./res/markup.html",
|
||||
'legacyRegistry'
|
||||
], function (
|
||||
|
||||
|
@ -1,134 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2018, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define([
|
||||
"./src/directives/MCTTable",
|
||||
"./src/controllers/TelemetryTableController",
|
||||
"./src/controllers/TableOptionsController",
|
||||
'../../commonUI/regions/src/Region',
|
||||
'../../commonUI/browse/src/InspectorRegion',
|
||||
"text!./res/templates/table-options-edit.html",
|
||||
"text!./res/templates/telemetry-table.html",
|
||||
"legacyRegistry"
|
||||
], function (
|
||||
MCTTable,
|
||||
TelemetryTableController,
|
||||
TableOptionsController,
|
||||
Region,
|
||||
InspectorRegion,
|
||||
tableOptionsEditTemplate,
|
||||
telemetryTableTemplate,
|
||||
legacyRegistry
|
||||
) {
|
||||
/**
|
||||
* Two region parts are defined here. One that appears only in browse
|
||||
* mode, and one that appears only in edit mode. For not they both point
|
||||
* to the same representation, but a different key could be used here to
|
||||
* include a customized representation for edit mode.
|
||||
*/
|
||||
var tableInspector = new InspectorRegion(),
|
||||
tableOptionsEditRegion = new Region({
|
||||
name: "table-options",
|
||||
title: "Table Options",
|
||||
modes: ['edit'],
|
||||
content: {
|
||||
key: "table-options-edit"
|
||||
}
|
||||
});
|
||||
tableInspector.addRegion(tableOptionsEditRegion);
|
||||
|
||||
legacyRegistry.register("platform/features/table", {
|
||||
"extensions": {
|
||||
"types": [
|
||||
{
|
||||
"key": "table",
|
||||
"name": "Telemetry Table",
|
||||
"cssClass": "icon-tabular-realtime",
|
||||
"description": "A table of values over a given time period. The table will be automatically updated with new values as they become available",
|
||||
"priority": 861,
|
||||
"features": "creation",
|
||||
"delegates": [
|
||||
"telemetry"
|
||||
],
|
||||
"inspector": "table-options-edit",
|
||||
"contains": [
|
||||
{
|
||||
"has": "telemetry"
|
||||
}
|
||||
],
|
||||
"model": {
|
||||
"composition": []
|
||||
},
|
||||
"views": [
|
||||
"table"
|
||||
]
|
||||
}
|
||||
],
|
||||
"controllers": [
|
||||
{
|
||||
"key": "TelemetryTableController",
|
||||
"implementation": TelemetryTableController,
|
||||
"depends": ["$scope", "$timeout", "openmct"]
|
||||
},
|
||||
{
|
||||
"key": "TableOptionsController",
|
||||
"implementation": TableOptionsController,
|
||||
"depends": ["$scope"]
|
||||
}
|
||||
|
||||
],
|
||||
"views": [
|
||||
{
|
||||
"name": "Telemetry Table",
|
||||
"key": "table",
|
||||
"cssClass": "icon-tabular-realtime",
|
||||
"template": telemetryTableTemplate,
|
||||
"needs": [
|
||||
"telemetry"
|
||||
],
|
||||
"delegation": true,
|
||||
"editable": false
|
||||
}
|
||||
],
|
||||
"directives": [
|
||||
{
|
||||
"key": "mctTable",
|
||||
"implementation": MCTTable,
|
||||
"depends": ["$timeout"]
|
||||
}
|
||||
],
|
||||
"representations": [
|
||||
{
|
||||
"key": "table-options-edit",
|
||||
"template": tableOptionsEditTemplate
|
||||
}
|
||||
],
|
||||
"stylesheets": [
|
||||
{
|
||||
"stylesheetUrl": "css/table.css",
|
||||
"priority": "mandatory"
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
});
|
@ -1,95 +0,0 @@
|
||||
<div class="l-control-bar">
|
||||
<a class="s-button t-export icon-download labeled"
|
||||
ng-click="exportAsCSV()"
|
||||
title="Export This View's Data">
|
||||
Export
|
||||
</a>
|
||||
</div>
|
||||
<div class="mct-table-headers-w" mct-scroll-x="scroll.x">
|
||||
<table class="mct-table l-tabular-headers filterable"
|
||||
ng-style="{
|
||||
'max-width': totalWidth
|
||||
}">
|
||||
<thead>
|
||||
<tr>
|
||||
<th ng-repeat="header in displayHeaders"
|
||||
ng-style="{
|
||||
width: columnWidths[$index] + 'px',
|
||||
'max-width': columnWidths[$index] + 'px',
|
||||
}"
|
||||
ng-class="[
|
||||
enableSort ? 'sortable' : '',
|
||||
sortColumn === header ? 'sort' : '',
|
||||
sortDirection || ''
|
||||
].join(' ')"
|
||||
ng-click="toggleSort(header)">
|
||||
{{ header }}
|
||||
</th>
|
||||
</tr>
|
||||
<tr ng-if="enableFilter" class="s-filters">
|
||||
<th ng-repeat="header in displayHeaders"
|
||||
ng-style="{
|
||||
width: columnWidths[$index] + 'px',
|
||||
'max-width': columnWidths[$index] + 'px',
|
||||
}">
|
||||
<div class="holder l-filter flex-elem grows"
|
||||
ng-class="{active: filters[header]}">
|
||||
<input type="text"
|
||||
ng-model="filters[header]"/>
|
||||
<a class="clear-icon clear-input icon-x-in-circle"
|
||||
ng-class="{show: filters[header]}"
|
||||
ng-click="filters[header] = undefined"></a>
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
<table class="mct-sizing-table t-sizing-table"
|
||||
ng-style="{
|
||||
width: calcTableWidthPx
|
||||
}">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td ng-repeat="header in displayHeaders">{{header}}</td>
|
||||
</tr>
|
||||
<tr><td ng-repeat="header in displayHeaders" >
|
||||
{{sizingRow[header].text}}
|
||||
</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="l-tabular-body t-scrolling vscroll--persist" mct-resize="resize()" mct-scroll-x="scroll.x">
|
||||
<div class="mct-table-scroll-forcer"
|
||||
ng-style="{
|
||||
width: totalWidth
|
||||
}"></div>
|
||||
<table class="mct-table"
|
||||
ng-style="{
|
||||
height: totalHeight + 'px',
|
||||
'max-width': totalWidth
|
||||
}">
|
||||
<tbody>
|
||||
<tr ng-repeat-start="visibleRow in visibleRows track by $index"
|
||||
ng-if="visibleRow.rowIndex === toiRowIndex"
|
||||
ng-style="{ top: visibleRow.offsetY + 'px' }"
|
||||
class="l-toi-tablerow">
|
||||
<td colspan="999">
|
||||
<mct-include key="'time-of-interest'"
|
||||
class="l-toi-holder pinned"></mct-include>
|
||||
</td>
|
||||
</tr>
|
||||
<tr ng-repeat-end
|
||||
ng-style="{ top: visibleRow.offsetY + 'px' }"
|
||||
ng-click="table.onRowClick($event, visibleRow.rowIndex)">
|
||||
<td ng-repeat="header in displayHeaders"
|
||||
ng-style="{
|
||||
width: columnWidths[$index] + 'px',
|
||||
'max-width': columnWidths[$index] + 'px',
|
||||
}"
|
||||
class="{{visibleRow.contents[header].cssClass}}">
|
||||
{{ visibleRow.contents[header].text }}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
@ -1,32 +0,0 @@
|
||||
<!--
|
||||
Open MCT, Copyright (c) 2014-2018, United States Government
|
||||
as represented by the Administrator of the National Aeronautics and Space
|
||||
Administration. All rights reserved.
|
||||
|
||||
Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0.
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
License for the specific language governing permissions and limitations
|
||||
under the License.
|
||||
|
||||
Open MCT includes source code licensed under additional open source
|
||||
licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
this source code distribution or the Licensing information page available
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
|
||||
<div ng-if="domainObject.getCapability('editor').inEditContext()"
|
||||
ng-controller="TableOptionsController"
|
||||
class="flex-elem grows l-inspector-part">
|
||||
<mct-form
|
||||
ng-model="configuration.table.columns"
|
||||
structure="columnsForm"
|
||||
name="columnsFormState"
|
||||
class="flex-elem no-margin">
|
||||
</mct-form>
|
||||
</div>
|
@ -1,15 +0,0 @@
|
||||
<div ng-controller="TelemetryTableController as tableController"
|
||||
ng-class="{'loading': loading}">
|
||||
<mct-table
|
||||
headers="headers"
|
||||
rows="rows"
|
||||
time-columns="[tableController.table.timeSystemColumnTitle]"
|
||||
format-cell="formatCell"
|
||||
enableFilter="true"
|
||||
enableSort="true"
|
||||
auto-scroll="autoScroll"
|
||||
default-sort="defaultSort"
|
||||
export-as="{{ exportAs }}"
|
||||
class="tabular-holder l-sticky-headers has-control-bar">
|
||||
</mct-table>
|
||||
</div>
|
@ -1,67 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2018, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
define(function () {
|
||||
function TableColumn(openmct, telemetryObject, metadatum) {
|
||||
this.openmct = openmct;
|
||||
this.telemetryObject = telemetryObject;
|
||||
this.metadatum = metadatum;
|
||||
this.formatter = openmct.telemetry.getValueFormatter(metadatum);
|
||||
|
||||
this.titleValue = this.metadatum.name;
|
||||
}
|
||||
|
||||
TableColumn.prototype.title = function (title) {
|
||||
if (arguments.length > 0) {
|
||||
this.titleValue = title;
|
||||
}
|
||||
return this.titleValue;
|
||||
};
|
||||
|
||||
TableColumn.prototype.isCurrentTimeSystem = function () {
|
||||
var isCurrentTimeSystem = this.metadatum.hints.hasOwnProperty('domain') &&
|
||||
this.metadatum.key === this.openmct.time.timeSystem().key;
|
||||
|
||||
return isCurrentTimeSystem;
|
||||
};
|
||||
|
||||
TableColumn.prototype.hasValue = function (telemetryObject, telemetryDatum) {
|
||||
var keyStringForDatum = this.openmct.objects.makeKeyString(telemetryObject.identifier);
|
||||
var keyStringForColumn = this.openmct.objects.makeKeyString(this.telemetryObject.identifier);
|
||||
return keyStringForDatum === keyStringForColumn && telemetryDatum.hasOwnProperty(this.metadatum.source);
|
||||
};
|
||||
|
||||
TableColumn.prototype.getValue = function (telemetryDatum, limitEvaluator) {
|
||||
var alarm = limitEvaluator &&
|
||||
limitEvaluator.evaluate(telemetryDatum, this.metadatum);
|
||||
var value = {
|
||||
text: this.formatter.format(telemetryDatum),
|
||||
value: this.formatter.parse(telemetryDatum)
|
||||
};
|
||||
|
||||
if (alarm) {
|
||||
value.cssClass = alarm.cssClass;
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
return TableColumn;
|
||||
});
|
@ -1,164 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2018, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
/* global Set */
|
||||
define(
|
||||
['./TableColumn'],
|
||||
function (TableColumn) {
|
||||
|
||||
/**
|
||||
* Class that manages table metadata, state, and contents.
|
||||
* @memberof platform/features/table
|
||||
* @param domainObject
|
||||
* @constructor
|
||||
*/
|
||||
function TableConfiguration(domainObject, openmct) {
|
||||
this.domainObject = domainObject;
|
||||
this.openmct = openmct;
|
||||
this.timeSystemColumn = undefined;
|
||||
this.columns = [];
|
||||
this.headers = new Set();
|
||||
this.timeSystemColumnTitle = undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build column definition based on supplied telemetry metadata
|
||||
* @param telemetryObject the telemetry producing object associated with this column
|
||||
* @param metadata Metadata describing the domains and ranges available
|
||||
* @returns {TableConfiguration} This object
|
||||
*/
|
||||
TableConfiguration.prototype.addColumn = function (telemetryObject, metadatum) {
|
||||
var column = new TableColumn(this.openmct, telemetryObject, metadatum);
|
||||
|
||||
if (column.isCurrentTimeSystem()) {
|
||||
if (!this.timeSystemColumnTitle) {
|
||||
this.timeSystemColumnTitle = column.title();
|
||||
}
|
||||
column.title(this.timeSystemColumnTitle);
|
||||
}
|
||||
|
||||
this.columns.push(column);
|
||||
this.headers.add(column.title());
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve and format values for a given telemetry datum.
|
||||
* @param telemetryObject The object that the telemetry data is
|
||||
* associated with
|
||||
* @param datum The telemetry datum to retrieve values from
|
||||
* @returns {Object} Key value pairs where the key is the column
|
||||
* title, and the value is the formatted value from the provided datum.
|
||||
*/
|
||||
TableConfiguration.prototype.getRowValues = function (telemetryObject, limitEvaluator, datum) {
|
||||
return this.columns.reduce(function (rowObject, column) {
|
||||
var columnTitle = column.title();
|
||||
var columnValue = {
|
||||
text: '',
|
||||
value: undefined
|
||||
};
|
||||
if (rowObject[columnTitle] === undefined) {
|
||||
rowObject[columnTitle] = columnValue;
|
||||
}
|
||||
|
||||
if (column.hasValue(telemetryObject, datum)) {
|
||||
columnValue = column.getValue(datum, limitEvaluator);
|
||||
|
||||
if (columnValue.text === undefined) {
|
||||
columnValue.text = '';
|
||||
}
|
||||
// Don't replace something with nothing.
|
||||
// This occurs when there are multiple columns with the same
|
||||
// column title
|
||||
if (rowObject[columnTitle].text === undefined ||
|
||||
rowObject[columnTitle].text.length === 0) {
|
||||
rowObject[columnTitle] = columnValue;
|
||||
}
|
||||
}
|
||||
|
||||
return rowObject;
|
||||
}, {});
|
||||
};
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
TableConfiguration.prototype.defaultColumnConfiguration = function () {
|
||||
return ((this.domainObject.getModel().configuration || {}).table || {}).columns || {};
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the established configuration on the domain object
|
||||
* @private
|
||||
*/
|
||||
TableConfiguration.prototype.saveColumnConfiguration = function (columnConfig) {
|
||||
this.domainObject.useCapability('mutation', function (model) {
|
||||
model.configuration = model.configuration || {};
|
||||
model.configuration.table = model.configuration.table || {};
|
||||
model.configuration.table.columns = columnConfig;
|
||||
});
|
||||
};
|
||||
|
||||
function configChanged(config1, config2) {
|
||||
var config1Keys = Object.keys(config1),
|
||||
config2Keys = Object.keys(config2);
|
||||
|
||||
return (config1Keys.length !== config2Keys.length) ||
|
||||
config1Keys.some(function (key) {
|
||||
return config1[key] !== config2[key];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* As part of the process of building the table definition, extract
|
||||
* configuration from column definitions.
|
||||
* @returns {Object} A configuration object consisting of key-value
|
||||
* pairs where the key is the column title, and the value is a
|
||||
* boolean indicating whether the column should be shown.
|
||||
*/
|
||||
TableConfiguration.prototype.buildColumnConfiguration = function () {
|
||||
var configuration = {},
|
||||
//Use existing persisted config, or default it
|
||||
defaultConfig = this.defaultColumnConfiguration();
|
||||
|
||||
/**
|
||||
* For each column header, define a configuration value
|
||||
* specifying whether the column is visible or not. Default to
|
||||
* existing (persisted) configuration if available
|
||||
*/
|
||||
this.headers.forEach(function (columnTitle) {
|
||||
configuration[columnTitle] =
|
||||
typeof defaultConfig[columnTitle] === 'undefined' ? true :
|
||||
defaultConfig[columnTitle];
|
||||
});
|
||||
|
||||
//Synchronize column configuration with model
|
||||
if (this.domainObject.hasCapability('editor') &&
|
||||
this.domainObject.getCapability('editor').isEditContextRoot() &&
|
||||
configChanged(configuration, defaultConfig)) {
|
||||
this.saveColumnConfiguration(configuration);
|
||||
}
|
||||
|
||||
return configuration;
|
||||
};
|
||||
|
||||
return TableConfiguration;
|
||||
}
|
||||
);
|
@ -1,249 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2018, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define(
|
||||
[
|
||||
'lodash',
|
||||
'EventEmitter'
|
||||
],
|
||||
function (_, EventEmitter) {
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
function TelemetryCollection() {
|
||||
EventEmitter.call(this, arguments);
|
||||
this.dupeCheck = false;
|
||||
this.telemetry = [];
|
||||
this.highBuffer = [];
|
||||
this.sortField = undefined;
|
||||
this.lastBounds = {};
|
||||
|
||||
_.bindAll(this, [
|
||||
'addOne',
|
||||
'iteratee'
|
||||
]);
|
||||
}
|
||||
|
||||
TelemetryCollection.prototype = Object.create(EventEmitter.prototype);
|
||||
|
||||
TelemetryCollection.prototype.iteratee = function (item) {
|
||||
return _.get(item, this.sortField);
|
||||
};
|
||||
|
||||
/**
|
||||
* This function is optimized for ticking - it assumes that start and end
|
||||
* bounds will only increase and as such this cannot be used for decreasing
|
||||
* bounds changes.
|
||||
*
|
||||
* An implication of this is that data will not be discarded that exceeds
|
||||
* the given end bounds. For arbitrary bounds changes, it's assumed that
|
||||
* a telemetry requery is performed anyway, and the collection is cleared
|
||||
* and repopulated.
|
||||
*
|
||||
* @fires TelemetryCollection#added
|
||||
* @fires TelemetryCollection#discarded
|
||||
* @param bounds
|
||||
*/
|
||||
TelemetryCollection.prototype.bounds = function (bounds) {
|
||||
var startChanged = this.lastBounds.start !== bounds.start;
|
||||
var endChanged = this.lastBounds.end !== bounds.end;
|
||||
var startIndex = 0;
|
||||
var endIndex = 0;
|
||||
var discarded;
|
||||
var added;
|
||||
var testValue;
|
||||
|
||||
this.lastBounds = bounds;
|
||||
|
||||
// If collection is not sorted by a time field, we cannot respond to
|
||||
// bounds events
|
||||
if (this.sortField === undefined) {
|
||||
this.lastBounds = bounds;
|
||||
return;
|
||||
}
|
||||
|
||||
if (startChanged) {
|
||||
testValue = _.set({}, this.sortField, bounds.start);
|
||||
// Calculate the new index of the first item within the bounds
|
||||
startIndex = _.sortedIndex(this.telemetry, testValue, this.sortField);
|
||||
discarded = this.telemetry.splice(0, startIndex);
|
||||
}
|
||||
if (endChanged) {
|
||||
testValue = _.set({}, this.sortField, bounds.end);
|
||||
// Calculate the new index of the last item in bounds
|
||||
endIndex = _.sortedLastIndex(this.highBuffer, testValue, this.sortField);
|
||||
added = this.highBuffer.splice(0, endIndex);
|
||||
added.forEach(function (datum) {
|
||||
this.telemetry.push(datum);
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
if (discarded && discarded.length > 0) {
|
||||
/**
|
||||
* A `discarded` event is emitted when telemetry data fall out of
|
||||
* bounds due to a bounds change event
|
||||
* @type {object[]} discarded the telemetry data
|
||||
* discarded as a result of the bounds change
|
||||
*/
|
||||
this.emit('discarded', discarded);
|
||||
}
|
||||
if (added && added.length > 0) {
|
||||
/**
|
||||
* An `added` event is emitted when a bounds change results in
|
||||
* received telemetry falling within the new bounds.
|
||||
* @type {object[]} added the telemetry data that is now within bounds
|
||||
*/
|
||||
this.emit('added', added);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds an individual item to the collection. Used internally only
|
||||
* @private
|
||||
* @param item
|
||||
*/
|
||||
TelemetryCollection.prototype.addOne = function (item) {
|
||||
var isDuplicate = false;
|
||||
var boundsDefined = this.lastBounds &&
|
||||
(this.lastBounds.start !== undefined && this.lastBounds.end !== undefined);
|
||||
var array;
|
||||
var boundsLow;
|
||||
var boundsHigh;
|
||||
|
||||
// If collection is not sorted by a time field, we cannot respond to
|
||||
// bounds events, so no bounds checking necessary
|
||||
if (this.sortField === undefined) {
|
||||
this.telemetry.push(item);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Insert into either in-bounds array, or the out of bounds high buffer.
|
||||
// Data in the high buffer will be re-evaluated for possible insertion on next tick
|
||||
|
||||
if (boundsDefined) {
|
||||
boundsHigh = _.get(item, this.sortField) > this.lastBounds.end;
|
||||
boundsLow = _.get(item, this.sortField) < this.lastBounds.start;
|
||||
|
||||
if (!boundsHigh && !boundsLow) {
|
||||
array = this.telemetry;
|
||||
} else if (boundsHigh) {
|
||||
array = this.highBuffer;
|
||||
}
|
||||
} else {
|
||||
array = this.telemetry;
|
||||
}
|
||||
|
||||
// If out of bounds low, disregard data
|
||||
if (!boundsLow) {
|
||||
// Going to check for duplicates. Bound the search problem to
|
||||
// items around the given time. Use sortedIndex because it
|
||||
// employs a binary search which is O(log n). Can use binary search
|
||||
// based on time stamp because the array is guaranteed ordered due
|
||||
// to sorted insertion.
|
||||
var startIx = _.sortedIndex(array, item, this.sortField);
|
||||
var endIx;
|
||||
|
||||
if (this.dupeCheck && startIx !== array.length) {
|
||||
endIx = _.sortedLastIndex(array, item, this.sortField);
|
||||
|
||||
// Create an array of potential dupes, based on having the
|
||||
// same time stamp
|
||||
var potentialDupes = array.slice(startIx, endIx + 1);
|
||||
// Search potential dupes for exact dupe
|
||||
isDuplicate = _.findIndex(potentialDupes, _.isEqual.bind(undefined, item)) > -1;
|
||||
}
|
||||
|
||||
if (!isDuplicate) {
|
||||
array.splice(endIx || startIx, 0, item);
|
||||
|
||||
//Return true if it was added and in bounds
|
||||
return array === this.telemetry;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add an array of objects to this telemetry collection
|
||||
* @fires TelemetryCollection#added
|
||||
* @param {object[]} items
|
||||
*/
|
||||
TelemetryCollection.prototype.add = function (items) {
|
||||
var added = items.filter(this.addOne);
|
||||
this.emit('added', added);
|
||||
this.dupeCheck = true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Clears the contents of the telemetry collection
|
||||
*/
|
||||
TelemetryCollection.prototype.clear = function () {
|
||||
this.telemetry = [];
|
||||
this.highBuffer = [];
|
||||
};
|
||||
|
||||
/**
|
||||
* Sorts the telemetry collection based on the provided sort field
|
||||
* specifier. Subsequent inserts are sorted to maintain specified sport
|
||||
* order.
|
||||
*
|
||||
* @example
|
||||
* // First build some mock telemetry for the purpose of an example
|
||||
* let now = Date.now();
|
||||
* let telemetry = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map(function (value) {
|
||||
* return {
|
||||
* // define an object property to demonstrate nested paths
|
||||
* timestamp: {
|
||||
* ms: now - value * 1000,
|
||||
* text:
|
||||
* },
|
||||
* value: value
|
||||
* }
|
||||
* });
|
||||
* let collection = new TelemetryCollection();
|
||||
*
|
||||
* collection.add(telemetry);
|
||||
*
|
||||
* // Sort by telemetry value
|
||||
* collection.sort("value");
|
||||
*
|
||||
* // Sort by ms since epoch
|
||||
* collection.sort("timestamp.ms");
|
||||
*
|
||||
* // Sort by formatted date text
|
||||
* collection.sort("timestamp.text");
|
||||
*
|
||||
*
|
||||
* @param {string} sortField An object property path.
|
||||
*/
|
||||
TelemetryCollection.prototype.sort = function (sortField) {
|
||||
this.sortField = sortField;
|
||||
if (sortField !== undefined) {
|
||||
this.telemetry = _.sortBy(this.telemetry, this.iteratee);
|
||||
}
|
||||
};
|
||||
|
||||
return TelemetryCollection;
|
||||
}
|
||||
);
|
@ -1,828 +0,0 @@
|
||||
|
||||
define(
|
||||
[
|
||||
'zepto',
|
||||
'lodash'
|
||||
],
|
||||
function ($, _) {
|
||||
|
||||
/**
|
||||
* A controller for the MCTTable directive. Populates scope with
|
||||
* data used for populating, sorting, and filtering
|
||||
* tables.
|
||||
* @param $scope
|
||||
* @param $timeout
|
||||
* @param element
|
||||
* @constructor
|
||||
*/
|
||||
function MCTTableController($scope, $window, element, exportService, formatService, openmct) {
|
||||
var self = this;
|
||||
|
||||
this.$scope = $scope;
|
||||
this.element = $(element[0]);
|
||||
this.$window = $window;
|
||||
this.maxDisplayRows = 100;
|
||||
|
||||
this.scrollable = this.element.find('.t-scrolling').first();
|
||||
this.resultsHeader = this.element.find('.mct-table>thead').first();
|
||||
this.sizingTableBody = this.element.find('.t-sizing-table>tbody').first();
|
||||
this.$scope.sizingRow = {};
|
||||
this.$scope.calcTableWidthPx = '100%';
|
||||
this.timeApi = openmct.time;
|
||||
this.toiFormatter = undefined;
|
||||
this.formatService = formatService;
|
||||
this.callbacks = {};
|
||||
|
||||
//Bind all class functions to 'this'
|
||||
_.bindAll(this, [
|
||||
'addRows',
|
||||
'binarySearch',
|
||||
'buildLargestRow',
|
||||
'changeBounds',
|
||||
'changeTimeOfInterest',
|
||||
'changeTimeSystem',
|
||||
'destroyConductorListeners',
|
||||
'digest',
|
||||
'filterAndSort',
|
||||
'filterRows',
|
||||
'firstVisible',
|
||||
'insertSorted',
|
||||
'lastVisible',
|
||||
'onRowClick',
|
||||
'onScroll',
|
||||
'removeRows',
|
||||
'resize',
|
||||
'scrollToBottom',
|
||||
'scrollToRow',
|
||||
'setElementSizes',
|
||||
'setHeaders',
|
||||
'setRows',
|
||||
'setTimeOfInterestRow',
|
||||
'setVisibleRows',
|
||||
'sortComparator',
|
||||
'sortRows'
|
||||
]);
|
||||
|
||||
this.scrollable.on('scroll', this.onScroll);
|
||||
|
||||
$scope.visibleRows = [];
|
||||
$scope.displayRows = [];
|
||||
|
||||
/**
|
||||
* Set default values for optional parameters on a given scope
|
||||
*/
|
||||
function setDefaults(scope) {
|
||||
if (typeof scope.enableFilter === 'undefined') {
|
||||
scope.enableFilter = true;
|
||||
scope.filters = {};
|
||||
}
|
||||
if (typeof scope.enableSort === 'undefined') {
|
||||
scope.enableSort = true;
|
||||
scope.sortColumn = undefined;
|
||||
scope.sortDirection = undefined;
|
||||
}
|
||||
if (scope.sortColumn !== undefined) {
|
||||
scope.sortDirection = "asc";
|
||||
}
|
||||
}
|
||||
|
||||
setDefaults($scope);
|
||||
|
||||
$scope.exportAsCSV = function () {
|
||||
var headers = $scope.displayHeaders,
|
||||
filename = $(element[0]).attr('export-as');
|
||||
|
||||
exportService.exportCSV($scope.displayRows.map(function (row) {
|
||||
return headers.reduce(function (r, header) {
|
||||
r[header] = row[header].text;
|
||||
return r;
|
||||
}, {});
|
||||
}), {
|
||||
headers: headers,
|
||||
filename: filename
|
||||
});
|
||||
};
|
||||
|
||||
$scope.toggleSort = function (key) {
|
||||
if (!$scope.enableSort) {
|
||||
return;
|
||||
}
|
||||
if ($scope.sortColumn !== key) {
|
||||
$scope.sortColumn = key;
|
||||
$scope.sortDirection = 'asc';
|
||||
} else if ($scope.sortDirection === 'asc') {
|
||||
$scope.sortDirection = 'desc';
|
||||
} else if ($scope.sortDirection === 'desc') {
|
||||
$scope.sortColumn = undefined;
|
||||
$scope.sortDirection = undefined;
|
||||
} else if ($scope.sortColumn !== undefined &&
|
||||
$scope.sortDirection === undefined) {
|
||||
$scope.sortDirection = 'asc';
|
||||
}
|
||||
self.setRows($scope.rows);
|
||||
self.setTimeOfInterestRow(self.timeApi.timeOfInterest());
|
||||
};
|
||||
|
||||
/*
|
||||
* Define watches to listen for changes to headers and rows.
|
||||
*/
|
||||
$scope.$watchCollection('filters', function () {
|
||||
self.setRows($scope.rows);
|
||||
});
|
||||
$scope.$watch('headers', function (newHeaders, oldHeaders) {
|
||||
if (newHeaders !== oldHeaders) {
|
||||
this.setHeaders(newHeaders);
|
||||
}
|
||||
}.bind(this));
|
||||
$scope.$watch('rows', this.setRows);
|
||||
|
||||
/*
|
||||
* Listen for rows added individually (eg. for real-time tables)
|
||||
*/
|
||||
$scope.$on('add:rows', this.addRows);
|
||||
$scope.$on('remove:rows', this.removeRows);
|
||||
|
||||
/**
|
||||
* Populated from the default-sort attribute on MctTable
|
||||
* directive tag.
|
||||
*/
|
||||
$scope.$watch('defaultSort', function (newColumn, oldColumn) {
|
||||
if (newColumn !== oldColumn) {
|
||||
$scope.toggleSort(newColumn);
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
* Listen for resize events to trigger recalculation of table width
|
||||
*/
|
||||
$scope.resize = this.setElementSizes;
|
||||
|
||||
/**
|
||||
* Scope variable that is populated from the 'time-columns'
|
||||
* attribute on the MctTable tag. Indicates which columns, while
|
||||
* sorted, can be used for indicated time of interest.
|
||||
*/
|
||||
$scope.$watch("timeColumns", function (timeColumns) {
|
||||
if (timeColumns) {
|
||||
this.destroyConductorListeners();
|
||||
|
||||
this.timeApi.on('timeSystem', this.changeTimeSystem);
|
||||
this.timeApi.on('timeOfInterest', this.changeTimeOfInterest);
|
||||
this.timeApi.on('bounds', this.changeBounds);
|
||||
|
||||
// If time system defined, set initially
|
||||
if (this.timeApi.timeSystem() !== undefined) {
|
||||
this.changeTimeSystem(this.timeApi.timeSystem());
|
||||
}
|
||||
}
|
||||
}.bind(this));
|
||||
|
||||
$scope.$on('$destroy', function () {
|
||||
this.scrollable.off('scroll', this.onScroll);
|
||||
this.destroyConductorListeners();
|
||||
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
MCTTableController.prototype.destroyConductorListeners = function () {
|
||||
this.timeApi.off('timeSystem', this.changeTimeSystem);
|
||||
this.timeApi.off('timeOfInterest', this.changeTimeOfInterest);
|
||||
this.timeApi.off('bounds', this.changeBounds);
|
||||
};
|
||||
|
||||
MCTTableController.prototype.changeTimeSystem = function (timeSystem) {
|
||||
var format = timeSystem.timeFormat;
|
||||
this.toiFormatter = this.formatService.getFormat(format);
|
||||
};
|
||||
|
||||
/**
|
||||
* If auto-scroll is enabled, this function will scroll to the
|
||||
* bottom of the page
|
||||
* @private
|
||||
*/
|
||||
MCTTableController.prototype.scrollToBottom = function () {
|
||||
this.scrollable[0].scrollTop = this.scrollable[0].scrollHeight;
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles a row add event. Rows can be added as needed using the
|
||||
* `add:row` broadcast event.
|
||||
* @private
|
||||
*/
|
||||
MCTTableController.prototype.addRows = function (event, rows) {
|
||||
//Does the row pass the current filter?
|
||||
if (this.filterRows(rows).length > 0) {
|
||||
rows.forEach(this.insertSorted.bind(this, this.$scope.displayRows));
|
||||
|
||||
//Resize the columns , then update the rows visible in the table
|
||||
this.resize([this.$scope.sizingRow].concat(rows))
|
||||
.then(this.setVisibleRows)
|
||||
.then(function () {
|
||||
if (this.$scope.autoScroll) {
|
||||
this.scrollToBottom();
|
||||
}
|
||||
}.bind(this));
|
||||
|
||||
var toi = this.timeApi.timeOfInterest();
|
||||
if (toi !== -1) {
|
||||
this.setTimeOfInterestRow(toi);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles a row remove event. Rows can be removed as needed using the
|
||||
* `remove:row` broadcast event.
|
||||
* @private
|
||||
*/
|
||||
MCTTableController.prototype.removeRows = function (event, rows) {
|
||||
var indexInDisplayRows;
|
||||
rows.forEach(function (row) {
|
||||
// Do a sequential search here. Only way of finding row is by
|
||||
// object equality, so array is in effect unsorted.
|
||||
indexInDisplayRows = this.$scope.displayRows.indexOf(row);
|
||||
if (indexInDisplayRows !== -1) {
|
||||
this.$scope.displayRows.splice(indexInDisplayRows, 1);
|
||||
}
|
||||
}, this);
|
||||
|
||||
this.$scope.sizingRow = this.buildLargestRow([this.$scope.sizingRow].concat(rows));
|
||||
|
||||
this.setElementSizes();
|
||||
this.setVisibleRows()
|
||||
.then(function () {
|
||||
if (this.$scope.autoScroll) {
|
||||
this.scrollToBottom();
|
||||
}
|
||||
}.bind(this));
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
MCTTableController.prototype.onScroll = function (event) {
|
||||
this.scrollWindow = {
|
||||
top: this.scrollable[0].scrollTop,
|
||||
bottom: this.scrollable[0].scrollTop + this.scrollable[0].offsetHeight,
|
||||
offsetHeight: this.scrollable[0].offsetHeight,
|
||||
height: this.scrollable[0].scrollHeight
|
||||
};
|
||||
this.$window.requestAnimationFrame(function () {
|
||||
this.setVisibleRows();
|
||||
this.digest();
|
||||
|
||||
// If user scrolls away from bottom, disable auto-scroll.
|
||||
// Auto-scroll will be re-enabled if user scrolls to bottom again.
|
||||
if (this.scrollWindow.top <
|
||||
(this.scrollWindow.height - this.scrollWindow.offsetHeight) - 20) {
|
||||
this.$scope.autoScroll = false;
|
||||
} else {
|
||||
this.$scope.autoScroll = true;
|
||||
}
|
||||
this.scrolling = false;
|
||||
delete this.scrollWindow;
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
/**
|
||||
* Return first visible row, based on current scroll state.
|
||||
* @private
|
||||
*/
|
||||
MCTTableController.prototype.firstVisible = function () {
|
||||
var topScroll = this.scrollWindow ?
|
||||
this.scrollWindow.top :
|
||||
this.scrollable[0].scrollTop;
|
||||
|
||||
return Math.floor(
|
||||
(topScroll) / this.$scope.rowHeight
|
||||
);
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Return last visible row, based on current scroll state.
|
||||
* @private
|
||||
*/
|
||||
MCTTableController.prototype.lastVisible = function () {
|
||||
var bottomScroll = this.scrollWindow ?
|
||||
this.scrollWindow.bottom :
|
||||
this.scrollable[0].scrollTop + this.scrollable[0].offsetHeight;
|
||||
|
||||
return Math.ceil(
|
||||
(bottomScroll) /
|
||||
this.$scope.rowHeight
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets visible rows based on array
|
||||
* content and current scroll state.
|
||||
*/
|
||||
MCTTableController.prototype.setVisibleRows = function () {
|
||||
var self = this,
|
||||
totalVisible,
|
||||
numberOffscreen,
|
||||
firstVisible,
|
||||
lastVisible,
|
||||
start,
|
||||
end;
|
||||
|
||||
//No need to scroll
|
||||
if (this.$scope.displayRows.length < this.maxDisplayRows) {
|
||||
start = 0;
|
||||
end = this.$scope.displayRows.length;
|
||||
} else {
|
||||
firstVisible = this.firstVisible();
|
||||
lastVisible = this.lastVisible();
|
||||
totalVisible = lastVisible - firstVisible;
|
||||
numberOffscreen = this.maxDisplayRows - totalVisible;
|
||||
start = firstVisible - Math.floor(numberOffscreen / 2);
|
||||
end = lastVisible + Math.ceil(numberOffscreen / 2);
|
||||
|
||||
if (start < 0) {
|
||||
start = 0;
|
||||
end = Math.min(this.maxDisplayRows,
|
||||
this.$scope.displayRows.length);
|
||||
} else if (end >= this.$scope.displayRows.length) {
|
||||
end = this.$scope.displayRows.length;
|
||||
start = end - this.maxDisplayRows + 1;
|
||||
}
|
||||
if (this.$scope.visibleRows[0] &&
|
||||
this.$scope.visibleRows[0].rowIndex === start &&
|
||||
this.$scope.visibleRows[this.$scope.visibleRows.length - 1]
|
||||
.rowIndex === end) {
|
||||
return this.digest();
|
||||
}
|
||||
}
|
||||
//Set visible rows from display rows, based on calculated offset.
|
||||
this.$scope.visibleRows = this.$scope.displayRows.slice(start, end)
|
||||
.map(function (row, i) {
|
||||
return {
|
||||
rowIndex: start + i,
|
||||
offsetY: ((start + i) * self.$scope.rowHeight),
|
||||
contents: row
|
||||
};
|
||||
});
|
||||
return this.digest();
|
||||
};
|
||||
|
||||
/**
|
||||
* Update table headers with new headers. If filtering is
|
||||
* enabled, reset filters. If sorting is enabled, reset
|
||||
* sorting.
|
||||
*/
|
||||
MCTTableController.prototype.setHeaders = function (newHeaders) {
|
||||
if (!newHeaders) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.$scope.displayHeaders = newHeaders;
|
||||
if (this.$scope.enableFilter) {
|
||||
this.$scope.filters = {};
|
||||
}
|
||||
// Reset column sort information unless the new headers
|
||||
// contain the column currently sorted on.
|
||||
if (this.$scope.enableSort &&
|
||||
newHeaders.indexOf(this.$scope.sortColumn) === -1) {
|
||||
this.$scope.sortColumn = undefined;
|
||||
this.$scope.sortDirection = undefined;
|
||||
}
|
||||
this.setRows(this.$scope.rows);
|
||||
};
|
||||
|
||||
/**
|
||||
* Read styles from the DOM and use them to calculate offsets
|
||||
* for individual rows.
|
||||
*/
|
||||
MCTTableController.prototype.setElementSizes = function () {
|
||||
var tbody = this.sizingTableBody,
|
||||
firstRow = tbody.find('tr'),
|
||||
column = firstRow.find('td'),
|
||||
rowHeight = firstRow.prop('offsetHeight'),
|
||||
columnWidth,
|
||||
tableWidth = 0,
|
||||
overallHeight = (rowHeight *
|
||||
(this.$scope.displayRows ? this.$scope.displayRows.length - 1 : 0));
|
||||
|
||||
this.$scope.columnWidths = [];
|
||||
|
||||
while (column.length) {
|
||||
columnWidth = column.prop('offsetWidth');
|
||||
this.$scope.columnWidths.push(column.prop('offsetWidth'));
|
||||
tableWidth += columnWidth;
|
||||
column = column.next();
|
||||
}
|
||||
this.$scope.rowHeight = rowHeight;
|
||||
this.$scope.totalHeight = overallHeight;
|
||||
|
||||
var scrollW = this.scrollable[0].offsetWidth - this.scrollable[0].clientWidth;
|
||||
if (scrollW && scrollW > 0) {
|
||||
this.$scope.calcTableWidthPx = 'calc(100% - ' + scrollW + 'px)';
|
||||
}
|
||||
|
||||
if (tableWidth > 0) {
|
||||
this.$scope.totalWidth = tableWidth + 'px';
|
||||
} else {
|
||||
this.$scope.totalWidth = 'none';
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Finds the correct insertion point for a new row, which takes into
|
||||
* account duplicates to make sure new rows are inserted in a way that
|
||||
* maintains arrival order.
|
||||
*
|
||||
* @private
|
||||
* @param {Array} searchArray
|
||||
* @param {Object} searchElement Object to find the insertion point for
|
||||
*/
|
||||
MCTTableController.prototype.findInsertionPoint = function (searchArray, searchElement) {
|
||||
var index;
|
||||
var testIndex;
|
||||
var first = searchArray[0];
|
||||
var last = searchArray[searchArray.length - 1];
|
||||
|
||||
if (first) {
|
||||
first = first[this.$scope.sortColumn].text;
|
||||
}
|
||||
if (last) {
|
||||
last = last[this.$scope.sortColumn].text;
|
||||
}
|
||||
// Shortcut check for append/prepend
|
||||
if (first && this.sortComparator(first, searchElement) >= 0) {
|
||||
index = testIndex = 0;
|
||||
} else if (last && this.sortComparator(last, searchElement) <= 0) {
|
||||
index = testIndex = searchArray.length;
|
||||
} else {
|
||||
// use a binary search to find the correct insertion point
|
||||
index = testIndex = this.binarySearch(
|
||||
searchArray,
|
||||
searchElement,
|
||||
0,
|
||||
searchArray.length - 1
|
||||
);
|
||||
}
|
||||
|
||||
//It's possible that the insertion point is a duplicate of the element to be inserted
|
||||
var isDupe = function () {
|
||||
return this.sortComparator(searchElement,
|
||||
searchArray[testIndex][this.$scope.sortColumn].text) === 0;
|
||||
}.bind(this);
|
||||
|
||||
// In the event of a duplicate, scan left or right (depending on
|
||||
// sort order) to find an insertion point that maintains order received
|
||||
while (testIndex >= 0 && testIndex < searchArray.length && isDupe()) {
|
||||
if (this.$scope.sortDirection === 'asc') {
|
||||
index = ++testIndex;
|
||||
} else {
|
||||
index = testIndex--;
|
||||
}
|
||||
}
|
||||
return index;
|
||||
};
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
MCTTableController.prototype.binarySearch = function (searchArray, searchElement, min, max) {
|
||||
var sampleAt = Math.floor((max - min) / 2) + min;
|
||||
|
||||
if (max < min) {
|
||||
return min; // Element is not in array, min gives direction
|
||||
}
|
||||
switch (this.sortComparator(searchElement,
|
||||
searchArray[sampleAt][this.$scope.sortColumn].text)) {
|
||||
case -1:
|
||||
return this.binarySearch(searchArray, searchElement, min,
|
||||
sampleAt - 1);
|
||||
case 0:
|
||||
return sampleAt;
|
||||
case 1:
|
||||
return this.binarySearch(searchArray, searchElement,
|
||||
sampleAt + 1, max);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
MCTTableController.prototype.insertSorted = function (array, element) {
|
||||
var index = -1;
|
||||
|
||||
if (!this.$scope.sortColumn || !this.$scope.sortDirection) {
|
||||
//No sorting applied, push it on the end.
|
||||
index = array.length;
|
||||
} else {
|
||||
//Sort is enabled, perform binary search to find insertion point
|
||||
index = this.findInsertionPoint(array, element[this.$scope.sortColumn].text);
|
||||
}
|
||||
if (index === -1) {
|
||||
array.unshift(element);
|
||||
} else if (index === array.length) {
|
||||
array.push(element);
|
||||
} else {
|
||||
array.splice(index, 0, element);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Compare two variables, returning a number that represents
|
||||
* which is larger. Similar to the default array sort
|
||||
* comparator, but does not coerce all values to string before
|
||||
* conversion. Strings are lowercased before comparison.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
MCTTableController.prototype.sortComparator = function (a, b) {
|
||||
var result = 0,
|
||||
sortDirectionMultiplier,
|
||||
numberA,
|
||||
numberB;
|
||||
/**
|
||||
* Given a value, if it is a number, or a string representation of a
|
||||
* number, then return a number representation. Otherwise, return
|
||||
* the original value. It's a little more robust than using just
|
||||
* Number() or parseFloat, or isNaN in isolation, all of which are
|
||||
* fairly inconsistent in their results.
|
||||
* @param value The value to return as a number.
|
||||
* @returns {*} The value cast to a Number, or the original value if
|
||||
* a Number representation is not possible.
|
||||
*/
|
||||
function toNumber(value) {
|
||||
var val = !isNaN(Number(value)) && !isNaN(parseFloat(value)) ? Number(value) : value;
|
||||
return val;
|
||||
}
|
||||
|
||||
numberA = toNumber(a);
|
||||
numberB = toNumber(b);
|
||||
|
||||
//If they're both numbers, then compare them as numbers
|
||||
if (typeof numberA === "number" && typeof numberB === "number") {
|
||||
a = numberA;
|
||||
b = numberB;
|
||||
}
|
||||
|
||||
//If they're both strings, then ignore case
|
||||
if (typeof a === "string" && typeof b === "string") {
|
||||
a = a.toLowerCase();
|
||||
b = b.toLowerCase();
|
||||
}
|
||||
|
||||
if (a < b) {
|
||||
result = -1;
|
||||
}
|
||||
if (a > b) {
|
||||
result = 1;
|
||||
}
|
||||
|
||||
if (this.$scope.sortDirection === 'asc') {
|
||||
sortDirectionMultiplier = 1;
|
||||
} else if (this.$scope.sortDirection === 'desc') {
|
||||
sortDirectionMultiplier = -1;
|
||||
}
|
||||
|
||||
return result * sortDirectionMultiplier;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a new array which is a result of applying the sort
|
||||
* criteria defined in $scope.
|
||||
*
|
||||
* Does not modify the array that was passed in.
|
||||
*/
|
||||
MCTTableController.prototype.sortRows = function (rowsToSort) {
|
||||
var self = this,
|
||||
sortKey = this.$scope.sortColumn;
|
||||
|
||||
if (!this.$scope.sortColumn || !this.$scope.sortDirection) {
|
||||
return rowsToSort;
|
||||
}
|
||||
|
||||
return rowsToSort.sort(function (a, b) {
|
||||
return self.sortComparator(a[sortKey].text, b[sortKey].text);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns an object which contains the largest values
|
||||
* for each key in the given set of rows. This is used to
|
||||
* pre-calculate optimal column sizes without having to render
|
||||
* every row.
|
||||
*/
|
||||
MCTTableController.prototype.buildLargestRow = function (rows) {
|
||||
var largestRow = rows.reduce(function (prevLargest, row) {
|
||||
Object.keys(row).forEach(function (key) {
|
||||
var currentColumn,
|
||||
currentColumnLength,
|
||||
largestColumn,
|
||||
largestColumnLength;
|
||||
if (row[key]) {
|
||||
currentColumn = (row[key]).text;
|
||||
currentColumnLength =
|
||||
(currentColumn && currentColumn.length) ?
|
||||
currentColumn.length :
|
||||
currentColumn;
|
||||
largestColumn = prevLargest[key] ? prevLargest[key].text : "";
|
||||
largestColumnLength = largestColumn.length;
|
||||
|
||||
if (currentColumnLength > largestColumnLength) {
|
||||
prevLargest[key] = JSON.parse(JSON.stringify(row[key]));
|
||||
}
|
||||
}
|
||||
});
|
||||
return prevLargest;
|
||||
}, JSON.parse(JSON.stringify(rows[0] || {})));
|
||||
return largestRow;
|
||||
};
|
||||
|
||||
// Will effectively cap digests at 60Hz
|
||||
// Also turns digest into a promise allowing code to force digest, then
|
||||
// schedule something to happen afterwards
|
||||
MCTTableController.prototype.digest = function () {
|
||||
var scope = this.$scope;
|
||||
var self = this;
|
||||
var raf = this.$window.requestAnimationFrame;
|
||||
var promise = this.digestPromise;
|
||||
|
||||
if (!promise) {
|
||||
self.digestPromise = promise = new Promise(function (resolve) {
|
||||
raf(function () {
|
||||
scope.$digest();
|
||||
self.digestPromise = undefined;
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return promise;
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculates the widest row in the table, and if necessary, resizes
|
||||
* the table accordingly
|
||||
*
|
||||
* @param rows the rows on which to resize
|
||||
* @returns {Promise} a promise that will resolve when resizing has
|
||||
* occurred.
|
||||
* @private
|
||||
*/
|
||||
MCTTableController.prototype.resize = function (rows) {
|
||||
this.$scope.sizingRow = this.buildLargestRow(rows);
|
||||
return this.digest().then(this.setElementSizes);
|
||||
};
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
MCTTableController.prototype.filterAndSort = function (rows) {
|
||||
var displayRows = rows;
|
||||
if (this.$scope.enableFilter) {
|
||||
displayRows = this.filterRows(displayRows);
|
||||
}
|
||||
|
||||
if (this.$scope.enableSort) {
|
||||
displayRows = this.sortRows(displayRows.slice(0));
|
||||
}
|
||||
return displayRows;
|
||||
};
|
||||
|
||||
/**
|
||||
* Update rows with new data. If filtering is enabled, rows
|
||||
* will be sorted before display.
|
||||
*/
|
||||
MCTTableController.prototype.setRows = function (newRows) {
|
||||
//Nothing to show because no columns visible
|
||||
if (!this.$scope.displayHeaders || !newRows) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.$scope.displayRows = this.filterAndSort(newRows || []);
|
||||
return this.resize(newRows)
|
||||
.then(function (rows) {
|
||||
return this.setVisibleRows(rows);
|
||||
}.bind(this))
|
||||
//Timeout following setVisibleRows to allow digest to
|
||||
// perform DOM changes, otherwise scrollTo won't work.
|
||||
.then(function () {
|
||||
//If TOI specified, scroll to it
|
||||
var timeOfInterest = this.timeApi.timeOfInterest();
|
||||
if (timeOfInterest) {
|
||||
this.setTimeOfInterestRow(timeOfInterest);
|
||||
this.scrollToRow(this.$scope.toiRowIndex);
|
||||
}
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
/**
|
||||
* Applies user defined filters to rows. These filters are based on
|
||||
* the text entered in the search areas in each column.
|
||||
* @param rowsToFilter {Object[]} The rows to apply filters to
|
||||
* @returns {Object[]} A filtered copy of the supplied rows
|
||||
*/
|
||||
MCTTableController.prototype.filterRows = function (rowsToFilter) {
|
||||
var filters = {},
|
||||
self = this;
|
||||
|
||||
/**
|
||||
* Returns true if row matches all filters.
|
||||
*/
|
||||
function matchRow(filterMap, row) {
|
||||
return Object.keys(filterMap).every(function (key) {
|
||||
if (!row[key]) {
|
||||
return false;
|
||||
}
|
||||
var testVal = String(row[key].text).toLowerCase();
|
||||
return testVal.indexOf(filterMap[key]) !== -1;
|
||||
});
|
||||
}
|
||||
|
||||
if (!Object.keys(this.$scope.filters).length) {
|
||||
return rowsToFilter;
|
||||
}
|
||||
|
||||
Object.keys(this.$scope.filters).forEach(function (key) {
|
||||
if (!self.$scope.filters[key]) {
|
||||
return;
|
||||
}
|
||||
filters[key] = self.$scope.filters[key].toLowerCase();
|
||||
});
|
||||
|
||||
return rowsToFilter.filter(matchRow.bind(null, filters));
|
||||
};
|
||||
|
||||
/**
|
||||
* Scroll the view to a given row index
|
||||
* @param displayRowIndex {number} The index in the displayed rows
|
||||
* to scroll to.
|
||||
*/
|
||||
MCTTableController.prototype.scrollToRow = function (displayRowIndex) {
|
||||
|
||||
var visible = displayRowIndex > this.firstVisible() && displayRowIndex < this.lastVisible();
|
||||
|
||||
if (!visible) {
|
||||
var scrollTop = displayRowIndex * this.$scope.rowHeight +
|
||||
(this.scrollable[0].offsetHeight / 2);
|
||||
this.scrollable[0].scrollTop = scrollTop;
|
||||
this.setVisibleRows();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Update rows with new data. If filtering is enabled, rows
|
||||
* will be sorted before display.
|
||||
*/
|
||||
MCTTableController.prototype.setTimeOfInterestRow = function (newTOI) {
|
||||
var isSortedByTime =
|
||||
this.$scope.timeColumns &&
|
||||
this.$scope.timeColumns.indexOf(this.$scope.sortColumn) !== -1;
|
||||
|
||||
this.$scope.toiRowIndex = -1;
|
||||
|
||||
if (newTOI && isSortedByTime) {
|
||||
var formattedTOI = this.toiFormatter.format(newTOI);
|
||||
var rowIndex = this.binarySearch(
|
||||
this.$scope.displayRows,
|
||||
formattedTOI,
|
||||
0,
|
||||
this.$scope.displayRows.length - 1);
|
||||
|
||||
if (rowIndex > 0 && rowIndex < this.$scope.displayRows.length) {
|
||||
this.$scope.toiRowIndex = rowIndex;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
MCTTableController.prototype.changeTimeOfInterest = function (newTOI) {
|
||||
this.setTimeOfInterestRow(newTOI);
|
||||
this.scrollToRow(this.$scope.toiRowIndex);
|
||||
};
|
||||
|
||||
/**
|
||||
* On zoom, pan, etc. reset TOI
|
||||
* @param bounds
|
||||
*/
|
||||
MCTTableController.prototype.changeBounds = function (bounds) {
|
||||
this.setTimeOfInterestRow(this.timeApi.timeOfInterest());
|
||||
if (this.$scope.toiRowIndex !== -1) {
|
||||
this.scrollToRow(this.$scope.toiRowIndex);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
MCTTableController.prototype.onRowClick = function (event, rowIndex) {
|
||||
if (this.$scope.timeColumns.indexOf(this.$scope.sortColumn) !== -1) {
|
||||
var selectedTime = this.$scope.displayRows[rowIndex][this.$scope.sortColumn].text;
|
||||
if (selectedTime &&
|
||||
this.toiFormatter.validate(selectedTime) &&
|
||||
event.altKey) {
|
||||
this.timeApi.timeOfInterest(this.toiFormatter.parse(selectedTime));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return MCTTableController;
|
||||
}
|
||||
);
|
@ -1,113 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2018, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
|
||||
/**
|
||||
* Notes on implementation of plot options
|
||||
*
|
||||
* Multiple y-axes will have to be handled with multiple forms as
|
||||
* they will need to be stored on distinct model object
|
||||
*
|
||||
* Likewise plot series options per-child will need to be separate
|
||||
* forms.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The LayoutController is responsible for supporting the
|
||||
* Layout view. It arranges frames according to saved configuration
|
||||
* and provides methods for updating these based on mouse
|
||||
* movement.
|
||||
* @memberof platform/features/plot
|
||||
* @constructor
|
||||
* @param {Scope} $scope the controller's Angular scope
|
||||
*/
|
||||
function TableOptionsController($scope) {
|
||||
|
||||
var self = this;
|
||||
|
||||
this.$scope = $scope;
|
||||
this.domainObject = $scope.domainObject;
|
||||
this.listeners = [];
|
||||
|
||||
$scope.columnsForm = {};
|
||||
|
||||
function unlisten() {
|
||||
self.listeners.forEach(function (listener) {
|
||||
listener();
|
||||
});
|
||||
}
|
||||
|
||||
$scope.$watch('domainObject', function (domainObject) {
|
||||
unlisten();
|
||||
self.populateForm(domainObject.getModel());
|
||||
|
||||
self.listeners.push(self.domainObject.getCapability('mutation').listen(function (model) {
|
||||
self.populateForm(model);
|
||||
}));
|
||||
});
|
||||
|
||||
/**
|
||||
* Maintain a configuration object on scope that stores column
|
||||
* configuration. On change, synchronize with object model.
|
||||
*/
|
||||
$scope.$watchCollection('configuration.table.columns', function (newColumns, oldColumns) {
|
||||
if (newColumns !== oldColumns) {
|
||||
self.domainObject.useCapability('mutation', function (model) {
|
||||
model.configuration.table.columns = newColumns;
|
||||
});
|
||||
self.domainObject.getCapability('persistence').persist();
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Destroy all mutation listeners
|
||||
*/
|
||||
$scope.$on('$destroy', unlisten);
|
||||
|
||||
}
|
||||
|
||||
TableOptionsController.prototype.populateForm = function (model) {
|
||||
var columnsDefinition = (((model.configuration || {}).table || {}).columns || {}),
|
||||
rows = [];
|
||||
this.$scope.columnsForm = {
|
||||
'name': 'Columns',
|
||||
'sections': [{
|
||||
'name': 'Columns',
|
||||
'rows': rows
|
||||
}]};
|
||||
|
||||
Object.keys(columnsDefinition).forEach(function (key) {
|
||||
rows.push({
|
||||
'name': key,
|
||||
'control': 'checkbox',
|
||||
'key': key
|
||||
});
|
||||
});
|
||||
this.$scope.configuration = JSON.parse(JSON.stringify(model.configuration || {}));
|
||||
};
|
||||
|
||||
return TableOptionsController;
|
||||
}
|
||||
);
|
@ -1,450 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2018, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
/* global console*/
|
||||
|
||||
/**
|
||||
* This bundle adds a table view for displaying telemetry data.
|
||||
* @namespace platform/features/table
|
||||
*/
|
||||
define(
|
||||
[
|
||||
'../TableConfiguration',
|
||||
'../../../../../src/api/objects/object-utils',
|
||||
'../TelemetryCollection',
|
||||
'lodash'
|
||||
|
||||
],
|
||||
function (TableConfiguration, objectUtils, TelemetryCollection, _) {
|
||||
|
||||
/**
|
||||
* The TableController is responsible for getting data onto the page
|
||||
* in the table widget. This includes handling composition,
|
||||
* configuration, and telemetry subscriptions.
|
||||
* @memberof platform/features/table
|
||||
* @param $scope
|
||||
* @constructor
|
||||
*/
|
||||
function TelemetryTableController(
|
||||
$scope,
|
||||
$timeout,
|
||||
openmct
|
||||
) {
|
||||
|
||||
this.$scope = $scope;
|
||||
this.$timeout = $timeout;
|
||||
this.openmct = openmct;
|
||||
this.batchSize = 1000;
|
||||
|
||||
/*
|
||||
* Initialization block
|
||||
*/
|
||||
this.columns = {}; //Range and Domain columns
|
||||
this.unobserveObject = undefined;
|
||||
this.subscriptions = [];
|
||||
this.timeColumns = [];
|
||||
$scope.rows = [];
|
||||
this.table = new TableConfiguration($scope.domainObject,
|
||||
openmct);
|
||||
this.lastBounds = this.openmct.time.bounds();
|
||||
this.lastRequestTime = 0;
|
||||
this.telemetry = new TelemetryCollection();
|
||||
if (this.lastBounds) {
|
||||
this.telemetry.bounds(this.lastBounds);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a new format object from legacy object, and replace it
|
||||
* when it changes
|
||||
*/
|
||||
this.domainObject = objectUtils.toNewFormat($scope.domainObject.getModel(),
|
||||
$scope.domainObject.getId());
|
||||
|
||||
this.$scope.exportAs = this.$scope.domainObject.getModel().name;
|
||||
|
||||
_.bindAll(this, [
|
||||
'destroy',
|
||||
'sortByTimeSystem',
|
||||
'loadColumns',
|
||||
'getHistoricalData',
|
||||
'subscribeToNewData',
|
||||
'changeBounds',
|
||||
'setClock',
|
||||
'addRowsToTable',
|
||||
'removeRowsFromTable'
|
||||
]);
|
||||
|
||||
// Retrieve data when domain object is available.
|
||||
// Also deferring telemetry request makes testing easier as controller
|
||||
// construction has no unintended consequences.
|
||||
$scope.$watch("domainObject", function () {
|
||||
this.getData();
|
||||
this.registerChangeListeners();
|
||||
}.bind(this));
|
||||
|
||||
this.setClock(this.openmct.time.clock());
|
||||
|
||||
this.$scope.$on("$destroy", this.destroy);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {boolean} scroll
|
||||
*/
|
||||
TelemetryTableController.prototype.setClock = function (clock) {
|
||||
this.$scope.autoScroll = clock !== undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
* Based on the selected time system, find a matching domain column
|
||||
* to sort by. By default will just match on key.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
TelemetryTableController.prototype.sortByTimeSystem = function () {
|
||||
var scope = this.$scope;
|
||||
var sortColumn;
|
||||
scope.defaultSort = undefined;
|
||||
|
||||
sortColumn = this.table.columns.filter(function (column) {
|
||||
return column.isCurrentTimeSystem();
|
||||
})[0];
|
||||
if (sortColumn) {
|
||||
scope.defaultSort = sortColumn.title();
|
||||
this.telemetry.sort(sortColumn.title() + '.value');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Attaches listeners that respond to state change in domain object,
|
||||
* conductor, and receipt of telemetry
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
TelemetryTableController.prototype.registerChangeListeners = function () {
|
||||
if (this.unobserveObject) {
|
||||
this.unobserveObject();
|
||||
}
|
||||
|
||||
this.unobserveObject = this.openmct.objects.observe(this.domainObject, "*",
|
||||
function (domainObject) {
|
||||
this.domainObject = domainObject;
|
||||
this.getData();
|
||||
}.bind(this)
|
||||
);
|
||||
|
||||
this.openmct.time.on('timeSystem', this.sortByTimeSystem);
|
||||
this.openmct.time.on('bounds', this.changeBounds);
|
||||
this.openmct.time.on('clock', this.setClock);
|
||||
|
||||
this.telemetry.on('added', this.addRowsToTable);
|
||||
this.telemetry.on('discarded', this.removeRowsFromTable);
|
||||
};
|
||||
|
||||
/**
|
||||
* On receipt of new telemetry, informs mct-table directive that new rows
|
||||
* are available and passes populated rows to it
|
||||
*
|
||||
* @private
|
||||
* @param rows
|
||||
*/
|
||||
TelemetryTableController.prototype.addRowsToTable = function (rows) {
|
||||
this.$scope.$broadcast('add:rows', rows);
|
||||
};
|
||||
|
||||
/**
|
||||
* When rows are to be removed, informs mct-table directive. Row removal
|
||||
* happens when rows call outside the bounds of the time conductor
|
||||
*
|
||||
* @private
|
||||
* @param rows
|
||||
*/
|
||||
TelemetryTableController.prototype.removeRowsFromTable = function (rows) {
|
||||
this.$scope.$broadcast('remove:rows', rows);
|
||||
};
|
||||
|
||||
/**
|
||||
* On Time Conductor bounds change, update displayed telemetry. In the
|
||||
* case of a tick, previously visible telemetry that is now out of band
|
||||
* will be removed from the table.
|
||||
* @param {openmct.TimeConductorBounds~TimeConductorBounds} bounds
|
||||
*/
|
||||
TelemetryTableController.prototype.changeBounds = function (bounds, isTick) {
|
||||
if (isTick) {
|
||||
this.telemetry.bounds(bounds);
|
||||
} else {
|
||||
// Is fixed bounds change
|
||||
this.getData();
|
||||
}
|
||||
this.lastBounds = bounds;
|
||||
};
|
||||
|
||||
/**
|
||||
* Clean controller, deregistering listeners etc.
|
||||
*/
|
||||
TelemetryTableController.prototype.destroy = function () {
|
||||
|
||||
this.openmct.time.off('timeSystem', this.sortByTimeSystem);
|
||||
this.openmct.time.off('bounds', this.changeBounds);
|
||||
this.openmct.time.off('clock', this.setClock);
|
||||
|
||||
this.subscriptions.forEach(function (subscription) {
|
||||
subscription();
|
||||
});
|
||||
|
||||
if (this.unobserveObject) {
|
||||
this.unobserveObject();
|
||||
}
|
||||
this.subscriptions = [];
|
||||
|
||||
if (this.timeoutHandle) {
|
||||
this.$timeout.cancel(this.timeoutHandle);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* For given objects, populate column metadata and table headers.
|
||||
* @private
|
||||
* @param {module:openmct.DomainObject[]} objects the domain objects for
|
||||
* which columns should be populated
|
||||
*/
|
||||
TelemetryTableController.prototype.loadColumns = function (objects) {
|
||||
var telemetryApi = this.openmct.telemetry;
|
||||
|
||||
this.table = new TableConfiguration(this.$scope.domainObject,
|
||||
this.openmct);
|
||||
|
||||
this.$scope.headers = [];
|
||||
|
||||
if (objects.length > 0) {
|
||||
objects.forEach(function (object) {
|
||||
var metadataValues = telemetryApi.getMetadata(object).values();
|
||||
metadataValues.forEach(function (metadatum) {
|
||||
this.table.addColumn(object, metadatum);
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
|
||||
this.filterColumns();
|
||||
this.sortByTimeSystem();
|
||||
}
|
||||
|
||||
return objects;
|
||||
};
|
||||
|
||||
/**
|
||||
* Request telemetry data from an historical store for given objects.
|
||||
* @private
|
||||
* @param {object[]} The domain objects to request telemetry for
|
||||
* @returns {Promise} resolved when historical data is available
|
||||
*/
|
||||
TelemetryTableController.prototype.getHistoricalData = function (objects) {
|
||||
var self = this;
|
||||
var openmct = this.openmct;
|
||||
var bounds = openmct.time.bounds();
|
||||
var scope = this.$scope;
|
||||
var rowData = [];
|
||||
var processedObjects = 0;
|
||||
var requestTime = this.lastRequestTime = Date.now();
|
||||
var telemetryCollection = this.telemetry;
|
||||
|
||||
var promise = new Promise(function (resolve, reject) {
|
||||
/*
|
||||
* On completion of batched processing, set the rows on scope
|
||||
*/
|
||||
function finishProcessing() {
|
||||
telemetryCollection.add(rowData);
|
||||
scope.rows = telemetryCollection.telemetry;
|
||||
self.loading(false);
|
||||
|
||||
resolve(scope.rows);
|
||||
}
|
||||
|
||||
/*
|
||||
* Process a batch of historical data
|
||||
*/
|
||||
function processData(object, historicalData, index, limitEvaluator) {
|
||||
if (index >= historicalData.length) {
|
||||
processedObjects++;
|
||||
|
||||
if (processedObjects === objects.length) {
|
||||
finishProcessing();
|
||||
}
|
||||
} else {
|
||||
rowData = rowData.concat(historicalData.slice(index, index + self.batchSize)
|
||||
.map(self.table.getRowValues.bind(self.table, object, limitEvaluator)));
|
||||
/*
|
||||
Use timeout to yield process to other UI activities. On
|
||||
return, process next batch
|
||||
*/
|
||||
self.timeoutHandle = self.$timeout(function () {
|
||||
processData(object, historicalData, index + self.batchSize, limitEvaluator);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function makeTableRows(object, historicalData) {
|
||||
// Only process the most recent request
|
||||
if (requestTime === self.lastRequestTime) {
|
||||
var limitEvaluator = openmct.telemetry.limitEvaluator(object);
|
||||
processData(object, historicalData, 0, limitEvaluator);
|
||||
} else {
|
||||
resolve(rowData);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Use the telemetry API to request telemetry for a given object
|
||||
*/
|
||||
function requestData(object) {
|
||||
return openmct.telemetry.request(object, {
|
||||
start: bounds.start,
|
||||
end: bounds.end
|
||||
}).then(makeTableRows.bind(undefined, object))
|
||||
.catch(reject);
|
||||
}
|
||||
this.$timeout.cancel(this.timeoutHandle);
|
||||
|
||||
if (objects.length > 0) {
|
||||
objects.forEach(requestData);
|
||||
} else {
|
||||
self.loading(false);
|
||||
resolve([]);
|
||||
}
|
||||
}.bind(this));
|
||||
|
||||
return promise;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Subscribe to real-time data for the given objects.
|
||||
* @private
|
||||
* @param {object[]} objects The objects to subscribe to.
|
||||
*/
|
||||
TelemetryTableController.prototype.subscribeToNewData = function (objects) {
|
||||
var telemetryApi = this.openmct.telemetry;
|
||||
var telemetryCollection = this.telemetry;
|
||||
//Set table max length to avoid unbounded growth.
|
||||
var limitEvaluator;
|
||||
var table = this.table;
|
||||
|
||||
this.subscriptions.forEach(function (subscription) {
|
||||
subscription();
|
||||
});
|
||||
this.subscriptions = [];
|
||||
|
||||
function newData(domainObject, datum) {
|
||||
limitEvaluator = telemetryApi.limitEvaluator(domainObject);
|
||||
telemetryCollection.add([table.getRowValues(domainObject, limitEvaluator, datum)]);
|
||||
}
|
||||
|
||||
objects.forEach(function (object) {
|
||||
this.subscriptions.push(
|
||||
telemetryApi.subscribe(object, newData.bind(this, object), {}));
|
||||
}.bind(this));
|
||||
|
||||
return objects;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return an array of telemetry objects in this view that should be
|
||||
* subscribed to.
|
||||
* @private
|
||||
* @returns {Promise<Array>} a promise that resolves with an array of
|
||||
* telemetry objects in this view.
|
||||
*/
|
||||
TelemetryTableController.prototype.getTelemetryObjects = function () {
|
||||
var telemetryApi = this.openmct.telemetry;
|
||||
var compositionApi = this.openmct.composition;
|
||||
|
||||
function filterForTelemetry(objects) {
|
||||
return objects.filter(telemetryApi.isTelemetryObject.bind(telemetryApi));
|
||||
}
|
||||
|
||||
/*
|
||||
* If parent object is a telemetry object, subscribe to it. Do not
|
||||
* test composees.
|
||||
*/
|
||||
if (telemetryApi.isTelemetryObject(this.domainObject)) {
|
||||
return Promise.resolve([this.domainObject]);
|
||||
} else {
|
||||
/*
|
||||
* If parent object is not a telemetry object, subscribe to all
|
||||
* composees that are telemetry producing objects.
|
||||
*/
|
||||
var composition = compositionApi.get(this.domainObject);
|
||||
|
||||
if (composition) {
|
||||
return composition
|
||||
.load()
|
||||
.then(filterForTelemetry);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Request historical data, and subscribe to for real-time data.
|
||||
* @private
|
||||
* @returns {Promise} A promise that is resolved once subscription is
|
||||
* established, and historical telemetry is received and processed.
|
||||
*/
|
||||
TelemetryTableController.prototype.getData = function () {
|
||||
var scope = this.$scope;
|
||||
|
||||
this.telemetry.clear();
|
||||
this.telemetry.bounds(this.openmct.time.bounds());
|
||||
|
||||
this.loading(true);
|
||||
scope.rows = [];
|
||||
|
||||
return this.getTelemetryObjects()
|
||||
.then(this.loadColumns)
|
||||
.then(this.subscribeToNewData)
|
||||
.then(this.getHistoricalData)
|
||||
.catch(function error(e) {
|
||||
this.loading(false);
|
||||
console.error(e.stack || e);
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
TelemetryTableController.prototype.loading = function (loading) {
|
||||
this.$timeout(function () {
|
||||
this.$scope.loading = loading;
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
/**
|
||||
* When column configuration changes, update the visible headers
|
||||
* accordingly.
|
||||
* @private
|
||||
*/
|
||||
TelemetryTableController.prototype.filterColumns = function () {
|
||||
var columnConfig = this.table.buildColumnConfiguration();
|
||||
|
||||
//Populate headers with visible columns (determined by configuration)
|
||||
this.$scope.headers = Object.keys(columnConfig).filter(function (column) {
|
||||
return columnConfig[column];
|
||||
});
|
||||
};
|
||||
|
||||
return TelemetryTableController;
|
||||
}
|
||||
);
|
@ -1,115 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2018, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define(
|
||||
[
|
||||
"../controllers/MCTTableController",
|
||||
"text!../../res/templates/mct-table.html"
|
||||
],
|
||||
function (MCTTableController, TableTemplate) {
|
||||
/**
|
||||
* Defines a generic 'Table' component. The table can be populated
|
||||
* en-masse by setting the rows attribute, or rows can be added as
|
||||
* needed via a broadcast 'addRow' event.
|
||||
*
|
||||
* This directive accepts parameters specifying header and row
|
||||
* content, as well as some additional options.
|
||||
*
|
||||
* Two broadcast events for notifying the table that the rows have
|
||||
* changed. For performance reasons, the table does not monitor the
|
||||
* content of `rows` constantly.
|
||||
* - 'add:row': A $broadcast event that will notify the table that
|
||||
* a new row has been added to the table.
|
||||
* eg.
|
||||
* <pre><code>
|
||||
* $scope.rows.push(newRow);
|
||||
* $scope.$broadcast('add:row', $scope.rows.length-1);
|
||||
* </code></pre>
|
||||
* The code above adds a new row, and alerts the table using the
|
||||
* add:row event. Sorting and filtering will be applied
|
||||
* automatically by the table component.
|
||||
*
|
||||
* - 'remove:row': A $broadcast event that will notify the table that a
|
||||
* row should be removed from the table.
|
||||
* eg.
|
||||
* <pre><code>
|
||||
* $scope.rows.slice(5, 1);
|
||||
* $scope.$broadcast('remove:row', 5);
|
||||
* </code></pre>
|
||||
* The code above removes a row from the rows array, and then alerts
|
||||
* the table to its removal.
|
||||
*
|
||||
* @memberof platform/features/table
|
||||
* @param {string[]} headers The column titles to appear at the top
|
||||
* of the table. Corresponding values are specified in the rows
|
||||
* using the header title provided here.
|
||||
* @param {Object[]} rows The row content. Each row is an object
|
||||
* with key-value pairs where the key corresponds to a header
|
||||
* specified in the headers parameter.
|
||||
* @param {boolean} enableFilter If true, values will be searchable
|
||||
* and results filtered
|
||||
* @param {boolean} enableSort If true, sorting will be enabled
|
||||
* allowing sorting by clicking on column headers
|
||||
* @param {boolean} autoScroll If true, table will automatically
|
||||
* scroll to the bottom as new data arrives. Auto-scroll can be
|
||||
* disengaged manually by scrolling away from the bottom of the
|
||||
* table, and can also be enabled manually by scrolling to the bottom of
|
||||
* the table rows.
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
function MCTTable() {
|
||||
return {
|
||||
restrict: "E",
|
||||
template: TableTemplate,
|
||||
controller: [
|
||||
'$scope',
|
||||
'$window',
|
||||
'$element',
|
||||
'exportService',
|
||||
'formatService',
|
||||
'openmct',
|
||||
MCTTableController
|
||||
],
|
||||
controllerAs: "table",
|
||||
scope: {
|
||||
headers: "=",
|
||||
rows: "=",
|
||||
formatCell: "=?",
|
||||
enableFilter: "=?",
|
||||
enableSort: "=?",
|
||||
autoScroll: "=?",
|
||||
// Used to indicate which columns contain time data. This
|
||||
// will be used for determining when the table is sorted
|
||||
// by the column that can be used for time conductor
|
||||
// time of interest.
|
||||
timeColumns: "=?",
|
||||
// Indicate a column to sort on. Allows control of sort
|
||||
// via configuration (eg. for default sort column).
|
||||
defaultSort: "=?"
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return MCTTable;
|
||||
}
|
||||
);
|
@ -1,214 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2018, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define(
|
||||
[
|
||||
"../src/TableConfiguration"
|
||||
],
|
||||
function (Table) {
|
||||
|
||||
describe("A table", function () {
|
||||
var mockTableObject,
|
||||
mockTelemetryObject,
|
||||
mockAPI,
|
||||
mockTelemetryAPI,
|
||||
table,
|
||||
mockTimeAPI,
|
||||
mockObjectsAPI,
|
||||
mockModel;
|
||||
|
||||
beforeEach(function () {
|
||||
mockTableObject = jasmine.createSpyObj('domainObject',
|
||||
['getModel', 'useCapability', 'getCapability', 'hasCapability']
|
||||
);
|
||||
mockModel = {};
|
||||
mockTableObject.getModel.and.returnValue(mockModel);
|
||||
mockTableObject.getCapability.and.callFake(function (name) {
|
||||
return name === 'editor' && {
|
||||
isEditContextRoot: function () {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
});
|
||||
mockTelemetryObject = {
|
||||
identifier: {
|
||||
namespace: 'mock',
|
||||
key: 'domainObject'
|
||||
}
|
||||
};
|
||||
|
||||
mockTelemetryAPI = jasmine.createSpyObj('telemetryAPI', [
|
||||
'getValueFormatter'
|
||||
]);
|
||||
mockTimeAPI = jasmine.createSpyObj('timeAPI', [
|
||||
'timeSystem'
|
||||
]);
|
||||
mockObjectsAPI = jasmine.createSpyObj('objectsAPI', [
|
||||
'makeKeyString'
|
||||
]);
|
||||
mockObjectsAPI.makeKeyString.and.callFake(function (identifier) {
|
||||
return [identifier.namespace, identifier.key].join(':');
|
||||
});
|
||||
|
||||
mockAPI = {
|
||||
telemetry: mockTelemetryAPI,
|
||||
time: mockTimeAPI,
|
||||
objects: mockObjectsAPI
|
||||
};
|
||||
mockTelemetryAPI.getValueFormatter.and.callFake(function (metadata) {
|
||||
var formatter = jasmine.createSpyObj(
|
||||
'telemetryFormatter:' + metadata.key,
|
||||
[
|
||||
'format',
|
||||
'parse'
|
||||
]
|
||||
);
|
||||
var getter = function (datum) {
|
||||
return datum[metadata.key];
|
||||
};
|
||||
formatter.format.and.callFake(getter);
|
||||
formatter.parse.and.callFake(getter);
|
||||
return formatter;
|
||||
});
|
||||
|
||||
table = new Table(mockTableObject, mockAPI);
|
||||
});
|
||||
|
||||
describe("Building columns from telemetry metadata", function () {
|
||||
var metadata = [
|
||||
{
|
||||
name: 'Range 1',
|
||||
key: 'range1',
|
||||
source: 'range1',
|
||||
hints: {
|
||||
range: 1
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'Range 2',
|
||||
key: 'range2',
|
||||
source: 'range2',
|
||||
hints: {
|
||||
range: 2
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'Domain 1',
|
||||
key: 'domain1',
|
||||
source: 'domain1',
|
||||
format: 'utc',
|
||||
hints: {
|
||||
domain: 1
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'Domain 2',
|
||||
key: 'domain2',
|
||||
source: 'domain2',
|
||||
format: 'utc',
|
||||
hints: {
|
||||
domain: 2
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
beforeEach(function () {
|
||||
mockTimeAPI.timeSystem.and.returnValue({
|
||||
key: 'domain1'
|
||||
});
|
||||
metadata.forEach(function (metadatum) {
|
||||
table.addColumn(mockTelemetryObject, metadatum);
|
||||
});
|
||||
});
|
||||
|
||||
it("populates columns", function () {
|
||||
expect(table.columns.length).toBe(4);
|
||||
});
|
||||
|
||||
it("Produces headers for each column based on metadata name", function () {
|
||||
expect(table.headers.size).toBe(4);
|
||||
Array.from(table.headers.values).forEach(function (header, i) {
|
||||
expect(header).toEqual(metadata[i].name);
|
||||
});
|
||||
});
|
||||
|
||||
it("Provides a default configuration with all columns" +
|
||||
" visible", function () {
|
||||
var configuration = table.buildColumnConfiguration();
|
||||
|
||||
expect(configuration).toBeDefined();
|
||||
expect(Object.keys(configuration).every(function (key) {
|
||||
return configuration[key];
|
||||
}));
|
||||
});
|
||||
|
||||
it("Column configuration exposes persisted configuration", function () {
|
||||
var tableConfig,
|
||||
modelConfig = {
|
||||
table: {
|
||||
columns : {
|
||||
'Range 1': false
|
||||
}
|
||||
}
|
||||
};
|
||||
mockModel.configuration = modelConfig;
|
||||
|
||||
tableConfig = table.buildColumnConfiguration();
|
||||
|
||||
expect(tableConfig).toBeDefined();
|
||||
expect(tableConfig['Range 1']).toBe(false);
|
||||
});
|
||||
|
||||
describe('retrieving row values', function () {
|
||||
var datum,
|
||||
rowValues;
|
||||
|
||||
beforeEach(function () {
|
||||
datum = {
|
||||
'range1': 10,
|
||||
'range2': 20,
|
||||
'domain1': 0,
|
||||
'domain2': 1
|
||||
};
|
||||
var limitEvaluator = {
|
||||
evaluate: function () {
|
||||
return {
|
||||
"cssClass": "alarm-class"
|
||||
};
|
||||
}
|
||||
};
|
||||
rowValues = table.getRowValues(mockTelemetryObject, limitEvaluator, datum);
|
||||
});
|
||||
|
||||
it("Returns a value for every column", function () {
|
||||
expect(rowValues['Range 1'].text).toEqual(10);
|
||||
});
|
||||
|
||||
it("Applies appropriate css class if limit violated.", function () {
|
||||
expect(rowValues['Range 1'].cssClass).toEqual("alarm-class");
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user