Compare commits
12 Commits
notebook-i
...
inline-edi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
889350623a | ||
|
|
aac1f02bd6 | ||
|
|
e759761a04 | ||
|
|
490567c8e8 | ||
|
|
ede5b85c93 | ||
|
|
82f32a57f4 | ||
|
|
0dd6a4eb44 | ||
|
|
4c03a3b31d | ||
|
|
aaeffb16e3 | ||
|
|
41f6047c96 | ||
|
|
c35cdf176f | ||
|
|
05227286c4 |
@@ -21,6 +21,5 @@
|
||||
"shadow": "outer",
|
||||
"strict": "implied",
|
||||
"undef": true,
|
||||
"unused": "vars",
|
||||
"latedef": "nofunc"
|
||||
"unused": "vars"
|
||||
}
|
||||
|
||||
15
API.md
15
API.md
@@ -879,21 +879,6 @@ openmct.install(openmct.plugins.CouchDB('http://localhost:9200'))
|
||||
* `openmct.plugins.Espresso` and `openmct.plugins.Snow` are two different
|
||||
themes (dark and light) available for Open MCT. Note that at least one
|
||||
of these themes must be installed for Open MCT to appear correctly.
|
||||
* `openmct.plugins.URLIndicatorPlugin` adds an indicator which shows the
|
||||
availability of a URL with the following options:
|
||||
- `url` : URL to indicate the status of
|
||||
- `cssClass`: Icon to show in the status bar, defaults to `icon-database`, [list of all icons](https://nasa.github.io/openmct/style-guide/#/browse/styleguide:home?view=items)
|
||||
- `interval`: Interval between checking the connection, defaults to `10000`
|
||||
- `label` Name showing up as text in the status bar, defaults to url
|
||||
```javascript
|
||||
openmct.install(openmct.plugins.URLIndicatorPlugin({
|
||||
url: 'http://google.com',
|
||||
cssClass: 'check',
|
||||
interval: 10000,
|
||||
label: 'Google'
|
||||
})
|
||||
);
|
||||
```
|
||||
* `openmct.plugins.LocalStorage` provides persistence of user-created
|
||||
objects in browser-local storage. This is particularly useful in
|
||||
development environments.
|
||||
|
||||
@@ -88,7 +88,7 @@ and [`gulp`](http://gulpjs.com/).
|
||||
|
||||
To build Open MCT for deployment:
|
||||
|
||||
`npm run prepare`
|
||||
`npm run prepublish`
|
||||
|
||||
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
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
"screenfull": "^3.0.0",
|
||||
"node-uuid": "^1.4.7",
|
||||
"comma-separated-values": "^3.6.4",
|
||||
"file-saver": "^1.3.3",
|
||||
"FileSaver.js": "^0.0.2",
|
||||
"zepto": "^1.1.6",
|
||||
"eventemitter3": "^1.2.0",
|
||||
"lodash": "3.10.1",
|
||||
@@ -25,4 +25,4 @@
|
||||
"html2canvas": "^0.4.1",
|
||||
"moment-timezone": "^0.5.13"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
16
circle.yml
16
circle.yml
@@ -1,17 +1,15 @@
|
||||
machine:
|
||||
node:
|
||||
version: 4.7.0
|
||||
|
||||
dependencies:
|
||||
pre:
|
||||
- npm install -g npm@latest
|
||||
|
||||
deployment:
|
||||
production:
|
||||
branch: master
|
||||
commands:
|
||||
- npm install canvas nomnoml
|
||||
- ./build-docs.sh
|
||||
- git fetch --unshallow
|
||||
- git push git@heroku.com:openmctweb-demo.git $CIRCLE_SHA1:refs/heads/master
|
||||
openmct-demo:
|
||||
branch: live_demo
|
||||
heroku:
|
||||
appname: openmct-demo
|
||||
openmctweb-staging-deux:
|
||||
branch: mobile
|
||||
heroku:
|
||||
@@ -24,4 +22,4 @@ test:
|
||||
general:
|
||||
branches:
|
||||
ignore:
|
||||
- gh-pages
|
||||
- gh-pages
|
||||
|
||||
@@ -2283,7 +2283,7 @@ To install build dependencies (only needs to be run once):
|
||||
|
||||
To build:
|
||||
|
||||
`npm run prepare`
|
||||
`npm run prepublish`
|
||||
|
||||
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
|
||||
|
||||
@@ -59,7 +59,7 @@ define([
|
||||
if (domainObject.telemetry && domainObject.telemetry.hasOwnProperty(prop)) {
|
||||
workerRequest[prop] = domainObject.telemetry[prop];
|
||||
}
|
||||
if (request && request.hasOwnProperty(prop)) {
|
||||
if (request.hasOwnProperty(prop)) {
|
||||
workerRequest[prop] = request[prop];
|
||||
}
|
||||
if (!workerRequest[prop]) {
|
||||
@@ -78,8 +78,8 @@ define([
|
||||
return this.workerInterface.request(workerRequest);
|
||||
};
|
||||
|
||||
GeneratorProvider.prototype.subscribe = function (domainObject, callback) {
|
||||
var workerRequest = this.makeWorkerRequest(domainObject, {});
|
||||
GeneratorProvider.prototype.subscribe = function (domainObject, callback, request) {
|
||||
var workerRequest = this.makeWorkerRequest(domainObject, request);
|
||||
return this.workerInterface.subscribe(workerRequest, callback);
|
||||
};
|
||||
|
||||
|
||||
@@ -44,7 +44,9 @@ define([
|
||||
message = message.data;
|
||||
var callback = this.callbacks[message.id];
|
||||
if (callback) {
|
||||
callback(message);
|
||||
if (callback(message)) {
|
||||
delete this.callbacks[message.id];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -70,7 +72,6 @@ define([
|
||||
deferred.resolve = resolve;
|
||||
deferred.reject = reject;
|
||||
});
|
||||
var messageId;
|
||||
|
||||
function callback(message) {
|
||||
if (message.error) {
|
||||
@@ -78,27 +79,33 @@ define([
|
||||
} else {
|
||||
deferred.resolve(message.data);
|
||||
}
|
||||
delete this.callbacks[messageId];
|
||||
return true;
|
||||
}
|
||||
|
||||
messageId = this.dispatch('request', request, callback.bind(this));
|
||||
this.dispatch('request', request, callback);
|
||||
|
||||
return promise;
|
||||
};
|
||||
|
||||
WorkerInterface.prototype.subscribe = function (request, cb) {
|
||||
function callback(message) {
|
||||
var isCancelled = false;
|
||||
|
||||
var callback = function (message) {
|
||||
if (isCancelled) {
|
||||
return true;
|
||||
}
|
||||
cb(message.data);
|
||||
};
|
||||
|
||||
var messageId = this.dispatch('subscribe', request, callback);
|
||||
var messageId = this.dispatch('subscribe', request, callback)
|
||||
|
||||
return function () {
|
||||
isCancelled = true;
|
||||
this.dispatch('unsubscribe', {
|
||||
id: messageId
|
||||
});
|
||||
delete this.callbacks[messageId];
|
||||
}.bind(this);
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -127,8 +127,7 @@
|
||||
{ 'meaning': 'Timer object', 'cssClass': 'icon-timer', 'cssContent': 'e1127', 'htmlEntity': '&#xe1127' },
|
||||
{ 'meaning': 'Data Topic', 'cssClass': 'icon-topic', 'cssContent': 'e1128', 'htmlEntity': '&#xe1128' },
|
||||
{ 'meaning': 'Fixed Position object', 'cssClass': 'icon-box-with-dashed-lines', 'cssContent': 'e1129', 'htmlEntity': '&#xe1129' },
|
||||
{ 'meaning': 'Summary Widget', 'cssClass': 'icon-summary-widget', 'cssContent': 'e1130', 'htmlEntity': '&#xe1130' },
|
||||
{ 'meaning': 'Notebook object', 'cssClass': 'icon-notebook', 'cssContent': 'e1131', 'htmlEntity': '&#xe1131' }
|
||||
{ 'meaning': 'Summary Widget', 'cssClass': 'icon-summary-widget', 'cssContent': 'e1130', 'htmlEntity': '&#xe1130' }
|
||||
];
|
||||
"></div>
|
||||
|
||||
|
||||
@@ -121,7 +121,7 @@
|
||||
<h2>Palettes</h2>
|
||||
<div class="cols cols1-1">
|
||||
<div class="col">
|
||||
<p>Use a palette to provide color choices. Similar to context menus and dropdowns, palettes should be dismissed when a choice is made within them, or if the user clicks outside one. Selected palette choices should utilize the <code>selected</code> CSS class to visualize indicate that state.</p>
|
||||
<p>Use a palette to provide color choices. Similar to context menus and dropdowns, palettes should be dismissed when a choice is made within them, or if the user clicks outside one.</p>
|
||||
<p>Note that while this example uses static markup for illustrative purposes, don't do this - use a front-end framework with repeaters to build the color choices.</p>
|
||||
</div>
|
||||
<mct-example><div style="height: 220px" title="Ignore me, I'm just here to provide space for this example.">
|
||||
@@ -129,9 +129,9 @@
|
||||
<div class="s-button s-menu-button menu-element t-color-palette icon-paint-bucket" ng-controller="ClickAwayController as toggle">
|
||||
<span class="l-click-area" ng-click="toggle.toggle()"></span>
|
||||
<span class="color-swatch" style="background: rgb(255, 0, 0);"></span>
|
||||
<div class="menu l-palette l-color-palette" ng-show="toggle.isActive()">
|
||||
<div class="menu l-color-palette" ng-show="toggle.isActive()">
|
||||
<div class="l-palette-row l-option-row">
|
||||
<div class="l-palette-item s-palette-item no-selection"></div>
|
||||
<div class="l-palette-item s-palette-item " ng-click="ngModel[field] = 'transparent'"></div>
|
||||
<span class="l-palette-item-label">None</span>
|
||||
</div>
|
||||
<div class="l-palette-row">
|
||||
@@ -147,7 +147,7 @@
|
||||
<div class="l-palette-item s-palette-item" style="background: rgb(255, 255, 255);"></div>
|
||||
</div>
|
||||
<div class="l-palette-row">
|
||||
<div class="l-palette-item s-palette-item selected" style="background: rgb(255, 0, 0);"></div>
|
||||
<div class="l-palette-item s-palette-item" style="background: rgb(136, 32, 32);"></div>
|
||||
<div class="l-palette-item s-palette-item" style="background: rgb(224, 64, 64);"></div>
|
||||
<div class="l-palette-item s-palette-item" style="background: rgb(240, 160, 72);"></div>
|
||||
<div class="l-palette-item s-palette-item" style="background: rgb(255, 248, 96);"></div>
|
||||
|
||||
32
gulpfile.js
32
gulpfile.js
@@ -22,8 +22,6 @@
|
||||
|
||||
/*global require,__dirname*/
|
||||
|
||||
require("v8-compile-cache");
|
||||
|
||||
var gulp = require('gulp'),
|
||||
sourcemaps = require('gulp-sourcemaps'),
|
||||
path = require('path'),
|
||||
@@ -48,22 +46,9 @@ var gulp = require('gulp'),
|
||||
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];
|
||||
});;
|
||||
}()),
|
||||
startFile: "src/start.frag",
|
||||
endFile: "src/end.frag"
|
||||
},
|
||||
optimize: 'uglify2',
|
||||
uglify2: { output: { comments: /@preserve/ } },
|
||||
mainConfigFile: paths.main,
|
||||
wrapShim: true
|
||||
},
|
||||
@@ -73,6 +58,14 @@ var gulp = require('gulp'),
|
||||
},
|
||||
sass: {
|
||||
sourceComments: true
|
||||
},
|
||||
replace: {
|
||||
variables: {
|
||||
version: project.version,
|
||||
timestamp: moment.utc(Date.now()).format(),
|
||||
revision: fs.existsSync('.git') ? git.long() : 'Unknown',
|
||||
branch: fs.existsSync('.git') ? git.branch() : 'Unknown'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -83,11 +76,16 @@ if (process.env.NODE_ENV === 'development') {
|
||||
|
||||
gulp.task('scripts', function () {
|
||||
var requirejsOptimize = require('gulp-requirejs-optimize');
|
||||
var replace = require('gulp-replace-task');
|
||||
var header = require('gulp-header');
|
||||
var comment = fs.readFileSync('src/about.frag');
|
||||
|
||||
return gulp.src(paths.main)
|
||||
.pipe(sourcemaps.init())
|
||||
.pipe(requirejsOptimize(options.requirejsOptimize))
|
||||
.pipe(sourcemaps.write('.'))
|
||||
.pipe(replace(options.replace))
|
||||
.pipe(header(comment, options.replace.variables))
|
||||
.pipe(gulp.dest(paths.dist));
|
||||
});
|
||||
|
||||
@@ -179,4 +177,4 @@ gulp.task('install', [ 'assets', 'scripts' ]);
|
||||
|
||||
gulp.task('verify', [ 'lint', 'test', 'checkstyle' ]);
|
||||
|
||||
gulp.task('build', [ 'verify', 'install' ]);
|
||||
gulp.task('build', [ 'verify', 'install' ]);
|
||||
|
||||
@@ -25,7 +25,8 @@
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
||||
<title></title>
|
||||
<script src="bower_components/requirejs/require.js"> </script>
|
||||
<script src="bower_components/requirejs/require.js">
|
||||
</script>
|
||||
<script>
|
||||
var THIRTY_MINUTES = 30 * 60 * 1000;
|
||||
|
||||
@@ -43,16 +44,13 @@
|
||||
openmct.install(openmct.plugins.ExampleImagery());
|
||||
openmct.install(openmct.plugins.UTCTimeSystem());
|
||||
openmct.install(openmct.plugins.ImportExport());
|
||||
openmct.install(openmct.plugins.AutoflowView({
|
||||
type: "telemetry.panel"
|
||||
}));
|
||||
openmct.install(openmct.plugins.Conductor({
|
||||
menuOptions: [
|
||||
{
|
||||
name: "Fixed",
|
||||
timeSystem: 'utc',
|
||||
bounds: {
|
||||
start: Date.now() - THIRTY_MINUTES,
|
||||
start: Date.now() - 30 * 60 * 1000,
|
||||
end: Date.now()
|
||||
}
|
||||
},
|
||||
@@ -67,7 +65,6 @@
|
||||
}
|
||||
]
|
||||
}));
|
||||
openmct.install(openmct.plugins.SummaryWidget());
|
||||
openmct.time.clock('local', {start: -THIRTY_MINUTES, end: 0});
|
||||
openmct.time.timeSystem('utc');
|
||||
openmct.start();
|
||||
|
||||
@@ -36,8 +36,6 @@ module.exports = function(config) {
|
||||
files: [
|
||||
{pattern: 'bower_components/**/*.js', included: false},
|
||||
{pattern: 'node_modules/d3-*/**/*.js', included: false},
|
||||
{pattern: 'node_modules/vue/**/*.js', included: false},
|
||||
{pattern: 'node_modules/@cristian77/**/*.js', included: false},
|
||||
{pattern: 'src/**/*.js', included: false},
|
||||
{pattern: 'example/**/*.html', included: false},
|
||||
{pattern: 'example/**/*.js', included: false},
|
||||
|
||||
23
openmct.js
23
openmct.js
@@ -19,7 +19,7 @@
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
/*global requirejs,BUILD_CONSTANTS*/
|
||||
/*global requirejs*/
|
||||
|
||||
requirejs.config({
|
||||
"paths": {
|
||||
@@ -33,11 +33,10 @@ requirejs.config({
|
||||
"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",
|
||||
"saveAs": "bower_components/FileSaver.js/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/build/d3-selection.min",
|
||||
@@ -49,8 +48,7 @@ requirejs.config({
|
||||
"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",
|
||||
"painterro": "node_modules/@cristian77/painterro/build/painterro.min"
|
||||
"d3-time-format": "node_modules/d3-time-format/build/d3-time-format.min"
|
||||
},
|
||||
"shim": {
|
||||
"angular": {
|
||||
@@ -68,12 +66,6 @@ requirejs.config({
|
||||
"moment-duration-format": {
|
||||
"deps": ["moment"]
|
||||
},
|
||||
"painterro": {
|
||||
"exports": "Painterro"
|
||||
},
|
||||
"saveAs": {
|
||||
"exports": "saveAs"
|
||||
},
|
||||
"screenfull": {
|
||||
"exports": "screenfull"
|
||||
},
|
||||
@@ -99,17 +91,12 @@ requirejs.config({
|
||||
define([
|
||||
'./platform/framework/src/Main',
|
||||
'./src/defaultRegistry',
|
||||
'./src/MCT',
|
||||
'./src/plugins/buildInfo/plugin'
|
||||
], function (Main, defaultRegistry, MCT, buildInfo) {
|
||||
'./src/MCT'
|
||||
], function (Main, defaultRegistry, MCT) {
|
||||
var openmct = new MCT();
|
||||
|
||||
openmct.legacyRegistry = defaultRegistry;
|
||||
|
||||
if (typeof BUILD_CONSTANTS !== 'undefined') {
|
||||
openmct.install(buildInfo(BUILD_CONSTANTS));
|
||||
}
|
||||
|
||||
openmct.on('start', function () {
|
||||
return new Main().run(defaultRegistry);
|
||||
});
|
||||
|
||||
11
package.json
11
package.json
@@ -3,7 +3,6 @@
|
||||
"version": "0.12.1-SNAPSHOT",
|
||||
"description": "The Open MCT core platform",
|
||||
"dependencies": {
|
||||
"@cristian77/painterro": "^0.2.48",
|
||||
"d3-array": "^1.0.2",
|
||||
"d3-axis": "^1.0.4",
|
||||
"d3-collection": "^1.0.2",
|
||||
@@ -16,18 +15,19 @@
|
||||
"d3-time-format": "^2.0.3",
|
||||
"express": "^4.13.1",
|
||||
"minimist": "^1.1.1",
|
||||
"request": "^2.69.0",
|
||||
"vue": "^2.5.6"
|
||||
"request": "^2.69.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"bower": "^1.7.7",
|
||||
"git-rev-sync": "^1.4.0",
|
||||
"glob": ">= 3.0.0",
|
||||
"gulp": "^3.9.1",
|
||||
"gulp-header": "^1.8.8",
|
||||
"gulp-jscs": "^3.0.2",
|
||||
"gulp-jshint": "^2.0.0",
|
||||
"gulp-jshint-html-reporter": "^0.1.3",
|
||||
"gulp-rename": "^1.2.2",
|
||||
"gulp-replace-task": "^0.11.0",
|
||||
"gulp-requirejs-optimize": "^0.3.1",
|
||||
"gulp-sass": "^2.2.0",
|
||||
"gulp-sourcemaps": "^1.6.0",
|
||||
@@ -51,8 +51,7 @@
|
||||
"moment": "^2.11.1",
|
||||
"node-bourbon": "^4.2.3",
|
||||
"requirejs": "2.1.x",
|
||||
"split": "^1.0.0",
|
||||
"v8-compile-cache": "^1.1.0"
|
||||
"split": "^1.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "node app.js",
|
||||
@@ -62,7 +61,7 @@
|
||||
"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"
|
||||
"prepublish": "node ./node_modules/bower/bin/bower install && node ./node_modules/gulp/bin/gulp.js install"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -37,7 +37,6 @@ define([
|
||||
"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",
|
||||
@@ -61,7 +60,6 @@ define([
|
||||
browseObjectTemplate,
|
||||
gridItemTemplate,
|
||||
objectHeaderTemplate,
|
||||
objectHeaderFrameTemplate,
|
||||
menuArrowTemplate,
|
||||
backArrowTemplate,
|
||||
itemsTemplate,
|
||||
@@ -184,13 +182,6 @@ define([
|
||||
"type"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "object-header-frame",
|
||||
"template": objectHeaderFrameTemplate,
|
||||
"uses": [
|
||||
"type"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "menu-arrow",
|
||||
"template": menuArrowTemplate,
|
||||
|
||||
@@ -57,12 +57,7 @@
|
||||
</div>
|
||||
<mct-representation key="representation.selected.key"
|
||||
mct-object="representation.selected.key && domainObject"
|
||||
class="abs flex-elem grows object-holder-main scroll"
|
||||
mct-selectable="{
|
||||
item: domainObject.useCapability('adapter'),
|
||||
oldItem: domainObject
|
||||
}"
|
||||
mct-init-select>
|
||||
class="abs flex-elem grows object-holder-main scroll">
|
||||
</mct-representation>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -19,21 +19,12 @@
|
||||
this source code distribution or the Licensing information page available
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
<div ng-controller="InspectorController as controller">
|
||||
<div ng-controller="InspectorController">
|
||||
<div ng-repeat="region in regions">
|
||||
<mct-representation
|
||||
key="'object-properties'"
|
||||
mct-object="controller.selectedItem()"
|
||||
key="region.content.key"
|
||||
mct-object="domainObject"
|
||||
ng-model="ngModel">
|
||||
</mct-representation>
|
||||
|
||||
<div ng-if="!controller.hasProviderView()">
|
||||
<mct-representation
|
||||
key="inspectorKey"
|
||||
mct-object="controller.selectedItem()"
|
||||
ng-model="ngModel">
|
||||
</mct-representation>
|
||||
</div>
|
||||
|
||||
<div class='inspector-provider-view'>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,31 +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.
|
||||
-->
|
||||
<span class='type-icon flex-elem {{type.getCssClass()}}'></span>
|
||||
<span class="l-elem-wrapper l-flex-row flex-elem grows" ng-controller="ObjectHeaderController as controller">
|
||||
<span ng-if="parameters.mode" class='action flex-elem'>{{parameters.mode}}</span>
|
||||
<span class='title-label flex-elem holder flex-can-shrink s-input-inline'>{{model.name}}</span>
|
||||
<span class='t-object-alert t-alert-unsynced flex-elem holder' title='This object is not currently displaying real-time data'></span>
|
||||
<mct-representation
|
||||
key="'menu-arrow'"
|
||||
mct-object='domainObject'
|
||||
class="flex-elem context-available-w"></mct-representation>
|
||||
</span>
|
||||
@@ -22,8 +22,9 @@
|
||||
<span class='type-icon flex-elem {{type.getCssClass()}}'></span>
|
||||
<span class="l-elem-wrapper l-flex-row flex-elem grows" ng-controller="ObjectHeaderController as controller">
|
||||
<span ng-if="parameters.mode" class='action flex-elem'>{{parameters.mode}}</span>
|
||||
<span ng-attr-contenteditable="{{ controller.editable ? true : undefined }}"
|
||||
class='title-label flex-elem holder flex-can-shrink s-input-inline'
|
||||
<span contenteditable="true"
|
||||
class='title-label flex-elem holder flex-can-shrink s-inline-edit'
|
||||
ng-class="{'s-status-editing': inlineEdit}"
|
||||
ng-click="controller.edit()"
|
||||
ng-blur="controller.updateName($event)"
|
||||
ng-keypress="controller.updateName($event)">{{model.name}}</span>
|
||||
|
||||
@@ -38,6 +38,8 @@
|
||||
ng-class="{ last:($index + 1) === contextualParents.length }">
|
||||
<mct-representation key="'label'"
|
||||
mct-object="parent"
|
||||
ng-model="ngModel"
|
||||
ng-click="ngModel.selectedObject = parent"
|
||||
class="location-item">
|
||||
</mct-representation>
|
||||
</span>
|
||||
@@ -49,6 +51,8 @@
|
||||
ng-class="{ last:($index + 1) === primaryParents.length }">
|
||||
<mct-representation key="'label'"
|
||||
mct-object="parent"
|
||||
ng-model="ngModel"
|
||||
ng-click="ngModel.selectedObject = parent"
|
||||
class="location-item">
|
||||
</mct-representation>
|
||||
</span>
|
||||
|
||||
@@ -21,72 +21,56 @@
|
||||
*****************************************************************************/
|
||||
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
[],
|
||||
function () {
|
||||
|
||||
/**
|
||||
* Controller to provide the ability to inline edit an object name.
|
||||
*
|
||||
* @constructor
|
||||
* @memberof platform/commonUI/browse
|
||||
*/
|
||||
function ObjectHeaderController($scope) {
|
||||
this.$scope = $scope;
|
||||
this.domainObject = $scope.domainObject;
|
||||
this.editable = this.allowEdit();
|
||||
}
|
||||
/**
|
||||
* Controller to provide the ability to inline edit an object name.
|
||||
*
|
||||
* @constructor
|
||||
* @memberof platform/commonUI/browse
|
||||
*/
|
||||
function ObjectHeaderController($scope) {
|
||||
this.$scope = $scope;
|
||||
this.$scope.inlineEdit = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the object name on blur and enter keypress events.
|
||||
*
|
||||
* @param event the mouse event
|
||||
*/
|
||||
ObjectHeaderController.prototype.updateName = function (event) {
|
||||
if (!event || !event.currentTarget) {
|
||||
return;
|
||||
}
|
||||
/**
|
||||
* Handler for the blur and enter/return key press events
|
||||
* to update the object name.
|
||||
*
|
||||
* @param event the mouse event
|
||||
*/
|
||||
ObjectHeaderController.prototype.updateName = function (event) {
|
||||
if (event && (event.type === 'blur' || event.which === 13)) {
|
||||
var name = event.currentTarget.innerHTML;
|
||||
|
||||
if (event.type === 'blur') {
|
||||
this.updateModel(event);
|
||||
} else if (event.which === 13) {
|
||||
this.updateModel(event);
|
||||
event.currentTarget.blur();
|
||||
window.getSelection().removeAllRanges();
|
||||
}
|
||||
};
|
||||
if (name.length === 0) {
|
||||
name = "Unnamed " + this.$scope.domainObject.getCapability("type").typeDef.name;
|
||||
event.currentTarget.innerHTML = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the model.
|
||||
*
|
||||
* @param event the mouse event
|
||||
* @param private
|
||||
*/
|
||||
ObjectHeaderController.prototype.updateModel = function (event) {
|
||||
var name = event.currentTarget.textContent.replace(/\n/g, ' ');
|
||||
if (name !== this.$scope.domainObject.model.name) {
|
||||
this.$scope.domainObject.getCapability('mutation').mutate(function (model) {
|
||||
model.name = name;
|
||||
});
|
||||
}
|
||||
|
||||
if (name.length === 0) {
|
||||
name = "Unnamed " + this.domainObject.getCapability("type").typeDef.name;
|
||||
event.currentTarget.textContent = name;
|
||||
}
|
||||
this.$scope.inlineEdit = false;
|
||||
|
||||
if (name !== this.domainObject.getModel().name) {
|
||||
this.domainObject.getCapability('mutation').mutate(function (model) {
|
||||
model.name = name;
|
||||
});
|
||||
}
|
||||
};
|
||||
if (event.which === 13) {
|
||||
event.currentTarget.blur();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks if the domain object is editable.
|
||||
*
|
||||
* @private
|
||||
* @return true if object is editable
|
||||
*/
|
||||
ObjectHeaderController.prototype.allowEdit = function () {
|
||||
var type = this.domainObject && this.domainObject.getCapability('type');
|
||||
return !!(type && type.hasFeature('creation'));
|
||||
};
|
||||
/**
|
||||
* Handler for the click event to mark the filed as inline edit.
|
||||
*/
|
||||
ObjectHeaderController.prototype.edit = function () {
|
||||
this.$scope.inlineEdit = true;
|
||||
};
|
||||
|
||||
return ObjectHeaderController;
|
||||
}
|
||||
return ObjectHeaderController;
|
||||
}
|
||||
);
|
||||
|
||||
@@ -21,117 +21,74 @@
|
||||
*****************************************************************************/
|
||||
|
||||
define(
|
||||
["../src/ObjectHeaderController"],
|
||||
function (ObjectHeaderController) {
|
||||
["../src/ObjectHeaderController"],
|
||||
function (ObjectHeaderController) {
|
||||
|
||||
describe("The object header controller", function () {
|
||||
var mockScope,
|
||||
mockDomainObject,
|
||||
mockCapabilities,
|
||||
mockMutationCapability,
|
||||
mockTypeCapability,
|
||||
mockEvent,
|
||||
mockCurrentTarget,
|
||||
model,
|
||||
controller;
|
||||
describe("The object header controller", function () {
|
||||
var mockScope,
|
||||
mockDomainObject,
|
||||
mockMutationCapability,
|
||||
mockEvent,
|
||||
mockCurrentTarget,
|
||||
controller;
|
||||
|
||||
beforeEach(function () {
|
||||
mockMutationCapability = jasmine.createSpyObj("mutation", ["mutate"]);
|
||||
mockTypeCapability = jasmine.createSpyObj("type", ["typeDef", "hasFeature"]);
|
||||
mockTypeCapability.typeDef = { name: ""};
|
||||
mockTypeCapability.hasFeature.andCallFake(function (feature) {
|
||||
return feature === 'creation';
|
||||
});
|
||||
function getModel() {
|
||||
return {
|
||||
name: 'Test name'
|
||||
};
|
||||
}
|
||||
|
||||
mockCapabilities = {
|
||||
mutation: mockMutationCapability,
|
||||
type: mockTypeCapability
|
||||
};
|
||||
beforeEach(function () {
|
||||
mockMutationCapability = jasmine.createSpyObj("mutation", ["mutate"]);
|
||||
|
||||
model = {
|
||||
name: "Test name"
|
||||
};
|
||||
mockDomainObject = jasmine.createSpyObj("domainObject", ["getCapability", "getModel"]);
|
||||
mockDomainObject.getModel.andReturn(model);
|
||||
mockDomainObject.getCapability.andCallFake(function (key) {
|
||||
return mockCapabilities[key];
|
||||
});
|
||||
mockDomainObject = jasmine.createSpyObj("domainObject", ["getCapability", "model"]);
|
||||
mockDomainObject.model = getModel();
|
||||
mockDomainObject.getCapability.andReturn(mockMutationCapability);
|
||||
|
||||
mockScope = {
|
||||
domainObject: mockDomainObject
|
||||
};
|
||||
mockScope = jasmine.createSpyObj("$scope", ["name"]);
|
||||
mockScope.domainObject = mockDomainObject;
|
||||
|
||||
mockCurrentTarget = jasmine.createSpyObj("currentTarget", ["blur", "textContent"]);
|
||||
mockCurrentTarget.blur.andReturn(mockCurrentTarget);
|
||||
mockCurrentTarget = jasmine.createSpyObj("currentTarget", ["blur"]);
|
||||
mockCurrentTarget.blur.andReturn({ blur: function () {} });
|
||||
|
||||
mockEvent = {
|
||||
which: {},
|
||||
type: {},
|
||||
currentTarget: mockCurrentTarget
|
||||
};
|
||||
mockEvent = jasmine.createSpyObj('event', ["which"]);
|
||||
mockEvent.currentTarget = mockCurrentTarget;
|
||||
|
||||
controller = new ObjectHeaderController(mockScope);
|
||||
});
|
||||
controller = new ObjectHeaderController(mockScope);
|
||||
});
|
||||
|
||||
it("updates the model with new name on blur", function () {
|
||||
mockEvent.type = "blur";
|
||||
mockCurrentTarget.textContent = "New name";
|
||||
controller.updateName(mockEvent);
|
||||
it("updates the model with new name", function () {
|
||||
mockScope.name = 'New name';
|
||||
controller.updateName();
|
||||
|
||||
expect(mockMutationCapability.mutate).toHaveBeenCalled();
|
||||
});
|
||||
expect(mockMutationCapability.mutate).toHaveBeenCalledWith(jasmine.any(Function));
|
||||
});
|
||||
|
||||
it("updates the model with a default for blank names", function () {
|
||||
mockEvent.type = "blur";
|
||||
mockCurrentTarget.textContent = "";
|
||||
controller.updateName(mockEvent);
|
||||
it("does not update the model for blank names", function () {
|
||||
mockScope.name = "";
|
||||
controller.updateName();
|
||||
|
||||
expect(mockCurrentTarget.textContent.length).not.toEqual(0);
|
||||
expect(mockMutationCapability.mutate).toHaveBeenCalled();
|
||||
});
|
||||
expect(mockMutationCapability.mutate).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("does not update the model if the same name", function () {
|
||||
mockEvent.type = "blur";
|
||||
mockCurrentTarget.textContent = mockDomainObject.getModel().name;
|
||||
controller.updateName(mockEvent);
|
||||
it("updates the model on enter keypress event only", function () {
|
||||
mockScope.name = 'New name';
|
||||
controller.updateName(mockEvent);
|
||||
|
||||
expect(mockMutationCapability.mutate).not.toHaveBeenCalled();
|
||||
});
|
||||
expect(mockMutationCapability.mutate).not.toHaveBeenCalled();
|
||||
|
||||
it("updates the model on enter keypress event only", function () {
|
||||
mockCurrentTarget.textContent = "New name";
|
||||
controller.updateName(mockEvent);
|
||||
mockEvent.which = 13;
|
||||
controller.updateName(mockEvent);
|
||||
|
||||
expect(mockMutationCapability.mutate).not.toHaveBeenCalled();
|
||||
expect(mockMutationCapability.mutate).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
mockEvent.which = 13;
|
||||
controller.updateName(mockEvent);
|
||||
it("blurs the field on enter key press", function () {
|
||||
mockEvent.which = 13;
|
||||
controller.updateName(mockEvent);
|
||||
|
||||
expect(mockMutationCapability.mutate).toHaveBeenCalledWith(jasmine.any(Function));
|
||||
|
||||
mockMutationCapability.mutate.mostRecentCall.args[0](model);
|
||||
|
||||
expect(mockDomainObject.getModel().name).toBe("New name");
|
||||
});
|
||||
|
||||
it("blurs the field on enter key press", function () {
|
||||
mockCurrentTarget.textContent = "New name";
|
||||
mockEvent.which = 13;
|
||||
controller.updateName(mockEvent);
|
||||
|
||||
expect(mockEvent.currentTarget.blur).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("allows editting name when object is creatable", function () {
|
||||
expect(controller.allowEdit()).toBe(true);
|
||||
});
|
||||
|
||||
it("disallows editting name when object is non-creatable", function () {
|
||||
mockTypeCapability.hasFeature.andReturn(false);
|
||||
|
||||
expect(controller.allowEdit()).toBe(false);
|
||||
|
||||
});
|
||||
});
|
||||
}
|
||||
expect(mockEvent.currentTarget.blur).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
<div class="abs top-bar">
|
||||
<div class="dialog-title">{{ngModel.title}}</div>
|
||||
<div class="title">{{ngModel.title}}</div>
|
||||
<div class="hint">All fields marked <span class="req icon-asterisk"></span> are required.</div>
|
||||
</div>
|
||||
<div class='abs editor'>
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
<div class="l-message"
|
||||
ng-class="'message-severity-' + ngModel.severity">
|
||||
<div class="w-message-contents">
|
||||
<div class="ui-symbol type-icon message-type"></div>
|
||||
<div class="message-contents">
|
||||
<div class="top-bar">
|
||||
<div class="title">{{ngModel.title}}</div>
|
||||
<div class="hint" ng-hide="ngModel.hint === undefined">{{ngModel.hint}}</div>
|
||||
</div>
|
||||
<div class="hint" ng-hide="ngModel.hint === undefined">{{ngModel.hint}}</div>
|
||||
<div class="message-body">
|
||||
<div class="message-action">
|
||||
{{ngModel.actionText}}
|
||||
@@ -24,6 +25,8 @@
|
||||
ng-click="ngModel.primaryOption.callback()">
|
||||
{{ngModel.primaryOption.label}}
|
||||
</a>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
<mct-container key="overlay">
|
||||
<div class="t-message-list">
|
||||
<div class="top-bar">
|
||||
<div class="dialog-title">{{ngModel.dialog.title}}</div>
|
||||
<mct-container key="overlay" class="t-message-list">
|
||||
<div class="message-contents">
|
||||
<div class="abs top-bar">
|
||||
<div class="title">{{ngModel.dialog.title}}</div>
|
||||
<div class="hint">Displaying {{ngModel.dialog.messages.length}} message<span ng-show="ngModel.dialog.messages.length > 1 ||
|
||||
ngModel.dialog.messages.length == 0">s</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-messages">
|
||||
<div class="abs message-body">
|
||||
<mct-include
|
||||
ng-repeat="msg in ngModel.dialog.messages | orderBy: '-'"
|
||||
key="'message'" ng-model="msg.model"></mct-include>
|
||||
ng-repeat="msg in ngModel.dialog.messages | orderBy: '-'"
|
||||
key="'message'" ng-model="msg.model"></mct-include>
|
||||
</div>
|
||||
<div class="bottom-bar">
|
||||
<div class="abs bottom-bar">
|
||||
<a ng-repeat="dialogAction in ngModel.dialog.actions"
|
||||
class="s-button major"
|
||||
ng-click="dialogAction.action()">
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
-->
|
||||
<mct-container key="overlay">
|
||||
<div class="abs top-bar">
|
||||
<div class="dialog-title">{{ngModel.dialog.title}}</div>
|
||||
<div class="title">{{ngModel.dialog.title}}</div>
|
||||
<div class="hint">{{ngModel.dialog.hint}}</div>
|
||||
</div>
|
||||
<div class='abs editor'>
|
||||
|
||||
@@ -121,8 +121,7 @@ define([
|
||||
"key": "ElementsController",
|
||||
"implementation": ElementsController,
|
||||
"depends": [
|
||||
"$scope",
|
||||
"openmct"
|
||||
"$scope"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -300,6 +299,9 @@ define([
|
||||
{
|
||||
"key": "edit-elements",
|
||||
"template": elementsTemplate,
|
||||
"uses": [
|
||||
"composition"
|
||||
],
|
||||
"gestures": [
|
||||
"drop"
|
||||
]
|
||||
@@ -383,10 +385,7 @@ define([
|
||||
]
|
||||
},
|
||||
{
|
||||
"implementation": EditToolbarRepresenter,
|
||||
"depends": [
|
||||
"openmct"
|
||||
]
|
||||
"implementation": EditToolbarRepresenter
|
||||
}
|
||||
],
|
||||
"constants": [
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
<div class="s-menu-button major create-button" ng-click="createController.toggle()">
|
||||
<span class="title-label">Create</span>
|
||||
</div>
|
||||
<div class="menu super-menu l-create-menu" ng-show="createController.isActive()">
|
||||
<div class="menu super-menu" ng-show="createController.isActive()">
|
||||
<mct-representation mct-object="domainObject" key="'create-menu'">
|
||||
</mct-representation>
|
||||
</div>
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
this source code distribution or the Licensing information page available
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
<div class="w-menu" ng-controller="CreateMenuController">
|
||||
<div class="col menu-items">
|
||||
<div class="contents" ng-controller="CreateMenuController">
|
||||
<div class="pane left menu-items">
|
||||
<ul>
|
||||
<li ng-repeat="createAction in createActions" ng-click="createAction.perform()">
|
||||
<a ng-mouseover="representation.activeMetadata = createAction.getMetadata()"
|
||||
@@ -31,15 +31,13 @@
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col menu-item-description">
|
||||
<div class="pane right menu-item-description">
|
||||
<div class="desc-area icon {{ representation.activeMetadata.cssClass }}"></div>
|
||||
<div class="w-title-desc">
|
||||
<div class="desc-area title">
|
||||
{{representation.activeMetadata.name}}
|
||||
</div>
|
||||
<div class="desc-area description">
|
||||
{{representation.activeMetadata.description}}
|
||||
</div>
|
||||
<div class="desc-area title">
|
||||
{{representation.activeMetadata.name}}
|
||||
</div>
|
||||
<div class="desc-area description">
|
||||
{{representation.activeMetadata.description}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -61,12 +61,7 @@
|
||||
<mct-representation key="representation.selected.key"
|
||||
mct-object="representation.selected.key && domainObject"
|
||||
class="abs flex-elem grows object-holder-main scroll"
|
||||
toolbar="toolbar"
|
||||
mct-selectable="{
|
||||
item: domainObject.useCapability('adapter'),
|
||||
oldItem: domainObject
|
||||
}"
|
||||
mct-init-select>
|
||||
toolbar="toolbar">
|
||||
</mct-representation>
|
||||
</div><!--/ l-object-wrapper-inner -->
|
||||
</div>
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
ng-model="filterBy">
|
||||
</mct-include>
|
||||
<div class="flex-elem grows vscroll">
|
||||
<ul class="tree" ng-if="composition.length > 0">
|
||||
<ul class="tree">
|
||||
<li ng-repeat="containedObject in composition | filter:searchElements">
|
||||
<span class="tree-item">
|
||||
<mct-representation
|
||||
@@ -36,6 +36,5 @@
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
<div ng-if="composition.length === 0">No contained elements</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -101,15 +101,10 @@ define(
|
||||
*/
|
||||
EditorCapability.prototype.finish = function () {
|
||||
var domainObject = this.domainObject;
|
||||
|
||||
if (this.transactionService.isActive()) {
|
||||
return this.transactionService.cancel().then(function () {
|
||||
domainObject.getCapability("status").set("editing", false);
|
||||
return domainObject;
|
||||
});
|
||||
} else {
|
||||
return Promise.resolve(domainObject);
|
||||
}
|
||||
return this.transactionService.cancel().then(function () {
|
||||
domainObject.getCapability("status").set("editing", false);
|
||||
return domainObject;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -28,6 +28,16 @@ define(
|
||||
[],
|
||||
function () {
|
||||
|
||||
function isDirty(domainObject) {
|
||||
var navigatedObject = domainObject,
|
||||
editorCapability = navigatedObject &&
|
||||
navigatedObject.getCapability("editor");
|
||||
|
||||
return editorCapability &&
|
||||
editorCapability.isEditContextRoot() &&
|
||||
editorCapability.dirty();
|
||||
}
|
||||
|
||||
function cancelEditing(domainObject) {
|
||||
var navigatedObject = domainObject,
|
||||
editorCapability = navigatedObject &&
|
||||
@@ -49,7 +59,10 @@ define(
|
||||
|
||||
var removeCheck = navigationService
|
||||
.checkBeforeNavigation(function () {
|
||||
return "Continuing will cause the loss of any unsaved changes.";
|
||||
if (isDirty(domainObject)) {
|
||||
return "Continuing will cause the loss of any unsaved changes.";
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
$scope.$on('$destroy', function () {
|
||||
|
||||
@@ -29,11 +29,7 @@ define(
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
function ElementsController($scope, openmct) {
|
||||
this.scope = $scope;
|
||||
this.scope.composition = [];
|
||||
var self = this;
|
||||
|
||||
function ElementsController($scope) {
|
||||
function filterBy(text) {
|
||||
if (typeof text === 'undefined') {
|
||||
return $scope.searchText;
|
||||
@@ -51,45 +47,10 @@ define(
|
||||
}
|
||||
}
|
||||
|
||||
function setSelection(selection) {
|
||||
self.scope.selection = selection;
|
||||
self.refreshComposition(selection);
|
||||
}
|
||||
|
||||
$scope.filterBy = filterBy;
|
||||
$scope.searchElements = searchElements;
|
||||
|
||||
openmct.selection.on('change', setSelection);
|
||||
setSelection(openmct.selection.get());
|
||||
|
||||
$scope.$on("$destroy", function () {
|
||||
openmct.selection.off("change", setSelection);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the composition for the selected object and populates the scope with it.
|
||||
*
|
||||
* @param selection the selection object
|
||||
* @private
|
||||
*/
|
||||
ElementsController.prototype.refreshComposition = function (selection) {
|
||||
if (!selection[0]) {
|
||||
return;
|
||||
}
|
||||
|
||||
var selected = selection[0].context.oldItem;
|
||||
var selectedObjectComposition = selected && selected.useCapability('composition');
|
||||
|
||||
if (selectedObjectComposition) {
|
||||
selectedObjectComposition.then(function (composition) {
|
||||
this.scope.composition = composition;
|
||||
}.bind(this));
|
||||
} else {
|
||||
this.scope.composition = [];
|
||||
}
|
||||
};
|
||||
|
||||
return ElementsController;
|
||||
}
|
||||
);
|
||||
|
||||
@@ -38,7 +38,7 @@ define(
|
||||
* @constructor
|
||||
* @implements {Representer}
|
||||
*/
|
||||
function EditToolbarRepresenter(openmct, scope, element, attrs) {
|
||||
function EditToolbarRepresenter(scope, element, attrs) {
|
||||
var self = this;
|
||||
|
||||
// Mark changes as ready to persist
|
||||
@@ -109,7 +109,6 @@ define(
|
||||
this.updateSelection = updateSelection;
|
||||
this.toolbar = undefined;
|
||||
this.toolbarObject = {};
|
||||
this.openmct = openmct;
|
||||
|
||||
// If this representation exposes a toolbar, set up watches
|
||||
// to synchronize with it.
|
||||
@@ -147,7 +146,7 @@ define(
|
||||
// Expose the toolbar object to the parent scope
|
||||
initialize(definition);
|
||||
// Create a selection scope
|
||||
this.setSelection(new EditToolbarSelection(this.openmct));
|
||||
this.setSelection(new EditToolbarSelection());
|
||||
// Initialize toolbar to an empty selection
|
||||
this.updateSelection([]);
|
||||
};
|
||||
|
||||
@@ -38,24 +38,10 @@ define(
|
||||
* @memberof platform/commonUI/edit
|
||||
* @constructor
|
||||
*/
|
||||
function EditToolbarSelection(openmct) {
|
||||
function EditToolbarSelection() {
|
||||
this.selection = [{}];
|
||||
this.selecting = false;
|
||||
this.selectedObj = undefined;
|
||||
|
||||
openmct.selection.on('change', function (selection) {
|
||||
var selected = selection[0];
|
||||
|
||||
if (selected && selected.context.toolbar) {
|
||||
this.select(selected.context.toolbar);
|
||||
} else {
|
||||
this.deselect();
|
||||
}
|
||||
|
||||
if (selected && selected.context.viewProxy) {
|
||||
this.proxy(selected.context.viewProxy);
|
||||
}
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -62,7 +62,6 @@ define(
|
||||
);
|
||||
mockTransactionService.commit.andReturn(fastPromise());
|
||||
mockTransactionService.cancel.andReturn(fastPromise());
|
||||
mockTransactionService.isActive = jasmine.createSpy('isActive');
|
||||
|
||||
mockStatusCapability = jasmine.createSpyObj(
|
||||
"statusCapability",
|
||||
@@ -142,7 +141,6 @@ define(
|
||||
|
||||
describe("finish", function () {
|
||||
beforeEach(function () {
|
||||
mockTransactionService.isActive.andReturn(true);
|
||||
capability.edit();
|
||||
capability.finish();
|
||||
});
|
||||
@@ -154,23 +152,6 @@ define(
|
||||
});
|
||||
});
|
||||
|
||||
describe("finish", function () {
|
||||
beforeEach(function () {
|
||||
mockTransactionService.isActive.andReturn(false);
|
||||
capability.edit();
|
||||
});
|
||||
|
||||
it("does not cancel transaction when transaction is not active", function () {
|
||||
capability.finish();
|
||||
expect(mockTransactionService.cancel).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("returns a promise", function () {
|
||||
expect(capability.finish() instanceof Promise).toBe(true);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe("dirty", function () {
|
||||
var model = {};
|
||||
|
||||
|
||||
@@ -104,10 +104,10 @@ define(
|
||||
mockEditorCapability.isEditContextRoot.andReturn(false);
|
||||
mockEditorCapability.dirty.andReturn(false);
|
||||
|
||||
expect(checkFn()).toBe("Continuing will cause the loss of any unsaved changes.");
|
||||
expect(checkFn()).toBe(false);
|
||||
|
||||
mockEditorCapability.isEditContextRoot.andReturn(true);
|
||||
expect(checkFn()).toBe("Continuing will cause the loss of any unsaved changes.");
|
||||
expect(checkFn()).toBe(false);
|
||||
|
||||
mockEditorCapability.dirty.andReturn(true);
|
||||
expect(checkFn())
|
||||
|
||||
@@ -27,23 +27,11 @@ define(
|
||||
|
||||
describe("The Elements Pane controller", function () {
|
||||
var mockScope,
|
||||
mockOpenMCT,
|
||||
mockSelection,
|
||||
controller;
|
||||
|
||||
beforeEach(function () {
|
||||
mockScope = jasmine.createSpyObj("$scope", ['$on']);
|
||||
mockSelection = jasmine.createSpyObj("selection", [
|
||||
'on',
|
||||
'off',
|
||||
'get'
|
||||
]);
|
||||
mockSelection.get.andReturn([]);
|
||||
mockOpenMCT = {
|
||||
selection: mockSelection
|
||||
};
|
||||
|
||||
controller = new ElementsController(mockScope, mockOpenMCT);
|
||||
mockScope = jasmine.createSpy("$scope");
|
||||
controller = new ElementsController(mockScope);
|
||||
});
|
||||
|
||||
function getModel(model) {
|
||||
|
||||
@@ -29,9 +29,7 @@ define(
|
||||
mockElement,
|
||||
testAttrs,
|
||||
mockUnwatch,
|
||||
representer,
|
||||
mockOpenMCT,
|
||||
mockSelection;
|
||||
representer;
|
||||
|
||||
beforeEach(function () {
|
||||
mockScope = jasmine.createSpyObj(
|
||||
@@ -48,18 +46,7 @@ define(
|
||||
|
||||
mockScope.$parent.$watchCollection.andReturn(mockUnwatch);
|
||||
|
||||
mockSelection = jasmine.createSpyObj("selection", [
|
||||
'on',
|
||||
'off',
|
||||
'get'
|
||||
]);
|
||||
mockSelection.get.andReturn([]);
|
||||
mockOpenMCT = {
|
||||
selection: mockSelection
|
||||
};
|
||||
|
||||
representer = new EditToolbarRepresenter(
|
||||
mockOpenMCT,
|
||||
mockScope,
|
||||
mockElement,
|
||||
testAttrs
|
||||
|
||||
@@ -28,25 +28,13 @@ define(
|
||||
var testProxy,
|
||||
testElement,
|
||||
otherElement,
|
||||
selection,
|
||||
mockSelection,
|
||||
mockOpenMCT;
|
||||
selection;
|
||||
|
||||
beforeEach(function () {
|
||||
testProxy = { someKey: "some value" };
|
||||
testElement = { someOtherKey: "some other value" };
|
||||
otherElement = { yetAnotherKey: 42 };
|
||||
mockSelection = jasmine.createSpyObj("selection", [
|
||||
// 'select',
|
||||
'on',
|
||||
'off',
|
||||
'get'
|
||||
]);
|
||||
mockSelection.get.andReturn([]);
|
||||
mockOpenMCT = {
|
||||
selection: mockSelection
|
||||
};
|
||||
selection = new EditToolbarSelection(mockOpenMCT);
|
||||
selection = new EditToolbarSelection();
|
||||
selection.proxy(testProxy);
|
||||
});
|
||||
|
||||
|
||||
@@ -121,9 +121,6 @@ define([
|
||||
};
|
||||
|
||||
UTCTimeFormat.prototype.parse = function (text) {
|
||||
if (typeof text === 'number') {
|
||||
return text;
|
||||
}
|
||||
return moment.utc(text, DATE_FORMATS).valueOf();
|
||||
};
|
||||
|
||||
|
||||
@@ -41,7 +41,6 @@ define([
|
||||
"./src/controllers/BannerController",
|
||||
"./src/directives/MCTContainer",
|
||||
"./src/directives/MCTDrag",
|
||||
"./src/directives/MCTSelectable",
|
||||
"./src/directives/MCTClickElsewhere",
|
||||
"./src/directives/MCTResize",
|
||||
"./src/directives/MCTPopup",
|
||||
@@ -91,7 +90,6 @@ define([
|
||||
BannerController,
|
||||
MCTContainer,
|
||||
MCTDrag,
|
||||
MCTSelectable,
|
||||
MCTClickElsewhere,
|
||||
MCTResize,
|
||||
MCTPopup,
|
||||
@@ -330,13 +328,6 @@ define([
|
||||
"$document"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "mctSelectable",
|
||||
"implementation": MCTSelectable,
|
||||
"depends": [
|
||||
"openmct"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "mctClickElsewhere",
|
||||
"implementation": MCTClickElsewhere,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"metadata": {
|
||||
"name": "openmct-symbols-16px",
|
||||
"lastOpened": 0,
|
||||
"created": 1506973656040
|
||||
"created": 1502487054429
|
||||
},
|
||||
"iconSets": [
|
||||
{
|
||||
@@ -636,29 +636,13 @@
|
||||
"code": 921670,
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 138,
|
||||
"id": 115,
|
||||
"name": "icon-import",
|
||||
"prevSize": 24,
|
||||
"code": 921671,
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 136,
|
||||
"id": 116,
|
||||
"name": "icon-export",
|
||||
"prevSize": 24,
|
||||
"code": 921672,
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 37,
|
||||
"prevSize": 24,
|
||||
"name": "icon-activity",
|
||||
"id": 32,
|
||||
"code": 921856,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 36,
|
||||
@@ -666,7 +650,7 @@
|
||||
"name": "icon-activity-mode",
|
||||
"id": 31,
|
||||
"code": 921857,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 52,
|
||||
@@ -674,7 +658,7 @@
|
||||
"name": "icon-autoflow-tabular",
|
||||
"id": 47,
|
||||
"code": 921858,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 55,
|
||||
@@ -682,7 +666,7 @@
|
||||
"name": "icon-clock",
|
||||
"id": 50,
|
||||
"code": 921859,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 58,
|
||||
@@ -690,7 +674,7 @@
|
||||
"name": "icon-database",
|
||||
"id": 53,
|
||||
"code": 921860,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 57,
|
||||
@@ -698,7 +682,7 @@
|
||||
"name": "icon-database-query",
|
||||
"id": 52,
|
||||
"code": 921861,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 17,
|
||||
@@ -706,7 +690,7 @@
|
||||
"name": "icon-dataset",
|
||||
"id": 12,
|
||||
"code": 921862,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 22,
|
||||
@@ -714,7 +698,7 @@
|
||||
"name": "icon-datatable",
|
||||
"id": 17,
|
||||
"code": 921863,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 59,
|
||||
@@ -722,7 +706,7 @@
|
||||
"name": "icon-dictionary",
|
||||
"id": 54,
|
||||
"code": 921864,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 62,
|
||||
@@ -730,7 +714,7 @@
|
||||
"name": "icon-folder",
|
||||
"id": 57,
|
||||
"code": 921865,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 66,
|
||||
@@ -738,7 +722,7 @@
|
||||
"name": "icon-image",
|
||||
"id": 61,
|
||||
"code": 921872,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 68,
|
||||
@@ -746,7 +730,7 @@
|
||||
"name": "icon-layout",
|
||||
"id": 63,
|
||||
"code": 921873,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 77,
|
||||
@@ -754,7 +738,7 @@
|
||||
"name": "icon-object",
|
||||
"id": 72,
|
||||
"code": 921874,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 78,
|
||||
@@ -762,7 +746,7 @@
|
||||
"name": "icon-object-unknown",
|
||||
"id": 73,
|
||||
"code": 921875,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 79,
|
||||
@@ -770,7 +754,7 @@
|
||||
"name": "icon-packet",
|
||||
"id": 74,
|
||||
"code": 921876,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 80,
|
||||
@@ -778,7 +762,7 @@
|
||||
"name": "icon-page",
|
||||
"id": 75,
|
||||
"code": 921877,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 135,
|
||||
@@ -786,7 +770,7 @@
|
||||
"name": "icon-plot-overlay",
|
||||
"prevSize": 24,
|
||||
"code": 921878,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 113,
|
||||
@@ -794,7 +778,7 @@
|
||||
"name": "icon-plot-stacked",
|
||||
"prevSize": 24,
|
||||
"code": 921879,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 10,
|
||||
@@ -802,7 +786,7 @@
|
||||
"name": "icon-session",
|
||||
"id": 5,
|
||||
"code": 921880,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 24,
|
||||
@@ -810,7 +794,7 @@
|
||||
"name": "icon-tabular",
|
||||
"id": 19,
|
||||
"code": 921881,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 7,
|
||||
@@ -818,7 +802,7 @@
|
||||
"name": "icon-tabular-lad",
|
||||
"id": 2,
|
||||
"code": 921888,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 6,
|
||||
@@ -826,7 +810,7 @@
|
||||
"name": "icon-tabular-lad-set",
|
||||
"id": 1,
|
||||
"code": 921889,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 8,
|
||||
@@ -834,7 +818,7 @@
|
||||
"name": "icon-tabular-realtime",
|
||||
"id": 3,
|
||||
"code": 921890,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 23,
|
||||
@@ -842,7 +826,7 @@
|
||||
"name": "icon-tabular-scrolling",
|
||||
"id": 18,
|
||||
"code": 921891,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 112,
|
||||
@@ -850,7 +834,7 @@
|
||||
"name": "icon-telemetry",
|
||||
"id": 86,
|
||||
"code": 921892,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 90,
|
||||
@@ -858,7 +842,7 @@
|
||||
"name": "icon-telemetry-panel",
|
||||
"id": 85,
|
||||
"code": 921893,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 93,
|
||||
@@ -866,7 +850,7 @@
|
||||
"name": "icon-timeline",
|
||||
"id": 88,
|
||||
"code": 921894,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 116,
|
||||
@@ -874,7 +858,7 @@
|
||||
"name": "icon-timer-v1.5",
|
||||
"prevSize": 24,
|
||||
"code": 921895,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 11,
|
||||
@@ -882,7 +866,7 @@
|
||||
"name": "icon-topic",
|
||||
"id": 6,
|
||||
"code": 921896,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 115,
|
||||
@@ -890,7 +874,7 @@
|
||||
"name": "icon-box-with-dashed-lines",
|
||||
"id": 29,
|
||||
"code": 921897,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 126,
|
||||
@@ -898,15 +882,7 @@
|
||||
"name": "icon-summary-widget",
|
||||
"prevSize": 24,
|
||||
"code": 921904,
|
||||
"tempChar": ""
|
||||
},
|
||||
{
|
||||
"order": 139,
|
||||
"id": 117,
|
||||
"name": "icon-notebook",
|
||||
"prevSize": 24,
|
||||
"code": 921905,
|
||||
"tempChar": ""
|
||||
"tempChar": ""
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
@@ -2707,52 +2683,6 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 115,
|
||||
"paths": [
|
||||
"M832 192.4v639.4c0 0.2-0.2 0.2-0.4 0.4h-319.6v192h320c105.6 0 192-86.4 192-192v-640.2c0-105.6-86.4-192-192-192h-320v192h319.6c0.2 0 0.4 0.2 0.4 0.4z",
|
||||
"M192 704v192l384-384-384-384v192h-192v384z"
|
||||
],
|
||||
"attrs": [
|
||||
{},
|
||||
{}
|
||||
],
|
||||
"grid": 16,
|
||||
"tags": [
|
||||
"icon-import"
|
||||
],
|
||||
"isMulticolor": false,
|
||||
"isMulticolor2": false,
|
||||
"colorPermutations": {
|
||||
"1161751207457516161751": [
|
||||
{},
|
||||
{}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 116,
|
||||
"paths": [
|
||||
"M192 831.66v-639.32l0.34-0.34h319.66v-192h-320c-105.6 0-192 86.4-192 192v640c0 105.6 86.4 192 192 192h320v-192h-319.66z",
|
||||
"M1024 512l-384-384v192h-192v384h192v192l384-384z"
|
||||
],
|
||||
"attrs": [
|
||||
{},
|
||||
{}
|
||||
],
|
||||
"isMulticolor": false,
|
||||
"isMulticolor2": false,
|
||||
"grid": 16,
|
||||
"tags": [
|
||||
"icon-export"
|
||||
],
|
||||
"colorPermutations": {
|
||||
"1161751207457516161751": [
|
||||
{},
|
||||
{}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"paths": [
|
||||
"M576 64h-256l320 320h-290.256c-44.264-76.516-126.99-128-221.744-128h-128v512h128c94.754 0 177.48-51.484 221.744-128h290.256l-320 320h256l448-448-448-448z"
|
||||
@@ -3532,29 +3462,6 @@
|
||||
{}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 117,
|
||||
"paths": [
|
||||
"M896 110.8c0-79.8-55.4-127.4-123-105.4l-773 250.6h896v-145.2z",
|
||||
"M896 320h-896v576c0 70.4 57.6 128 128 128h768c70.4 0 128-57.6 128-128v-448c0-70.4-57.6-128-128-128zM832 832h-384v-320h384v320z"
|
||||
],
|
||||
"attrs": [
|
||||
{},
|
||||
{}
|
||||
],
|
||||
"isMulticolor": false,
|
||||
"isMulticolor2": false,
|
||||
"grid": 16,
|
||||
"tags": [
|
||||
"icon-notebook"
|
||||
],
|
||||
"colorPermutations": {
|
||||
"1161751207457516161751": [
|
||||
{},
|
||||
{}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"colorThemes": [
|
||||
|
||||
Binary file not shown.
@@ -85,8 +85,6 @@
|
||||
<glyph unicode="󡁄" glyph-name="icon-grid-snap-no" d="M768 384h192v-64h-192v64zM256 384h192v-64h-192v64zM0 384h192v-64h-192v64zM640 448h-64v-64h-64v-64h64v-64h64v64h64v64h-64zM576 704h64v-192h-64v192zM576 960h64v-192h-64v192zM576 192h64v-192h-64v192z" />
|
||||
<glyph unicode="󡁅" glyph-name="icon-frame-show" d="M0 896v-896h1024v896h-1024zM896 128h-768v640h768v-640zM192 704h384v-128h-384v128z" />
|
||||
<glyph unicode="󡁆" glyph-name="icon-frame-hide" d="M128 770h420l104 128h-652v-802.4l128 157.4zM896 130h-420l-104-128h652v802.4l-128-157.4zM832 962l-832-1024h192l832 1024zM392 578l104 128h-304v-128z" />
|
||||
<glyph unicode="󡁇" glyph-name="icon-import" d="M832 767.6v-639.4c0-0.2-0.2-0.2-0.4-0.4h-319.6v-192h320c105.6 0 192 86.4 192 192v640.2c0 105.6-86.4 192-192 192h-320v-192h319.6c0.2 0 0.4-0.2 0.4-0.4zM192 256v-192l384 384-384 384v-192h-192v-384z" />
|
||||
<glyph unicode="󡁈" glyph-name="icon-export" d="M192 128.34v639.32l0.34 0.34h319.66v192h-320c-105.6 0-192-86.4-192-192v-640c0-105.6 86.4-192 192-192h320v192h-319.66zM1024 448l-384 384v-192h-192v-384h192v-192l384 384z" />
|
||||
<glyph unicode="󡄀" glyph-name="icon-activity" d="M576 896h-256l320-320h-290.256c-44.264 76.516-126.99 128-221.744 128h-128v-512h128c94.754 0 177.48 51.484 221.744 128h290.256l-320-320h256l448 448-448 448z" />
|
||||
<glyph unicode="󡄁" glyph-name="icon-activity-mode" d="M512 960c-214.866 0-398.786-132.372-474.744-320h90.744c56.86 0 107.938-24.724 143.094-64h240.906l-192 192h256l320-320-320-320h-256l192 192h-240.906c-35.156-39.276-86.234-64-143.094-64h-90.744c75.958-187.628 259.878-320 474.744-320 282.77 0 512 229.23 512 512s-229.23 512-512 512z" />
|
||||
<glyph unicode="󡄂" glyph-name="icon-autoflow-tabular" d="M192 960c-105.6 0-192-86.4-192-192v-640c0-105.6 86.4-192 192-192h64v1024h-64zM384 960h256v-1024h-256v1024zM832 960h-64v-704h256v512c0 105.6-86.4 192-192 192z" />
|
||||
@@ -118,5 +116,4 @@
|
||||
<glyph unicode="󡄨" glyph-name="icon-topic" d="M454.36 483.36l86.3 86.3c9.088 8.965 21.577 14.502 35.36 14.502s26.272-5.537 35.366-14.507l86.294-86.294c19.328-19.358 42.832-34.541 69.047-44.082l1.313 171.722-57.64 57.64c-34.407 34.33-81.9 55.558-134.35 55.558s-99.943-21.228-134.354-55.562l-86.296-86.297c-9.088-8.965-21.577-14.502-35.36-14.502s-26.272 5.537-35.366 14.507l-28.674 28.654v-172.14c19.045-7.022 41.040-11.084 63.984-11.084 52.463 0 99.966 21.239 134.379 55.587zM505.64 412.64l-86.3-86.3c-9.088-8.965-21.577-14.502-35.36-14.502s-26.272 5.537-35.366 14.507l-86.294 86.294c-2 2-4.2 4-6.36 6v-197.36c33.664-30.72 78.65-49.537 128.031-49.537 52.44 0 99.923 21.22 134.333 55.541l86.296 86.296c9.088 8.965 21.577 14.502 35.36 14.502s26.272-5.537 35.366-14.507l86.294-86.294c2-2 4.2-4 6.36-6v197.36c-33.664 30.72-78.65 49.537-128.031 49.537-52.44 0-99.923-21.22-134.333-55.541zM832 960h-128v-192h127.66l0.34-0.34v-639.32l-0.34-0.34h-127.66v-192h128c105.6 0 192 86.4 192 192v640c0 105.6-86.4 192-192 192zM320 128h-127.66l-0.34 0.34v639.32l0.34 0.34h127.66v192h-128c-105.6 0-192-86.4-192-192v-640c0-105.6 86.4-192 192-192h128v192z" />
|
||||
<glyph unicode="󡄩" glyph-name="icon-box-with-dashed-lines" d="M0 576h128v-256h-128v256zM128 831.78l0.22 0.22h191.78v128h-192c-70.606-0.215-127.785-57.394-128-127.979v-192.021h128v191.78zM128 64.22v191.78h-128v-192c0.215-70.606 57.394-127.785 127.979-128h192.021v128h-191.78zM384 960h256v-128h-256v128zM896 64.22l-0.22-0.22h-191.78v-128h192c70.606 0.215 127.785 57.394 128 127.979v192.021h-128v-191.78zM896 960h-192v-128h191.78l0.22-0.22v-191.78h128v192c-0.215 70.606-57.394 127.785-127.979 128zM896 576h128v-256h-128v256zM384 64h256v-128h-256v128zM256 704h512v-512h-512v512z" />
|
||||
<glyph unicode="󡄰" glyph-name="icon-summary-widget" d="M896 960h-768c-70.4 0-128-57.6-128-128v-768c0-70.4 57.6-128 128-128h768c70.4 0 128 57.6 128 128v768c0 70.4-57.6 128-128 128zM847.8 349.6l-82.6-143.2-189.6 131.6 19.2-230h-165.4l19.2 230-189.6-131.6-82.6 143.2 208.6 98.4-208.8 98.4 82.6 143.2 189.6-131.6-19.2 230h165.4l-19.2-230 189.6 131.6 82.6-143.2-208.6-98.4 208.8-98.4z" />
|
||||
<glyph unicode="󡄱" glyph-name="icon-notebook" d="M896 849.2c0 79.8-55.4 127.4-123 105.4l-773-250.6h896v145.2zM896 640h-896v-576c0-70.4 57.6-128 128-128h768c70.4 0 128 57.6 128 128v448c0 70.4-57.6 128-128 128zM832 128h-384v320h384v-320z" />
|
||||
</font></defs></svg>
|
||||
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 43 KiB |
Binary file not shown.
Binary file not shown.
@@ -137,11 +137,6 @@
|
||||
min-height: 0;
|
||||
&.holder:not(:last-child) { margin-bottom: $interiorMarginLg; }
|
||||
}
|
||||
&.l-flex-accordion .flex-accordion-holder {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
//overflow: hidden !important;
|
||||
}
|
||||
.flex-container { @include flex-direction(column); }
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
*****************************************************************************/
|
||||
|
||||
/************************** FEATURES */
|
||||
$enableImageryThumbs: true; // Set to true if historical imagery thumbnails are supported
|
||||
$enableImageryThumbs: false; // Set to true if historical imagery thumbnails are supported
|
||||
|
||||
/************************** VERY INFLUENTIAL GLOBAL DIMENSIONS */
|
||||
$bodyMargin: 10px;
|
||||
@@ -82,7 +82,7 @@ $tabularTdPadTB: 2px;
|
||||
/*************** Imagery */
|
||||
$imageMainControlBarH: 25px;
|
||||
$imageThumbsD: 120px;
|
||||
$imageThumbsWrapperH: 155px;
|
||||
$imageThumbsWrapperH: $imageThumbsD * 1.4;
|
||||
$imageThumbPad: 1px;
|
||||
/*************** Ticks */
|
||||
$ticksH: 25px;
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
}
|
||||
|
||||
.l-fixed-position-item {
|
||||
border-width: 1px;
|
||||
position: absolute;
|
||||
&.s-not-selected {
|
||||
opacity: 0.8;
|
||||
@@ -53,7 +52,6 @@
|
||||
font-size: 0.8rem;
|
||||
$p: 1px;
|
||||
line-height: 100%;
|
||||
overflow: hidden;
|
||||
&.l-static-text {
|
||||
padding: $p;
|
||||
}
|
||||
|
||||
@@ -180,20 +180,6 @@ a.disabled {
|
||||
@include ellipsize();
|
||||
}
|
||||
|
||||
.no-selection {
|
||||
// aka selection = "None". Used in palettes and their menu buttons.
|
||||
$c: red; $s: 48%; $e: 52%;
|
||||
@include background-image(linear-gradient(-45deg,
|
||||
transparent $s - 5%,
|
||||
$c $s,
|
||||
$c $e,
|
||||
transparent $e + 5%
|
||||
));
|
||||
background-repeat: no-repeat;
|
||||
background-size: contain;
|
||||
}
|
||||
|
||||
|
||||
.scrolling,
|
||||
.scroll {
|
||||
overflow: auto;
|
||||
|
||||
@@ -113,8 +113,6 @@ $glyph-icon-grid-snap-to: '\e1043';
|
||||
$glyph-icon-grid-snap-no: '\e1044';
|
||||
$glyph-icon-frame-show: '\e1045';
|
||||
$glyph-icon-frame-hide: '\e1046';
|
||||
$glyph-icon-import: '\e1047';
|
||||
$glyph-icon-export: '\e1048';
|
||||
$glyph-icon-activity: '\e1100';
|
||||
$glyph-icon-activity-mode: '\e1101';
|
||||
$glyph-icon-autoflow-tabular: '\e1102';
|
||||
@@ -146,7 +144,6 @@ $glyph-icon-timer: '\e1127';
|
||||
$glyph-icon-topic: '\e1128';
|
||||
$glyph-icon-box-with-dashed-lines: '\e1129';
|
||||
$glyph-icon-summary-widget: '\e1130';
|
||||
$glyph-icon-notebook: '\e1131';
|
||||
|
||||
/************************** 16 PX CLASSES */
|
||||
|
||||
@@ -228,8 +225,6 @@ $glyph-icon-notebook: '\e1131';
|
||||
.icon-grid-snap-no { @include glyphBefore($glyph-icon-grid-snap-no); }
|
||||
.icon-frame-show { @include glyphBefore($glyph-icon-frame-show); }
|
||||
.icon-frame-hide { @include glyphBefore($glyph-icon-frame-hide); }
|
||||
.icon-import { @include glyphBefore($glyph-icon-import); }
|
||||
.icon-export { @include glyphBefore($glyph-icon-export); }
|
||||
.icon-activity { @include glyphBefore($glyph-icon-activity); }
|
||||
.icon-activity-mode { @include glyphBefore($glyph-icon-activity-mode); }
|
||||
.icon-autoflow-tabular { @include glyphBefore($glyph-icon-autoflow-tabular); }
|
||||
@@ -261,7 +256,6 @@ $glyph-icon-notebook: '\e1131';
|
||||
.icon-topic { @include glyphBefore($glyph-icon-topic); }
|
||||
.icon-box-with-dashed-lines { @include glyphBefore($glyph-icon-box-with-dashed-lines); }
|
||||
.icon-summary-widget { @include glyphBefore($glyph-icon-summary-widget); }
|
||||
.icon-notebook { @include glyphBefore($glyph-icon-notebook); }
|
||||
|
||||
/************************** 12 PX CLASSES */
|
||||
.icon-crosshair-12px { @include glyphBefore($glyph-icon-crosshair,'symbolsfont-12px'); }
|
||||
|
||||
@@ -26,6 +26,5 @@
|
||||
display: block;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
/********************************* CONTROLS */
|
||||
@import "controls/breadcrumb";
|
||||
@import "controls/buttons";
|
||||
@import "controls/palette";
|
||||
@import "controls/color-palette";
|
||||
@import "controls/controls";
|
||||
@import "controls/lists";
|
||||
@import "controls/menus";
|
||||
@@ -80,4 +80,3 @@
|
||||
@import "autoflow";
|
||||
@import "features/imagery";
|
||||
@import "features/time-display";
|
||||
@import "widgets";
|
||||
|
||||
@@ -327,17 +327,14 @@
|
||||
}
|
||||
}
|
||||
|
||||
@mixin s-input($bg: $colorInputBg, $fg: $colorInputFg, $shdw: rgba(black, 0.6) 0 1px 3px) {
|
||||
@include input-base();
|
||||
@mixin nice-input($bg: $colorInputBg, $fg: $colorInputFg, $shdw: rgba(black, 0.6) 0 1px 3px) {
|
||||
@include input-base();
|
||||
background: $bg;
|
||||
box-shadow: inset $shdw;
|
||||
color: $fg;
|
||||
}
|
||||
|
||||
@mixin nice-input($bg: $colorInputBg, $fg: $colorInputFg, $shdw: rgba(black, 0.6) 0 1px 3px) {
|
||||
@include s-input($bg, $fg, $shdw);
|
||||
border: none;
|
||||
color: $fg;
|
||||
outline: none;
|
||||
padding: $inputTextPTopBtm $inputTextPLeftRight;
|
||||
}
|
||||
|
||||
@mixin contextArrow() {
|
||||
|
||||
@@ -50,6 +50,7 @@
|
||||
content:'';
|
||||
font-family: symbolsfont;
|
||||
font-size: 0.8em;
|
||||
display: inline;
|
||||
margin-right: $interiorMarginSm;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,306 +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.
|
||||
*****************************************************************************/
|
||||
|
||||
/************************************************************* WIDGET OBJECT */
|
||||
.l-summary-widget {
|
||||
// Widget layout classes here
|
||||
@include ellipsize();
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
.widget-label:before {
|
||||
// Widget icon
|
||||
font-size: 0.9em;
|
||||
margin-right: $interiorMarginSm;
|
||||
}
|
||||
}
|
||||
|
||||
.s-summary-widget {
|
||||
// Widget style classes here
|
||||
@include boxShdw($shdwBtns);
|
||||
border-radius: $basicCr;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
box-sizing: border-box;
|
||||
cursor: default;
|
||||
font-size: 0.8rem;
|
||||
padding: $interiorMarginLg $interiorMarginLg * 2;
|
||||
&[href] {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.widget-edit-holder {
|
||||
// Hide edit area when in browse mode
|
||||
display: none;
|
||||
}
|
||||
|
||||
.widget-rule-header {
|
||||
@extend .l-flex-row;
|
||||
@include align-items(center);
|
||||
margin-bottom: $interiorMargin;
|
||||
> .flex-elem {
|
||||
&:not(:first-child) {
|
||||
margin-left: $interiorMargin;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.widget-rules-wrapper,
|
||||
.widget-rule-content,
|
||||
.w-widget-test-data-content {
|
||||
@include trans-prop-nice($props: (height, min-height, opacity), $dur: 250ms);
|
||||
min-height: 0;
|
||||
height: 0;
|
||||
opacity: 0;
|
||||
overflow: hidden;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.widget-rules-wrapper {
|
||||
flex: 1 1 auto !important;
|
||||
}
|
||||
|
||||
.widget-rule-content.expanded {
|
||||
overflow: visible !important;
|
||||
min-height: 50px;
|
||||
height: auto;
|
||||
opacity: 1;
|
||||
pointer-events: inherit;
|
||||
}
|
||||
|
||||
.w-widget-test-data-content {
|
||||
.l-enable {
|
||||
padding: $interiorMargin 0;
|
||||
}
|
||||
|
||||
.w-widget-test-data-items {
|
||||
max-height: 20vh;
|
||||
overflow-y: scroll !important;
|
||||
padding-right: $interiorMargin;
|
||||
}
|
||||
}
|
||||
|
||||
.l-widget-thumb-wrapper,
|
||||
.l-compact-form label {
|
||||
$ruleLabelW: 40%;
|
||||
$ruleLabelMaxW: 150px;
|
||||
@include display(flex);
|
||||
max-width: $ruleLabelMaxW;
|
||||
width: $ruleLabelW;
|
||||
}
|
||||
|
||||
.t-message-widget-no-data {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/********************************************************** EDITING A WIDGET */
|
||||
.s-status-editing > mct-view > .w-summary-widget {
|
||||
// Classes for editor layout while editing a widget
|
||||
// This selector is ugly and brittle, but needed to prevent interface from showing when widget is in a layout
|
||||
// being edited.
|
||||
@include absPosDefault();
|
||||
@extend .l-flex-col;
|
||||
|
||||
> .l-summary-widget {
|
||||
// Main view of the summary widget
|
||||
// Give some airspace and center the widget in the area
|
||||
margin: 30px auto;
|
||||
}
|
||||
|
||||
.widget-edit-holder {
|
||||
display: flex; // Overrides `display: none` during Browse mode
|
||||
.flex-accordion-holder {
|
||||
// Needed because otherwise accordion elements "creep" when contents expand and contract
|
||||
display: block !important;
|
||||
}
|
||||
&.expanded-widget-test-data {
|
||||
.w-widget-test-data-content {
|
||||
min-height: 50px;
|
||||
height: auto;
|
||||
opacity: 1;
|
||||
pointer-events: inherit;
|
||||
}
|
||||
&:not(.expanded-widget-rules) {
|
||||
// Test data is expanded and rules are collapsed
|
||||
// Make text data take up all the vertical space
|
||||
.flex-accordion-holder { display: flex; }
|
||||
.widget-test-data {
|
||||
flex-grow: 999999;
|
||||
}
|
||||
.w-widget-test-data-items {
|
||||
max-height: inherit;
|
||||
}
|
||||
}
|
||||
}
|
||||
&.expanded-widget-rules {
|
||||
.widget-rules-wrapper {
|
||||
min-height: 50px;
|
||||
height: auto;
|
||||
opacity: 1;
|
||||
pointer-events: inherit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.s-status-no-data {
|
||||
.widget-edit-holder {
|
||||
opacity: 0.3;
|
||||
pointer-events: none;
|
||||
}
|
||||
.t-message-widget-no-data {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.l-compact-form {
|
||||
// Overrides on .l-compact-form
|
||||
ul {
|
||||
&:last-child { margin: 0; }
|
||||
li {
|
||||
@include align-items(flex-start);
|
||||
@include flex-wrap(nowrap);
|
||||
line-height: 230%; // Provide enough space when controls wrap
|
||||
padding: 2px 0;
|
||||
&:not(.widget-rule-header) {
|
||||
&:not(.connects-to-previous) {
|
||||
border-top: 1px solid $colorFormLines;
|
||||
}
|
||||
}
|
||||
&.connects-to-previous {
|
||||
padding: $interiorMargin 0;
|
||||
}
|
||||
|
||||
> label {
|
||||
display: block; // Needed to align text to right
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.s-widget-test-data-item {
|
||||
// Single line of ul li label span, etc.
|
||||
ul {
|
||||
li {
|
||||
border: none !important;
|
||||
> label {
|
||||
display: inline-block;
|
||||
width: auto;
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.widget-edit-holder {
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.widget-rules-wrapper {
|
||||
// Wrapper area that holds n rules
|
||||
box-sizing: border-box;
|
||||
overflow-y: scroll;
|
||||
padding-right: $interiorMargin;
|
||||
}
|
||||
|
||||
.l-widget-rule,
|
||||
.l-widget-test-data-item {
|
||||
box-sizing: border-box;
|
||||
margin-bottom: $interiorMarginSm;
|
||||
padding: $interiorMargin $interiorMarginLg;
|
||||
}
|
||||
|
||||
.l-widget-thumb-wrapper {
|
||||
@extend .l-flex-row;
|
||||
@include align-items(center);
|
||||
> span { display: block; }
|
||||
.grippy-holder,
|
||||
.view-control {
|
||||
margin-right: $interiorMargin;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
}
|
||||
|
||||
.widget-thumb {
|
||||
@include flex(1 1 auto);
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.rule-title {
|
||||
@include flex(0 1 auto);
|
||||
color: pullForward($colorBodyFg, 50%);
|
||||
}
|
||||
|
||||
.rule-description {
|
||||
@include flex(1 1 auto);
|
||||
@include ellipsize();
|
||||
color: pushBack($colorBodyFg, 20%);
|
||||
}
|
||||
|
||||
.s-widget-rule,
|
||||
.s-widget-test-data-item {
|
||||
background-color: rgba($colorBodyFg, 0.1);
|
||||
border-radius: $basicCr;
|
||||
}
|
||||
|
||||
.widget-thumb {
|
||||
@include ellipsize();
|
||||
@extend .s-summary-widget;
|
||||
@extend .l-summary-widget;
|
||||
padding: $interiorMarginSm $interiorMargin;
|
||||
}
|
||||
|
||||
// Hide and show elements in the rule-header on hover
|
||||
.l-widget-rule,
|
||||
.l-widget-test-data-item {
|
||||
.grippy,
|
||||
.l-rule-action-buttons-wrapper,
|
||||
.l-condition-action-buttons-wrapper,
|
||||
.l-widget-test-data-item-action-buttons-wrapper {
|
||||
@include trans-prop-nice($props: opacity, $dur: 500ms);
|
||||
opacity: 0;
|
||||
}
|
||||
&:hover {
|
||||
.grippy,
|
||||
.l-rule-action-buttons-wrapper,
|
||||
.l-widget-test-data-item-action-buttons-wrapper {
|
||||
@include trans-prop-nice($props: opacity, $dur: 0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
.l-rule-action-buttons-wrapper {
|
||||
.t-delete {
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
.t-condition {
|
||||
&:hover {
|
||||
.l-condition-action-buttons-wrapper {
|
||||
@include trans-prop-nice($props: opacity, $dur: 0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -33,6 +33,7 @@ $pad: $interiorMargin * $baseRatio;
|
||||
height: $btnStdH;
|
||||
line-height: $btnStdH;
|
||||
padding: 0 $pad;
|
||||
vertical-align: top;
|
||||
|
||||
&.labeled:before {
|
||||
// Icon when it's included
|
||||
|
||||
@@ -19,10 +19,11 @@
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
.l-palette {
|
||||
.l-color-palette {
|
||||
$d: 16px;
|
||||
$colorsPerRow: 10;
|
||||
$m: 1;
|
||||
$colorSelectedColor: #fff;
|
||||
|
||||
box-sizing: border-box;
|
||||
padding: $interiorMargin !important;
|
||||
@@ -32,41 +33,46 @@
|
||||
line-height: $d;
|
||||
width: ($d * $colorsPerRow) + ($m * $colorsPerRow);
|
||||
|
||||
&.l-option-row {
|
||||
margin-bottom: $interiorMargin;
|
||||
.s-palette-item {
|
||||
border-color: $colorPaletteFg;
|
||||
}
|
||||
}
|
||||
|
||||
.l-palette-item {
|
||||
box-sizing: border-box;
|
||||
@include txtShdwSubtle(0.8);
|
||||
@include trans-prop-nice-fade(0.25s);
|
||||
border: 1px solid transparent;
|
||||
color: $colorSelectedColor;
|
||||
display: block;
|
||||
float: left;
|
||||
height: $d; width: $d;
|
||||
line-height: $d * 0.9;
|
||||
margin: 0 ($m * 1px) ($m * 1px) 0;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
&:before {
|
||||
// Check mark for selected items
|
||||
font-size: 0.8em;
|
||||
}
|
||||
}
|
||||
|
||||
.s-palette-item {
|
||||
border: 1px solid transparent;
|
||||
color: $colorPaletteFg;
|
||||
text-shadow: $shdwPaletteFg;
|
||||
@include trans-prop-nice-fade(0.25s);
|
||||
&:hover {
|
||||
@include trans-prop-nice-fade(0);
|
||||
border-color: $colorPaletteSelected !important;
|
||||
border-color: $colorSelectedColor !important;
|
||||
}
|
||||
&.selected {
|
||||
border-color: $colorPaletteSelected;
|
||||
box-shadow: $shdwPaletteSelected; //Needed to see selection rect on light colored swatches
|
||||
}
|
||||
}
|
||||
|
||||
.l-palette-item-label {
|
||||
margin-left: $interiorMargin;
|
||||
}
|
||||
|
||||
&.l-option-row {
|
||||
margin-bottom: $interiorMargin;
|
||||
.s-palette-item {
|
||||
border-color: $colorBodyFg;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -72,13 +72,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Hyperlink objects
|
||||
.s-hyperlink {
|
||||
.label {
|
||||
font-size: 0.8rem !important;
|
||||
}
|
||||
// Hyperlink objects
|
||||
&:not(.s-button) {
|
||||
color: $colorKey;
|
||||
font-size: 0.8rem;
|
||||
&:hover { color: $colorKeyHov; }
|
||||
}
|
||||
}
|
||||
@@ -234,21 +232,35 @@ textarea {
|
||||
}
|
||||
|
||||
/******************************************************** INPUTS */
|
||||
%input-base {
|
||||
@include input-base();
|
||||
}
|
||||
|
||||
input[type="text"],
|
||||
input[type="search"],
|
||||
input[type="number"] {
|
||||
@include nice-input();
|
||||
vertical-align: baseline;
|
||||
padding: $inputTextPTopBtm $inputTextPLeftRight;
|
||||
padding: $inputTextP;
|
||||
&.numeric {
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
span[contenteditable].s-inline-edit {
|
||||
@include trans-prop-nice((padding), 250ms);
|
||||
@include input-base();
|
||||
border: 1px solid transparent;
|
||||
min-width: 20px;
|
||||
&:hover {
|
||||
border-color: rgba($colorBodyFg, 0.2);
|
||||
padding-left: $inputTextPLeftRight;
|
||||
padding-right: $inputTextPLeftRight;
|
||||
}
|
||||
}
|
||||
|
||||
span[contenteditable].s-inline-edit.s-status-editing {
|
||||
@include nice-input();
|
||||
vertical-align: baseline;
|
||||
padding: 0 $inputTextPLeftRight;
|
||||
}
|
||||
|
||||
.l-input-sm {
|
||||
input[type="text"],
|
||||
input[type="search"],
|
||||
@@ -261,7 +273,7 @@ input[type="number"] {
|
||||
input[type="text"].lg { width: 100% !important; }
|
||||
.l-input-med input[type="text"],
|
||||
input[type="text"].med { width: 200px !important; }
|
||||
input[type="text"].sm, input[type="number"].sm { width: 50px !important; }
|
||||
input[type="text"].sm { width: 50px !important; }
|
||||
.l-numeric input[type="text"],
|
||||
input[type="text"].numeric { text-align: right; }
|
||||
|
||||
@@ -287,44 +299,21 @@ textarea.lg { position: relative; height: 300px; }
|
||||
}
|
||||
}
|
||||
|
||||
*[contenteditable].s-input-inline,
|
||||
input[type="text"].s-input-inline,
|
||||
.s-input-inline input[type="text"] {
|
||||
// A text input or contenteditable element that indicates edit affordance on hover and looks like an input on focus
|
||||
@extend %input-base;
|
||||
@include trans-prop-nice((padding, box-shadow), 250ms);
|
||||
background: none;
|
||||
box-shadow: none;
|
||||
border: 1px solid transparent;
|
||||
min-width: 20px;
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
&:hover,
|
||||
&:focus {
|
||||
padding-left: $inputTextPLeftRight;
|
||||
padding-right: $inputTextPLeftRight;
|
||||
}
|
||||
&:hover {
|
||||
border-color: rgba($colorBodyFg, 0.2);
|
||||
}
|
||||
&:focus {
|
||||
@include s-input();
|
||||
border-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************** SELECTS */
|
||||
.select {
|
||||
@include btnSubtle($bg: $colorSelectBg);
|
||||
@extend .icon-arrow-down; // Context arrow
|
||||
@if $shdwBtns != none {
|
||||
margin: 0 0 2px 0; // Needed to avoid dropshadow from being clipped by parent containers
|
||||
}
|
||||
display: inline-block;
|
||||
padding: 0 $interiorMargin;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
line-height: $formInputH;
|
||||
select {
|
||||
@include appearance(none);
|
||||
box-sizing: border-box;
|
||||
&:focus { outline: 0; }
|
||||
background: none;
|
||||
color: $colorSelectFg;
|
||||
cursor: pointer;
|
||||
@@ -336,13 +325,12 @@ input[type="text"].s-input-inline,
|
||||
}
|
||||
}
|
||||
&:before {
|
||||
@include transform(translateY(-50%));
|
||||
color: rgba($colorInvokeMenu, percentToDecimal($contrastInvokeMenuPercent));
|
||||
display: block;
|
||||
//@include contextArrow();
|
||||
pointer-events: none;
|
||||
color: rgba($colorSelectFg, percentToDecimal($contrastInvokeMenuPercent));
|
||||
display: block;
|
||||
position: absolute;
|
||||
right: $interiorMargin;
|
||||
top: 50%;
|
||||
right: $interiorMargin; top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -394,7 +382,8 @@ input[type="text"].s-input-inline,
|
||||
.l-elem-wrapper {
|
||||
mct-representation {
|
||||
// Holds the context-available item
|
||||
// Must have min-width to make flex work properly in Safari
|
||||
// Must have min-width to make flex work properly
|
||||
// in Safari
|
||||
min-width: 0.7em;
|
||||
}
|
||||
}
|
||||
@@ -560,6 +549,7 @@ input[type="text"].s-input-inline,
|
||||
height: $h;
|
||||
margin-top: 1 + floor($h/2) * -1;
|
||||
@include btnSubtle(pullForward($colorBtnBg, 10%));
|
||||
//border-radius: 50% !important;
|
||||
}
|
||||
|
||||
@mixin sliderKnobRound() {
|
||||
@@ -574,6 +564,7 @@ input[type="text"].s-input-inline,
|
||||
|
||||
input[type="range"] {
|
||||
// HTML5 range inputs
|
||||
|
||||
-webkit-appearance: none; /* Hides the slider so that custom slider can be made */
|
||||
background: transparent; /* Otherwise white in Chrome */
|
||||
&:focus {
|
||||
@@ -731,30 +722,6 @@ textarea {
|
||||
}
|
||||
}
|
||||
|
||||
.view-switcher,
|
||||
.t-btn-view-large {
|
||||
@include trans-prop-nice-fade($controlFadeMs);
|
||||
}
|
||||
|
||||
.view-control {
|
||||
@extend .icon-arrow-right;
|
||||
cursor: pointer;
|
||||
font-size: 0.75em;
|
||||
&:before {
|
||||
position: absolute;
|
||||
@include trans-prop-nice(transform, 100ms);
|
||||
@include transform-origin(center);
|
||||
}
|
||||
&.expanded:before {
|
||||
@include transform(rotate(90deg));
|
||||
}
|
||||
}
|
||||
|
||||
.grippy {
|
||||
@extend .icon-grippy;
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
/******************************************************** BROWSER ELEMENTS */
|
||||
body.desktop {
|
||||
::-webkit-scrollbar {
|
||||
@@ -772,15 +739,11 @@ body.desktop {
|
||||
}
|
||||
|
||||
.overlay ::-webkit-scrollbar-thumb {
|
||||
$lr: 15%;
|
||||
background: $scrollbarThumbColorOverlay;
|
||||
&:hover { background: $scrollbarThumbColorOverlayHov; }
|
||||
}
|
||||
|
||||
.menu ::-webkit-scrollbar-thumb {
|
||||
background: $scrollbarThumbColorMenu;
|
||||
&:hover { background: $scrollbarThumbColorMenuHov; }
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-corner {
|
||||
background: $scrollbarTrackColorBg;
|
||||
}
|
||||
|
||||
@@ -21,91 +21,92 @@
|
||||
*****************************************************************************/
|
||||
/******************************************************** MENU BUTTONS */
|
||||
.s-menu-button {
|
||||
// Formerly .btn-menu
|
||||
@extend .s-button;
|
||||
span.l-click-area {
|
||||
// In markup, this element should not enclose anything.
|
||||
@extend .abs;
|
||||
}
|
||||
// Formerly .btn-menu
|
||||
@extend .s-button;
|
||||
span.l-click-area {
|
||||
// In markup, this element should not enclose anything.
|
||||
@extend .abs;
|
||||
}
|
||||
|
||||
.icon {
|
||||
font-size: 16px;
|
||||
}
|
||||
.icon {
|
||||
font-size: 16px; //120%;
|
||||
}
|
||||
|
||||
.title-label {
|
||||
margin-left: $interiorMarginSm;
|
||||
}
|
||||
.title-label {
|
||||
margin-left: $interiorMarginSm;
|
||||
}
|
||||
|
||||
.icon-swatch,
|
||||
.color-swatch {
|
||||
// Used in color menu buttons in toolbar
|
||||
$d: 10px;
|
||||
display: inline-block;
|
||||
border: 1px solid rgba($colorBtnFg, 0.2);
|
||||
height: $d; width: $d;
|
||||
line-height: $d;
|
||||
vertical-align: middle;
|
||||
margin-left: $interiorMarginSm;
|
||||
margin-top: -2px;
|
||||
&:not(.no-selection) {
|
||||
border-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
&:after {
|
||||
// Adds the downward facing 'context available / invoke menu' arrow element
|
||||
@include contextArrow();
|
||||
color: rgba($colorInvokeMenu, percentToDecimal($contrastInvokeMenuPercent));
|
||||
}
|
||||
&:after {
|
||||
// Adds the downward facing 'context available / invoke menu' arrow element
|
||||
@include contextArrow();
|
||||
color: rgba($colorInvokeMenu, percentToDecimal($contrastInvokeMenuPercent));
|
||||
}
|
||||
|
||||
&.create-button {
|
||||
&.create-button {
|
||||
@extend .icon-plus;
|
||||
.title-label {
|
||||
font-size: 1rem;
|
||||
}
|
||||
}
|
||||
.title-label {
|
||||
font-size: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.menu {
|
||||
left: 0;
|
||||
text-align: left;
|
||||
}
|
||||
.menu {
|
||||
left: 0;
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************** MENUS THEMSELVES */
|
||||
.menu-element {
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.s-menu {
|
||||
border-radius: $basicCr;
|
||||
@include containerSubtle($colorMenuBg, $colorMenuFg);
|
||||
@include boxShdw($shdwMenu);
|
||||
@include txtShdw($shdwMenuText);
|
||||
padding: $interiorMarginSm 0;
|
||||
}
|
||||
|
||||
.menu {
|
||||
border-radius: $basicCr;
|
||||
@include containerSubtle($colorMenuBg, $colorMenuFg);
|
||||
@include boxShdw($shdwMenu);
|
||||
@include txtShdw($shdwMenuText);
|
||||
padding: $interiorMarginSm 0;
|
||||
display: block;
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
ul {
|
||||
@include menuUlReset();
|
||||
li {
|
||||
box-sizing: border-box;
|
||||
border-top: 1px solid pullForward($colorMenuBg, 10%);
|
||||
// TODO: reduce size of icons
|
||||
@extend .s-menu;
|
||||
display: block;
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
ul {
|
||||
@include menuUlReset();
|
||||
li {
|
||||
box-sizing: border-box;
|
||||
border-top: 1px solid pullForward($colorMenuBg, 10%);
|
||||
color: $colorMenuFg;
|
||||
line-height: $menuLineH;
|
||||
padding: $interiorMarginSm $interiorMargin * 2 $interiorMarginSm ($interiorMargin * 2) + $treeTypeIconW;
|
||||
position: relative;
|
||||
white-space: nowrap;
|
||||
&:first-child {
|
||||
border: none;
|
||||
}
|
||||
&:hover {
|
||||
background: $colorMenuHovBg;
|
||||
color: $colorMenuHovFg;
|
||||
//color: pullForward($colorMenuBg, 60%);
|
||||
line-height: $menuLineH;
|
||||
padding: $interiorMarginSm $interiorMargin * 2 $interiorMarginSm ($interiorMargin * 2) + $treeTypeIconW;
|
||||
position: relative;
|
||||
white-space: nowrap;
|
||||
&:first-child {
|
||||
border: none;
|
||||
}
|
||||
&:hover {
|
||||
background: $colorMenuHovBg;
|
||||
color: $colorMenuHovFg;
|
||||
&:before {
|
||||
color: $colorMenuHovIc;
|
||||
}
|
||||
}
|
||||
}
|
||||
&:before {
|
||||
@extend .ui-symbol;
|
||||
@extend .type-icon;
|
||||
@@ -113,8 +114,8 @@
|
||||
display: inline-block;
|
||||
left: $interiorMargin * 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.menu,
|
||||
@@ -122,97 +123,94 @@
|
||||
.context-menu,
|
||||
.super-menu,
|
||||
.s-menu-button .menu {
|
||||
pointer-events: auto;
|
||||
ul li {
|
||||
a.menu-item-a {
|
||||
pointer-events: auto;
|
||||
ul li {
|
||||
a.menu-item-a {
|
||||
color: $colorMenuFg;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
&:before,
|
||||
a.menu-item-a:before {
|
||||
color: $colorMenuIc;
|
||||
left: $interiorMargin;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.checkbox-menu {
|
||||
// Used in search dropdown in tree
|
||||
@extend .context-menu;
|
||||
ul li {
|
||||
padding-left: 50px;
|
||||
.checkbox {
|
||||
$d: 0.7rem;
|
||||
position: absolute;
|
||||
left: $interiorMargin;
|
||||
top: ($menuLineH - $d) / 1.5;
|
||||
em {
|
||||
height: $d;
|
||||
width: $d;
|
||||
&:before {
|
||||
font-size: 7px !important;
|
||||
height: $d;
|
||||
width: $d;
|
||||
line-height: $d;
|
||||
}
|
||||
}
|
||||
}
|
||||
&:before {
|
||||
// Used in search dropdown in tree
|
||||
@extend .context-menu;
|
||||
ul li {
|
||||
padding-left: 50px;
|
||||
.checkbox {
|
||||
$d: 0.7rem;
|
||||
position: absolute;
|
||||
left: $interiorMargin;
|
||||
top: ($menuLineH - $d) / 1.5;
|
||||
em {
|
||||
height: $d;
|
||||
width: $d;
|
||||
&:before {
|
||||
font-size: 7px !important;
|
||||
height: $d;
|
||||
width: $d;
|
||||
line-height: $d;
|
||||
}
|
||||
}
|
||||
}
|
||||
&:before {
|
||||
// Type icon
|
||||
left: 25px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.super-menu,
|
||||
.super-menu > mct-representation,
|
||||
.super-menu > .contents {
|
||||
box-sizing: border-box;
|
||||
display: block;
|
||||
position: relative;
|
||||
left: 25px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.super-menu {
|
||||
$plw: 50%;
|
||||
$prw: 100% - $plw;
|
||||
position: absolute;
|
||||
.w-menu {
|
||||
align-items: stretch;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
margin: $interiorMarginLg;
|
||||
}
|
||||
.col {
|
||||
box-sizing: border-box;
|
||||
flex: 1 1 auto;
|
||||
overflow-x: hidden;
|
||||
&.menu-items {
|
||||
border-right: 1px solid pullForward($colorMenuBg, 10%);
|
||||
overflow-y: auto;
|
||||
padding-right: $interiorMargin;
|
||||
width: $plw;
|
||||
ul {
|
||||
li {
|
||||
border-radius: $controlCr;
|
||||
padding-left: 30px;
|
||||
border-top: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
&.menu-item-description {
|
||||
$p: $interiorMargin * 3;
|
||||
overflow-y: hidden;
|
||||
padding: $p $p 0 $p;
|
||||
width: $prw;
|
||||
|
||||
$w: 500px;
|
||||
$h: $w - 20;
|
||||
$plw: 50%;
|
||||
$prw: 50%;
|
||||
display: block;
|
||||
width: $w;
|
||||
height: $h;
|
||||
.contents {
|
||||
@include absPosDefault($interiorMargin);
|
||||
}
|
||||
.pane {
|
||||
box-sizing: border-box;
|
||||
&.menu-items {
|
||||
border-right: 1px solid pullForward($colorMenuBg, 10%);
|
||||
left: 0;
|
||||
padding-right: $interiorMargin;
|
||||
right: auto;
|
||||
width: $plw;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
ul {
|
||||
li {
|
||||
border-radius: $controlCr;
|
||||
padding-left: 30px;
|
||||
border-top: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
&.menu-item-description {
|
||||
left: auto;
|
||||
right: 0;
|
||||
padding: $interiorMargin * 5;
|
||||
width: $prw;
|
||||
.desc-area {
|
||||
&.icon {
|
||||
color: $colorCreateMenuLgIcon;
|
||||
font-size: 8em;
|
||||
margin-bottom: $interiorMargin * 3;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
}
|
||||
&.title {
|
||||
color: $colorCreateMenuText;
|
||||
font-size: 1.2em;
|
||||
margin-bottom: $interiorMargin * 2;
|
||||
}
|
||||
&.description {
|
||||
color: pushBack($colorCreateMenuText, 20%);
|
||||
@@ -220,104 +218,67 @@
|
||||
line-height: 1.5em;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.w-title-desc {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden; // Height set in specific menu instances
|
||||
}
|
||||
|
||||
// Specific menu instances
|
||||
&.l-create-menu {
|
||||
width: 500px;
|
||||
.col {
|
||||
max-height: 70vh;
|
||||
}
|
||||
.w-title-desc {
|
||||
height: 190px;
|
||||
}
|
||||
.desc-area {
|
||||
&.icon {
|
||||
font-size: 8em;
|
||||
height: 135px;
|
||||
margin-bottom: $interiorMargin * 3;
|
||||
}
|
||||
&.title {
|
||||
font-size: 1.2em;
|
||||
margin-bottom: $interiorMargin * 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.mini {
|
||||
width: 400px;
|
||||
.col {
|
||||
max-height: 50vh;
|
||||
height: 300px;
|
||||
.pane {
|
||||
&.menu-items {
|
||||
font-size: 0.8em;
|
||||
}
|
||||
&.menu-item-description {
|
||||
$p: $interiorMargin * 2;
|
||||
padding: $p $p 0 $p;
|
||||
}
|
||||
}
|
||||
.w-title-desc {
|
||||
height: 180px;
|
||||
}
|
||||
.desc-area {
|
||||
&.icon {
|
||||
font-size: 4em;
|
||||
height: 70px;
|
||||
margin-bottom: $interiorMargin * 3;
|
||||
}
|
||||
&.title {
|
||||
font-size: 1em;
|
||||
margin-bottom: $interiorMargin * 2;
|
||||
padding: $interiorMargin * 3;
|
||||
.desc-area {
|
||||
&.icon {
|
||||
font-size: 4em;
|
||||
}
|
||||
&.title {
|
||||
font-size: 1em;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.context-menu {
|
||||
font-size: 0.80rem;
|
||||
font-size: 0.80rem;
|
||||
}
|
||||
|
||||
.context-menu-holder,
|
||||
.menu-holder {
|
||||
position: absolute;
|
||||
z-index: 120;
|
||||
.context-menu-wrapper {
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
&.go-left .context-menu,
|
||||
&.go-left .menu {
|
||||
right: 0;
|
||||
}
|
||||
&.go-up .context-menu,
|
||||
&.go-up .menu {
|
||||
bottom: 0;
|
||||
}
|
||||
position: absolute;
|
||||
z-index: 120;
|
||||
.context-menu-wrapper {
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
&.go-left .context-menu,
|
||||
&.go-left .menu {
|
||||
right: 0;
|
||||
}
|
||||
&.go-up .context-menu,
|
||||
&.go-up .menu {
|
||||
bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.context-menu-holder {
|
||||
pointer-events: none;
|
||||
height: 200px;
|
||||
width: 170px;
|
||||
pointer-events: none;
|
||||
height: 200px;
|
||||
width: 170px;
|
||||
}
|
||||
|
||||
.btn-bar.right .menu,
|
||||
.menus-to-left .menu {
|
||||
z-index: 79;
|
||||
left: auto;
|
||||
right: 0;
|
||||
width: auto;
|
||||
left: auto;
|
||||
right: 0;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.menus-up .menu {
|
||||
bottom: $btnStdH;
|
||||
top: auto;
|
||||
bottom: $btnStdH; top: auto;
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
/******************************************************************* STATUS BLOCK ELEMS */
|
||||
|
||||
@mixin statusBannerColors($bg, $fg: $colorStatusFg) {
|
||||
$bgPb: 30%;
|
||||
$bgPbD: 10%;
|
||||
@@ -120,11 +120,7 @@
|
||||
}
|
||||
|
||||
.status-indicator {
|
||||
background: none !important;
|
||||
margin-right: $interiorMarginSm;
|
||||
&[class*='s-status']:before {
|
||||
font-size: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
.count {
|
||||
@@ -140,7 +136,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************* MESSAGE BANNERS */
|
||||
/* Styles for messages and message banners */
|
||||
.message {
|
||||
&.block {
|
||||
border-radius: $basicCr;
|
||||
@@ -196,6 +192,7 @@
|
||||
padding: 0 $interiorMargin;
|
||||
}
|
||||
.close {
|
||||
//@include test(red, 0.7);
|
||||
cursor: pointer;
|
||||
font-size: 7px;
|
||||
width: 8px;
|
||||
@@ -239,147 +236,132 @@
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************* MESSAGES */
|
||||
|
||||
/* Contexts:
|
||||
In .t-message-list
|
||||
In .overlay as a singleton
|
||||
Inline in the view area
|
||||
*/
|
||||
|
||||
// Archetypal message
|
||||
.l-message {
|
||||
$iconW: 32px;
|
||||
@include display(flex);
|
||||
@include flex-direction(row);
|
||||
@include align-items(stretch);
|
||||
padding: $interiorMarginLg;
|
||||
|
||||
&:before {
|
||||
// Icon
|
||||
@include flex(0 1 auto);
|
||||
@mixin messageBlock($iconW: 32px) {
|
||||
.type-icon.message-type {
|
||||
@include txtShdw($shdwStatusIc);
|
||||
@extend .icon-bell;
|
||||
color: $colorStatusDefault;
|
||||
font-size: $iconW;
|
||||
padding: 1px;
|
||||
width: $iconW + 2;
|
||||
margin-right: $interiorMarginLg;
|
||||
}
|
||||
|
||||
&.message-severity-info:before {
|
||||
.message-severity-info .type-icon.message-type {
|
||||
@extend .icon-info;
|
||||
color: $colorInfo;
|
||||
}
|
||||
|
||||
&.message-severity-alert:before {
|
||||
.message-severity-alert .type-icon.message-type {
|
||||
@extend .icon-bell;
|
||||
color: $colorWarningLo;
|
||||
}
|
||||
|
||||
&.message-severity-error:before {
|
||||
.message-severity-error .type-icon.message-type {
|
||||
@extend .icon-alert-rect;
|
||||
color: $colorWarningHi;
|
||||
}
|
||||
}
|
||||
/* Paths:
|
||||
t-dialog | t-dialog-sm > t-message-single | t-message-list > overlay > holder > contents > l-message >
|
||||
message-type > (icon)
|
||||
message-contents >
|
||||
top-bar >
|
||||
title
|
||||
hint
|
||||
editor >
|
||||
(if displaying list of messages)
|
||||
ul > li > l-message >
|
||||
... same as above
|
||||
bottom-bar
|
||||
*/
|
||||
|
||||
|
||||
.w-message-contents {
|
||||
@include flex(1 1 auto);
|
||||
.l-message {
|
||||
@include display(flex);
|
||||
@include flex-direction(column);
|
||||
|
||||
> div,
|
||||
> span {
|
||||
//@include test(red);
|
||||
margin-bottom: $interiorMargin;
|
||||
@include flex-direction(row);
|
||||
@include align-items(stretch);
|
||||
.type-icon.message-type {
|
||||
@include flex(0 1 auto);
|
||||
position: relative;
|
||||
}
|
||||
.message-contents {
|
||||
@include flex(1 1 auto);
|
||||
margin-left: $overlayMargin;
|
||||
position: relative;
|
||||
|
||||
.message-body {
|
||||
@include flex(1 1 100%);
|
||||
}
|
||||
}
|
||||
|
||||
// Singleton in an overlay dialog
|
||||
.t-message-single .l-message,
|
||||
.t-message-single.l-message {
|
||||
$iconW: 80px;
|
||||
@include absPosDefault();
|
||||
padding: 0;
|
||||
&:before {
|
||||
font-size: $iconW;
|
||||
width: $iconW + 2;
|
||||
}
|
||||
.title {
|
||||
font-size: 1.2em;
|
||||
}
|
||||
}
|
||||
|
||||
// Singleton inline in a view
|
||||
.t-message-inline .l-message,
|
||||
.t-message-inline.l-message {
|
||||
border-radius: $controlCr;
|
||||
&.message-severity-info { background-color: rgba($colorInfo, 0.3); }
|
||||
&.message-severity-alert { background-color: rgba($colorWarningLo, 0.3); }
|
||||
&.message-severity-error { background-color: rgba($colorWarningHi, 0.3); }
|
||||
|
||||
.w-message-contents.l-message-body-only {
|
||||
.top-bar,
|
||||
.message-body {
|
||||
margin-top: $interiorMargin;
|
||||
margin-bottom: $interiorMarginLg * 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// In a list
|
||||
.t-message-list {
|
||||
@include absPosDefault();
|
||||
@include display(flex);
|
||||
@include flex-direction(column);
|
||||
|
||||
> div,
|
||||
> span {
|
||||
margin-bottom: $interiorMargin;
|
||||
// Message as singleton
|
||||
.t-message-single {
|
||||
@include messageBlock(80px);
|
||||
}
|
||||
|
||||
body.desktop .t-message-single {
|
||||
.l-message,
|
||||
.bottom-bar {
|
||||
@include absPosDefault();
|
||||
}
|
||||
|
||||
.w-messages {
|
||||
@include flex(1 1 100%);
|
||||
overflow-y: auto;
|
||||
padding-right: $interiorMargin;
|
||||
.bottom-bar {
|
||||
top: auto;
|
||||
height: $ovrFooterH;
|
||||
}
|
||||
// Each message
|
||||
.l-message {
|
||||
border-radius: $controlCr;
|
||||
background: rgba($colorOvrFg, 0.1);
|
||||
margin-bottom: $interiorMargin;
|
||||
.hint,
|
||||
.bottom-bar {
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@include phonePortrait {
|
||||
.t-message-single .l-message,
|
||||
.t-message-single.l-message {
|
||||
@include flex-direction(column);
|
||||
&:before {
|
||||
margin-right: 0;
|
||||
.t-message-single {
|
||||
.l-message {
|
||||
@include flex-direction(column);
|
||||
.message-contents { margin-left: 0; }
|
||||
}
|
||||
.type-icon.message-type {
|
||||
margin-bottom: $interiorMarginLg;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.bottom-bar {
|
||||
text-align: center;
|
||||
.s-button {
|
||||
display: block;
|
||||
width: 100%;
|
||||
text-align: center !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Messages in list
|
||||
.t-message-list {
|
||||
@include messageBlock(32px);
|
||||
|
||||
.message-contents {
|
||||
.l-message {
|
||||
border-radius: $controlCr;
|
||||
background: rgba($colorOvrFg, 0.1);
|
||||
margin-bottom: $interiorMargin;
|
||||
padding: $interiorMarginLg;
|
||||
|
||||
.message-contents,
|
||||
.bottom-bar {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.message-contents {
|
||||
font-size: 0.9em;
|
||||
margin-left: $interiorMarginLg;
|
||||
.message-action { color: pushBack($colorOvrFg, 20%); }
|
||||
.bottom-bar { text-align: left; }
|
||||
}
|
||||
|
||||
.top-bar,
|
||||
.message-body {
|
||||
margin-bottom: $interiorMarginLg;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
body.desktop .t-message-list {
|
||||
.w-message-contents { padding-right: $interiorMargin; }
|
||||
.message-contents .l-message { margin-right: $interiorMarginLg; }
|
||||
}
|
||||
|
||||
// Alert elements in views
|
||||
|
||||
@@ -80,32 +80,23 @@
|
||||
|
||||
// Editing Grids
|
||||
.l-grid-holder {
|
||||
display: block;
|
||||
.l-grid {
|
||||
&.l-grid-x { @include bgTicks($colorGridLines, 'x'); }
|
||||
&.l-grid-y { @include bgTicks($colorGridLines, 'y'); }
|
||||
}
|
||||
}
|
||||
|
||||
// Display grid when selected or selection parent.
|
||||
.s-selected .l-grid-holder,
|
||||
.s-selected-parent .l-grid-holder {
|
||||
display: block;
|
||||
// Prevent nested frames from showing their grids
|
||||
.t-frame-outer .l-grid-holder { display: none !important; }
|
||||
|
||||
// Prevent nested elements from showing s-hover-border
|
||||
.t-frame-outer .s-hover-border {
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
// Display in nested frames...
|
||||
.t-frame-outer {
|
||||
// ...when drilled in or selection parent...
|
||||
&.s-drilled-in, &.s-selected-parent {
|
||||
.l-grid-holder {
|
||||
display: block;
|
||||
}
|
||||
.t-frame-outer:not(.s-drilled-in) .l-grid-holder {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
// ...but hide otherwise.
|
||||
.l-grid-holder {
|
||||
display: none;
|
||||
}
|
||||
// Prevent nested frames from being selectable until we have proper sub-object editing
|
||||
.t-frame-outer .t-frame-outer {
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
@if $enableImageryThumbs == true {
|
||||
bottom: $interiorMargin*2 + $imageThumbsWrapperH;
|
||||
}
|
||||
min-height: 100px;
|
||||
min-width: 150px;
|
||||
.l-image-main {
|
||||
background-color: $colorPlotBg;
|
||||
@@ -21,9 +22,7 @@
|
||||
|
||||
.l-image-thumbs-wrapper {
|
||||
top: auto;
|
||||
min-height: $imageThumbsWrapperH;
|
||||
max-height: 60%;
|
||||
box-sizing: border-box;
|
||||
height: $imageThumbsWrapperH;
|
||||
}
|
||||
|
||||
.l-date,
|
||||
@@ -44,16 +43,14 @@
|
||||
.l-image-main-controlbar {
|
||||
font-size: 0.8em;
|
||||
line-height: inherit;
|
||||
.l-datetime-w, .l-controls-w {
|
||||
.left, .right {
|
||||
direction: rtl;
|
||||
overflow: hidden;
|
||||
}
|
||||
.l-datetime-w {
|
||||
@include ellipsize();
|
||||
margin-right: $interiorMarginSm;
|
||||
.left {
|
||||
text-align: left;
|
||||
}
|
||||
.l-controls-w {
|
||||
.right {
|
||||
z-index: 2;
|
||||
}
|
||||
.l-date,
|
||||
@@ -85,8 +82,9 @@
|
||||
/*************************************** THUMBS */
|
||||
|
||||
.l-image-thumbs-wrapper {
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
//@include test(green);
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
padding-bottom: $interiorMargin;
|
||||
white-space: nowrap;
|
||||
}
|
||||
@@ -94,17 +92,8 @@
|
||||
.l-image-thumb-item {
|
||||
@include transition(background-color, 0.25s);
|
||||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
direction: ltr;
|
||||
display: inline-block;
|
||||
float: left;
|
||||
font-size: 0.8em;
|
||||
padding: 1px;
|
||||
margin-left: $interiorMarginSm;
|
||||
position: relative;
|
||||
text-align: left;
|
||||
width: $imageThumbsD + $imageThumbPad*2;
|
||||
white-space: normal;
|
||||
position: relative;
|
||||
.l-thumb,
|
||||
.l-date,
|
||||
.l-time {
|
||||
@@ -114,7 +103,14 @@
|
||||
.l-time {
|
||||
padding: 2px 3px;
|
||||
}
|
||||
|
||||
cursor: pointer;
|
||||
direction: ltr;
|
||||
display: inline-block;
|
||||
font-size: 0.8em;
|
||||
margin-left: $interiorMarginSm;
|
||||
text-align: left;
|
||||
width: $imageThumbsD + $imageThumbPad*2;
|
||||
white-space: normal;
|
||||
&:hover {
|
||||
background: $colorThumbHoverBg;
|
||||
.l-date,
|
||||
@@ -140,7 +136,6 @@
|
||||
/*************************************** LOCAL CONTROLS */
|
||||
.l-local-controls {
|
||||
max-width: 200px;
|
||||
min-width: 100px;
|
||||
width: 35%;
|
||||
input[type="range"] {
|
||||
display: block;
|
||||
@@ -189,8 +184,7 @@
|
||||
/*************************************** WHEN IN FRAME */
|
||||
.frame .t-imagery {
|
||||
.l-image-main-wrapper {
|
||||
bottom: 0 !important;
|
||||
height: 100% !important;
|
||||
bottom: 0;
|
||||
.l-image-main-controlbar {
|
||||
font-size: 0.7em;
|
||||
}
|
||||
@@ -200,8 +194,7 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
.l-image-thumbs-wrapper,
|
||||
mct-splitter {
|
||||
.l-image-thumbs-wrapper {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,19 +20,7 @@
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
.section-header {
|
||||
border-radius: $basicCr;
|
||||
background: $colorFormSectionHeader;
|
||||
color: lighten($colorBodyFg, 20%);
|
||||
font-size: inherit;
|
||||
margin: $interiorMargin 0;
|
||||
padding: $formTBPad $formLRPad;
|
||||
text-transform: uppercase;
|
||||
.view-control {
|
||||
display: inline-block;
|
||||
margin-right: $interiorMargin;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
.form {
|
||||
@@ -53,6 +41,15 @@
|
||||
}
|
||||
}
|
||||
|
||||
.section-header {
|
||||
border-radius: $basicCr;
|
||||
background: $colorFormSectionHeader;
|
||||
$c: lighten($colorBodyFg, 20%);
|
||||
color: $c;
|
||||
font-size: 0.8em;
|
||||
padding: $formTBPad $formLRPad;
|
||||
}
|
||||
|
||||
.form-row {
|
||||
$m: $interiorMargin;
|
||||
box-sizing: border-box;
|
||||
@@ -60,6 +57,9 @@
|
||||
margin-bottom: $interiorMarginLg * 2;
|
||||
padding: $formTBPad 0;
|
||||
position: relative;
|
||||
//&ng-form {
|
||||
// display: block;
|
||||
//}
|
||||
|
||||
&.first {
|
||||
border-top: none;
|
||||
@@ -171,106 +171,3 @@
|
||||
padding: $interiorMargin;
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************** COMPACT FORM */
|
||||
// ul > li > label, control
|
||||
// Make a new UL for each form section
|
||||
// Allow control-first, controls-below
|
||||
// TO-DO: migrate work in branch ch-plot-styling that users .inspector-config to use classes below instead
|
||||
|
||||
.l-compact-form .tree ul li,
|
||||
.l-compact-form ul li {
|
||||
padding: 2px 0;
|
||||
}
|
||||
|
||||
|
||||
.l-compact-form {
|
||||
$labelW: 40%;
|
||||
$minW: $labelW;
|
||||
ul {
|
||||
margin-bottom: $interiorMarginLg;
|
||||
li {
|
||||
@include display(flex);
|
||||
@include flex-wrap(wrap);
|
||||
@include align-items(center);
|
||||
label,
|
||||
.control {
|
||||
@include display(flex);
|
||||
}
|
||||
label {
|
||||
line-height: inherit;
|
||||
width: $labelW;
|
||||
}
|
||||
.controls {
|
||||
@include flex-grow(1);
|
||||
margin-left: $interiorMargin;
|
||||
input[type="text"],
|
||||
input[type="search"],
|
||||
input[type="number"],
|
||||
.select {
|
||||
height: $btnStdH;
|
||||
line-height: $btnStdH;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.e-control {
|
||||
// Individual form controls
|
||||
&:not(:first-child) {
|
||||
margin-left: $interiorMarginSm;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.connects-to-previous {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
&.section-header {
|
||||
margin-top: $interiorMarginLg;
|
||||
border-top: 1px solid $colorFormLines;
|
||||
}
|
||||
|
||||
&.controls-first {
|
||||
.control {
|
||||
@include flex-grow(0);
|
||||
margin-right: $interiorMargin;
|
||||
min-width: 0;
|
||||
order: 1;
|
||||
width: auto;
|
||||
}
|
||||
label {
|
||||
@include flex-grow(1);
|
||||
order: 2;
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
&.controls-under {
|
||||
display: block;
|
||||
.control, label {
|
||||
display: block;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
ul li {
|
||||
border-top: none !important;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.form-error {
|
||||
// Block element that visually flags an error and contains a message
|
||||
background-color: $colorFormFieldErrorBg;
|
||||
color: $colorFormFieldErrorFg;
|
||||
border-radius: $basicCr;
|
||||
display: block;
|
||||
padding: 1px 6px;
|
||||
&:before {
|
||||
content: $glyph-icon-alert-triangle;
|
||||
display: inline;
|
||||
font-family: symbolsfont;
|
||||
margin-right: $interiorMarginSm;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,7 +79,6 @@
|
||||
|
||||
// Dialog boxes, size constrained and centered in desktop/tablet
|
||||
&.l-dialog {
|
||||
font-size: 0.8rem;
|
||||
.s-button {
|
||||
&:not(.major) {
|
||||
@include btnSubtle($bg: $colorOvrBtnBg, $bgHov: pullForward($colorOvrBtnBg, 10%), $fg: $colorOvrBtnFg, $fgHov: $colorOvrBtnFg, $ic: $colorOvrBtnFg, $icHov: $colorOvrBtnFg);
|
||||
@@ -126,9 +125,9 @@
|
||||
@include containerSubtle($colorOvrBg, $colorOvrFg);
|
||||
}
|
||||
|
||||
.dialog-title {
|
||||
.title {
|
||||
@include ellipsize();
|
||||
font-size: 1.5em;
|
||||
font-size: 1.2em;
|
||||
line-height: 120%;
|
||||
margin-bottom: $interiorMargin;
|
||||
}
|
||||
@@ -157,8 +156,6 @@
|
||||
left: 0;
|
||||
right: 0;
|
||||
overflow: auto;
|
||||
padding-right: $interiorMargin;
|
||||
padding-bottom: $interiorMargin;
|
||||
.field.l-input-med {
|
||||
input[type='text'] {
|
||||
width: 100%;
|
||||
|
||||
@@ -52,13 +52,21 @@ ul.tree {
|
||||
|
||||
.view-control {
|
||||
color: $colorItemTreeVC;
|
||||
font-size: 0.75em;
|
||||
margin-right: $interiorMargin;
|
||||
height: 100%;
|
||||
line-height: inherit;
|
||||
width: $treeVCW;
|
||||
&:before { display: none; }
|
||||
&.has-children {
|
||||
&:before { display: block; }
|
||||
&:before {
|
||||
position: absolute;
|
||||
@include trans-prop-nice(transform, 100ms);
|
||||
content: "\e904";
|
||||
@include transform-origin(center);
|
||||
}
|
||||
&.expanded:before {
|
||||
@include transform(rotate(90deg));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,10 +26,12 @@
|
||||
z-index: 0; // Needed to prevent child-frame controls from showing through when another child-frame is above
|
||||
&:not(.no-frame) {
|
||||
background: $colorBodyBg;
|
||||
border-color: $bc;
|
||||
border: 1px solid $bc;
|
||||
&:hover {
|
||||
border-color: lighten($bc, 10%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.object-browse-bar {
|
||||
font-size: 0.75em;
|
||||
height: $ohH;
|
||||
@@ -42,11 +44,10 @@
|
||||
|
||||
&.t-object-type-timer,
|
||||
&.t-object-type-clock,
|
||||
&.t-object-type-hyperlink,
|
||||
&.t-object-type-summary-widget {
|
||||
&.t-object-type-hyperlink {
|
||||
// Hide the right side buttons for objects where they don't make sense
|
||||
// Note that this will hide the view Switcher button if applied
|
||||
// to an object that has it.
|
||||
// to an object that it.
|
||||
.object-browse-bar .right { display: none; }
|
||||
}
|
||||
|
||||
@@ -90,9 +91,9 @@
|
||||
|
||||
&.no-frame {
|
||||
background: transparent !important;
|
||||
border-color: transparent;
|
||||
border: none !important;
|
||||
.object-browse-bar .right {
|
||||
$m: 0;
|
||||
$m: 0; // $interiorMarginSm;
|
||||
background: rgba(black, 0.3);
|
||||
border-radius: $basicCr;
|
||||
padding: $interiorMarginSm;
|
||||
@@ -102,7 +103,7 @@
|
||||
}
|
||||
&.t-frame-outer > .t-rep-frame {
|
||||
&.contents {
|
||||
$m: 0px;
|
||||
$m: 2px;
|
||||
top: $m;
|
||||
right: $m;
|
||||
bottom: $m;
|
||||
@@ -113,33 +114,17 @@
|
||||
display: none;
|
||||
}
|
||||
> .object-holder.abs {
|
||||
overflow: hidden;
|
||||
top: 0 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.t-frame-outer .s-input-inline {
|
||||
// Prevent inline inputs from being edited when nested in a Layout
|
||||
pointer-events: none !important;
|
||||
}
|
||||
|
||||
/********************************************************** OBJECT TYPES */
|
||||
.t-object-type-hyperlink,
|
||||
.t-object-type-summary-widget {
|
||||
.object-holder {
|
||||
overflow: hidden;
|
||||
}
|
||||
.w-summary-widget,
|
||||
.l-summary-widget,
|
||||
.l-hyperlink.s-button {
|
||||
// Some object types expand to the full size of the object-holder.
|
||||
.t-object-type-hyperlink {
|
||||
.s-hyperlink.s-button {
|
||||
// When a hyperlink is a button in a frame, make it expand to fill out to the object-holder
|
||||
@extend .abs;
|
||||
}
|
||||
|
||||
.l-summary-widget,
|
||||
.l-hyperlink.s-button {
|
||||
.label {
|
||||
@include ellipsize();
|
||||
@include transform(translateY(-50%));
|
||||
@@ -157,7 +142,7 @@
|
||||
body.desktop .frame {
|
||||
// Hide local controls initially and show it them on hover when they're in an element that's in a frame context
|
||||
// Frame template is used because we need to target the lowest nested frame
|
||||
.object-browse-bar .btn-bar {
|
||||
.right {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
@@ -165,7 +150,7 @@ body.desktop .frame {
|
||||
// Target the first descendant so that we only show the elements in the outermost container.
|
||||
// Handles the case where we have layouts in layouts.
|
||||
&:hover > .object-browse-bar {
|
||||
.btn-bar {
|
||||
.right {
|
||||
opacity: 1;
|
||||
pointer-events: inherit;
|
||||
}
|
||||
|
||||
@@ -240,9 +240,7 @@ body.desktop .pane .mini-tab-icon.toggle-pane {
|
||||
.top-bar .buttons-main .s-button,
|
||||
.top-bar .s-menu-button,
|
||||
.tool-bar .s-button,
|
||||
.tool-bar .s-menu-button,
|
||||
.tool-bar .select,
|
||||
.tool-bar .input-labeled {
|
||||
.tool-bar .s-menu-button {
|
||||
$h: $btnToolbarH;
|
||||
height: $h;
|
||||
line-height: $h;
|
||||
|
||||
@@ -20,52 +20,35 @@
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
.s-hover-border {
|
||||
border: 1px solid transparent;
|
||||
&:hover {
|
||||
border-color: rgba($colorSelectableSelectedPrimary, 0.5) !important;
|
||||
}
|
||||
border: 1px dotted transparent;
|
||||
}
|
||||
|
||||
.s-status-editing {
|
||||
// Limit to editing mode
|
||||
$o: 0.5;
|
||||
$oHover: 0.8;
|
||||
$bc: $colorSelectableSelectedPrimary;
|
||||
// Limit to editing mode until we have sub-object selection
|
||||
.s-hover-border {
|
||||
// Show a border by default so user can see object bounds and empty objects
|
||||
border-color: rgba($bc, $o) !important;
|
||||
border-style: dotted !important;
|
||||
|
||||
border: 1px dotted rgba($colorSelectableSelectedPrimary, 0.3) !important;
|
||||
&:hover {
|
||||
border-color: rgba($bc, $oHover) !important;
|
||||
}
|
||||
|
||||
&.t-object-type-layout {
|
||||
border-style: dashed !important;
|
||||
border-color: rgba($colorSelectableSelectedPrimary, 0.7) !important;
|
||||
}
|
||||
}
|
||||
.s-selected {
|
||||
&.s-moveable {
|
||||
&:not(.s-drilled-in) {
|
||||
cursor: move;
|
||||
|
||||
.s-selected > .s-hover-border,
|
||||
.s-selected.s-hover-border {
|
||||
// Styles for a selected object. Also used by legacy Fixed Position/Panel objects.
|
||||
border-color: $colorSelectableSelectedPrimary !important;
|
||||
@include boxShdwLarge();
|
||||
// Show edit-corners if you got 'em
|
||||
.edit-corner {
|
||||
display: block;
|
||||
&:hover {
|
||||
background-color: rgba($colorKey, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.s-selected > .s-hover-border,
|
||||
.s-selected.s-hover-border {
|
||||
// Styles for a selected object. Also used by legacy Fixed Position/Panel objects.
|
||||
border-color: $colorSelectableSelectedPrimary !important;
|
||||
@include boxShdwLarge();
|
||||
// Show edit-corners if you got 'em
|
||||
.edit-corner {
|
||||
display: block;
|
||||
&:hover {
|
||||
background-color: rgba($colorKey, 1);
|
||||
}
|
||||
.s-selected > .s-moveable,
|
||||
.s-selected.s-moveable {
|
||||
cursor: move;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -20,7 +20,6 @@
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
.tool-bar {
|
||||
font-size: 0.7rem;
|
||||
&.btn-bar {
|
||||
white-space: nowrap;
|
||||
}
|
||||
@@ -31,7 +30,9 @@
|
||||
input[type="search"],
|
||||
input[type="number"] {
|
||||
box-sizing: border-box;
|
||||
font-size: .8em;
|
||||
height: $btnToolbarH;
|
||||
margin-bottom: 1px;
|
||||
position: relative;
|
||||
&.sm {
|
||||
width: $btnToolbarH;
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
<span ng-controller="DateTimeFieldController">
|
||||
<input type="text" autocorrect="off" spellcheck="false"
|
||||
<input type="text"
|
||||
ng-model="textValue"
|
||||
ng-blur="restoreTextValue(); ngBlur()"
|
||||
ng-mouseup="ngMouseup()"
|
||||
|
||||
@@ -40,7 +40,7 @@ define(
|
||||
|
||||
// Gets an array of the contextual parents/ancestors of the selected object
|
||||
function getContextualPath() {
|
||||
var currentObj = $scope.domainObject,
|
||||
var currentObj = $scope.ngModel.selectedObject,
|
||||
currentParent,
|
||||
parents = [];
|
||||
|
||||
@@ -68,7 +68,7 @@ define(
|
||||
|
||||
// If this the the initial call of this recursive function
|
||||
if (!current) {
|
||||
current = $scope.domainObject;
|
||||
current = $scope.ngModel.selectedObject;
|
||||
$scope.primaryParents = [];
|
||||
}
|
||||
|
||||
@@ -87,16 +87,16 @@ define(
|
||||
|
||||
// Gets the metadata for the selected object
|
||||
function getMetadata() {
|
||||
$scope.metadata = $scope.domainObject &&
|
||||
$scope.domainObject.hasCapability('metadata') &&
|
||||
$scope.domainObject.useCapability('metadata');
|
||||
$scope.metadata = $scope.ngModel.selectedObject &&
|
||||
$scope.ngModel.selectedObject.hasCapability('metadata') &&
|
||||
$scope.ngModel.selectedObject.useCapability('metadata');
|
||||
}
|
||||
|
||||
// Set scope variables when the selected object changes
|
||||
$scope.$watch('domainObject', function () {
|
||||
$scope.isLink = $scope.domainObject &&
|
||||
$scope.domainObject.hasCapability('location') &&
|
||||
$scope.domainObject.getCapability('location').isLink();
|
||||
$scope.$watch('ngModel.selectedObject', function () {
|
||||
$scope.isLink = $scope.ngModel.selectedObject &&
|
||||
$scope.ngModel.selectedObject.hasCapability('location') &&
|
||||
$scope.ngModel.selectedObject.getCapability('location').isLink();
|
||||
|
||||
if ($scope.isLink) {
|
||||
getPrimaryPath();
|
||||
@@ -108,11 +108,8 @@ define(
|
||||
|
||||
getMetadata();
|
||||
});
|
||||
|
||||
var mutation = $scope.domainObject.getCapability('mutation');
|
||||
var unlisten = mutation.listen(getMetadata);
|
||||
$scope.$on('$destroy', unlisten);
|
||||
}
|
||||
|
||||
return ObjectInspectorController;
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2017, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
|
||||
/**
|
||||
* The mct-selectable directive allows selection functionality
|
||||
* (click) to be attached to specific elements.
|
||||
*
|
||||
* @memberof platform/commonUI/general
|
||||
* @constructor
|
||||
*/
|
||||
function MCTSelectable(openmct) {
|
||||
|
||||
// Link; install event handlers.
|
||||
function link(scope, element, attrs) {
|
||||
var removeSelectable = openmct.selection.selectable(
|
||||
element[0],
|
||||
scope.$eval(attrs.mctSelectable),
|
||||
attrs.hasOwnProperty('mctInitSelect') && scope.$eval(attrs.mctInitSelect) !== false
|
||||
);
|
||||
|
||||
scope.$on("$destroy", function () {
|
||||
removeSelectable();
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
// mct-selectable only makes sense as an attribute
|
||||
restrict: "A",
|
||||
// Link function, to install event handlers
|
||||
link: link
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
return MCTSelectable;
|
||||
}
|
||||
);
|
||||
@@ -117,7 +117,9 @@ define(
|
||||
|
||||
// Apply styles to child elements
|
||||
function updateChildren(children) {
|
||||
position = userWidthPreference || position;
|
||||
if (alias) {
|
||||
position = userWidthPreference || position;
|
||||
}
|
||||
|
||||
// Pick out correct elements to update, flowing from
|
||||
// selected anchor edge.
|
||||
@@ -180,9 +182,7 @@ define(
|
||||
}
|
||||
|
||||
function setUserWidthPreference(value) {
|
||||
if (alias) {
|
||||
userWidthPreference = value;
|
||||
}
|
||||
userWidthPreference = value;
|
||||
}
|
||||
|
||||
function persistToLocalStorage(value) {
|
||||
|
||||
@@ -39,8 +39,10 @@ define(
|
||||
beforeEach(function () {
|
||||
mockScope = jasmine.createSpyObj(
|
||||
"$scope",
|
||||
["$watch", "$on"]
|
||||
["$watch"]
|
||||
);
|
||||
mockScope.ngModel = {};
|
||||
mockScope.ngModel.selectedObject = 'mock selected object';
|
||||
|
||||
mockObjectService = jasmine.createSpyObj(
|
||||
"objectService",
|
||||
@@ -67,27 +69,22 @@ define(
|
||||
"location capability",
|
||||
["isLink"]
|
||||
);
|
||||
|
||||
mockDomainObject.getCapability.andCallFake(function (param) {
|
||||
if (param === 'location') {
|
||||
return mockLocationCapability;
|
||||
} else if (param === 'context') {
|
||||
return mockContextCapability;
|
||||
} else if (param === 'mutation') {
|
||||
return {
|
||||
listen: function () {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
mockScope.domainObject = mockDomainObject;
|
||||
controller = new ObjectInspectorController(mockScope, mockObjectService);
|
||||
|
||||
// Change the selected object to trigger the watch call
|
||||
mockScope.ngModel.selectedObject = mockDomainObject;
|
||||
});
|
||||
|
||||
it("watches for changes to the selected object", function () {
|
||||
expect(mockScope.$watch).toHaveBeenCalledWith('domainObject', jasmine.any(Function));
|
||||
expect(mockScope.$watch).toHaveBeenCalledWith('ngModel.selectedObject', jasmine.any(Function));
|
||||
});
|
||||
|
||||
it("looks for contextual parent objects", function () {
|
||||
|
||||
@@ -65,10 +65,6 @@ define(
|
||||
options = Object.create(OPTIONS);
|
||||
options.marginX = -bubbleSpaceLR;
|
||||
|
||||
// prevent bubble from appearing right under pointer,
|
||||
// which causes hover callback to be called multiple times
|
||||
options.offsetX = 1;
|
||||
|
||||
// On a phone, bubble takes up more screen real estate,
|
||||
// so position it differently (toward the bottom)
|
||||
if (this.agentService.isPhone()) {
|
||||
|
||||
@@ -38,8 +38,7 @@ define([
|
||||
"implementation": InspectorController,
|
||||
"depends": [
|
||||
"$scope",
|
||||
"openmct",
|
||||
"$document"
|
||||
"policyService"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
@@ -21,73 +21,44 @@
|
||||
*****************************************************************************/
|
||||
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
['../../browse/src/InspectorRegion'],
|
||||
function (InspectorRegion) {
|
||||
|
||||
/**
|
||||
* The InspectorController listens for the selection changes and adds the selection
|
||||
* object to the scope.
|
||||
* The InspectorController adds region data for a domain object's type
|
||||
* to the scope.
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
function InspectorController($scope, openmct, $document) {
|
||||
var self = this;
|
||||
self.$scope = $scope;
|
||||
function InspectorController($scope, policyService) {
|
||||
var domainObject = $scope.domainObject,
|
||||
typeCapability = domainObject.getCapability('type'),
|
||||
statusListener;
|
||||
|
||||
/**
|
||||
* Callback handler for the selection change event.
|
||||
* Adds the selection object to the scope. If the selected item has an inspector view,
|
||||
* it puts the key in the scope. If provider view exists, it shows the view.
|
||||
* Filters region parts to only those allowed by region policies
|
||||
* @param regions
|
||||
* @returns {{}}
|
||||
*/
|
||||
function setSelection(selection) {
|
||||
if (selection[0]) {
|
||||
var view = openmct.inspectorViews.get(selection);
|
||||
var container = $document[0].querySelectorAll('.inspector-provider-view')[0];
|
||||
container.innerHTML = "";
|
||||
|
||||
if (view) {
|
||||
self.providerView = true;
|
||||
view.show(container);
|
||||
} else {
|
||||
self.providerView = false;
|
||||
var selectedItem = selection[0].context.oldItem;
|
||||
|
||||
if (selectedItem) {
|
||||
$scope.inspectorKey = selectedItem.getCapability("type").typeDef.inspector;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.$scope.selection = selection;
|
||||
function filterRegions(inspector) {
|
||||
//Dupe so we're not modifying the type definition.
|
||||
return inspector.regions && inspector.regions.filter(function (region) {
|
||||
return policyService.allow('region', region, domainObject);
|
||||
});
|
||||
}
|
||||
|
||||
openmct.selection.on("change", setSelection);
|
||||
|
||||
setSelection(openmct.selection.get());
|
||||
function setRegions() {
|
||||
$scope.regions = filterRegions(typeCapability.getDefinition().inspector || new InspectorRegion());
|
||||
}
|
||||
|
||||
statusListener = domainObject.getCapability("status").listen(setRegions);
|
||||
$scope.$on("$destroy", function () {
|
||||
openmct.selection.off("change", setSelection);
|
||||
statusListener();
|
||||
});
|
||||
|
||||
setRegions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the selected item.
|
||||
*
|
||||
* @returns a domain object
|
||||
*/
|
||||
InspectorController.prototype.selectedItem = function () {
|
||||
return this.$scope.selection[0].context.oldItem;
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks if a provider view exists.
|
||||
*
|
||||
* @returns 'true' if provider view exists, 'false' otherwise
|
||||
*/
|
||||
InspectorController.prototype.hasProviderView = function () {
|
||||
return this.providerView;
|
||||
};
|
||||
|
||||
return InspectorController;
|
||||
}
|
||||
);
|
||||
|
||||
@@ -27,93 +27,82 @@ define(
|
||||
describe("The inspector controller ", function () {
|
||||
var mockScope,
|
||||
mockDomainObject,
|
||||
mockOpenMCT,
|
||||
mockSelection,
|
||||
mockInspectorViews,
|
||||
mockTypeDef,
|
||||
controller,
|
||||
container,
|
||||
$document = [],
|
||||
selectable = [];
|
||||
mockTypeCapability,
|
||||
mockTypeDefinition,
|
||||
mockPolicyService,
|
||||
mockStatusCapability,
|
||||
capabilities = {},
|
||||
controller;
|
||||
|
||||
beforeEach(function () {
|
||||
mockTypeDef = {
|
||||
typeDef: {
|
||||
inspector: "some-key"
|
||||
}
|
||||
mockTypeDefinition = {
|
||||
inspector:
|
||||
{
|
||||
'regions': [
|
||||
{'name': 'Part One'},
|
||||
{'name': 'Part Two'}
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
mockTypeCapability = jasmine.createSpyObj('typeCapability', [
|
||||
'getDefinition'
|
||||
]);
|
||||
mockTypeCapability.getDefinition.andReturn(mockTypeDefinition);
|
||||
capabilities.type = mockTypeCapability;
|
||||
|
||||
mockStatusCapability = jasmine.createSpyObj('statusCapability', [
|
||||
'listen'
|
||||
]);
|
||||
capabilities.status = mockStatusCapability;
|
||||
|
||||
mockDomainObject = jasmine.createSpyObj('domainObject', [
|
||||
'getCapability'
|
||||
]);
|
||||
mockDomainObject.getCapability.andReturn(mockTypeDef);
|
||||
mockDomainObject.getCapability.andCallFake(function (name) {
|
||||
return capabilities[name];
|
||||
});
|
||||
|
||||
mockPolicyService = jasmine.createSpyObj('policyService', [
|
||||
'allow'
|
||||
]);
|
||||
|
||||
mockScope = jasmine.createSpyObj('$scope',
|
||||
['$on', 'selection']
|
||||
['$on']
|
||||
);
|
||||
|
||||
selectable[0] = {
|
||||
context: {
|
||||
oldItem: mockDomainObject
|
||||
}
|
||||
};
|
||||
|
||||
mockSelection = jasmine.createSpyObj("selection", [
|
||||
'on',
|
||||
'off',
|
||||
'get'
|
||||
]);
|
||||
mockSelection.get.andReturn(selectable);
|
||||
|
||||
mockInspectorViews = jasmine.createSpyObj('inspectorViews', ['get']);
|
||||
mockOpenMCT = {
|
||||
selection: mockSelection,
|
||||
inspectorViews: mockInspectorViews
|
||||
};
|
||||
|
||||
container = jasmine.createSpy('container', ['innerHTML']);
|
||||
$document[0] = jasmine.createSpyObj("$document", ['querySelectorAll']);
|
||||
$document[0].querySelectorAll.andReturn([container]);
|
||||
|
||||
controller = new InspectorController(mockScope, mockOpenMCT, $document);
|
||||
mockScope.domainObject = mockDomainObject;
|
||||
});
|
||||
|
||||
it("listens for selection change event", function () {
|
||||
expect(mockOpenMCT.selection.on).toHaveBeenCalledWith(
|
||||
'change',
|
||||
jasmine.any(Function)
|
||||
);
|
||||
|
||||
expect(controller.selectedItem()).toEqual(mockDomainObject);
|
||||
|
||||
var mockItem = jasmine.createSpyObj('domainObject', [
|
||||
'getCapability'
|
||||
]);
|
||||
mockItem.getCapability.andReturn(mockTypeDef);
|
||||
selectable[0].context.oldItem = mockItem;
|
||||
|
||||
mockOpenMCT.selection.on.mostRecentCall.args[1](selectable);
|
||||
|
||||
expect(controller.selectedItem()).toEqual(mockItem);
|
||||
it("filters out regions disallowed by region policy", function () {
|
||||
mockPolicyService.allow.andReturn(false);
|
||||
controller = new InspectorController(mockScope, mockPolicyService);
|
||||
expect(mockScope.regions.length).toBe(0);
|
||||
});
|
||||
|
||||
it("cleans up on scope destroy", function () {
|
||||
expect(mockScope.$on).toHaveBeenCalledWith(
|
||||
'$destroy',
|
||||
jasmine.any(Function)
|
||||
);
|
||||
|
||||
mockScope.$on.calls[0].args[1]();
|
||||
|
||||
expect(mockOpenMCT.selection.off).toHaveBeenCalledWith(
|
||||
'change',
|
||||
jasmine.any(Function)
|
||||
);
|
||||
it("does not filter out regions allowed by region policy", function () {
|
||||
mockPolicyService.allow.andReturn(true);
|
||||
controller = new InspectorController(mockScope, mockPolicyService);
|
||||
expect(mockScope.regions.length).toBe(2);
|
||||
});
|
||||
|
||||
it("adds selection object to scope", function () {
|
||||
expect(mockScope.selection).toEqual(selectable);
|
||||
expect(controller.selectedItem()).toEqual(mockDomainObject);
|
||||
it("Responds to status changes", function () {
|
||||
mockPolicyService.allow.andReturn(true);
|
||||
controller = new InspectorController(mockScope, mockPolicyService);
|
||||
expect(mockScope.regions.length).toBe(2);
|
||||
expect(mockStatusCapability.listen).toHaveBeenCalled();
|
||||
mockPolicyService.allow.andReturn(false);
|
||||
mockStatusCapability.listen.mostRecentCall.args[0]();
|
||||
expect(mockScope.regions.length).toBe(0);
|
||||
});
|
||||
|
||||
it("Unregisters status listener", function () {
|
||||
var mockListener = jasmine.createSpy('listener');
|
||||
mockStatusCapability.listen.andReturn(mockListener);
|
||||
controller = new InspectorController(mockScope, mockPolicyService);
|
||||
expect(mockScope.$on).toHaveBeenCalledWith("$destroy", jasmine.any(Function));
|
||||
mockScope.$on.mostRecentCall.args[1]();
|
||||
expect(mockListener).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -201,15 +201,13 @@ $shdwItemTreeIcon: 0.6;
|
||||
$colorThumbHoverBg: $colorItemTreeHoverBg;
|
||||
|
||||
// Scrollbar
|
||||
$scrollbarTrackSize: 7px;
|
||||
$scrollbarTrackShdw: rgba(#000, 0.5) 0 1px 5px;
|
||||
$scrollbarTrackColorBg: transparent; //rgba(#000, 0.4);
|
||||
$scrollbarTrackSize: 10px;
|
||||
$scrollbarTrackShdw: rgba(#000, 0.7) 0 1px 5px;
|
||||
$scrollbarTrackColorBg: rgba(#000, 0.4);
|
||||
$scrollbarThumbColor: pullForward($colorBodyBg, 10%);
|
||||
$scrollbarThumbColorHov: pullForward($scrollbarThumbColor, 2%);
|
||||
$scrollbarThumbColorOverlay: pullForward($colorOvrBg, 10%);
|
||||
$scrollbarThumbColorOverlayHov: pullForward($scrollbarThumbColorOverlay, 2%);
|
||||
$scrollbarThumbColorMenu: pullForward($colorMenuBg, 20%);
|
||||
$scrollbarThumbColorMenuHov: pullForward($scrollbarThumbColorMenu, 2%);
|
||||
|
||||
// Splitter
|
||||
// All splitterD* values MUST both be either odd or even numbers
|
||||
@@ -243,12 +241,6 @@ $colorCalCellSelectedBg: $colorItemTreeSelectedBg;
|
||||
$colorCalCellSelectedFg: $colorItemTreeSelectedFg;
|
||||
$colorCalCellInMonthBg: pushBack($colorMenuBg, 5%);
|
||||
|
||||
// Palettes
|
||||
$colorPaletteFg: pullForward($colorMenuBg, 30%);
|
||||
$colorPaletteSelected: #fff;
|
||||
$shdwPaletteFg: black 0 0 2px;
|
||||
$shdwPaletteSelected: inset 0 0 0 1px #000;
|
||||
|
||||
// About Screen
|
||||
$colorAboutLink: #84b3ff;
|
||||
|
||||
|
||||
@@ -201,15 +201,13 @@ $shdwItemTreeIcon: none;
|
||||
$colorThumbHoverBg: $colorItemTreeHoverBg;
|
||||
|
||||
// Scrollbar
|
||||
$scrollbarTrackSize: 7px;
|
||||
$scrollbarTrackSize: 10px;
|
||||
$scrollbarTrackShdw: rgba(#000, 0.2) 0 1px 2px;
|
||||
$scrollbarTrackColorBg: rgba(#000, 0.2);
|
||||
$scrollbarThumbColor: darken($colorBodyBg, 50%);
|
||||
$scrollbarThumbColorHov: $colorKey;
|
||||
$scrollbarThumbColorOverlay: darken($colorOvrBg, 50%);
|
||||
$scrollbarThumbColorOverlayHov: $scrollbarThumbColorHov;
|
||||
$scrollbarThumbColorMenu: pullForward($colorMenuBg, 10%);
|
||||
$scrollbarThumbColorMenuHov: pullForward($scrollbarThumbColorMenu, 2%);
|
||||
|
||||
// Splitter
|
||||
// All splitterD* values MUST both be either odd or even numbers
|
||||
@@ -243,12 +241,6 @@ $colorCalCellSelectedBg: $colorItemTreeSelectedBg;
|
||||
$colorCalCellSelectedFg: $colorItemTreeSelectedFg;
|
||||
$colorCalCellInMonthBg: pullForward($colorMenuBg, 5%);
|
||||
|
||||
// Palettes
|
||||
$colorPaletteFg: pullForward($colorMenuBg, 30%);
|
||||
$colorPaletteSelected: #333;
|
||||
$shdwPaletteFg: none;
|
||||
$shdwPaletteSelected: inset 0 0 0 1px #fff;
|
||||
|
||||
// About Screen
|
||||
$colorAboutLink: #84b3ff;
|
||||
|
||||
|
||||
@@ -94,6 +94,31 @@ define([
|
||||
}
|
||||
},
|
||||
"extensions": {
|
||||
"versions": [
|
||||
{
|
||||
"name": "Version",
|
||||
"value": "@@version",
|
||||
"priority": 999
|
||||
},
|
||||
{
|
||||
"name": "Built",
|
||||
"value": "@@timestamp",
|
||||
"description": "The date on which this version of the client was built.",
|
||||
"priority": 990
|
||||
},
|
||||
{
|
||||
"name": "Revision",
|
||||
"value": "@@revision",
|
||||
"description": "A unique revision identifier for the client sources.",
|
||||
"priority": 995
|
||||
},
|
||||
{
|
||||
"name": "Branch",
|
||||
"value": "@@branch",
|
||||
"description": "The name of the branch that was used during the build.",
|
||||
"priority": 994
|
||||
}
|
||||
],
|
||||
"components": [
|
||||
{
|
||||
"provides": "objectService",
|
||||
|
||||
54
platform/features/autoflow/plugin.js
Executable file
54
platform/features/autoflow/plugin.js
Executable file
@@ -0,0 +1,54 @@
|
||||
define([
|
||||
'text!./res/templates/autoflow-tabular.html',
|
||||
'./src/AutoflowTabularController',
|
||||
'./src/MCTAutoflowTable'
|
||||
], function (
|
||||
autoflowTabularTemplate,
|
||||
AutoflowTabularController,
|
||||
MCTAutoflowTable
|
||||
) {
|
||||
return function (options) {
|
||||
return function (openmct) {
|
||||
openmct.legacyRegistry.register("platform/features/autoflow", {
|
||||
"name": "WARP Telemetry Adapter",
|
||||
"description": "Retrieves telemetry from the WARP Server and provides related types and views.",
|
||||
"resources": "res",
|
||||
"extensions": {
|
||||
"views": [
|
||||
{
|
||||
"key": "autoflow",
|
||||
"name": "Autoflow Tabular",
|
||||
"cssClass": "icon-packet",
|
||||
"description": "A tabular view of packet contents.",
|
||||
"template": autoflowTabularTemplate,
|
||||
"type": options && options.type,
|
||||
"needs": [
|
||||
"telemetry"
|
||||
],
|
||||
"delegation": true
|
||||
}
|
||||
],
|
||||
"controllers": [
|
||||
{
|
||||
"key": "AutoflowTabularController",
|
||||
"implementation": AutoflowTabularController,
|
||||
"depends": [
|
||||
"$scope",
|
||||
"$timeout",
|
||||
"telemetrySubscriber"
|
||||
]
|
||||
}
|
||||
],
|
||||
"directives": [
|
||||
{
|
||||
"key": "mctAutoflowTable",
|
||||
"implementation": MCTAutoflowTable
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
openmct.legacyRegistry.enable("platform/features/autoflow");
|
||||
};
|
||||
};
|
||||
});
|
||||
|
||||
26
platform/features/autoflow/res/templates/autoflow-tabular.html
Executable file
26
platform/features/autoflow/res/templates/autoflow-tabular.html
Executable file
@@ -0,0 +1,26 @@
|
||||
<div class="items-holder abs contents autoflow obj-value-format"
|
||||
ng-controller="AutoflowTabularController as autoflow">
|
||||
<div class="abs l-flex-row holder t-autoflow-header l-autoflow-header">
|
||||
<mct-include key="'input-filter'"
|
||||
ng-model="autoflow.filter"
|
||||
class="flex-elem">
|
||||
</mct-include>
|
||||
<div class="flex-elem grows t-last-update" title="Last Update">{{autoflow.updated()}}</div>
|
||||
<a title="Change column width"
|
||||
class="s-button flex-elem icon-arrows-right-left change-column-width"
|
||||
ng-click="autoflow.increaseColumnWidth()"></a>
|
||||
</div>
|
||||
<div class="abs t-autoflow-items l-autoflow-items"
|
||||
mct-resize="autoflow.setBounds(bounds)"
|
||||
mct-resize-interval="50">
|
||||
<mct-autoflow-table values="autoflow.rangeValues()"
|
||||
objects="autoflow.getTelemetryObjects()"
|
||||
rows="autoflow.getRows()"
|
||||
classes="autoflow.classes()"
|
||||
updated="autoflow.updated()"
|
||||
column-width="autoflow.columnWidth()"
|
||||
counter="autoflow.counter()"
|
||||
>
|
||||
</mct-autoflow-table>
|
||||
</div>
|
||||
</div>
|
||||
169
platform/features/autoflow/src/AutoflowTableLinker.js
Executable file
169
platform/features/autoflow/src/AutoflowTableLinker.js
Executable file
@@ -0,0 +1,169 @@
|
||||
/*global angular*/
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
|
||||
/**
|
||||
* The link step for the `mct-autoflow-table` directive;
|
||||
* watches scope and updates the DOM appropriately.
|
||||
* See documentation in `MCTAutoflowTable.js` for the rationale
|
||||
* for including this directive, as well as for an explanation
|
||||
* of which values are placed in scope.
|
||||
*
|
||||
* @constructor
|
||||
* @param {Scope} scope the scope for this usage of the directive
|
||||
* @param element the jqLite-wrapped element which used this directive
|
||||
*/
|
||||
function AutoflowTableLinker(scope, element) {
|
||||
var objects, // Domain objects at last structure refresh
|
||||
rows, // Number of rows from last structure refresh
|
||||
priorClasses = {},
|
||||
valueSpans = {}; // Span elements to put data values in
|
||||
|
||||
// Create a new name-value pair in the specified column
|
||||
function createListItem(domainObject, ul) {
|
||||
// Create a new li, and spans to go in it.
|
||||
var li = angular.element('<li>'),
|
||||
titleSpan = angular.element('<span>'),
|
||||
valueSpan = angular.element('<span>');
|
||||
|
||||
// Place spans in the li, and li into the column.
|
||||
// valueSpan must precede titleSpan in the DOM due to new CSS float approach
|
||||
li.append(valueSpan).append(titleSpan);
|
||||
ul.append(li);
|
||||
|
||||
// Style appropriately
|
||||
li.addClass('l-autoflow-row');
|
||||
titleSpan.addClass('l-autoflow-item l');
|
||||
valueSpan.addClass('l-autoflow-item r l-obj-val-format');
|
||||
|
||||
// Set text/tooltip for the name-value row
|
||||
titleSpan.text(domainObject.getModel().name);
|
||||
titleSpan.attr("title", domainObject.getModel().name);
|
||||
|
||||
// Keep a reference to the span which will hold the
|
||||
// data value, to populate in the next refreshValues call
|
||||
valueSpans[domainObject.getId()] = valueSpan;
|
||||
|
||||
return li;
|
||||
}
|
||||
|
||||
// Create a new column of name-value pairs in this table.
|
||||
function createColumn(el) {
|
||||
// Create a ul
|
||||
var ul = angular.element('<ul>');
|
||||
|
||||
// Add it into the mct-autoflow-table
|
||||
el.append(ul);
|
||||
|
||||
// Style appropriately
|
||||
ul.addClass('l-autoflow-col');
|
||||
|
||||
// Get the current col width and apply at time of column creation
|
||||
// Important to do this here, as new columns could be created after
|
||||
// the user has changed the width.
|
||||
ul.css('width', scope.columnWidth + 'px');
|
||||
|
||||
// Return it, so some li elements can be added
|
||||
return ul;
|
||||
}
|
||||
|
||||
// Change the width of the columns when user clicks the resize button.
|
||||
function resizeColumn() {
|
||||
element.find('ul').css('width', scope.columnWidth + 'px');
|
||||
}
|
||||
|
||||
// Rebuild the DOM associated with this table.
|
||||
function rebuild(domainObjects, rowCount) {
|
||||
var activeColumn;
|
||||
|
||||
// Empty out our cached span elements
|
||||
valueSpans = {};
|
||||
|
||||
// Start with an empty DOM beneath this directive
|
||||
element.html("");
|
||||
|
||||
// Add DOM elements for each domain object being displayed
|
||||
// in this table.
|
||||
domainObjects.forEach(function (object, index) {
|
||||
// Start a new column if we'd run out of room
|
||||
if (index % rowCount === 0) {
|
||||
activeColumn = createColumn(element);
|
||||
}
|
||||
// Add the DOM elements for that object to whichever
|
||||
// column (a `ul` element) is current.
|
||||
createListItem(object, activeColumn);
|
||||
});
|
||||
}
|
||||
|
||||
// Update spans with values, as made available via the
|
||||
// `values` attribute of this directive.
|
||||
function refreshValues() {
|
||||
// Get the available values
|
||||
var values = scope.values || {},
|
||||
classes = scope.classes || {};
|
||||
|
||||
// Populate all spans with those values (or clear
|
||||
// those spans if no value is available)
|
||||
(objects || []).forEach(function (object) {
|
||||
var id = object.getId(),
|
||||
span = valueSpans[id],
|
||||
value;
|
||||
|
||||
if (span) {
|
||||
// Look up the value...
|
||||
value = values[id];
|
||||
// ...and convert to empty string if it's undefined
|
||||
value = value === undefined ? "" : value;
|
||||
span.attr("data-value", value);
|
||||
|
||||
// Update the span
|
||||
span.text(value);
|
||||
span.attr("title", value);
|
||||
span.removeClass(priorClasses[id]);
|
||||
span.addClass(classes[id]);
|
||||
priorClasses[id] = classes[id];
|
||||
}
|
||||
// Also need stale/alert/ok class
|
||||
// on span
|
||||
});
|
||||
}
|
||||
|
||||
// Refresh the DOM for this table, if necessary
|
||||
function refreshStructure() {
|
||||
// Only rebuild if number of rows or set of objects
|
||||
// has changed; otherwise, our structure is still valid.
|
||||
if (scope.objects !== objects ||
|
||||
scope.rows !== rows) {
|
||||
|
||||
// Track those values to support future refresh checks
|
||||
objects = scope.objects;
|
||||
rows = scope.rows;
|
||||
|
||||
// Rebuild the DOM
|
||||
rebuild(objects || [], rows || 1);
|
||||
|
||||
// Refresh all data values shown
|
||||
refreshValues();
|
||||
}
|
||||
}
|
||||
|
||||
// Changing the domain objects in use or the number
|
||||
// of rows should trigger a structure change (DOM rebuild)
|
||||
scope.$watch("objects", refreshStructure);
|
||||
scope.$watch("rows", refreshStructure);
|
||||
|
||||
// When the current column width has been changed, resize the column
|
||||
scope.$watch('columnWidth', resizeColumn);
|
||||
|
||||
// When the last-updated time ticks,
|
||||
scope.$watch("updated", refreshValues);
|
||||
|
||||
// Update displayed values when the counter changes.
|
||||
scope.$watch("counter", refreshValues);
|
||||
|
||||
}
|
||||
|
||||
return AutoflowTableLinker;
|
||||
}
|
||||
);
|
||||
324
platform/features/autoflow/src/AutoflowTabularController.js
Executable file
324
platform/features/autoflow/src/AutoflowTabularController.js
Executable file
@@ -0,0 +1,324 @@
|
||||
|
||||
define(
|
||||
['moment'],
|
||||
function (moment) {
|
||||
|
||||
var ROW_HEIGHT = 16,
|
||||
SLIDER_HEIGHT = 10,
|
||||
INITIAL_COLUMN_WIDTH = 225,
|
||||
MAX_COLUMN_WIDTH = 525,
|
||||
COLUMN_WIDTH_STEP = 25,
|
||||
DEBOUNCE_INTERVAL = 100,
|
||||
DATE_FORMAT = "YYYY-DDD HH:mm:ss.SSS\\Z",
|
||||
NOT_UPDATED = "No updates",
|
||||
EMPTY_ARRAY = [];
|
||||
|
||||
/**
|
||||
* Responsible for supporting the autoflow tabular view.
|
||||
* Implements the all-over logic which drives that view,
|
||||
* mediating between template-provided areas, the included
|
||||
* `mct-autoflow-table` directive, and the underlying
|
||||
* domain object model.
|
||||
* @constructor
|
||||
*/
|
||||
function AutflowTabularController(
|
||||
$scope,
|
||||
$timeout,
|
||||
telemetrySubscriber
|
||||
) {
|
||||
var filterValue = "",
|
||||
filterValueLowercase = "",
|
||||
subscription,
|
||||
filteredObjects = [],
|
||||
lastUpdated = {},
|
||||
updateText = NOT_UPDATED,
|
||||
rangeValues = {},
|
||||
classes = {},
|
||||
limits = {},
|
||||
updatePending = false,
|
||||
lastBounce = Number.NEGATIVE_INFINITY,
|
||||
columnWidth = INITIAL_COLUMN_WIDTH,
|
||||
rows = 1,
|
||||
counter = 0;
|
||||
|
||||
// Trigger an update of the displayed table by incrementing
|
||||
// the counter that it watches.
|
||||
function triggerDisplayUpdate() {
|
||||
counter += 1;
|
||||
}
|
||||
|
||||
// Check whether or not an object's name matches the
|
||||
// user-entered filter value.
|
||||
function filterObject(domainObject) {
|
||||
return (domainObject.getModel().name || "")
|
||||
.toLowerCase()
|
||||
.indexOf(filterValueLowercase) !== -1;
|
||||
}
|
||||
|
||||
// Comparator for sorting points back into packet order
|
||||
function compareObject(objectA, objectB) {
|
||||
var indexA = objectA.getModel().index || 0,
|
||||
indexB = objectB.getModel().index || 0;
|
||||
return indexA - indexB;
|
||||
}
|
||||
|
||||
// Update the list of currently-displayed objects; these
|
||||
// will be the subset of currently subscribed-to objects
|
||||
// which match a user-entered filter.
|
||||
function doUpdateFilteredObjects() {
|
||||
// Generate the list
|
||||
filteredObjects = (
|
||||
subscription ?
|
||||
subscription.getTelemetryObjects() :
|
||||
[]
|
||||
).filter(filterObject).sort(compareObject);
|
||||
|
||||
// Clear the pending flag
|
||||
updatePending = false;
|
||||
|
||||
// Track when this occurred, so that we can wait
|
||||
// a whole before updating again.
|
||||
lastBounce = Date.now();
|
||||
|
||||
triggerDisplayUpdate();
|
||||
}
|
||||
|
||||
// Request an update to the list of current objects; this may
|
||||
// run on a timeout to avoid excessive calls, e.g. while the user
|
||||
// is typing a filter.
|
||||
function updateFilteredObjects() {
|
||||
// Don't do anything if an update is already scheduled
|
||||
if (!updatePending) {
|
||||
if (Date.now() > lastBounce + DEBOUNCE_INTERVAL) {
|
||||
// Update immediately if it's been long enough
|
||||
doUpdateFilteredObjects();
|
||||
} else {
|
||||
// Otherwise, update later, and track that we have
|
||||
// an update pending so that subsequent calls can
|
||||
// be ignored.
|
||||
updatePending = true;
|
||||
$timeout(doUpdateFilteredObjects, DEBOUNCE_INTERVAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Track the latest data values for this domain object
|
||||
function recordData(telemetryObject) {
|
||||
// Get latest domain/range values for this object.
|
||||
var id = telemetryObject.getId(),
|
||||
domainValue = subscription.getDomainValue(telemetryObject),
|
||||
rangeValue = subscription.getRangeValue(telemetryObject);
|
||||
|
||||
// Track the most recent timestamp change observed...
|
||||
if (domainValue !== undefined && domainValue !== lastUpdated[id]) {
|
||||
lastUpdated[id] = domainValue;
|
||||
// ... and update the displayable text for that timestamp
|
||||
updateText = isNaN(domainValue) ? "" :
|
||||
moment.utc(domainValue).format(DATE_FORMAT);
|
||||
}
|
||||
|
||||
// Store data values into the rangeValues structure, which
|
||||
// will be used to populate the table itself.
|
||||
// Note that we want full precision here.
|
||||
rangeValues[id] = rangeValue;
|
||||
|
||||
// Update limit states as well
|
||||
classes[id] = limits[id] && (limits[id].evaluate({
|
||||
// This relies on external knowledge that the
|
||||
// range value of a telemetry point is encoded
|
||||
// in its datum as "value."
|
||||
value: rangeValue
|
||||
}) || {}).cssClass;
|
||||
}
|
||||
|
||||
|
||||
// Look at telemetry objects from the subscription; this is watched
|
||||
// to detect changes from the subscription.
|
||||
function subscribedTelemetry() {
|
||||
return subscription ?
|
||||
subscription.getTelemetryObjects() : EMPTY_ARRAY;
|
||||
}
|
||||
|
||||
// Update the data values which will be used to populate the table
|
||||
function updateValues() {
|
||||
subscribedTelemetry().forEach(recordData);
|
||||
triggerDisplayUpdate();
|
||||
}
|
||||
|
||||
// Getter-setter function for user-entered filter text.
|
||||
function filter(value) {
|
||||
// If value was specified, we're a setter
|
||||
if (value !== undefined) {
|
||||
// Store the new value
|
||||
filterValue = value;
|
||||
filterValueLowercase = value.toLowerCase();
|
||||
// Change which objects appear in the table
|
||||
updateFilteredObjects();
|
||||
}
|
||||
|
||||
// Always act as a getter
|
||||
return filterValue;
|
||||
}
|
||||
|
||||
// Update the bounds (width and height) of this view;
|
||||
// called from the mct-resize directive. Recalculates how
|
||||
// many rows should appear in the contained table.
|
||||
function setBounds(bounds) {
|
||||
var availableSpace = bounds.height - SLIDER_HEIGHT;
|
||||
rows = Math.max(1, Math.floor(availableSpace / ROW_HEIGHT));
|
||||
}
|
||||
|
||||
// Increment the current column width, up to the defined maximum.
|
||||
// When the max is hit, roll back to the default.
|
||||
function increaseColumnWidth() {
|
||||
columnWidth += COLUMN_WIDTH_STEP;
|
||||
// Cycle down to the initial width instead of exceeding max
|
||||
columnWidth = columnWidth > MAX_COLUMN_WIDTH ?
|
||||
INITIAL_COLUMN_WIDTH : columnWidth;
|
||||
}
|
||||
|
||||
// Get displayable text for last-updated value
|
||||
function updated() {
|
||||
return updateText;
|
||||
}
|
||||
|
||||
// Unsubscribe, if a subscription is active.
|
||||
function releaseSubscription() {
|
||||
if (subscription) {
|
||||
subscription.unsubscribe();
|
||||
subscription = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
// Update set of telemetry objects managed by this view
|
||||
function updateTelemetryObjects(telemetryObjects) {
|
||||
updateFilteredObjects();
|
||||
limits = {};
|
||||
telemetryObjects.forEach(function (telemetryObject) {
|
||||
var id = telemetryObject.getId();
|
||||
limits[id] = telemetryObject.getCapability('limit');
|
||||
});
|
||||
}
|
||||
|
||||
// Create a subscription for the represented domain object.
|
||||
// This will resolve capability delegation as necessary.
|
||||
function makeSubscription(domainObject) {
|
||||
// Unsubscribe, if there is an existing subscription
|
||||
releaseSubscription();
|
||||
|
||||
// Clear updated timestamp
|
||||
lastUpdated = {};
|
||||
updateText = NOT_UPDATED;
|
||||
|
||||
// Create a new subscription; telemetrySubscriber gets
|
||||
// to do the meaningful work here.
|
||||
subscription = domainObject && telemetrySubscriber.subscribe(
|
||||
domainObject,
|
||||
updateValues
|
||||
);
|
||||
|
||||
// Our set of in-view telemetry objects may have changed,
|
||||
// so update the set that is being passed down to the table.
|
||||
updateFilteredObjects();
|
||||
}
|
||||
|
||||
// Watch for changes to the set of objects which have telemetry
|
||||
$scope.$watch(subscribedTelemetry, updateTelemetryObjects);
|
||||
|
||||
// Watch for the represented domainObject (this field will
|
||||
// be populated by mct-representation)
|
||||
$scope.$watch("domainObject", makeSubscription);
|
||||
|
||||
// Make sure we unsubscribe when this view is destroyed.
|
||||
$scope.$on("$destroy", releaseSubscription);
|
||||
|
||||
return {
|
||||
/**
|
||||
* Get the number of rows which should be shown in this table.
|
||||
* @return {number} the number of rows to show
|
||||
*/
|
||||
getRows: function () {
|
||||
return rows;
|
||||
},
|
||||
/**
|
||||
* Get the objects which should currently be displayed in
|
||||
* this table. This will be watched, so the return value
|
||||
* should be stable when this list is unchanging. Only
|
||||
* objects which match the user-entered filter value should
|
||||
* be returned here.
|
||||
* @return {DomainObject[]} the domain objects to include in
|
||||
* this table.
|
||||
*/
|
||||
getTelemetryObjects: function () {
|
||||
return filteredObjects;
|
||||
},
|
||||
/**
|
||||
* Set the bounds (width/height) of this autoflow tabular view.
|
||||
* The template must ensure that these bounds are tracked on
|
||||
* the table area only.
|
||||
* @param bounds the bounds; and object with `width` and
|
||||
* `height` properties, both as numbers, in pixels.
|
||||
*/
|
||||
setBounds: setBounds,
|
||||
/**
|
||||
* Increments the width of the autoflow column.
|
||||
* Setting does not yet persist.
|
||||
*/
|
||||
increaseColumnWidth: increaseColumnWidth,
|
||||
/**
|
||||
* Get-or-set the user-supplied filter value.
|
||||
* @param {string} [value] the new filter value; omit to use
|
||||
* as a getter
|
||||
* @returns {string} the user-supplied filter value
|
||||
*/
|
||||
filter: filter,
|
||||
/**
|
||||
* Get all range values for use in this table. These will be
|
||||
* returned as an object of key-value pairs, where keys are
|
||||
* domain object IDs, and values are the most recently observed
|
||||
* data values associated with those objects, formatted for
|
||||
* display.
|
||||
* @returns {object.<string,string>} most recent values
|
||||
*/
|
||||
rangeValues: function () {
|
||||
return rangeValues;
|
||||
},
|
||||
/**
|
||||
* Get CSS classes to apply to specific rows, representing limit
|
||||
* states and/or stale states. These are returned as key-value
|
||||
* pairs where keys are domain object IDs, and values are CSS
|
||||
* classes to display for domain objects with those IDs.
|
||||
* @returns {object.<string,string>} CSS classes
|
||||
*/
|
||||
classes: function () {
|
||||
return classes;
|
||||
},
|
||||
/**
|
||||
* Get the "last updated" text for this view; this will be
|
||||
* the most recent timestamp observed for any telemetry-
|
||||
* providing object, formatted for display.
|
||||
* @returns {string} the time of the most recent update
|
||||
*/
|
||||
updated: updated,
|
||||
/**
|
||||
* Get the current column width, in pixels.
|
||||
* @returns {number} column width
|
||||
*/
|
||||
columnWidth: function () {
|
||||
return columnWidth;
|
||||
},
|
||||
/**
|
||||
* Keep a counter and increment this whenever the display
|
||||
* should be updated; this will be watched by the
|
||||
* `mct-autoflow-table`.
|
||||
* @returns {number} a counter value
|
||||
*/
|
||||
counter: function () {
|
||||
return counter;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return AutflowTabularController;
|
||||
}
|
||||
);
|
||||
60
platform/features/autoflow/src/MCTAutoflowTable.js
Executable file
60
platform/features/autoflow/src/MCTAutoflowTable.js
Executable file
@@ -0,0 +1,60 @@
|
||||
|
||||
define(
|
||||
["./AutoflowTableLinker"],
|
||||
function (AutoflowTableLinker) {
|
||||
|
||||
/**
|
||||
* The `mct-autoflow-table` directive specifically supports
|
||||
* autoflow tabular views; it is not intended for use outside
|
||||
* of that view.
|
||||
*
|
||||
* This directive is responsible for creating the structure
|
||||
* of the table in this view, and for updating its values.
|
||||
* While this is achievable using a regular Angular template,
|
||||
* this is undesirable from the perspective of performance
|
||||
* due to the number of watches that can be involved for large
|
||||
* tables. Instead, this directive will maintain a small number
|
||||
* of watches, rebuilding table structure only when necessary,
|
||||
* and updating displayed values in the more common case of
|
||||
* new data arriving.
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
function MCTAutoflowTable() {
|
||||
return {
|
||||
// Only applicable at the element level
|
||||
restrict: "E",
|
||||
|
||||
// The link function; handles DOM update/manipulation
|
||||
link: AutoflowTableLinker,
|
||||
|
||||
// Parameters to pass from attributes into scope
|
||||
scope: {
|
||||
// Set of domain objects to show in the table
|
||||
objects: "=",
|
||||
|
||||
// Values for those objects, by ID
|
||||
values: "=",
|
||||
|
||||
// CSS classes to show for objects, by ID
|
||||
classes: "=",
|
||||
|
||||
// Number of rows to show before autoflowing
|
||||
rows: "=",
|
||||
|
||||
// Time of last update; watched to refresh values
|
||||
updated: "=",
|
||||
|
||||
// Current width of the autoflow column
|
||||
columnWidth: "=",
|
||||
|
||||
// A counter used to trigger display updates
|
||||
counter: "="
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return MCTAutoflowTable;
|
||||
|
||||
}
|
||||
);
|
||||
178
platform/features/autoflow/test/AutoflowTableLinkerSpec.js
Executable file
178
platform/features/autoflow/test/AutoflowTableLinkerSpec.js
Executable file
@@ -0,0 +1,178 @@
|
||||
|
||||
define(
|
||||
["../src/AutoflowTableLinker"],
|
||||
function (AutoflowTableLinker) {
|
||||
|
||||
describe("The mct-autoflow-table linker", function () {
|
||||
var cachedAngular,
|
||||
mockAngular,
|
||||
mockScope,
|
||||
mockElement,
|
||||
mockElements,
|
||||
linker;
|
||||
|
||||
// Utility function to generate more mock elements
|
||||
function createMockElement(html) {
|
||||
var mockEl = jasmine.createSpyObj(
|
||||
"element-" + html,
|
||||
[
|
||||
"append",
|
||||
"addClass",
|
||||
"removeClass",
|
||||
"text",
|
||||
"attr",
|
||||
"html",
|
||||
"css",
|
||||
"find"
|
||||
]
|
||||
);
|
||||
mockEl.testHtml = html;
|
||||
mockEl.append.andReturn(mockEl);
|
||||
mockElements.push(mockEl);
|
||||
return mockEl;
|
||||
}
|
||||
|
||||
function createMockDomainObject(id) {
|
||||
var mockDomainObject = jasmine.createSpyObj(
|
||||
"domainObject-" + id,
|
||||
["getId", "getModel"]
|
||||
);
|
||||
mockDomainObject.getId.andReturn(id);
|
||||
mockDomainObject.getModel.andReturn({name: id.toUpperCase()});
|
||||
return mockDomainObject;
|
||||
}
|
||||
|
||||
function fireWatch(watchExpression, value) {
|
||||
mockScope.$watch.calls.forEach(function (call) {
|
||||
if (call.args[0] === watchExpression) {
|
||||
call.args[1](value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// AutoflowTableLinker accesses Angular in the global
|
||||
// scope, since it is not injectable; we simulate that
|
||||
// here by adding/removing it to/from the window object.
|
||||
beforeEach(function () {
|
||||
mockElements = [];
|
||||
|
||||
mockAngular = jasmine.createSpyObj("angular", ["element"]);
|
||||
mockScope = jasmine.createSpyObj("scope", ["$watch"]);
|
||||
mockElement = createMockElement('<div>');
|
||||
|
||||
mockAngular.element.andCallFake(createMockElement);
|
||||
|
||||
if (window.angular !== undefined) {
|
||||
cachedAngular = window.angular;
|
||||
}
|
||||
window.angular = mockAngular;
|
||||
|
||||
linker = new AutoflowTableLinker(mockScope, mockElement);
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
if (cachedAngular !== undefined) {
|
||||
window.angular = cachedAngular;
|
||||
} else {
|
||||
delete window.angular;
|
||||
}
|
||||
});
|
||||
|
||||
it("watches for changes in inputs", function () {
|
||||
expect(mockScope.$watch).toHaveBeenCalledWith(
|
||||
"objects",
|
||||
jasmine.any(Function)
|
||||
);
|
||||
expect(mockScope.$watch).toHaveBeenCalledWith(
|
||||
"rows",
|
||||
jasmine.any(Function)
|
||||
);
|
||||
expect(mockScope.$watch).toHaveBeenCalledWith(
|
||||
"counter",
|
||||
jasmine.any(Function)
|
||||
);
|
||||
});
|
||||
|
||||
it("changes structure when domain objects change", function () {
|
||||
// Set up scope
|
||||
mockScope.rows = 4;
|
||||
mockScope.objects = ['a', 'b', 'c', 'd', 'e', 'f']
|
||||
.map(createMockDomainObject);
|
||||
|
||||
// Fire an update to the set of objects
|
||||
fireWatch("objects");
|
||||
|
||||
// Should have rebuilt with two columns of
|
||||
// four and two rows each; first, by clearing...
|
||||
expect(mockElement.html).toHaveBeenCalledWith("");
|
||||
|
||||
// Should have appended two columns...
|
||||
expect(mockElement.append.calls.length).toEqual(2);
|
||||
|
||||
// ...which should have received two and four rows each
|
||||
expect(mockElement.append.calls[0].args[0].append.calls.length)
|
||||
.toEqual(4);
|
||||
expect(mockElement.append.calls[1].args[0].append.calls.length)
|
||||
.toEqual(2);
|
||||
});
|
||||
|
||||
it("updates values", function () {
|
||||
var mockSpans;
|
||||
|
||||
mockScope.objects = ['a', 'b', 'c', 'd', 'e', 'f']
|
||||
.map(createMockDomainObject);
|
||||
mockScope.values = { a: 0 };
|
||||
|
||||
// Fire an update to the set of values
|
||||
fireWatch("objects");
|
||||
fireWatch("updated");
|
||||
|
||||
// Get all created spans
|
||||
mockSpans = mockElements.filter(function (mockElem) {
|
||||
return mockElem.testHtml === '<span>';
|
||||
});
|
||||
|
||||
// First span should be a, should have gotten this value.
|
||||
// This test detects, in particular, WTD-749
|
||||
expect(mockSpans[0].text).toHaveBeenCalledWith('A');
|
||||
expect(mockSpans[1].text).toHaveBeenCalledWith(0);
|
||||
});
|
||||
|
||||
it("listens for changes in column width", function () {
|
||||
var mockUL = createMockElement("<ul>");
|
||||
mockElement.find.andReturn(mockUL);
|
||||
mockScope.columnWidth = 200;
|
||||
fireWatch("columnWidth", mockScope.columnWidth);
|
||||
expect(mockUL.css).toHaveBeenCalledWith("width", "200px");
|
||||
});
|
||||
|
||||
it("updates CSS classes", function () {
|
||||
var mockSpans;
|
||||
|
||||
mockScope.objects = ['a', 'b', 'c', 'd', 'e', 'f']
|
||||
.map(createMockDomainObject);
|
||||
mockScope.values = { a: "a value to find" };
|
||||
mockScope.classes = { a: 'class-a' };
|
||||
|
||||
// Fire an update to the set of values
|
||||
fireWatch("objects");
|
||||
fireWatch("updated");
|
||||
|
||||
// Figure out which span holds the relevant value...
|
||||
mockSpans = mockElements.filter(function (mockElem) {
|
||||
return mockElem.testHtml === '<span>';
|
||||
}).filter(function (mockSpan) {
|
||||
var attrCalls = mockSpan.attr.calls;
|
||||
return attrCalls.some(function (call) {
|
||||
return call.args[0] === 'title' &&
|
||||
call.args[1] === mockScope.values.a;
|
||||
});
|
||||
});
|
||||
|
||||
// ...and make sure it also has had its class applied
|
||||
expect(mockSpans[0].addClass)
|
||||
.toHaveBeenCalledWith(mockScope.classes.a);
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
341
platform/features/autoflow/test/AutoflowTabularControllerSpec.js
Executable file
341
platform/features/autoflow/test/AutoflowTabularControllerSpec.js
Executable file
@@ -0,0 +1,341 @@
|
||||
|
||||
define(
|
||||
["../src/AutoflowTabularController"],
|
||||
function (AutoflowTabularController) {
|
||||
|
||||
describe("The autoflow tabular controller", function () {
|
||||
var mockScope,
|
||||
mockTimeout,
|
||||
mockSubscriber,
|
||||
mockDomainObject,
|
||||
mockSubscription,
|
||||
controller;
|
||||
|
||||
// Fire watches that are registered as functions.
|
||||
function fireFnWatches() {
|
||||
mockScope.$watch.calls.forEach(function (call) {
|
||||
if (typeof call.args[0] === 'function') {
|
||||
call.args[1](call.args[0]());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
beforeEach(function () {
|
||||
mockScope = jasmine.createSpyObj(
|
||||
"$scope",
|
||||
["$on", "$watch"]
|
||||
);
|
||||
mockTimeout = jasmine.createSpy("$timeout");
|
||||
mockSubscriber = jasmine.createSpyObj(
|
||||
"telemetrySubscriber",
|
||||
["subscribe"]
|
||||
);
|
||||
mockDomainObject = jasmine.createSpyObj(
|
||||
"domainObject",
|
||||
["getId", "getModel", "getCapability"]
|
||||
);
|
||||
mockSubscription = jasmine.createSpyObj(
|
||||
"subscription",
|
||||
[
|
||||
"unsubscribe",
|
||||
"getTelemetryObjects",
|
||||
"getDomainValue",
|
||||
"getRangeValue"
|
||||
]
|
||||
);
|
||||
|
||||
mockSubscriber.subscribe.andReturn(mockSubscription);
|
||||
mockDomainObject.getModel.andReturn({name: "something"});
|
||||
|
||||
controller = new AutoflowTabularController(
|
||||
mockScope,
|
||||
mockTimeout,
|
||||
mockSubscriber
|
||||
);
|
||||
});
|
||||
|
||||
it("listens for the represented domain object", function () {
|
||||
expect(mockScope.$watch).toHaveBeenCalledWith(
|
||||
"domainObject",
|
||||
jasmine.any(Function)
|
||||
);
|
||||
});
|
||||
|
||||
it("provides a getter-setter function for filtering", function () {
|
||||
expect(controller.filter()).toEqual("");
|
||||
controller.filter("something");
|
||||
expect(controller.filter()).toEqual("something");
|
||||
});
|
||||
|
||||
it("tracks bounds and adjust number of rows accordingly", function () {
|
||||
// Rows are 15px high, and need room for an 10px slider
|
||||
controller.setBounds({ width: 700, height: 120 });
|
||||
expect(controller.getRows()).toEqual(6); // 110 usable height / 16px
|
||||
controller.setBounds({ width: 700, height: 240 });
|
||||
expect(controller.getRows()).toEqual(14); // 230 usable height / 16px
|
||||
});
|
||||
|
||||
it("subscribes to a represented object's telemetry", function () {
|
||||
// Set up subscription, scope
|
||||
mockSubscription.getTelemetryObjects
|
||||
.andReturn([mockDomainObject]);
|
||||
mockScope.domainObject = mockDomainObject;
|
||||
|
||||
// Invoke the watcher with represented domain object
|
||||
mockScope.$watch.mostRecentCall.args[1](mockDomainObject);
|
||||
|
||||
// Should have subscribed to it
|
||||
expect(mockSubscriber.subscribe).toHaveBeenCalledWith(
|
||||
mockDomainObject,
|
||||
jasmine.any(Function)
|
||||
);
|
||||
|
||||
// Should report objects as reported from subscription
|
||||
expect(controller.getTelemetryObjects())
|
||||
.toEqual([mockDomainObject]);
|
||||
});
|
||||
|
||||
it("releases subscriptions on destroy", function () {
|
||||
// Set up subscription...
|
||||
mockSubscription.getTelemetryObjects
|
||||
.andReturn([mockDomainObject]);
|
||||
mockScope.domainObject = mockDomainObject;
|
||||
mockScope.$watch.mostRecentCall.args[1](mockDomainObject);
|
||||
|
||||
// Verify precondition
|
||||
expect(mockSubscription.unsubscribe).not.toHaveBeenCalled();
|
||||
|
||||
// Make sure we're listening for $destroy
|
||||
expect(mockScope.$on).toHaveBeenCalledWith(
|
||||
"$destroy",
|
||||
jasmine.any(Function)
|
||||
);
|
||||
|
||||
// Fire a destroy event
|
||||
mockScope.$on.mostRecentCall.args[1]();
|
||||
|
||||
// Should have unsubscribed
|
||||
expect(mockSubscription.unsubscribe).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("presents latest values and latest update state", function () {
|
||||
// Make sure values are available
|
||||
mockSubscription.getDomainValue.andReturn(402654321123);
|
||||
mockSubscription.getRangeValue.andReturn(789);
|
||||
mockDomainObject.getId.andReturn('testId');
|
||||
|
||||
// Set up subscription...
|
||||
mockSubscription.getTelemetryObjects
|
||||
.andReturn([mockDomainObject]);
|
||||
mockScope.domainObject = mockDomainObject;
|
||||
mockScope.$watch.mostRecentCall.args[1](mockDomainObject);
|
||||
|
||||
// Fire subscription callback
|
||||
mockSubscriber.subscribe.mostRecentCall.args[1]();
|
||||
|
||||
// ...and exposed the results for template to consume
|
||||
expect(controller.updated()).toEqual("1982-278 08:25:21.123Z");
|
||||
expect(controller.rangeValues().testId).toEqual(789);
|
||||
});
|
||||
|
||||
it("sorts domain objects by index", function () {
|
||||
var testIndexes = { a: 2, b: 1, c: 3, d: 0 },
|
||||
mockDomainObjects = Object.keys(testIndexes).sort().map(function (id) {
|
||||
var mockDomainObj = jasmine.createSpyObj(
|
||||
"domainObject",
|
||||
["getId", "getModel"]
|
||||
);
|
||||
|
||||
mockDomainObj.getId.andReturn(id);
|
||||
mockDomainObj.getModel.andReturn({ index: testIndexes[id] });
|
||||
|
||||
return mockDomainObj;
|
||||
});
|
||||
|
||||
// Expose those domain objects...
|
||||
mockSubscription.getTelemetryObjects.andReturn(mockDomainObjects);
|
||||
mockScope.domainObject = mockDomainObject;
|
||||
mockScope.$watch.mostRecentCall.args[1](mockDomainObject);
|
||||
|
||||
// Fire subscription callback
|
||||
mockSubscriber.subscribe.mostRecentCall.args[1]();
|
||||
|
||||
// Controller should expose same objects, but sorted by index from model
|
||||
expect(controller.getTelemetryObjects()).toEqual([
|
||||
mockDomainObjects[3], // d, index=0
|
||||
mockDomainObjects[1], // b, index=1
|
||||
mockDomainObjects[0], // a, index=2
|
||||
mockDomainObjects[2] // c, index=3
|
||||
]);
|
||||
});
|
||||
|
||||
it("uses a timeout to throttle update", function () {
|
||||
// Set up subscription...
|
||||
mockSubscription.getTelemetryObjects
|
||||
.andReturn([mockDomainObject]);
|
||||
mockScope.domainObject = mockDomainObject;
|
||||
|
||||
// Set the object in view; should not need a timeout
|
||||
mockScope.$watch.mostRecentCall.args[1](mockDomainObject);
|
||||
expect(mockTimeout.calls.length).toEqual(0);
|
||||
|
||||
// Next call should schedule an update on a timeout
|
||||
mockScope.$watch.mostRecentCall.args[1](mockDomainObject);
|
||||
expect(mockTimeout.calls.length).toEqual(1);
|
||||
|
||||
// ...but this last one should not, since existing
|
||||
// timeout will cover it
|
||||
mockScope.$watch.mostRecentCall.args[1](mockDomainObject);
|
||||
expect(mockTimeout.calls.length).toEqual(1);
|
||||
});
|
||||
|
||||
it("allows changing column width", function () {
|
||||
var initialWidth = controller.columnWidth();
|
||||
controller.increaseColumnWidth();
|
||||
expect(controller.columnWidth()).toBeGreaterThan(initialWidth);
|
||||
});
|
||||
|
||||
describe("filter", function () {
|
||||
var doFilter,
|
||||
filteredObjects,
|
||||
filteredObjectNames;
|
||||
|
||||
beforeEach(function () {
|
||||
var telemetryObjects,
|
||||
updateFilteredObjects;
|
||||
|
||||
telemetryObjects = [
|
||||
'DEF123',
|
||||
'abc789',
|
||||
'456abc',
|
||||
'4ab3cdef',
|
||||
'hjs[12].*(){}^\\'
|
||||
].map(function (objectName, index) {
|
||||
var mockTelemetryObject = jasmine.createSpyObj(
|
||||
objectName,
|
||||
["getId", "getModel"]
|
||||
);
|
||||
|
||||
mockTelemetryObject.getId.andReturn(objectName);
|
||||
mockTelemetryObject.getModel.andReturn({
|
||||
name: objectName,
|
||||
index: index
|
||||
});
|
||||
|
||||
return mockTelemetryObject;
|
||||
});
|
||||
|
||||
mockSubscription
|
||||
.getTelemetryObjects
|
||||
.andReturn(telemetryObjects);
|
||||
|
||||
// Trigger domainObject change to create subscription.
|
||||
mockScope.$watch.mostRecentCall.args[1](mockDomainObject);
|
||||
|
||||
updateFilteredObjects = function () {
|
||||
filteredObjects = controller.getTelemetryObjects();
|
||||
filteredObjectNames = filteredObjects.map(function (o) {
|
||||
return o.getModel().name;
|
||||
});
|
||||
};
|
||||
|
||||
doFilter = function (term) {
|
||||
controller.filter(term);
|
||||
// Filter is debounced so we have to force it to occur.
|
||||
mockTimeout.mostRecentCall.args[0]();
|
||||
updateFilteredObjects();
|
||||
};
|
||||
|
||||
updateFilteredObjects();
|
||||
});
|
||||
|
||||
it("initially shows all objects", function () {
|
||||
expect(filteredObjectNames).toEqual([
|
||||
'DEF123',
|
||||
'abc789',
|
||||
'456abc',
|
||||
'4ab3cdef',
|
||||
'hjs[12].*(){}^\\'
|
||||
]);
|
||||
});
|
||||
|
||||
it("by blank string matches all objects", function () {
|
||||
doFilter('');
|
||||
expect(filteredObjectNames).toEqual([
|
||||
'DEF123',
|
||||
'abc789',
|
||||
'456abc',
|
||||
'4ab3cdef',
|
||||
'hjs[12].*(){}^\\'
|
||||
]);
|
||||
});
|
||||
|
||||
it("exactly matches an object name", function () {
|
||||
doFilter('4ab3cdef');
|
||||
expect(filteredObjectNames).toEqual(['4ab3cdef']);
|
||||
});
|
||||
|
||||
it("partially matches object names", function () {
|
||||
doFilter('abc');
|
||||
expect(filteredObjectNames).toEqual([
|
||||
'abc789',
|
||||
'456abc'
|
||||
]);
|
||||
});
|
||||
|
||||
it("matches case insensitive names", function () {
|
||||
doFilter('def');
|
||||
expect(filteredObjectNames).toEqual([
|
||||
'DEF123',
|
||||
'4ab3cdef'
|
||||
]);
|
||||
});
|
||||
|
||||
it("works as expected with special characters", function () {
|
||||
doFilter('[12]');
|
||||
expect(filteredObjectNames).toEqual(['hjs[12].*(){}^\\']);
|
||||
doFilter('.*');
|
||||
expect(filteredObjectNames).toEqual(['hjs[12].*(){}^\\']);
|
||||
doFilter('.*()');
|
||||
expect(filteredObjectNames).toEqual(['hjs[12].*(){}^\\']);
|
||||
doFilter('.*?');
|
||||
expect(filteredObjectNames).toEqual([]);
|
||||
doFilter('.+');
|
||||
expect(filteredObjectNames).toEqual([]);
|
||||
});
|
||||
|
||||
it("exposes CSS classes from limits", function () {
|
||||
var id = mockDomainObject.getId(),
|
||||
testClass = "some-css-class",
|
||||
mockLimitCapability =
|
||||
jasmine.createSpyObj('limit', ['evaluate']);
|
||||
|
||||
mockDomainObject.getCapability.andCallFake(function (key) {
|
||||
return key === 'limit' && mockLimitCapability;
|
||||
});
|
||||
mockLimitCapability.evaluate
|
||||
.andReturn({ cssClass: testClass });
|
||||
|
||||
mockSubscription.getTelemetryObjects
|
||||
.andReturn([mockDomainObject]);
|
||||
|
||||
fireFnWatches();
|
||||
mockSubscriber.subscribe.mostRecentCall.args[1]();
|
||||
|
||||
expect(controller.classes()[id]).toEqual(testClass);
|
||||
});
|
||||
|
||||
it("exposes a counter that changes with each update", function () {
|
||||
var i, prior;
|
||||
|
||||
for (i = 0; i < 10; i += 1) {
|
||||
prior = controller.counter();
|
||||
expect(controller.counter()).toEqual(prior);
|
||||
mockSubscriber.subscribe.mostRecentCall.args[1]();
|
||||
expect(controller.counter()).not.toEqual(prior);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
39
platform/features/autoflow/test/MCTAutoflowTableSpec.js
Executable file
39
platform/features/autoflow/test/MCTAutoflowTableSpec.js
Executable file
@@ -0,0 +1,39 @@
|
||||
|
||||
define(
|
||||
["../src/MCTAutoflowTable"],
|
||||
function (MCTAutoflowTable) {
|
||||
|
||||
describe("The mct-autoflow-table directive", function () {
|
||||
var mctAutoflowTable;
|
||||
|
||||
beforeEach(function () {
|
||||
mctAutoflowTable = new MCTAutoflowTable();
|
||||
});
|
||||
|
||||
// Real functionality is contained/tested in the linker,
|
||||
// so just check to make sure we're exposing the directive
|
||||
// appropriately.
|
||||
it("is applicable at the element level", function () {
|
||||
expect(mctAutoflowTable.restrict).toEqual("E");
|
||||
});
|
||||
|
||||
it("two-ways binds needed scope variables", function () {
|
||||
expect(mctAutoflowTable.scope).toEqual({
|
||||
objects: "=",
|
||||
values: "=",
|
||||
rows: "=",
|
||||
updated: "=",
|
||||
classes: "=",
|
||||
columnWidth: "=",
|
||||
counter: "="
|
||||
});
|
||||
});
|
||||
|
||||
it("provides a link function", function () {
|
||||
expect(mctAutoflowTable.link).toEqual(jasmine.any(Function));
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
}
|
||||
);
|
||||
@@ -23,13 +23,10 @@
|
||||
define([
|
||||
"moment-timezone",
|
||||
"./src/indicators/ClockIndicator",
|
||||
"./src/indicators/FollowIndicator",
|
||||
"./src/services/TickerService",
|
||||
"./src/services/TimerService",
|
||||
"./src/controllers/ClockController",
|
||||
"./src/controllers/TimerController",
|
||||
"./src/controllers/RefreshingController",
|
||||
"./src/actions/FollowTimerAction",
|
||||
"./src/actions/StartTimerAction",
|
||||
"./src/actions/RestartTimerAction",
|
||||
"./src/actions/StopTimerAction",
|
||||
@@ -40,13 +37,10 @@ define([
|
||||
], function (
|
||||
MomentTimezone,
|
||||
ClockIndicator,
|
||||
FollowIndicator,
|
||||
TickerService,
|
||||
TimerService,
|
||||
ClockController,
|
||||
TimerController,
|
||||
RefreshingController,
|
||||
FollowTimerAction,
|
||||
StartTimerAction,
|
||||
RestartTimerAction,
|
||||
StopTimerAction,
|
||||
@@ -86,11 +80,6 @@ define([
|
||||
"CLOCK_INDICATOR_FORMAT"
|
||||
],
|
||||
"priority": "preferred"
|
||||
},
|
||||
{
|
||||
"implementation": FollowIndicator,
|
||||
"depends": ["timerService"],
|
||||
"priority": "fallback"
|
||||
}
|
||||
],
|
||||
"services": [
|
||||
@@ -101,11 +90,6 @@ define([
|
||||
"$timeout",
|
||||
"now"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "timerService",
|
||||
"implementation": TimerService,
|
||||
"depends": ["openmct"]
|
||||
}
|
||||
],
|
||||
"controllers": [
|
||||
@@ -150,15 +134,6 @@ define([
|
||||
}
|
||||
],
|
||||
"actions": [
|
||||
{
|
||||
"key": "timer.follow",
|
||||
"implementation": FollowTimerAction,
|
||||
"depends": ["timerService"],
|
||||
"category": "contextual",
|
||||
"name": "Follow Timer",
|
||||
"cssClass": "icon-clock",
|
||||
"priority": "optional"
|
||||
},
|
||||
{
|
||||
"key": "timer.start",
|
||||
"implementation": StartTimerAction,
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2009-2016, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define(
|
||||
[],
|
||||
function () {
|
||||
|
||||
/**
|
||||
* Designates a specific timer for following. Timelines, for example,
|
||||
* use the actively followed timer to display a time-of-interest line
|
||||
* and interpret time conductor bounds in the Timeline's relative
|
||||
* time frame.
|
||||
*
|
||||
* @implements {Action}
|
||||
* @memberof platform/features/clock
|
||||
* @constructor
|
||||
* @param {ActionContext} context the context for this action
|
||||
*/
|
||||
function FollowTimerAction(timerService, context) {
|
||||
var domainObject =
|
||||
context.domainObject &&
|
||||
context.domainObject.useCapability('adapter');
|
||||
this.perform =
|
||||
timerService.setTimer.bind(timerService, domainObject);
|
||||
}
|
||||
|
||||
FollowTimerAction.appliesTo = function (context) {
|
||||
var model =
|
||||
(context.domainObject && context.domainObject.getModel()) ||
|
||||
{};
|
||||
|
||||
return model.type === 'timer';
|
||||
};
|
||||
|
||||
return FollowTimerAction;
|
||||
}
|
||||
);
|
||||
@@ -1,57 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2009-2016, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define(
|
||||
['moment'],
|
||||
function (moment) {
|
||||
var NO_TIMER = "No timer being followed";
|
||||
|
||||
/**
|
||||
* Indicator that displays the active timer, as well as its
|
||||
* current state.
|
||||
* @implements {Indicator}
|
||||
* @memberof platform/features/clock
|
||||
*/
|
||||
function FollowIndicator(timerService) {
|
||||
this.timerService = timerService;
|
||||
}
|
||||
|
||||
FollowIndicator.prototype.getGlyphClass = function () {
|
||||
return "";
|
||||
};
|
||||
|
||||
FollowIndicator.prototype.getCssClass = function () {
|
||||
return (this.timerService.getTimer()) ? "icon-timer s-status-ok" : "icon-timer";
|
||||
};
|
||||
|
||||
FollowIndicator.prototype.getText = function () {
|
||||
var timer = this.timerService.getTimer();
|
||||
return timer ? ('Following timer ' + timer.name) : NO_TIMER;
|
||||
};
|
||||
|
||||
FollowIndicator.prototype.getDescription = function () {
|
||||
return "";
|
||||
};
|
||||
|
||||
return FollowIndicator;
|
||||
}
|
||||
);
|
||||
@@ -1,113 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2009-2016, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define(['EventEmitter'], function (EventEmitter) {
|
||||
|
||||
/**
|
||||
* Tracks the currently-followed Timer object. Used by
|
||||
* timelines et al to synchronize to a particular timer.
|
||||
*
|
||||
* The TimerService emits `change` events when the active timer
|
||||
* is changed.
|
||||
*/
|
||||
function TimerService(openmct) {
|
||||
EventEmitter.apply(this);
|
||||
this.time = openmct.time;
|
||||
this.objects = openmct.objects;
|
||||
}
|
||||
|
||||
TimerService.prototype = Object.create(EventEmitter.prototype);
|
||||
|
||||
/**
|
||||
* Set (or clear, if `timer` is undefined) the currently active timer.
|
||||
* @param {DomainObject} timer the new active timer
|
||||
* @emits change
|
||||
*/
|
||||
TimerService.prototype.setTimer = function (timer) {
|
||||
this.timer = timer;
|
||||
this.emit('change');
|
||||
|
||||
if (this.stopObserving) {
|
||||
this.stopObserving();
|
||||
delete this.stopObserving;
|
||||
}
|
||||
|
||||
if (timer) {
|
||||
this.stopObserving =
|
||||
this.objects.observe(timer, '*', this.setTimer.bind(this));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the currently active timer.
|
||||
* @return {DomainObject} the active timer
|
||||
* @emits change
|
||||
*/
|
||||
TimerService.prototype.getTimer = function () {
|
||||
return this.timer;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Check if there is a currently active timer.
|
||||
* @return {boolean} true if there is a timer
|
||||
*/
|
||||
TimerService.prototype.hasTimer = function () {
|
||||
return !!this.timer;
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert the provided timestamp to milliseconds relative to
|
||||
* the active timer.
|
||||
* @return {number} milliseconds since timer start
|
||||
*/
|
||||
TimerService.prototype.convert = function (timestamp) {
|
||||
var clock = this.time.clock();
|
||||
var canConvert = this.hasTimer() &&
|
||||
!!clock &&
|
||||
this.timer.timerState !== 'stopped';
|
||||
|
||||
if (!canConvert) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
var now = clock.currentValue();
|
||||
var delta = this.timer.timerState === 'paused' ?
|
||||
now - this.timer.pausedTime : 0;
|
||||
var epoch = this.timer.timestamp;
|
||||
|
||||
return timestamp - epoch - delta;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the value of the active clock, adjusted to be relative to the active
|
||||
* timer. If there is no clock or no active timer, this will return
|
||||
* `undefined`.
|
||||
* @return {number} milliseconds since the start of the active timer
|
||||
*/
|
||||
TimerService.prototype.now = function () {
|
||||
var clock = this.time.clock();
|
||||
return clock && this.convert(clock.currentValue());
|
||||
};
|
||||
|
||||
return TimerService;
|
||||
});
|
||||
@@ -1,87 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2009-2016, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define([
|
||||
"../../src/actions/FollowTimerAction"
|
||||
], function (FollowTimerAction) {
|
||||
var TIMER_SERVICE_METHODS =
|
||||
['setTimer', 'getTimer', 'clearTimer', 'on', 'off'];
|
||||
|
||||
describe("The Follow Timer action", function () {
|
||||
var testContext;
|
||||
var testModel;
|
||||
var testAdaptedObject;
|
||||
|
||||
beforeEach(function () {
|
||||
testModel = {};
|
||||
testContext = { domainObject: jasmine.createSpyObj('domainObject', [
|
||||
'getModel',
|
||||
'useCapability'
|
||||
]) };
|
||||
testAdaptedObject = { foo: 'bar' };
|
||||
testContext.domainObject.getModel.andReturn(testModel);
|
||||
testContext.domainObject.useCapability.andCallFake(function (c) {
|
||||
return c === 'adapter' && testAdaptedObject;
|
||||
});
|
||||
});
|
||||
|
||||
it("is applicable to timers", function () {
|
||||
testModel.type = "timer";
|
||||
expect(FollowTimerAction.appliesTo(testContext)).toBe(true);
|
||||
});
|
||||
|
||||
it("is inapplicable to non-timers", function () {
|
||||
testModel.type = "folder";
|
||||
expect(FollowTimerAction.appliesTo(testContext)).toBe(false);
|
||||
});
|
||||
|
||||
describe("when instantiated", function () {
|
||||
var mockTimerService;
|
||||
var action;
|
||||
|
||||
beforeEach(function () {
|
||||
mockTimerService = jasmine.createSpyObj(
|
||||
'timerService',
|
||||
TIMER_SERVICE_METHODS
|
||||
);
|
||||
action = new FollowTimerAction(mockTimerService, testContext);
|
||||
});
|
||||
|
||||
it("does not interact with the timer service", function () {
|
||||
TIMER_SERVICE_METHODS.forEach(function (method) {
|
||||
expect(mockTimerService[method]).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("and performed", function () {
|
||||
beforeEach(function () {
|
||||
action.perform();
|
||||
});
|
||||
|
||||
it("sets the active timer", function () {
|
||||
expect(mockTimerService.setTimer)
|
||||
.toHaveBeenCalledWith(testAdaptedObject);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,58 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2009-2016, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define(["../../src/indicators/FollowIndicator"], function (FollowIndicator) {
|
||||
var TIMER_SERVICE_METHODS =
|
||||
['setTimer', 'getTimer', 'clearTimer', 'on', 'off'];
|
||||
|
||||
describe("The timer-following indicator", function () {
|
||||
var mockTimerService;
|
||||
var indicator;
|
||||
|
||||
beforeEach(function () {
|
||||
mockTimerService =
|
||||
jasmine.createSpyObj('timerService', TIMER_SERVICE_METHODS);
|
||||
indicator = new FollowIndicator(mockTimerService);
|
||||
});
|
||||
|
||||
it("implements the Indicator interface", function () {
|
||||
expect(indicator.getGlyphClass()).toEqual(jasmine.any(String));
|
||||
expect(indicator.getCssClass()).toEqual(jasmine.any(String));
|
||||
expect(indicator.getText()).toEqual(jasmine.any(String));
|
||||
expect(indicator.getDescription()).toEqual(jasmine.any(String));
|
||||
});
|
||||
|
||||
describe("when a timer is set", function () {
|
||||
var testObject;
|
||||
|
||||
beforeEach(function () {
|
||||
testObject = { name: "some timer!" };
|
||||
mockTimerService.getTimer.andReturn(testObject);
|
||||
});
|
||||
|
||||
it("displays the timer's name", function () {
|
||||
expect(indicator.getText().indexOf(testObject.name))
|
||||
.not.toEqual(-1);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,77 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2009-2016, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define([
|
||||
'../../src/services/TimerService'
|
||||
], function (TimerService) {
|
||||
describe("TimerService", function () {
|
||||
var callback;
|
||||
var mockmct;
|
||||
var timerService;
|
||||
|
||||
beforeEach(function () {
|
||||
callback = jasmine.createSpy('callback');
|
||||
mockmct = {
|
||||
time: { clock: jasmine.createSpy('clock') },
|
||||
objects: { observe: jasmine.createSpy('observe') }
|
||||
};
|
||||
timerService = new TimerService(mockmct);
|
||||
timerService.on('change', callback);
|
||||
});
|
||||
|
||||
it("initially emits no change events", function () {
|
||||
expect(callback).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("reports no current timer", function () {
|
||||
expect(timerService.getTimer()).toBeUndefined();
|
||||
});
|
||||
|
||||
describe("setTimer", function () {
|
||||
var testTimer;
|
||||
|
||||
beforeEach(function () {
|
||||
testTimer = { name: "I am some timer; you are nobody." };
|
||||
timerService.setTimer(testTimer);
|
||||
});
|
||||
|
||||
it("emits a change event", function () {
|
||||
expect(callback).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("reports the current timer", function () {
|
||||
expect(timerService.getTimer()).toBe(testTimer);
|
||||
});
|
||||
|
||||
it("observes changes to an object", function () {
|
||||
var newTimer = { name: "I am another timer." };
|
||||
expect(mockmct.objects.observe).toHaveBeenCalledWith(
|
||||
testTimer,
|
||||
'*',
|
||||
jasmine.any(Function)
|
||||
);
|
||||
mockmct.objects.observe.mostRecentCall.args[2](newTimer);
|
||||
expect(timerService.getTimer()).toBe(newTimer);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user