mirror of
https://github.com/nasa/openmct.git
synced 2025-06-27 03:22:04 +00:00
Compare commits
18 Commits
api-gestur
...
handle-inv
Author | SHA1 | Date | |
---|---|---|---|
6cfee100d7 | |||
eeb214204d | |||
b41ceab51e | |||
10b0f43fc1 | |||
593c1adf56 | |||
5a7fdf82ac | |||
4571205871 | |||
34c3763421 | |||
ed6ae23dc0 | |||
23839b05b0 | |||
6aed3bb0b5 | |||
1ae62cde05 | |||
4e7e5bb783 | |||
efc46613bb | |||
218ef16160 | |||
fb0a577d16 | |||
19b5e7c781 | |||
cb242d8efb |
@ -25,8 +25,8 @@
|
|||||||
* @namespace platform/commonUI/browse
|
* @namespace platform/commonUI/browse
|
||||||
*/
|
*/
|
||||||
define(
|
define(
|
||||||
[],
|
['lodash'],
|
||||||
function () {
|
function (_) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The BrowseController is used to populate the initial scope in Browse
|
* The BrowseController is used to populate the initial scope in Browse
|
||||||
@ -157,12 +157,28 @@ define(
|
|||||||
// (e.g. bookmarks to pages in OpenMCT) and prevent them. Instead,
|
// (e.g. bookmarks to pages in OpenMCT) and prevent them. Instead,
|
||||||
// navigate to the path ourselves, which results in it being
|
// navigate to the path ourselves, which results in it being
|
||||||
// properly set.
|
// properly set.
|
||||||
$scope.$on('$routeChangeStart', function (event, route) {
|
$scope.$on('$routeChangeStart', function (event, route, oldRoute) {
|
||||||
if (route.$$route === $route.current.$$route) {
|
if (route.$$route === $route.current.$$route) {
|
||||||
if (route.pathParams.ids &&
|
if (route.pathParams.ids &&
|
||||||
route.pathParams.ids !== $route.current.pathParams.ids) {
|
route.pathParams.ids !== $route.current.pathParams.ids) {
|
||||||
|
|
||||||
|
var otherParams = _.omit(route.params, 'ids');
|
||||||
|
var oldOtherParams = _.omit(oldRoute.params, 'ids');
|
||||||
|
var deletedParams = _.omit(oldOtherParams, _.keys(otherParams));
|
||||||
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
navigateToPath(route.pathParams.ids.split('/'));
|
|
||||||
|
navigateToPath(route.pathParams.ids.split('/'))
|
||||||
|
.then(function () {
|
||||||
|
if (!_.isEqual(otherParams, oldOtherParams)) {
|
||||||
|
_.forEach(otherParams, function (v, k) {
|
||||||
|
$location.search(k, v);
|
||||||
|
});
|
||||||
|
_.forEach(deletedParams, function (k) {
|
||||||
|
$location.search(k, null);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
navigateToPath([]);
|
navigateToPath([]);
|
||||||
}
|
}
|
||||||
|
@ -83,12 +83,10 @@
|
|||||||
|
|
||||||
.l-image-thumbs-wrapper {
|
.l-image-thumbs-wrapper {
|
||||||
//@include test(green);
|
//@include test(green);
|
||||||
direction: rtl;
|
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
overflow-y: hidden;
|
overflow-y: hidden;
|
||||||
padding-bottom: $interiorMargin;
|
padding-bottom: $interiorMargin;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
z-index: 70;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.l-image-thumb-item {
|
.l-image-thumb-item {
|
||||||
@ -114,7 +112,7 @@
|
|||||||
width: $imageThumbsD + $imageThumbPad*2;
|
width: $imageThumbsD + $imageThumbPad*2;
|
||||||
white-space: normal;
|
white-space: normal;
|
||||||
&:hover {
|
&:hover {
|
||||||
background: rgba(#fff, 0.2);
|
background: $colorThumbHoverBg;
|
||||||
.l-date,
|
.l-date,
|
||||||
.l-time {
|
.l-time {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
|
@ -191,6 +191,9 @@ $colorItemTreeVCHover: pullForward($colorItemTreeVC, 20%);
|
|||||||
$colorItemTreeSelectedVC: $colorItemTreeVC;
|
$colorItemTreeSelectedVC: $colorItemTreeVC;
|
||||||
$shdwItemTreeIcon: 0.6;
|
$shdwItemTreeIcon: 0.6;
|
||||||
|
|
||||||
|
// Images
|
||||||
|
$colorThumbHoverBg: $colorItemTreeHoverBg;
|
||||||
|
|
||||||
// Scrollbar
|
// Scrollbar
|
||||||
$scrollbarTrackSize: 10px;
|
$scrollbarTrackSize: 10px;
|
||||||
$scrollbarTrackShdw: rgba(#000, 0.7) 0 1px 5px;
|
$scrollbarTrackShdw: rgba(#000, 0.7) 0 1px 5px;
|
||||||
|
@ -191,6 +191,9 @@ $colorItemTreeVCHover: $colorKey;
|
|||||||
$colorItemTreeSelectedVC: $colorBodyBg;
|
$colorItemTreeSelectedVC: $colorBodyBg;
|
||||||
$shdwItemTreeIcon: none;
|
$shdwItemTreeIcon: none;
|
||||||
|
|
||||||
|
// Images
|
||||||
|
$colorThumbHoverBg: $colorItemTreeHoverBg;
|
||||||
|
|
||||||
// Scrollbar
|
// Scrollbar
|
||||||
$scrollbarTrackSize: 10px;
|
$scrollbarTrackSize: 10px;
|
||||||
$scrollbarTrackShdw: rgba(#000, 0.2) 0 1px 2px;
|
$scrollbarTrackShdw: rgba(#000, 0.2) 0 1px 2px;
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
<div class="pane left menu-items">
|
<div class="pane left menu-items">
|
||||||
<ul>
|
<ul>
|
||||||
<li ng-repeat="metadata in ngModel.options"
|
<li ng-repeat="metadata in ngModel.options"
|
||||||
ng-click="ngModel.selected = metadata">
|
ng-click="ngModel.select(metadata)">
|
||||||
<a ng-mouseover="ngModel.activeMetadata = metadata"
|
<a ng-mouseover="ngModel.activeMetadata = metadata"
|
||||||
ng-mouseleave="ngModel.activeMetadata = undefined"
|
ng-mouseleave="ngModel.activeMetadata = undefined"
|
||||||
class="menu-item-a {{metadata.cssClass}}">
|
class="menu-item-a {{metadata.cssClass}}">
|
||||||
|
@ -111,7 +111,8 @@ define(
|
|||||||
var options = this.optionsFromConfig(config);
|
var options = this.optionsFromConfig(config);
|
||||||
this.menu = {
|
this.menu = {
|
||||||
selected: undefined,
|
selected: undefined,
|
||||||
options: options
|
options: options,
|
||||||
|
select: this.selectMenuOption
|
||||||
};
|
};
|
||||||
|
|
||||||
//Set the initial state of the UI from the conductor state
|
//Set the initial state of the UI from the conductor state
|
||||||
@ -132,8 +133,6 @@ define(
|
|||||||
this.setViewFromBounds(bounds);
|
this.setViewFromBounds(bounds);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$scope.$watch("tcController.menu.selected", this.selectMenuOption);
|
|
||||||
|
|
||||||
this.conductorViewService.on('pan', this.onPan);
|
this.conductorViewService.on('pan', this.onPan);
|
||||||
this.conductorViewService.on('pan-stop', this.onPanStop);
|
this.conductorViewService.on('pan-stop', this.onPanStop);
|
||||||
|
|
||||||
@ -164,10 +163,13 @@ define(
|
|||||||
*
|
*
|
||||||
* @private
|
* @private
|
||||||
* @param newOption
|
* @param newOption
|
||||||
* @param oldOption
|
|
||||||
*/
|
*/
|
||||||
TimeConductorController.prototype.selectMenuOption = function (newOption, oldOption) {
|
TimeConductorController.prototype.selectMenuOption = function (newOption) {
|
||||||
if (newOption !== oldOption) {
|
if (this.menu.selected.key === newOption.key) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.menu.selected = newOption;
|
||||||
|
|
||||||
var config = this.getConfig(this.timeAPI.timeSystem(), newOption.clock);
|
var config = this.getConfig(this.timeAPI.timeSystem(), newOption.clock);
|
||||||
if (!config) {
|
if (!config) {
|
||||||
// Clock does not support this timeSystem, fallback to first
|
// Clock does not support this timeSystem, fallback to first
|
||||||
@ -184,7 +186,6 @@ define(
|
|||||||
this.timeAPI.stopClock();
|
this.timeAPI.stopClock();
|
||||||
this.timeAPI.timeSystem(config.timeSystem, config.bounds);
|
this.timeAPI.timeSystem(config.timeSystem, config.bounds);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -25,12 +25,14 @@ define([
|
|||||||
"./src/controllers/ImageryController",
|
"./src/controllers/ImageryController",
|
||||||
"./src/directives/MCTBackgroundImage",
|
"./src/directives/MCTBackgroundImage",
|
||||||
"text!./res/templates/imagery.html",
|
"text!./res/templates/imagery.html",
|
||||||
|
"text!./res/templates/imageryTimeline.html",
|
||||||
'legacyRegistry'
|
'legacyRegistry'
|
||||||
], function (
|
], function (
|
||||||
ImageryViewPolicy,
|
ImageryViewPolicy,
|
||||||
ImageryController,
|
ImageryController,
|
||||||
MCTBackgroundImage,
|
MCTBackgroundImage,
|
||||||
imageryTemplate,
|
imageryTemplate,
|
||||||
|
imageryTimelineTemplate,
|
||||||
legacyRegistry
|
legacyRegistry
|
||||||
) {
|
) {
|
||||||
|
|
||||||
@ -48,6 +50,17 @@ define([
|
|||||||
"telemetry"
|
"telemetry"
|
||||||
],
|
],
|
||||||
"editable": false
|
"editable": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Historical Imagery",
|
||||||
|
"key": "historical-imagery",
|
||||||
|
"cssClass": "icon-image",
|
||||||
|
"template": imageryTimelineTemplate,
|
||||||
|
"priority": "preferred",
|
||||||
|
"needs": [
|
||||||
|
"telemetry"
|
||||||
|
],
|
||||||
|
"editable": false
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"policies": [
|
"policies": [
|
||||||
@ -65,6 +78,8 @@ define([
|
|||||||
"implementation": ImageryController,
|
"implementation": ImageryController,
|
||||||
"depends": [
|
"depends": [
|
||||||
"$scope",
|
"$scope",
|
||||||
|
"$window",
|
||||||
|
"$element",
|
||||||
"openmct"
|
"openmct"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
<div class="l-image-thumbs-wrapper" ng-controller="ImageryController as imagery">
|
||||||
|
<div class="l-image-thumb-item" ng-repeat="image in imageHistory track by $index">
|
||||||
|
<img class="l-thumb" ng-init="imagery.scrollToRight()"
|
||||||
|
ng-src={{imagery.getImageUrl(image)}} >
|
||||||
|
<div class="l-time">{{imagery.getTime(image)}}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -24,9 +24,13 @@
|
|||||||
* This bundle implements views of image telemetry.
|
* This bundle implements views of image telemetry.
|
||||||
* @namespace platform/features/imagery
|
* @namespace platform/features/imagery
|
||||||
*/
|
*/
|
||||||
|
|
||||||
define(
|
define(
|
||||||
['moment'],
|
[
|
||||||
function (moment) {
|
'zepto',
|
||||||
|
'lodash'
|
||||||
|
],
|
||||||
|
function ($, _) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controller for the "Imagery" view of a domain object which
|
* Controller for the "Imagery" view of a domain object which
|
||||||
@ -34,14 +38,20 @@ define(
|
|||||||
* @constructor
|
* @constructor
|
||||||
* @memberof platform/features/imagery
|
* @memberof platform/features/imagery
|
||||||
*/
|
*/
|
||||||
function ImageryController($scope, openmct) {
|
|
||||||
|
function ImageryController($scope, $window, element, openmct) {
|
||||||
this.$scope = $scope;
|
this.$scope = $scope;
|
||||||
|
this.$window = $window;
|
||||||
this.openmct = openmct;
|
this.openmct = openmct;
|
||||||
this.date = "";
|
this.date = "";
|
||||||
this.time = "";
|
this.time = "";
|
||||||
this.zone = "";
|
this.zone = "";
|
||||||
this.imageUrl = "";
|
this.imageUrl = "";
|
||||||
|
this.requestCount = 0;
|
||||||
|
this.scrollable = $(element[0]);
|
||||||
|
this.autoScroll = openmct.time.clock() ? true : false;
|
||||||
|
|
||||||
|
this.$scope.imageHistory = [];
|
||||||
this.$scope.filters = {
|
this.$scope.filters = {
|
||||||
brightness: 100,
|
brightness: 100,
|
||||||
contrast: 100
|
contrast: 100
|
||||||
@ -50,12 +60,15 @@ define(
|
|||||||
this.subscribe = this.subscribe.bind(this);
|
this.subscribe = this.subscribe.bind(this);
|
||||||
this.stopListening = this.stopListening.bind(this);
|
this.stopListening = this.stopListening.bind(this);
|
||||||
this.updateValues = this.updateValues.bind(this);
|
this.updateValues = this.updateValues.bind(this);
|
||||||
|
this.updateHistory = this.updateHistory.bind(this);
|
||||||
|
this.onBoundsChange = this.onBoundsChange.bind(this);
|
||||||
|
this.onScroll = this.onScroll.bind(this);
|
||||||
|
|
||||||
// Subscribe to telemetry when a domain object becomes available
|
|
||||||
this.subscribe(this.$scope.domainObject);
|
this.subscribe(this.$scope.domainObject);
|
||||||
|
|
||||||
// Unsubscribe when the plot is destroyed
|
this.$scope.$on('$destroy', this.stopListening);
|
||||||
this.$scope.$on("$destroy", this.stopListening);
|
this.openmct.time.on('bounds', this.onBoundsChange);
|
||||||
|
this.scrollable.on('scroll', this.onScroll);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageryController.prototype.subscribe = function (domainObject) {
|
ImageryController.prototype.subscribe = function (domainObject) {
|
||||||
@ -75,7 +88,42 @@ define(
|
|||||||
.telemetry
|
.telemetry
|
||||||
.getValueFormatter(metadata.valuesForHints(['image'])[0]);
|
.getValueFormatter(metadata.valuesForHints(['image'])[0]);
|
||||||
this.unsubscribe = this.openmct.telemetry
|
this.unsubscribe = this.openmct.telemetry
|
||||||
.subscribe(this.domainObject, this.updateValues);
|
.subscribe(this.domainObject, function (datum) {
|
||||||
|
this.updateHistory(datum);
|
||||||
|
this.updateValues(datum);
|
||||||
|
}.bind(this));
|
||||||
|
this.requestLad(false);
|
||||||
|
this.requestHistory(this.openmct.time.bounds());
|
||||||
|
}.bind(this));
|
||||||
|
};
|
||||||
|
|
||||||
|
ImageryController.prototype.requestHistory = function (bounds) {
|
||||||
|
this.requestCount++;
|
||||||
|
this.$scope.imageHistory = [];
|
||||||
|
var requestId = this.requestCount;
|
||||||
|
this.openmct.telemetry
|
||||||
|
.request(this.domainObject, bounds)
|
||||||
|
.then(function (values) {
|
||||||
|
if (this.requestCount > requestId) {
|
||||||
|
return Promise.resolve('Stale request');
|
||||||
|
}
|
||||||
|
values.forEach(function (datum) {
|
||||||
|
this.updateHistory(datum);
|
||||||
|
}, this);
|
||||||
|
this.requestLad(true);
|
||||||
|
}.bind(this));
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes a request for the most recent datum in the
|
||||||
|
* telelmetry store. Optional addToHistory argument
|
||||||
|
* determines whether the requested telemetry should
|
||||||
|
* be added to history or only used to update the current
|
||||||
|
* image url and timestamp.
|
||||||
|
* @private
|
||||||
|
* @param {boolean} [addToHistory] if true, adds to history
|
||||||
|
*/
|
||||||
|
ImageryController.prototype.requestLad = function (addToHistory) {
|
||||||
this.openmct.telemetry
|
this.openmct.telemetry
|
||||||
.request(this.domainObject, {
|
.request(this.domainObject, {
|
||||||
strategy: 'latest',
|
strategy: 'latest',
|
||||||
@ -83,42 +131,109 @@ define(
|
|||||||
})
|
})
|
||||||
.then(function (values) {
|
.then(function (values) {
|
||||||
this.updateValues(values[0]);
|
this.updateValues(values[0]);
|
||||||
}.bind(this));
|
if (addToHistory !== false) {
|
||||||
|
this.updateHistory(values[0]);
|
||||||
|
}
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
};
|
};
|
||||||
|
|
||||||
ImageryController.prototype.stopListening = function () {
|
ImageryController.prototype.stopListening = function () {
|
||||||
|
this.openmct.time.off('bounds', this.onBoundsChange);
|
||||||
|
this.scrollable.off('scroll', this.onScroll);
|
||||||
if (this.unsubscribe) {
|
if (this.unsubscribe) {
|
||||||
this.unsubscribe();
|
this.unsubscribe();
|
||||||
delete this.unsubscribe;
|
delete this.unsubscribe;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Update displayable values to reflect latest image telemetry
|
/**
|
||||||
|
* Responds to bound change event be requesting new
|
||||||
|
* historical data if the bound change was manual.
|
||||||
|
* @private
|
||||||
|
* @param {object} [newBounds] new bounds object
|
||||||
|
* @param {boolean} [tick] true when change is automatic
|
||||||
|
*/
|
||||||
|
ImageryController.prototype.onBoundsChange = function (newBounds, tick) {
|
||||||
|
if (this.domainObject && !tick) {
|
||||||
|
this.requestHistory(newBounds);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates displayable values to match those of the most
|
||||||
|
* recently recieved datum.
|
||||||
|
* @param {object} [datum] the datum
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
ImageryController.prototype.updateValues = function (datum) {
|
ImageryController.prototype.updateValues = function (datum) {
|
||||||
if (this.isPaused) {
|
if (this.isPaused) {
|
||||||
this.nextDatum = datum;
|
this.nextDatum = datum;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.time = this.timeFormat.format(datum);
|
this.time = this.timeFormat.format(datum);
|
||||||
this.imageUrl = this.imageFormat.format(datum);
|
this.imageUrl = this.imageFormat.format(datum);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends given imagery datum to running history.
|
||||||
|
* @private
|
||||||
|
* @param {object} [datum] target telemetry datum
|
||||||
|
* @returns {boolean} falsy when a duplicate datum is given
|
||||||
|
*/
|
||||||
|
ImageryController.prototype.updateHistory = function (datum) {
|
||||||
|
if (this.$scope.imageHistory.length === 0 ||
|
||||||
|
!_.isEqual(this.$scope.imageHistory.slice(-1)[0], datum)) {
|
||||||
|
|
||||||
|
var index = _.sortedIndex(this.$scope.imageHistory, datum, 'utc');
|
||||||
|
this.$scope.imageHistory.splice(index, 0, datum);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
ImageryController.prototype.onScroll = function (event) {
|
||||||
|
this.$window.requestAnimationFrame(function () {
|
||||||
|
if (this.scrollable[0].scrollLeft <
|
||||||
|
(this.scrollable[0].scrollWidth - this.scrollable[0].clientWidth) - 20) {
|
||||||
|
this.autoScroll = false;
|
||||||
|
} else {
|
||||||
|
this.autoScroll = true;
|
||||||
|
}
|
||||||
|
}.bind(this));
|
||||||
|
};
|
||||||
|
|
||||||
|
ImageryController.prototype.scrollToRight = function () {
|
||||||
|
if (this.autoScroll) {
|
||||||
|
this.scrollable[0].scrollLeft = this.scrollable[0].scrollWidth;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the time portion (hours, minutes, seconds) of the
|
* Get the time portion (hours, minutes, seconds) of the
|
||||||
* timestamp associated with the incoming image telemetry.
|
* timestamp associated with the incoming image telemetry
|
||||||
|
* if no parameter is given, or of a provided datum.
|
||||||
|
* @param {object} [datum] target telemetry datum
|
||||||
* @returns {string} the time
|
* @returns {string} the time
|
||||||
*/
|
*/
|
||||||
ImageryController.prototype.getTime = function () {
|
ImageryController.prototype.getTime = function (datum) {
|
||||||
return this.time;
|
return datum ?
|
||||||
|
this.timeFormat.format(datum) :
|
||||||
|
this.time;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the URL of the image telemetry to display.
|
* Get the URL of the most recent image telemetry if no
|
||||||
|
* parameter is given, or of a provided datum.
|
||||||
|
* @param {object} [datum] target telemetry datum
|
||||||
* @returns {string} URL for telemetry image
|
* @returns {string} URL for telemetry image
|
||||||
*/
|
*/
|
||||||
ImageryController.prototype.getImageUrl = function () {
|
ImageryController.prototype.getImageUrl = function (datum) {
|
||||||
return this.imageUrl;
|
return datum ?
|
||||||
|
this.imageFormat.format(datum) :
|
||||||
|
this.imageUrl;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -47,7 +47,7 @@ define([
|
|||||||
};
|
};
|
||||||
|
|
||||||
ImageryViewPolicy.prototype.allow = function (view, domainObject) {
|
ImageryViewPolicy.prototype.allow = function (view, domainObject) {
|
||||||
if (view.key === 'imagery') {
|
if (view.key === 'imagery' || view.key === 'historical-imagery') {
|
||||||
return this.hasImageTelemetry(domainObject);
|
return this.hasImageTelemetry(domainObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,8 +21,14 @@
|
|||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
define(
|
define(
|
||||||
["../../src/controllers/ImageryController"],
|
[
|
||||||
function (ImageryController) {
|
"zepto",
|
||||||
|
"../../src/controllers/ImageryController"
|
||||||
|
],
|
||||||
|
function ($, ImageryController) {
|
||||||
|
|
||||||
|
var MOCK_ELEMENT_TEMPLATE =
|
||||||
|
'<div class="l-image-thumbs-wrapper"></div>';
|
||||||
|
|
||||||
describe("The Imagery controller", function () {
|
describe("The Imagery controller", function () {
|
||||||
var $scope,
|
var $scope,
|
||||||
@ -33,7 +39,9 @@ define(
|
|||||||
metadata,
|
metadata,
|
||||||
prefix,
|
prefix,
|
||||||
controller,
|
controller,
|
||||||
hasLoaded;
|
hasLoaded,
|
||||||
|
mockWindow,
|
||||||
|
mockElement;
|
||||||
|
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
$scope = jasmine.createSpyObj('$scope', ['$on', '$watch']);
|
$scope = jasmine.createSpyObj('$scope', ['$on', '$watch']);
|
||||||
@ -42,14 +50,16 @@ define(
|
|||||||
['getId']
|
['getId']
|
||||||
);
|
);
|
||||||
newDomainObject = { name: 'foo' };
|
newDomainObject = { name: 'foo' };
|
||||||
|
|
||||||
oldDomainObject.getId.andReturn('testID');
|
oldDomainObject.getId.andReturn('testID');
|
||||||
openmct = {
|
openmct = {
|
||||||
objects: jasmine.createSpyObj('objectAPI', [
|
objects: jasmine.createSpyObj('objectAPI', [
|
||||||
'get'
|
'get'
|
||||||
]),
|
]),
|
||||||
time: jasmine.createSpyObj('timeAPI', [
|
time: jasmine.createSpyObj('timeAPI', [
|
||||||
'timeSystem'
|
'timeSystem',
|
||||||
|
'clock',
|
||||||
|
'on',
|
||||||
|
'off'
|
||||||
]),
|
]),
|
||||||
telemetry: jasmine.createSpyObj('telemetryAPI', [
|
telemetry: jasmine.createSpyObj('telemetryAPI', [
|
||||||
'subscribe',
|
'subscribe',
|
||||||
@ -92,13 +102,24 @@ define(
|
|||||||
});
|
});
|
||||||
metadata.value.andReturn("timestamp");
|
metadata.value.andReturn("timestamp");
|
||||||
metadata.valuesForHints.andReturn(["value"]);
|
metadata.valuesForHints.andReturn(["value"]);
|
||||||
|
mockElement = $(MOCK_ELEMENT_TEMPLATE);
|
||||||
|
mockWindow = jasmine.createSpyObj('$window', ['requestAnimationFrame']);
|
||||||
|
mockWindow.requestAnimationFrame.andCallFake(function (f) {
|
||||||
|
return f();
|
||||||
|
});
|
||||||
|
|
||||||
controller = new ImageryController($scope, openmct);
|
controller = new ImageryController(
|
||||||
|
$scope,
|
||||||
|
mockWindow,
|
||||||
|
mockElement,
|
||||||
|
openmct
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("when loaded", function () {
|
describe("when loaded", function () {
|
||||||
var callback;
|
var callback,
|
||||||
|
boundsListener;
|
||||||
|
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
waitsFor(function () {
|
waitsFor(function () {
|
||||||
return hasLoaded;
|
return hasLoaded;
|
||||||
@ -106,12 +127,16 @@ define(
|
|||||||
|
|
||||||
|
|
||||||
runs(function () {
|
runs(function () {
|
||||||
|
openmct.time.on.calls.forEach(function (call) {
|
||||||
|
if (call.args[0] === "bounds") {
|
||||||
|
boundsListener = call.args[1];
|
||||||
|
}
|
||||||
|
});
|
||||||
callback =
|
callback =
|
||||||
openmct.telemetry.subscribe.mostRecentCall.args[1];
|
openmct.telemetry.subscribe.mostRecentCall.args[1];
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it("uses LAD telemetry", function () {
|
it("uses LAD telemetry", function () {
|
||||||
expect(openmct.telemetry.request).toHaveBeenCalledWith(
|
expect(openmct.telemetry.request).toHaveBeenCalledWith(
|
||||||
newDomainObject,
|
newDomainObject,
|
||||||
@ -165,7 +190,14 @@ define(
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("unsubscribes when scope is destroyed", function () {
|
it("requests telemetry", function () {
|
||||||
|
expect(openmct.telemetry.request).toHaveBeenCalledWith(
|
||||||
|
newDomainObject,
|
||||||
|
jasmine.any(Object)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("unsubscribes and unlistens when scope is destroyed", function () {
|
||||||
expect(unsubscribe).not.toHaveBeenCalled();
|
expect(unsubscribe).not.toHaveBeenCalled();
|
||||||
|
|
||||||
$scope.$on.calls.forEach(function (call) {
|
$scope.$on.calls.forEach(function (call) {
|
||||||
@ -174,6 +206,25 @@ define(
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
expect(unsubscribe).toHaveBeenCalled();
|
expect(unsubscribe).toHaveBeenCalled();
|
||||||
|
expect(openmct.time.off)
|
||||||
|
.toHaveBeenCalledWith('bounds', jasmine.any(Function));
|
||||||
|
});
|
||||||
|
|
||||||
|
it("listens for bounds event and responds to tick and manual change", function () {
|
||||||
|
var mockBounds = {start: 1434600000000, end: 1434600500000};
|
||||||
|
expect(openmct.time.on).toHaveBeenCalled();
|
||||||
|
openmct.telemetry.request.reset();
|
||||||
|
boundsListener(mockBounds, true);
|
||||||
|
expect(openmct.telemetry.request).not.toHaveBeenCalled();
|
||||||
|
boundsListener(mockBounds, false);
|
||||||
|
expect(openmct.telemetry.request).toHaveBeenCalledWith(newDomainObject, mockBounds);
|
||||||
|
});
|
||||||
|
|
||||||
|
it ("doesnt append duplicate datum", function () {
|
||||||
|
var mockDatum = {url: 'image/url', utc: 1434600000000};
|
||||||
|
expect(controller.updateHistory(mockDatum)).toBe(true);
|
||||||
|
expect(controller.updateHistory(mockDatum)).toBe(false);
|
||||||
|
expect(controller.updateHistory(mockDatum)).toBe(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -75,6 +75,21 @@ define(
|
|||||||
].join(""));
|
].join(""));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Log an info: defaults to "no service provide by"
|
||||||
|
function info(extension, category, message) {
|
||||||
|
var msg = message || "No service provided by";
|
||||||
|
$log.info([
|
||||||
|
msg,
|
||||||
|
" ",
|
||||||
|
category,
|
||||||
|
" ",
|
||||||
|
extension.key,
|
||||||
|
" from bundle ",
|
||||||
|
(extension.bundle || { path: "unknown bundle" }).path,
|
||||||
|
"; skipping."
|
||||||
|
].join(""));
|
||||||
|
}
|
||||||
|
|
||||||
// Echo arguments; used to represent groups of non-built-in
|
// Echo arguments; used to represent groups of non-built-in
|
||||||
// extensions as a single dependency.
|
// extensions as a single dependency.
|
||||||
function echoMany() {
|
function echoMany() {
|
||||||
@ -161,13 +176,13 @@ define(
|
|||||||
name = makeName("aggregator", service, index);
|
name = makeName("aggregator", service, index);
|
||||||
|
|
||||||
if (!service) {
|
if (!service) {
|
||||||
return warn(aggregator, "aggregator");
|
return info(aggregator, "aggregator");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Aggregators need other services to aggregate, otherwise they
|
// Aggregators need other services to aggregate, otherwise they
|
||||||
// do nothing.
|
// do nothing.
|
||||||
if (!latest[service]) {
|
if (!latest[service]) {
|
||||||
return warn(
|
return info(
|
||||||
aggregator,
|
aggregator,
|
||||||
"aggregator",
|
"aggregator",
|
||||||
"No services to aggregate for"
|
"No services to aggregate for"
|
||||||
|
@ -195,7 +195,8 @@ define(
|
|||||||
expect(mockApp.service).not.toHaveBeenCalled();
|
expect(mockApp.service).not.toHaveBeenCalled();
|
||||||
|
|
||||||
// Should have gotten one warning for each skipped component
|
// Should have gotten one warning for each skipped component
|
||||||
expect(mockLog.warn.calls.length).toEqual(3);
|
expect(mockLog.warn.calls.length).toEqual(2);
|
||||||
|
expect(mockLog.info.calls.length).toEqual(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("warns about and skips aggregators with zero providers", function () {
|
it("warns about and skips aggregators with zero providers", function () {
|
||||||
@ -217,7 +218,7 @@ define(
|
|||||||
expect(mockApp.service).not.toHaveBeenCalled();
|
expect(mockApp.service).not.toHaveBeenCalled();
|
||||||
|
|
||||||
// Should have gotten a warning
|
// Should have gotten a warning
|
||||||
expect(mockLog.warn).toHaveBeenCalled();
|
expect(mockLog.info).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("warns about and skips decorators with nothing to decorate", function () {
|
it("warns about and skips decorators with nothing to decorate", function () {
|
||||||
|
@ -115,9 +115,7 @@ define(
|
|||||||
return (this.telemetryService =
|
return (this.telemetryService =
|
||||||
$injector.get("telemetryService"));
|
$injector.get("telemetryService"));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// $injector should throw if telemetryService
|
$log.info("Telemetry service unavailable");
|
||||||
// is unavailable or unsatisfiable.
|
|
||||||
$log.warn("Telemetry service unavailable");
|
|
||||||
return (this.telemetryService = null);
|
return (this.telemetryService = null);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -314,4 +312,3 @@ define(
|
|||||||
return TelemetryCapability;
|
return TelemetryCapability;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -199,7 +199,7 @@ define(
|
|||||||
|
|
||||||
telemetry.requestData();
|
telemetry.requestData();
|
||||||
|
|
||||||
expect(mockLog.warn).toHaveBeenCalled();
|
expect(mockLog.info).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("if a new style telemetry source is available, use it", function () {
|
it("if a new style telemetry source is available, use it", function () {
|
||||||
|
@ -20,7 +20,11 @@
|
|||||||
* at runtime from the About dialog for additional information.
|
* at runtime from the About dialog for additional information.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
define([], function () {
|
define([
|
||||||
|
'lodash'
|
||||||
|
], function (
|
||||||
|
_
|
||||||
|
) {
|
||||||
// Parameter names in query string
|
// Parameter names in query string
|
||||||
var SEARCH = {
|
var SEARCH = {
|
||||||
MODE: 'tc.mode',
|
MODE: 'tc.mode',
|
||||||
@ -73,43 +77,72 @@ define([], function () {
|
|||||||
this.$location.search(SEARCH.END_DELTA, deltas.end);
|
this.$location.search(SEARCH.END_DELTA, deltas.end);
|
||||||
};
|
};
|
||||||
|
|
||||||
TimeSettingsURLHandler.prototype.updateTime = function () {
|
TimeSettingsURLHandler.prototype.parseQueryParams = function () {
|
||||||
var searchParams = this.$location.search();
|
var searchParams = _.pick(this.$location.search(), _.values(SEARCH));
|
||||||
var mode = searchParams[SEARCH.MODE];
|
var parsedParams = {
|
||||||
var timeSystem = searchParams[SEARCH.TIME_SYSTEM];
|
clock: searchParams[SEARCH.MODE],
|
||||||
var clockOffsets = {
|
timeSystem: searchParams[SEARCH.TIME_SYSTEM]
|
||||||
|
};
|
||||||
|
if (!isNaN(parseInt(searchParams[SEARCH.START_DELTA], 0xA)) &&
|
||||||
|
!isNaN(parseInt(searchParams[SEARCH.END_DELTA], 0xA))) {
|
||||||
|
parsedParams.clockOffsets = {
|
||||||
start: -searchParams[SEARCH.START_DELTA],
|
start: -searchParams[SEARCH.START_DELTA],
|
||||||
end: +searchParams[SEARCH.END_DELTA]
|
end: +searchParams[SEARCH.END_DELTA]
|
||||||
};
|
};
|
||||||
var bounds = {
|
}
|
||||||
|
if (!isNaN(parseInt(searchParams[SEARCH.START_BOUND], 0xA)) &&
|
||||||
|
!isNaN(parseInt(searchParams[SEARCH.END_BOUND], 0xA))) {
|
||||||
|
parsedParams.bounds = {
|
||||||
start: +searchParams[SEARCH.START_BOUND],
|
start: +searchParams[SEARCH.START_BOUND],
|
||||||
end: +searchParams[SEARCH.END_BOUND]
|
end: +searchParams[SEARCH.END_BOUND]
|
||||||
};
|
};
|
||||||
var fixed = (mode === 'fixed');
|
}
|
||||||
var clock = fixed ? undefined : mode;
|
return parsedParams;
|
||||||
var hasDeltas =
|
};
|
||||||
!isNaN(parseInt(searchParams[SEARCH.START_DELTA], 0xA)) &&
|
|
||||||
!isNaN(parseInt(searchParams[SEARCH.END_DELTA], 0xA));
|
|
||||||
var hasBounds =
|
|
||||||
!isNaN(parseInt(searchParams[SEARCH.START_BOUND], 0xA)) &&
|
|
||||||
!isNaN(parseInt(searchParams[SEARCH.END_BOUND], 0xA));
|
|
||||||
|
|
||||||
if (fixed && timeSystem && hasBounds) {
|
TimeSettingsURLHandler.prototype.updateTime = function () {
|
||||||
this.time.timeSystem(timeSystem, bounds);
|
var params = this.parseQueryParams();
|
||||||
|
if (_.isEqual(params, this.last)) {
|
||||||
|
return; // Do nothing;
|
||||||
|
}
|
||||||
|
this.last = params;
|
||||||
|
|
||||||
|
if (!params.timeSystem) {
|
||||||
|
this.updateQueryParams();
|
||||||
|
} else if (params.clock === 'fixed' && params.bounds) {
|
||||||
|
if (!this.time.timeSystem() ||
|
||||||
|
this.time.timeSystem().key !== params.timeSystem) {
|
||||||
|
|
||||||
|
this.time.timeSystem(
|
||||||
|
params.timeSystem,
|
||||||
|
params.bounds
|
||||||
|
);
|
||||||
|
} else if (!_.isEqual(this.time.bounds(), params.bounds)) {
|
||||||
|
this.time.bounds(params.bounds);
|
||||||
|
}
|
||||||
|
if (this.time.clock()) {
|
||||||
this.time.stopClock();
|
this.time.stopClock();
|
||||||
}
|
}
|
||||||
|
} else if (params.clockOffsets) {
|
||||||
if (!fixed && clock && hasDeltas) {
|
if (params.clock === 'fixed') {
|
||||||
this.time.clock(clock, clockOffsets);
|
this.time.stopClock();
|
||||||
this.time.timeSystem(timeSystem);
|
return;
|
||||||
}
|
}
|
||||||
|
if (!this.time.clock() ||
|
||||||
|
this.time.clock().key !== params.clock) {
|
||||||
|
|
||||||
if (hasDeltas && !fixed) {
|
this.time.clock(params.clock, params.clockOffsets);
|
||||||
this.time.clockOffsets(clockOffsets);
|
} else if (!_.isEqual(this.time.clockOffsets(), params.clockOffsets)) {
|
||||||
|
this.time.clockOffsets(params.clockOffsets);
|
||||||
}
|
}
|
||||||
|
if (!this.time.timeSystem() ||
|
||||||
|
this.time.timeSystem().key !== params.timeSystem) {
|
||||||
|
|
||||||
if (hasBounds && fixed) {
|
this.time.timeSystem(params.timeSystem);
|
||||||
this.time.bounds(bounds);
|
}
|
||||||
|
} else {
|
||||||
|
// Neither found, update from timeSystem.
|
||||||
|
this.updateQueryParams();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -20,23 +20,78 @@
|
|||||||
* at runtime from the About dialog for additional information.
|
* at runtime from the About dialog for additional information.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
define(['./TimeSettingsURLHandler'], function (TimeSettingsURLHandler) {
|
define([
|
||||||
|
'./TimeSettingsURLHandler',
|
||||||
|
'../../api/time/TimeAPI'
|
||||||
|
], function (
|
||||||
|
TimeSettingsURLHandler,
|
||||||
|
TimeAPI
|
||||||
|
) {
|
||||||
describe("TimeSettingsURLHandler", function () {
|
describe("TimeSettingsURLHandler", function () {
|
||||||
var time;
|
var time;
|
||||||
var $location;
|
var $location;
|
||||||
var $rootScope;
|
var $rootScope;
|
||||||
var search;
|
var search;
|
||||||
var handler;
|
var handler;
|
||||||
|
var clockA;
|
||||||
|
var clockB;
|
||||||
|
var timeSystemA;
|
||||||
|
var timeSystemB;
|
||||||
|
var boundsA;
|
||||||
|
var boundsB;
|
||||||
|
var offsetsA;
|
||||||
|
var offsetsB;
|
||||||
|
var initialize;
|
||||||
|
var triggerLocationChange;
|
||||||
|
|
||||||
|
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
time = jasmine.createSpyObj('time', [
|
clockA = jasmine.createSpyObj('clockA', ['on', 'off']);
|
||||||
|
clockA.key = 'clockA';
|
||||||
|
clockA.currentValue = function () {
|
||||||
|
return 1000;
|
||||||
|
};
|
||||||
|
clockB = jasmine.createSpyObj('clockB', ['on', 'off']);
|
||||||
|
clockB.key = 'clockB';
|
||||||
|
clockB.currentValue = function () {
|
||||||
|
return 2000;
|
||||||
|
};
|
||||||
|
timeSystemA = {key: 'timeSystemA'};
|
||||||
|
timeSystemB = {key: 'timeSystemB'};
|
||||||
|
boundsA = {
|
||||||
|
start: 10,
|
||||||
|
end: 20
|
||||||
|
};
|
||||||
|
boundsB = {
|
||||||
|
start: 120,
|
||||||
|
end: 360
|
||||||
|
};
|
||||||
|
offsetsA = {
|
||||||
|
start: -100,
|
||||||
|
end: 0
|
||||||
|
};
|
||||||
|
offsetsB = {
|
||||||
|
start: -50,
|
||||||
|
end: 50
|
||||||
|
};
|
||||||
|
|
||||||
|
time = new TimeAPI();
|
||||||
|
|
||||||
|
[
|
||||||
'on',
|
'on',
|
||||||
'bounds',
|
'bounds',
|
||||||
'clockOffsets',
|
'clockOffsets',
|
||||||
'timeSystem',
|
'timeSystem',
|
||||||
'clock',
|
'clock',
|
||||||
'stopClock'
|
'stopClock'
|
||||||
]);
|
].forEach(function (method) {
|
||||||
|
spyOn(time, method).andCallThrough();
|
||||||
|
});
|
||||||
|
time.addTimeSystem(timeSystemA);
|
||||||
|
time.addTimeSystem(timeSystemB);
|
||||||
|
time.addClock(clockA);
|
||||||
|
time.addClock(clockB);
|
||||||
|
|
||||||
$location = jasmine.createSpyObj('$location', [
|
$location = jasmine.createSpyObj('$location', [
|
||||||
'search'
|
'search'
|
||||||
]);
|
]);
|
||||||
@ -44,8 +99,6 @@ define(['./TimeSettingsURLHandler'], function (TimeSettingsURLHandler) {
|
|||||||
'$on'
|
'$on'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
time.timeSystem.andReturn({ key: 'test-time-system' });
|
|
||||||
|
|
||||||
search = {};
|
search = {};
|
||||||
$location.search.andCallFake(function (key, value) {
|
$location.search.andCallFake(function (key, value) {
|
||||||
if (arguments.length === 0) {
|
if (arguments.length === 0) {
|
||||||
@ -59,142 +112,465 @@ define(['./TimeSettingsURLHandler'], function (TimeSettingsURLHandler) {
|
|||||||
return this;
|
return this;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
expect(time.timeSystem()).toBeUndefined();
|
||||||
|
expect(time.bounds()).toEqual({});
|
||||||
|
expect(time.clockOffsets()).toBeUndefined();
|
||||||
|
expect(time.clock()).toBeUndefined();
|
||||||
|
|
||||||
|
initialize = function () {
|
||||||
handler = new TimeSettingsURLHandler(
|
handler = new TimeSettingsURLHandler(
|
||||||
time,
|
time,
|
||||||
$location,
|
$location,
|
||||||
$rootScope
|
$rootScope
|
||||||
);
|
);
|
||||||
});
|
expect($rootScope.$on).toHaveBeenCalledWith(
|
||||||
|
'$locationChangeSuccess',
|
||||||
|
jasmine.any(Function)
|
||||||
|
);
|
||||||
|
triggerLocationChange = $rootScope.$on.mostRecentCall.args[1];
|
||||||
|
|
||||||
['bounds', 'timeSystem', 'clock', 'clockOffsets'].forEach(function (event) {
|
|
||||||
it("listens for " + event + " time events", function () {
|
|
||||||
expect(time.on)
|
|
||||||
.toHaveBeenCalledWith(event, jasmine.any(Function));
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("when " + event + " time event occurs with no clock", function () {
|
|
||||||
var expected;
|
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
expected = {
|
|
||||||
'tc.mode': 'fixed',
|
|
||||||
'tc.timeSystem': 'test-time-system',
|
|
||||||
'tc.startBound': '123',
|
|
||||||
'tc.endBound': '456'
|
|
||||||
};
|
};
|
||||||
time.clock.andReturn(undefined);
|
});
|
||||||
time.bounds.andReturn({ start: 123, end: 456 });
|
|
||||||
|
|
||||||
time.on.calls.forEach(function (call) {
|
it("initializes with missing time system", function () {
|
||||||
if (call.args[0] === event) {
|
// This handles an odd transitory case where a url does not include
|
||||||
call.args[1]();
|
// a timeSystem. It's generally only experienced by those who
|
||||||
|
// based their code on the tutorial before it specified a time
|
||||||
|
// system.
|
||||||
|
search['tc.mode'] = 'clockA';
|
||||||
|
search['tc.timeSystem'] = undefined;
|
||||||
|
search['tc.startDelta'] = '123';
|
||||||
|
search['tc.endDelta'] = '456';
|
||||||
|
|
||||||
|
// We don't specify behavior right now other than "don't break."
|
||||||
|
expect(initialize).not.toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("can initalize fixed mode from location", function () {
|
||||||
|
search['tc.mode'] = 'fixed';
|
||||||
|
search['tc.timeSystem'] = 'timeSystemA';
|
||||||
|
search['tc.startBound'] = '123';
|
||||||
|
search['tc.endBound'] = '456';
|
||||||
|
|
||||||
|
initialize();
|
||||||
|
|
||||||
|
expect(time.timeSystem).toHaveBeenCalledWith(
|
||||||
|
'timeSystemA',
|
||||||
|
{
|
||||||
|
start: 123,
|
||||||
|
end: 456
|
||||||
}
|
}
|
||||||
});
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("updates query parameters for fixed mode", function () {
|
it("can initialize clock mode from location", function () {
|
||||||
expect(search).toEqual(expected);
|
search['tc.mode'] = 'clockA';
|
||||||
});
|
search['tc.timeSystem'] = 'timeSystemA';
|
||||||
});
|
search['tc.startDelta'] = '123';
|
||||||
|
search['tc.endDelta'] = '456';
|
||||||
|
|
||||||
describe("when " + event + " time event occurs with no time system", function () {
|
initialize();
|
||||||
beforeEach(function () {
|
|
||||||
time.timeSystem.andReturn(undefined);
|
expect(time.clock).toHaveBeenCalledWith(
|
||||||
time.on.calls.forEach(function (call) {
|
'clockA',
|
||||||
if (call.args[0] === event) {
|
{
|
||||||
call.args[1]();
|
start: -123,
|
||||||
|
end: 456
|
||||||
}
|
}
|
||||||
});
|
);
|
||||||
|
expect(time.timeSystem).toHaveBeenCalledWith(
|
||||||
|
'timeSystemA'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("clears the time system from the URL", function () {
|
it("can initialize fixed mode from time API", function () {
|
||||||
expect(search['tc.timeSystem']).toBeUndefined();
|
time.timeSystem(timeSystemA.key, boundsA);
|
||||||
});
|
initialize();
|
||||||
|
expect($location.search)
|
||||||
|
.toHaveBeenCalledWith('tc.mode', 'fixed');
|
||||||
|
expect($location.search)
|
||||||
|
.toHaveBeenCalledWith('tc.timeSystem', 'timeSystemA');
|
||||||
|
expect($location.search)
|
||||||
|
.toHaveBeenCalledWith('tc.startBound', 10);
|
||||||
|
expect($location.search)
|
||||||
|
.toHaveBeenCalledWith('tc.endBound', 20);
|
||||||
|
expect($location.search)
|
||||||
|
.toHaveBeenCalledWith('tc.startDelta', null);
|
||||||
|
expect($location.search)
|
||||||
|
.toHaveBeenCalledWith('tc.endDelta', null);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("when " + event + " time event occurs with a clock", function () {
|
it("can initialize clock mode from time API", function () {
|
||||||
var expected;
|
time.clock(clockA.key, offsetsA);
|
||||||
|
time.timeSystem(timeSystemA.key);
|
||||||
|
initialize();
|
||||||
|
expect($location.search)
|
||||||
|
.toHaveBeenCalledWith('tc.mode', 'clockA');
|
||||||
|
expect($location.search)
|
||||||
|
.toHaveBeenCalledWith('tc.timeSystem', 'timeSystemA');
|
||||||
|
expect($location.search)
|
||||||
|
.toHaveBeenCalledWith('tc.startBound', null);
|
||||||
|
expect($location.search)
|
||||||
|
.toHaveBeenCalledWith('tc.endBound', null);
|
||||||
|
expect($location.search)
|
||||||
|
.toHaveBeenCalledWith('tc.startDelta', 100);
|
||||||
|
expect($location.search)
|
||||||
|
.toHaveBeenCalledWith('tc.endDelta', 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('location changes in fixed mode', function () {
|
||||||
|
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
expected = {
|
time.timeSystem(timeSystemA.key, boundsA);
|
||||||
'tc.mode': 'clocky',
|
initialize();
|
||||||
'tc.timeSystem': 'test-time-system',
|
time.timeSystem.reset();
|
||||||
'tc.startDelta': '123',
|
time.bounds.reset();
|
||||||
'tc.endDelta': '456'
|
time.clock.reset();
|
||||||
};
|
time.stopClock.reset();
|
||||||
time.clock.andReturn({ key: 'clocky' });
|
});
|
||||||
time.clockOffsets.andReturn({ start: -123, end: 456 });
|
|
||||||
|
|
||||||
time.on.calls.forEach(function (call) {
|
it("does not change on spurious location change", function () {
|
||||||
if (call.args[0] === event) {
|
triggerLocationChange();
|
||||||
call.args[1]();
|
expect(time.timeSystem).not.toHaveBeenCalledWith(
|
||||||
|
'timeSystemA',
|
||||||
|
jasmine.any(Object)
|
||||||
|
);
|
||||||
|
expect(time.bounds).not.toHaveBeenCalledWith(
|
||||||
|
jasmine.any(Object)
|
||||||
|
);
|
||||||
|
expect(time.stopClock).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("updates timeSystem changes", function () {
|
||||||
|
search['tc.timeSystem'] = 'timeSystemB';
|
||||||
|
triggerLocationChange();
|
||||||
|
expect(time.timeSystem).toHaveBeenCalledWith(
|
||||||
|
'timeSystemB',
|
||||||
|
{
|
||||||
|
start: 10,
|
||||||
|
end: 20
|
||||||
}
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("updates bounds changes", function () {
|
||||||
|
search['tc.startBound'] = '100';
|
||||||
|
search['tc.endBound'] = '200';
|
||||||
|
triggerLocationChange();
|
||||||
|
expect(time.timeSystem).not.toHaveBeenCalledWith(
|
||||||
|
jasmine.any(), jasmine.any()
|
||||||
|
);
|
||||||
|
expect(time.bounds).toHaveBeenCalledWith({
|
||||||
|
start: 100,
|
||||||
|
end: 200
|
||||||
|
});
|
||||||
|
search['tc.endBound'] = '300';
|
||||||
|
triggerLocationChange();
|
||||||
|
expect(time.timeSystem).not.toHaveBeenCalledWith(
|
||||||
|
jasmine.any(), jasmine.any()
|
||||||
|
);
|
||||||
|
expect(time.bounds).toHaveBeenCalledWith({
|
||||||
|
start: 100,
|
||||||
|
end: 300
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("updates query parameters for realtime mode", function () {
|
it("updates clock mode w/o timeSystem change", function () {
|
||||||
expect(search).toEqual(expected);
|
search['tc.mode'] = 'clockA';
|
||||||
|
search['tc.startDelta'] = '50';
|
||||||
|
search['tc.endDelta'] = '50';
|
||||||
|
delete search['tc.endBound'];
|
||||||
|
delete search['tc.startBound'];
|
||||||
|
triggerLocationChange();
|
||||||
|
expect(time.clock).toHaveBeenCalledWith(
|
||||||
|
'clockA',
|
||||||
|
{
|
||||||
|
start: -50,
|
||||||
|
end: 50
|
||||||
|
}
|
||||||
|
);
|
||||||
|
expect(time.timeSystem).not.toHaveBeenCalledWith(
|
||||||
|
jasmine.any(), jasmine.any()
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("updates clock mode and timeSystem", function () {
|
||||||
|
search['tc.mode'] = 'clockA';
|
||||||
|
search['tc.startDelta'] = '50';
|
||||||
|
search['tc.endDelta'] = '50';
|
||||||
|
search['tc.timeSystem'] = 'timeSystemB';
|
||||||
|
delete search['tc.endBound'];
|
||||||
|
delete search['tc.startBound'];
|
||||||
|
triggerLocationChange();
|
||||||
|
expect(time.clock).toHaveBeenCalledWith(
|
||||||
|
'clockA',
|
||||||
|
{
|
||||||
|
start: -50,
|
||||||
|
end: 50
|
||||||
|
}
|
||||||
|
);
|
||||||
|
expect(time.timeSystem).toHaveBeenCalledWith('timeSystemB');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("listens for location changes", function () {
|
describe('location changes in clock mode', function () {
|
||||||
expect($rootScope.$on)
|
|
||||||
.toHaveBeenCalledWith('$locationChangeSuccess', jasmine.any(Function));
|
|
||||||
});
|
|
||||||
|
|
||||||
[false, true].forEach(function (fixed) {
|
|
||||||
var name = fixed ? "fixed-time" : "real-time";
|
|
||||||
var suffix = fixed ? 'Bound' : 'Delta';
|
|
||||||
describe("when " + name + " location changes occur", function () {
|
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
search['tc.mode'] = fixed ? 'fixed' : 'clocky';
|
time.clock(clockA.key, offsetsA);
|
||||||
search['tc.timeSystem'] = 'some-time-system';
|
time.timeSystem(timeSystemA.key);
|
||||||
search['tc.start' + suffix] = '12321';
|
initialize();
|
||||||
search['tc.end' + suffix] = '32123';
|
time.timeSystem.reset();
|
||||||
$rootScope.$on.mostRecentCall.args[1]();
|
time.bounds.reset();
|
||||||
|
time.clock.reset();
|
||||||
|
time.clockOffsets.reset();
|
||||||
|
time.stopClock.reset();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not change on spurious location change", function () {
|
||||||
|
triggerLocationChange();
|
||||||
|
expect(time.timeSystem).not.toHaveBeenCalledWith(
|
||||||
|
'timeSystemA',
|
||||||
|
jasmine.any(Object)
|
||||||
|
);
|
||||||
|
expect(time.clockOffsets).not.toHaveBeenCalledWith(
|
||||||
|
jasmine.any(Object)
|
||||||
|
);
|
||||||
|
expect(time.clock).not.toHaveBeenCalledWith(
|
||||||
|
jasmine.any(Object)
|
||||||
|
);
|
||||||
|
expect(time.bounds).not.toHaveBeenCalledWith(
|
||||||
|
jasmine.any(Object)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("changes time system", function () {
|
||||||
|
search['tc.timeSystem'] = 'timeSystemB';
|
||||||
|
triggerLocationChange();
|
||||||
|
expect(time.timeSystem).toHaveBeenCalledWith(
|
||||||
|
'timeSystemB'
|
||||||
|
);
|
||||||
|
expect(time.clockOffsets).not.toHaveBeenCalledWith(
|
||||||
|
jasmine.any(Object)
|
||||||
|
);
|
||||||
|
expect(time.clock).not.toHaveBeenCalledWith(
|
||||||
|
jasmine.any(Object)
|
||||||
|
);
|
||||||
|
expect(time.stopClock).not.toHaveBeenCalled();
|
||||||
|
expect(time.bounds).not.toHaveBeenCalledWith(
|
||||||
|
jasmine.any(Object)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("changes offsets", function () {
|
||||||
|
search['tc.startDelta'] = '50';
|
||||||
|
search['tc.endDelta'] = '50';
|
||||||
|
triggerLocationChange();
|
||||||
|
expect(time.timeSystem).not.toHaveBeenCalledWith(
|
||||||
|
'timeSystemA',
|
||||||
|
jasmine.any(Object)
|
||||||
|
);
|
||||||
|
expect(time.clockOffsets).toHaveBeenCalledWith(
|
||||||
|
{
|
||||||
|
start: -50,
|
||||||
|
end: 50
|
||||||
|
}
|
||||||
|
);
|
||||||
|
expect(time.clock).not.toHaveBeenCalledWith(
|
||||||
|
jasmine.any(Object)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("updates to fixed w/o timeSystem change", function () {
|
||||||
|
search['tc.mode'] = 'fixed';
|
||||||
|
search['tc.startBound'] = '234';
|
||||||
|
search['tc.endBound'] = '567';
|
||||||
|
delete search['tc.endDelta'];
|
||||||
|
delete search['tc.startDelta'];
|
||||||
|
|
||||||
|
triggerLocationChange();
|
||||||
|
expect(time.stopClock).toHaveBeenCalled();
|
||||||
|
expect(time.bounds).toHaveBeenCalledWith({
|
||||||
|
start: 234,
|
||||||
|
end: 567
|
||||||
|
});
|
||||||
|
expect(time.timeSystem).not.toHaveBeenCalledWith(
|
||||||
|
jasmine.any(), jasmine.any()
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("updates fixed and timeSystem", function () {
|
||||||
|
search['tc.mode'] = 'fixed';
|
||||||
|
search['tc.startBound'] = '234';
|
||||||
|
search['tc.endBound'] = '567';
|
||||||
|
search['tc.timeSystem'] = 'timeSystemB';
|
||||||
|
delete search['tc.endDelta'];
|
||||||
|
delete search['tc.startDelta'];
|
||||||
|
|
||||||
|
triggerLocationChange();
|
||||||
|
expect(time.stopClock).toHaveBeenCalled();
|
||||||
|
expect(time.timeSystem).toHaveBeenCalledWith(
|
||||||
|
'timeSystemB',
|
||||||
|
{
|
||||||
|
start: 234,
|
||||||
|
end: 567
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("updates clock", function () {
|
||||||
|
search['tc.mode'] = 'clockB';
|
||||||
|
triggerLocationChange();
|
||||||
|
expect(time.clock).toHaveBeenCalledWith(
|
||||||
|
'clockB',
|
||||||
|
{
|
||||||
|
start: -100,
|
||||||
|
end: 0
|
||||||
|
}
|
||||||
|
);
|
||||||
|
expect(time.timeSystem).not.toHaveBeenCalledWith(jasmine.any());
|
||||||
|
});
|
||||||
|
|
||||||
|
it("updates clock and timeSystem", function () {
|
||||||
|
search['tc.mode'] = 'clockB';
|
||||||
|
search['tc.timeSystem'] = 'timeSystemB';
|
||||||
|
triggerLocationChange();
|
||||||
|
expect(time.clock).toHaveBeenCalledWith(
|
||||||
|
'clockB',
|
||||||
|
{
|
||||||
|
start: -100,
|
||||||
|
end: 0
|
||||||
|
}
|
||||||
|
);
|
||||||
|
expect(time.timeSystem).toHaveBeenCalledWith(
|
||||||
|
'timeSystemB'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("updates clock and timeSystem and offsets", function () {
|
||||||
|
search['tc.mode'] = 'clockB';
|
||||||
|
search['tc.timeSystem'] = 'timeSystemB';
|
||||||
|
search['tc.startDelta'] = '50';
|
||||||
|
search['tc.endDelta'] = '50';
|
||||||
|
triggerLocationChange();
|
||||||
|
expect(time.clock).toHaveBeenCalledWith(
|
||||||
|
'clockB',
|
||||||
|
{
|
||||||
|
start: -50,
|
||||||
|
end: 50
|
||||||
|
}
|
||||||
|
);
|
||||||
|
expect(time.timeSystem).toHaveBeenCalledWith(
|
||||||
|
'timeSystemB'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (fixed) {
|
|
||||||
var bounds = { start: 12321, end: 32123 };
|
|
||||||
it("stops the clock", function () {
|
it("stops the clock", function () {
|
||||||
|
// this is a robustness test, unsure if desired, requires
|
||||||
|
// user to be manually editing location strings.
|
||||||
|
search['tc.mode'] = 'fixed';
|
||||||
|
triggerLocationChange();
|
||||||
expect(time.stopClock).toHaveBeenCalled();
|
expect(time.stopClock).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("sets the bounds", function () {
|
|
||||||
expect(time.bounds).toHaveBeenCalledWith(bounds);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("sets the time system with bounds", function () {
|
|
||||||
expect(time.timeSystem).toHaveBeenCalledWith(
|
|
||||||
search['tc.timeSystem'],
|
|
||||||
bounds
|
|
||||||
);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
var clockOffsets = { start: -12321, end: 32123 };
|
|
||||||
|
|
||||||
it("sets the clock", function () {
|
describe("location updates from time API in fixed", function () {
|
||||||
expect(time.stopClock).not.toHaveBeenCalled();
|
beforeEach(function () {
|
||||||
expect(time.clock).toHaveBeenCalledWith(
|
time.timeSystem(timeSystemA.key, boundsA);
|
||||||
search['tc.mode'],
|
initialize();
|
||||||
clockOffsets
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("sets clock offsets", function () {
|
it("updates on bounds change", function () {
|
||||||
expect(time.clockOffsets)
|
time.bounds(boundsB);
|
||||||
.toHaveBeenCalledWith(clockOffsets);
|
expect(search).toEqual({
|
||||||
});
|
'tc.mode': 'fixed',
|
||||||
|
'tc.startBound': '120',
|
||||||
it("sets the time system without bounds", function () {
|
'tc.endBound': '360',
|
||||||
expect(time.timeSystem).toHaveBeenCalledWith(
|
'tc.timeSystem': 'timeSystemA'
|
||||||
search['tc.timeSystem']
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("updates on timeSystem change", function () {
|
||||||
|
time.timeSystem(timeSystemB, boundsA);
|
||||||
|
expect(search).toEqual({
|
||||||
|
'tc.mode': 'fixed',
|
||||||
|
'tc.startBound': '10',
|
||||||
|
'tc.endBound': '20',
|
||||||
|
'tc.timeSystem': 'timeSystemB'
|
||||||
|
});
|
||||||
|
time.timeSystem(timeSystemA, boundsB);
|
||||||
|
expect(search).toEqual({
|
||||||
|
'tc.mode': 'fixed',
|
||||||
|
'tc.startBound': '120',
|
||||||
|
'tc.endBound': '360',
|
||||||
|
'tc.timeSystem': 'timeSystemA'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Updates to clock", function () {
|
||||||
|
time.clock(clockA, offsetsA);
|
||||||
|
expect(search).toEqual({
|
||||||
|
'tc.mode': 'clockA',
|
||||||
|
'tc.startDelta': '100',
|
||||||
|
'tc.endDelta': '0',
|
||||||
|
'tc.timeSystem': 'timeSystemA'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("location updates from time API in fixed", function () {
|
||||||
|
beforeEach(function () {
|
||||||
|
time.clock(clockA.key, offsetsA);
|
||||||
|
time.timeSystem(timeSystemA.key);
|
||||||
|
initialize();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("updates offsets", function () {
|
||||||
|
time.clockOffsets(offsetsB);
|
||||||
|
expect(search).toEqual({
|
||||||
|
'tc.mode': 'clockA',
|
||||||
|
'tc.startDelta': '50',
|
||||||
|
'tc.endDelta': '50',
|
||||||
|
'tc.timeSystem': 'timeSystemA'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("updates clocks", function () {
|
||||||
|
time.clock(clockB, offsetsA);
|
||||||
|
expect(search).toEqual({
|
||||||
|
'tc.mode': 'clockB',
|
||||||
|
'tc.startDelta': '100',
|
||||||
|
'tc.endDelta': '0',
|
||||||
|
'tc.timeSystem': 'timeSystemA'
|
||||||
|
});
|
||||||
|
time.clock(clockA, offsetsB);
|
||||||
|
expect(search).toEqual({
|
||||||
|
'tc.mode': 'clockA',
|
||||||
|
'tc.startDelta': '50',
|
||||||
|
'tc.endDelta': '50',
|
||||||
|
'tc.timeSystem': 'timeSystemA'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("updates timesystems", function () {
|
||||||
|
time.timeSystem(timeSystemB);
|
||||||
|
expect(search).toEqual({
|
||||||
|
'tc.mode': 'clockA',
|
||||||
|
'tc.startDelta': '100',
|
||||||
|
'tc.endDelta': '0',
|
||||||
|
'tc.timeSystem': 'timeSystemB'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("stops the clock", function () {
|
||||||
|
time.stopClock();
|
||||||
|
expect(search).toEqual({
|
||||||
|
'tc.mode': 'fixed',
|
||||||
|
'tc.startBound': '900',
|
||||||
|
'tc.endBound': '1000',
|
||||||
|
'tc.timeSystem': 'timeSystemA'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
Reference in New Issue
Block a user