mirror of
https://github.com/nasa/openmct.git
synced 2025-01-31 00:23:54 +00:00
[Time] Encode time settings in URL (#1620)
* [Time Conductor] Skeleton class for URL handling #1550 * [Time Conductor] Scaffold in param handling * [Time Conductor] Finish sketching in URL handler * [Time Conductor] Usage correct constants for bounds * [Time Conductor] Use start/end for bounds/deltas * [Time] Move URL handler Per discussion, https://github.com/nasa/openmct/issues/1550#issuecomment-308849449 * [Time] Rename URL handler * [Time] Rename URL handler script * [Time] Use Time API from URL handler * [Time] Utilize Time API * [Time] Listen for changes, synchronize URL * [Time] Move URL handler into adapter ...as it uses Angular constructs. * [Time] Wire URL handler into adapter bundle * [Time] Pass correct constructor arguments to URL handler * [Time] Begin debugging URL handling * [Time] Clarify and correct logic for bounds/deltas in URL * [Time] Define timeSystem * [Time] Pass start/end into time API as numbers ...instead of strings. * [Time] Avoid creating redundant objects * [Time] Restructure fixed vs clock logic * [Time] Stop clock correctly for fixed mode * [Time] Fix hasBounds/hasDeltas logic ...given that both inputs will be strings when read from search params, _.isFinite was doomed to return false. * [Time] Check for complete information ...before updating Time API to reflect search state. Additionally, flatten logic to ease readability. * [Time] Begin testing TimeSettingsURLHandler * [Time] Test fixed mode query string updates * [Time] Test realtime mode query string updates * [Time] Test update of time API from query params * [Time] Add missing semicolons Satisfies JSHint; fixes #1550
This commit is contained in:
parent
1d7d56d5e7
commit
0713941812
@ -32,6 +32,7 @@ define([
|
||||
'./policies/AdapterCompositionPolicy',
|
||||
'./policies/AdaptedViewPolicy',
|
||||
'./runs/AlternateCompositionInitializer',
|
||||
'./runs/TimeSettingsURLHandler',
|
||||
'text!./templates/adapted-view-template.html'
|
||||
], function (
|
||||
legacyRegistry,
|
||||
@ -45,6 +46,7 @@ define([
|
||||
AdapterCompositionPolicy,
|
||||
AdaptedViewPolicy,
|
||||
AlternateCompositionInitializer,
|
||||
TimeSettingsURLHandler,
|
||||
adaptedViewTemplate
|
||||
) {
|
||||
legacyRegistry.register('src/adapter', {
|
||||
@ -121,6 +123,16 @@ define([
|
||||
{
|
||||
implementation: AlternateCompositionInitializer,
|
||||
depends: ["openmct"]
|
||||
},
|
||||
{
|
||||
implementation: function (openmct, $location, $rootScope) {
|
||||
return new TimeSettingsURLHandler(
|
||||
openmct.time,
|
||||
$location,
|
||||
$rootScope
|
||||
);
|
||||
},
|
||||
depends: ["openmct", "$location", "$rootScope"]
|
||||
}
|
||||
],
|
||||
views: [
|
||||
|
117
src/adapter/runs/TimeSettingsURLHandler.js
Normal file
117
src/adapter/runs/TimeSettingsURLHandler.js
Normal file
@ -0,0 +1,117 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2017, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define([], function () {
|
||||
// Parameter names in query string
|
||||
var SEARCH = {
|
||||
MODE: 'tc.mode',
|
||||
TIME_SYSTEM: 'tc.timeSystem',
|
||||
START_BOUND: 'tc.startBound',
|
||||
END_BOUND: 'tc.endBound',
|
||||
START_DELTA: 'tc.startDelta',
|
||||
END_DELTA: 'tc.endDelta'
|
||||
};
|
||||
var TIME_EVENTS = ['bounds', 'timeSystem', 'clock', 'clockOffsets'];
|
||||
|
||||
/**
|
||||
* Communicates settings from the URL to the time API,
|
||||
* and vice versa.
|
||||
*/
|
||||
function TimeSettingsURLHandler(time, $location, $rootScope) {
|
||||
this.time = time;
|
||||
this.$location = $location;
|
||||
|
||||
$rootScope.$on('$locationChangeSuccess', this.updateTime.bind(this));
|
||||
|
||||
TIME_EVENTS.forEach(function (event) {
|
||||
this.time.on(event, this.updateQueryParams.bind(this));
|
||||
}, this);
|
||||
|
||||
this.updateTime(); // Initialize
|
||||
}
|
||||
|
||||
TimeSettingsURLHandler.prototype.updateQueryParams = function () {
|
||||
var clock = this.time.clock();
|
||||
var fixed = !clock;
|
||||
var mode = fixed ? 'fixed' : clock.key;
|
||||
var timeSystem = this.time.timeSystem().key;
|
||||
|
||||
this.$location.search(SEARCH.MODE, mode);
|
||||
this.$location.search(SEARCH.TIME_SYSTEM, timeSystem);
|
||||
|
||||
if (fixed) {
|
||||
var bounds = this.time.bounds();
|
||||
this.$location.search(SEARCH.START_BOUND, bounds.start);
|
||||
this.$location.search(SEARCH.END_BOUND, bounds.end);
|
||||
this.$location.search(SEARCH.START_DELTA, null);
|
||||
this.$location.search(SEARCH.END_DELTA, null);
|
||||
} else {
|
||||
var deltas = this.time.clockOffsets();
|
||||
this.$location.search(SEARCH.START_BOUND, null);
|
||||
this.$location.search(SEARCH.END_BOUND, null);
|
||||
this.$location.search(SEARCH.START_DELTA, -deltas.start);
|
||||
this.$location.search(SEARCH.END_DELTA, deltas.end);
|
||||
}
|
||||
};
|
||||
|
||||
TimeSettingsURLHandler.prototype.updateTime = function () {
|
||||
var searchParams = this.$location.search();
|
||||
var mode = searchParams[SEARCH.MODE];
|
||||
var timeSystem = searchParams[SEARCH.TIME_SYSTEM];
|
||||
var clockOffsets = {
|
||||
start: -searchParams[SEARCH.START_DELTA],
|
||||
end: +searchParams[SEARCH.END_DELTA]
|
||||
};
|
||||
var bounds = {
|
||||
start: +searchParams[SEARCH.START_BOUND],
|
||||
end: +searchParams[SEARCH.END_BOUND]
|
||||
};
|
||||
var fixed = (mode === 'fixed');
|
||||
var clock = fixed ? undefined : mode;
|
||||
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) {
|
||||
this.time.timeSystem(timeSystem, bounds);
|
||||
this.time.stopClock();
|
||||
}
|
||||
|
||||
if (!fixed && clock && hasDeltas) {
|
||||
this.time.clock(clock, clockOffsets);
|
||||
this.time.timeSystem(timeSystem);
|
||||
}
|
||||
|
||||
if (hasDeltas && !fixed) {
|
||||
this.time.clockOffsets(clockOffsets);
|
||||
}
|
||||
|
||||
if (hasBounds && fixed) {
|
||||
this.time.bounds(bounds);
|
||||
}
|
||||
};
|
||||
|
||||
return TimeSettingsURLHandler;
|
||||
});
|
185
src/adapter/runs/TimeSettingsURLHandlerSpec.js
Normal file
185
src/adapter/runs/TimeSettingsURLHandlerSpec.js
Normal file
@ -0,0 +1,185 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2017, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define(['./TimeSettingsURLHandler'], function (TimeSettingsURLHandler) {
|
||||
describe("TimeSettingsURLHandler", function () {
|
||||
var time;
|
||||
var $location;
|
||||
var $rootScope;
|
||||
var search;
|
||||
var handler;
|
||||
|
||||
beforeEach(function () {
|
||||
time = jasmine.createSpyObj('time', [
|
||||
'on',
|
||||
'bounds',
|
||||
'clockOffsets',
|
||||
'timeSystem',
|
||||
'clock',
|
||||
'stopClock'
|
||||
]);
|
||||
$location = jasmine.createSpyObj('$location', [
|
||||
'search'
|
||||
]);
|
||||
$rootScope = jasmine.createSpyObj('$rootScope', [
|
||||
'$on'
|
||||
]);
|
||||
|
||||
time.timeSystem.andReturn({ key: 'test-time-system' });
|
||||
|
||||
search = {};
|
||||
$location.search.andCallFake(function (key, value) {
|
||||
if (arguments.length === 0) {
|
||||
return search;
|
||||
}
|
||||
if (value === null) {
|
||||
delete search[key];
|
||||
} else {
|
||||
search[key] = String(value);
|
||||
}
|
||||
return this;
|
||||
});
|
||||
|
||||
handler = new TimeSettingsURLHandler(
|
||||
time,
|
||||
$location,
|
||||
$rootScope
|
||||
);
|
||||
});
|
||||
|
||||
['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) {
|
||||
if (call.args[0] === event) {
|
||||
call.args[1]();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it("updates query parameters for fixed mode", function () {
|
||||
expect(search).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe("when " + event + " time event occurs with a clock", function () {
|
||||
var expected;
|
||||
|
||||
beforeEach(function () {
|
||||
expected = {
|
||||
'tc.mode': 'clocky',
|
||||
'tc.timeSystem': 'test-time-system',
|
||||
'tc.startDelta': '123',
|
||||
'tc.endDelta': '456'
|
||||
};
|
||||
time.clock.andReturn({ key: 'clocky' });
|
||||
time.clockOffsets.andReturn({ start: -123, end: 456 });
|
||||
|
||||
time.on.calls.forEach(function (call) {
|
||||
if (call.args[0] === event) {
|
||||
call.args[1]();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it("updates query parameters for realtime mode", function () {
|
||||
expect(search).toEqual(expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("listens for location changes", 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 () {
|
||||
search['tc.mode'] = fixed ? 'fixed' : 'clocky';
|
||||
search['tc.timeSystem'] = 'some-time-system';
|
||||
search['tc.start' + suffix] = '12321';
|
||||
search['tc.end' + suffix] = '32123';
|
||||
$rootScope.$on.mostRecentCall.args[1]();
|
||||
});
|
||||
|
||||
if (fixed) {
|
||||
var bounds = { start: 12321, end: 32123 };
|
||||
it("stops the clock", function () {
|
||||
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 () {
|
||||
expect(time.stopClock).not.toHaveBeenCalled();
|
||||
expect(time.clock).toHaveBeenCalledWith(
|
||||
search['tc.mode'],
|
||||
clockOffsets
|
||||
);
|
||||
});
|
||||
|
||||
it("sets clock offsets", function () {
|
||||
expect(time.clockOffsets)
|
||||
.toHaveBeenCalledWith(clockOffsets);
|
||||
});
|
||||
|
||||
it("sets the time system without bounds", function () {
|
||||
expect(time.timeSystem).toHaveBeenCalledWith(
|
||||
search['tc.timeSystem']
|
||||
);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user