mirror of
https://github.com/nasa/openmct.git
synced 2025-05-09 20:12:50 +00:00
Merge remote-tracking branch 'origin/master' into restore-fixed-pos
This commit is contained in:
commit
971b92acbb
@ -22,6 +22,7 @@
|
|||||||
"eventemitter3": "^1.2.0",
|
"eventemitter3": "^1.2.0",
|
||||||
"lodash": "3.10.1",
|
"lodash": "3.10.1",
|
||||||
"almond": "~0.3.2",
|
"almond": "~0.3.2",
|
||||||
|
"d3": "~4.1.0",
|
||||||
"html2canvas": "^0.4.1"
|
"html2canvas": "^0.4.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
|
|
||||||
# Script to build and deploy docs.
|
# Script to build and deploy docs.
|
||||||
|
|
||||||
OUTPUT_DIRECTORY="target/docs"
|
OUTPUT_DIRECTORY="dist/docs"
|
||||||
# Docs, once built, are pushed to the private website repo
|
# Docs, once built, are pushed to the private website repo
|
||||||
REPOSITORY_URL="git@github.com:nasa/openmct-website.git"
|
REPOSITORY_URL="git@github.com:nasa/openmct-website.git"
|
||||||
WEBSITE_DIRECTORY="website"
|
WEBSITE_DIRECTORY="website"
|
||||||
|
@ -34,5 +34,4 @@ As we transition to a new API, the following documentation for the old API
|
|||||||
platform and the functionality that it provides.
|
platform and the functionality that it provides.
|
||||||
|
|
||||||
* The [Tutorials](tutorials/) give examples of extending the platform to add
|
* The [Tutorials](tutorials/) give examples of extending the platform to add
|
||||||
functionality,
|
functionality, and integrate with data sources.
|
||||||
and integrate with data sources.
|
|
||||||
|
48
example/localTimeSystem/bundle.js
Normal file
48
example/localTimeSystem/bundle.js
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT Web includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
define([
|
||||||
|
"./src/LocalTimeSystem",
|
||||||
|
"./src/LocalTimeFormat",
|
||||||
|
'legacyRegistry'
|
||||||
|
], function (
|
||||||
|
LocalTimeSystem,
|
||||||
|
LocalTimeFormat,
|
||||||
|
legacyRegistry
|
||||||
|
) {
|
||||||
|
legacyRegistry.register("example/localTimeSystem", {
|
||||||
|
"extensions": {
|
||||||
|
"formats": [
|
||||||
|
{
|
||||||
|
"key": "local-format",
|
||||||
|
"implementation": LocalTimeFormat
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"timeSystems": [
|
||||||
|
{
|
||||||
|
"implementation": LocalTimeSystem,
|
||||||
|
"depends": ["$timeout"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
43
example/localTimeSystem/src/LADTickSource.js
Normal file
43
example/localTimeSystem/src/LADTickSource.js
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT Web includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
define(['../../../platform/features/conductor-v2/conductor/src/timeSystems/LocalClock'], function (LocalClock) {
|
||||||
|
/**
|
||||||
|
* @implements TickSource
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function LADTickSource ($timeout, period) {
|
||||||
|
LocalClock.call(this, $timeout, period);
|
||||||
|
|
||||||
|
this.metadata = {
|
||||||
|
key: 'test-lad',
|
||||||
|
mode: 'lad',
|
||||||
|
cssclass: 'icon-clock',
|
||||||
|
label: 'Latest Available Data',
|
||||||
|
name: 'Latest available data',
|
||||||
|
description: 'Monitor real-time streaming data as it comes in. The Time Conductor and displays will automatically advance themselves based on a UTC clock.'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
LADTickSource.prototype = Object.create(LocalClock.prototype);
|
||||||
|
|
||||||
|
return LADTickSource;
|
||||||
|
});
|
112
example/localTimeSystem/src/LocalTimeFormat.js
Normal file
112
example/localTimeSystem/src/LocalTimeFormat.js
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT Web includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
define([
|
||||||
|
'moment'
|
||||||
|
], function (
|
||||||
|
moment
|
||||||
|
) {
|
||||||
|
|
||||||
|
var DATE_FORMAT = "YYYY-MM-DD h:mm:ss.SSS a",
|
||||||
|
DATE_FORMATS = [
|
||||||
|
DATE_FORMAT,
|
||||||
|
"YYYY-MM-DD h:mm:ss a",
|
||||||
|
"YYYY-MM-DD h:mm a",
|
||||||
|
"YYYY-MM-DD"
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef Scale
|
||||||
|
* @property {number} min the minimum scale value, in ms
|
||||||
|
* @property {number} max the maximum scale value, in ms
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formatter for UTC timestamps. Interprets numeric values as
|
||||||
|
* milliseconds since the start of 1970.
|
||||||
|
*
|
||||||
|
* @implements {Format}
|
||||||
|
* @constructor
|
||||||
|
* @memberof platform/commonUI/formats
|
||||||
|
*/
|
||||||
|
function LocalTimeFormat() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an appropriate time format based on the provided value and
|
||||||
|
* the threshold required.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
function getScaledFormat (d) {
|
||||||
|
var m = moment.utc(d);
|
||||||
|
/**
|
||||||
|
* Uses logic from d3 Time-Scales, v3 of the API. See
|
||||||
|
* https://github.com/d3/d3-3.x-api-reference/blob/master/Time-Scales.md
|
||||||
|
*
|
||||||
|
* Licensed
|
||||||
|
*/
|
||||||
|
return [
|
||||||
|
[".SSS", function(m) { return m.milliseconds(); }],
|
||||||
|
[":ss", function(m) { return m.seconds(); }],
|
||||||
|
["hh:mma", function(m) { return m.minutes(); }],
|
||||||
|
["hha", function(m) { return m.hours(); }],
|
||||||
|
["ddd DD", function(m) {
|
||||||
|
return m.days() &&
|
||||||
|
m.date() != 1;
|
||||||
|
}],
|
||||||
|
["MMM DD", function(m) { return m.date() != 1; }],
|
||||||
|
["MMMM", function(m) {
|
||||||
|
return m.month();
|
||||||
|
}],
|
||||||
|
["YYYY", function() { return true; }]
|
||||||
|
].filter(function (row){
|
||||||
|
return row[1](m);
|
||||||
|
})[0][0];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param value
|
||||||
|
* @param {Scale} [scale] Optionally provides context to the
|
||||||
|
* format request, allowing for scale-appropriate formatting.
|
||||||
|
* @returns {string} the formatted date
|
||||||
|
*/
|
||||||
|
LocalTimeFormat.prototype.format = function (value, scale) {
|
||||||
|
if (scale !== undefined){
|
||||||
|
var scaledFormat = getScaledFormat(value, scale);
|
||||||
|
if (scaledFormat) {
|
||||||
|
return moment.utc(value).format(scaledFormat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return moment(value).format(DATE_FORMAT);
|
||||||
|
};
|
||||||
|
|
||||||
|
LocalTimeFormat.prototype.parse = function (text) {
|
||||||
|
return moment(text, DATE_FORMATS).valueOf();
|
||||||
|
};
|
||||||
|
|
||||||
|
LocalTimeFormat.prototype.validate = function (text) {
|
||||||
|
return moment(text, DATE_FORMATS).isValid();
|
||||||
|
};
|
||||||
|
|
||||||
|
return LocalTimeFormat;
|
||||||
|
});
|
79
example/localTimeSystem/src/LocalTimeSystem.js
Normal file
79
example/localTimeSystem/src/LocalTimeSystem.js
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT Web includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
define([
|
||||||
|
'../../../platform/features/conductor-v2/conductor/src/timeSystems/TimeSystem',
|
||||||
|
'../../../platform/features/conductor-v2/conductor/src/timeSystems/LocalClock',
|
||||||
|
'./LADTickSource'
|
||||||
|
], function (TimeSystem, LocalClock, LADTickSource) {
|
||||||
|
var THIRTY_MINUTES = 30 * 60 * 1000,
|
||||||
|
DEFAULT_PERIOD = 1000;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This time system supports UTC dates and provides a ticking clock source.
|
||||||
|
* @implements TimeSystem
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function LocalTimeSystem ($timeout) {
|
||||||
|
TimeSystem.call(this);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Some metadata, which will be used to identify the time system in
|
||||||
|
* the UI
|
||||||
|
* @type {{key: string, name: string, glyph: string}}
|
||||||
|
*/
|
||||||
|
this.metadata = {
|
||||||
|
'key': 'local',
|
||||||
|
'name': 'Local',
|
||||||
|
'glyph': '\u0043'
|
||||||
|
};
|
||||||
|
|
||||||
|
this.fmts = ['local-format'];
|
||||||
|
this.sources = [new LocalClock($timeout, DEFAULT_PERIOD), new LADTickSource($timeout, DEFAULT_PERIOD)];
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalTimeSystem.prototype = Object.create(TimeSystem.prototype);
|
||||||
|
|
||||||
|
LocalTimeSystem.prototype.formats = function () {
|
||||||
|
return this.fmts;
|
||||||
|
};
|
||||||
|
|
||||||
|
LocalTimeSystem.prototype.deltaFormat = function () {
|
||||||
|
return 'duration';
|
||||||
|
};
|
||||||
|
|
||||||
|
LocalTimeSystem.prototype.tickSources = function () {
|
||||||
|
return this.sources;
|
||||||
|
};
|
||||||
|
|
||||||
|
LocalTimeSystem.prototype.defaults = function (key) {
|
||||||
|
var now = Math.ceil(Date.now() / 1000) * 1000;
|
||||||
|
return {
|
||||||
|
key: 'local-default',
|
||||||
|
name: 'Local 12 hour time system defaults',
|
||||||
|
deltas: {start: THIRTY_MINUTES, end: 0},
|
||||||
|
bounds: {start: now - THIRTY_MINUTES, end: now}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
return LocalTimeSystem;
|
||||||
|
});
|
@ -37,7 +37,8 @@ requirejs.config({
|
|||||||
"text": "bower_components/text/text",
|
"text": "bower_components/text/text",
|
||||||
"uuid": "bower_components/node-uuid/uuid",
|
"uuid": "bower_components/node-uuid/uuid",
|
||||||
"zepto": "bower_components/zepto/zepto.min",
|
"zepto": "bower_components/zepto/zepto.min",
|
||||||
"lodash": "bower_components/lodash/lodash"
|
"lodash": "bower_components/lodash/lodash",
|
||||||
|
"d3": "bower_components/d3/d3.min"
|
||||||
},
|
},
|
||||||
"shim": {
|
"shim": {
|
||||||
"angular": {
|
"angular": {
|
||||||
@ -63,6 +64,9 @@ requirejs.config({
|
|||||||
},
|
},
|
||||||
"lodash": {
|
"lodash": {
|
||||||
"exports": "lodash"
|
"exports": "lodash"
|
||||||
|
},
|
||||||
|
"d3": {
|
||||||
|
"exports": "d3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -49,7 +49,7 @@
|
|||||||
"jshint": "jshint platform example",
|
"jshint": "jshint platform example",
|
||||||
"watch": "karma start",
|
"watch": "karma start",
|
||||||
"jsdoc": "jsdoc -c jsdoc.json -R API.md -r -d dist/docs/api",
|
"jsdoc": "jsdoc -c jsdoc.json -R API.md -r -d dist/docs/api",
|
||||||
"otherdoc": "node docs/gendocs.js --in docs/src --out target/docs --suppress-toc 'docs/src/index.md|docs/src/process/index.md'",
|
"otherdoc": "node docs/gendocs.js --in docs/src --out dist/docs --suppress-toc 'docs/src/index.md|docs/src/process/index.md'",
|
||||||
"docs": "npm run jsdoc ; npm run otherdoc",
|
"docs": "npm run jsdoc ; npm run otherdoc",
|
||||||
"prepublish": "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"
|
||||||
},
|
},
|
||||||
|
@ -43,7 +43,7 @@
|
|||||||
</mct-representation>
|
</mct-representation>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="holder l-flex-col flex-elem grows l-object-wrapper">
|
<div class="holder l-flex-col flex-elem grows l-object-wrapper l-controls-visible l-time-controller-visible">
|
||||||
<div class="holder l-flex-col flex-elem grows l-object-wrapper-inner">
|
<div class="holder l-flex-col flex-elem grows l-object-wrapper-inner">
|
||||||
<!-- Toolbar and Save/Cancel buttons -->
|
<!-- Toolbar and Save/Cancel buttons -->
|
||||||
<div class="l-edit-controls flex-elem l-flex-row flex-align-end">
|
<div class="l-edit-controls flex-elem l-flex-row flex-align-end">
|
||||||
@ -59,4 +59,5 @@
|
|||||||
</mct-representation>
|
</mct-representation>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<mct-include key="'conductor'" class="abs holder flex-elem flex-fixed l-flex-row l-time-conductor-holder"></mct-include>
|
||||||
</div>
|
</div>
|
||||||
|
@ -22,7 +22,8 @@
|
|||||||
<span class='type-icon flex-elem {{type.getCssClass()}}'></span>
|
<span class='type-icon flex-elem {{type.getCssClass()}}'></span>
|
||||||
<span class="l-elem-wrapper l-flex-row flex-elem grows">
|
<span class="l-elem-wrapper l-flex-row flex-elem grows">
|
||||||
<span ng-if="parameters.mode" class='action flex-elem'>{{parameters.mode}}</span>
|
<span ng-if="parameters.mode" class='action flex-elem'>{{parameters.mode}}</span>
|
||||||
<span class='title-label flex-elem flex-can-shrink'>{{model.name}}</span>
|
<span class='title-label flex-elem holder flex-can-shrink'>{{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
|
<mct-representation
|
||||||
key="'menu-arrow'"
|
key="'menu-arrow'"
|
||||||
mct-object='domainObject'
|
mct-object='domainObject'
|
||||||
|
@ -66,4 +66,9 @@
|
|||||||
</mct-representation>
|
</mct-representation>
|
||||||
</div><!--/ l-object-wrapper-inner -->
|
</div><!--/ l-object-wrapper-inner -->
|
||||||
</div>
|
</div>
|
||||||
|
<mct-representation mct-object="domainObject"
|
||||||
|
key="'time-conductor'"
|
||||||
|
class="abs holder flex-elem flex-fixed l-flex-row l-time-conductor-holder">
|
||||||
|
</mct-representation>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -23,10 +23,12 @@
|
|||||||
define([
|
define([
|
||||||
"./src/FormatProvider",
|
"./src/FormatProvider",
|
||||||
"./src/UTCTimeFormat",
|
"./src/UTCTimeFormat",
|
||||||
|
"./src/DurationFormat",
|
||||||
'legacyRegistry'
|
'legacyRegistry'
|
||||||
], function (
|
], function (
|
||||||
FormatProvider,
|
FormatProvider,
|
||||||
UTCTimeFormat,
|
UTCTimeFormat,
|
||||||
|
DurationFormat,
|
||||||
legacyRegistry
|
legacyRegistry
|
||||||
) {
|
) {
|
||||||
|
|
||||||
@ -48,6 +50,10 @@ define([
|
|||||||
{
|
{
|
||||||
"key": "utc",
|
"key": "utc",
|
||||||
"implementation": UTCTimeFormat
|
"implementation": UTCTimeFormat
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "duration",
|
||||||
|
"implementation": DurationFormat
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"constants": [
|
"constants": [
|
||||||
@ -55,6 +61,17 @@ define([
|
|||||||
"key": "DEFAULT_TIME_FORMAT",
|
"key": "DEFAULT_TIME_FORMAT",
|
||||||
"value": "utc"
|
"value": "utc"
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
"licenses": [
|
||||||
|
{
|
||||||
|
"name": "d3",
|
||||||
|
"version": "3.0.0",
|
||||||
|
"description": "Incorporates modified code from d3 Time Scales",
|
||||||
|
"author": "Mike Bostock",
|
||||||
|
"copyright": "Copyright 2010-2016 Mike Bostock. " +
|
||||||
|
"All rights reserved.",
|
||||||
|
"link": "https://github.com/d3/d3/blob/master/LICENSE"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
62
platform/commonUI/formats/src/DurationFormat.js
Normal file
62
platform/commonUI/formats/src/DurationFormat.js
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT Web includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
define([
|
||||||
|
'moment'
|
||||||
|
], function (
|
||||||
|
moment
|
||||||
|
) {
|
||||||
|
|
||||||
|
var DATE_FORMAT = "HH:mm:ss",
|
||||||
|
DATE_FORMATS = [
|
||||||
|
DATE_FORMAT
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formatter for duration. Uses moment to produce a date from a given
|
||||||
|
* value, but output is formatted to display only time. Can be used for
|
||||||
|
* specifying a time duration. For specifying duration, it's best to
|
||||||
|
* specify a date of January 1, 1970, as the ms offset will equal the
|
||||||
|
* duration represented by the time.
|
||||||
|
*
|
||||||
|
* @implements {Format}
|
||||||
|
* @constructor
|
||||||
|
* @memberof platform/commonUI/formats
|
||||||
|
*/
|
||||||
|
function DurationFormat() {
|
||||||
|
}
|
||||||
|
|
||||||
|
DurationFormat.prototype.format = function (value) {
|
||||||
|
return moment.utc(value).format(DATE_FORMAT);
|
||||||
|
};
|
||||||
|
|
||||||
|
DurationFormat.prototype.parse = function (text) {
|
||||||
|
return moment.duration(text).asMilliseconds();
|
||||||
|
};
|
||||||
|
|
||||||
|
DurationFormat.prototype.validate = function (text) {
|
||||||
|
return moment.utc(text, DATE_FORMATS).isValid();
|
||||||
|
};
|
||||||
|
|
||||||
|
return DurationFormat;
|
||||||
|
});
|
@ -58,6 +58,10 @@ define([
|
|||||||
* @method format
|
* @method format
|
||||||
* @memberof Format#
|
* @memberof Format#
|
||||||
* @param {number} value the numeric value to format
|
* @param {number} value the numeric value to format
|
||||||
|
* @param {number} [threshold] Optionally provides context to the
|
||||||
|
* format request, allowing for scale-appropriate formatting. This value
|
||||||
|
* should be the minimum unit to be represented by this format, in ms. For
|
||||||
|
* example, to display seconds, a threshold of 1 * 1000 should be provided.
|
||||||
* @returns {string} the text representation of the value
|
* @returns {string} the text representation of the value
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -34,6 +34,11 @@ define([
|
|||||||
"YYYY-MM-DD"
|
"YYYY-MM-DD"
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef Scale
|
||||||
|
* @property {number} min the minimum scale value, in ms
|
||||||
|
* @property {number} max the maximum scale value, in ms
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Formatter for UTC timestamps. Interprets numeric values as
|
* Formatter for UTC timestamps. Interprets numeric values as
|
||||||
@ -46,7 +51,64 @@ define([
|
|||||||
function UTCTimeFormat() {
|
function UTCTimeFormat() {
|
||||||
}
|
}
|
||||||
|
|
||||||
UTCTimeFormat.prototype.format = function (value) {
|
/**
|
||||||
|
* Returns an appropriate time format based on the provided value and
|
||||||
|
* the threshold required.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
function getScaledFormat(d) {
|
||||||
|
var momentified = moment.utc(d);
|
||||||
|
/**
|
||||||
|
* Uses logic from d3 Time-Scales, v3 of the API. See
|
||||||
|
* https://github.com/d3/d3-3.x-api-reference/blob/master/Time-Scales.md
|
||||||
|
*
|
||||||
|
* Licensed
|
||||||
|
*/
|
||||||
|
return [
|
||||||
|
[".SSS", function (m) {
|
||||||
|
return m.milliseconds();
|
||||||
|
}],
|
||||||
|
[":ss", function (m) {
|
||||||
|
return m.seconds();
|
||||||
|
}],
|
||||||
|
["HH:mm", function (m) {
|
||||||
|
return m.minutes();
|
||||||
|
}],
|
||||||
|
["HH", function (m) {
|
||||||
|
return m.hours();
|
||||||
|
}],
|
||||||
|
["ddd DD", function (m) {
|
||||||
|
return m.days() &&
|
||||||
|
m.date() !== 1;
|
||||||
|
}],
|
||||||
|
["MMM DD", function (m) {
|
||||||
|
return m.date() !== 1;
|
||||||
|
}],
|
||||||
|
["MMMM", function (m) {
|
||||||
|
return m.month();
|
||||||
|
}],
|
||||||
|
["YYYY", function () {
|
||||||
|
return true;
|
||||||
|
}]
|
||||||
|
].filter(function (row) {
|
||||||
|
return row[1](momentified);
|
||||||
|
})[0][0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param value
|
||||||
|
* @param {Scale} [scale] Optionally provides context to the
|
||||||
|
* format request, allowing for scale-appropriate formatting.
|
||||||
|
* @returns {string} the formatted date
|
||||||
|
*/
|
||||||
|
UTCTimeFormat.prototype.format = function (value, scale) {
|
||||||
|
if (scale !== undefined) {
|
||||||
|
var scaledFormat = getScaledFormat(value, scale);
|
||||||
|
if (scaledFormat) {
|
||||||
|
return moment.utc(value).format(scaledFormat);
|
||||||
|
}
|
||||||
|
}
|
||||||
return moment.utc(value).format(DATE_FORMAT) + "Z";
|
return moment.utc(value).format(DATE_FORMAT) + "Z";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
62
platform/commonUI/formats/src/UTCTimeFormatSpec.js
Normal file
62
platform/commonUI/formats/src/UTCTimeFormatSpec.js
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT Web includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
define([
|
||||||
|
"./UTCTimeFormat",
|
||||||
|
"moment"
|
||||||
|
], function (
|
||||||
|
UTCTimeFormat,
|
||||||
|
moment
|
||||||
|
) {
|
||||||
|
describe("The UTCTimeFormat class", function () {
|
||||||
|
var format;
|
||||||
|
var scale;
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
format = new UTCTimeFormat();
|
||||||
|
scale = {min: 0, max: 0};
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Provides an appropriately scaled time format based on the input" +
|
||||||
|
" time", function () {
|
||||||
|
var TWO_HUNDRED_MS = 200;
|
||||||
|
var THREE_SECONDS = 3000;
|
||||||
|
var FIVE_MINUTES = 5 * 60 * 1000;
|
||||||
|
var ONE_HOUR_TWENTY_MINS = (1 * 60 * 60 * 1000) + (20 * 60 * 1000);
|
||||||
|
var TEN_HOURS = (10 * 60 * 60 * 1000);
|
||||||
|
|
||||||
|
var JUNE_THIRD = moment.utc("2016-06-03", "YYYY-MM-DD");
|
||||||
|
var APRIL = moment.utc("2016-04", "YYYY-MM");
|
||||||
|
var TWENTY_SIXTEEN = moment.utc("2016", "YYYY");
|
||||||
|
|
||||||
|
expect(format.format(TWO_HUNDRED_MS, scale)).toBe(".200");
|
||||||
|
expect(format.format(THREE_SECONDS, scale)).toBe(":03");
|
||||||
|
expect(format.format(FIVE_MINUTES, scale)).toBe("00:05");
|
||||||
|
expect(format.format(ONE_HOUR_TWENTY_MINS, scale)).toBe("01:20");
|
||||||
|
expect(format.format(TEN_HOURS, scale)).toBe("10");
|
||||||
|
|
||||||
|
expect(format.format(JUNE_THIRD, scale)).toBe("Fri 03");
|
||||||
|
expect(format.format(APRIL, scale)).toBe("April");
|
||||||
|
expect(format.format(TWENTY_SIXTEEN, scale)).toBe("2016");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
91
platform/commonUI/general/res/sass/_animations.scss
Normal file
91
platform/commonUI/general/res/sass/_animations.scss
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
@include keyframes(rotation) {
|
||||||
|
100% { @include transform(rotate(360deg)); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@include keyframes(rotation-centered) {
|
||||||
|
0% { @include transform(translate(-50%, -50%) rotate(0deg)); }
|
||||||
|
100% { @include transform(translate(-50%, -50%) rotate(360deg)); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@include keyframes(clock-hands) {
|
||||||
|
0% { @include transform(translate(-50%, -50%) rotate(0deg)); }
|
||||||
|
100% { @include transform(translate(-50%, -50%) rotate(360deg)); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@include keyframes(clock-hands-sticky) {
|
||||||
|
0% {
|
||||||
|
@include transform(translate(-50%, -50%) rotate(0deg));
|
||||||
|
}
|
||||||
|
7% {
|
||||||
|
@include transform(translate(-50%, -50%) rotate(0deg));
|
||||||
|
}
|
||||||
|
8% {
|
||||||
|
@include transform(translate(-50%, -50%) rotate(30deg));
|
||||||
|
}
|
||||||
|
15% {
|
||||||
|
@include transform(translate(-50%, -50%) rotate(30deg));
|
||||||
|
}
|
||||||
|
16% {
|
||||||
|
@include transform(translate(-50%, -50%) rotate(60deg));
|
||||||
|
}
|
||||||
|
24% {
|
||||||
|
@include transform(translate(-50%, -50%) rotate(60deg));
|
||||||
|
}
|
||||||
|
25% {
|
||||||
|
@include transform(translate(-50%, -50%) rotate(90deg));
|
||||||
|
}
|
||||||
|
32% {
|
||||||
|
@include transform(translate(-50%, -50%) rotate(90deg));
|
||||||
|
}
|
||||||
|
33% {
|
||||||
|
@include transform(translate(-50%, -50%) rotate(120deg));
|
||||||
|
}
|
||||||
|
40% {
|
||||||
|
@include transform(translate(-50%, -50%) rotate(120deg));
|
||||||
|
}
|
||||||
|
41% {
|
||||||
|
@include transform(translate(-50%, -50%) rotate(150deg));
|
||||||
|
}
|
||||||
|
49% {
|
||||||
|
@include transform(translate(-50%, -50%) rotate(150deg));
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
@include transform(translate(-50%, -50%) rotate(180deg));
|
||||||
|
}
|
||||||
|
57% {
|
||||||
|
@include transform(translate(-50%, -50%) rotate(180deg));
|
||||||
|
}
|
||||||
|
58% {
|
||||||
|
@include transform(translate(-50%, -50%) rotate(210deg));
|
||||||
|
}
|
||||||
|
65% {
|
||||||
|
@include transform(translate(-50%, -50%) rotate(210deg));
|
||||||
|
}
|
||||||
|
66% {
|
||||||
|
@include transform(translate(-50%, -50%) rotate(240deg));
|
||||||
|
}
|
||||||
|
74% {
|
||||||
|
@include transform(translate(-50%, -50%) rotate(240deg));
|
||||||
|
}
|
||||||
|
75% {
|
||||||
|
@include transform(translate(-50%, -50%) rotate(270deg));
|
||||||
|
}
|
||||||
|
82% {
|
||||||
|
@include transform(translate(-50%, -50%) rotate(270deg));
|
||||||
|
}
|
||||||
|
83% {
|
||||||
|
@include transform(translate(-50%, -50%) rotate(300deg));
|
||||||
|
}
|
||||||
|
90% {
|
||||||
|
@include transform(translate(-50%, -50%) rotate(300deg));
|
||||||
|
}
|
||||||
|
91% {
|
||||||
|
@include transform(translate(-50%, -50%) rotate(330deg));
|
||||||
|
}
|
||||||
|
99% {
|
||||||
|
@include transform(translate(-50%, -50%) rotate(330deg));
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
@include transform(translate(-50%, -50%) rotate(360deg));
|
||||||
|
}
|
||||||
|
}
|
@ -108,6 +108,9 @@
|
|||||||
&.grows {
|
&.grows {
|
||||||
@include flex(1 1 auto);
|
@include flex(1 1 auto);
|
||||||
}
|
}
|
||||||
|
&.contents-align-right {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.flex-container {
|
.flex-container {
|
||||||
// Apply to wrapping elements, mct-includes, etc.
|
// Apply to wrapping elements, mct-includes, etc.
|
||||||
|
@ -49,7 +49,6 @@ $uePaneMiniTabFontSize: 8px;
|
|||||||
$uePaneMiniTabCollapsedW: 18px;
|
$uePaneMiniTabCollapsedW: 18px;
|
||||||
$ueEditLeftPaneW: 75%;
|
$ueEditLeftPaneW: 75%;
|
||||||
$treeSearchInputBarH: 25px;
|
$treeSearchInputBarH: 25px;
|
||||||
$ueTimeControlH: (33px, 18px, 20px);
|
|
||||||
/*************** Panes */
|
/*************** Panes */
|
||||||
$ueBrowseLeftPaneTreeMinW: 150px;
|
$ueBrowseLeftPaneTreeMinW: 150px;
|
||||||
$ueBrowseLeftPaneTreeMaxW: 35%;
|
$ueBrowseLeftPaneTreeMaxW: 35%;
|
||||||
@ -112,6 +111,7 @@ $bubbleMaxW: 300px;
|
|||||||
$reqSymbolW: 15px;
|
$reqSymbolW: 15px;
|
||||||
$reqSymbolM: $interiorMargin * 2;
|
$reqSymbolM: $interiorMargin * 2;
|
||||||
$reqSymbolFontSize: 0.75em;
|
$reqSymbolFontSize: 0.75em;
|
||||||
|
$inputTextP: 3px 5px;
|
||||||
/*************** Wait Spinner Defaults */
|
/*************** Wait Spinner Defaults */
|
||||||
$waitSpinnerD: 32px;
|
$waitSpinnerD: 32px;
|
||||||
$waitSpinnerTreeD: 20px;
|
$waitSpinnerTreeD: 20px;
|
||||||
|
@ -4,4 +4,3 @@
|
|||||||
@include s-stale();
|
@include s-stale();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,20 +39,20 @@
|
|||||||
@include pulse($animName: pulse-subtle, $dur: 500ms, $opacity0: 0.7);
|
@include pulse($animName: pulse-subtle, $dur: 500ms, $opacity0: 0.7);
|
||||||
}
|
}
|
||||||
|
|
||||||
@mixin animTo($animName, $propName, $propValStart, $propValEnd, $dur: 500ms, $delay: 0) {
|
@mixin animTo($animName, $propName, $propValStart, $propValEnd, $dur: 500ms, $delay: 0, $dir: normal, $count: 1) {
|
||||||
@include keyframes($animName) {
|
@include keyframes($animName) {
|
||||||
from { #{propName}: $propValStart; }
|
from { #{propName}: $propValStart; }
|
||||||
to { #{$propName}: $propValEnd; }
|
to { #{$propName}: $propValEnd; }
|
||||||
}
|
}
|
||||||
@include animToParams($animName, $dur: 500ms, $delay: 0)
|
@include animToParams($animName, $dur: $dur, $delay: $delay, $dir: $dir, $count: $count)
|
||||||
}
|
}
|
||||||
|
|
||||||
@mixin animToParams($animName, $dur: 500ms, $delay: 0) {
|
@mixin animToParams($animName, $dur: 500ms, $delay: 0, $dir: normal, $count: 1) {
|
||||||
@include animation-name($animName);
|
@include animation-name($animName);
|
||||||
@include animation-duration($dur);
|
@include animation-duration($dur);
|
||||||
@include animation-delay($delay);
|
@include animation-delay($delay);
|
||||||
@include animation-fill-mode(both);
|
@include animation-fill-mode(both);
|
||||||
@include animation-direction(normal);
|
@include animation-direction($dir);
|
||||||
@include animation-iteration-count(1);
|
@include animation-iteration-count($count);
|
||||||
@include animation-timing-function(ease-in-out);
|
@include animation-timing-function(ease-in-out);
|
||||||
}
|
}
|
@ -82,7 +82,7 @@ input, textarea {
|
|||||||
input[type="text"],
|
input[type="text"],
|
||||||
input[type="search"] {
|
input[type="search"] {
|
||||||
vertical-align: baseline;
|
vertical-align: baseline;
|
||||||
padding: 3px 5px;
|
padding: $inputTextP;
|
||||||
}
|
}
|
||||||
|
|
||||||
h1, h2, h3 {
|
h1, h2, h3 {
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
|
|
||||||
.ui-symbol {
|
.ui-symbol {
|
||||||
font-family: 'symbolsfont';
|
font-family: 'symbolsfont';
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ui-symbol.icon {
|
.ui-symbol.icon {
|
||||||
@ -70,7 +71,6 @@
|
|||||||
line-height: inherit;
|
line-height: inherit;
|
||||||
position: relative;
|
position: relative;
|
||||||
&.l-icon-link {
|
&.l-icon-link {
|
||||||
.t-item-icon-glyph {
|
|
||||||
&:after {
|
&:after {
|
||||||
color: $colorIconLink;
|
color: $colorIconLink;
|
||||||
content: $glyph-icon-link;
|
content: $glyph-icon-link;
|
||||||
@ -81,6 +81,18 @@
|
|||||||
@include transform(scale(0.3));
|
@include transform(scale(0.3));
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
/* .t-item-icon-glyph {
|
||||||
|
&:after {
|
||||||
|
color: $colorIconLink;
|
||||||
|
content: '\e921'; //$glyph-icon-link;
|
||||||
|
height: auto; width: auto;
|
||||||
|
position: absolute;
|
||||||
|
left: 0; top: 0; right: 0; bottom: 20%;
|
||||||
|
@include transform-origin(bottom left);
|
||||||
|
@include transform(scale(0.3));
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
}*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
@import "effects";
|
@import "effects";
|
||||||
@import "global";
|
@import "global";
|
||||||
@import "glyphs";
|
@import "glyphs";
|
||||||
|
@import "animations";
|
||||||
@import "archetypes";
|
@import "archetypes";
|
||||||
@import "about";
|
@import "about";
|
||||||
@import "text";
|
@import "text";
|
||||||
@ -41,7 +42,6 @@
|
|||||||
@import "controls/lists";
|
@import "controls/lists";
|
||||||
@import "controls/menus";
|
@import "controls/menus";
|
||||||
@import "controls/messages";
|
@import "controls/messages";
|
||||||
@import "controls/time-controller";
|
|
||||||
@import "mobile/controls/menus";
|
@import "mobile/controls/menus";
|
||||||
|
|
||||||
/********************************* FORMS */
|
/********************************* FORMS */
|
||||||
|
@ -185,21 +185,15 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@mixin sliderTrack($bg: $scrollbarTrackColorBg) {
|
@mixin sliderTrack($bg: $scrollbarTrackColorBg) {
|
||||||
//$b: 1px solid lighten($bg, 30%);
|
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
@include boxIncised(0.7);
|
@include boxIncised(0.7);
|
||||||
background-color: $bg;
|
background-color: $bg;
|
||||||
//border-bottom: $b;
|
|
||||||
//border-right: $b;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@mixin controlGrippy($b, $direction: horizontal, $w: 1px, $style: dotted) {
|
@mixin controlGrippy($b, $direction: horizontal, $w: 1px, $style: dotted) {
|
||||||
//&:before {
|
|
||||||
//@include trans-prop-nice("border-color", 25ms);
|
|
||||||
content: '';
|
content: '';
|
||||||
display: block;
|
display: block;
|
||||||
//height: auto;
|
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
@ -274,16 +268,6 @@
|
|||||||
text-shadow: rgba(black, $sVal) 0 3px 7px;
|
text-shadow: rgba(black, $sVal) 0 3px 7px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@function pullForward($c, $p: 20%) {
|
|
||||||
// For dark interfaces, lighter things come forward
|
|
||||||
@return lighten($c, $p);
|
|
||||||
}
|
|
||||||
|
|
||||||
@function pushBack($c, $p: 20%) {
|
|
||||||
// For dark interfaces, darker things move back
|
|
||||||
@return darken($c, $p);
|
|
||||||
}
|
|
||||||
|
|
||||||
@function percentToDecimal($p) {
|
@function percentToDecimal($p) {
|
||||||
@return $p / 100%;
|
@return $p / 100%;
|
||||||
}
|
}
|
||||||
@ -304,7 +288,6 @@
|
|||||||
border-radius: $controlCr;
|
border-radius: $controlCr;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
color: $fg;
|
color: $fg;
|
||||||
//display: inline-block;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@mixin btnBase($bg: $colorBtnBg, $bgHov: $colorBtnBgHov, $fg: $colorBtnFg, $fgHov: $colorBtnFgHov, $ic: $colorBtnIcon, $icHov: $colorBtnIconHov) {
|
@mixin btnBase($bg: $colorBtnBg, $bgHov: $colorBtnBgHov, $fg: $colorBtnFg, $fgHov: $colorBtnFgHov, $ic: $colorBtnIcon, $icHov: $colorBtnIconHov) {
|
||||||
|
@ -296,8 +296,6 @@ input[type="search"] {
|
|||||||
.title-label {
|
.title-label {
|
||||||
color: $colorObjHdrTxt;
|
color: $colorObjHdrTxt;
|
||||||
@include ellipsize();
|
@include ellipsize();
|
||||||
@include webkitProp(flex, '0 1 auto');
|
|
||||||
padding-right: 0.35em; // For context arrow. Done with em's so pad is relative to the scale of the text.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.context-available-w {
|
.context-available-w {
|
||||||
@ -308,6 +306,10 @@ input[type="search"] {
|
|||||||
font-size: 0.7em;
|
font-size: 0.7em;
|
||||||
@include flex(0 0 1);
|
@include flex(0 0 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.t-object-alert {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************** PROGRESS BAR */
|
/******************************************************** PROGRESS BAR */
|
||||||
@ -441,6 +443,63 @@ input[type="search"] {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@mixin sliderKnob() {
|
||||||
|
$h: 16px;
|
||||||
|
cursor: pointer;
|
||||||
|
width: floor($h/1.75);
|
||||||
|
height: $h;
|
||||||
|
margin-top: 1 + floor($h/2) * -1;
|
||||||
|
@include btnSubtle(pullForward($colorBtnBg, 10%));
|
||||||
|
//border-radius: 50% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
@mixin sliderKnobRound() {
|
||||||
|
$h: 12px;
|
||||||
|
cursor: pointer;
|
||||||
|
width: $h;
|
||||||
|
height: $h;
|
||||||
|
margin-top: 1 + floor($h/2) * -1;
|
||||||
|
@include btnSubtle(pullForward($colorBtnBg, 10%));
|
||||||
|
border-radius: 50% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
outline: none; /* Removes the blue border. */
|
||||||
|
}
|
||||||
|
|
||||||
|
// Thumb
|
||||||
|
&::-webkit-slider-thumb {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
@include sliderKnobRound();
|
||||||
|
}
|
||||||
|
&::-moz-range-thumb {
|
||||||
|
border: none;
|
||||||
|
@include sliderKnobRound();
|
||||||
|
}
|
||||||
|
&::-ms-thumb {
|
||||||
|
border: none;
|
||||||
|
@include sliderKnobRound();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Track
|
||||||
|
&::-webkit-slider-runnable-track {
|
||||||
|
width: 100%;
|
||||||
|
height: 3px;
|
||||||
|
@include sliderTrack();
|
||||||
|
}
|
||||||
|
|
||||||
|
&::-moz-range-track {
|
||||||
|
width: 100%;
|
||||||
|
height: 3px;
|
||||||
|
@include sliderTrack();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/******************************************************** DATETIME PICKER */
|
/******************************************************** DATETIME PICKER */
|
||||||
.l-datetime-picker {
|
.l-datetime-picker {
|
||||||
$r1H: 15px;
|
$r1H: 15px;
|
||||||
|
@ -178,7 +178,7 @@
|
|||||||
}
|
}
|
||||||
.pane {
|
.pane {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
&.left {
|
&.menu-items {
|
||||||
border-right: 1px solid pullForward($colorMenuBg, 10%);
|
border-right: 1px solid pullForward($colorMenuBg, 10%);
|
||||||
left: 0;
|
left: 0;
|
||||||
padding-right: $interiorMargin;
|
padding-right: $interiorMargin;
|
||||||
@ -194,39 +194,54 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&.right {
|
&.menu-item-description {
|
||||||
left: auto;
|
left: auto;
|
||||||
right: 0;
|
right: 0;
|
||||||
padding: $interiorMargin * 5;
|
padding: $interiorMargin * 5;
|
||||||
width: $prw;
|
width: $prw;
|
||||||
}
|
|
||||||
}
|
|
||||||
.menu-item-description {
|
|
||||||
.desc-area {
|
.desc-area {
|
||||||
&.icon {
|
&.icon {
|
||||||
$h: 150px;
|
|
||||||
color: $colorCreateMenuLgIcon;
|
color: $colorCreateMenuLgIcon;
|
||||||
position: relative;
|
|
||||||
font-size: 8em;
|
font-size: 8em;
|
||||||
left: 0;
|
margin-bottom: $interiorMargin * 3;
|
||||||
height: $h;
|
position: relative;
|
||||||
line-height: $h;
|
|
||||||
margin-bottom: $interiorMargin * 5;
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
&.title {
|
&.title {
|
||||||
color: $colorCreateMenuText;
|
color: $colorCreateMenuText;
|
||||||
font-size: 1.2em;
|
font-size: 1.2em;
|
||||||
margin-bottom: 0.5em;
|
margin-bottom: $interiorMargin * 2;
|
||||||
}
|
}
|
||||||
&.description {
|
&.description {
|
||||||
color: $colorCreateMenuText;
|
color: pushBack($colorCreateMenuText, 20%);
|
||||||
font-size: 0.8em;
|
font-size: 0.8em;
|
||||||
line-height: 1.5em;
|
line-height: 1.5em;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.mini {
|
||||||
|
width: 400px;
|
||||||
|
height: 300px;
|
||||||
|
.pane {
|
||||||
|
&.menu-items {
|
||||||
|
font-size: 0.8em;
|
||||||
|
}
|
||||||
|
&.menu-item-description {
|
||||||
|
padding: $interiorMargin * 3;
|
||||||
|
.desc-area {
|
||||||
|
&.icon {
|
||||||
|
font-size: 4em;
|
||||||
|
}
|
||||||
|
&.title {
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
.context-menu {
|
.context-menu {
|
||||||
font-size: 0.80rem;
|
font-size: 0.80rem;
|
||||||
}
|
}
|
||||||
@ -262,3 +277,7 @@
|
|||||||
right: 0;
|
right: 0;
|
||||||
width: auto;
|
width: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.menus-up .menu {
|
||||||
|
bottom: $btnStdH; top: auto;
|
||||||
|
}
|
||||||
|
@ -345,3 +345,29 @@ body.desktop .t-message-single {
|
|||||||
body.desktop .t-message-list {
|
body.desktop .t-message-list {
|
||||||
.message-contents .l-message { margin-right: $interiorMarginLg; }
|
.message-contents .l-message { margin-right: $interiorMarginLg; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Alert elements in views
|
||||||
|
.s-unsynced {
|
||||||
|
$c: $colorPausedBg;
|
||||||
|
border: 1px solid $c;
|
||||||
|
@include animTo($animName: pulsePaused, $propName: border-color, $propValStart: rgba($c, 0.8), $propValEnd: rgba($c, 0.5), $dur: $animPausedPulseDur, $dir: alternate, $count: infinite);
|
||||||
|
}
|
||||||
|
|
||||||
|
.s-status-timeconductor-unsynced {
|
||||||
|
// Plot areas
|
||||||
|
.gl-plot .gl-plot-display-area {
|
||||||
|
@extend .s-unsynced;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Object headers
|
||||||
|
.object-header {
|
||||||
|
.t-object-alert {
|
||||||
|
display: inline;
|
||||||
|
&.t-alert-unsynced {
|
||||||
|
@extend .icon-alert-triangle;
|
||||||
|
color: $colorPausedBg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -1,266 +0,0 @@
|
|||||||
@mixin toiLineHovEffects() {
|
|
||||||
&:before,
|
|
||||||
&:after {
|
|
||||||
background-color: $timeControllerToiLineColorHov;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.l-time-controller {
|
|
||||||
$minW: 500px;
|
|
||||||
$knobHOffset: 0px;
|
|
||||||
$knobM: ($sliderKnobW + $knobHOffset) * -1;
|
|
||||||
$rangeValPad: $interiorMargin;
|
|
||||||
$rangeValOffset: $sliderKnobW + $interiorMargin;
|
|
||||||
$timeRangeSliderLROffset: 150px + ($sliderKnobW * 2);
|
|
||||||
$r1H: nth($ueTimeControlH,1); // Not currently used
|
|
||||||
$r2H: nth($ueTimeControlH,2);
|
|
||||||
$r3H: nth($ueTimeControlH,3);
|
|
||||||
|
|
||||||
min-width: $minW;
|
|
||||||
font-size: 0.8rem;
|
|
||||||
|
|
||||||
.l-time-range-inputs-holder,
|
|
||||||
.l-time-range-slider-holder,
|
|
||||||
.l-time-range-ticks-holder
|
|
||||||
{
|
|
||||||
box-sizing: border-box;
|
|
||||||
position: relative;
|
|
||||||
&:not(:first-child) {
|
|
||||||
margin-top: $interiorMargin;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.l-time-range-slider,
|
|
||||||
.l-time-range-ticks {
|
|
||||||
@include absPosDefault(0, visible);
|
|
||||||
left: $timeRangeSliderLROffset; right: $timeRangeSliderLROffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
.l-time-range-inputs-holder {
|
|
||||||
border-top: 1px solid $colorInteriorBorder;
|
|
||||||
padding-top: $interiorMargin;
|
|
||||||
&.l-flex-row,
|
|
||||||
.l-flex-row {
|
|
||||||
@include align-items(center);
|
|
||||||
.flex-elem {
|
|
||||||
height: auto;
|
|
||||||
line-height: normal;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.type-icon {
|
|
||||||
font-size: 120%;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
.l-time-range-input-w,
|
|
||||||
.l-time-range-inputs-elem {
|
|
||||||
margin-right: $interiorMargin;
|
|
||||||
.lbl {
|
|
||||||
color: $colorPlotLabelFg;
|
|
||||||
}
|
|
||||||
.ui-symbol.icon {
|
|
||||||
font-size: 11px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.l-time-range-input-w {
|
|
||||||
// Wraps a datetime text input field
|
|
||||||
position: relative;
|
|
||||||
input[type="text"] {
|
|
||||||
width: 200px;
|
|
||||||
&.picker-icon {
|
|
||||||
padding-right: 20px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.icon-calendar {
|
|
||||||
position: absolute;
|
|
||||||
right: 5px;
|
|
||||||
top: 5px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.l-time-range-slider-holder {
|
|
||||||
height: $r2H;
|
|
||||||
.range-holder {
|
|
||||||
box-shadow: none;
|
|
||||||
background: none;
|
|
||||||
border: none;
|
|
||||||
.range {
|
|
||||||
.toi-line {
|
|
||||||
$myC: $timeControllerToiLineColor;
|
|
||||||
$myW: 8px;
|
|
||||||
@include transform(translateX(50%));
|
|
||||||
position: absolute;
|
|
||||||
top: 0; right: 0; bottom: 0px; left: auto;
|
|
||||||
width: $myW;
|
|
||||||
height: auto;
|
|
||||||
z-index: 2;
|
|
||||||
&:before {
|
|
||||||
// Vert line
|
|
||||||
background-color: $myC;
|
|
||||||
position: absolute;
|
|
||||||
content: "";
|
|
||||||
top: 0; right: auto; bottom: -10px; left: floor($myW/2) - 1;
|
|
||||||
width: 1px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&:hover .toi-line {
|
|
||||||
@include toiLineHovEffects;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&:not(:active) {
|
|
||||||
.knob,
|
|
||||||
.range {
|
|
||||||
@include transition-property(left, right);
|
|
||||||
@include transition-duration(500ms);
|
|
||||||
@include transition-timing-function(ease-in-out);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.l-time-range-ticks-holder {
|
|
||||||
height: $r3H;
|
|
||||||
.l-time-range-ticks {
|
|
||||||
border-top: 1px solid $colorTick;
|
|
||||||
.tick {
|
|
||||||
background-color: $colorTick;
|
|
||||||
border:none;
|
|
||||||
height: 5px;
|
|
||||||
width: 1px;
|
|
||||||
margin-left: -1px;
|
|
||||||
position: absolute;
|
|
||||||
&:first-child {
|
|
||||||
margin-left: 0;
|
|
||||||
}
|
|
||||||
.l-time-range-tick-label {
|
|
||||||
@include webkitProp(transform, translateX(-50%));
|
|
||||||
color: $colorPlotLabelFg;
|
|
||||||
display: inline-block;
|
|
||||||
font-size: 0.7rem;
|
|
||||||
position: absolute;
|
|
||||||
top: 5px;
|
|
||||||
white-space: nowrap;
|
|
||||||
z-index: 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.knob {
|
|
||||||
z-index: 2;
|
|
||||||
&:before {
|
|
||||||
$mTB: 2px;
|
|
||||||
$grippyW: 3px;
|
|
||||||
$mLR: ($sliderKnobW - $grippyW)/2;
|
|
||||||
@include bgStripes($c: pullForward($sliderColorKnob, 20%), $a: 1, $bgsize: 4px, $angle: 0deg);
|
|
||||||
content: '';
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
top: $mTB; right: $mLR; bottom: $mTB; left: $mLR;
|
|
||||||
}
|
|
||||||
.range-value {
|
|
||||||
@include trans-prop-nice-fade(.25s);
|
|
||||||
font-size: 0.7rem;
|
|
||||||
position: absolute;
|
|
||||||
height: $r2H;
|
|
||||||
line-height: $r2H;
|
|
||||||
white-space: nowrap;
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
&:hover {
|
|
||||||
.range-value {
|
|
||||||
color: $sliderColorKnobHov;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&.knob-l {
|
|
||||||
margin-left: $knobM;
|
|
||||||
.range-value {
|
|
||||||
text-align: right;
|
|
||||||
right: $rangeValOffset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&.knob-r {
|
|
||||||
margin-right: $knobM;
|
|
||||||
.range-value {
|
|
||||||
left: $rangeValOffset;
|
|
||||||
}
|
|
||||||
&:hover + .range-holder .range .toi-line {
|
|
||||||
@include toiLineHovEffects;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.l-time-domain-selector {
|
|
||||||
position: absolute;
|
|
||||||
right: 0px;
|
|
||||||
top: $interiorMargin;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.s-time-range-val {
|
|
||||||
border-radius: $controlCr;
|
|
||||||
background-color: $colorInputBg;
|
|
||||||
padding: 1px 1px 0 $interiorMargin;
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************************************************************** MOBILE */
|
|
||||||
|
|
||||||
@include phoneandtablet {
|
|
||||||
.l-time-controller {
|
|
||||||
min-width: 0;
|
|
||||||
.l-time-range-slider-holder,
|
|
||||||
.l-time-range-ticks-holder {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@include phone {
|
|
||||||
.l-time-controller {
|
|
||||||
.l-time-range-inputs-holder {
|
|
||||||
&.l-flex-row,
|
|
||||||
.l-flex-row {
|
|
||||||
@include align-items(flex-start);
|
|
||||||
}
|
|
||||||
.l-time-range-inputs-elem {
|
|
||||||
&.type-icon {
|
|
||||||
margin-top: 3px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.t-inputs-w {
|
|
||||||
@include flex-direction(column);
|
|
||||||
.l-time-range-input-w:not(:first-child) {
|
|
||||||
&:not(:first-child) {
|
|
||||||
margin-top: $interiorMargin;
|
|
||||||
}
|
|
||||||
margin-right: 0;
|
|
||||||
}
|
|
||||||
.l-time-range-inputs-elem {
|
|
||||||
&.lbl { display: none; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@include phonePortrait {
|
|
||||||
.l-time-controller {
|
|
||||||
.l-time-range-inputs-holder {
|
|
||||||
.t-inputs-w {
|
|
||||||
@include flex(1 1 auto);
|
|
||||||
padding-top: 25px; // Make room for the ever lovin' Time Domain Selector
|
|
||||||
.flex-elem {
|
|
||||||
@include flex(1 1 auto);
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
input[type="text"] {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.l-time-domain-selector {
|
|
||||||
right: auto;
|
|
||||||
left: 20px;
|
|
||||||
}
|
|
||||||
}
|
|
@ -74,7 +74,7 @@
|
|||||||
.s-image-main {
|
.s-image-main {
|
||||||
border: 1px solid transparent;
|
border: 1px solid transparent;
|
||||||
&.paused {
|
&.paused {
|
||||||
border-color: $colorPausedBg;
|
@extend .s-unsynced;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,15 +19,6 @@
|
|||||||
* this source code distribution or the Licensing information page available
|
* this source code distribution or the Licensing information page available
|
||||||
* at runtime from the About dialog for additional information.
|
* at runtime from the About dialog for additional information.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
@include keyframes(rotation) {
|
|
||||||
100% { @include transform(rotate(360deg)); }
|
|
||||||
}
|
|
||||||
|
|
||||||
@include keyframes(rotation-centered) {
|
|
||||||
0% { @include transform(translate(-50%, -50%) rotate(0deg)); }
|
|
||||||
100% { @include transform(translate(-50%, -50%) rotate(360deg)); }
|
|
||||||
}
|
|
||||||
|
|
||||||
@mixin spinner($b: 5px, $c: $colorKey) {
|
@mixin spinner($b: 5px, $c: $colorKey) {
|
||||||
@include transform-origin(center);
|
@include transform-origin(center);
|
||||||
@include animation-name(rotation-centered);
|
@include animation-name(rotation-centered);
|
||||||
|
@ -128,7 +128,7 @@
|
|||||||
line-height: $ueTopBarH;
|
line-height: $ueTopBarH;
|
||||||
}
|
}
|
||||||
|
|
||||||
.primary-pane {
|
.t-object.primary-pane {
|
||||||
// Need to lift up this pane to ensure that 'collapsed' panes don't block user interactions
|
// Need to lift up this pane to ensure that 'collapsed' panes don't block user interactions
|
||||||
z-index: 4;
|
z-index: 4;
|
||||||
}
|
}
|
||||||
@ -212,6 +212,8 @@ body.desktop .pane .mini-tab-icon.toggle-pane {
|
|||||||
.holder-object {
|
.holder-object {
|
||||||
top: $bodyMargin;
|
top: $bodyMargin;
|
||||||
bottom: $interiorMargin;
|
bottom: $interiorMargin;
|
||||||
|
// Clip element that have min-widths
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
.holder-inspector {
|
.holder-inspector {
|
||||||
top: $bodyMargin;
|
top: $bodyMargin;
|
||||||
|
@ -23,6 +23,8 @@
|
|||||||
<input type="text"
|
<input type="text"
|
||||||
ng-model="textValue"
|
ng-model="textValue"
|
||||||
ng-blur="restoreTextValue(); ngBlur()"
|
ng-blur="restoreTextValue(); ngBlur()"
|
||||||
|
ng-mouseup="ngMouseup()"
|
||||||
|
ng-disabled="ngDisabled"
|
||||||
ng-class="{
|
ng-class="{
|
||||||
error: textInvalid ||
|
error: textInvalid ||
|
||||||
(structure.validate &&
|
(structure.validate &&
|
||||||
|
@ -116,6 +116,7 @@ $colorProgressBarAmt: $colorKey;
|
|||||||
$progressBarHOverlay: 15px;
|
$progressBarHOverlay: 15px;
|
||||||
$progressBarStripeW: 20px;
|
$progressBarStripeW: 20px;
|
||||||
$shdwStatusIc: rgba(black, 0.4) 0 1px 2px;
|
$shdwStatusIc: rgba(black, 0.4) 0 1px 2px;
|
||||||
|
$animPausedPulseDur: 500ms;
|
||||||
|
|
||||||
// Selects
|
// Selects
|
||||||
$colorSelectBg: $colorBtnBg;
|
$colorSelectBg: $colorBtnBg;
|
||||||
|
@ -116,6 +116,7 @@ $colorProgressBarAmt: #0a0;
|
|||||||
$progressBarHOverlay: 15px;
|
$progressBarHOverlay: 15px;
|
||||||
$progressBarStripeW: 20px;
|
$progressBarStripeW: 20px;
|
||||||
$shdwStatusIc: rgba(white, 0.8) 0 0px 5px;
|
$shdwStatusIc: rgba(white, 0.8) 0 0px 5px;
|
||||||
|
$animPausedPulseDur: 1s;
|
||||||
|
|
||||||
// Selects
|
// Selects
|
||||||
$colorSelectBg: $colorBtnBg;
|
$colorSelectBg: $colorBtnBg;
|
||||||
|
66
platform/features/conductor-v2/compatibility/bundle.js
Normal file
66
platform/features/conductor-v2/compatibility/bundle.js
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT Web includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
define([
|
||||||
|
"./src/ConductorTelemetryDecorator",
|
||||||
|
"./src/ConductorRepresenter",
|
||||||
|
"./src/ConductorService",
|
||||||
|
'legacyRegistry'
|
||||||
|
], function (
|
||||||
|
ConductorTelemetryDecorator,
|
||||||
|
ConductorRepresenter,
|
||||||
|
ConductorService,
|
||||||
|
legacyRegistry
|
||||||
|
) {
|
||||||
|
|
||||||
|
legacyRegistry.register("platform/features/conductor-v2/compatibility", {
|
||||||
|
"extensions": {
|
||||||
|
"services": [
|
||||||
|
{
|
||||||
|
"key": "conductorService",
|
||||||
|
"implementation": ConductorService,
|
||||||
|
"depends": [
|
||||||
|
"timeConductor"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"representers": [
|
||||||
|
{
|
||||||
|
"implementation": ConductorRepresenter,
|
||||||
|
"depends": [
|
||||||
|
"timeConductor"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"components": [
|
||||||
|
{
|
||||||
|
"type": "decorator",
|
||||||
|
"provides": "telemetryService",
|
||||||
|
"implementation": ConductorTelemetryDecorator,
|
||||||
|
"depends": [
|
||||||
|
"timeConductor"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,94 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT Web includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
define(
|
||||||
|
[],
|
||||||
|
function () {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Representer that provides a compatibility layer between the new
|
||||||
|
* time conductor and existing representations / views. Listens to
|
||||||
|
* the v2 time conductor API and generates v1 style events using the
|
||||||
|
* Angular event bus. This is transitional code code and will be
|
||||||
|
* removed.
|
||||||
|
*
|
||||||
|
* Deprecated immediately as this is temporary code
|
||||||
|
*
|
||||||
|
* @deprecated
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function ConductorRepresenter(
|
||||||
|
timeConductor,
|
||||||
|
scope,
|
||||||
|
element
|
||||||
|
) {
|
||||||
|
this.conductor = timeConductor;
|
||||||
|
this.scope = scope;
|
||||||
|
this.element = element;
|
||||||
|
|
||||||
|
this.boundsListener = this.boundsListener.bind(this);
|
||||||
|
this.timeSystemListener = this.timeSystemListener.bind(this);
|
||||||
|
this.followListener = this.followListener.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
ConductorRepresenter.prototype.boundsListener = function (bounds) {
|
||||||
|
this.scope.$broadcast('telemetry:display:bounds', {
|
||||||
|
start: bounds.start,
|
||||||
|
end: bounds.end,
|
||||||
|
domain: this.conductor.timeSystem().metadata.key
|
||||||
|
}, this.conductor.follow());
|
||||||
|
};
|
||||||
|
|
||||||
|
ConductorRepresenter.prototype.timeSystemListener = function (timeSystem) {
|
||||||
|
var bounds = this.conductor.bounds();
|
||||||
|
this.scope.$broadcast('telemetry:display:bounds', {
|
||||||
|
start: bounds.start,
|
||||||
|
end: bounds.end,
|
||||||
|
domain: timeSystem.metadata.key
|
||||||
|
}, this.conductor.follow());
|
||||||
|
};
|
||||||
|
|
||||||
|
ConductorRepresenter.prototype.followListener = function () {
|
||||||
|
this.boundsListener(this.conductor.bounds());
|
||||||
|
};
|
||||||
|
|
||||||
|
// Handle a specific representation of a specific domain object
|
||||||
|
ConductorRepresenter.prototype.represent = function represent(representation) {
|
||||||
|
if (representation.key === 'browse-object') {
|
||||||
|
this.destroy();
|
||||||
|
|
||||||
|
this.conductor.on("bounds", this.boundsListener);
|
||||||
|
this.conductor.on("timeSystem", this.timeSystemListener);
|
||||||
|
this.conductor.on("follow", this.followListener);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ConductorRepresenter.prototype.destroy = function destroy() {
|
||||||
|
this.conductor.off("bounds", this.boundsListener);
|
||||||
|
this.conductor.off("timeSystem", this.timeSystemListener);
|
||||||
|
this.conductor.off("follow", this.followListener);
|
||||||
|
};
|
||||||
|
|
||||||
|
return ConductorRepresenter;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
@ -0,0 +1,72 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT Web includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
define([
|
||||||
|
|
||||||
|
], function (
|
||||||
|
|
||||||
|
) {
|
||||||
|
|
||||||
|
function Conductor(timeConductorService) {
|
||||||
|
this.timeConductor = timeConductorService.conductor();
|
||||||
|
}
|
||||||
|
|
||||||
|
Conductor.prototype.displayStart = function () {
|
||||||
|
return this.timeConductor.bounds().start;
|
||||||
|
};
|
||||||
|
|
||||||
|
Conductor.prototype.displayEnd = function () {
|
||||||
|
return this.timeConductor.bounds().end;
|
||||||
|
};
|
||||||
|
|
||||||
|
Conductor.prototype.domainOptions = function () {
|
||||||
|
throw new Error([
|
||||||
|
'domainOptions not implemented in compatibility layer,',
|
||||||
|
' you must be using some crazy unknown code'
|
||||||
|
].join(''));
|
||||||
|
};
|
||||||
|
|
||||||
|
Conductor.prototype.domain = function () {
|
||||||
|
var system = this.timeConductor.timeSystem();
|
||||||
|
return {
|
||||||
|
key: system.metadata.key,
|
||||||
|
name: system.metadata.name,
|
||||||
|
format: system.formats()[0]
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Small compatibility layer that implements old conductor service by
|
||||||
|
* wrapping new time conductor. This allows views that previously depended
|
||||||
|
* directly on the conductor service to continue to do so without
|
||||||
|
* modification.
|
||||||
|
*/
|
||||||
|
function ConductorService(timeConductor) {
|
||||||
|
this.tc = new Conductor(timeConductor);
|
||||||
|
}
|
||||||
|
|
||||||
|
ConductorService.prototype.getConductor = function () {
|
||||||
|
return this.tc;
|
||||||
|
};
|
||||||
|
|
||||||
|
return ConductorService;
|
||||||
|
});
|
@ -0,0 +1,87 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT Web includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
define(
|
||||||
|
function () {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decorates the `telemetryService` such that requests are
|
||||||
|
* mediated by the time conductor. This is a modified version of the
|
||||||
|
* decorator used in the old TimeConductor that integrates with the
|
||||||
|
* new TimeConductor API.
|
||||||
|
*
|
||||||
|
* @constructor
|
||||||
|
* @memberof platform/features/conductor
|
||||||
|
* @implements {TelemetryService}
|
||||||
|
* @param {platform/features/conductor.TimeConductor} conductor
|
||||||
|
* the service which exposes the global time conductor
|
||||||
|
* @param {TelemetryService} telemetryService the decorated service
|
||||||
|
*/
|
||||||
|
function ConductorTelemetryDecorator(timeConductor, telemetryService) {
|
||||||
|
this.conductor = timeConductor;
|
||||||
|
this.telemetryService = telemetryService;
|
||||||
|
|
||||||
|
this.amendRequests = ConductorTelemetryDecorator.prototype.amendRequests.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
function amendRequest(request, bounds, timeSystem) {
|
||||||
|
request = request || {};
|
||||||
|
request.start = bounds.start;
|
||||||
|
request.end = bounds.end;
|
||||||
|
request.domain = timeSystem.metadata.key;
|
||||||
|
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConductorTelemetryDecorator.prototype.amendRequests = function (requests) {
|
||||||
|
var bounds = this.conductor.bounds(),
|
||||||
|
timeSystem = this.conductor.timeSystem();
|
||||||
|
|
||||||
|
return (requests || []).map(function (request) {
|
||||||
|
return amendRequest(request, bounds, timeSystem);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
ConductorTelemetryDecorator.prototype.requestTelemetry = function (requests) {
|
||||||
|
return this.telemetryService
|
||||||
|
.requestTelemetry(this.amendRequests(requests));
|
||||||
|
};
|
||||||
|
|
||||||
|
ConductorTelemetryDecorator.prototype.subscribe = function (callback, requests) {
|
||||||
|
var unsubscribeFunc = this.telemetryService.subscribe(callback, this.amendRequests(requests)),
|
||||||
|
conductor = this.conductor,
|
||||||
|
self = this;
|
||||||
|
|
||||||
|
function amendRequests() {
|
||||||
|
return self.amendRequests(requests);
|
||||||
|
}
|
||||||
|
|
||||||
|
conductor.on('bounds', amendRequests);
|
||||||
|
return function () {
|
||||||
|
unsubscribeFunc();
|
||||||
|
conductor.off('bounds', amendRequests);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
return ConductorTelemetryDecorator;
|
||||||
|
}
|
||||||
|
);
|
134
platform/features/conductor-v2/conductor/bundle.js
Normal file
134
platform/features/conductor-v2/conductor/bundle.js
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT Web includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
define([
|
||||||
|
"./src/ui/TimeConductorViewService",
|
||||||
|
"./src/ui/TimeConductorController",
|
||||||
|
"./src/TimeConductor",
|
||||||
|
"./src/ui/MctConductorAxis",
|
||||||
|
"./src/ui/NumberFormat",
|
||||||
|
"text!./res/templates/time-conductor.html",
|
||||||
|
"text!./res/templates/mode-selector/mode-selector.html",
|
||||||
|
"text!./res/templates/mode-selector/mode-menu.html",
|
||||||
|
'legacyRegistry'
|
||||||
|
], function (
|
||||||
|
TimeConductorViewService,
|
||||||
|
TimeConductorController,
|
||||||
|
TimeConductor,
|
||||||
|
MCTConductorAxis,
|
||||||
|
NumberFormat,
|
||||||
|
timeConductorTemplate,
|
||||||
|
modeSelectorTemplate,
|
||||||
|
modeMenuTemplate,
|
||||||
|
legacyRegistry
|
||||||
|
) {
|
||||||
|
|
||||||
|
legacyRegistry.register("platform/features/conductor-v2/conductor", {
|
||||||
|
"extensions": {
|
||||||
|
"services": [
|
||||||
|
{
|
||||||
|
"key": "timeConductor",
|
||||||
|
"implementation": TimeConductor
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "timeConductorViewService",
|
||||||
|
"implementation": TimeConductorViewService,
|
||||||
|
"depends": [
|
||||||
|
"timeConductor",
|
||||||
|
"timeSystems[]"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"controllers": [
|
||||||
|
{
|
||||||
|
"key": "TimeConductorController",
|
||||||
|
"implementation": TimeConductorController,
|
||||||
|
"depends": [
|
||||||
|
"$scope",
|
||||||
|
"$window",
|
||||||
|
"timeConductor",
|
||||||
|
"timeConductorViewService",
|
||||||
|
"timeSystems[]"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"directives": [
|
||||||
|
{
|
||||||
|
"key": "mctConductorAxis",
|
||||||
|
"implementation": MCTConductorAxis,
|
||||||
|
"depends": [
|
||||||
|
"timeConductor",
|
||||||
|
"formatService"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stylesheets": [
|
||||||
|
{
|
||||||
|
"stylesheetUrl": "css/time-conductor-espresso.css",
|
||||||
|
"theme": "espresso"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"stylesheetUrl": "css/time-conductor-snow.css",
|
||||||
|
"theme": "snow"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"templates": [
|
||||||
|
{
|
||||||
|
"key": "conductor",
|
||||||
|
"template": timeConductorTemplate
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "mode-menu",
|
||||||
|
"template": modeMenuTemplate
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "mode-selector",
|
||||||
|
"template": modeSelectorTemplate
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"representations": [
|
||||||
|
{
|
||||||
|
"key": "time-conductor",
|
||||||
|
"template": timeConductorTemplate
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"licenses": [
|
||||||
|
{
|
||||||
|
"name": "D3: Data-Driven Documents",
|
||||||
|
"version": "4.1.0",
|
||||||
|
"author": "Mike Bostock",
|
||||||
|
"description": "D3 (or D3.js) is a JavaScript library for visualizing data using web standards. D3 helps you bring data to life using SVG, Canvas and HTML. D3 combines powerful visualization and interaction techniques with a data-driven approach to DOM manipulation, giving you the full capabilities of modern browsers and the freedom to design the right visual interface for your data.",
|
||||||
|
"website": "https://d3js.org/",
|
||||||
|
"copyright": "Copyright 2010-2016 Mike Bostock",
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"link": "https://github.com/d3/d3/blob/master/LICENSE"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"formats": [
|
||||||
|
{
|
||||||
|
"key": "number",
|
||||||
|
"implementation": NumberFormat
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,3 @@
|
|||||||
|
$ueTimeConductorH: (25px, 3px, 20px);
|
||||||
|
$timeCondInputTimeSysDefW: 165px; // Default width for datetime value inputs
|
||||||
|
$timeCondInputDeltaDefW: 60px; // Default width for delta value inputs, typically 00:00:00
|
@ -0,0 +1,431 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2014-2015, 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.
|
||||||
|
*****************************************************************************/
|
||||||
|
@mixin toiLineHovEffects() {
|
||||||
|
&:before,
|
||||||
|
&:after {
|
||||||
|
background-color: $timeControllerToiLineColorHov;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.l-time-conductor-holder {
|
||||||
|
border-top: 1px solid $colorInteriorBorder;
|
||||||
|
min-width: 500px;
|
||||||
|
padding-top: $interiorMargin;
|
||||||
|
}
|
||||||
|
|
||||||
|
.time-conductor-icon {
|
||||||
|
$c: $colorObjHdrIc;
|
||||||
|
$d: 18px;
|
||||||
|
height: $d !important;
|
||||||
|
width: $d;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
@extend .ui-symbol;
|
||||||
|
color: $c;
|
||||||
|
content: $glyph-icon-brackets;
|
||||||
|
font-size: $d;
|
||||||
|
line-height: normal;
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clock hands
|
||||||
|
div[class*="hand"] {
|
||||||
|
$handW: 2px;
|
||||||
|
$handH: $d * 0.4; //8px;
|
||||||
|
@include transform(translate(-50%, -50%));
|
||||||
|
@include animation-iteration-count(infinite);
|
||||||
|
@include animation-timing-function(linear);
|
||||||
|
position: absolute;
|
||||||
|
height: $handW;
|
||||||
|
width: $handW;
|
||||||
|
left: 50%;
|
||||||
|
top: 50%;
|
||||||
|
z-index: 2;
|
||||||
|
&:before {
|
||||||
|
background: $colorObjHdrIc;
|
||||||
|
content: '';
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
bottom: -1px;
|
||||||
|
}
|
||||||
|
&.hand-little {
|
||||||
|
z-index: 2;
|
||||||
|
@include animation-duration(12s);
|
||||||
|
&:before {
|
||||||
|
height: ceil($handH * 0.7);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.hand-big {
|
||||||
|
z-index: 1;
|
||||||
|
@include animation-duration(1s);
|
||||||
|
&:before {
|
||||||
|
height: $handH;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.l-time-conductor {
|
||||||
|
$knobHOffset: 0px;
|
||||||
|
$rangeValPad: $interiorMargin;
|
||||||
|
$rangeValOffset: $sliderKnobW + $interiorMargin;
|
||||||
|
$r1H: nth($ueTimeConductorH, 1);
|
||||||
|
$r2H: nth($ueTimeConductorH, 2);
|
||||||
|
$r3H: nth($ueTimeConductorH, 3);
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
> .l-row-elem {
|
||||||
|
// First order row elements
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: 100%;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mode-selector .s-menu-button,
|
||||||
|
.time-delta {
|
||||||
|
&:before {
|
||||||
|
@extend .ui-symbol;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.time-delta {
|
||||||
|
&:before {
|
||||||
|
color: $colorTimeCondKeyBg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.l-time-conductor-inputs-holder,
|
||||||
|
.l-time-conductor-inputs-and-ticks,
|
||||||
|
.l-time-conductor-zoom-w {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.l-time-conductor-inputs-holder {
|
||||||
|
$ticksBlockerFadeW: 50px;
|
||||||
|
$iconCalendarW: 16px;
|
||||||
|
$wBgColor: $colorBodyBg;
|
||||||
|
|
||||||
|
height: $r1H;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: 1;
|
||||||
|
.l-time-range-w {
|
||||||
|
// Wraps a datetime text input field
|
||||||
|
height: 100%;
|
||||||
|
position: absolute;
|
||||||
|
.title {
|
||||||
|
display: inline-block;
|
||||||
|
margin-right: $interiorMarginSm;
|
||||||
|
}
|
||||||
|
&.start-w {
|
||||||
|
@include background-image(linear-gradient(270deg, transparent, $wBgColor $ticksBlockerFadeW));
|
||||||
|
padding-right: $ticksBlockerFadeW;
|
||||||
|
.title:before {
|
||||||
|
content: 'Start';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.end-w {
|
||||||
|
@include background-image(linear-gradient(90deg, transparent, $wBgColor $ticksBlockerFadeW));
|
||||||
|
padding-left: $ticksBlockerFadeW;
|
||||||
|
right: 0;
|
||||||
|
.title:before {
|
||||||
|
content: 'End';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
input[type="text"] {
|
||||||
|
@include trans-prop-nice(padding, 250ms);
|
||||||
|
}
|
||||||
|
.time-range-input input[type="text"] {
|
||||||
|
width: $timeCondInputTimeSysDefW;
|
||||||
|
}
|
||||||
|
.hrs-min-input input[type="text"] {
|
||||||
|
width: $timeCondInputDeltaDefW;
|
||||||
|
}
|
||||||
|
.icon-calendar {
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.l-time-conductor-inputs-and-ticks {
|
||||||
|
$c: $colorTimeCondTicks; //$colorTick;
|
||||||
|
height: $r1H;
|
||||||
|
mct-conductor-axis {
|
||||||
|
display: block;
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.l-axis-holder {
|
||||||
|
height: $r1H;
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
svg {
|
||||||
|
text-rendering: geometricPrecision;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
> g {
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
path {
|
||||||
|
// Line beneath ticks
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
line {
|
||||||
|
// Tick marks
|
||||||
|
stroke: $c;
|
||||||
|
}
|
||||||
|
text {
|
||||||
|
// Tick labels
|
||||||
|
fill: $c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.l-data-visualization {
|
||||||
|
background: $colorTimeCondDataVisBg;
|
||||||
|
height: $r2H;
|
||||||
|
}
|
||||||
|
|
||||||
|
.l-time-conductor-controls {
|
||||||
|
align-items: center;
|
||||||
|
margin-top: $interiorMargin;
|
||||||
|
.l-time-conductor-zoom-w {
|
||||||
|
@include justify-content(flex-end);
|
||||||
|
.time-conductor-zoom {
|
||||||
|
display: none; // TEMP per request from Andrew 8/1/16
|
||||||
|
height: $r3H;
|
||||||
|
min-width: 100px;
|
||||||
|
width: 20%;
|
||||||
|
}
|
||||||
|
.time-conductor-zoom-current-range {
|
||||||
|
display: none; // TEMP per request from Andrew 8/1/16
|
||||||
|
color: $colorTick;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Real-time, latest modes
|
||||||
|
&.realtime-mode,
|
||||||
|
&.lad-mode {
|
||||||
|
.time-conductor-icon {
|
||||||
|
&:before { color: $colorTimeCondKeyBg; }
|
||||||
|
div[class*="hand"] {
|
||||||
|
@include animation-name(clock-hands);
|
||||||
|
&:before {
|
||||||
|
background: $colorTimeCondKeyBg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.l-time-conductor-inputs-holder {
|
||||||
|
.l-time-range-input-w {
|
||||||
|
input[type="text"]:not(.error) {
|
||||||
|
background: transparent;
|
||||||
|
box-shadow: none;
|
||||||
|
border-radius: 0;
|
||||||
|
padding-left: 0;
|
||||||
|
padding-right: 0;
|
||||||
|
&:hover,
|
||||||
|
&:focus {
|
||||||
|
@include nice-input();
|
||||||
|
padding: $inputTextP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.icon-calendar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
&.start-date {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
&.end-date {
|
||||||
|
pointer-events: none;
|
||||||
|
input[type="text"] {
|
||||||
|
color: pullForward($colorTimeCondKeyBg, 5%);
|
||||||
|
margin-right: $interiorMargin;
|
||||||
|
tab-index: -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.l-data-visualization {
|
||||||
|
background: $colorTimeCondDataVisRtBg !important
|
||||||
|
}
|
||||||
|
|
||||||
|
.mode-selector .s-menu-button {
|
||||||
|
$fg: $colorTimeCondKeyFg;
|
||||||
|
@include btnSubtle($bg: $colorTimeCondKeyBg, $bgHov: pullForward($colorTimeCondKeyBg, $ltGamma), $fg: $colorTimeCondKeyFg);
|
||||||
|
&:before { color: $fg !important; };
|
||||||
|
color: $fg !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fixed mode
|
||||||
|
&.fixed-mode {
|
||||||
|
$i: $glyph-icon-calendar;
|
||||||
|
.time-conductor-icon div[class*="hand"] {
|
||||||
|
&.hand-little {
|
||||||
|
@include transform(rotate(120deg));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.mode-selector .s-menu-button:before {
|
||||||
|
content: $i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Realtime mode
|
||||||
|
&.realtime-mode {
|
||||||
|
$i: $glyph-icon-clock;
|
||||||
|
.time-conductor-icon div[class*="hand"] {
|
||||||
|
@include animation-name(clock-hands);
|
||||||
|
}
|
||||||
|
.time-delta:before {
|
||||||
|
content: $i;
|
||||||
|
}
|
||||||
|
.l-time-conductor-inputs-holder .l-time-range-w.end-w .title:before {
|
||||||
|
content: 'Now';
|
||||||
|
}
|
||||||
|
.mode-selector .s-menu-button:before {
|
||||||
|
content: $i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// LAD mode
|
||||||
|
&.lad-mode {
|
||||||
|
$i: $glyph-icon-database;
|
||||||
|
.time-conductor-icon div[class*="hand"] {
|
||||||
|
@include animation-name(clock-hands-sticky);
|
||||||
|
&.hand-big {
|
||||||
|
@include animation-duration(5s);
|
||||||
|
}
|
||||||
|
&.hand-little {
|
||||||
|
@include animation-duration(60s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.time-delta:before {
|
||||||
|
content: $i;
|
||||||
|
}
|
||||||
|
.l-time-conductor-inputs-holder .l-time-range-w.end-w .title:before {
|
||||||
|
content: 'LAD';
|
||||||
|
}
|
||||||
|
.mode-selector .s-menu-button:before {
|
||||||
|
content: $i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************** MOBILE */
|
||||||
|
|
||||||
|
@include phoneandtablet {
|
||||||
|
.l-time-conductor-holder { min-width: 0 !important; }
|
||||||
|
.super-menu.mini {
|
||||||
|
width: 200px;
|
||||||
|
height: 100px;
|
||||||
|
.pane.menu-item-description {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include phone {
|
||||||
|
.l-time-conductor {
|
||||||
|
min-width: 0;
|
||||||
|
.l-time-conductor-inputs-and-ticks {
|
||||||
|
.l-time-conductor-inputs-holder {
|
||||||
|
.l-time-range-w {
|
||||||
|
background-image: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mct-conductor-axis {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include phonePortrait {
|
||||||
|
.l-time-conductor {
|
||||||
|
.l-data-visualization,
|
||||||
|
.l-time-conductor-zoom-w,
|
||||||
|
.time-delta {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.l-time-conductor-inputs-and-ticks {
|
||||||
|
height: auto !important;
|
||||||
|
.l-time-conductor-inputs-holder {
|
||||||
|
position: relative;
|
||||||
|
height: auto !important;
|
||||||
|
|
||||||
|
.l-time-range-w {
|
||||||
|
background-image: none !important;
|
||||||
|
display: block;
|
||||||
|
height: auto !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
position: relative;
|
||||||
|
text-align: left;
|
||||||
|
&:not(:first-child) {
|
||||||
|
margin-top: $interiorMargin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fixed mode
|
||||||
|
&.fixed-mode {
|
||||||
|
.l-time-conductor-inputs-and-ticks {
|
||||||
|
.l-time-range-w {
|
||||||
|
.title {
|
||||||
|
width: 30px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Real-time, latest modes
|
||||||
|
&.realtime-mode,
|
||||||
|
&.lad-mode {
|
||||||
|
.l-time-conductor-inputs-and-ticks {
|
||||||
|
.l-time-range-w {
|
||||||
|
&.start-w {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
&.end-w {
|
||||||
|
margin-top: 0;
|
||||||
|
.end-date input[type="text"] {
|
||||||
|
margin: 0;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2014-2015, 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.
|
||||||
|
*****************************************************************************/
|
||||||
|
@import "bourbon";
|
||||||
|
@import "../../../../../commonUI/general/res/sass/constants";
|
||||||
|
@import "../../../../../commonUI/general/res/sass/mixins";
|
||||||
|
@import "../../../../../commonUI/general/res/sass/mobile/constants";
|
||||||
|
@import "../../../../../commonUI/general/res/sass/mobile/mixins";
|
||||||
|
@import "../../../../../commonUI/themes/espresso/res/sass/constants";
|
||||||
|
@import "../../../../../commonUI/themes/espresso/res/sass/mixins";
|
||||||
|
@import "../../../../../commonUI/general/res/sass/glyphs";
|
||||||
|
@import "../../../../../commonUI/general/res/sass/icons";
|
||||||
|
@import "constants";
|
||||||
|
|
||||||
|
// Thematic constants
|
||||||
|
$colorTimeCondTicks: pullForward($colorBodyBg, 30%);
|
||||||
|
$colorTimeCondKeyBg: #4e70dc;
|
||||||
|
$colorTimeCondKeyFg: #fff;
|
||||||
|
$colorTimeCondDataVisBg: pullForward($colorBodyBg, 10%);
|
||||||
|
$colorTimeCondDataVisRtBg: pushBack($colorTimeCondKeyBg, 10%);
|
||||||
|
@import "time-conductor-base";
|
@ -0,0 +1,39 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2014-2015, 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.
|
||||||
|
*****************************************************************************/
|
||||||
|
@import "bourbon";
|
||||||
|
@import "../../../../../commonUI/general/res/sass/constants";
|
||||||
|
@import "../../../../../commonUI/general/res/sass/mixins";
|
||||||
|
@import "../../../../../commonUI/general/res/sass/mobile/constants";
|
||||||
|
@import "../../../../../commonUI/general/res/sass/mobile/mixins";
|
||||||
|
@import "../../../../../commonUI/themes/snow/res/sass/constants";
|
||||||
|
@import "../../../../../commonUI/themes/snow/res/sass/mixins";
|
||||||
|
@import "../../../../../commonUI/general/res/sass/glyphs";
|
||||||
|
@import "../../../../../commonUI/general/res/sass/icons";
|
||||||
|
@import "constants";
|
||||||
|
|
||||||
|
// Thematic constants
|
||||||
|
$colorTimeCondTicks: pullForward($colorBodyBg, 30%);
|
||||||
|
$colorTimeCondKeyBg: #6178dc;
|
||||||
|
$colorTimeCondKeyFg: #fff;
|
||||||
|
$colorTimeCondDataVisBg: pullForward($colorBodyBg, 10%);
|
||||||
|
$colorTimeCondDataVisRtBg: pushBack($colorTimeCondKeyBg, 30%);
|
||||||
|
@import "time-conductor-base";
|
@ -0,0 +1,45 @@
|
|||||||
|
<!--
|
||||||
|
Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||||
|
as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
Administration. All rights reserved.
|
||||||
|
|
||||||
|
Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||||
|
"License"); you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
License for the specific language governing permissions and limitations
|
||||||
|
under the License.
|
||||||
|
|
||||||
|
Open MCT Web includes source code licensed under additional open source
|
||||||
|
licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
this source code distribution or the Licensing information page available
|
||||||
|
at runtime from the About dialog for additional information.
|
||||||
|
-->
|
||||||
|
<div class="contents">
|
||||||
|
<div class="pane left menu-items">
|
||||||
|
<ul>
|
||||||
|
<li ng-repeat="(key, metadata) in ngModel.options"
|
||||||
|
ng-click="ngModel.selectedKey=key">
|
||||||
|
<a ng-mouseover="ngModel.activeMetadata = metadata"
|
||||||
|
ng-mouseleave="ngModel.activeMetadata = undefined"
|
||||||
|
class="menu-item-a {{metadata.cssclass}}">
|
||||||
|
{{metadata.name}}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="pane right menu-item-description">
|
||||||
|
<div
|
||||||
|
class="desc-area ui-symbol icon type-icon {{ngModel.activeMetadata.cssclass}}"></div>
|
||||||
|
<div class="desc-area title">
|
||||||
|
{{ngModel.activeMetadata.name}}
|
||||||
|
</div>
|
||||||
|
<div class="desc-area description">
|
||||||
|
{{ngModel.activeMetadata.description}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -0,0 +1,34 @@
|
|||||||
|
<!--
|
||||||
|
Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||||
|
as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
Administration. All rights reserved.
|
||||||
|
|
||||||
|
Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||||
|
"License"); you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
License for the specific language governing permissions and limitations
|
||||||
|
under the License.
|
||||||
|
|
||||||
|
Open MCT Web includes source code licensed under additional open source
|
||||||
|
licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
this source code distribution or the Licensing information page available
|
||||||
|
at runtime from the About dialog for additional information.
|
||||||
|
-->
|
||||||
|
<span ng-controller="ClickAwayController as modeController">
|
||||||
|
<div class="s-menu-button"
|
||||||
|
ng-click="modeController.toggle()">
|
||||||
|
<span class="title-label">{{ngModel.options[ngModel.selectedKey]
|
||||||
|
.label}}</span>
|
||||||
|
</div>
|
||||||
|
<div class="menu super-menu mini mode-selector-menu"
|
||||||
|
ng-show="modeController.isActive()">
|
||||||
|
<mct-include key="'mode-menu'"
|
||||||
|
ng-model="ngModel">
|
||||||
|
</mct-include>
|
||||||
|
</div>
|
||||||
|
</span>
|
@ -0,0 +1,108 @@
|
|||||||
|
<!-- Parent holder for time conductor. follow-mode | fixed-mode -->
|
||||||
|
<div ng-controller="TimeConductorController as tcController"
|
||||||
|
class="holder grows flex-elem l-flex-row l-time-conductor {{modeModel.selectedKey}}-mode {{timeSystemModel.selected.metadata.key}}-time-system">
|
||||||
|
|
||||||
|
<div class="flex-elem holder time-conductor-icon">
|
||||||
|
<div class="hand-little"></div>
|
||||||
|
<div class="hand-big"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex-elem holder grows l-flex-col l-time-conductor-inner">
|
||||||
|
<!-- Holds inputs and ticks -->
|
||||||
|
<div class="l-time-conductor-inputs-and-ticks l-row-elem flex-elem no-margin">
|
||||||
|
<form class="l-time-conductor-inputs-holder"
|
||||||
|
ng-submit="tcController.updateBoundsFromForm(boundsModel)">
|
||||||
|
<span class="l-time-range-w start-w">
|
||||||
|
<span class="l-time-range-input-w start-date">
|
||||||
|
<span class="title"></span>
|
||||||
|
<mct-control key="'datetime-field'"
|
||||||
|
structure="{
|
||||||
|
format: timeSystemModel.format,
|
||||||
|
validate: tcController.validation.validateStart
|
||||||
|
}"
|
||||||
|
ng-model="boundsModel"
|
||||||
|
ng-blur="tcController.updateBoundsFromForm(boundsModel)"
|
||||||
|
field="'start'"
|
||||||
|
class="time-range-input">
|
||||||
|
</mct-control>
|
||||||
|
</span>
|
||||||
|
<span class="l-time-range-input-w time-delta start-delta"
|
||||||
|
ng-class="{'hide':(modeModel.selectedKey === 'fixed')}">
|
||||||
|
-
|
||||||
|
<mct-control key="'datetime-field'"
|
||||||
|
structure="{
|
||||||
|
format: timeSystemModel.deltaFormat,
|
||||||
|
validate: tcController.validation.validateStartDelta
|
||||||
|
}"
|
||||||
|
ng-model="boundsModel"
|
||||||
|
ng-blur="tcController.updateDeltasFromForm(boundsModel)"
|
||||||
|
field="'startDelta'"
|
||||||
|
class="hrs-min-input">
|
||||||
|
</mct-control>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
<span class="l-time-range-w end-w">
|
||||||
|
<span class="l-time-range-input-w end-date"
|
||||||
|
ng-controller="ToggleController as t2">
|
||||||
|
<span class="title"></span>
|
||||||
|
<mct-control key="'datetime-field'"
|
||||||
|
structure="{
|
||||||
|
format: timeSystemModel.format,
|
||||||
|
validate: tcController.validation.validateEnd
|
||||||
|
}"
|
||||||
|
ng-model="boundsModel"
|
||||||
|
ng-blur="tcController.updateBoundsFromForm(boundsModel)"
|
||||||
|
ng-disabled="modeModel.selectedKey !== 'fixed'"
|
||||||
|
field="'end'"
|
||||||
|
class="time-range-input">
|
||||||
|
</mct-control>
|
||||||
|
</span>
|
||||||
|
<span class="l-time-range-input-w time-delta end-delta"
|
||||||
|
ng-class="{'hide':(modeModel.selectedKey === 'fixed')}">
|
||||||
|
+
|
||||||
|
<mct-control key="'datetime-field'"
|
||||||
|
structure="{
|
||||||
|
format: timeSystemModel.deltaFormat,
|
||||||
|
validate: tcController.validation.validateEndDelta
|
||||||
|
}"
|
||||||
|
ng-model="boundsModel"
|
||||||
|
ng-blur="tcController.updateDeltasFromForm(boundsModel)"
|
||||||
|
field="'endDelta'"
|
||||||
|
class="hrs-min-input">
|
||||||
|
</mct-control>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<input type="submit" class="hidden">
|
||||||
|
</form>
|
||||||
|
<mct-conductor-axis></mct-conductor-axis>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Holds data availability, time of interest -->
|
||||||
|
<div class="l-data-visualization l-row-elem flex-elem"></div>
|
||||||
|
|
||||||
|
<!-- Holds time system and session selectors, and zoom control -->
|
||||||
|
<div class="l-time-conductor-controls l-row-elem l-flex-row flex-elem">
|
||||||
|
<mct-include
|
||||||
|
key="'mode-selector'"
|
||||||
|
ng-model="modeModel"
|
||||||
|
class="holder flex-elem menus-up mode-selector">
|
||||||
|
</mct-include>
|
||||||
|
<mct-control
|
||||||
|
key="'menu-button'"
|
||||||
|
class="holder flex-elem menus-up time-system"
|
||||||
|
structure="{
|
||||||
|
text: timeSystemModel.selected.metadata.name,
|
||||||
|
click: tcController.selectTimeSystemByKey,
|
||||||
|
options: timeSystemModel.options
|
||||||
|
}">
|
||||||
|
</mct-control>
|
||||||
|
<!-- Zoom control -->
|
||||||
|
<div class="l-time-conductor-zoom-w grows flex-elem l-flex-row">
|
||||||
|
<span class="time-conductor-zoom-current-range flex-elem flex-fixed holder"></span>
|
||||||
|
<input class="time-conductor-zoom flex-elem" type="range" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
179
platform/features/conductor-v2/conductor/src/TimeConductor.js
Normal file
179
platform/features/conductor-v2/conductor/src/TimeConductor.js
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT Web includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
define(['EventEmitter'], function (EventEmitter) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The public API for setting and querying time conductor state. The
|
||||||
|
* time conductor is the means by which the temporal bounds of a view
|
||||||
|
* are controlled. Time-sensitive views will typically respond to
|
||||||
|
* changes to bounds or other properties of the time conductor and
|
||||||
|
* update the data displayed based on the time conductor state.
|
||||||
|
*
|
||||||
|
* The TimeConductor extends the EventEmitter class. A number of events are
|
||||||
|
* fired when properties of the time conductor change, which are
|
||||||
|
* documented below.
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function TimeConductor() {
|
||||||
|
EventEmitter.call(this);
|
||||||
|
|
||||||
|
//The Time System
|
||||||
|
this.system = undefined;
|
||||||
|
//The Time Of Interest
|
||||||
|
this.toi = undefined;
|
||||||
|
|
||||||
|
this.boundsVal = {
|
||||||
|
start: undefined,
|
||||||
|
end: undefined
|
||||||
|
};
|
||||||
|
|
||||||
|
//Default to fixed mode
|
||||||
|
this.followMode = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
TimeConductor.prototype = Object.create(EventEmitter.prototype);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate the given bounds. This can be used for pre-validation of
|
||||||
|
* bounds, for example by views validating user inputs.
|
||||||
|
* @param bounds The start and end time of the conductor.
|
||||||
|
* @returns {string | true} A validation error, or true if valid
|
||||||
|
*/
|
||||||
|
TimeConductor.prototype.validateBounds = function (bounds) {
|
||||||
|
if ((bounds.start === undefined) ||
|
||||||
|
(bounds.end === undefined) ||
|
||||||
|
isNaN(bounds.start) ||
|
||||||
|
isNaN(bounds.end)
|
||||||
|
) {
|
||||||
|
return "Start and end must be specified as integer values";
|
||||||
|
} else if (bounds.start > bounds.end) {
|
||||||
|
return "Specified start date exceeds end bound";
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get or set the follow mode of the time conductor. In follow mode the
|
||||||
|
* time conductor ticks, regularly updating the bounds from a timing
|
||||||
|
* source appropriate to the selected time system and mode of the time
|
||||||
|
* conductor.
|
||||||
|
* @fires TimeConductor#follow
|
||||||
|
* @param {boolean} followMode
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
TimeConductor.prototype.follow = function (followMode) {
|
||||||
|
if (arguments.length > 0) {
|
||||||
|
this.followMode = followMode;
|
||||||
|
/**
|
||||||
|
* @event TimeConductor#follow The TimeConductor has toggled
|
||||||
|
* into or out of follow mode.
|
||||||
|
* @property {boolean} followMode true if follow mode is
|
||||||
|
* enabled, otherwise false.
|
||||||
|
*/
|
||||||
|
this.emit('follow', this.followMode);
|
||||||
|
}
|
||||||
|
return this.followMode;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} TimeConductorBounds
|
||||||
|
* @property {number} start The start time displayed by the time conductor in ms since epoch. Epoch determined by current time system
|
||||||
|
* @property {number} end The end time displayed by the time conductor in ms since epoch.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* Get or set the start and end time of the time conductor. Basic validation
|
||||||
|
* of bounds is performed.
|
||||||
|
*
|
||||||
|
* @param {TimeConductorBounds} newBounds
|
||||||
|
* @throws {Error} Validation error
|
||||||
|
* @fires TimeConductor#bounds
|
||||||
|
* @returns {TimeConductorBounds}
|
||||||
|
*/
|
||||||
|
TimeConductor.prototype.bounds = function (newBounds) {
|
||||||
|
if (arguments.length > 0) {
|
||||||
|
var validationResult = this.validateBounds(newBounds);
|
||||||
|
if (validationResult !== true) {
|
||||||
|
throw new Error(validationResult);
|
||||||
|
}
|
||||||
|
//Create a copy to avoid direct mutation of conductor bounds
|
||||||
|
this.boundsVal = JSON.parse(JSON.stringify(newBounds));
|
||||||
|
/**
|
||||||
|
* @event TimeConductor#bounds The start time, end time, or
|
||||||
|
* both have been updated
|
||||||
|
* @property {TimeConductorBounds} bounds
|
||||||
|
*/
|
||||||
|
this.emit('bounds', this.boundsVal);
|
||||||
|
}
|
||||||
|
//Return a copy to prevent direct mutation of time conductor bounds.
|
||||||
|
return JSON.parse(JSON.stringify(this.boundsVal));
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get or set the time system of the TimeConductor. Time systems determine
|
||||||
|
* units, epoch, and other aspects of time representation. When changing
|
||||||
|
* the time system in use, new valid bounds must also be provided.
|
||||||
|
* @param {TimeSystem} newTimeSystem
|
||||||
|
* @param {TimeConductorBounds} bounds
|
||||||
|
* @fires TimeConductor#timeSystem
|
||||||
|
* @returns {TimeSystem} The currently applied time system
|
||||||
|
*/
|
||||||
|
TimeConductor.prototype.timeSystem = function (newTimeSystem, bounds) {
|
||||||
|
if (arguments.length >= 2) {
|
||||||
|
this.system = newTimeSystem;
|
||||||
|
/**
|
||||||
|
* @event TimeConductor#timeSystem The time system used by the time
|
||||||
|
* conductor has changed. A change in Time System will always be
|
||||||
|
* followed by a bounds event specifying new query bounds
|
||||||
|
* @property {TimeSystem} The value of the currently applied
|
||||||
|
* Time System
|
||||||
|
* */
|
||||||
|
this.emit('timeSystem', this.system);
|
||||||
|
this.bounds(bounds);
|
||||||
|
} else if (arguments.length === 1) {
|
||||||
|
throw new Error('Must set bounds when changing time system');
|
||||||
|
}
|
||||||
|
return this.system;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get or set the Time of Interest. The Time of Interest is the temporal
|
||||||
|
* focus of the current view. It can be manipulated by the user from the
|
||||||
|
* time conductor or from other views.
|
||||||
|
* @fires TimeConductor#timeOfInterest
|
||||||
|
* @param newTOI
|
||||||
|
* @returns {number} the current time of interest
|
||||||
|
*/
|
||||||
|
TimeConductor.prototype.timeOfInterest = function (newTOI) {
|
||||||
|
if (arguments.length > 0) {
|
||||||
|
this.toi = newTOI;
|
||||||
|
/**
|
||||||
|
* @event TimeConductor#timeOfInterest The Time of Interest has moved.
|
||||||
|
* @property {number} Current time of interest
|
||||||
|
*/
|
||||||
|
this.emit('timeOfInterest', this.toi);
|
||||||
|
}
|
||||||
|
return this.toi;
|
||||||
|
};
|
||||||
|
|
||||||
|
return TimeConductor;
|
||||||
|
});
|
@ -0,0 +1,110 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT Web includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
define(['./TimeConductor'], function (TimeConductor) {
|
||||||
|
describe("The Time Conductor", function () {
|
||||||
|
var tc,
|
||||||
|
timeSystem,
|
||||||
|
bounds,
|
||||||
|
eventListener,
|
||||||
|
toi,
|
||||||
|
follow;
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
tc = new TimeConductor();
|
||||||
|
timeSystem = {};
|
||||||
|
bounds = {start: 0, end: 0};
|
||||||
|
eventListener = jasmine.createSpy("eventListener");
|
||||||
|
toi = 111;
|
||||||
|
follow = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Supports setting and querying of time of interest and and follow mode", function () {
|
||||||
|
expect(tc.timeOfInterest()).not.toBe(toi);
|
||||||
|
tc.timeOfInterest(toi);
|
||||||
|
expect(tc.timeOfInterest()).toBe(toi);
|
||||||
|
|
||||||
|
expect(tc.follow()).not.toBe(follow);
|
||||||
|
tc.follow(follow);
|
||||||
|
expect(tc.follow()).toBe(follow);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Allows setting of valid bounds", function () {
|
||||||
|
bounds = {start: 0, end: 1};
|
||||||
|
expect(tc.bounds()).not.toEqual(bounds);
|
||||||
|
expect(tc.bounds.bind(tc, bounds)).not.toThrow();
|
||||||
|
expect(tc.bounds()).toEqual(bounds);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Disallows setting of invalid bounds", function () {
|
||||||
|
bounds = {start: 1, end: 0};
|
||||||
|
expect(tc.bounds()).not.toEqual(bounds);
|
||||||
|
expect(tc.bounds.bind(tc, bounds)).toThrow();
|
||||||
|
expect(tc.bounds()).not.toEqual(bounds);
|
||||||
|
|
||||||
|
bounds = {start: 1};
|
||||||
|
expect(tc.bounds()).not.toEqual(bounds);
|
||||||
|
expect(tc.bounds.bind(tc, bounds)).toThrow();
|
||||||
|
expect(tc.bounds()).not.toEqual(bounds);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Allows setting of time system with bounds", function () {
|
||||||
|
expect(tc.timeSystem()).not.toBe(timeSystem);
|
||||||
|
expect(tc.timeSystem.bind(tc, timeSystem, bounds)).not.toThrow();
|
||||||
|
expect(tc.timeSystem()).toBe(timeSystem);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Disallows setting of time system without bounds", function () {
|
||||||
|
expect(tc.timeSystem()).not.toBe(timeSystem);
|
||||||
|
expect(tc.timeSystem.bind(tc, timeSystem)).toThrow();
|
||||||
|
expect(tc.timeSystem()).not.toBe(timeSystem);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Emits an event when time system changes", function () {
|
||||||
|
expect(eventListener).not.toHaveBeenCalled();
|
||||||
|
tc.on("timeSystem", eventListener);
|
||||||
|
tc.timeSystem(timeSystem, bounds);
|
||||||
|
expect(eventListener).toHaveBeenCalledWith(timeSystem);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Emits an event when time of interest changes", function () {
|
||||||
|
expect(eventListener).not.toHaveBeenCalled();
|
||||||
|
tc.on("timeOfInterest", eventListener);
|
||||||
|
tc.timeOfInterest(toi);
|
||||||
|
expect(eventListener).toHaveBeenCalledWith(toi);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Emits an event when bounds change", function () {
|
||||||
|
expect(eventListener).not.toHaveBeenCalled();
|
||||||
|
tc.on("bounds", eventListener);
|
||||||
|
tc.bounds(bounds);
|
||||||
|
expect(eventListener).toHaveBeenCalledWith(bounds);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Emits an event when follow mode changes", function () {
|
||||||
|
expect(eventListener).not.toHaveBeenCalled();
|
||||||
|
tc.on("follow", eventListener);
|
||||||
|
tc.follow(follow);
|
||||||
|
expect(eventListener).toHaveBeenCalledWith(follow);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,89 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT Web includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
define(['./TickSource'], function (TickSource) {
|
||||||
|
/**
|
||||||
|
* @implements TickSource
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function LocalClock($timeout, period) {
|
||||||
|
TickSource.call(this);
|
||||||
|
|
||||||
|
this.metadata = {
|
||||||
|
key: 'local',
|
||||||
|
mode: 'realtime',
|
||||||
|
cssclass: 'icon-clock',
|
||||||
|
label: 'Real-time',
|
||||||
|
name: 'Real-time Mode',
|
||||||
|
description: 'Monitor real-time streaming data as it comes in. The Time Conductor and displays will automatically advance themselves based on a UTC clock.'
|
||||||
|
};
|
||||||
|
|
||||||
|
this.period = period;
|
||||||
|
this.$timeout = $timeout;
|
||||||
|
this.timeoutHandle = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalClock.prototype = Object.create(TickSource.prototype);
|
||||||
|
|
||||||
|
LocalClock.prototype.start = function () {
|
||||||
|
this.timeoutHandle = this.$timeout(this.tick.bind(this), this.period);
|
||||||
|
};
|
||||||
|
|
||||||
|
LocalClock.prototype.stop = function () {
|
||||||
|
if (this.timeoutHandle) {
|
||||||
|
this.$timeout.cancel(this.timeoutHandle);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
LocalClock.prototype.tick = function () {
|
||||||
|
var now = Date.now();
|
||||||
|
this.listeners.forEach(function (listener) {
|
||||||
|
listener(now);
|
||||||
|
});
|
||||||
|
this.timeoutHandle = this.$timeout(this.tick.bind(this), this.period);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a listener for the local clock. When it ticks, the local
|
||||||
|
* clock will provide the current local system time
|
||||||
|
*
|
||||||
|
* @param listener
|
||||||
|
* @returns {function} a function for deregistering the provided listener
|
||||||
|
*/
|
||||||
|
LocalClock.prototype.listen = function (listener) {
|
||||||
|
var listeners = this.listeners;
|
||||||
|
listeners.push(listener);
|
||||||
|
|
||||||
|
if (listeners.length === 1) {
|
||||||
|
this.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
return function () {
|
||||||
|
listeners.splice(listeners.indexOf(listener));
|
||||||
|
if (listeners.length === 0) {
|
||||||
|
this.stop();
|
||||||
|
}
|
||||||
|
}.bind(this);
|
||||||
|
};
|
||||||
|
|
||||||
|
return LocalClock;
|
||||||
|
});
|
@ -0,0 +1,50 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT Web includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
define(["./LocalClock"], function (LocalClock) {
|
||||||
|
describe("The LocalClock class", function () {
|
||||||
|
var clock,
|
||||||
|
mockTimeout,
|
||||||
|
timeoutHandle = {};
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
mockTimeout = jasmine.createSpy("timeout");
|
||||||
|
mockTimeout.andReturn(timeoutHandle);
|
||||||
|
mockTimeout.cancel = jasmine.createSpy("cancel");
|
||||||
|
|
||||||
|
clock = new LocalClock(mockTimeout, 0);
|
||||||
|
clock.start();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("calls listeners on tick with current time", function () {
|
||||||
|
var mockListener = jasmine.createSpy("listener");
|
||||||
|
clock.listen(mockListener);
|
||||||
|
clock.tick();
|
||||||
|
expect(mockListener).toHaveBeenCalledWith(jasmine.any(Number));
|
||||||
|
});
|
||||||
|
|
||||||
|
it("stops ticking when stop is called", function () {
|
||||||
|
clock.stop();
|
||||||
|
expect(mockTimeout.cancel).toHaveBeenCalledWith(timeoutHandle);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,47 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT Web includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
define([], function () {
|
||||||
|
/**
|
||||||
|
* A tick source is an event generator such as a timing signal, or
|
||||||
|
* indicator of data availability, which can be used to advance the Time
|
||||||
|
* Conductor. Usage is simple, a listener registers a callback which is
|
||||||
|
* invoked when this source 'ticks'.
|
||||||
|
*
|
||||||
|
* @interface
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function TickSource() {
|
||||||
|
this.listeners = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param callback Function to be called when this tick source ticks.
|
||||||
|
* @returns an 'unlisten' function that will remove the callback from
|
||||||
|
* the registered listeners
|
||||||
|
*/
|
||||||
|
TickSource.prototype.listen = function (callback) {
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
};
|
||||||
|
|
||||||
|
return TickSource;
|
||||||
|
});
|
@ -0,0 +1,93 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT Web includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
define([], function () {
|
||||||
|
/**
|
||||||
|
* @interface
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function TimeSystem() {
|
||||||
|
/**
|
||||||
|
* @typedef TimeSystemMetadata
|
||||||
|
* @property {string} key
|
||||||
|
* @property {string} name
|
||||||
|
* @property {string} description
|
||||||
|
*
|
||||||
|
* @type {TimeSystemMetadata}
|
||||||
|
*/
|
||||||
|
this.metadata = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Time formats are defined as extensions. Time systems that implement
|
||||||
|
* this interface should provide an array of format keys supported by them.
|
||||||
|
*
|
||||||
|
* @returns {string[]} An array of time format keys
|
||||||
|
*/
|
||||||
|
TimeSystem.prototype.formats = function () {
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef DeltaFormat
|
||||||
|
* @property {string} type the type of MctControl used to represent this
|
||||||
|
* field. Typically 'datetime-field' for UTC based dates, or 'textfield'
|
||||||
|
* otherwise
|
||||||
|
* @property {string} [format] An optional field specifying the
|
||||||
|
* Format to use for delta fields in this time system.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* Specifies a format for deltas in this time system.
|
||||||
|
*
|
||||||
|
* @returns {DeltaFormat} a delta format specifier
|
||||||
|
*/
|
||||||
|
TimeSystem.prototype.deltaFormat = function () {
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the tick sources supported by this time system. Tick sources
|
||||||
|
* are event generators that can be used to advance the time conductor
|
||||||
|
* @returns {TickSource[]} The tick sources supported by this time system.
|
||||||
|
*/
|
||||||
|
TimeSystem.prototype.tickSources = function () {
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @returns {TimeSystemDefault[]} At least one set of default values for
|
||||||
|
* this time system.
|
||||||
|
*/
|
||||||
|
TimeSystem.prototype.defaults = function () {
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {boolean}
|
||||||
|
*/
|
||||||
|
TimeSystem.prototype.isUTCBased = function () {
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
return TimeSystem;
|
||||||
|
});
|
@ -0,0 +1,146 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT Web includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
define(
|
||||||
|
[
|
||||||
|
"d3"
|
||||||
|
],
|
||||||
|
function (d3) {
|
||||||
|
var PADDING = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The mct-conductor-axis renders a horizontal axis with regular
|
||||||
|
* labelled 'ticks'. It requires 'start' and 'end' integer values to
|
||||||
|
* be specified as attributes.
|
||||||
|
*/
|
||||||
|
function MCTConductorAxis(conductor, formatService) {
|
||||||
|
// Dependencies
|
||||||
|
this.d3 = d3;
|
||||||
|
this.conductor = conductor;
|
||||||
|
this.formatService = formatService;
|
||||||
|
|
||||||
|
// Runtime properties (set by 'link' function)
|
||||||
|
this.target = undefined;
|
||||||
|
this.xScale = undefined;
|
||||||
|
this.xAxis = undefined;
|
||||||
|
this.axisElement = undefined;
|
||||||
|
|
||||||
|
// Angular Directive interface
|
||||||
|
this.link = this.link.bind(this);
|
||||||
|
this.restrict = "E";
|
||||||
|
this.template =
|
||||||
|
"<div class=\"l-axis-holder\" mct-resize=\"resize()\"></div>";
|
||||||
|
this.priority = 1000;
|
||||||
|
|
||||||
|
//Bind all class functions to 'this'
|
||||||
|
Object.keys(MCTConductorAxis.prototype).filter(function (key) {
|
||||||
|
return typeof MCTConductorAxis.prototype[key] === 'function';
|
||||||
|
}).forEach(function (key) {
|
||||||
|
this[key] = this[key].bind(this);
|
||||||
|
}.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
MCTConductorAxis.prototype.setScale = function () {
|
||||||
|
var width = this.target.offsetWidth;
|
||||||
|
var timeSystem = this.conductor.timeSystem();
|
||||||
|
var bounds = this.conductor.bounds();
|
||||||
|
|
||||||
|
if (timeSystem.isUTCBased()) {
|
||||||
|
this.xScale = this.xScale || this.d3.scaleUtc();
|
||||||
|
this.xScale.domain([new Date(bounds.start), new Date(bounds.end)]);
|
||||||
|
} else {
|
||||||
|
this.xScale = this.xScale || this.d3.scaleLinear();
|
||||||
|
this.xScale.domain([bounds.start, bounds.end]);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.xScale.range([PADDING, width - PADDING * 2]);
|
||||||
|
this.axisElement.call(this.xAxis);
|
||||||
|
};
|
||||||
|
|
||||||
|
MCTConductorAxis.prototype.changeTimeSystem = function (timeSystem) {
|
||||||
|
var key = timeSystem.formats()[0];
|
||||||
|
if (key !== undefined) {
|
||||||
|
var format = this.formatService.getFormat(key);
|
||||||
|
var bounds = this.conductor.bounds();
|
||||||
|
|
||||||
|
if (timeSystem.isUTCBased()) {
|
||||||
|
this.xScale = this.d3.scaleUtc();
|
||||||
|
} else {
|
||||||
|
this.xScale = this.d3.scaleLinear();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.xAxis.scale(this.xScale);
|
||||||
|
//Define a custom format function
|
||||||
|
this.xAxis.tickFormat(function (tickValue) {
|
||||||
|
// Normalize date representations to numbers
|
||||||
|
if (tickValue instanceof Date) {
|
||||||
|
tickValue = tickValue.getTime();
|
||||||
|
}
|
||||||
|
return format.format(tickValue, {
|
||||||
|
min: bounds.start,
|
||||||
|
max: bounds.end
|
||||||
|
});
|
||||||
|
});
|
||||||
|
this.axisElement.call(this.xAxis);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
MCTConductorAxis.prototype.destroy = function () {
|
||||||
|
this.conductor.off('timeSystem', this.changeTimeSystem);
|
||||||
|
this.conductor.off('bounds', this.setScale);
|
||||||
|
};
|
||||||
|
|
||||||
|
MCTConductorAxis.prototype.link = function (scope, element) {
|
||||||
|
var conductor = this.conductor;
|
||||||
|
this.target = element[0].firstChild;
|
||||||
|
var height = this.target.offsetHeight;
|
||||||
|
var vis = this.d3.select(this.target)
|
||||||
|
.append('svg:svg')
|
||||||
|
.attr('width', '100%')
|
||||||
|
.attr('height', height);
|
||||||
|
|
||||||
|
this.xAxis = this.d3.axisTop();
|
||||||
|
|
||||||
|
// draw x axis with labels and move to the bottom of the chart area
|
||||||
|
this.axisElement = vis.append("g")
|
||||||
|
.attr("transform", "translate(0," + (height - PADDING) + ")");
|
||||||
|
|
||||||
|
scope.resize = this.setScale;
|
||||||
|
|
||||||
|
conductor.on('timeSystem', this.changeTimeSystem);
|
||||||
|
|
||||||
|
//On conductor bounds changes, redraw ticks
|
||||||
|
conductor.on('bounds', this.setScale);
|
||||||
|
|
||||||
|
scope.$on("$destroy", this.destroy);
|
||||||
|
|
||||||
|
if (conductor.timeSystem() !== undefined) {
|
||||||
|
this.changeTimeSystem(conductor.timeSystem());
|
||||||
|
this.setScale();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return function (conductor, formatService) {
|
||||||
|
return new MCTConductorAxis(conductor, formatService);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
@ -0,0 +1,146 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT Web includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
define(['./MctConductorAxis'], function (MctConductorAxis) {
|
||||||
|
describe("The MctConductorAxis directive", function () {
|
||||||
|
var directive,
|
||||||
|
mockConductor,
|
||||||
|
mockFormatService,
|
||||||
|
mockScope,
|
||||||
|
mockElement,
|
||||||
|
mockTarget,
|
||||||
|
mockBounds,
|
||||||
|
d3;
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
mockScope = jasmine.createSpyObj("scope", [
|
||||||
|
"$on"
|
||||||
|
]);
|
||||||
|
|
||||||
|
//Add some HTML elements
|
||||||
|
mockTarget = {
|
||||||
|
offsetWidth: 0,
|
||||||
|
offsetHeight: 0
|
||||||
|
};
|
||||||
|
mockElement = {
|
||||||
|
firstChild: mockTarget
|
||||||
|
};
|
||||||
|
mockBounds = {
|
||||||
|
start: 100,
|
||||||
|
end: 200
|
||||||
|
};
|
||||||
|
mockConductor = jasmine.createSpyObj("conductor", [
|
||||||
|
"timeSystem",
|
||||||
|
"bounds",
|
||||||
|
"on",
|
||||||
|
"off"
|
||||||
|
]);
|
||||||
|
mockConductor.bounds.andReturn(mockBounds);
|
||||||
|
|
||||||
|
mockFormatService = jasmine.createSpyObj("formatService", [
|
||||||
|
"getFormat"
|
||||||
|
]);
|
||||||
|
|
||||||
|
var d3Functions = [
|
||||||
|
"scale",
|
||||||
|
"scaleUtc",
|
||||||
|
"scaleLinear",
|
||||||
|
"select",
|
||||||
|
"append",
|
||||||
|
"attr",
|
||||||
|
"axisTop",
|
||||||
|
"call",
|
||||||
|
"tickFormat",
|
||||||
|
"domain",
|
||||||
|
"range"
|
||||||
|
];
|
||||||
|
d3 = jasmine.createSpyObj("d3", d3Functions);
|
||||||
|
d3Functions.forEach(function (func) {
|
||||||
|
d3[func].andReturn(d3);
|
||||||
|
});
|
||||||
|
|
||||||
|
directive = new MctConductorAxis(mockConductor, mockFormatService);
|
||||||
|
directive.d3 = d3;
|
||||||
|
directive.link(mockScope, [mockElement]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("listens for changes to time system and bounds", function () {
|
||||||
|
expect(mockConductor.on).toHaveBeenCalledWith("timeSystem", directive.changeTimeSystem);
|
||||||
|
expect(mockConductor.on).toHaveBeenCalledWith("bounds", directive.setScale);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("on scope destruction, deregisters listeners", function () {
|
||||||
|
expect(mockScope.$on).toHaveBeenCalledWith("$destroy", directive.destroy);
|
||||||
|
directive.destroy();
|
||||||
|
expect(mockConductor.off).toHaveBeenCalledWith("timeSystem", directive.changeTimeSystem);
|
||||||
|
expect(mockConductor.off).toHaveBeenCalledWith("bounds", directive.setScale);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("when the time system changes", function () {
|
||||||
|
var mockTimeSystem;
|
||||||
|
var mockFormat;
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
mockTimeSystem = jasmine.createSpyObj("timeSystem", [
|
||||||
|
"formats",
|
||||||
|
"isUTCBased"
|
||||||
|
]);
|
||||||
|
mockFormat = jasmine.createSpyObj("format", [
|
||||||
|
"format"
|
||||||
|
]);
|
||||||
|
|
||||||
|
mockTimeSystem.formats.andReturn(["mockFormat"]);
|
||||||
|
mockFormatService.getFormat.andReturn(mockFormat);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("uses a UTC scale for UTC time systems", function () {
|
||||||
|
mockTimeSystem.isUTCBased.andReturn(true);
|
||||||
|
directive.changeTimeSystem(mockTimeSystem);
|
||||||
|
expect(d3.scaleUtc).toHaveBeenCalled();
|
||||||
|
expect(d3.scaleLinear).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("uses a linear scale for non-UTC time systems", function () {
|
||||||
|
mockTimeSystem.isUTCBased.andReturn(false);
|
||||||
|
directive.changeTimeSystem(mockTimeSystem);
|
||||||
|
expect(d3.scaleLinear).toHaveBeenCalled();
|
||||||
|
expect(d3.scaleUtc).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("sets axis domain to time conductor bounds", function () {
|
||||||
|
mockTimeSystem.isUTCBased.andReturn(false);
|
||||||
|
mockConductor.timeSystem.andReturn(mockTimeSystem);
|
||||||
|
|
||||||
|
directive.setScale();
|
||||||
|
expect(d3.domain).toHaveBeenCalledWith([mockBounds.start, mockBounds.end]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("uses the format specified by the time system to format tick" +
|
||||||
|
" labels", function () {
|
||||||
|
directive.changeTimeSystem(mockTimeSystem);
|
||||||
|
expect(d3.tickFormat).toHaveBeenCalled();
|
||||||
|
d3.tickFormat.mostRecentCall.args[0]();
|
||||||
|
expect(mockFormat.format).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,53 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2014-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 () {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formatter for basic numbers. Provides basic support for non-UTC
|
||||||
|
* numbering systems
|
||||||
|
*
|
||||||
|
* @implements {Format}
|
||||||
|
* @constructor
|
||||||
|
* @memberof platform/commonUI/formats
|
||||||
|
*/
|
||||||
|
function NumberFormat() {
|
||||||
|
}
|
||||||
|
|
||||||
|
NumberFormat.prototype.format = function (value) {
|
||||||
|
if (isNaN(value)) {
|
||||||
|
return '';
|
||||||
|
} else {
|
||||||
|
return '' + value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
NumberFormat.prototype.parse = function (text) {
|
||||||
|
return parseFloat(text);
|
||||||
|
};
|
||||||
|
|
||||||
|
NumberFormat.prototype.validate = function (text) {
|
||||||
|
return !isNaN(text);
|
||||||
|
};
|
||||||
|
|
||||||
|
return NumberFormat;
|
||||||
|
});
|
@ -0,0 +1,49 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT Web includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
define(['./NumberFormat'], function (NumberFormat) {
|
||||||
|
describe("The NumberFormat class", function () {
|
||||||
|
var format;
|
||||||
|
beforeEach(function () {
|
||||||
|
format = new NumberFormat();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("The format function takes a string and produces a number", function () {
|
||||||
|
var text = format.format(1);
|
||||||
|
expect(text).toBe("1");
|
||||||
|
expect(typeof text).toBe("string");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("The parse function takes a string and produces a number", function () {
|
||||||
|
var number = format.parse("1");
|
||||||
|
expect(number).toBe(1);
|
||||||
|
expect(typeof number).toBe("number");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("validates that the input is a number", function () {
|
||||||
|
expect(format.validate("1")).toBe(true);
|
||||||
|
expect(format.validate(1)).toBe(true);
|
||||||
|
expect(format.validate("1.1")).toBe(true);
|
||||||
|
expect(format.validate("abc")).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,243 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT Web includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
define(
|
||||||
|
[
|
||||||
|
'./TimeConductorValidation'
|
||||||
|
],
|
||||||
|
function (TimeConductorValidation) {
|
||||||
|
|
||||||
|
function TimeConductorController($scope, $window, timeConductor, conductorViewService, timeSystems) {
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
//Bind all class functions to 'this'
|
||||||
|
Object.keys(TimeConductorController.prototype).filter(function (key) {
|
||||||
|
return typeof TimeConductorController.prototype[key] === 'function';
|
||||||
|
}).forEach(function (key) {
|
||||||
|
self[key] = self[key].bind(self);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.$scope = $scope;
|
||||||
|
this.$window = $window;
|
||||||
|
this.conductorViewService = conductorViewService;
|
||||||
|
this.conductor = timeConductor;
|
||||||
|
this.modes = conductorViewService.availableModes();
|
||||||
|
this.validation = new TimeConductorValidation(this.conductor);
|
||||||
|
|
||||||
|
// Construct the provided time system definitions
|
||||||
|
this.timeSystems = timeSystems.map(function (timeSystemConstructor) {
|
||||||
|
return timeSystemConstructor();
|
||||||
|
});
|
||||||
|
|
||||||
|
//Set the initial state of the view based on current time conductor
|
||||||
|
this.initializeScope();
|
||||||
|
|
||||||
|
this.conductor.on('bounds', this.setFormFromBounds);
|
||||||
|
this.conductor.on('timeSystem', this.changeTimeSystem);
|
||||||
|
|
||||||
|
// If no mode selected, select fixed as the default
|
||||||
|
if (!this.conductorViewService.mode()) {
|
||||||
|
this.setMode('fixed');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
TimeConductorController.prototype.initializeScope = function () {
|
||||||
|
//Set time Conductor bounds in the form
|
||||||
|
this.$scope.boundsModel = this.conductor.bounds();
|
||||||
|
|
||||||
|
//If conductor has a time system selected already, populate the
|
||||||
|
//form from it
|
||||||
|
this.$scope.timeSystemModel = {};
|
||||||
|
if (this.conductor.timeSystem()) {
|
||||||
|
this.setFormFromTimeSystem(this.conductor.timeSystem());
|
||||||
|
}
|
||||||
|
|
||||||
|
//Represents the various modes, and the currently selected mode
|
||||||
|
//in the view
|
||||||
|
this.$scope.modeModel = {
|
||||||
|
options: this.conductorViewService.availableModes()
|
||||||
|
};
|
||||||
|
|
||||||
|
var mode = this.conductorViewService.mode();
|
||||||
|
if (mode) {
|
||||||
|
//If view already defines a mode (eg. controller is being
|
||||||
|
// initialized after navigation), then pre-populate form.
|
||||||
|
this.setFormFromMode(mode);
|
||||||
|
var deltas = this.conductorViewService.deltas();
|
||||||
|
if (deltas) {
|
||||||
|
this.setFormFromDeltas(deltas);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setFormFromBounds(this.conductor.bounds());
|
||||||
|
|
||||||
|
// Watch scope for selection of mode or time system by user
|
||||||
|
this.$scope.$watch('modeModel.selectedKey', this.setMode);
|
||||||
|
|
||||||
|
this.$scope.$on('$destroy', this.destroy);
|
||||||
|
};
|
||||||
|
|
||||||
|
TimeConductorController.prototype.destroy = function () {
|
||||||
|
this.conductor.off('bounds', this.setFormFromBounds);
|
||||||
|
this.conductor.off('timeSystem', this.changeTimeSystem);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the bounds change in the time conductor. Synchronizes
|
||||||
|
* the bounds values in the time conductor with those in the form
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
TimeConductorController.prototype.setFormFromBounds = function (bounds) {
|
||||||
|
this.$scope.boundsModel.start = bounds.start;
|
||||||
|
this.$scope.boundsModel.end = bounds.end;
|
||||||
|
if (!this.pendingUpdate) {
|
||||||
|
this.pendingUpdate = true;
|
||||||
|
this.$window.requestAnimationFrame(function () {
|
||||||
|
this.pendingUpdate = false;
|
||||||
|
this.$scope.$digest();
|
||||||
|
}.bind(this));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
TimeConductorController.prototype.setFormFromMode = function (mode) {
|
||||||
|
this.$scope.modeModel.selectedKey = mode;
|
||||||
|
//Synchronize scope with time system on mode
|
||||||
|
this.$scope.timeSystemModel.options =
|
||||||
|
this.conductorViewService.availableTimeSystems()
|
||||||
|
.map(function (t) {
|
||||||
|
return t.metadata;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
TimeConductorController.prototype.setFormFromDeltas = function (deltas) {
|
||||||
|
this.$scope.boundsModel.startDelta = deltas.start;
|
||||||
|
this.$scope.boundsModel.endDelta = deltas.end;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
TimeConductorController.prototype.setFormFromTimeSystem = function (timeSystem) {
|
||||||
|
this.$scope.timeSystemModel.selected = timeSystem;
|
||||||
|
this.$scope.timeSystemModel.format = timeSystem.formats()[0];
|
||||||
|
this.$scope.timeSystemModel.deltaFormat = timeSystem.deltaFormat();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when form values are changed. Synchronizes the form with
|
||||||
|
* the time conductor
|
||||||
|
* @param formModel
|
||||||
|
*/
|
||||||
|
TimeConductorController.prototype.updateBoundsFromForm = function (boundsModel) {
|
||||||
|
this.conductor.bounds({
|
||||||
|
start: boundsModel.start,
|
||||||
|
end: boundsModel.end
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the delta values in the form change. Validates and
|
||||||
|
* sets the new deltas on the Mode.
|
||||||
|
* @param boundsModel
|
||||||
|
* @see TimeConductorMode
|
||||||
|
*/
|
||||||
|
TimeConductorController.prototype.updateDeltasFromForm = function (boundsFormModel) {
|
||||||
|
var deltas = {
|
||||||
|
start: boundsFormModel.startDelta,
|
||||||
|
end: boundsFormModel.endDelta
|
||||||
|
};
|
||||||
|
if (this.validation.validateStartDelta(deltas.start) && this.validation.validateEndDelta(deltas.end)) {
|
||||||
|
//Sychronize deltas between form and mode
|
||||||
|
this.conductorViewService.deltas(deltas);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Change the selected Time Conductor mode. This will call destroy
|
||||||
|
* and initialization functions on the relevant modes, setting
|
||||||
|
* default values for bound and deltas in the form.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param newModeKey
|
||||||
|
* @param oldModeKey
|
||||||
|
*/
|
||||||
|
TimeConductorController.prototype.setMode = function (newModeKey, oldModeKey) {
|
||||||
|
if (newModeKey !== oldModeKey) {
|
||||||
|
this.conductorViewService.mode(newModeKey);
|
||||||
|
this.setFormFromMode(newModeKey);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Respond to time system selection from UI
|
||||||
|
*
|
||||||
|
* Allows time system to be changed by key. This supports selection
|
||||||
|
* from the menu. Resolves a TimeSystem object and then invokes
|
||||||
|
* TimeConductorController#setTimeSystem
|
||||||
|
* @param key
|
||||||
|
* @see TimeConductorController#setTimeSystem
|
||||||
|
*/
|
||||||
|
TimeConductorController.prototype.selectTimeSystemByKey = function (key) {
|
||||||
|
var selected = this.timeSystems.filter(function (timeSystem) {
|
||||||
|
return timeSystem.metadata.key === key;
|
||||||
|
})[0];
|
||||||
|
this.conductor.timeSystem(selected, selected.defaults().bounds);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles time system change from time conductor
|
||||||
|
*
|
||||||
|
* Sets the selected time system. Will populate form with the default
|
||||||
|
* bounds and deltas defined in the selected time system.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param newTimeSystem
|
||||||
|
*/
|
||||||
|
TimeConductorController.prototype.changeTimeSystem = function (newTimeSystem) {
|
||||||
|
if (newTimeSystem && (newTimeSystem !== this.$scope.timeSystemModel.selected)) {
|
||||||
|
if (newTimeSystem.defaults()) {
|
||||||
|
var deltas = newTimeSystem.defaults().deltas || {start: 0, end: 0};
|
||||||
|
var bounds = newTimeSystem.defaults().bounds || {start: 0, end: 0};
|
||||||
|
|
||||||
|
this.setFormFromDeltas(deltas);
|
||||||
|
this.setFormFromBounds(bounds);
|
||||||
|
}
|
||||||
|
this.setFormFromTimeSystem(newTimeSystem);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return TimeConductorController;
|
||||||
|
}
|
||||||
|
);
|
@ -0,0 +1,335 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT Web includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
define(['./TimeConductorController'], function (TimeConductorController) {
|
||||||
|
describe("The time conductor controller", function () {
|
||||||
|
var mockScope;
|
||||||
|
var mockWindow;
|
||||||
|
var mockTimeConductor;
|
||||||
|
var mockConductorViewService;
|
||||||
|
var mockTimeSystems;
|
||||||
|
var controller;
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
mockScope = jasmine.createSpyObj("$scope", [
|
||||||
|
"$watch",
|
||||||
|
"$on"
|
||||||
|
]);
|
||||||
|
mockWindow = jasmine.createSpyObj("$window", ["requestAnimationFrame"]);
|
||||||
|
mockTimeConductor = jasmine.createSpyObj(
|
||||||
|
"TimeConductor",
|
||||||
|
[
|
||||||
|
"bounds",
|
||||||
|
"timeSystem",
|
||||||
|
"on",
|
||||||
|
"off"
|
||||||
|
]
|
||||||
|
);
|
||||||
|
mockTimeConductor.bounds.andReturn({start: undefined, end: undefined});
|
||||||
|
|
||||||
|
mockConductorViewService = jasmine.createSpyObj(
|
||||||
|
"ConductorViewService",
|
||||||
|
[
|
||||||
|
"availableModes",
|
||||||
|
"mode",
|
||||||
|
"availableTimeSystems",
|
||||||
|
"deltas"
|
||||||
|
]
|
||||||
|
);
|
||||||
|
mockConductorViewService.availableModes.andReturn([]);
|
||||||
|
mockConductorViewService.availableTimeSystems.andReturn([]);
|
||||||
|
|
||||||
|
mockTimeSystems = [];
|
||||||
|
});
|
||||||
|
|
||||||
|
function getListener(name) {
|
||||||
|
return mockTimeConductor.on.calls.filter(function (call) {
|
||||||
|
return call.args[0] === name;
|
||||||
|
})[0].args[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("", function () {
|
||||||
|
beforeEach(function () {
|
||||||
|
controller = new TimeConductorController(
|
||||||
|
mockScope,
|
||||||
|
mockWindow,
|
||||||
|
mockTimeConductor,
|
||||||
|
mockConductorViewService,
|
||||||
|
mockTimeSystems
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("when time conductor state changes", function () {
|
||||||
|
var mockFormat;
|
||||||
|
var mockDeltaFormat;
|
||||||
|
var defaultBounds;
|
||||||
|
var defaultDeltas;
|
||||||
|
var mockDefaults;
|
||||||
|
var timeSystem;
|
||||||
|
var tsListener;
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
mockFormat = {};
|
||||||
|
mockDeltaFormat = {};
|
||||||
|
defaultBounds = {
|
||||||
|
start: 2,
|
||||||
|
end: 3
|
||||||
|
};
|
||||||
|
defaultDeltas = {
|
||||||
|
start: 10,
|
||||||
|
end: 20
|
||||||
|
};
|
||||||
|
mockDefaults = {
|
||||||
|
deltas: defaultDeltas,
|
||||||
|
bounds: defaultBounds
|
||||||
|
};
|
||||||
|
timeSystem = {
|
||||||
|
formats: function () {
|
||||||
|
return [mockFormat];
|
||||||
|
},
|
||||||
|
deltaFormat: function () {
|
||||||
|
return mockDeltaFormat;
|
||||||
|
},
|
||||||
|
defaults: function () {
|
||||||
|
return mockDefaults;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
controller = new TimeConductorController(
|
||||||
|
mockScope,
|
||||||
|
mockWindow,
|
||||||
|
mockTimeConductor,
|
||||||
|
mockConductorViewService,
|
||||||
|
mockTimeSystems
|
||||||
|
);
|
||||||
|
|
||||||
|
tsListener = getListener("timeSystem");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("listens for changes to conductor state", function () {
|
||||||
|
expect(mockTimeConductor.on).toHaveBeenCalledWith("timeSystem", controller.changeTimeSystem);
|
||||||
|
expect(mockTimeConductor.on).toHaveBeenCalledWith("bounds", controller.setFormFromBounds);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("deregisters conductor listens when scope is destroyed", function () {
|
||||||
|
expect(mockScope.$on).toHaveBeenCalledWith("$destroy", controller.destroy);
|
||||||
|
|
||||||
|
controller.destroy();
|
||||||
|
expect(mockTimeConductor.off).toHaveBeenCalledWith("timeSystem", controller.changeTimeSystem);
|
||||||
|
expect(mockTimeConductor.off).toHaveBeenCalledWith("bounds", controller.setFormFromBounds);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("when time system changes, sets time system on scope", function () {
|
||||||
|
expect(tsListener).toBeDefined();
|
||||||
|
tsListener(timeSystem);
|
||||||
|
|
||||||
|
expect(mockScope.timeSystemModel).toBeDefined();
|
||||||
|
expect(mockScope.timeSystemModel.selected).toBe(timeSystem);
|
||||||
|
expect(mockScope.timeSystemModel.format).toBe(mockFormat);
|
||||||
|
expect(mockScope.timeSystemModel.deltaFormat).toBe(mockDeltaFormat);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("when time system changes, sets defaults on scope", function () {
|
||||||
|
expect(tsListener).toBeDefined();
|
||||||
|
tsListener(timeSystem);
|
||||||
|
|
||||||
|
expect(mockScope.boundsModel.start).toEqual(defaultBounds.start);
|
||||||
|
expect(mockScope.boundsModel.end).toEqual(defaultBounds.end);
|
||||||
|
|
||||||
|
expect(mockScope.boundsModel.startDelta).toEqual(defaultDeltas.start);
|
||||||
|
expect(mockScope.boundsModel.endDelta).toEqual(defaultDeltas.end);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("when bounds change, sets them on scope", function () {
|
||||||
|
var bounds = {
|
||||||
|
start: 1,
|
||||||
|
end: 2
|
||||||
|
};
|
||||||
|
|
||||||
|
var boundsListener = getListener("bounds");
|
||||||
|
expect(boundsListener).toBeDefined();
|
||||||
|
boundsListener(bounds);
|
||||||
|
|
||||||
|
expect(mockScope.boundsModel).toBeDefined();
|
||||||
|
expect(mockScope.boundsModel.start).toEqual(bounds.start);
|
||||||
|
expect(mockScope.boundsModel.end).toEqual(bounds.end);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("when user makes changes from UI", function () {
|
||||||
|
var mode = "realtime";
|
||||||
|
var ts1Metadata;
|
||||||
|
var ts2Metadata;
|
||||||
|
var ts3Metadata;
|
||||||
|
var mockTimeSystemConstructors;
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
mode = "realtime";
|
||||||
|
ts1Metadata = {
|
||||||
|
'key': 'ts1',
|
||||||
|
'name': 'Time System One',
|
||||||
|
'cssClass': 'cssClassOne'
|
||||||
|
};
|
||||||
|
ts2Metadata = {
|
||||||
|
'key': 'ts2',
|
||||||
|
'name': 'Time System Two',
|
||||||
|
'cssClass': 'cssClassTwo'
|
||||||
|
};
|
||||||
|
ts3Metadata = {
|
||||||
|
'key': 'ts3',
|
||||||
|
'name': 'Time System Three',
|
||||||
|
'cssClass': 'cssClassThree'
|
||||||
|
};
|
||||||
|
mockTimeSystems = [
|
||||||
|
{
|
||||||
|
metadata: ts1Metadata
|
||||||
|
},
|
||||||
|
{
|
||||||
|
metadata: ts2Metadata
|
||||||
|
},
|
||||||
|
{
|
||||||
|
metadata: ts3Metadata
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
//Wrap in mock constructors
|
||||||
|
mockTimeSystemConstructors = mockTimeSystems.map(function (mockTimeSystem) {
|
||||||
|
return function () {
|
||||||
|
return mockTimeSystem;
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("sets the mode on scope", function () {
|
||||||
|
controller = new TimeConductorController(
|
||||||
|
mockScope,
|
||||||
|
mockWindow,
|
||||||
|
mockTimeConductor,
|
||||||
|
mockConductorViewService,
|
||||||
|
mockTimeSystemConstructors
|
||||||
|
);
|
||||||
|
|
||||||
|
mockConductorViewService.availableTimeSystems.andReturn(mockTimeSystems);
|
||||||
|
controller.setMode(mode);
|
||||||
|
|
||||||
|
expect(mockScope.modeModel.selectedKey).toEqual(mode);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("sets available time systems on scope when mode changes", function () {
|
||||||
|
controller = new TimeConductorController(
|
||||||
|
mockScope,
|
||||||
|
mockWindow,
|
||||||
|
mockTimeConductor,
|
||||||
|
mockConductorViewService,
|
||||||
|
mockTimeSystemConstructors
|
||||||
|
);
|
||||||
|
|
||||||
|
mockConductorViewService.availableTimeSystems.andReturn(mockTimeSystems);
|
||||||
|
controller.setMode(mode);
|
||||||
|
|
||||||
|
expect(mockScope.timeSystemModel.options.length).toEqual(3);
|
||||||
|
expect(mockScope.timeSystemModel.options[0]).toEqual(ts1Metadata);
|
||||||
|
expect(mockScope.timeSystemModel.options[1]).toEqual(ts2Metadata);
|
||||||
|
expect(mockScope.timeSystemModel.options[2]).toEqual(ts3Metadata);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("sets bounds on the time conductor", function () {
|
||||||
|
var formModel = {
|
||||||
|
start: 1,
|
||||||
|
end: 10
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
controller = new TimeConductorController(
|
||||||
|
mockScope,
|
||||||
|
mockWindow,
|
||||||
|
mockTimeConductor,
|
||||||
|
mockConductorViewService,
|
||||||
|
mockTimeSystemConstructors
|
||||||
|
);
|
||||||
|
|
||||||
|
controller.updateBoundsFromForm(formModel);
|
||||||
|
expect(mockTimeConductor.bounds).toHaveBeenCalledWith(formModel);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("applies deltas when they change in form", function () {
|
||||||
|
var deltas = {
|
||||||
|
start: 1000,
|
||||||
|
end: 2000
|
||||||
|
};
|
||||||
|
var formModel = {
|
||||||
|
startDelta: deltas.start,
|
||||||
|
endDelta: deltas.end
|
||||||
|
};
|
||||||
|
|
||||||
|
controller = new TimeConductorController(
|
||||||
|
mockScope,
|
||||||
|
mockWindow,
|
||||||
|
mockTimeConductor,
|
||||||
|
mockConductorViewService,
|
||||||
|
mockTimeSystemConstructors
|
||||||
|
);
|
||||||
|
|
||||||
|
controller.updateDeltasFromForm(formModel);
|
||||||
|
expect(mockConductorViewService.deltas).toHaveBeenCalledWith(deltas);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("sets the time system on the time conductor", function () {
|
||||||
|
var defaultBounds = {
|
||||||
|
start: 5,
|
||||||
|
end: 6
|
||||||
|
};
|
||||||
|
var timeSystem = {
|
||||||
|
metadata: {
|
||||||
|
key: 'testTimeSystem'
|
||||||
|
},
|
||||||
|
defaults: function () {
|
||||||
|
return {
|
||||||
|
bounds: defaultBounds
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
mockTimeSystems = [
|
||||||
|
// Wrap as constructor function
|
||||||
|
function () {
|
||||||
|
return timeSystem;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
controller = new TimeConductorController(
|
||||||
|
mockScope,
|
||||||
|
mockWindow,
|
||||||
|
mockTimeConductor,
|
||||||
|
mockConductorViewService,
|
||||||
|
mockTimeSystems
|
||||||
|
);
|
||||||
|
|
||||||
|
controller.selectTimeSystemByKey('testTimeSystem');
|
||||||
|
expect(mockTimeConductor.timeSystem).toHaveBeenCalledWith(timeSystem, defaultBounds);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,201 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT Web includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
define(
|
||||||
|
[],
|
||||||
|
function () {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Supports mode-specific time conductor behavior.
|
||||||
|
*
|
||||||
|
* @constructor
|
||||||
|
* @param {TimeConductorMetadata} metadata
|
||||||
|
*/
|
||||||
|
function TimeConductorMode(metadata, conductor, timeSystems) {
|
||||||
|
this.conductor = conductor;
|
||||||
|
|
||||||
|
this.mdata = metadata;
|
||||||
|
this.dlts = undefined;
|
||||||
|
this.source = undefined;
|
||||||
|
this.sourceUnlisten = undefined;
|
||||||
|
this.systems = timeSystems;
|
||||||
|
this.availableSources = undefined;
|
||||||
|
this.changeTimeSystem = this.changeTimeSystem.bind(this);
|
||||||
|
this.tick = this.tick.bind(this);
|
||||||
|
|
||||||
|
//Set the time system initially
|
||||||
|
if (conductor.timeSystem()) {
|
||||||
|
this.changeTimeSystem(conductor.timeSystem());
|
||||||
|
}
|
||||||
|
|
||||||
|
//Listen for subsequent changes to time system
|
||||||
|
conductor.on('timeSystem', this.changeTimeSystem);
|
||||||
|
|
||||||
|
if (metadata.key === 'fixed') {
|
||||||
|
//Fixed automatically supports all time systems
|
||||||
|
this.availableSystems = timeSystems;
|
||||||
|
} else {
|
||||||
|
this.availableSystems = timeSystems.filter(function (timeSystem) {
|
||||||
|
//Only include time systems that have tick sources that
|
||||||
|
// support the current mode
|
||||||
|
return timeSystem.tickSources().some(function (tickSource) {
|
||||||
|
return metadata.key === tickSource.metadata.mode;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get or set the currently selected time system
|
||||||
|
* @param timeSystem
|
||||||
|
* @returns {TimeSystem} the currently selected time system
|
||||||
|
*/
|
||||||
|
TimeConductorMode.prototype.changeTimeSystem = function (timeSystem) {
|
||||||
|
// On time system change, apply default deltas
|
||||||
|
var defaults = timeSystem.defaults() || {
|
||||||
|
bounds: {
|
||||||
|
start: 0,
|
||||||
|
end: 0
|
||||||
|
},
|
||||||
|
deltas: {
|
||||||
|
start: 0,
|
||||||
|
end: 0
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.conductor.bounds(defaults.bounds);
|
||||||
|
this.deltas(defaults.deltas);
|
||||||
|
|
||||||
|
// Tick sources are mode-specific, so restrict tick sources to only those supported by the current mode.
|
||||||
|
var key = this.mdata.key;
|
||||||
|
var tickSources = timeSystem.tickSources();
|
||||||
|
if (tickSources) {
|
||||||
|
this.availableSources = tickSources.filter(function (source) {
|
||||||
|
return source.metadata.mode === key;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set an appropriate tick source from the new time system
|
||||||
|
this.tickSource(this.availableTickSources(timeSystem)[0]);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {ModeMetadata}
|
||||||
|
*/
|
||||||
|
TimeConductorMode.prototype.metadata = function () {
|
||||||
|
return this.mdata;
|
||||||
|
};
|
||||||
|
|
||||||
|
TimeConductorMode.prototype.availableTimeSystems = function () {
|
||||||
|
return this.availableSystems;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tick sources are mode-specific. This returns a filtered list of the tick sources available in the currently selected mode
|
||||||
|
* @param timeSystem
|
||||||
|
* @returns {Array.<T>}
|
||||||
|
*/
|
||||||
|
TimeConductorMode.prototype.availableTickSources = function (timeSystem) {
|
||||||
|
return this.availableSources;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get or set tick source. Setting tick source will also start
|
||||||
|
* listening to it and unlisten from any existing tick source
|
||||||
|
* @param tickSource
|
||||||
|
* @returns {TickSource}
|
||||||
|
*/
|
||||||
|
TimeConductorMode.prototype.tickSource = function (tickSource) {
|
||||||
|
if (arguments.length > 0) {
|
||||||
|
if (this.sourceUnlisten) {
|
||||||
|
this.sourceUnlisten();
|
||||||
|
}
|
||||||
|
this.source = tickSource;
|
||||||
|
if (tickSource) {
|
||||||
|
this.sourceUnlisten = tickSource.listen(this.tick);
|
||||||
|
//Now following a tick source
|
||||||
|
this.conductor.follow(true);
|
||||||
|
} else {
|
||||||
|
this.conductor.follow(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.source;
|
||||||
|
};
|
||||||
|
|
||||||
|
TimeConductorMode.prototype.destroy = function () {
|
||||||
|
this.conductor.off('timeSystem', this.changeTimeSystem);
|
||||||
|
|
||||||
|
if (this.sourceUnlisten) {
|
||||||
|
this.sourceUnlisten();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @param {number} time some value that is valid in the current TimeSystem
|
||||||
|
*/
|
||||||
|
TimeConductorMode.prototype.tick = function (time) {
|
||||||
|
var deltas = this.deltas();
|
||||||
|
var startTime = time;
|
||||||
|
var endTime = time;
|
||||||
|
|
||||||
|
if (deltas) {
|
||||||
|
startTime = time - deltas.start;
|
||||||
|
endTime = time + deltas.end;
|
||||||
|
}
|
||||||
|
this.conductor.bounds({
|
||||||
|
start: startTime,
|
||||||
|
end: endTime
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get or set the current value for the deltas used by this time system.
|
||||||
|
* On change, the new deltas will be used to calculate and set the
|
||||||
|
* bounds on the time conductor.
|
||||||
|
* @param deltas
|
||||||
|
* @returns {TimeSystemDeltas}
|
||||||
|
*/
|
||||||
|
TimeConductorMode.prototype.deltas = function (deltas) {
|
||||||
|
if (arguments.length !== 0) {
|
||||||
|
var oldEnd = this.conductor.bounds().end;
|
||||||
|
|
||||||
|
if (this.dlts && this.dlts.end !== undefined) {
|
||||||
|
//Calculate the previous raw end value (without delta)
|
||||||
|
oldEnd = oldEnd - this.dlts.end;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.dlts = deltas;
|
||||||
|
|
||||||
|
var newBounds = {
|
||||||
|
start: oldEnd - this.dlts.start,
|
||||||
|
end: oldEnd + this.dlts.end
|
||||||
|
};
|
||||||
|
|
||||||
|
this.conductor.bounds(newBounds);
|
||||||
|
}
|
||||||
|
return this.dlts;
|
||||||
|
};
|
||||||
|
|
||||||
|
return TimeConductorMode;
|
||||||
|
}
|
||||||
|
);
|
@ -0,0 +1,210 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT Web includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
define(['./TimeConductorMode'], function (TimeConductorMode) {
|
||||||
|
describe("The Time Conductor Mode", function () {
|
||||||
|
var mockTimeConductor,
|
||||||
|
fixedModeMetaData,
|
||||||
|
mockTimeSystems,
|
||||||
|
fixedTimeSystem,
|
||||||
|
|
||||||
|
realtimeModeMetaData,
|
||||||
|
realtimeTimeSystem,
|
||||||
|
mockTickSource,
|
||||||
|
|
||||||
|
mockBounds,
|
||||||
|
mode;
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
fixedModeMetaData = {
|
||||||
|
key: "fixed"
|
||||||
|
};
|
||||||
|
realtimeModeMetaData = {
|
||||||
|
key: "realtime"
|
||||||
|
};
|
||||||
|
mockBounds = {
|
||||||
|
start: 0,
|
||||||
|
end: 1
|
||||||
|
};
|
||||||
|
|
||||||
|
fixedTimeSystem = jasmine.createSpyObj("timeSystem", [
|
||||||
|
"defaults",
|
||||||
|
"tickSources"
|
||||||
|
]);
|
||||||
|
fixedTimeSystem.tickSources.andReturn([]);
|
||||||
|
|
||||||
|
mockTickSource = jasmine.createSpyObj("tickSource", [
|
||||||
|
"listen"
|
||||||
|
]);
|
||||||
|
mockTickSource.metadata = {
|
||||||
|
mode: "realtime"
|
||||||
|
};
|
||||||
|
realtimeTimeSystem = jasmine.createSpyObj("realtimeTimeSystem", [
|
||||||
|
"defaults",
|
||||||
|
"tickSources"
|
||||||
|
]);
|
||||||
|
realtimeTimeSystem.tickSources.andReturn([mockTickSource]);
|
||||||
|
|
||||||
|
//Do not return any time systems initially for a default
|
||||||
|
// construction configuration that works without any additional work
|
||||||
|
mockTimeSystems = [];
|
||||||
|
|
||||||
|
mockTimeConductor = jasmine.createSpyObj("timeConductor", [
|
||||||
|
"bounds",
|
||||||
|
"timeSystem",
|
||||||
|
"on",
|
||||||
|
"off",
|
||||||
|
"follow"
|
||||||
|
]);
|
||||||
|
mockTimeConductor.bounds.andReturn(mockBounds);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Reacts to changes in conductor time system", function () {
|
||||||
|
mode = new TimeConductorMode(fixedModeMetaData, mockTimeConductor, mockTimeSystems);
|
||||||
|
expect(mockTimeConductor.on).toHaveBeenCalledWith("timeSystem", mode.changeTimeSystem);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Stops listening to time system changes on destroy", function () {
|
||||||
|
mode = new TimeConductorMode(fixedModeMetaData, mockTimeConductor, mockTimeSystems);
|
||||||
|
mode.destroy();
|
||||||
|
expect(mockTimeConductor.off).toHaveBeenCalledWith("timeSystem", mode.changeTimeSystem);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Filters available time systems to those with tick sources that" +
|
||||||
|
" support this mode", function () {
|
||||||
|
mockTimeSystems = [fixedTimeSystem, realtimeTimeSystem];
|
||||||
|
mode = new TimeConductorMode(realtimeModeMetaData, mockTimeConductor, mockTimeSystems);
|
||||||
|
|
||||||
|
var availableTimeSystems = mode.availableTimeSystems();
|
||||||
|
expect(availableTimeSystems.length).toBe(1);
|
||||||
|
expect(availableTimeSystems.indexOf(fixedTimeSystem)).toBe(-1);
|
||||||
|
expect(availableTimeSystems.indexOf(realtimeTimeSystem)).toBe(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("Changing the time system", function () {
|
||||||
|
var defaults;
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
defaults = {
|
||||||
|
bounds: {
|
||||||
|
start: 1,
|
||||||
|
end: 2
|
||||||
|
},
|
||||||
|
deltas: {
|
||||||
|
start: 3,
|
||||||
|
end: 4
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fixedTimeSystem.defaults.andReturn(defaults);
|
||||||
|
|
||||||
|
});
|
||||||
|
it ("sets defaults from new time system", function () {
|
||||||
|
mode = new TimeConductorMode(fixedModeMetaData, mockTimeConductor, mockTimeSystems);
|
||||||
|
spyOn(mode, "deltas");
|
||||||
|
mode.deltas.andCallThrough();
|
||||||
|
|
||||||
|
mode.changeTimeSystem(fixedTimeSystem);
|
||||||
|
expect(mockTimeConductor.bounds).toHaveBeenCalledWith(defaults.bounds);
|
||||||
|
expect(mode.deltas).toHaveBeenCalledWith(defaults.deltas);
|
||||||
|
});
|
||||||
|
it ("If a tick source is available, sets the tick source", function () {
|
||||||
|
mode = new TimeConductorMode(realtimeModeMetaData, mockTimeConductor, mockTimeSystems);
|
||||||
|
mode.changeTimeSystem(realtimeTimeSystem);
|
||||||
|
|
||||||
|
var currentTickSource = mode.tickSource();
|
||||||
|
expect(currentTickSource).toBe(mockTickSource);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("Setting a tick source", function () {
|
||||||
|
var mockUnlistener;
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
mockUnlistener = jasmine.createSpy("unlistener");
|
||||||
|
mockTickSource.listen.andReturn(mockUnlistener);
|
||||||
|
|
||||||
|
mode = new TimeConductorMode(realtimeModeMetaData, mockTimeConductor, mockTimeSystems);
|
||||||
|
mode.tickSource(mockTickSource);
|
||||||
|
});
|
||||||
|
|
||||||
|
it ("Unlistens from old tick source", function () {
|
||||||
|
mode.tickSource(mockTickSource);
|
||||||
|
expect(mockUnlistener).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it ("Listens to new tick source", function () {
|
||||||
|
expect(mockTickSource.listen).toHaveBeenCalledWith(mode.tick);
|
||||||
|
});
|
||||||
|
|
||||||
|
it ("Sets 'follow' state on time conductor", function () {
|
||||||
|
expect(mockTimeConductor.follow).toHaveBeenCalledWith(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it ("on destroy, unlistens from tick source", function () {
|
||||||
|
mode.destroy();
|
||||||
|
expect(mockUnlistener).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("setting deltas", function () {
|
||||||
|
beforeEach(function () {
|
||||||
|
mode = new TimeConductorMode(realtimeModeMetaData, mockTimeConductor, mockTimeSystems);
|
||||||
|
});
|
||||||
|
it ("sets the bounds on the time conductor based on new delta" +
|
||||||
|
" values", function () {
|
||||||
|
var deltas = {
|
||||||
|
start: 20,
|
||||||
|
end: 10
|
||||||
|
};
|
||||||
|
|
||||||
|
mode.deltas(deltas);
|
||||||
|
|
||||||
|
expect(mockTimeConductor.bounds).toHaveBeenCalledWith({
|
||||||
|
start: mockBounds.end - deltas.start,
|
||||||
|
end: mockBounds.end + deltas.end
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("ticking", function () {
|
||||||
|
beforeEach(function () {
|
||||||
|
mode = new TimeConductorMode(realtimeModeMetaData, mockTimeConductor, mockTimeSystems);
|
||||||
|
});
|
||||||
|
it ("sets bounds based on current delta values", function () {
|
||||||
|
var deltas = {
|
||||||
|
start: 20,
|
||||||
|
end: 10
|
||||||
|
};
|
||||||
|
var time = 100;
|
||||||
|
|
||||||
|
mode.deltas(deltas);
|
||||||
|
mode.tick(time);
|
||||||
|
|
||||||
|
expect(mockTimeConductor.bounds).toHaveBeenCalledWith({
|
||||||
|
start: time - deltas.start,
|
||||||
|
end: time + deltas.end
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,69 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT Web includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
define(
|
||||||
|
[],
|
||||||
|
function () {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Form validation for the TimeConductorController.
|
||||||
|
* @param conductor
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function TimeConductorValidation(conductor) {
|
||||||
|
var self = this;
|
||||||
|
this.conductor = conductor;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Bind all class functions to 'this'
|
||||||
|
*/
|
||||||
|
Object.keys(TimeConductorValidation.prototype).filter(function (key) {
|
||||||
|
return typeof TimeConductorValidation.prototype[key] === 'function';
|
||||||
|
}).forEach(function (key) {
|
||||||
|
self[key] = self[key].bind(self);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validation methods below are invoked directly from controls in the TimeConductor form
|
||||||
|
*/
|
||||||
|
TimeConductorValidation.prototype.validateStart = function (start) {
|
||||||
|
var bounds = this.conductor.bounds();
|
||||||
|
return this.conductor.validateBounds({start: start, end: bounds.end}) === true;
|
||||||
|
};
|
||||||
|
|
||||||
|
TimeConductorValidation.prototype.validateEnd = function (end) {
|
||||||
|
var bounds = this.conductor.bounds();
|
||||||
|
return this.conductor.validateBounds({start: bounds.start, end: end}) === true;
|
||||||
|
};
|
||||||
|
|
||||||
|
TimeConductorValidation.prototype.validateStartDelta = function (startDelta) {
|
||||||
|
return !isNaN(startDelta) && startDelta > 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
TimeConductorValidation.prototype.validateEndDelta = function (endDelta) {
|
||||||
|
return !isNaN(endDelta) && endDelta >= 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
return TimeConductorValidation;
|
||||||
|
}
|
||||||
|
);
|
@ -0,0 +1,73 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT Web includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
define(['./TimeConductorValidation'], function (TimeConductorValidation) {
|
||||||
|
describe("The Time Conductor Validation class", function () {
|
||||||
|
var timeConductorValidation,
|
||||||
|
mockTimeConductor;
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
mockTimeConductor = jasmine.createSpyObj("timeConductor", [
|
||||||
|
"validateBounds",
|
||||||
|
"bounds"
|
||||||
|
]);
|
||||||
|
timeConductorValidation = new TimeConductorValidation(mockTimeConductor);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("Validates start and end values using Time Conductor", function () {
|
||||||
|
beforeEach(function () {
|
||||||
|
var mockBounds = {
|
||||||
|
start: 10,
|
||||||
|
end: 20
|
||||||
|
};
|
||||||
|
|
||||||
|
mockTimeConductor.bounds.andReturn(mockBounds);
|
||||||
|
|
||||||
|
});
|
||||||
|
it("Validates start values using Time Conductor", function () {
|
||||||
|
var startValue = 30;
|
||||||
|
timeConductorValidation.validateStart(startValue);
|
||||||
|
expect(mockTimeConductor.validateBounds).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
it("Validates end values using Time Conductor", function () {
|
||||||
|
var endValue = 40;
|
||||||
|
timeConductorValidation.validateEnd(endValue);
|
||||||
|
expect(mockTimeConductor.validateBounds).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Validates that start delta is valid number > 0", function () {
|
||||||
|
expect(timeConductorValidation.validateStartDelta(-1)).toBe(false);
|
||||||
|
expect(timeConductorValidation.validateStartDelta("abc")).toBe(false);
|
||||||
|
expect(timeConductorValidation.validateStartDelta("1")).toBe(true);
|
||||||
|
expect(timeConductorValidation.validateStartDelta(1)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Validates that end delta is valid number >= 0", function () {
|
||||||
|
expect(timeConductorValidation.validateEndDelta(-1)).toBe(false);
|
||||||
|
expect(timeConductorValidation.validateEndDelta("abc")).toBe(false);
|
||||||
|
expect(timeConductorValidation.validateEndDelta("1")).toBe(true);
|
||||||
|
expect(timeConductorValidation.validateEndDelta(0)).toBe(true);
|
||||||
|
expect(timeConductorValidation.validateEndDelta(1)).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,202 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT Web includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
define(
|
||||||
|
[
|
||||||
|
'./TimeConductorMode'
|
||||||
|
],
|
||||||
|
function (TimeConductorMode) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class representing the state of the time conductor view. This
|
||||||
|
* exposes details of the UI that are not represented on the
|
||||||
|
* TimeConductor API itself such as modes and deltas.
|
||||||
|
*
|
||||||
|
* @param conductor
|
||||||
|
* @param timeSystems
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function TimeConductorViewService(conductor, timeSystems) {
|
||||||
|
this.systems = timeSystems.map(function (timeSystemConstructor) {
|
||||||
|
return timeSystemConstructor();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.conductor = conductor;
|
||||||
|
this.currentMode = undefined;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {object} ModeMetadata
|
||||||
|
* @property {string} key A unique identifying key for this mode
|
||||||
|
* @property {string} cssClass The css class for the glyph
|
||||||
|
* representing this mode
|
||||||
|
* @property {string} label A short label for this mode
|
||||||
|
* @property {string} name A longer name for the mode
|
||||||
|
* @property {string} description A description of the mode
|
||||||
|
*/
|
||||||
|
this.availModes = {
|
||||||
|
'fixed': {
|
||||||
|
key: 'fixed',
|
||||||
|
cssclass: 'icon-calendar',
|
||||||
|
label: 'Fixed',
|
||||||
|
name: 'Fixed Timespan Mode',
|
||||||
|
description: 'Query and explore data that falls between two fixed datetimes.'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function hasTickSource(sourceType, timeSystem) {
|
||||||
|
return timeSystem.tickSources().some(function (tickSource) {
|
||||||
|
return tickSource.metadata.mode === sourceType;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var timeSystemsForMode = function (sourceType) {
|
||||||
|
return this.systems.filter(hasTickSource.bind(this, sourceType));
|
||||||
|
}.bind(this);
|
||||||
|
|
||||||
|
//Only show 'real-time mode' if appropriate time systems available
|
||||||
|
if (timeSystemsForMode('realtime').length > 0) {
|
||||||
|
var realtimeMode = {
|
||||||
|
key: 'realtime',
|
||||||
|
cssclass: 'icon-clock',
|
||||||
|
label: 'Real-time',
|
||||||
|
name: 'Real-time Mode',
|
||||||
|
description: 'Monitor real-time streaming data as it comes in. The Time Conductor and displays will automatically advance themselves based on a UTC clock.'
|
||||||
|
};
|
||||||
|
this.availModes[realtimeMode.key] = realtimeMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Only show 'LAD mode' if appropriate time systems available
|
||||||
|
if (timeSystemsForMode('lad').length > 0) {
|
||||||
|
var ladMode = {
|
||||||
|
key: 'lad',
|
||||||
|
cssclass: 'icon-database',
|
||||||
|
label: 'LAD',
|
||||||
|
name: 'LAD Mode',
|
||||||
|
description: 'Latest Available Data mode monitors real-time streaming data as it comes in. The Time Conductor and displays will only advance when data becomes available.'
|
||||||
|
};
|
||||||
|
this.availModes[ladMode.key] = ladMode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Getter/Setter for the Time Conductor Mode. Modes determine the
|
||||||
|
* behavior of the time conductor, especially with regards to the
|
||||||
|
* bounds and how they change with time.
|
||||||
|
*
|
||||||
|
* In fixed mode, the bounds do not change with time, but can be
|
||||||
|
* modified by the used
|
||||||
|
*
|
||||||
|
* In realtime mode, the bounds change with time. Bounds are not
|
||||||
|
* directly modifiable by the user, however deltas can be.
|
||||||
|
*
|
||||||
|
* In Latest Available Data (LAD) mode, the bounds are updated when
|
||||||
|
* data is received. As with realtime mode the
|
||||||
|
*
|
||||||
|
* @param {string} newModeKey One of 'fixed', 'realtime', or 'LAD'
|
||||||
|
* @returns {string} the current mode, one of 'fixed', 'realtime',
|
||||||
|
* or 'LAD'.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
TimeConductorViewService.prototype.mode = function (newModeKey) {
|
||||||
|
function contains(timeSystems, ts) {
|
||||||
|
return timeSystems.filter(function (t) {
|
||||||
|
return t.metadata.key === ts.metadata.key;
|
||||||
|
}).length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arguments.length === 1) {
|
||||||
|
var timeSystem = this.conductor.timeSystem();
|
||||||
|
var modes = this.availableModes();
|
||||||
|
var modeMetaData = modes[newModeKey];
|
||||||
|
|
||||||
|
if (this.currentMode) {
|
||||||
|
this.currentMode.destroy();
|
||||||
|
}
|
||||||
|
this.currentMode = new TimeConductorMode(modeMetaData, this.conductor, this.systems);
|
||||||
|
|
||||||
|
// If no time system set on time conductor, or the currently selected time system is not available in
|
||||||
|
// the new mode, default to first available time system
|
||||||
|
if (!timeSystem || !contains(this.currentMode.availableTimeSystems(), timeSystem)) {
|
||||||
|
timeSystem = this.currentMode.availableTimeSystems()[0];
|
||||||
|
this.conductor.timeSystem(timeSystem, timeSystem.defaults().bounds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.currentMode ? this.currentMode.metadata().key : undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {object} Delta
|
||||||
|
* @property {number} start Used to set the start bound of the
|
||||||
|
* TimeConductor on tick. A positive value that will be subtracted
|
||||||
|
* from the value provided by a tick source to determine the start
|
||||||
|
* bound.
|
||||||
|
* @property {number} end Used to set the end bound of the
|
||||||
|
* TimeConductor on tick. A positive value that will be added
|
||||||
|
* from the value provided by a tick source to determine the start
|
||||||
|
* bound.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* Deltas define the offset from the latest time value provided by
|
||||||
|
* the current tick source. Deltas are only valid in realtime or LAD
|
||||||
|
* modes.
|
||||||
|
*
|
||||||
|
* Realtime mode:
|
||||||
|
* - start: A time in ms before now which will be used to
|
||||||
|
* determine the 'start' bound on tick
|
||||||
|
* - end: A time in ms after now which will be used to determine
|
||||||
|
* the 'end' bound on tick
|
||||||
|
*
|
||||||
|
* LAD mode:
|
||||||
|
* - start: A time in ms before the timestamp of the last data
|
||||||
|
* received which will be used to determine the 'start' bound on
|
||||||
|
* tick
|
||||||
|
* - end: A time in ms after the timestamp of the last data received
|
||||||
|
* which will be used to determine the 'end' bound on tick
|
||||||
|
* @returns {Delta} current value of the deltas
|
||||||
|
*/
|
||||||
|
TimeConductorViewService.prototype.deltas = function () {
|
||||||
|
//Deltas stored on mode. Use .apply to preserve arguments
|
||||||
|
return this.currentMode.deltas.apply(this.currentMode, arguments);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Availability of modes depends on the time systems and tick
|
||||||
|
* sources available. For example, Latest Available Data mode will
|
||||||
|
* not be available if there are no time systems and tick sources
|
||||||
|
* that support LAD mode.
|
||||||
|
* @returns {ModeMetadata[]}
|
||||||
|
*/
|
||||||
|
TimeConductorViewService.prototype.availableModes = function () {
|
||||||
|
return this.availModes;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Availability of time systems depends on the currently selected
|
||||||
|
* mode. Time systems and tick sources are mode dependent
|
||||||
|
*/
|
||||||
|
TimeConductorViewService.prototype.availableTimeSystems = function () {
|
||||||
|
return this.currentMode.availableTimeSystems();
|
||||||
|
};
|
||||||
|
|
||||||
|
return TimeConductorViewService;
|
||||||
|
}
|
||||||
|
);
|
@ -0,0 +1,185 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT Web includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
define(['./TimeConductorViewService'], function (TimeConductorViewService) {
|
||||||
|
describe("The Time Conductor view service", function () {
|
||||||
|
var mockTimeConductor;
|
||||||
|
var basicTimeSystem;
|
||||||
|
var tickingTimeSystem;
|
||||||
|
var viewService;
|
||||||
|
var tickingTimeSystemDefaults;
|
||||||
|
|
||||||
|
function mockConstructor(object) {
|
||||||
|
return function () {
|
||||||
|
return object;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
mockTimeConductor = jasmine.createSpyObj("timeConductor", [
|
||||||
|
"timeSystem",
|
||||||
|
"bounds",
|
||||||
|
"follow",
|
||||||
|
"on",
|
||||||
|
"off"
|
||||||
|
]);
|
||||||
|
|
||||||
|
basicTimeSystem = jasmine.createSpyObj("basicTimeSystem", [
|
||||||
|
"tickSources",
|
||||||
|
"defaults"
|
||||||
|
]);
|
||||||
|
basicTimeSystem.metadata = {
|
||||||
|
key: "basic"
|
||||||
|
};
|
||||||
|
basicTimeSystem.tickSources.andReturn([]);
|
||||||
|
basicTimeSystem.defaults.andReturn({
|
||||||
|
bounds: {
|
||||||
|
start: 0,
|
||||||
|
end: 1
|
||||||
|
},
|
||||||
|
deltas: {
|
||||||
|
start: 0,
|
||||||
|
end: 0
|
||||||
|
}
|
||||||
|
});
|
||||||
|
//Initialize conductor
|
||||||
|
mockTimeConductor.timeSystem.andReturn(basicTimeSystem);
|
||||||
|
mockTimeConductor.bounds.andReturn({start: 0, end: 1});
|
||||||
|
|
||||||
|
tickingTimeSystem = jasmine.createSpyObj("tickingTimeSystem", [
|
||||||
|
"tickSources",
|
||||||
|
"defaults"
|
||||||
|
]);
|
||||||
|
tickingTimeSystem.metadata = {
|
||||||
|
key: "ticking"
|
||||||
|
};
|
||||||
|
tickingTimeSystemDefaults = {
|
||||||
|
bounds: {
|
||||||
|
start: 100,
|
||||||
|
end: 200
|
||||||
|
},
|
||||||
|
deltas: {
|
||||||
|
start: 1000,
|
||||||
|
end: 500
|
||||||
|
}
|
||||||
|
};
|
||||||
|
tickingTimeSystem.defaults.andReturn(tickingTimeSystemDefaults);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("At a minimum supports fixed mode", function () {
|
||||||
|
var mockTimeSystems = [mockConstructor(basicTimeSystem)];
|
||||||
|
viewService = new TimeConductorViewService(mockTimeConductor, mockTimeSystems);
|
||||||
|
|
||||||
|
var availableModes = viewService.availableModes();
|
||||||
|
expect(availableModes.fixed).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Supports realtime mode if appropriate tick source(s) availables", function () {
|
||||||
|
var mockTimeSystems = [mockConstructor(tickingTimeSystem)];
|
||||||
|
var mockRealtimeTickSource = {
|
||||||
|
metadata: {
|
||||||
|
mode: 'realtime'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
tickingTimeSystem.tickSources.andReturn([mockRealtimeTickSource]);
|
||||||
|
|
||||||
|
viewService = new TimeConductorViewService(mockTimeConductor, mockTimeSystems);
|
||||||
|
|
||||||
|
var availableModes = viewService.availableModes();
|
||||||
|
expect(availableModes.realtime).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Supports LAD mode if appropriate tick source(s) available", function () {
|
||||||
|
var mockTimeSystems = [mockConstructor(tickingTimeSystem)];
|
||||||
|
var mockLADTickSource = {
|
||||||
|
metadata: {
|
||||||
|
mode: 'lad'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
tickingTimeSystem.tickSources.andReturn([mockLADTickSource]);
|
||||||
|
|
||||||
|
viewService = new TimeConductorViewService(mockTimeConductor, mockTimeSystems);
|
||||||
|
|
||||||
|
var availableModes = viewService.availableModes();
|
||||||
|
expect(availableModes.lad).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("when mode is changed", function () {
|
||||||
|
|
||||||
|
it("destroys previous mode", function () {
|
||||||
|
var mockTimeSystems = [mockConstructor(basicTimeSystem)];
|
||||||
|
|
||||||
|
var oldMode = jasmine.createSpyObj("conductorMode", [
|
||||||
|
"destroy"
|
||||||
|
]);
|
||||||
|
|
||||||
|
viewService = new TimeConductorViewService(mockTimeConductor, mockTimeSystems);
|
||||||
|
viewService.currentMode = oldMode;
|
||||||
|
viewService.mode('fixed');
|
||||||
|
expect(oldMode.destroy).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("the time system", function () {
|
||||||
|
it("is retained if available in new mode", function () {
|
||||||
|
var mockTimeSystems = [mockConstructor(basicTimeSystem), mockConstructor(tickingTimeSystem)];
|
||||||
|
var mockRealtimeTickSource = {
|
||||||
|
metadata: {
|
||||||
|
mode: 'realtime'
|
||||||
|
},
|
||||||
|
listen: function () {}
|
||||||
|
};
|
||||||
|
tickingTimeSystem.tickSources.andReturn([mockRealtimeTickSource]);
|
||||||
|
|
||||||
|
viewService = new TimeConductorViewService(mockTimeConductor, mockTimeSystems);
|
||||||
|
|
||||||
|
//Set time system to one known to support realtime mode
|
||||||
|
mockTimeConductor.timeSystem.andReturn(tickingTimeSystem);
|
||||||
|
|
||||||
|
//Select realtime mode
|
||||||
|
mockTimeConductor.timeSystem.reset();
|
||||||
|
viewService.mode('realtime');
|
||||||
|
expect(mockTimeConductor.timeSystem).not.toHaveBeenCalledWith(tickingTimeSystem, tickingTimeSystemDefaults.bounds);
|
||||||
|
});
|
||||||
|
it("is defaulted if selected time system not available in new mode", function () {
|
||||||
|
var mockTimeSystems = [mockConstructor(basicTimeSystem), mockConstructor(tickingTimeSystem)];
|
||||||
|
var mockRealtimeTickSource = {
|
||||||
|
metadata: {
|
||||||
|
mode: 'realtime'
|
||||||
|
},
|
||||||
|
listen: function () {}
|
||||||
|
};
|
||||||
|
tickingTimeSystem.tickSources.andReturn([mockRealtimeTickSource]);
|
||||||
|
|
||||||
|
viewService = new TimeConductorViewService(mockTimeConductor, mockTimeSystems);
|
||||||
|
|
||||||
|
//Set time system to one known to not support realtime mode
|
||||||
|
mockTimeConductor.timeSystem.andReturn(basicTimeSystem);
|
||||||
|
|
||||||
|
//Select realtime mode
|
||||||
|
mockTimeConductor.timeSystem.reset();
|
||||||
|
viewService.mode('realtime');
|
||||||
|
expect(mockTimeConductor.timeSystem).toHaveBeenCalledWith(tickingTimeSystem, tickingTimeSystemDefaults.bounds);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
40
platform/features/conductor-v2/utcTimeSystem/bundle.js
Normal file
40
platform/features/conductor-v2/utcTimeSystem/bundle.js
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT Web includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
define([
|
||||||
|
"./src/UTCTimeSystem",
|
||||||
|
'legacyRegistry'
|
||||||
|
], function (
|
||||||
|
UTCTimeSystem,
|
||||||
|
legacyRegistry
|
||||||
|
) {
|
||||||
|
legacyRegistry.register("platform/features/conductor-v2/utcTimeSystem", {
|
||||||
|
"extensions": {
|
||||||
|
"timeSystems": [
|
||||||
|
{
|
||||||
|
"implementation": UTCTimeSystem,
|
||||||
|
"depends": ["$timeout"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,78 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT Web includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
define([
|
||||||
|
'../../conductor/src/timeSystems/TimeSystem',
|
||||||
|
'../../conductor/src/timeSystems/LocalClock'
|
||||||
|
], function (TimeSystem, LocalClock) {
|
||||||
|
var FIFTEEN_MINUTES = 15 * 60 * 1000,
|
||||||
|
DEFAULT_PERIOD = 1000;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This time system supports UTC dates and provides a ticking clock source.
|
||||||
|
* @implements TimeSystem
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
function UTCTimeSystem($timeout) {
|
||||||
|
TimeSystem.call(this);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Some metadata, which will be used to identify the time system in
|
||||||
|
* the UI
|
||||||
|
* @type {{key: string, name: string, cssclass: string}}
|
||||||
|
*/
|
||||||
|
this.metadata = {
|
||||||
|
'key': 'utc',
|
||||||
|
'name': 'UTC',
|
||||||
|
'cssclass': 'icon-clock'
|
||||||
|
};
|
||||||
|
|
||||||
|
this.fmts = ['utc'];
|
||||||
|
this.sources = [new LocalClock($timeout, DEFAULT_PERIOD)];
|
||||||
|
}
|
||||||
|
|
||||||
|
UTCTimeSystem.prototype = Object.create(TimeSystem.prototype);
|
||||||
|
|
||||||
|
UTCTimeSystem.prototype.formats = function () {
|
||||||
|
return this.fmts;
|
||||||
|
};
|
||||||
|
|
||||||
|
UTCTimeSystem.prototype.deltaFormat = function () {
|
||||||
|
return 'duration';
|
||||||
|
};
|
||||||
|
|
||||||
|
UTCTimeSystem.prototype.tickSources = function () {
|
||||||
|
return this.sources;
|
||||||
|
};
|
||||||
|
|
||||||
|
UTCTimeSystem.prototype.defaults = function (key) {
|
||||||
|
var now = Math.ceil(Date.now() / 1000) * 1000;
|
||||||
|
return {
|
||||||
|
key: 'utc-default',
|
||||||
|
name: 'UTC time system defaults',
|
||||||
|
deltas: {start: FIFTEEN_MINUTES, end: 0},
|
||||||
|
bounds: {start: now - FIFTEEN_MINUTES, end: now}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
return UTCTimeSystem;
|
||||||
|
});
|
@ -0,0 +1,46 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT Web includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
define(['./UTCTimeSystem'], function (UTCTimeSystem) {
|
||||||
|
describe("The UTCTimeSystem class", function () {
|
||||||
|
var timeSystem,
|
||||||
|
mockTimeout;
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
mockTimeout = jasmine.createSpy("timeout");
|
||||||
|
timeSystem = new UTCTimeSystem(mockTimeout);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("defines at least one format", function () {
|
||||||
|
expect(timeSystem.formats().length).toBeGreaterThan(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("defines a tick source", function () {
|
||||||
|
var tickSources = timeSystem.tickSources();
|
||||||
|
expect(tickSources.length).toBeGreaterThan(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("defines some defaults", function () {
|
||||||
|
expect(timeSystem.defaults()).toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -47,6 +47,11 @@ define([
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"stylesheets": [
|
||||||
|
{
|
||||||
|
"stylesheetUrl": "css/time-conductor.css"
|
||||||
|
}
|
||||||
|
],
|
||||||
"components": [
|
"components": [
|
||||||
{
|
{
|
||||||
"type": "decorator",
|
"type": "decorator",
|
||||||
|
300
platform/features/conductor/res/sass/time-conductor.scss
Normal file
300
platform/features/conductor/res/sass/time-conductor.scss
Normal file
@ -0,0 +1,300 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT Web, Copyright (c) 2014-2015, United States Government
|
||||||
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
|
* Administration. All rights reserved.
|
||||||
|
*
|
||||||
|
* Open MCT Web is licensed under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
* Open MCT Web includes source code licensed under additional open source
|
||||||
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||||
|
* this source code distribution or the Licensing information page available
|
||||||
|
* at runtime from the About dialog for additional information.
|
||||||
|
*****************************************************************************/
|
||||||
|
@import "bourbon";
|
||||||
|
|
||||||
|
@import "../../../../commonUI/general/res/sass/constants";
|
||||||
|
@import "../../../../commonUI/general/res/sass/mixins";
|
||||||
|
@import "../../../../commonUI/general/res/sass/mobile/constants";
|
||||||
|
@import "../../../../commonUI/general/res/sass/mobile/mixins";
|
||||||
|
@import "../../../../commonUI/themes/espresso/res/sass/constants";
|
||||||
|
@import "../../../../commonUI/themes/espresso/res/sass/mixins";
|
||||||
|
|
||||||
|
$ueTimeConductorH: (33px, 18px, 20px);
|
||||||
|
|
||||||
|
@mixin toiLineHovEffects() {
|
||||||
|
&:before,
|
||||||
|
&:after {
|
||||||
|
background-color: $timeControllerToiLineColorHov;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.l-time-controller {
|
||||||
|
$minW: 500px;
|
||||||
|
$knobHOffset: 0px;
|
||||||
|
$knobM: ($sliderKnobW + $knobHOffset) * -1;
|
||||||
|
$rangeValPad: $interiorMargin;
|
||||||
|
$rangeValOffset: $sliderKnobW + $interiorMargin;
|
||||||
|
$timeRangeSliderLROffset: 150px + ($sliderKnobW * 2);
|
||||||
|
$r1H: nth($ueTimeConductorH,1);
|
||||||
|
$r2H: nth($ueTimeConductorH,2);
|
||||||
|
$r3H: nth($ueTimeConductorH,3);
|
||||||
|
|
||||||
|
min-width: $minW;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
|
||||||
|
.l-time-range-inputs-holder,
|
||||||
|
.l-time-range-slider-holder,
|
||||||
|
.l-time-range-ticks-holder
|
||||||
|
{
|
||||||
|
box-sizing: border-box;
|
||||||
|
position: relative;
|
||||||
|
&:not(:first-child) {
|
||||||
|
margin-top: $interiorMargin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.l-time-range-slider,
|
||||||
|
.l-time-range-ticks {
|
||||||
|
@include absPosDefault(0, visible);
|
||||||
|
left: $timeRangeSliderLROffset; right: $timeRangeSliderLROffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
.l-time-range-inputs-holder {
|
||||||
|
border-top: 1px solid $colorInteriorBorder;
|
||||||
|
padding-top: $interiorMargin;
|
||||||
|
&.l-flex-row,
|
||||||
|
.l-flex-row {
|
||||||
|
@include align-items(center);
|
||||||
|
.flex-elem {
|
||||||
|
height: auto;
|
||||||
|
line-height: normal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.type-icon {
|
||||||
|
font-size: 120%;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
.l-time-range-input-w,
|
||||||
|
.l-time-range-inputs-elem {
|
||||||
|
margin-right: $interiorMargin;
|
||||||
|
.lbl {
|
||||||
|
color: $colorPlotLabelFg;
|
||||||
|
}
|
||||||
|
.ui-symbol.icon {
|
||||||
|
font-size: 11px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.l-time-range-input-w {
|
||||||
|
// Wraps a datetime text input field
|
||||||
|
position: relative;
|
||||||
|
input[type="text"] {
|
||||||
|
width: 200px;
|
||||||
|
&.picker-icon {
|
||||||
|
padding-right: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.icon-calendar {
|
||||||
|
position: absolute;
|
||||||
|
right: 5px;
|
||||||
|
top: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.l-time-range-slider-holder {
|
||||||
|
height: $r2H;
|
||||||
|
.range-holder {
|
||||||
|
box-shadow: none;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
.range {
|
||||||
|
.toi-line {
|
||||||
|
$myC: $timeControllerToiLineColor;
|
||||||
|
$myW: 8px;
|
||||||
|
@include transform(translateX(50%));
|
||||||
|
position: absolute;
|
||||||
|
top: 0; right: 0; bottom: 0px; left: auto;
|
||||||
|
width: $myW;
|
||||||
|
height: auto;
|
||||||
|
z-index: 2;
|
||||||
|
&:before {
|
||||||
|
// Vert line
|
||||||
|
background-color: $myC;
|
||||||
|
position: absolute;
|
||||||
|
content: "";
|
||||||
|
top: 0; right: auto; bottom: -10px; left: floor($myW/2) - 1;
|
||||||
|
width: 1px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&:hover .toi-line {
|
||||||
|
@include toiLineHovEffects;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&:not(:active) {
|
||||||
|
.knob,
|
||||||
|
.range {
|
||||||
|
@include transition-property(left, right);
|
||||||
|
@include transition-duration(500ms);
|
||||||
|
@include transition-timing-function(ease-in-out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.l-time-range-ticks-holder {
|
||||||
|
height: $r3H;
|
||||||
|
.l-time-range-ticks {
|
||||||
|
border-top: 1px solid $colorTick;
|
||||||
|
.tick {
|
||||||
|
background-color: $colorTick;
|
||||||
|
border:none;
|
||||||
|
height: 5px;
|
||||||
|
width: 1px;
|
||||||
|
margin-left: -1px;
|
||||||
|
position: absolute;
|
||||||
|
&:first-child {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
.l-time-range-tick-label {
|
||||||
|
@include webkitProp(transform, translateX(-50%));
|
||||||
|
color: $colorPlotLabelFg;
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 0.7rem;
|
||||||
|
position: absolute;
|
||||||
|
top: 5px;
|
||||||
|
white-space: nowrap;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.knob {
|
||||||
|
z-index: 2;
|
||||||
|
&:before {
|
||||||
|
$mTB: 2px;
|
||||||
|
$grippyW: 3px;
|
||||||
|
$mLR: ($sliderKnobW - $grippyW)/2;
|
||||||
|
@include bgStripes($c: pullForward($sliderColorKnob, 20%), $a: 1, $bgsize: 4px, $angle: 0deg);
|
||||||
|
content: '';
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
top: $mTB; right: $mLR; bottom: $mTB; left: $mLR;
|
||||||
|
}
|
||||||
|
.range-value {
|
||||||
|
@include trans-prop-nice-fade(.25s);
|
||||||
|
font-size: 0.7rem;
|
||||||
|
position: absolute;
|
||||||
|
height: $r2H;
|
||||||
|
line-height: $r2H;
|
||||||
|
white-space: nowrap;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
&:hover {
|
||||||
|
.range-value {
|
||||||
|
color: $sliderColorKnobHov;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.knob-l {
|
||||||
|
margin-left: $knobM;
|
||||||
|
.range-value {
|
||||||
|
text-align: right;
|
||||||
|
right: $rangeValOffset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.knob-r {
|
||||||
|
margin-right: $knobM;
|
||||||
|
.range-value {
|
||||||
|
left: $rangeValOffset;
|
||||||
|
}
|
||||||
|
&:hover + .range-holder .range .toi-line {
|
||||||
|
@include toiLineHovEffects;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.l-time-domain-selector {
|
||||||
|
position: absolute;
|
||||||
|
right: 0px;
|
||||||
|
top: $interiorMargin;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.s-time-range-val {
|
||||||
|
border-radius: $controlCr;
|
||||||
|
background-color: $colorInputBg;
|
||||||
|
padding: 1px 1px 0 $interiorMargin;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************** MOBILE */
|
||||||
|
|
||||||
|
@include phoneandtablet {
|
||||||
|
.l-time-controller {
|
||||||
|
min-width: 0;
|
||||||
|
.l-time-range-slider-holder,
|
||||||
|
.l-time-range-ticks-holder {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include phone {
|
||||||
|
.l-time-controller {
|
||||||
|
.l-time-range-inputs-holder {
|
||||||
|
&.l-flex-row,
|
||||||
|
.l-flex-row {
|
||||||
|
@include align-items(flex-start);
|
||||||
|
}
|
||||||
|
.l-time-range-inputs-elem {
|
||||||
|
&.type-icon {
|
||||||
|
margin-top: 3px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.t-inputs-w,
|
||||||
|
.l-time-range-inputs-elem {
|
||||||
|
@include flex-direction(column);
|
||||||
|
.l-time-range-input-w:not(:first-child) {
|
||||||
|
&:not(:first-child) {
|
||||||
|
margin-top: $interiorMargin;
|
||||||
|
}
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
.l-time-range-inputs-elem {
|
||||||
|
&.lbl { display: none; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include phonePortrait {
|
||||||
|
.l-time-controller {
|
||||||
|
.l-time-range-inputs-holder {
|
||||||
|
.t-inputs-w,
|
||||||
|
.l-time-range-inputs-elem {
|
||||||
|
@include flex(1 1 auto);
|
||||||
|
padding-top: 25px; // Make room for the ever lovin' Time Domain Selector
|
||||||
|
.flex-elem {
|
||||||
|
@include flex(1 1 auto);
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
input[type="text"] {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.l-time-domain-selector {
|
||||||
|
right: auto;
|
||||||
|
left: 20px;
|
||||||
|
}
|
||||||
|
}
|
@ -26,11 +26,10 @@
|
|||||||
ng-repeat="childObject in composition"
|
ng-repeat="childObject in composition"
|
||||||
ng-style="controller.getFrameStyle(childObject.getId())">
|
ng-style="controller.getFrameStyle(childObject.getId())">
|
||||||
|
|
||||||
<div class="frame child-frame holder contents abs">
|
|
||||||
<mct-representation key="'frame'"
|
<mct-representation key="'frame'"
|
||||||
|
class="frame child-frame holder contents abs"
|
||||||
mct-object="childObject">
|
mct-object="childObject">
|
||||||
</mct-representation>
|
</mct-representation>
|
||||||
</div>
|
|
||||||
<!-- Drag handles -->
|
<!-- Drag handles -->
|
||||||
<span ng-show="domainObject.hasCapability('editor')">
|
<span ng-show="domainObject.hasCapability('editor')">
|
||||||
<span class="edit-handle edit-move"
|
<span class="edit-handle edit-move"
|
||||||
|
@ -229,7 +229,11 @@ define(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Respond to a display bounds change (requery for data)
|
// Respond to a display bounds change (requery for data)
|
||||||
function changeDisplayBounds(event, bounds) {
|
function changeDisplayBounds(event, bounds, follow) {
|
||||||
|
//'hack' for follow mode
|
||||||
|
if (follow === true) {
|
||||||
|
setBasePanZoom(bounds);
|
||||||
|
} else {
|
||||||
var domainAxis = $scope.axes[0];
|
var domainAxis = $scope.axes[0];
|
||||||
|
|
||||||
domainAxis.chooseOption(bounds.domain);
|
domainAxis.chooseOption(bounds.domain);
|
||||||
@ -237,6 +241,8 @@ define(
|
|||||||
setBasePanZoom(bounds);
|
setBasePanZoom(bounds);
|
||||||
requery();
|
requery();
|
||||||
}
|
}
|
||||||
|
self.setUnsynchedStatus($scope.domainObject, follow && self.isZoomed());
|
||||||
|
}
|
||||||
|
|
||||||
this.modeOptions = new PlotModeOptions([], subPlotFactory);
|
this.modeOptions = new PlotModeOptions([], subPlotFactory);
|
||||||
this.updateValues = updateValues;
|
this.updateValues = updateValues;
|
||||||
@ -368,6 +374,12 @@ define(
|
|||||||
return this.pending;
|
return this.pending;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
PlotController.prototype.setUnsynchedStatus = function (domainObject, status) {
|
||||||
|
if (domainObject.hasCapability('status')) {
|
||||||
|
domainObject.getCapability('status').set('timeconductor-unsynced', status);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Export the plot to PNG
|
* Export the plot to PNG
|
||||||
*/
|
*/
|
||||||
|
@ -39,6 +39,7 @@ define(
|
|||||||
mockHandle,
|
mockHandle,
|
||||||
mockDomainObject,
|
mockDomainObject,
|
||||||
mockSeries,
|
mockSeries,
|
||||||
|
mockStatusCapability,
|
||||||
controller;
|
controller;
|
||||||
|
|
||||||
function bind(method, thisObj) {
|
function bind(method, thisObj) {
|
||||||
@ -80,7 +81,7 @@ define(
|
|||||||
);
|
);
|
||||||
mockDomainObject = jasmine.createSpyObj(
|
mockDomainObject = jasmine.createSpyObj(
|
||||||
"domainObject",
|
"domainObject",
|
||||||
["getId", "getModel", "getCapability"]
|
["getId", "getModel", "getCapability", "hasCapability"]
|
||||||
);
|
);
|
||||||
mockHandler = jasmine.createSpyObj(
|
mockHandler = jasmine.createSpyObj(
|
||||||
"telemetrySubscriber",
|
"telemetrySubscriber",
|
||||||
@ -104,6 +105,11 @@ define(
|
|||||||
['getPointCount', 'getDomainValue', 'getRangeValue']
|
['getPointCount', 'getDomainValue', 'getRangeValue']
|
||||||
);
|
);
|
||||||
|
|
||||||
|
mockStatusCapability = jasmine.createSpyObj(
|
||||||
|
"statusCapability",
|
||||||
|
["set"]
|
||||||
|
);
|
||||||
|
|
||||||
mockHandler.handle.andReturn(mockHandle);
|
mockHandler.handle.andReturn(mockHandle);
|
||||||
mockThrottle.andCallFake(function (fn) {
|
mockThrottle.andCallFake(function (fn) {
|
||||||
return fn;
|
return fn;
|
||||||
@ -241,6 +247,34 @@ define(
|
|||||||
expect(bind(controller.unzoom, controller)).not.toThrow();
|
expect(bind(controller.unzoom, controller)).not.toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("sets status when plot becomes detached from time conductor", function () {
|
||||||
|
mockScope.$watch.mostRecentCall.args[1](mockDomainObject);
|
||||||
|
|
||||||
|
function boundsEvent() {
|
||||||
|
fireEvent("telemetry:display:bounds", [
|
||||||
|
{},
|
||||||
|
{ start: 10, end: 100 },
|
||||||
|
true
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
mockDomainObject.hasCapability.andCallFake(function (name) {
|
||||||
|
return name === "status";
|
||||||
|
});
|
||||||
|
mockDomainObject.getCapability.andReturn(mockStatusCapability);
|
||||||
|
spyOn(controller, "isZoomed");
|
||||||
|
|
||||||
|
//Mock zoomed in state
|
||||||
|
controller.isZoomed.andReturn(true);
|
||||||
|
boundsEvent();
|
||||||
|
expect(mockStatusCapability.set).toHaveBeenCalledWith("timeconductor-unsynced", true);
|
||||||
|
|
||||||
|
//"Reset" zoom
|
||||||
|
controller.isZoomed.andReturn(false);
|
||||||
|
boundsEvent();
|
||||||
|
expect(mockStatusCapability.set).toHaveBeenCalledWith("timeconductor-unsynced", false);
|
||||||
|
});
|
||||||
|
|
||||||
it("indicates if a request is pending", function () {
|
it("indicates if a request is pending", function () {
|
||||||
mockScope.$watch.mostRecentCall.args[1](mockDomainObject);
|
mockScope.$watch.mostRecentCall.args[1](mockDomainObject);
|
||||||
expect(controller.isRequestPending()).toBeTruthy();
|
expect(controller.isRequestPending()).toBeTruthy();
|
||||||
@ -297,7 +331,6 @@ define(
|
|||||||
expect(mockHandle.request.calls.length).toEqual(2);
|
expect(mockHandle.request.calls.length).toEqual(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it("maintains externally-provided domain axis bounds after data is received", function () {
|
it("maintains externally-provided domain axis bounds after data is received", function () {
|
||||||
mockSeries.getPointCount.andReturn(3);
|
mockSeries.getPointCount.andReturn(3);
|
||||||
mockSeries.getRangeValue.andReturn(42);
|
mockSeries.getRangeValue.andReturn(42);
|
||||||
|
@ -63,6 +63,28 @@ define(
|
|||||||
this.$scope.loading = false;
|
this.$scope.loading = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
HistoricalTableController.prototype.registerChangeListeners = function () {
|
||||||
|
TableController.prototype.registerChangeListeners.call(this);
|
||||||
|
//Change of bounds in time conductor
|
||||||
|
this.changeListeners.push(this.$scope.$on('telemetry:display:bounds',
|
||||||
|
this.boundsChange.bind(this))
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
HistoricalTableController.prototype.boundsChange = function (event, bounds, follow) {
|
||||||
|
// If in follow mode, don't bother re-subscribing, data will be
|
||||||
|
// received from existing subscription.
|
||||||
|
if (follow !== true) {
|
||||||
|
this.subscribe();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Processes an array of objects, formatting the telemetry available
|
* Processes an array of objects, formatting the telemetry available
|
||||||
* for them and setting it on scope when done
|
* for them and setting it on scope when done
|
||||||
|
@ -96,11 +96,6 @@ define(
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
//Change of bounds in time conductor
|
|
||||||
this.changeListeners.push(this.$scope.$on('telemetry:display:bounds',
|
|
||||||
this.subscribe.bind(this))
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
<input type="text"
|
<input type="text"
|
||||||
ng-required="ngRequired"
|
ng-required="ngRequired"
|
||||||
ng-model="ngModel[field]"
|
ng-model="ngModel[field]"
|
||||||
|
ng-blur="ngBlur()"
|
||||||
ng-pattern="ngPattern"
|
ng-pattern="ngPattern"
|
||||||
size="{{structure.size}}"
|
size="{{structure.size}}"
|
||||||
name="mctControl">
|
name="mctControl">
|
||||||
|
@ -71,6 +71,9 @@ define(
|
|||||||
// Allow controls to trigger blur-like events
|
// Allow controls to trigger blur-like events
|
||||||
ngBlur: "&",
|
ngBlur: "&",
|
||||||
|
|
||||||
|
// Allow controls to trigger blur-like events
|
||||||
|
ngMouseup: "&",
|
||||||
|
|
||||||
// The state of the form value itself
|
// The state of the form value itself
|
||||||
ngModel: "=",
|
ngModel: "=",
|
||||||
|
|
||||||
|
@ -45,6 +45,7 @@ define([
|
|||||||
'../example/scratchpad/bundle',
|
'../example/scratchpad/bundle',
|
||||||
'../example/taxonomy/bundle',
|
'../example/taxonomy/bundle',
|
||||||
'../example/worker/bundle',
|
'../example/worker/bundle',
|
||||||
|
'../example/localTimeSystem/bundle',
|
||||||
|
|
||||||
'../platform/commonUI/about/bundle',
|
'../platform/commonUI/about/bundle',
|
||||||
'../platform/commonUI/browse/bundle',
|
'../platform/commonUI/browse/bundle',
|
||||||
@ -66,6 +67,9 @@ define([
|
|||||||
'../platform/features/clock/bundle',
|
'../platform/features/clock/bundle',
|
||||||
'../platform/features/conductor/bundle',
|
'../platform/features/conductor/bundle',
|
||||||
'../platform/features/fixed/bundle',
|
'../platform/features/fixed/bundle',
|
||||||
|
'../platform/features/conductor-v2/conductor/bundle',
|
||||||
|
'../platform/features/conductor-v2/compatibility/bundle',
|
||||||
|
'../platform/features/conductor-v2/utcTimeSystem/bundle',
|
||||||
'../platform/features/imagery/bundle',
|
'../platform/features/imagery/bundle',
|
||||||
'../platform/features/layout/bundle',
|
'../platform/features/layout/bundle',
|
||||||
'../platform/features/pages/bundle',
|
'../platform/features/pages/bundle',
|
||||||
|
@ -1,3 +1,2 @@
|
|||||||
|
return require('openmct');
|
||||||
return require('main');
|
|
||||||
}));
|
}));
|
@ -63,7 +63,8 @@ requirejs.config({
|
|||||||
"text": "bower_components/text/text",
|
"text": "bower_components/text/text",
|
||||||
"uuid": "bower_components/node-uuid/uuid",
|
"uuid": "bower_components/node-uuid/uuid",
|
||||||
"zepto": "bower_components/zepto/zepto.min",
|
"zepto": "bower_components/zepto/zepto.min",
|
||||||
"lodash": "bower_components/lodash/lodash"
|
"lodash": "bower_components/lodash/lodash",
|
||||||
|
"d3": "bower_components/d3/d3.min"
|
||||||
},
|
},
|
||||||
|
|
||||||
"shim": {
|
"shim": {
|
||||||
@ -87,6 +88,9 @@ requirejs.config({
|
|||||||
},
|
},
|
||||||
"lodash": {
|
"lodash": {
|
||||||
"exports": "lodash"
|
"exports": "lodash"
|
||||||
|
},
|
||||||
|
"d3": {
|
||||||
|
"exports": "d3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user