Compare commits
	
		
			121 Commits
		
	
	
		
			angular-up
			...
			open1182
		
	
	| 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