Compare commits
	
		
			121 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					8b2047ca32 | ||
| 
						 | 
					02c543fddc | ||
| 
						 | 
					b384e84872 | ||
| 
						 | 
					07140b179f | ||
| 
						 | 
					3e9c0eb7a5 | ||
| 
						 | 
					f1d2072bb9 | ||
| 
						 | 
					5babf7274d | ||
| 
						 | 
					2db4aa6235 | ||
| 
						 | 
					3c95c095f1 | ||
| 
						 | 
					49ee5cb74b | ||
| 
						 | 
					98122cc730 | ||
| 
						 | 
					7fcafb6b58 | ||
| 
						 | 
					d77922d66c | ||
| 
						 | 
					2e81550c86 | ||
| 
						 | 
					8eb7585653 | ||
| 
						 | 
					904d56a089 | ||
| 
						 | 
					11e06039ec | ||
| 
						 | 
					a1331b7bb3 | ||
| 
						 | 
					d1960b2f46 | ||
| 
						 | 
					9a06325533 | ||
| 
						 | 
					e639e056ba | ||
| 
						 | 
					fbab890081 | ||
| 
						 | 
					d37dd52ee1 | ||
| 
						 | 
					7af5875dd5 | ||
| 
						 | 
					c6eaa3d528 | ||
| 
						 | 
					4cf6126d35 | ||
| 
						 | 
					4ae6da0334 | ||
| 
						 | 
					ae39343b76 | ||
| 
						 | 
					62ee7e569b | ||
| 
						 | 
					7557a86208 | ||
| 
						 | 
					46e644e6dc | ||
| 
						 | 
					af7954c5a1 | ||
| 
						 | 
					0e0ad64830 | ||
| 
						 | 
					f3fd386e3b | ||
| 
						 | 
					25b9f371e2 | ||
| 
						 | 
					6b482d487b | ||
| 
						 | 
					f96f78ff79 | ||
| 
						 | 
					579233ade9 | ||
| 
						 | 
					9a72c96ea4 | ||
| 
						 | 
					f4e1879a2d | ||
| 
						 | 
					f844495cc1 | ||
| 
						 | 
					900752208f | ||
| 
						 | 
					6501e2eb5f | ||
| 
						 | 
					b9c41107c1 | ||
| 
						 | 
					34c62ba405 | ||
| 
						 | 
					1eea5ce480 | ||
| 
						 | 
					4cd579d274 | ||
| 
						 | 
					11738286df | ||
| 
						 | 
					ca5206d4a0 | ||
| 
						 | 
					573f1f9f99 | ||
| 
						 | 
					c5c45f0a0e | ||
| 
						 | 
					121ab413ff | ||
| 
						 | 
					753bd97c8a | ||
| 
						 | 
					fcd7ab93e5 | ||
| 
						 | 
					c699cb8b4b | ||
| 
						 | 
					a75ea67b8c | ||
| 
						 | 
					9b58aa0052 | ||
| 
						 | 
					579c6b6d24 | ||
| 
						 | 
					762f43fa61 | ||
| 
						 | 
					ce5d0ef5bd | ||
| 
						 | 
					142ee2f336 | ||
| 
						 | 
					482fcbf6ee | ||
| 
						 | 
					523d6743fb | ||
| 
						 | 
					7af22126d4 | ||
| 
						 | 
					8e59072537 | ||
| 
						 | 
					c1bbc4f01d | ||
| 
						 | 
					aa4a5e56f9 | ||
| 
						 | 
					5b2eb72b16 | ||
| 
						 | 
					1b7fc57d21 | ||
| 
						 | 
					a4f6f6f50b | ||
| 
						 | 
					19fd63b850 | ||
| 
						 | 
					c2c8e16453 | ||
| 
						 | 
					a10ded25b4 | ||
| 
						 | 
					da7c636724 | ||
| 
						 | 
					b392633bc6 | ||
| 
						 | 
					ff1678435e | ||
| 
						 | 
					2124fe01e1 | ||
| 
						 | 
					e6d8944547 | ||
| 
						 | 
					ea1defac28 | ||
| 
						 | 
					2a19394334 | ||
| 
						 | 
					f641edbce7 | ||
| 
						 | 
					15a608a861 | ||
| 
						 | 
					334ca64551 | ||
| 
						 | 
					0af49efe06 | ||
| 
						 | 
					4087b9cdde | ||
| 
						 | 
					43a804eef4 | ||
| 
						 | 
					b3a4f52fe2 | ||
| 
						 | 
					671e3016d4 | ||
| 
						 | 
					379828315f | ||
| 
						 | 
					8c5538ec4d | ||
| 
						 | 
					2f9fbfef7f | ||
| 
						 | 
					2baca659ca | ||
| 
						 | 
					8b694ef337 | ||
| 
						 | 
					e193e3dfba | ||
| 
						 | 
					8214c8e895 | ||
| 
						 | 
					33b2225d10 | ||
| 
						 | 
					14463d39a8 | ||
| 
						 | 
					fcfda50e73 | ||
| 
						 | 
					06af84c161 | ||
| 
						 | 
					5238aa2731 | ||
| 
						 | 
					fd29473664 | ||
| 
						 | 
					97f3fd516b | ||
| 
						 | 
					088416905d | ||
| 
						 | 
					2056d87453 | ||
| 
						 | 
					64ce8a2b2a | ||
| 
						 | 
					585da38a16 | ||
| 
						 | 
					bf0e85a94c | ||
| 
						 | 
					84b7a9dc2f | ||
| 
						 | 
					11caa8396a | ||
| 
						 | 
					0017b77439 | ||
| 
						 | 
					7b7b21d748 | ||
| 
						 | 
					788483ec13 | ||
| 
						 | 
					7b19f91ce6 | ||
| 
						 | 
					5cc81ba12a | ||
| 
						 | 
					0a0bc55f5f | ||
| 
						 | 
					4e7b69c4df | ||
| 
						 | 
					cf83040c4b | ||
| 
						 | 
					32f7bc86af | ||
| 
						 | 
					e230b92946 | ||
| 
						 | 
					58ed500ecf | ||
| 
						 | 
					bca5eb0fdb | 
@@ -19,6 +19,8 @@
 | 
			
		||||
    "comma-separated-values": "^3.6.4",
 | 
			
		||||
    "FileSaver.js": "^0.0.2",
 | 
			
		||||
    "zepto": "^1.1.6",
 | 
			
		||||
    "eventemitter3": "^1.2.0",
 | 
			
		||||
    "d3": "~4.1.0",
 | 
			
		||||
    "html2canvas": "^0.4.1"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										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;
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										10
									
								
								main.js
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								main.js
									
									
									
									
									
								
							@@ -27,6 +27,7 @@ requirejs.config({
 | 
			
		||||
        "angular": "bower_components/angular/angular.min",
 | 
			
		||||
        "angular-route": "bower_components/angular-route/angular-route.min",
 | 
			
		||||
        "csv": "bower_components/comma-separated-values/csv.min",
 | 
			
		||||
        "EventEmitter": "bower_components/eventemitter3/index",
 | 
			
		||||
        "es6-promise": "bower_components/es6-promise/es6-promise.min",
 | 
			
		||||
        "html2canvas": "bower_components/html2canvas/build/html2canvas.min",
 | 
			
		||||
        "moment": "bower_components/moment/moment",
 | 
			
		||||
@@ -35,7 +36,8 @@ requirejs.config({
 | 
			
		||||
        "screenfull": "bower_components/screenfull/dist/screenfull.min",
 | 
			
		||||
        "text": "bower_components/text/text",
 | 
			
		||||
        "uuid": "bower_components/node-uuid/uuid",
 | 
			
		||||
        "zepto": "bower_components/zepto/zepto.min"
 | 
			
		||||
        "zepto": "bower_components/zepto/zepto.min",
 | 
			
		||||
        "d3": "bower_components/d3/d3.min"
 | 
			
		||||
    },
 | 
			
		||||
    "shim": {
 | 
			
		||||
        "angular": {
 | 
			
		||||
@@ -47,6 +49,9 @@ requirejs.config({
 | 
			
		||||
        "html2canvas": {
 | 
			
		||||
            "exports": "html2canvas"
 | 
			
		||||
        },
 | 
			
		||||
        "EventEmitter": {
 | 
			
		||||
            "exports": "EventEmitter"
 | 
			
		||||
        },
 | 
			
		||||
        "moment-duration-format": {
 | 
			
		||||
            "deps": ["moment"]
 | 
			
		||||
        },
 | 
			
		||||
@@ -55,6 +60,9 @@ requirejs.config({
 | 
			
		||||
        },
 | 
			
		||||
        "zepto": {
 | 
			
		||||
            "exports": "Zepto"
 | 
			
		||||
        },
 | 
			
		||||
        "d3": {
 | 
			
		||||
            "exports": "d3"
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -43,7 +43,7 @@
 | 
			
		||||
            </mct-representation>
 | 
			
		||||
        </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">
 | 
			
		||||
            <!-- Toolbar and Save/Cancel buttons -->
 | 
			
		||||
            <div class="l-edit-controls flex-elem l-flex-row flex-align-end">
 | 
			
		||||
@@ -59,4 +59,5 @@
 | 
			
		||||
            </mct-representation>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <mct-include key="'conductor'" class="abs holder flex-elem flex-fixed l-flex-row l-time-conductor-holder"></mct-include>
 | 
			
		||||
</div>
 | 
			
		||||
 
 | 
			
		||||
@@ -22,7 +22,8 @@
 | 
			
		||||
<span class='type-icon flex-elem {{type.getCssClass()}}'></span>
 | 
			
		||||
<span class="l-elem-wrapper l-flex-row flex-elem grows">
 | 
			
		||||
    <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
 | 
			
		||||
        key="'menu-arrow'"
 | 
			
		||||
        mct-object='domainObject'
 | 
			
		||||
 
 | 
			
		||||
@@ -66,4 +66,9 @@
 | 
			
		||||
            </mct-representation>
 | 
			
		||||
        </div><!--/ l-object-wrapper-inner -->
 | 
			
		||||
    </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>
 | 
			
		||||
 
 | 
			
		||||
@@ -23,10 +23,12 @@
 | 
			
		||||
define([
 | 
			
		||||
    "./src/FormatProvider",
 | 
			
		||||
    "./src/UTCTimeFormat",
 | 
			
		||||
    "./src/DurationFormat",
 | 
			
		||||
    'legacyRegistry'
 | 
			
		||||
], function (
 | 
			
		||||
    FormatProvider,
 | 
			
		||||
    UTCTimeFormat,
 | 
			
		||||
    DurationFormat,
 | 
			
		||||
    legacyRegistry
 | 
			
		||||
) {
 | 
			
		||||
 | 
			
		||||
@@ -48,6 +50,10 @@ define([
 | 
			
		||||
                {
 | 
			
		||||
                    "key": "utc",
 | 
			
		||||
                    "implementation": UTCTimeFormat
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "key": "duration",
 | 
			
		||||
                    "implementation": DurationFormat
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "constants": [
 | 
			
		||||
@@ -55,6 +61,17 @@ define([
 | 
			
		||||
                    "key": "DEFAULT_TIME_FORMAT",
 | 
			
		||||
                    "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
 | 
			
		||||
     * @memberof 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
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -34,6 +34,11 @@ define([
 | 
			
		||||
            "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
 | 
			
		||||
@@ -46,7 +51,96 @@ define([
 | 
			
		||||
    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];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    UTCTimeFormat.prototype.timeUnits = function (timeRange) {
 | 
			
		||||
        var momentified = moment.duration(timeRange);
 | 
			
		||||
        return [
 | 
			
		||||
            ["Decades", function (r) {
 | 
			
		||||
                return r.years() > 15;
 | 
			
		||||
            }],
 | 
			
		||||
            ["Years", function (r) {
 | 
			
		||||
                return r.years() > 1;
 | 
			
		||||
            }],
 | 
			
		||||
            ["Months", function (r) {
 | 
			
		||||
                return r.years() === 1 || r.months() > 1;
 | 
			
		||||
            }],
 | 
			
		||||
            ["Days", function (r) {
 | 
			
		||||
                return r.months() === 1 || r.days() > 1;
 | 
			
		||||
            }],
 | 
			
		||||
            ["Hours", function (r) {
 | 
			
		||||
                return r.days() === 1 || r.hours() > 1;
 | 
			
		||||
            }],
 | 
			
		||||
            ["Minutes", function (r) {
 | 
			
		||||
                return r.hours() === 1 || r.minutes() > 1;
 | 
			
		||||
            }],
 | 
			
		||||
            ["Seconds", function (r) {
 | 
			
		||||
                return r.minutes() === 1 || r.seconds() > 1;
 | 
			
		||||
            }],
 | 
			
		||||
            ["Milliseconds", function (r) {
 | 
			
		||||
                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";
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										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 {
 | 
			
		||||
            @include flex(1 1 auto);
 | 
			
		||||
        }
 | 
			
		||||
        &.contents-align-right {
 | 
			
		||||
            text-align: right;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    .flex-container {
 | 
			
		||||
        // Apply to wrapping elements, mct-includes, etc.
 | 
			
		||||
 
 | 
			
		||||
@@ -49,7 +49,6 @@ $uePaneMiniTabFontSize: 8px;
 | 
			
		||||
$uePaneMiniTabCollapsedW: 18px;
 | 
			
		||||
$ueEditLeftPaneW: 75%;
 | 
			
		||||
$treeSearchInputBarH: 25px;
 | 
			
		||||
$ueTimeControlH: (33px, 18px, 20px);
 | 
			
		||||
/*************** Panes */
 | 
			
		||||
$ueBrowseLeftPaneTreeMinW: 150px;
 | 
			
		||||
$ueBrowseLeftPaneTreeMaxW: 35%;
 | 
			
		||||
@@ -112,6 +111,7 @@ $bubbleMaxW: 300px;
 | 
			
		||||
$reqSymbolW: 15px;
 | 
			
		||||
$reqSymbolM: $interiorMargin * 2;
 | 
			
		||||
$reqSymbolFontSize: 0.75em;
 | 
			
		||||
$inputTextP: 3px 5px;
 | 
			
		||||
/*************** Wait Spinner Defaults */
 | 
			
		||||
$waitSpinnerD: 32px;
 | 
			
		||||
$waitSpinnerTreeD: 20px;
 | 
			
		||||
 
 | 
			
		||||
@@ -4,4 +4,3 @@
 | 
			
		||||
		@include s-stale();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -39,20 +39,20 @@
 | 
			
		||||
    @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) {
 | 
			
		||||
        from { #{propName}: $propValStart; }
 | 
			
		||||
        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-duration($dur);
 | 
			
		||||
    @include animation-delay($delay);
 | 
			
		||||
    @include animation-fill-mode(both);
 | 
			
		||||
    @include animation-direction(normal);
 | 
			
		||||
    @include animation-iteration-count(1);
 | 
			
		||||
    @include animation-direction($dir);
 | 
			
		||||
    @include animation-iteration-count($count);
 | 
			
		||||
    @include animation-timing-function(ease-in-out);
 | 
			
		||||
}
 | 
			
		||||
@@ -82,7 +82,7 @@ input, textarea {
 | 
			
		||||
input[type="text"],
 | 
			
		||||
input[type="search"] {
 | 
			
		||||
	vertical-align: baseline;
 | 
			
		||||
	padding: 3px 5px;
 | 
			
		||||
	padding: $inputTextP;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
h1, h2, h3 {
 | 
			
		||||
 
 | 
			
		||||
@@ -30,6 +30,7 @@
 | 
			
		||||
 | 
			
		||||
.ui-symbol {
 | 
			
		||||
    font-family: 'symbolsfont';
 | 
			
		||||
    -webkit-font-smoothing: antialiased;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.ui-symbol.icon {
 | 
			
		||||
@@ -70,10 +71,21 @@
 | 
			
		||||
    line-height: inherit;
 | 
			
		||||
    position: relative;
 | 
			
		||||
    &.l-icon-link {
 | 
			
		||||
        .t-item-icon-glyph {
 | 
			
		||||
        &:after {
 | 
			
		||||
            color: $colorIconLink;
 | 
			
		||||
            content: $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;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
/*        .t-item-icon-glyph {
 | 
			
		||||
            &:after {
 | 
			
		||||
                color: $colorIconLink;
 | 
			
		||||
                content: $glyph-icon-link;
 | 
			
		||||
                content: '\e921'; //$glyph-icon-link;
 | 
			
		||||
                height: auto; width: auto;
 | 
			
		||||
                position: absolute;
 | 
			
		||||
                left: 0; top: 0; right: 0; bottom: 20%;
 | 
			
		||||
@@ -81,6 +93,6 @@
 | 
			
		||||
                @include transform(scale(0.3));
 | 
			
		||||
                z-index: 2;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        }*/
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -22,6 +22,7 @@
 | 
			
		||||
@import "effects";
 | 
			
		||||
@import "global";
 | 
			
		||||
@import "glyphs";
 | 
			
		||||
@import "animations";
 | 
			
		||||
@import "archetypes";
 | 
			
		||||
@import "about";
 | 
			
		||||
@import "text";
 | 
			
		||||
@@ -41,7 +42,6 @@
 | 
			
		||||
@import "controls/lists";
 | 
			
		||||
@import "controls/menus";
 | 
			
		||||
@import "controls/messages";
 | 
			
		||||
@import "controls/time-controller";
 | 
			
		||||
@import "mobile/controls/menus";
 | 
			
		||||
 | 
			
		||||
/********************************* FORMS */
 | 
			
		||||
 
 | 
			
		||||
@@ -185,21 +185,15 @@
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@mixin sliderTrack($bg: $scrollbarTrackColorBg) {
 | 
			
		||||
    //$b: 1px solid lighten($bg, 30%);
 | 
			
		||||
    border-radius: 2px;
 | 
			
		||||
    box-sizing: border-box;
 | 
			
		||||
    @include boxIncised(0.7);
 | 
			
		||||
    background-color: $bg;
 | 
			
		||||
    //border-bottom: $b;
 | 
			
		||||
    //border-right: $b;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@mixin controlGrippy($b, $direction: horizontal, $w: 1px, $style: dotted) {
 | 
			
		||||
    //&:before {
 | 
			
		||||
    //@include trans-prop-nice("border-color", 25ms);
 | 
			
		||||
    content: '';
 | 
			
		||||
    display: block;
 | 
			
		||||
    //height: auto;
 | 
			
		||||
    pointer-events: none;
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    z-index: 2;
 | 
			
		||||
@@ -274,16 +268,6 @@
 | 
			
		||||
    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) {
 | 
			
		||||
	@return $p / 100%;
 | 
			
		||||
}
 | 
			
		||||
@@ -304,7 +288,6 @@
 | 
			
		||||
	border-radius: $controlCr;
 | 
			
		||||
	box-sizing: border-box;
 | 
			
		||||
	color: $fg;
 | 
			
		||||
	//display: inline-block;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@mixin btnBase($bg: $colorBtnBg, $bgHov: $colorBtnBgHov, $fg: $colorBtnFg, $fgHov: $colorBtnFgHov, $ic: $colorBtnIcon, $icHov: $colorBtnIconHov) {
 | 
			
		||||
 
 | 
			
		||||
@@ -296,8 +296,6 @@ input[type="search"] {
 | 
			
		||||
    .title-label {
 | 
			
		||||
        color: $colorObjHdrTxt;
 | 
			
		||||
        @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 {
 | 
			
		||||
@@ -308,6 +306,10 @@ input[type="search"] {
 | 
			
		||||
        font-size: 0.7em;
 | 
			
		||||
        @include flex(0 0 1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .t-object-alert {
 | 
			
		||||
        display: none;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/******************************************************** 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 */
 | 
			
		||||
.l-datetime-picker {
 | 
			
		||||
    $r1H: 15px;
 | 
			
		||||
 
 | 
			
		||||
@@ -178,7 +178,7 @@
 | 
			
		||||
	}
 | 
			
		||||
	.pane {
 | 
			
		||||
		box-sizing: border-box;
 | 
			
		||||
		&.left {
 | 
			
		||||
		&.menu-items {
 | 
			
		||||
			border-right: 1px solid pullForward($colorMenuBg, 10%);
 | 
			
		||||
			left: 0;
 | 
			
		||||
			padding-right: $interiorMargin;
 | 
			
		||||
@@ -194,38 +194,53 @@
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		&.right {
 | 
			
		||||
		&.menu-item-description {
 | 
			
		||||
			left: auto;
 | 
			
		||||
			right: 0;
 | 
			
		||||
			padding: $interiorMargin * 5;
 | 
			
		||||
			width: $prw;
 | 
			
		||||
            .desc-area {
 | 
			
		||||
                &.icon {
 | 
			
		||||
                    color: $colorCreateMenuLgIcon;
 | 
			
		||||
                    font-size: 8em;
 | 
			
		||||
                    margin-bottom: $interiorMargin * 3;
 | 
			
		||||
                    position: relative;
 | 
			
		||||
                    text-align: center;
 | 
			
		||||
                }
 | 
			
		||||
                &.title {
 | 
			
		||||
                    color: $colorCreateMenuText;
 | 
			
		||||
                    font-size: 1.2em;
 | 
			
		||||
                    margin-bottom: $interiorMargin * 2;
 | 
			
		||||
                }
 | 
			
		||||
                &.description {
 | 
			
		||||
                    color: pushBack($colorCreateMenuText, 20%);
 | 
			
		||||
                    font-size: 0.8em;
 | 
			
		||||
                    line-height: 1.5em;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	.menu-item-description {
 | 
			
		||||
		.desc-area {
 | 
			
		||||
			&.icon {
 | 
			
		||||
				$h: 150px;
 | 
			
		||||
				color: $colorCreateMenuLgIcon;
 | 
			
		||||
				position: relative;
 | 
			
		||||
				font-size: 8em;
 | 
			
		||||
				left: 0;
 | 
			
		||||
				height: $h;
 | 
			
		||||
				line-height: $h;
 | 
			
		||||
				margin-bottom: $interiorMargin * 5;
 | 
			
		||||
				text-align: center;
 | 
			
		||||
			}
 | 
			
		||||
			&.title {
 | 
			
		||||
				color: $colorCreateMenuText;
 | 
			
		||||
				font-size: 1.2em;
 | 
			
		||||
				margin-bottom: 0.5em;
 | 
			
		||||
			}
 | 
			
		||||
			&.description {
 | 
			
		||||
				color: $colorCreateMenuText;
 | 
			
		||||
				font-size: 0.8em;
 | 
			
		||||
				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 {
 | 
			
		||||
	font-size: 0.80rem;
 | 
			
		||||
@@ -262,3 +277,7 @@
 | 
			
		||||
	right: 0;
 | 
			
		||||
	width: auto;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.menus-up .menu {
 | 
			
		||||
    bottom: $btnStdH; top: auto;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -345,3 +345,29 @@ body.desktop .t-message-single {
 | 
			
		||||
body.desktop .t-message-list {
 | 
			
		||||
    .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 {
 | 
			
		||||
	border: 1px solid transparent;
 | 
			
		||||
	&.paused {
 | 
			
		||||
		border-color: $colorPausedBg;
 | 
			
		||||
		@extend .s-unsynced;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -19,15 +19,6 @@
 | 
			
		||||
 * this source code distribution or the Licensing information page available
 | 
			
		||||
 * 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) {
 | 
			
		||||
    @include transform-origin(center);
 | 
			
		||||
    @include animation-name(rotation-centered);
 | 
			
		||||
 
 | 
			
		||||
@@ -128,7 +128,7 @@
 | 
			
		||||
        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
 | 
			
		||||
        z-index: 4;
 | 
			
		||||
    }
 | 
			
		||||
@@ -212,6 +212,8 @@ body.desktop .pane .mini-tab-icon.toggle-pane {
 | 
			
		||||
        .holder-object {
 | 
			
		||||
            top: $bodyMargin;
 | 
			
		||||
            bottom: $interiorMargin;
 | 
			
		||||
            // Clip element that have min-widths
 | 
			
		||||
            overflow: hidden;
 | 
			
		||||
        }
 | 
			
		||||
        .holder-inspector {
 | 
			
		||||
            top: $bodyMargin;
 | 
			
		||||
 
 | 
			
		||||
@@ -23,6 +23,8 @@
 | 
			
		||||
    <input type="text"
 | 
			
		||||
           ng-model="textValue"
 | 
			
		||||
           ng-blur="restoreTextValue(); ngBlur()"
 | 
			
		||||
           ng-mouseup="ngMouseup()"
 | 
			
		||||
           ng-disabled="ngDisabled"
 | 
			
		||||
           ng-class="{
 | 
			
		||||
                        error: textInvalid ||
 | 
			
		||||
                            (structure.validate &&
 | 
			
		||||
 
 | 
			
		||||
@@ -116,6 +116,7 @@ $colorProgressBarAmt: $colorKey;
 | 
			
		||||
$progressBarHOverlay: 15px;
 | 
			
		||||
$progressBarStripeW: 20px;
 | 
			
		||||
$shdwStatusIc: rgba(black, 0.4) 0 1px 2px;
 | 
			
		||||
$animPausedPulseDur: 500ms;
 | 
			
		||||
 | 
			
		||||
// Selects
 | 
			
		||||
$colorSelectBg: $colorBtnBg;
 | 
			
		||||
 
 | 
			
		||||
@@ -116,6 +116,7 @@ $colorProgressBarAmt: #0a0;
 | 
			
		||||
$progressBarHOverlay: 15px;
 | 
			
		||||
$progressBarStripeW: 20px;
 | 
			
		||||
$shdwStatusIc: rgba(white, 0.8) 0 0px 5px;
 | 
			
		||||
$animPausedPulseDur: 1s;
 | 
			
		||||
 | 
			
		||||
// Selects
 | 
			
		||||
$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;
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
							
								
								
									
										146
									
								
								platform/features/conductor-v2/conductor/bundle.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										146
									
								
								platform/features/conductor-v2/conductor/bundle.js
									
									
									
									
									
										Normal file
									
								
							@@ -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([
 | 
			
		||||
    "./src/ui/TimeConductorViewService",
 | 
			
		||||
    "./src/ui/TimeConductorController",
 | 
			
		||||
    "./src/TimeConductor",
 | 
			
		||||
    "./src/ui/ConductorAxisController",
 | 
			
		||||
    "./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,
 | 
			
		||||
    ConductorAxisController,
 | 
			
		||||
    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[]",
 | 
			
		||||
                        "formatService"
 | 
			
		||||
                    ]
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "key": "ConductorAxisController",
 | 
			
		||||
                    "implementation": ConductorAxisController,
 | 
			
		||||
                    "depends": [
 | 
			
		||||
                        "timeConductor",
 | 
			
		||||
                        "formatService",
 | 
			
		||||
                        "timeConductorViewService"
 | 
			
		||||
                    ]
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "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,435 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * 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;
 | 
			
		||||
        pointer-events: none;
 | 
			
		||||
        .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';
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            .l-time-conductor-inputs {
 | 
			
		||||
                pointer-events: auto;
 | 
			
		||||
            }
 | 
			
		||||
            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,131 @@
 | 
			
		||||
<!-- Parent holder for time conductor. follow-mode | fixed-mode -->
 | 
			
		||||
<style>
 | 
			
		||||
    .fixed-mode .l-axis-holder {
 | 
			
		||||
        cursor: grab;
 | 
			
		||||
        cursor: -webkit-grab;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .fixed-mode .l-axis-holder:active {
 | 
			
		||||
        cursor: grabbing;
 | 
			
		||||
        cursor: -webkit-grabbing;
 | 
			
		||||
    }
 | 
			
		||||
</style>
 | 
			
		||||
<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"
 | 
			
		||||
        ng-class="{'status-panning': panning}">
 | 
			
		||||
 | 
			
		||||
    <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-conductor-inputs">
 | 
			
		||||
                        <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>
 | 
			
		||||
                <span class="l-time-range-w end-w">
 | 
			
		||||
                    <span class="l-time-conductor-inputs">
 | 
			
		||||
                        <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>
 | 
			
		||||
                </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">{{timeUnits}}</span>
 | 
			
		||||
                <input class="time-conductor-zoom flex-elem" type="range"
 | 
			
		||||
                       ng-model="currentZoom"
 | 
			
		||||
                       ng-mouseUp="tcController.zoomStop(currentZoom)"
 | 
			
		||||
                       ng-change="tcController.zoomDrag(currentZoom)"
 | 
			
		||||
                       min="0.01"
 | 
			
		||||
                       step="0.01"
 | 
			
		||||
                       max="0.99" />
 | 
			
		||||
            </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,105 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * 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');
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /***
 | 
			
		||||
     *
 | 
			
		||||
     * @typedef {object} TimeConductorZoom
 | 
			
		||||
     * @property {number} min The largest time span that the time
 | 
			
		||||
     * conductor can display in this time system
 | 
			
		||||
     * @property {number} max The smallest time span that the time
 | 
			
		||||
     * conductor can display in this time system
 | 
			
		||||
     *
 | 
			
		||||
     * @typedef {object} TimeSystemDefault
 | 
			
		||||
     * @property {TimeConductorDeltas} deltas The deltas to apply by default
 | 
			
		||||
     * when this time system is active. Applies to real-time modes only
 | 
			
		||||
     * @property {TimeConductorBounds} bounds The bounds to apply by default
 | 
			
		||||
     * when this time system is active
 | 
			
		||||
     * @property {TimeConductorZoom} zoom Default min and max zoom levels
 | 
			
		||||
     * @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,196 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * 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 ConductorAxisController(conductor, formatService, conductorViewService) {
 | 
			
		||||
            // Dependencies
 | 
			
		||||
            this.d3 = d3;
 | 
			
		||||
            this.formatService = formatService;
 | 
			
		||||
            this.conductor = conductor;
 | 
			
		||||
            this.conductorViewService = conductorViewService;
 | 
			
		||||
 | 
			
		||||
            // Runtime properties (set by 'link' function)
 | 
			
		||||
            this.target = undefined;
 | 
			
		||||
            this.xScale = undefined;
 | 
			
		||||
            this.xAxis = undefined;
 | 
			
		||||
            this.axisElement = undefined;
 | 
			
		||||
            this.initialized = false;
 | 
			
		||||
            this.msPerPixel = undefined;
 | 
			
		||||
 | 
			
		||||
            this.bounds = conductor.bounds();
 | 
			
		||||
            this.timeSystem = conductor.timeSystem();
 | 
			
		||||
 | 
			
		||||
            //Bind all class functions to 'this'
 | 
			
		||||
            Object.keys(ConductorAxisController.prototype).filter(function (key) {
 | 
			
		||||
                return typeof ConductorAxisController.prototype[key] === 'function';
 | 
			
		||||
            }).forEach(function (key) {
 | 
			
		||||
                this[key] = ConductorAxisController.prototype[key].bind(this);
 | 
			
		||||
            }.bind(this));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ConductorAxisController.prototype.destroy = function () {
 | 
			
		||||
            this.conductor.off('timeSystem', this.changeTimeSystem);
 | 
			
		||||
            this.conductor.off('bounds', this.setScale);
 | 
			
		||||
            this.conductorViewService.off("zoom", this.onZoom);
 | 
			
		||||
            this.conductorViewService.off("zoom-stop", this.onZoomStop)
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        ConductorAxisController.prototype.changeBounds = function (bounds) {
 | 
			
		||||
            this.bounds = bounds;
 | 
			
		||||
            if (this.initialized && !this.zooming) {
 | 
			
		||||
                this.setScale();
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        ConductorAxisController.prototype.setScale = function () {
 | 
			
		||||
            var width = this.target.offsetWidth;
 | 
			
		||||
            var timeSystem = this.conductor.timeSystem();
 | 
			
		||||
            var bounds = this.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);
 | 
			
		||||
 | 
			
		||||
            this.msPerPixel = (bounds.end - bounds.start) / width;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        ConductorAxisController.prototype.changeTimeSystem = function (timeSystem) {
 | 
			
		||||
            this.timeSystem = timeSystem;
 | 
			
		||||
 | 
			
		||||
            var key = timeSystem.formats()[0];
 | 
			
		||||
            if (this.initialized && 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);
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        ConductorAxisController.prototype.link = function (scope, element) {
 | 
			
		||||
            this.target = element[0].firstChild;
 | 
			
		||||
            this.scope = scope;
 | 
			
		||||
            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) + ")");
 | 
			
		||||
 | 
			
		||||
            this.initialized = true;
 | 
			
		||||
 | 
			
		||||
            if (this.timeSystem !== undefined) {
 | 
			
		||||
                this.changeTimeSystem(this.timeSystem);
 | 
			
		||||
                this.setScale();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            //Respond to changes in conductor
 | 
			
		||||
            this.conductor.on("timeSystem", this.changeTimeSystem);
 | 
			
		||||
            this.conductor.on("bounds", this.changeBounds);
 | 
			
		||||
 | 
			
		||||
            this.scope.$on("$destroy", this.destroy);
 | 
			
		||||
 | 
			
		||||
            this.conductorViewService.on("zoom", this.onZoom);
 | 
			
		||||
            this.conductorViewService.on("zoom-stop", this.onZoomStop);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        ConductorAxisController.prototype.panStop = function () {
 | 
			
		||||
            //resync view bounds with time conductor bounds
 | 
			
		||||
            this.conductorViewService.emit("pan-stop");
 | 
			
		||||
            this.conductor.bounds(this.bounds);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        ConductorAxisController.prototype.onZoom = function (zoom) {
 | 
			
		||||
            this.zooming = true;
 | 
			
		||||
 | 
			
		||||
            this.bounds = zoom.bounds;
 | 
			
		||||
            this.setScale();
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        ConductorAxisController.prototype.onZoomStop = function (zoom) {
 | 
			
		||||
            this.zooming = false;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        ConductorAxisController.prototype.pan = function (delta) {
 | 
			
		||||
            if (!this.conductor.follow()) {
 | 
			
		||||
                var deltaInMs = delta[0] * this.msPerPixel;
 | 
			
		||||
                var bounds = this.conductor.bounds();
 | 
			
		||||
                var start = Math.floor((bounds.start - deltaInMs) / 1000) * 1000;
 | 
			
		||||
                var end = Math.floor((bounds.end - deltaInMs) / 1000) * 1000;
 | 
			
		||||
                this.bounds = {
 | 
			
		||||
                    start: start,
 | 
			
		||||
                    end: end
 | 
			
		||||
                };
 | 
			
		||||
                this.setScale();
 | 
			
		||||
                this.conductorViewService.emit("pan", this.bounds);
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        ConductorAxisController.prototype.resize = function () {
 | 
			
		||||
            if (this.initialized) {
 | 
			
		||||
                this.setScale();
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        return ConductorAxisController;
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -0,0 +1,52 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * 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 MctConductorAxis() {
 | 
			
		||||
            /**
 | 
			
		||||
             * The mct-conductor-axis renders a horizontal axis with regular
 | 
			
		||||
             * labelled 'ticks'. It requires 'start' and 'end' integer values to
 | 
			
		||||
             * be specified as attributes.
 | 
			
		||||
             */
 | 
			
		||||
 | 
			
		||||
            return {
 | 
			
		||||
                controller: 'ConductorAxisController',
 | 
			
		||||
                controllerAs: 'axis',
 | 
			
		||||
                link: function(scope, element, attrs, controller){
 | 
			
		||||
                    controller.link(scope, element);
 | 
			
		||||
                },
 | 
			
		||||
 | 
			
		||||
                restrict: 'E',
 | 
			
		||||
                priority: 1000,
 | 
			
		||||
 | 
			
		||||
                template: '<div class="l-axis-holder" ' +
 | 
			
		||||
                '    mct-drag-down="axis.panStart()"' +
 | 
			
		||||
                '    mct-drag-up="axis.panStop(delta)"' +
 | 
			
		||||
                '    mct-drag="axis.pan(delta)"' +
 | 
			
		||||
                '    mct-resize="axis.resize()"></div>'
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return MctConductorAxis;
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
@@ -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,317 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * 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, formatService) {
 | 
			
		||||
 | 
			
		||||
            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);
 | 
			
		||||
            this.formatService = formatService;
 | 
			
		||||
 | 
			
		||||
            // 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.changeBounds);
 | 
			
		||||
            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.conductorViewService.on('pan', this.onPan);
 | 
			
		||||
            this.conductorViewService.on('pan-stop', this.onPanStop);
 | 
			
		||||
 | 
			
		||||
            this.$scope.$on('$destroy', this.destroy);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        TimeConductorController.prototype.destroy = function () {
 | 
			
		||||
            this.conductor.off('bounds', this.setFormFromBounds);
 | 
			
		||||
            this.conductor.off('timeSystem', this.changeTimeSystem);
 | 
			
		||||
 | 
			
		||||
            this.conductorViewService.off('pan', this.onPan);
 | 
			
		||||
            this.conductorViewService.off('pan-stop', this.onPanStop);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        TimeConductorController.prototype.onPan = function (bounds) {
 | 
			
		||||
            this.$scope.panning = true;
 | 
			
		||||
            this.$scope.boundsModel.start = bounds.start;
 | 
			
		||||
            this.$scope.boundsModel.end = bounds.end;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        TimeConductorController.prototype.onPanStop = function () {
 | 
			
		||||
            this.$scope.panning = false;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        TimeConductorController.prototype.changeBounds = function (bounds) {
 | 
			
		||||
            if (!this.$scope.zooming && !this.$scope.panning) {
 | 
			
		||||
                this.setFormFromBounds(bounds);
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * 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) {
 | 
			
		||||
            if (!this.$scope.zooming && ! this.$scope.panning) {
 | 
			
		||||
                this.$scope.boundsModel.start = bounds.start;
 | 
			
		||||
                this.$scope.boundsModel.end = bounds.end;
 | 
			
		||||
 | 
			
		||||
                this.$scope.currentZoom = this.toSliderValue(bounds.end - bounds.start);
 | 
			
		||||
                this.toTimeUnits(bounds.end - bounds.start);
 | 
			
		||||
 | 
			
		||||
                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) {
 | 
			
		||||
            var timeSystemModel = this.$scope.timeSystemModel;
 | 
			
		||||
            timeSystemModel.selected = timeSystem;
 | 
			
		||||
            timeSystemModel.format = timeSystem.formats()[0];
 | 
			
		||||
            timeSystemModel.deltaFormat = timeSystem.deltaFormat();
 | 
			
		||||
            timeSystemModel.minZoom = timeSystem.defaults().zoom.min;
 | 
			
		||||
            timeSystemModel.maxZoom = timeSystem.defaults().zoom.max;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * 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);
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        TimeConductorController.prototype.toSliderValue = function (timeSpan) {
 | 
			
		||||
            var timeSystem = this.conductor.timeSystem();
 | 
			
		||||
            if (timeSystem) {
 | 
			
		||||
                var zoomDefaults = this.conductor.timeSystem().defaults().zoom;
 | 
			
		||||
                var perc = timeSpan / (zoomDefaults.min - zoomDefaults.max);
 | 
			
		||||
                return 1 - Math.pow(perc, 1 / 4);
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        TimeConductorController.prototype.toTimeUnits = function (timeSpan) {
 | 
			
		||||
            if (this.conductor.timeSystem()) {
 | 
			
		||||
                var timeFormat = this.formatService.getFormat(this.conductor.timeSystem().formats()[0]);
 | 
			
		||||
                this.$scope.timeUnits = timeFormat.timeUnits && timeFormat.timeUnits(timeSpan);
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        TimeConductorController.prototype.zoomDrag = function(sliderValue) {
 | 
			
		||||
            var zoomDefaults = this.conductor.timeSystem().defaults().zoom;
 | 
			
		||||
            var timeSpan = Math.pow((1 - sliderValue), 4) * (zoomDefaults.min - zoomDefaults.max);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            var zoom = this.conductorViewService.zoom(timeSpan);
 | 
			
		||||
 | 
			
		||||
            this.$scope.boundsModel.start = zoom.bounds.start;
 | 
			
		||||
            this.$scope.boundsModel.end = zoom.bounds.end;
 | 
			
		||||
            this.toTimeUnits(zoom.bounds.end - zoom.bounds.start);
 | 
			
		||||
 | 
			
		||||
            if (zoom.deltas) {
 | 
			
		||||
                this.setFormFromDeltas(zoom.deltas);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            this.$scope.zooming = true;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        TimeConductorController.prototype.zoomStop = function () {
 | 
			
		||||
            this.updateBoundsFromForm(this.$scope.boundsModel);
 | 
			
		||||
            this.updateDeltasFromForm(this.$scope.boundsModel);
 | 
			
		||||
 | 
			
		||||
            this.$scope.zooming = false;
 | 
			
		||||
            this.conductorViewService.emit('zoom-stop');
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        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,234 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * 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 bounds = this.calculateBoundsFromDeltas(deltas);
 | 
			
		||||
                this.dlts = deltas;
 | 
			
		||||
                if (this.metadata().key!=='fixed') {
 | 
			
		||||
                    this.conductor.bounds(bounds);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            return this.dlts;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        TimeConductorMode.prototype.calculateBoundsFromDeltas = function (deltas) {
 | 
			
		||||
            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;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var bounds = {
 | 
			
		||||
                start: oldEnd - deltas.start,
 | 
			
		||||
                end: oldEnd + deltas.end
 | 
			
		||||
            };
 | 
			
		||||
            return bounds;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Performs zoom calculation. Will calculate new bounds and deltas
 | 
			
		||||
         * based on desired timeSpan
 | 
			
		||||
         * @param timeSpan
 | 
			
		||||
         */
 | 
			
		||||
        TimeConductorMode.prototype.calculateZoom = function (timeSpan) {
 | 
			
		||||
            var zoom = {};
 | 
			
		||||
 | 
			
		||||
            // If a tick source is defined, then the concept of 'now' is
 | 
			
		||||
            // important. Calculate zoom based on 'now'.
 | 
			
		||||
            if (this.tickSource()){
 | 
			
		||||
                zoom.deltas = {
 | 
			
		||||
                    start: timeSpan,
 | 
			
		||||
                    end: this.dlts.end
 | 
			
		||||
                };
 | 
			
		||||
                zoom.bounds = this.calculateBoundsFromDeltas(zoom.deltas);
 | 
			
		||||
                // Calculate bounds based on deltas;
 | 
			
		||||
            } else {
 | 
			
		||||
                var bounds = this.conductor.bounds();
 | 
			
		||||
                var center = bounds.start + ((bounds.end - bounds.start)) / 2;
 | 
			
		||||
                bounds.start = center - timeSpan / 2;
 | 
			
		||||
                bounds.end = center + timeSpan / 2;
 | 
			
		||||
                zoom.bounds = bounds;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return zoom;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        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,214 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * 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',
 | 
			
		||||
        './TimeConductorMode'
 | 
			
		||||
    ],
 | 
			
		||||
    function (EventEmitter, 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) {
 | 
			
		||||
 | 
			
		||||
            EventEmitter.call(this);
 | 
			
		||||
 | 
			
		||||
            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;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        TimeConductorViewService.prototype = Object.create(EventEmitter.prototype);
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * 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();
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        TimeConductorViewService.prototype.zoom = function (timeSpan) {
 | 
			
		||||
            var zoom = this.currentMode.calculateZoom(timeSpan);
 | 
			
		||||
            this.emit("zoom", zoom);
 | 
			
		||||
            return zoom;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        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,82 @@
 | 
			
		||||
/*****************************************************************************
 | 
			
		||||
 * 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 () {
 | 
			
		||||
        var now = Math.ceil(Date.now() / 1000) * 1000;
 | 
			
		||||
        var ONE_MINUTE = 60 * 1 * 1000;
 | 
			
		||||
        var FIFTY_YEARS = 50 * 365 * 24 * 60 * 60 * 1000;
 | 
			
		||||
 | 
			
		||||
        return {
 | 
			
		||||
            key: 'utc-default',
 | 
			
		||||
            name: 'UTC time system defaults',
 | 
			
		||||
            deltas: {start: FIFTEEN_MINUTES, end: 0},
 | 
			
		||||
            bounds: {start: now - FIFTEEN_MINUTES, end: now},
 | 
			
		||||
            zoom: {min: FIFTY_YEARS, max: ONE_MINUTE}
 | 
			
		||||
        };
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    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": [
 | 
			
		||||
                {
 | 
			
		||||
                    "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-style="controller.getFrameStyle(childObject.getId())">
 | 
			
		||||
 | 
			
		||||
        <div class="frame child-frame holder contents abs">
 | 
			
		||||
            <mct-representation key="'frame'"
 | 
			
		||||
                                mct-object="childObject">
 | 
			
		||||
            </mct-representation>
 | 
			
		||||
        </div>
 | 
			
		||||
        <mct-representation key="'frame'"
 | 
			
		||||
                            class="frame child-frame holder contents abs"
 | 
			
		||||
                            mct-object="childObject">
 | 
			
		||||
        </mct-representation>
 | 
			
		||||
        <!-- Drag handles -->
 | 
			
		||||
        <span ng-show="domainObject.hasCapability('editor')">
 | 
			
		||||
            <span class="edit-handle edit-move"
 | 
			
		||||
 
 | 
			
		||||
@@ -229,13 +229,19 @@ define(
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Respond to a display bounds change (requery for data)
 | 
			
		||||
            function changeDisplayBounds(event, bounds) {
 | 
			
		||||
                var domainAxis = $scope.axes[0];
 | 
			
		||||
            function changeDisplayBounds(event, bounds, follow) {
 | 
			
		||||
                //'hack' for follow mode
 | 
			
		||||
                if (follow === true) {
 | 
			
		||||
                    setBasePanZoom(bounds);
 | 
			
		||||
                } else {
 | 
			
		||||
                    var domainAxis = $scope.axes[0];
 | 
			
		||||
 | 
			
		||||
                domainAxis.chooseOption(bounds.domain);
 | 
			
		||||
                updateDomainFormat();
 | 
			
		||||
                setBasePanZoom(bounds);
 | 
			
		||||
                requery();
 | 
			
		||||
                    domainAxis.chooseOption(bounds.domain);
 | 
			
		||||
                    updateDomainFormat();
 | 
			
		||||
                    setBasePanZoom(bounds);
 | 
			
		||||
                    requery();
 | 
			
		||||
                }
 | 
			
		||||
                self.setUnsynchedStatus($scope.domainObject, follow && self.isZoomed());
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            this.modeOptions = new PlotModeOptions([], subPlotFactory);
 | 
			
		||||
@@ -368,6 +374,12 @@ define(
 | 
			
		||||
            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
 | 
			
		||||
         */
 | 
			
		||||
 
 | 
			
		||||
@@ -39,6 +39,7 @@ define(
 | 
			
		||||
                mockHandle,
 | 
			
		||||
                mockDomainObject,
 | 
			
		||||
                mockSeries,
 | 
			
		||||
                mockStatusCapability,
 | 
			
		||||
                controller;
 | 
			
		||||
 | 
			
		||||
            function bind(method, thisObj) {
 | 
			
		||||
@@ -80,7 +81,7 @@ define(
 | 
			
		||||
                );
 | 
			
		||||
                mockDomainObject = jasmine.createSpyObj(
 | 
			
		||||
                    "domainObject",
 | 
			
		||||
                    ["getId", "getModel", "getCapability"]
 | 
			
		||||
                    ["getId", "getModel", "getCapability", "hasCapability"]
 | 
			
		||||
                );
 | 
			
		||||
                mockHandler = jasmine.createSpyObj(
 | 
			
		||||
                    "telemetrySubscriber",
 | 
			
		||||
@@ -104,6 +105,11 @@ define(
 | 
			
		||||
                    ['getPointCount', 'getDomainValue', 'getRangeValue']
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
                mockStatusCapability = jasmine.createSpyObj(
 | 
			
		||||
                    "statusCapability",
 | 
			
		||||
                    ["set"]
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
                mockHandler.handle.andReturn(mockHandle);
 | 
			
		||||
                mockThrottle.andCallFake(function (fn) {
 | 
			
		||||
                    return fn;
 | 
			
		||||
@@ -241,6 +247,34 @@ define(
 | 
			
		||||
                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 () {
 | 
			
		||||
                mockScope.$watch.mostRecentCall.args[1](mockDomainObject);
 | 
			
		||||
                expect(controller.isRequestPending()).toBeTruthy();
 | 
			
		||||
@@ -297,7 +331,6 @@ define(
 | 
			
		||||
                expect(mockHandle.request.calls.length).toEqual(2);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            it("maintains externally-provided domain axis bounds after data is received", function () {
 | 
			
		||||
                mockSeries.getPointCount.andReturn(3);
 | 
			
		||||
                mockSeries.getRangeValue.andReturn(42);
 | 
			
		||||
 
 | 
			
		||||
@@ -63,6 +63,28 @@ define(
 | 
			
		||||
            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
 | 
			
		||||
         * 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"
 | 
			
		||||
               ng-required="ngRequired"
 | 
			
		||||
               ng-model="ngModel[field]"
 | 
			
		||||
               ng-blur="ngBlur()"
 | 
			
		||||
               ng-pattern="ngPattern"
 | 
			
		||||
               size="{{structure.size}}"
 | 
			
		||||
               name="mctControl">
 | 
			
		||||
 
 | 
			
		||||
@@ -71,6 +71,9 @@ define(
 | 
			
		||||
                    // Allow controls to trigger blur-like events
 | 
			
		||||
                    ngBlur: "&",
 | 
			
		||||
 | 
			
		||||
                    // Allow controls to trigger blur-like events
 | 
			
		||||
                    ngMouseup: "&",
 | 
			
		||||
 | 
			
		||||
                    // The state of the form value itself
 | 
			
		||||
                    ngModel: "=",
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										10
									
								
								test-main.js
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								test-main.js
									
									
									
									
									
								
							@@ -53,6 +53,7 @@ requirejs.config({
 | 
			
		||||
        "angular": "bower_components/angular/angular.min",
 | 
			
		||||
        "angular-route": "bower_components/angular-route/angular-route.min",
 | 
			
		||||
        "csv": "bower_components/comma-separated-values/csv.min",
 | 
			
		||||
        "EventEmitter": "bower_components/eventemitter3/index",
 | 
			
		||||
        "es6-promise": "bower_components/es6-promise/es6-promise.min",
 | 
			
		||||
        "html2canvas": "bower_components/html2canvas/build/html2canvas.min",
 | 
			
		||||
        "moment": "bower_components/moment/moment",
 | 
			
		||||
@@ -61,7 +62,8 @@ requirejs.config({
 | 
			
		||||
        "screenfull": "bower_components/screenfull/dist/screenfull.min",
 | 
			
		||||
        "text": "bower_components/text/text",
 | 
			
		||||
        "uuid": "bower_components/node-uuid/uuid",
 | 
			
		||||
        "zepto": "bower_components/zepto/zepto.min"
 | 
			
		||||
        "zepto": "bower_components/zepto/zepto.min",
 | 
			
		||||
        "d3": "bower_components/d3/d3.min"
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    "shim": {
 | 
			
		||||
@@ -71,6 +73,9 @@ requirejs.config({
 | 
			
		||||
        "angular-route": {
 | 
			
		||||
            "deps": [ "angular" ]
 | 
			
		||||
        },
 | 
			
		||||
        "EventEmitter": {
 | 
			
		||||
            "exports": "EventEmitter"
 | 
			
		||||
        },
 | 
			
		||||
        "moment-duration-format": {
 | 
			
		||||
            "deps": [ "moment" ]
 | 
			
		||||
        },
 | 
			
		||||
@@ -79,6 +84,9 @@ requirejs.config({
 | 
			
		||||
        },
 | 
			
		||||
        "zepto": {
 | 
			
		||||
            "exports": "Zepto"
 | 
			
		||||
        },
 | 
			
		||||
        "d3": {
 | 
			
		||||
            "exports": "d3"
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user