mirror of
https://github.com/nasa/openmct.git
synced 2025-06-10 19:31:42 +00:00
[Timer] Re-implement Timer object in Vue.js (#4311)
* Re-implemented timer and clock and installed as a plugin * Clock indicator is installed as configuration to clock plugin * Uses moment Co-authored-by: Andrew Henry <akhenry@gmail.com> Co-authored-by: Nikhil <nikhil.k.mandlik@nasa.gov>
This commit is contained in:
parent
b8fabb7e73
commit
6d4a324fca
@ -196,6 +196,7 @@
|
|||||||
{indicator: true}
|
{indicator: true}
|
||||||
));
|
));
|
||||||
openmct.install(openmct.plugins.Clock({ enableClockIndicator: true }));
|
openmct.install(openmct.plugins.Clock({ enableClockIndicator: true }));
|
||||||
|
openmct.install(openmct.plugins.Timer());
|
||||||
openmct.start();
|
openmct.start();
|
||||||
</script>
|
</script>
|
||||||
</html>
|
</html>
|
||||||
|
@ -1,209 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2014-2021, 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([
|
|
||||||
"./src/services/TickerService",
|
|
||||||
"./src/services/TimerService",
|
|
||||||
"./src/controllers/TimerController",
|
|
||||||
"./src/controllers/RefreshingController",
|
|
||||||
"./src/actions/StartTimerAction",
|
|
||||||
"./src/actions/RestartTimerAction",
|
|
||||||
"./src/actions/StopTimerAction",
|
|
||||||
"./src/actions/PauseTimerAction",
|
|
||||||
"./res/templates/timer.html"
|
|
||||||
], function (
|
|
||||||
TickerService,
|
|
||||||
TimerService,
|
|
||||||
TimerController,
|
|
||||||
RefreshingController,
|
|
||||||
StartTimerAction,
|
|
||||||
RestartTimerAction,
|
|
||||||
StopTimerAction,
|
|
||||||
PauseTimerAction,
|
|
||||||
timerTemplate
|
|
||||||
) {
|
|
||||||
return {
|
|
||||||
name: "platform/features/clock",
|
|
||||||
definition: {
|
|
||||||
"name": "Clocks/Timers",
|
|
||||||
"descriptions": "Domain objects for displaying current & relative times.",
|
|
||||||
"configuration": {
|
|
||||||
"paths": {
|
|
||||||
"moment-duration-format": "moment-duration-format"
|
|
||||||
},
|
|
||||||
"shim": {
|
|
||||||
"moment-duration-format": {
|
|
||||||
"deps": [
|
|
||||||
"moment"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"extensions": {
|
|
||||||
"constants": [
|
|
||||||
{
|
|
||||||
"key": "CLOCK_INDICATOR_FORMAT",
|
|
||||||
"value": "YYYY/MM/DD HH:mm:ss"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"services": [
|
|
||||||
{
|
|
||||||
"key": "tickerService",
|
|
||||||
"implementation": TickerService,
|
|
||||||
"depends": [
|
|
||||||
"$timeout",
|
|
||||||
"now"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "timerService",
|
|
||||||
"implementation": TimerService,
|
|
||||||
"depends": ["openmct"]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"controllers": [
|
|
||||||
{
|
|
||||||
"key": "TimerController",
|
|
||||||
"implementation": TimerController,
|
|
||||||
"depends": [
|
|
||||||
"$scope",
|
|
||||||
"$window",
|
|
||||||
"now"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "RefreshingController",
|
|
||||||
"implementation": RefreshingController,
|
|
||||||
"depends": [
|
|
||||||
"$scope",
|
|
||||||
"tickerService"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"views": [
|
|
||||||
{
|
|
||||||
"key": "timer",
|
|
||||||
"type": "timer",
|
|
||||||
"editable": false,
|
|
||||||
"template": timerTemplate
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"actions": [
|
|
||||||
{
|
|
||||||
"key": "timer.start",
|
|
||||||
"implementation": StartTimerAction,
|
|
||||||
"depends": [
|
|
||||||
"now"
|
|
||||||
],
|
|
||||||
"category": "contextual",
|
|
||||||
"name": "Start",
|
|
||||||
"cssClass": "icon-play",
|
|
||||||
"priority": "preferred"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "timer.pause",
|
|
||||||
"implementation": PauseTimerAction,
|
|
||||||
"depends": [
|
|
||||||
"now"
|
|
||||||
],
|
|
||||||
"category": "contextual",
|
|
||||||
"name": "Pause",
|
|
||||||
"cssClass": "icon-pause",
|
|
||||||
"priority": "preferred"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "timer.restart",
|
|
||||||
"implementation": RestartTimerAction,
|
|
||||||
"depends": [
|
|
||||||
"now"
|
|
||||||
],
|
|
||||||
"category": "contextual",
|
|
||||||
"name": "Restart at 0",
|
|
||||||
"cssClass": "icon-refresh",
|
|
||||||
"priority": "preferred"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "timer.stop",
|
|
||||||
"implementation": StopTimerAction,
|
|
||||||
"depends": [
|
|
||||||
"now"
|
|
||||||
],
|
|
||||||
"category": "contextual",
|
|
||||||
"name": "Stop",
|
|
||||||
"cssClass": "icon-box-round-corners",
|
|
||||||
"priority": "preferred"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"types": [
|
|
||||||
{
|
|
||||||
"key": "timer",
|
|
||||||
"name": "Timer",
|
|
||||||
"cssClass": "icon-timer",
|
|
||||||
"description": "A timer that counts up or down to a datetime. Timers can be started, stopped and reset whenever needed, and support a variety of display formats. Each Timer displays the same value to all users. Timers can be added to Display Layouts.",
|
|
||||||
"priority": 100,
|
|
||||||
"features": [
|
|
||||||
"creation"
|
|
||||||
],
|
|
||||||
"properties": [
|
|
||||||
{
|
|
||||||
"key": "timestamp",
|
|
||||||
"control": "datetime",
|
|
||||||
"name": "Target"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "timerFormat",
|
|
||||||
"control": "select",
|
|
||||||
"name": "Display Format",
|
|
||||||
"options": [
|
|
||||||
{
|
|
||||||
"value": "long",
|
|
||||||
"name": "DDD hh:mm:ss"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"value": "short",
|
|
||||||
"name": "hh:mm:ss"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"model": {
|
|
||||||
"timerFormat": "DDD hh:mm:ss"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"runs": [],
|
|
||||||
"licenses": [
|
|
||||||
{
|
|
||||||
"name": "moment-duration-format",
|
|
||||||
"version": "1.3.0",
|
|
||||||
"author": "John Madhavan-Reese",
|
|
||||||
"description": "Duration parsing/formatting",
|
|
||||||
"website": "https://github.com/jsmreese/moment-duration-format",
|
|
||||||
"copyright": "Copyright 2014 John Madhavan-Reese",
|
|
||||||
"license": "license-mit",
|
|
||||||
"link": "https://github.com/jsmreese/moment-duration-format/blob/master/LICENSE"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
@ -1,37 +0,0 @@
|
|||||||
<!--
|
|
||||||
Open MCT, Copyright (c) 2009-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.
|
|
||||||
-->
|
|
||||||
<div class="c-timer u-style-receiver js-style-receiver is-{{timer.timerState}}" ng-controller="TimerController as timer">
|
|
||||||
<div class="c-timer__controls">
|
|
||||||
<button ng-click="timer.clickStopButton()"
|
|
||||||
ng-hide="timer.timerState == 'stopped'"
|
|
||||||
title="Reset"
|
|
||||||
class="c-timer__ctrl-reset c-icon-button c-icon-button--major icon-reset"></button>
|
|
||||||
<button ng-click="timer.clickButton()"
|
|
||||||
title="{{timer.buttonText()}}"
|
|
||||||
class="c-timer__ctrl-pause-play c-icon-button c-icon-button--major {{timer.buttonCssClass()}}"></button>
|
|
||||||
</div>
|
|
||||||
<div class="c-timer__direction {{timer.signClass()}}"
|
|
||||||
ng-hide="!timer.signClass()"></div>
|
|
||||||
<div class="c-timer__value">{{timer.text() || "--:--:--"}}
|
|
||||||
</div>
|
|
||||||
<span class="c-timer__ng-controller u-contents" ng-controller="RefreshingController"></span>
|
|
||||||
</div>
|
|
@ -1,70 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2009-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 () {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implements the "Pause" action for timers.
|
|
||||||
*
|
|
||||||
* Sets the reference pausedTime in a timer to the current
|
|
||||||
* time, such that it stops counting up.
|
|
||||||
*
|
|
||||||
* @implements {Action}
|
|
||||||
* @memberof platform/features/clock
|
|
||||||
* @constructor
|
|
||||||
* @param {Function} now a function which returns the current
|
|
||||||
* time (typically wrapping `Date.now`)
|
|
||||||
* @param {ActionContext} context the context for this action
|
|
||||||
*/
|
|
||||||
function PauseTimerAction(now, context) {
|
|
||||||
this.domainObject = context.domainObject;
|
|
||||||
this.now = now;
|
|
||||||
}
|
|
||||||
|
|
||||||
PauseTimerAction.appliesTo = function (context) {
|
|
||||||
var model =
|
|
||||||
(context.domainObject && context.domainObject.getModel())
|
|
||||||
|| {};
|
|
||||||
|
|
||||||
// We show this variant for timers which have
|
|
||||||
// a target time, or is in a playing state.
|
|
||||||
return model.type === 'timer'
|
|
||||||
&& model.timerState === 'started';
|
|
||||||
};
|
|
||||||
|
|
||||||
PauseTimerAction.prototype.perform = function () {
|
|
||||||
var domainObject = this.domainObject,
|
|
||||||
now = this.now;
|
|
||||||
|
|
||||||
function updateModel(model) {
|
|
||||||
model.timerState = 'paused';
|
|
||||||
model.pausedTime = now();
|
|
||||||
}
|
|
||||||
|
|
||||||
return domainObject.useCapability('mutation', updateModel);
|
|
||||||
};
|
|
||||||
|
|
||||||
return PauseTimerAction;
|
|
||||||
}
|
|
||||||
);
|
|
@ -1,70 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2009-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 () {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implements the "Restart at 0" action.
|
|
||||||
*
|
|
||||||
* Behaves the same as (and delegates functionality to)
|
|
||||||
* the "Start" action.
|
|
||||||
*
|
|
||||||
* @implements {Action}
|
|
||||||
* @memberof platform/features/clock
|
|
||||||
* @constructor
|
|
||||||
* @param {Function} now a function which returns the current
|
|
||||||
* time (typically wrapping `Date.now`)
|
|
||||||
* @param {ActionContext} context the context for this action
|
|
||||||
*/
|
|
||||||
function RestartTimerAction(now, context) {
|
|
||||||
this.domainObject = context.domainObject;
|
|
||||||
this.now = now;
|
|
||||||
}
|
|
||||||
|
|
||||||
RestartTimerAction.appliesTo = function (context) {
|
|
||||||
var model =
|
|
||||||
(context.domainObject && context.domainObject.getModel())
|
|
||||||
|| {};
|
|
||||||
|
|
||||||
// We show this variant for timers which already have a target time.
|
|
||||||
return model.type === 'timer'
|
|
||||||
&& model.timerState !== 'stopped';
|
|
||||||
};
|
|
||||||
|
|
||||||
RestartTimerAction.prototype.perform = function () {
|
|
||||||
var domainObject = this.domainObject,
|
|
||||||
now = this.now;
|
|
||||||
|
|
||||||
function updateModel(model) {
|
|
||||||
model.timestamp = now();
|
|
||||||
model.timerState = 'started';
|
|
||||||
model.pausedTime = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
return domainObject.useCapability('mutation', updateModel);
|
|
||||||
};
|
|
||||||
|
|
||||||
return RestartTimerAction;
|
|
||||||
}
|
|
||||||
);
|
|
@ -1,78 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2009-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 () {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implements the "Start" action for timers.
|
|
||||||
*
|
|
||||||
* Sets the reference timestamp in a timer to the current
|
|
||||||
* time, such that it begins counting up.
|
|
||||||
*
|
|
||||||
* @implements {Action}
|
|
||||||
* @memberof platform/features/clock
|
|
||||||
* @constructor
|
|
||||||
* @param {Function} now a function which returns the current
|
|
||||||
* time (typically wrapping `Date.now`)
|
|
||||||
* @param {ActionContext} context the context for this action
|
|
||||||
*/
|
|
||||||
function StartTimerAction(now, context) {
|
|
||||||
this.domainObject = context.domainObject;
|
|
||||||
this.now = now;
|
|
||||||
}
|
|
||||||
|
|
||||||
StartTimerAction.appliesTo = function (context) {
|
|
||||||
var model =
|
|
||||||
(context.domainObject && context.domainObject.getModel())
|
|
||||||
|| {};
|
|
||||||
|
|
||||||
// We show this variant for timers which do not yet have
|
|
||||||
// a target time.
|
|
||||||
return model.type === 'timer'
|
|
||||||
&& model.timerState !== 'started';
|
|
||||||
};
|
|
||||||
|
|
||||||
StartTimerAction.prototype.perform = function () {
|
|
||||||
var domainObject = this.domainObject,
|
|
||||||
now = this.now;
|
|
||||||
|
|
||||||
function updateModel(model) {
|
|
||||||
//if we are resuming
|
|
||||||
if (model.pausedTime) {
|
|
||||||
var timeShift = now() - model.pausedTime;
|
|
||||||
model.timestamp = model.timestamp + timeShift;
|
|
||||||
} else {
|
|
||||||
model.timestamp = now();
|
|
||||||
}
|
|
||||||
|
|
||||||
model.timerState = 'started';
|
|
||||||
model.pausedTime = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
return domainObject.useCapability('mutation', updateModel);
|
|
||||||
};
|
|
||||||
|
|
||||||
return StartTimerAction;
|
|
||||||
}
|
|
||||||
);
|
|
@ -1,70 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2009-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 () {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implements the "Stop" action for timers.
|
|
||||||
*
|
|
||||||
* Sets the reference timestamp in a timer undefined,
|
|
||||||
* such that it is reset and makes no movements.
|
|
||||||
*
|
|
||||||
* @implements {Action}
|
|
||||||
* @memberof platform/features/clock
|
|
||||||
* @constructor
|
|
||||||
* @param {Function} now a function which returns the current
|
|
||||||
* time (typically wrapping `Date.now`)
|
|
||||||
* @param {ActionContext} context the context for this action
|
|
||||||
*/
|
|
||||||
function StopTimerAction(now, context) {
|
|
||||||
this.domainObject = context.domainObject;
|
|
||||||
this.now = now;
|
|
||||||
}
|
|
||||||
|
|
||||||
StopTimerAction.appliesTo = function (context) {
|
|
||||||
var model =
|
|
||||||
(context.domainObject && context.domainObject.getModel())
|
|
||||||
|| {};
|
|
||||||
|
|
||||||
// We show this variant for timers which do not yet have
|
|
||||||
// a target time.
|
|
||||||
return model.type === 'timer'
|
|
||||||
&& model.timerState !== 'stopped';
|
|
||||||
};
|
|
||||||
|
|
||||||
StopTimerAction.prototype.perform = function () {
|
|
||||||
var domainObject = this.domainObject;
|
|
||||||
|
|
||||||
function updateModel(model) {
|
|
||||||
model.timestamp = undefined;
|
|
||||||
model.timerState = 'stopped';
|
|
||||||
model.pausedTime = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
return domainObject.useCapability('mutation', updateModel);
|
|
||||||
};
|
|
||||||
|
|
||||||
return StopTimerAction;
|
|
||||||
}
|
|
||||||
);
|
|
@ -1,55 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2009-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 () {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Continually refreshes the represented domain object.
|
|
||||||
*
|
|
||||||
* This is a short-term workaround to assure Timer views stay
|
|
||||||
* up-to-date; should be replaced by a global auto-refresh.
|
|
||||||
*
|
|
||||||
* @constructor
|
|
||||||
* @memberof platform/features/clock
|
|
||||||
* @param {angular.Scope} $scope the Angular scope
|
|
||||||
* @param {platform/features/clock.TickerService} tickerService
|
|
||||||
* a service used to align behavior with clock ticks
|
|
||||||
*/
|
|
||||||
function RefreshingController($scope, tickerService) {
|
|
||||||
var unlisten;
|
|
||||||
|
|
||||||
function triggerRefresh() {
|
|
||||||
var persistence = $scope.domainObject
|
|
||||||
&& $scope.domainObject.getCapability('persistence');
|
|
||||||
|
|
||||||
return persistence && persistence.refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
unlisten = tickerService.listen(triggerRefresh);
|
|
||||||
$scope.$on('$destroy', unlisten);
|
|
||||||
}
|
|
||||||
|
|
||||||
return RefreshingController;
|
|
||||||
}
|
|
||||||
);
|
|
@ -1,239 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2009-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(
|
|
||||||
['./TimerFormatter'],
|
|
||||||
function (TimerFormatter) {
|
|
||||||
|
|
||||||
var FORMATTER = new TimerFormatter();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Controller for views of a Timer domain object.
|
|
||||||
*
|
|
||||||
* @constructor
|
|
||||||
* @memberof platform/features/clock
|
|
||||||
* @param {angular.Scope} $scope the Angular scope
|
|
||||||
* @param $window Angular-provided window object
|
|
||||||
* @param {Function} now a function which returns the current
|
|
||||||
* time (typically wrapping `Date.now`)
|
|
||||||
*/
|
|
||||||
function TimerController($scope, $window, now) {
|
|
||||||
var formatter,
|
|
||||||
active = true,
|
|
||||||
relativeTimestamp,
|
|
||||||
lastTimestamp,
|
|
||||||
relativeTimerState,
|
|
||||||
self = this;
|
|
||||||
|
|
||||||
function update() {
|
|
||||||
var timeDelta = lastTimestamp - relativeTimestamp;
|
|
||||||
|
|
||||||
if (formatter && !isNaN(timeDelta)) {
|
|
||||||
self.textValue = formatter(timeDelta);
|
|
||||||
self.signValue = timeDelta < 0 ? "-"
|
|
||||||
: timeDelta >= 1000 ? "+" : "";
|
|
||||||
self.signCssClass = timeDelta < 0 ? "icon-minus"
|
|
||||||
: timeDelta >= 1000 ? "icon-plus" : "";
|
|
||||||
} else {
|
|
||||||
self.textValue = "";
|
|
||||||
self.signValue = "";
|
|
||||||
self.signCssClass = "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateFormat(key) {
|
|
||||||
formatter = FORMATTER[key] || FORMATTER.long;
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateTimestamp(timestamp) {
|
|
||||||
relativeTimestamp = timestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateTimerState(timerState) {
|
|
||||||
self.timerState = relativeTimerState = timerState;
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateActions(actionCapability, actionKey) {
|
|
||||||
self.relevantAction = actionCapability
|
|
||||||
&& actionCapability.getActions(actionKey)[0];
|
|
||||||
|
|
||||||
self.stopAction = relativeTimerState !== 'stopped'
|
|
||||||
? actionCapability && actionCapability.getActions('timer.stop')[0] : undefined;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function isPaused() {
|
|
||||||
return relativeTimerState === 'paused';
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleLegacyTimer(model) {
|
|
||||||
if (model.timerState === undefined) {
|
|
||||||
model.timerState = model.timestamp === undefined
|
|
||||||
? 'stopped' : 'started';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateObject(domainObject) {
|
|
||||||
var model = domainObject.getModel();
|
|
||||||
handleLegacyTimer(model);
|
|
||||||
|
|
||||||
var timestamp = model.timestamp,
|
|
||||||
formatKey = model.timerFormat,
|
|
||||||
timerState = model.timerState,
|
|
||||||
actionCapability = domainObject.getCapability('action'),
|
|
||||||
actionKey = (timerState !== 'started')
|
|
||||||
? 'timer.start' : 'timer.pause';
|
|
||||||
|
|
||||||
updateFormat(formatKey);
|
|
||||||
updateTimestamp(timestamp);
|
|
||||||
updateTimerState(timerState);
|
|
||||||
updateActions(actionCapability, actionKey);
|
|
||||||
|
|
||||||
//if paused on startup show last known position
|
|
||||||
if (isPaused() && !lastTimestamp) {
|
|
||||||
lastTimestamp = model.pausedTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleObjectChange(domainObject) {
|
|
||||||
if (domainObject) {
|
|
||||||
updateObject(domainObject);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleModification() {
|
|
||||||
handleObjectChange($scope.domainObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
function tick() {
|
|
||||||
var lastSign = self.signValue,
|
|
||||||
lastText = self.textValue;
|
|
||||||
|
|
||||||
if (!isPaused()) {
|
|
||||||
lastTimestamp = now();
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (relativeTimerState === undefined) {
|
|
||||||
handleModification();
|
|
||||||
}
|
|
||||||
|
|
||||||
// We're running in an animation frame, not in a digest cycle.
|
|
||||||
// We need to trigger a digest cycle if our displayable data
|
|
||||||
// changes.
|
|
||||||
if (lastSign !== self.signValue || lastText !== self.textValue) {
|
|
||||||
$scope.$apply();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (active) {
|
|
||||||
$window.requestAnimationFrame(tick);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$window.requestAnimationFrame(tick);
|
|
||||||
|
|
||||||
// Pull in the timer format from the domain object model
|
|
||||||
$scope.$watch('domainObject', handleObjectChange);
|
|
||||||
$scope.$watch('model.modified', handleModification);
|
|
||||||
|
|
||||||
// When the scope is destroyed, stop requesting anim. frames
|
|
||||||
$scope.$on('$destroy', function () {
|
|
||||||
active = false;
|
|
||||||
});
|
|
||||||
|
|
||||||
this.$scope = $scope;
|
|
||||||
this.signValue = '';
|
|
||||||
this.textValue = '';
|
|
||||||
this.updateObject = updateObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the CSS class to display the right icon
|
|
||||||
* for the start/pause button.
|
|
||||||
* @returns {string} cssclass to display
|
|
||||||
*/
|
|
||||||
TimerController.prototype.buttonCssClass = function () {
|
|
||||||
return this.relevantAction
|
|
||||||
? this.relevantAction.getMetadata().cssClass : "";
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the text to show for the start/pause button
|
|
||||||
* (e.g. in a tooltip)
|
|
||||||
* @returns {string} name of the action
|
|
||||||
*/
|
|
||||||
TimerController.prototype.buttonText = function () {
|
|
||||||
return this.relevantAction
|
|
||||||
? this.relevantAction.getMetadata().name : "";
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Perform the action associated with the start/pause button.
|
|
||||||
*/
|
|
||||||
TimerController.prototype.clickButton = function () {
|
|
||||||
if (this.relevantAction) {
|
|
||||||
this.relevantAction.perform();
|
|
||||||
this.updateObject(this.$scope.domainObject);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Perform the action associated with the stop button.
|
|
||||||
*/
|
|
||||||
TimerController.prototype.clickStopButton = function () {
|
|
||||||
if (this.stopAction) {
|
|
||||||
this.stopAction.perform();
|
|
||||||
this.updateObject(this.$scope.domainObject);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the sign (+ or -) of the current timer value, as
|
|
||||||
* displayable text.
|
|
||||||
* @returns {string} sign of the current timer value
|
|
||||||
*/
|
|
||||||
TimerController.prototype.sign = function () {
|
|
||||||
return this.signValue;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the sign (+ or -) of the current timer value, as
|
|
||||||
* a CSS class.
|
|
||||||
* @returns {string} sign of the current timer value
|
|
||||||
*/
|
|
||||||
TimerController.prototype.signClass = function () {
|
|
||||||
return this.signCssClass;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the text to display for the current timer value.
|
|
||||||
* @returns {string} current timer value
|
|
||||||
*/
|
|
||||||
TimerController.prototype.text = function () {
|
|
||||||
return this.textValue;
|
|
||||||
};
|
|
||||||
|
|
||||||
return TimerController;
|
|
||||||
}
|
|
||||||
);
|
|
@ -1,73 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2009-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(
|
|
||||||
['moment', 'moment-duration-format'],
|
|
||||||
function (moment) {
|
|
||||||
|
|
||||||
var SHORT_FORMAT = "HH:mm:ss",
|
|
||||||
LONG_FORMAT = "d[D] HH:mm:ss";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides formatting functions for Timers.
|
|
||||||
*
|
|
||||||
* Display formats for timers are a little different from what
|
|
||||||
* moment.js provides, so we have custom logic here. This specifically
|
|
||||||
* supports `TimerController`.
|
|
||||||
*
|
|
||||||
* @constructor
|
|
||||||
* @memberof platform/features/clock
|
|
||||||
*/
|
|
||||||
function TimerFormatter() {
|
|
||||||
}
|
|
||||||
|
|
||||||
// Round this timestamp down to the second boundary
|
|
||||||
// (e.g. 1124ms goes down to 1000ms, -2400ms goes down to -3000ms)
|
|
||||||
function toWholeSeconds(duration) {
|
|
||||||
return Math.abs(Math.floor(duration / 1000) * 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Format a duration for display, using the short form.
|
|
||||||
* (e.g. 03:33:11)
|
|
||||||
* @param {number} duration the duration, in milliseconds
|
|
||||||
* @param {boolean} sign true if positive
|
|
||||||
*/
|
|
||||||
TimerFormatter.prototype.short = function (duration) {
|
|
||||||
return moment.duration(toWholeSeconds(duration), 'ms')
|
|
||||||
.format(SHORT_FORMAT, { trim: false });
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Format a duration for display, using the long form.
|
|
||||||
* (e.g. 0d 03:33:11)
|
|
||||||
* @param {number} duration the duration, in milliseconds
|
|
||||||
* @param {boolean} sign true if positive
|
|
||||||
*/
|
|
||||||
TimerFormatter.prototype.long = function (duration) {
|
|
||||||
return moment.duration(toWholeSeconds(duration), 'ms')
|
|
||||||
.format(LONG_FORMAT, { trim: false });
|
|
||||||
};
|
|
||||||
|
|
||||||
return TimerFormatter;
|
|
||||||
}
|
|
||||||
);
|
|
@ -1,87 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2009-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 () {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calls functions every second, as close to the actual second
|
|
||||||
* tick as is feasible.
|
|
||||||
* @constructor
|
|
||||||
* @memberof platform/features/clock
|
|
||||||
* @param $timeout Angular's $timeout
|
|
||||||
* @param {Function} now function to provide the current time in ms
|
|
||||||
*/
|
|
||||||
function TickerService($timeout, now) {
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
function tick() {
|
|
||||||
var timestamp = now(),
|
|
||||||
millis = timestamp % 1000;
|
|
||||||
|
|
||||||
// Only update callbacks if a second has actually passed.
|
|
||||||
if (timestamp >= self.last + 1000) {
|
|
||||||
self.callbacks.forEach(function (callback) {
|
|
||||||
callback(timestamp);
|
|
||||||
});
|
|
||||||
self.last = timestamp - millis;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to update at exactly the next second
|
|
||||||
$timeout(tick, 1000 - millis, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
tick();
|
|
||||||
|
|
||||||
this.callbacks = [];
|
|
||||||
this.last = now() - 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Listen for clock ticks. The provided callback will
|
|
||||||
* be invoked with the current timestamp (in milliseconds
|
|
||||||
* since Jan 1 1970) at regular intervals, as near to the
|
|
||||||
* second boundary as possible.
|
|
||||||
*
|
|
||||||
* @param {Function} callback callback to invoke
|
|
||||||
* @returns {Function} a function to unregister this listener
|
|
||||||
*/
|
|
||||||
TickerService.prototype.listen = function (callback) {
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
self.callbacks.push(callback);
|
|
||||||
|
|
||||||
// Provide immediate feedback
|
|
||||||
callback(this.last);
|
|
||||||
|
|
||||||
// Provide a deregistration function
|
|
||||||
return function () {
|
|
||||||
self.callbacks = self.callbacks.filter(function (cb) {
|
|
||||||
return cb !== callback;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
return TickerService;
|
|
||||||
}
|
|
||||||
);
|
|
@ -1,113 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2009-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(['EventEmitter'], function (EventEmitter) {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tracks the currently-followed Timer object. Used by
|
|
||||||
* timelines et al to synchronize to a particular timer.
|
|
||||||
*
|
|
||||||
* The TimerService emits `change` events when the active timer
|
|
||||||
* is changed.
|
|
||||||
*/
|
|
||||||
function TimerService(openmct) {
|
|
||||||
EventEmitter.apply(this);
|
|
||||||
this.time = openmct.time;
|
|
||||||
this.objects = openmct.objects;
|
|
||||||
}
|
|
||||||
|
|
||||||
TimerService.prototype = Object.create(EventEmitter.prototype);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set (or clear, if `timer` is undefined) the currently active timer.
|
|
||||||
* @param {DomainObject} timer the new active timer
|
|
||||||
* @emits change
|
|
||||||
*/
|
|
||||||
TimerService.prototype.setTimer = function (timer) {
|
|
||||||
this.timer = timer;
|
|
||||||
this.emit('change', timer);
|
|
||||||
|
|
||||||
if (this.stopObserving) {
|
|
||||||
this.stopObserving();
|
|
||||||
delete this.stopObserving;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (timer) {
|
|
||||||
this.stopObserving =
|
|
||||||
this.objects.observe(timer, '*', this.setTimer.bind(this));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the currently active timer.
|
|
||||||
* @return {DomainObject} the active timer
|
|
||||||
* @emits change
|
|
||||||
*/
|
|
||||||
TimerService.prototype.getTimer = function () {
|
|
||||||
return this.timer;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if there is a currently active timer.
|
|
||||||
* @return {boolean} true if there is a timer
|
|
||||||
*/
|
|
||||||
TimerService.prototype.hasTimer = function () {
|
|
||||||
return Boolean(this.timer);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert the provided timestamp to milliseconds relative to
|
|
||||||
* the active timer.
|
|
||||||
* @return {number} milliseconds since timer start
|
|
||||||
*/
|
|
||||||
TimerService.prototype.convert = function (timestamp) {
|
|
||||||
var clock = this.time.clock();
|
|
||||||
var canConvert = this.hasTimer()
|
|
||||||
&& Boolean(clock)
|
|
||||||
&& this.timer.timerState !== 'stopped';
|
|
||||||
|
|
||||||
if (!canConvert) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
var now = clock.currentValue();
|
|
||||||
var delta = this.timer.timerState === 'paused'
|
|
||||||
? now - this.timer.pausedTime : 0;
|
|
||||||
var epoch = this.timer.timestamp;
|
|
||||||
|
|
||||||
return timestamp - epoch - delta;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the value of the active clock, adjusted to be relative to the active
|
|
||||||
* timer. If there is no clock or no active timer, this will return
|
|
||||||
* `undefined`.
|
|
||||||
* @return {number} milliseconds since the start of the active timer
|
|
||||||
*/
|
|
||||||
TimerService.prototype.now = function () {
|
|
||||||
var clock = this.time.clock();
|
|
||||||
|
|
||||||
return clock && this.convert(clock.currentValue());
|
|
||||||
};
|
|
||||||
|
|
||||||
return TimerService;
|
|
||||||
});
|
|
@ -1,106 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2009-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(
|
|
||||||
["../../src/actions/PauseTimerAction"],
|
|
||||||
function (PauseTimerAction) {
|
|
||||||
|
|
||||||
describe("A timer's Pause action", function () {
|
|
||||||
var mockNow,
|
|
||||||
mockDomainObject,
|
|
||||||
testModel,
|
|
||||||
testContext,
|
|
||||||
action;
|
|
||||||
|
|
||||||
function asPromise(value) {
|
|
||||||
return (value || {}).then ? value : {
|
|
||||||
then: function (callback) {
|
|
||||||
return asPromise(callback(value));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function testState(type, timerState, timestamp, expected) {
|
|
||||||
testModel.type = type;
|
|
||||||
testModel.timerState = timerState;
|
|
||||||
testModel.timestamp = timestamp;
|
|
||||||
|
|
||||||
if (expected) {
|
|
||||||
expect(PauseTimerAction.appliesTo(testContext)).toBeTruthy();
|
|
||||||
} else {
|
|
||||||
expect(PauseTimerAction.appliesTo(testContext)).toBeFalsy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
mockNow = jasmine.createSpy('now');
|
|
||||||
mockDomainObject = jasmine.createSpyObj(
|
|
||||||
'domainObject',
|
|
||||||
['getCapability', 'useCapability', 'getModel']
|
|
||||||
);
|
|
||||||
|
|
||||||
mockDomainObject.useCapability.and.callFake(function (c, v) {
|
|
||||||
if (c === 'mutation') {
|
|
||||||
testModel = v(testModel) || testModel;
|
|
||||||
|
|
||||||
return asPromise(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
mockDomainObject.getModel.and.callFake(function () {
|
|
||||||
return testModel;
|
|
||||||
});
|
|
||||||
|
|
||||||
testModel = {};
|
|
||||||
testContext = {domainObject: mockDomainObject};
|
|
||||||
|
|
||||||
action = new PauseTimerAction(mockNow, testContext);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("updates the model with a timerState", function () {
|
|
||||||
testModel.timerState = 'started';
|
|
||||||
action.perform();
|
|
||||||
expect(testModel.timerState).toEqual('paused');
|
|
||||||
});
|
|
||||||
|
|
||||||
it("updates the model with a pausedTime", function () {
|
|
||||||
testModel.pausedTime = undefined;
|
|
||||||
mockNow.and.returnValue(12000);
|
|
||||||
action.perform();
|
|
||||||
expect(testModel.pausedTime).toEqual(12000);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("applies only to timers in a playing state", function () {
|
|
||||||
//in a stopped state
|
|
||||||
testState('timer', 'stopped', undefined, false);
|
|
||||||
|
|
||||||
//in a paused state
|
|
||||||
testState('timer', 'paused', 12000, false);
|
|
||||||
|
|
||||||
//in a playing state
|
|
||||||
testState('timer', 'started', 12000, true);
|
|
||||||
|
|
||||||
//not a timer
|
|
||||||
testState('clock', 'started', 12000, false);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
@ -1,112 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2009-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(
|
|
||||||
["../../src/actions/RestartTimerAction"],
|
|
||||||
function (RestartTimerAction) {
|
|
||||||
|
|
||||||
describe("A timer's restart action", function () {
|
|
||||||
var mockNow,
|
|
||||||
mockDomainObject,
|
|
||||||
testModel,
|
|
||||||
testContext,
|
|
||||||
action;
|
|
||||||
|
|
||||||
function asPromise(value) {
|
|
||||||
return (value || {}).then ? value : {
|
|
||||||
then: function (callback) {
|
|
||||||
return asPromise(callback(value));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function testState(type, timerState, timestamp, expected) {
|
|
||||||
testModel.type = type;
|
|
||||||
testModel.timerState = timerState;
|
|
||||||
testModel.timestamp = timestamp;
|
|
||||||
|
|
||||||
if (expected) {
|
|
||||||
expect(RestartTimerAction.appliesTo(testContext)).toBeTruthy();
|
|
||||||
} else {
|
|
||||||
expect(RestartTimerAction.appliesTo(testContext)).toBeFalsy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
mockNow = jasmine.createSpy('now');
|
|
||||||
mockDomainObject = jasmine.createSpyObj(
|
|
||||||
'domainObject',
|
|
||||||
['getCapability', 'useCapability', 'getModel']
|
|
||||||
);
|
|
||||||
|
|
||||||
mockDomainObject.useCapability.and.callFake(function (c, v) {
|
|
||||||
if (c === 'mutation') {
|
|
||||||
testModel = v(testModel) || testModel;
|
|
||||||
|
|
||||||
return asPromise(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
mockDomainObject.getModel.and.callFake(function () {
|
|
||||||
return testModel;
|
|
||||||
});
|
|
||||||
|
|
||||||
testModel = {};
|
|
||||||
testContext = { domainObject: mockDomainObject };
|
|
||||||
|
|
||||||
action = new RestartTimerAction(mockNow, testContext);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("updates the model with a timestamp", function () {
|
|
||||||
testModel.pausedTime = 12000;
|
|
||||||
mockNow.and.returnValue(12000);
|
|
||||||
action.perform();
|
|
||||||
expect(testModel.timestamp).toEqual(12000);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("updates the model with a pausedTime", function () {
|
|
||||||
testModel.pausedTime = 12000;
|
|
||||||
action.perform();
|
|
||||||
expect(testModel.pausedTime).toEqual(undefined);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("updates the model with a timerState", function () {
|
|
||||||
testModel.timerState = 'stopped';
|
|
||||||
action.perform();
|
|
||||||
expect(testModel.timerState).toEqual('started');
|
|
||||||
});
|
|
||||||
|
|
||||||
it("applies only to timers in a non-stopped state", function () {
|
|
||||||
//in a stopped state
|
|
||||||
testState('timer', 'stopped', undefined, false);
|
|
||||||
|
|
||||||
//in a paused state
|
|
||||||
testState('timer', 'paused', 12000, true);
|
|
||||||
|
|
||||||
//in a playing state
|
|
||||||
testState('timer', 'started', 12000, true);
|
|
||||||
|
|
||||||
//not a timer
|
|
||||||
testState('clock', 'paused', 12000, false);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
@ -1,111 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2009-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(
|
|
||||||
["../../src/actions/StartTimerAction"],
|
|
||||||
function (StartTimerAction) {
|
|
||||||
|
|
||||||
describe("A timer's start action", function () {
|
|
||||||
var mockNow,
|
|
||||||
mockDomainObject,
|
|
||||||
testModel,
|
|
||||||
testContext,
|
|
||||||
action;
|
|
||||||
|
|
||||||
function asPromise(value) {
|
|
||||||
return (value || {}).then ? value : {
|
|
||||||
then: function (callback) {
|
|
||||||
return asPromise(callback(value));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function testState(type, timerState, timestamp, expected) {
|
|
||||||
testModel.type = type;
|
|
||||||
testModel.timerState = timerState;
|
|
||||||
testModel.timestamp = timestamp;
|
|
||||||
|
|
||||||
if (expected) {
|
|
||||||
expect(StartTimerAction.appliesTo(testContext)).toBeTruthy();
|
|
||||||
} else {
|
|
||||||
expect(StartTimerAction.appliesTo(testContext)).toBeFalsy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
mockNow = jasmine.createSpy('now');
|
|
||||||
mockDomainObject = jasmine.createSpyObj(
|
|
||||||
'domainObject',
|
|
||||||
['getCapability', 'useCapability', 'getModel']
|
|
||||||
);
|
|
||||||
|
|
||||||
mockDomainObject.useCapability.and.callFake(function (c, v) {
|
|
||||||
if (c === 'mutation') {
|
|
||||||
testModel = v(testModel) || testModel;
|
|
||||||
|
|
||||||
return asPromise(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
mockDomainObject.getModel.and.callFake(function () {
|
|
||||||
return testModel;
|
|
||||||
});
|
|
||||||
|
|
||||||
testModel = {};
|
|
||||||
testContext = {domainObject: mockDomainObject};
|
|
||||||
|
|
||||||
action = new StartTimerAction(mockNow, testContext);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("updates the model with a timestamp", function () {
|
|
||||||
mockNow.and.returnValue(12000);
|
|
||||||
action.perform();
|
|
||||||
expect(testModel.timestamp).toEqual(12000);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("updates the model with a pausedTime", function () {
|
|
||||||
testModel.pausedTime = 12000;
|
|
||||||
action.perform();
|
|
||||||
expect(testModel.pausedTime).toEqual(undefined);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("updates the model with a timerState", function () {
|
|
||||||
testModel.timerState = undefined;
|
|
||||||
action.perform();
|
|
||||||
expect(testModel.timerState).toEqual('started');
|
|
||||||
});
|
|
||||||
|
|
||||||
it("applies only to timers not in a playing state", function () {
|
|
||||||
//in a stopped state
|
|
||||||
testState('timer', 'stopped', undefined, true);
|
|
||||||
|
|
||||||
//in a paused state
|
|
||||||
testState('timer', 'paused', 12000, true);
|
|
||||||
|
|
||||||
//in a playing state
|
|
||||||
testState('timer', 'started', 12000, false);
|
|
||||||
|
|
||||||
//not a timer
|
|
||||||
testState('clock', 'paused', 12000, false);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
@ -1,111 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2009-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(
|
|
||||||
["../../src/actions/StopTimerAction"],
|
|
||||||
function (StopTimerAction) {
|
|
||||||
|
|
||||||
describe("A timer's stop action", function () {
|
|
||||||
var mockNow,
|
|
||||||
mockDomainObject,
|
|
||||||
testModel,
|
|
||||||
testContext,
|
|
||||||
action;
|
|
||||||
|
|
||||||
function asPromise(value) {
|
|
||||||
return (value || {}).then ? value : {
|
|
||||||
then: function (callback) {
|
|
||||||
return asPromise(callback(value));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function testState(type, timerState, timestamp, expected) {
|
|
||||||
testModel.type = type;
|
|
||||||
testModel.timerState = timerState;
|
|
||||||
testModel.timestamp = timestamp;
|
|
||||||
|
|
||||||
if (expected) {
|
|
||||||
expect(StopTimerAction.appliesTo(testContext)).toBeTruthy();
|
|
||||||
} else {
|
|
||||||
expect(StopTimerAction.appliesTo(testContext)).toBeFalsy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
mockNow = jasmine.createSpy('now');
|
|
||||||
mockDomainObject = jasmine.createSpyObj(
|
|
||||||
'domainObject',
|
|
||||||
['getCapability', 'useCapability', 'getModel']
|
|
||||||
);
|
|
||||||
|
|
||||||
mockDomainObject.useCapability.and.callFake(function (c, v) {
|
|
||||||
if (c === 'mutation') {
|
|
||||||
testModel = v(testModel) || testModel;
|
|
||||||
|
|
||||||
return asPromise(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
mockDomainObject.getModel.and.callFake(function () {
|
|
||||||
return testModel;
|
|
||||||
});
|
|
||||||
|
|
||||||
testModel = {};
|
|
||||||
testContext = {domainObject: mockDomainObject};
|
|
||||||
|
|
||||||
action = new StopTimerAction(mockNow, testContext);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("updates the model with a timestamp", function () {
|
|
||||||
mockNow.and.returnValue(12000);
|
|
||||||
action.perform();
|
|
||||||
expect(testModel.timestamp).toEqual(undefined);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("updates the model with a pausedTime", function () {
|
|
||||||
testModel.pausedTime = 12000;
|
|
||||||
action.perform();
|
|
||||||
expect(testModel.pausedTime).toEqual(undefined);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("updates the model with a timerState", function () {
|
|
||||||
testModel.timerState = 'started';
|
|
||||||
action.perform();
|
|
||||||
expect(testModel.timerState).toEqual('stopped');
|
|
||||||
});
|
|
||||||
|
|
||||||
it("applies only to timers in a non-stopped state", function () {
|
|
||||||
//in a stopped state
|
|
||||||
testState('timer', 'stopped', undefined, false);
|
|
||||||
|
|
||||||
//in a paused state
|
|
||||||
testState('timer', 'paused', 12000, true);
|
|
||||||
|
|
||||||
//in a playing state
|
|
||||||
testState('timer', 'started', 12000, true);
|
|
||||||
|
|
||||||
//not a timer
|
|
||||||
testState('clock', 'paused', 12000, false);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
@ -1,80 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2009-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(
|
|
||||||
["../../src/controllers/RefreshingController"],
|
|
||||||
function (RefreshingController) {
|
|
||||||
|
|
||||||
describe("The refreshing controller", function () {
|
|
||||||
var mockScope,
|
|
||||||
mockTicker,
|
|
||||||
mockUnticker,
|
|
||||||
controller;
|
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
mockScope = jasmine.createSpyObj('$scope', ['$on']);
|
|
||||||
mockTicker = jasmine.createSpyObj('ticker', ['listen']);
|
|
||||||
mockUnticker = jasmine.createSpy('unticker');
|
|
||||||
|
|
||||||
mockTicker.listen.and.returnValue(mockUnticker);
|
|
||||||
|
|
||||||
controller = new RefreshingController(mockScope, mockTicker);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("refreshes the represented object on every tick", function () {
|
|
||||||
var mockDomainObject = jasmine.createSpyObj(
|
|
||||||
'domainObject',
|
|
||||||
['getCapability']
|
|
||||||
),
|
|
||||||
mockPersistence = jasmine.createSpyObj(
|
|
||||||
'persistence',
|
|
||||||
['persist', 'refresh']
|
|
||||||
);
|
|
||||||
|
|
||||||
mockDomainObject.getCapability.and.callFake(function (c) {
|
|
||||||
return (c === 'persistence') && mockPersistence;
|
|
||||||
});
|
|
||||||
|
|
||||||
mockScope.domainObject = mockDomainObject;
|
|
||||||
|
|
||||||
mockTicker.listen.calls.mostRecent().args[0](12321);
|
|
||||||
expect(mockPersistence.refresh).toHaveBeenCalled();
|
|
||||||
expect(mockPersistence.persist).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("subscribes to clock ticks", function () {
|
|
||||||
expect(mockTicker.listen)
|
|
||||||
.toHaveBeenCalledWith(jasmine.any(Function));
|
|
||||||
});
|
|
||||||
|
|
||||||
it("unsubscribes to ticks when destroyed", function () {
|
|
||||||
// Make sure $destroy is being listened for...
|
|
||||||
expect(mockScope.$on.calls.mostRecent().args[0]).toEqual('$destroy');
|
|
||||||
expect(mockUnticker).not.toHaveBeenCalled();
|
|
||||||
|
|
||||||
// ...and makes sure that its listener unsubscribes from ticker
|
|
||||||
mockScope.$on.calls.mostRecent().args[1]();
|
|
||||||
expect(mockUnticker).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
@ -1,227 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2009-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(
|
|
||||||
["../../src/controllers/TimerController"],
|
|
||||||
function (TimerController) {
|
|
||||||
|
|
||||||
// Wed, 03 Jun 2015 17:56:14 GMT
|
|
||||||
var TEST_TIMESTAMP = 1433354174000;
|
|
||||||
|
|
||||||
describe("A timer view's controller", function () {
|
|
||||||
var mockScope,
|
|
||||||
mockWindow,
|
|
||||||
mockNow,
|
|
||||||
mockDomainObject,
|
|
||||||
mockActionCapability,
|
|
||||||
mockStart,
|
|
||||||
mockPause,
|
|
||||||
mockStop,
|
|
||||||
testModel,
|
|
||||||
controller;
|
|
||||||
|
|
||||||
function invokeWatch(expr, value) {
|
|
||||||
mockScope.$watch.calls.all().forEach(function (call) {
|
|
||||||
if (call.args[0] === expr) {
|
|
||||||
call.args[1](value);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
mockScope = jasmine.createSpyObj(
|
|
||||||
'$scope',
|
|
||||||
['$watch', '$on', '$apply']
|
|
||||||
);
|
|
||||||
mockWindow = jasmine.createSpyObj(
|
|
||||||
'$window',
|
|
||||||
['requestAnimationFrame']
|
|
||||||
);
|
|
||||||
mockDomainObject = jasmine.createSpyObj(
|
|
||||||
'domainObject',
|
|
||||||
['getCapability', 'useCapability', 'getModel']
|
|
||||||
);
|
|
||||||
mockActionCapability = jasmine.createSpyObj(
|
|
||||||
'action',
|
|
||||||
['getActions']
|
|
||||||
);
|
|
||||||
mockStart = jasmine.createSpyObj(
|
|
||||||
'start',
|
|
||||||
['getMetadata', 'perform']
|
|
||||||
);
|
|
||||||
mockPause = jasmine.createSpyObj(
|
|
||||||
'paused',
|
|
||||||
['getMetadata', 'perform']
|
|
||||||
);
|
|
||||||
mockStop = jasmine.createSpyObj(
|
|
||||||
'stopped',
|
|
||||||
['getMetadata', 'perform']
|
|
||||||
);
|
|
||||||
mockNow = jasmine.createSpy('now');
|
|
||||||
|
|
||||||
mockDomainObject.getCapability.and.callFake(function (c) {
|
|
||||||
return (c === 'action') && mockActionCapability;
|
|
||||||
});
|
|
||||||
mockDomainObject.getModel.and.callFake(function () {
|
|
||||||
return testModel;
|
|
||||||
});
|
|
||||||
mockActionCapability.getActions.and.callFake(function (k) {
|
|
||||||
return [{
|
|
||||||
'timer.start': mockStart,
|
|
||||||
'timer.pause': mockPause,
|
|
||||||
'timer.stop': mockStop
|
|
||||||
}[k]];
|
|
||||||
});
|
|
||||||
|
|
||||||
mockStart.getMetadata.and.returnValue({
|
|
||||||
cssClass: "icon-play",
|
|
||||||
name: "Start"
|
|
||||||
});
|
|
||||||
mockPause.getMetadata.and.returnValue({
|
|
||||||
cssClass: "icon-pause",
|
|
||||||
name: "Pause"
|
|
||||||
});
|
|
||||||
mockStop.getMetadata.and.returnValue({
|
|
||||||
cssClass: "icon-box-round-corners",
|
|
||||||
name: "Stop"
|
|
||||||
});
|
|
||||||
mockScope.domainObject = mockDomainObject;
|
|
||||||
|
|
||||||
testModel = {};
|
|
||||||
|
|
||||||
controller = new TimerController(mockScope, mockWindow, mockNow);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("watches for the domain object in view", function () {
|
|
||||||
expect(mockScope.$watch).toHaveBeenCalledWith(
|
|
||||||
"domainObject",
|
|
||||||
jasmine.any(Function)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("watches for domain object modifications", function () {
|
|
||||||
expect(mockScope.$watch).toHaveBeenCalledWith(
|
|
||||||
"model.modified",
|
|
||||||
jasmine.any(Function)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("updates on a timer", function () {
|
|
||||||
expect(mockWindow.requestAnimationFrame)
|
|
||||||
.toHaveBeenCalledWith(jasmine.any(Function));
|
|
||||||
});
|
|
||||||
|
|
||||||
it("displays nothing when there is no target", function () {
|
|
||||||
// Notify that domain object is available via scope
|
|
||||||
invokeWatch('domainObject', mockDomainObject);
|
|
||||||
mockNow.and.returnValue(TEST_TIMESTAMP);
|
|
||||||
mockWindow.requestAnimationFrame.calls.mostRecent().args[0]();
|
|
||||||
expect(controller.sign()).toEqual("");
|
|
||||||
expect(controller.signClass()).toEqual("");
|
|
||||||
expect(controller.text()).toEqual("");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("formats time to display relative to target", function () {
|
|
||||||
testModel.timestamp = TEST_TIMESTAMP;
|
|
||||||
testModel.timerFormat = 'long';
|
|
||||||
// Notify that domain object is available via scope
|
|
||||||
invokeWatch('domainObject', mockDomainObject);
|
|
||||||
|
|
||||||
mockNow.and.returnValue(TEST_TIMESTAMP + 121000);
|
|
||||||
mockWindow.requestAnimationFrame.calls.mostRecent().args[0]();
|
|
||||||
expect(controller.sign()).toEqual("+");
|
|
||||||
expect(controller.signClass()).toEqual("icon-plus");
|
|
||||||
expect(controller.text()).toEqual("0D 00:02:01");
|
|
||||||
|
|
||||||
mockNow.and.returnValue(TEST_TIMESTAMP - 121000);
|
|
||||||
mockWindow.requestAnimationFrame.calls.mostRecent().args[0]();
|
|
||||||
expect(controller.sign()).toEqual("-");
|
|
||||||
expect(controller.signClass()).toEqual("icon-minus");
|
|
||||||
expect(controller.text()).toEqual("0D 00:02:01");
|
|
||||||
|
|
||||||
mockNow.and.returnValue(TEST_TIMESTAMP);
|
|
||||||
mockWindow.requestAnimationFrame.calls.mostRecent().args[0]();
|
|
||||||
expect(controller.sign()).toEqual("");
|
|
||||||
expect(controller.signClass()).toEqual("");
|
|
||||||
expect(controller.text()).toEqual("0D 00:00:00");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("shows cssClass & name for the applicable start/pause action", function () {
|
|
||||||
invokeWatch('domainObject', mockDomainObject);
|
|
||||||
expect(controller.buttonCssClass()).toEqual("icon-play");
|
|
||||||
expect(controller.buttonText()).toEqual("Start");
|
|
||||||
|
|
||||||
testModel.timestamp = 12321;
|
|
||||||
testModel.timerState = 'started';
|
|
||||||
invokeWatch('model.modified', 1);
|
|
||||||
expect(controller.buttonCssClass()).toEqual("icon-pause");
|
|
||||||
expect(controller.buttonText()).toEqual("Pause");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("performs correct start/pause/stop action on click", function () {
|
|
||||||
//test start
|
|
||||||
invokeWatch('domainObject', mockDomainObject);
|
|
||||||
expect(mockStart.perform).not.toHaveBeenCalled();
|
|
||||||
controller.clickButton();
|
|
||||||
expect(mockStart.perform).toHaveBeenCalled();
|
|
||||||
|
|
||||||
//test pause
|
|
||||||
testModel.timestamp = 12321;
|
|
||||||
testModel.timerState = 'started';
|
|
||||||
invokeWatch('model.modified', 1);
|
|
||||||
expect(mockPause.perform).not.toHaveBeenCalled();
|
|
||||||
controller.clickButton();
|
|
||||||
expect(mockPause.perform).toHaveBeenCalled();
|
|
||||||
|
|
||||||
//test stop
|
|
||||||
expect(mockStop.perform).not.toHaveBeenCalled();
|
|
||||||
controller.clickStopButton();
|
|
||||||
expect(mockStop.perform).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("stops requesting animation frames when destroyed", function () {
|
|
||||||
var initialCount = mockWindow.requestAnimationFrame.calls.count();
|
|
||||||
|
|
||||||
// First, check that normally new frames keep getting requested
|
|
||||||
mockWindow.requestAnimationFrame.calls.mostRecent().args[0]();
|
|
||||||
expect(mockWindow.requestAnimationFrame.calls.count())
|
|
||||||
.toEqual(initialCount + 1);
|
|
||||||
mockWindow.requestAnimationFrame.calls.mostRecent().args[0]();
|
|
||||||
expect(mockWindow.requestAnimationFrame.calls.count())
|
|
||||||
.toEqual(initialCount + 2);
|
|
||||||
|
|
||||||
// Now, verify that it stops after $destroy
|
|
||||||
expect(mockScope.$on.calls.mostRecent().args[0])
|
|
||||||
.toEqual('$destroy');
|
|
||||||
mockScope.$on.calls.mostRecent().args[1]();
|
|
||||||
|
|
||||||
// Frames should no longer get requested
|
|
||||||
mockWindow.requestAnimationFrame.calls.mostRecent().args[0]();
|
|
||||||
expect(mockWindow.requestAnimationFrame.calls.count())
|
|
||||||
.toEqual(initialCount + 2);
|
|
||||||
mockWindow.requestAnimationFrame.calls.mostRecent().args[0]();
|
|
||||||
expect(mockWindow.requestAnimationFrame.calls.count())
|
|
||||||
.toEqual(initialCount + 2);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
@ -1,111 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2009-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(
|
|
||||||
["../../src/controllers/TimerFormatter"],
|
|
||||||
function (TimerFormatter) {
|
|
||||||
|
|
||||||
var MS_IN_SEC = 1000,
|
|
||||||
MS_IN_MIN = MS_IN_SEC * 60,
|
|
||||||
MS_IN_HR = MS_IN_MIN * 60,
|
|
||||||
MS_IN_DAY = MS_IN_HR * 24;
|
|
||||||
|
|
||||||
describe("The timer value formatter", function () {
|
|
||||||
var formatter = new TimerFormatter();
|
|
||||||
|
|
||||||
function sum(a, b) {
|
|
||||||
return a + b;
|
|
||||||
}
|
|
||||||
|
|
||||||
function toDuration(days, hours, mins, secs) {
|
|
||||||
return [
|
|
||||||
days * MS_IN_DAY,
|
|
||||||
hours * MS_IN_HR,
|
|
||||||
mins * MS_IN_MIN,
|
|
||||||
secs * MS_IN_SEC
|
|
||||||
].reduce(sum, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
it("formats short-form values (no days)", function () {
|
|
||||||
expect(formatter.short(toDuration(0, 123, 2, 3) + 123))
|
|
||||||
.toEqual("123:02:03");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("formats negative short-form values (no days)", function () {
|
|
||||||
expect(formatter.short(-toDuration(0, 123, 2, 3) + 123))
|
|
||||||
.toEqual("123:02:03");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("formats long-form values (with days)", function () {
|
|
||||||
expect(formatter.long(toDuration(0, 123, 2, 3) + 123))
|
|
||||||
.toEqual("5D 03:02:03");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("formats negative long-form values (no days)", function () {
|
|
||||||
expect(formatter.long(-toDuration(0, 123, 2, 3) + 123))
|
|
||||||
.toEqual("5D 03:02:03");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("rounds seconds down for positive durations", function () {
|
|
||||||
expect(formatter.short(MS_IN_SEC + 600))
|
|
||||||
.toEqual("00:00:01");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("rounds seconds up for negative durations", function () {
|
|
||||||
expect(formatter.short(-MS_IN_SEC - 600))
|
|
||||||
.toEqual("00:00:02");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("short-formats correctly around negative time borders", function () {
|
|
||||||
expect(formatter.short(-1)).toEqual("00:00:01");
|
|
||||||
expect(formatter.short(-1000)).toEqual("00:00:01");
|
|
||||||
expect(formatter.short(-1001)).toEqual("00:00:02");
|
|
||||||
expect(formatter.short(-2000)).toEqual("00:00:02");
|
|
||||||
expect(formatter.short(-59001)).toEqual("00:01:00");
|
|
||||||
expect(formatter.short(-60000)).toEqual("00:01:00");
|
|
||||||
|
|
||||||
expect(formatter.short(-MS_IN_HR + 999)).toEqual("01:00:00");
|
|
||||||
expect(formatter.short(-MS_IN_HR)).toEqual("01:00:00");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("differentiates between values around zero", function () {
|
|
||||||
// These are more than 1000 ms apart so should not appear
|
|
||||||
// as the same second
|
|
||||||
expect(formatter.short(-999))
|
|
||||||
.not.toEqual(formatter.short(999));
|
|
||||||
});
|
|
||||||
|
|
||||||
it("handles negative days", function () {
|
|
||||||
expect(formatter.long(-10 * MS_IN_DAY))
|
|
||||||
.toEqual("10D 00:00:00");
|
|
||||||
expect(formatter.long(-10 * MS_IN_DAY + 100))
|
|
||||||
.toEqual("10D 00:00:00");
|
|
||||||
expect(formatter.long(-10 * MS_IN_DAY + 999))
|
|
||||||
.toEqual("10D 00:00:00");
|
|
||||||
|
|
||||||
expect(formatter.short(-10 * MS_IN_DAY + 100))
|
|
||||||
.toEqual("240:00:00");
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
@ -1,62 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2009-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(
|
|
||||||
["../../src/services/TickerService"],
|
|
||||||
function (TickerService) {
|
|
||||||
|
|
||||||
var TEST_TIMESTAMP = 1433354174000;
|
|
||||||
|
|
||||||
describe("The ticker service", function () {
|
|
||||||
var mockTimeout,
|
|
||||||
mockNow,
|
|
||||||
mockCallback,
|
|
||||||
tickerService;
|
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
mockTimeout = jasmine.createSpy('$timeout');
|
|
||||||
mockNow = jasmine.createSpy('now');
|
|
||||||
mockCallback = jasmine.createSpy('callback');
|
|
||||||
|
|
||||||
mockNow.and.returnValue(TEST_TIMESTAMP);
|
|
||||||
|
|
||||||
tickerService = new TickerService(mockTimeout, mockNow);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("notifies listeners of clock ticks", function () {
|
|
||||||
tickerService.listen(mockCallback);
|
|
||||||
mockNow.and.returnValue(TEST_TIMESTAMP + 12321);
|
|
||||||
mockTimeout.calls.mostRecent().args[0]();
|
|
||||||
expect(mockCallback)
|
|
||||||
.toHaveBeenCalledWith(TEST_TIMESTAMP + 12321);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("allows listeners to unregister", function () {
|
|
||||||
tickerService.listen(mockCallback)(); // Unregister immediately
|
|
||||||
mockNow.and.returnValue(TEST_TIMESTAMP + 12321);
|
|
||||||
mockTimeout.calls.mostRecent().args[0]();
|
|
||||||
expect(mockCallback).not
|
|
||||||
.toHaveBeenCalledWith(TEST_TIMESTAMP + 12321);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
@ -1,77 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2009-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([
|
|
||||||
'../../src/services/TimerService'
|
|
||||||
], function (TimerService) {
|
|
||||||
describe("TimerService", function () {
|
|
||||||
var callback;
|
|
||||||
var mockmct;
|
|
||||||
var timerService;
|
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
callback = jasmine.createSpy('callback');
|
|
||||||
mockmct = {
|
|
||||||
time: { clock: jasmine.createSpy('clock') },
|
|
||||||
objects: { observe: jasmine.createSpy('observe') }
|
|
||||||
};
|
|
||||||
timerService = new TimerService(mockmct);
|
|
||||||
timerService.on('change', callback);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("initially emits no change events", function () {
|
|
||||||
expect(callback).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("reports no current timer", function () {
|
|
||||||
expect(timerService.getTimer()).toBeUndefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("setTimer", function () {
|
|
||||||
var testTimer;
|
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
testTimer = { name: "I am some timer; you are nobody." };
|
|
||||||
timerService.setTimer(testTimer);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("emits a change event", function () {
|
|
||||||
expect(callback).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("reports the current timer", function () {
|
|
||||||
expect(timerService.getTimer()).toBe(testTimer);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("observes changes to an object", function () {
|
|
||||||
var newTimer = { name: "I am another timer." };
|
|
||||||
expect(mockmct.objects.observe).toHaveBeenCalledWith(
|
|
||||||
testTimer,
|
|
||||||
'*',
|
|
||||||
jasmine.any(Function)
|
|
||||||
);
|
|
||||||
mockmct.objects.observe.calls.mostRecent().args[2](newTimer);
|
|
||||||
expect(timerService.getTimer()).toBe(newTimer);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
@ -473,6 +473,23 @@ ObjectAPI.prototype.mutate = function (domainObject, path, value) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates a domain object based on its latest persisted state. Note that this will mutate the provided object.
|
||||||
|
* @param {module:openmct.DomainObject} domainObject an object to refresh from its persistence store
|
||||||
|
* @returns {Promise} the provided object, updated to reflect the latest persisted state of the object.
|
||||||
|
*/
|
||||||
|
ObjectAPI.prototype.refresh = async function (domainObject) {
|
||||||
|
const refreshedObject = await this.get(domainObject.identifier);
|
||||||
|
|
||||||
|
if (domainObject.isMutable) {
|
||||||
|
domainObject.$refresh(refreshedObject);
|
||||||
|
} else {
|
||||||
|
utils.refresh(domainObject, refreshedObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
return domainObject;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
|
@ -37,7 +37,6 @@ const DEFAULTS = [
|
|||||||
'platform/execution',
|
'platform/execution',
|
||||||
'platform/exporters',
|
'platform/exporters',
|
||||||
'platform/telemetry',
|
'platform/telemetry',
|
||||||
'platform/features/clock',
|
|
||||||
'platform/forms',
|
'platform/forms',
|
||||||
'platform/identity',
|
'platform/identity',
|
||||||
'platform/persistence/aggregator',
|
'platform/persistence/aggregator',
|
||||||
@ -77,7 +76,6 @@ define([
|
|||||||
'../platform/entanglement/bundle',
|
'../platform/entanglement/bundle',
|
||||||
'../platform/execution/bundle',
|
'../platform/execution/bundle',
|
||||||
'../platform/exporters/bundle',
|
'../platform/exporters/bundle',
|
||||||
'../platform/features/clock/bundle',
|
|
||||||
'../platform/features/static-markup/bundle',
|
'../platform/features/static-markup/bundle',
|
||||||
'../platform/forms/bundle',
|
'../platform/forms/bundle',
|
||||||
'../platform/framework/bundle',
|
'../platform/framework/bundle',
|
||||||
|
@ -41,6 +41,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import momentTimezone from 'moment-timezone';
|
import momentTimezone from 'moment-timezone';
|
||||||
|
import ticker from 'utils/clock/Ticker';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
inject: ['openmct', 'domainObject'],
|
inject: ['openmct', 'domainObject'],
|
||||||
@ -82,8 +83,7 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
const TickerService = this.openmct.$injector.get('tickerService');
|
this.unlisten = ticker.listen(this.tick);
|
||||||
this.unlisten = TickerService.listen(this.tick);
|
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
if (this.unlisten) {
|
if (this.unlisten) {
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
import ticker from 'utils/clock/Ticker';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
inject: ['openmct'],
|
inject: ['openmct'],
|
||||||
@ -45,10 +46,7 @@ export default {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.openmct.on('start', () => {
|
this.unlisten = ticker.listen(this.tick);
|
||||||
const TickerService = this.openmct.$injector.get('tickerService');
|
|
||||||
this.unlisten = TickerService.listen(this.tick);
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
if (this.unlisten) {
|
if (this.unlisten) {
|
||||||
|
@ -72,6 +72,7 @@ define([
|
|||||||
'./timeline/plugin',
|
'./timeline/plugin',
|
||||||
'./hyperlink/plugin',
|
'./hyperlink/plugin',
|
||||||
'./clock/plugin',
|
'./clock/plugin',
|
||||||
|
'./timer/plugin',
|
||||||
'./DeviceClassifier/plugin'
|
'./DeviceClassifier/plugin'
|
||||||
], function (
|
], function (
|
||||||
_,
|
_,
|
||||||
@ -125,6 +126,7 @@ define([
|
|||||||
Timeline,
|
Timeline,
|
||||||
Hyperlink,
|
Hyperlink,
|
||||||
Clock,
|
Clock,
|
||||||
|
Timer,
|
||||||
DeviceClassifier
|
DeviceClassifier
|
||||||
) {
|
) {
|
||||||
const bundleMap = {
|
const bundleMap = {
|
||||||
@ -232,6 +234,7 @@ define([
|
|||||||
plugins.Timeline = Timeline.default;
|
plugins.Timeline = Timeline.default;
|
||||||
plugins.Hyperlink = Hyperlink.default;
|
plugins.Hyperlink = Hyperlink.default;
|
||||||
plugins.Clock = Clock.default;
|
plugins.Clock = Clock.default;
|
||||||
|
plugins.Timer = Timer.default;
|
||||||
plugins.DeviceClassifier = DeviceClassifier.default;
|
plugins.DeviceClassifier = DeviceClassifier.default;
|
||||||
|
|
||||||
return plugins;
|
return plugins;
|
||||||
|
65
src/plugins/timer/TimerViewProvider.js
Normal file
65
src/plugins/timer/TimerViewProvider.js
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2009-2021, 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 Timer from './components/Timer.vue';
|
||||||
|
import Vue from 'vue';
|
||||||
|
|
||||||
|
export default function TimerViewProvider(openmct) {
|
||||||
|
return {
|
||||||
|
key: 'timer.view',
|
||||||
|
name: 'Timer',
|
||||||
|
cssClass: 'icon-timer',
|
||||||
|
canView(domainObject) {
|
||||||
|
return domainObject.type === 'timer';
|
||||||
|
},
|
||||||
|
|
||||||
|
view: function (domainObject, objectPath) {
|
||||||
|
let component;
|
||||||
|
|
||||||
|
return {
|
||||||
|
show: function (element) {
|
||||||
|
component = new Vue({
|
||||||
|
el: element,
|
||||||
|
components: {
|
||||||
|
Timer
|
||||||
|
},
|
||||||
|
provide: {
|
||||||
|
openmct,
|
||||||
|
objectPath,
|
||||||
|
currentView: this
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
domainObject
|
||||||
|
};
|
||||||
|
},
|
||||||
|
template: '<timer :domain-object="domainObject" />'
|
||||||
|
});
|
||||||
|
},
|
||||||
|
destroy: function () {
|
||||||
|
component.$destroy();
|
||||||
|
component = undefined;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
56
src/plugins/timer/actions/PauseTimerAction.js
Normal file
56
src/plugins/timer/actions/PauseTimerAction.js
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2009-2021, 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.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
export default class PauseTimerAction {
|
||||||
|
constructor(openmct) {
|
||||||
|
this.name = 'Pause';
|
||||||
|
this.key = 'timer.pause';
|
||||||
|
this.description = 'Pause the currently displayed timer';
|
||||||
|
this.group = 'view';
|
||||||
|
this.cssClass = 'icon-pause';
|
||||||
|
this.priority = 3;
|
||||||
|
|
||||||
|
this.openmct = openmct;
|
||||||
|
}
|
||||||
|
invoke(objectPath) {
|
||||||
|
const domainObject = objectPath[0];
|
||||||
|
if (!domainObject || !domainObject.configuration) {
|
||||||
|
return new Error('Unable to run pause timer action. No domainObject provided.');
|
||||||
|
}
|
||||||
|
|
||||||
|
const newConfiguration = { ...domainObject.configuration };
|
||||||
|
newConfiguration.timerState = 'paused';
|
||||||
|
newConfiguration.pausedTime = new Date();
|
||||||
|
|
||||||
|
this.openmct.objects.mutate(domainObject, 'configuration', newConfiguration);
|
||||||
|
}
|
||||||
|
appliesTo(objectPath) {
|
||||||
|
const domainObject = objectPath[0];
|
||||||
|
if (!domainObject || !domainObject.configuration) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { timerState } = domainObject.configuration;
|
||||||
|
|
||||||
|
return domainObject.type === 'timer' && timerState === 'started';
|
||||||
|
}
|
||||||
|
}
|
57
src/plugins/timer/actions/RestartTimerAction.js
Normal file
57
src/plugins/timer/actions/RestartTimerAction.js
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2009-2021, 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.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
export default class RestartTimerAction {
|
||||||
|
constructor(openmct) {
|
||||||
|
this.name = 'Restart at 0';
|
||||||
|
this.key = 'timer.restart';
|
||||||
|
this.description = 'Restart the currently displayed timer';
|
||||||
|
this.group = 'view';
|
||||||
|
this.cssClass = 'icon-refresh';
|
||||||
|
this.priority = 2;
|
||||||
|
|
||||||
|
this.openmct = openmct;
|
||||||
|
}
|
||||||
|
invoke(objectPath) {
|
||||||
|
const domainObject = objectPath[0];
|
||||||
|
if (!domainObject || !domainObject.configuration) {
|
||||||
|
return new Error('Unable to run restart timer action. No domainObject provided.');
|
||||||
|
}
|
||||||
|
|
||||||
|
const newConfiguration = { ...domainObject.configuration };
|
||||||
|
newConfiguration.timerState = 'started';
|
||||||
|
newConfiguration.timestamp = new Date();
|
||||||
|
newConfiguration.pausedTime = undefined;
|
||||||
|
|
||||||
|
this.openmct.objects.mutate(domainObject, 'configuration', newConfiguration);
|
||||||
|
}
|
||||||
|
appliesTo(objectPath) {
|
||||||
|
const domainObject = objectPath[0];
|
||||||
|
if (!domainObject || !domainObject.configuration) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { timerState } = domainObject.configuration;
|
||||||
|
|
||||||
|
return domainObject.type === 'timer' && timerState !== 'stopped';
|
||||||
|
}
|
||||||
|
}
|
76
src/plugins/timer/actions/StartTimerAction.js
Normal file
76
src/plugins/timer/actions/StartTimerAction.js
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2009-2021, 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 moment from 'moment';
|
||||||
|
|
||||||
|
export default class StartTimerAction {
|
||||||
|
constructor(openmct) {
|
||||||
|
this.name = 'Start';
|
||||||
|
this.key = 'timer.start';
|
||||||
|
this.description = 'Start the currently displayed timer';
|
||||||
|
this.group = 'view';
|
||||||
|
this.cssClass = 'icon-play';
|
||||||
|
this.priority = 3;
|
||||||
|
|
||||||
|
this.openmct = openmct;
|
||||||
|
}
|
||||||
|
invoke(objectPath) {
|
||||||
|
const domainObject = objectPath[0];
|
||||||
|
if (!domainObject || !domainObject.configuration) {
|
||||||
|
return new Error('Unable to run start timer action. No domainObject provided.');
|
||||||
|
}
|
||||||
|
|
||||||
|
let { pausedTime, timestamp } = domainObject.configuration;
|
||||||
|
const newConfiguration = { ...domainObject.configuration };
|
||||||
|
|
||||||
|
if (pausedTime) {
|
||||||
|
pausedTime = moment(pausedTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timestamp) {
|
||||||
|
timestamp = moment(timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
const now = moment(new Date());
|
||||||
|
if (pausedTime) {
|
||||||
|
const timeShift = moment.duration(now.diff(pausedTime));
|
||||||
|
const shiftedTime = timestamp.add(timeShift);
|
||||||
|
newConfiguration.timestamp = shiftedTime.toDate();
|
||||||
|
} else if (!timestamp) {
|
||||||
|
newConfiguration.timestamp = now.toDate();
|
||||||
|
}
|
||||||
|
|
||||||
|
newConfiguration.timerState = 'started';
|
||||||
|
newConfiguration.pausedTime = undefined;
|
||||||
|
this.openmct.objects.mutate(domainObject, 'configuration', newConfiguration);
|
||||||
|
}
|
||||||
|
appliesTo(objectPath) {
|
||||||
|
const domainObject = objectPath[0];
|
||||||
|
if (!domainObject || !domainObject.configuration) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { timerState } = domainObject.configuration;
|
||||||
|
|
||||||
|
return domainObject.type === 'timer' && timerState !== 'started';
|
||||||
|
}
|
||||||
|
}
|
57
src/plugins/timer/actions/StopTimerAction.js
Normal file
57
src/plugins/timer/actions/StopTimerAction.js
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2009-2021, 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.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
export default class StopTimerAction {
|
||||||
|
constructor(openmct) {
|
||||||
|
this.name = 'Stop';
|
||||||
|
this.key = 'timer.stop';
|
||||||
|
this.description = 'Stop the currently displayed timer';
|
||||||
|
this.group = 'view';
|
||||||
|
this.cssClass = 'icon-box-round-corners';
|
||||||
|
this.priority = 1;
|
||||||
|
|
||||||
|
this.openmct = openmct;
|
||||||
|
}
|
||||||
|
invoke(objectPath) {
|
||||||
|
const domainObject = objectPath[0];
|
||||||
|
if (!domainObject || !domainObject.configuration) {
|
||||||
|
return new Error('Unable to run stop timer action. No domainObject provided.');
|
||||||
|
}
|
||||||
|
|
||||||
|
const newConfiguration = { ...domainObject.configuration };
|
||||||
|
newConfiguration.timerState = 'stopped';
|
||||||
|
newConfiguration.timestamp = undefined;
|
||||||
|
newConfiguration.pausedTime = undefined;
|
||||||
|
|
||||||
|
this.openmct.objects.mutate(domainObject, 'configuration', newConfiguration);
|
||||||
|
}
|
||||||
|
appliesTo(objectPath) {
|
||||||
|
const domainObject = objectPath[0];
|
||||||
|
if (!domainObject || !domainObject.configuration) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { timerState } = domainObject.configuration;
|
||||||
|
|
||||||
|
return domainObject.type === 'timer' && timerState !== 'stopped';
|
||||||
|
}
|
||||||
|
}
|
233
src/plugins/timer/components/Timer.vue
Normal file
233
src/plugins/timer/components/Timer.vue
Normal file
@ -0,0 +1,233 @@
|
|||||||
|
<!--
|
||||||
|
Open MCT, Copyright (c) 2009-2021, 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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div
|
||||||
|
class="c-timer u-style-receiver js-style-receiver"
|
||||||
|
:class="[`is-${timerState}`]"
|
||||||
|
>
|
||||||
|
<div class="c-timer__controls">
|
||||||
|
<button
|
||||||
|
title="Reset"
|
||||||
|
class="c-timer__ctrl-reset c-icon-button c-icon-button--major icon-reset"
|
||||||
|
:class="[{'hide': timerState === 'stopped' }]"
|
||||||
|
@click="restartTimer"
|
||||||
|
></button>
|
||||||
|
<button :title="timerStateButtonText"
|
||||||
|
class="c-timer__ctrl-pause-play c-icon-button c-icon-button--major"
|
||||||
|
:class="[timerStateButtonIcon]"
|
||||||
|
@click="toggleStateButton"
|
||||||
|
></button>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="c-timer__direction"
|
||||||
|
:class="[{'hide': !timerSign }, `icon-${timerSign}`]"
|
||||||
|
></div>
|
||||||
|
<div class="c-timer__value">{{ timeTextValue || "--:--:--" }}</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import ticker from 'utils/clock/Ticker';
|
||||||
|
|
||||||
|
const moment = require("moment-timezone");
|
||||||
|
const momentDurationFormatSetup = require("moment-duration-format");
|
||||||
|
|
||||||
|
momentDurationFormatSetup(moment);
|
||||||
|
|
||||||
|
export default {
|
||||||
|
inject: ['openmct', 'currentView', 'objectPath'],
|
||||||
|
props: {
|
||||||
|
domainObject: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
lastTimestamp: undefined,
|
||||||
|
active: true
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
configuration() {
|
||||||
|
let configuration;
|
||||||
|
if (this.domainObject && this.domainObject.configuration) {
|
||||||
|
configuration = this.domainObject.configuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
return configuration;
|
||||||
|
},
|
||||||
|
relativeTimestamp() {
|
||||||
|
let relativeTimestamp;
|
||||||
|
if (this.configuration && this.configuration.timestamp) {
|
||||||
|
relativeTimestamp = moment(this.configuration.timestamp).toDate();
|
||||||
|
} else if (this.configuration && this.configuration.timestamp === undefined) {
|
||||||
|
relativeTimestamp = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return relativeTimestamp;
|
||||||
|
},
|
||||||
|
timeDelta() {
|
||||||
|
return this.lastTimestamp - this.relativeTimestamp;
|
||||||
|
},
|
||||||
|
timeTextValue() {
|
||||||
|
if (isNaN(this.timeDelta)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const toWholeSeconds = Math.abs(Math.floor(this.timeDelta / 1000) * 1000);
|
||||||
|
|
||||||
|
return moment.duration(toWholeSeconds, 'ms').format(this.format, { trim: false });
|
||||||
|
},
|
||||||
|
pausedTime() {
|
||||||
|
let pausedTime;
|
||||||
|
if (this.configuration && this.configuration.pausedTime) {
|
||||||
|
pausedTime = moment(this.configuration.pausedTime).toDate();
|
||||||
|
} else if (this.configuration && this.configuration.pausedTime === undefined) {
|
||||||
|
pausedTime = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pausedTime;
|
||||||
|
},
|
||||||
|
timerState() {
|
||||||
|
let timerState = 'started';
|
||||||
|
if (this.configuration && this.configuration.timerState) {
|
||||||
|
timerState = this.configuration.timerState;
|
||||||
|
}
|
||||||
|
|
||||||
|
return timerState;
|
||||||
|
},
|
||||||
|
timerStateButtonText() {
|
||||||
|
let buttonText = 'Pause';
|
||||||
|
if (['paused', 'stopped'].includes(this.timerState)) {
|
||||||
|
buttonText = 'Start';
|
||||||
|
}
|
||||||
|
|
||||||
|
return buttonText;
|
||||||
|
},
|
||||||
|
timerStateButtonIcon() {
|
||||||
|
let buttonIcon = 'icon-pause';
|
||||||
|
if (['paused', 'stopped'].includes(this.timerState)) {
|
||||||
|
buttonIcon = 'icon-play';
|
||||||
|
}
|
||||||
|
|
||||||
|
return buttonIcon;
|
||||||
|
},
|
||||||
|
timerFormat() {
|
||||||
|
let timerFormat = 'long';
|
||||||
|
if (this.configuration && this.configuration.timerFormat) {
|
||||||
|
timerFormat = this.configuration.timerFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
return timerFormat;
|
||||||
|
},
|
||||||
|
format() {
|
||||||
|
let format;
|
||||||
|
if (this.timerFormat === 'long') {
|
||||||
|
format = 'd[D] HH:mm:ss';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.timerFormat === 'short') {
|
||||||
|
format = 'HH:mm:ss';
|
||||||
|
}
|
||||||
|
|
||||||
|
return format;
|
||||||
|
},
|
||||||
|
timerType() {
|
||||||
|
let timerType = null;
|
||||||
|
if (isNaN(this.timeDelta)) {
|
||||||
|
return timerType;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.timeDelta < 0) {
|
||||||
|
timerType = 'countDown';
|
||||||
|
} else if (this.timeDelta >= 1000) {
|
||||||
|
timerType = 'countUp';
|
||||||
|
}
|
||||||
|
|
||||||
|
return timerType;
|
||||||
|
},
|
||||||
|
timerSign() {
|
||||||
|
let timerSign = null;
|
||||||
|
if (this.timerType === 'countUp') {
|
||||||
|
timerSign = 'plus';
|
||||||
|
} else if (this.timerType === 'countDown') {
|
||||||
|
timerSign = 'minus';
|
||||||
|
}
|
||||||
|
|
||||||
|
return timerSign;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
if (this.configuration && this.configuration.timerState === undefined) {
|
||||||
|
const timerAction = !this.relativeTimestamp ? 'stop' : 'start';
|
||||||
|
this.triggerAction(`timer.${timerAction}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
window.requestAnimationFrame(this.tick);
|
||||||
|
this.unlisten = ticker.listen(() => {
|
||||||
|
this.openmct.objects.refresh(this.domainObject);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
destroyed() {
|
||||||
|
this.active = false;
|
||||||
|
if (this.unlisten) {
|
||||||
|
this.unlisten();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
tick() {
|
||||||
|
const isTimerRunning = !['paused', 'stopped'].includes(this.timerState);
|
||||||
|
if (isTimerRunning) {
|
||||||
|
this.lastTimestamp = new Date();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.timerState === 'paused' && !this.lastTimestamp) {
|
||||||
|
this.lastTimestamp = this.pausedTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.active) {
|
||||||
|
window.requestAnimationFrame(this.tick);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
restartTimer() {
|
||||||
|
this.triggerAction('timer.restart');
|
||||||
|
},
|
||||||
|
toggleStateButton() {
|
||||||
|
if (this.timerState === 'started') {
|
||||||
|
this.triggerAction('timer.pause');
|
||||||
|
} else if (['paused', 'stopped'].includes(this.timerState)) {
|
||||||
|
this.triggerAction('timer.start');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
triggerAction(actionKey) {
|
||||||
|
const action = this.openmct.actions.getAction(actionKey);
|
||||||
|
if (action) {
|
||||||
|
action.invoke(this.objectPath, this.currentView);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
119
src/plugins/timer/plugin.js
Normal file
119
src/plugins/timer/plugin.js
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2009-2021, 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 TimerViewProvider from './TimerViewProvider';
|
||||||
|
|
||||||
|
import PauseTimerAction from './actions/PauseTimerAction';
|
||||||
|
import RestartTimerAction from './actions/RestartTimerAction';
|
||||||
|
import StartTimerAction from './actions/StartTimerAction';
|
||||||
|
import StopTimerAction from './actions/StopTimerAction';
|
||||||
|
|
||||||
|
export default function TimerPlugin() {
|
||||||
|
return function install(openmct) {
|
||||||
|
openmct.types.addType('timer', {
|
||||||
|
name: 'Timer',
|
||||||
|
description: 'A timer that counts up or down to a datetime. Timers can be started, stopped and reset whenever needed, and support a variety of display formats. Each Timer displays the same value to all users. Timers can be added to Display Layouts.',
|
||||||
|
creatable: true,
|
||||||
|
cssClass: 'icon-timer',
|
||||||
|
initialize: function (domainObject) {
|
||||||
|
domainObject.configuration = {
|
||||||
|
timerFormat: 'long',
|
||||||
|
timestamp: undefined,
|
||||||
|
timezone: 'UTC',
|
||||||
|
timerState: undefined,
|
||||||
|
pausedTime: undefined
|
||||||
|
};
|
||||||
|
},
|
||||||
|
"form": [
|
||||||
|
{
|
||||||
|
"key": "timestamp",
|
||||||
|
"control": "datetime",
|
||||||
|
"name": "Target",
|
||||||
|
property: [
|
||||||
|
'configuration',
|
||||||
|
'timestamp'
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "timerFormat",
|
||||||
|
"name": "Display Format",
|
||||||
|
"control": "select",
|
||||||
|
"options": [
|
||||||
|
{
|
||||||
|
"value": "long",
|
||||||
|
"name": "DDD hh:mm:ss"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value": "short",
|
||||||
|
"name": "hh:mm:ss"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
property: [
|
||||||
|
'configuration',
|
||||||
|
'timerFormat'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
openmct.objectViews.addProvider(new TimerViewProvider(openmct));
|
||||||
|
|
||||||
|
openmct.actions.register(new PauseTimerAction(openmct));
|
||||||
|
openmct.actions.register(new RestartTimerAction(openmct));
|
||||||
|
openmct.actions.register(new StartTimerAction(openmct));
|
||||||
|
openmct.actions.register(new StopTimerAction(openmct));
|
||||||
|
|
||||||
|
openmct.objects.addGetInterceptor({
|
||||||
|
appliesTo: (identifier, domainObject) => {
|
||||||
|
return domainObject && domainObject.type === 'timer';
|
||||||
|
},
|
||||||
|
invoke: (identifier, domainObject) => {
|
||||||
|
if (domainObject.configuration) {
|
||||||
|
return domainObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
const configuration = {};
|
||||||
|
|
||||||
|
if (domainObject.timerFormat) {
|
||||||
|
configuration.timerFormat = domainObject.timerFormat;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (domainObject.timestamp) {
|
||||||
|
configuration.timestamp = domainObject.timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (domainObject.timerState) {
|
||||||
|
configuration.timerState = domainObject.timerState;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (domainObject.pausedTime) {
|
||||||
|
configuration.pausedTime = domainObject.pausedTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
openmct.objects.mutate(domainObject, 'configuration', configuration);
|
||||||
|
|
||||||
|
return domainObject;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
354
src/plugins/timer/pluginSpec.js
Normal file
354
src/plugins/timer/pluginSpec.js
Normal file
@ -0,0 +1,354 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2009-2021, 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 { createOpenMct, spyOnBuiltins, resetApplicationState } from 'utils/testing';
|
||||||
|
import timerPlugin from './plugin';
|
||||||
|
|
||||||
|
import Vue from 'vue';
|
||||||
|
|
||||||
|
describe("Timer plugin:", () => {
|
||||||
|
let openmct;
|
||||||
|
let timerDefinition;
|
||||||
|
let element;
|
||||||
|
let child;
|
||||||
|
let appHolder;
|
||||||
|
|
||||||
|
let timerDomainObject;
|
||||||
|
|
||||||
|
function setupTimer() {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
timerDomainObject = {
|
||||||
|
identifier: {
|
||||||
|
key: 'timer',
|
||||||
|
namespace: 'test-namespace'
|
||||||
|
},
|
||||||
|
type: 'timer'
|
||||||
|
};
|
||||||
|
|
||||||
|
appHolder = document.createElement('div');
|
||||||
|
appHolder.style.width = '640px';
|
||||||
|
appHolder.style.height = '480px';
|
||||||
|
document.body.appendChild(appHolder);
|
||||||
|
|
||||||
|
openmct = createOpenMct();
|
||||||
|
|
||||||
|
element = document.createElement('div');
|
||||||
|
child = document.createElement('div');
|
||||||
|
element.appendChild(child);
|
||||||
|
|
||||||
|
openmct.install(timerPlugin());
|
||||||
|
|
||||||
|
timerDefinition = openmct.types.get('timer').definition;
|
||||||
|
timerDefinition.initialize(timerDomainObject);
|
||||||
|
|
||||||
|
openmct.on('start', resolve);
|
||||||
|
openmct.start(appHolder);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("should still work if it's in the old format", () => {
|
||||||
|
let timerViewProvider;
|
||||||
|
let timerView;
|
||||||
|
let timerViewObject;
|
||||||
|
let mutableTimerObject;
|
||||||
|
let timerObjectPath;
|
||||||
|
const relativeTimestamp = 1634774400000; // Oct 21 2021, 12:00 AM
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await setupTimer();
|
||||||
|
|
||||||
|
timerViewObject = {
|
||||||
|
identifier: {
|
||||||
|
key: 'timer',
|
||||||
|
namespace: 'test-namespace'
|
||||||
|
},
|
||||||
|
type: 'timer',
|
||||||
|
id: "test-object",
|
||||||
|
name: 'Timer',
|
||||||
|
timerFormat: 'short',
|
||||||
|
timestamp: relativeTimestamp,
|
||||||
|
timerState: 'paused',
|
||||||
|
pausedTime: relativeTimestamp
|
||||||
|
};
|
||||||
|
|
||||||
|
const applicableViews = openmct.objectViews.get(timerViewObject, [timerViewObject]);
|
||||||
|
timerViewProvider = applicableViews.find(viewProvider => viewProvider.key === 'timer.view');
|
||||||
|
|
||||||
|
mutableTimerObject = await openmct.objects.getMutable(timerViewObject.identifier);
|
||||||
|
|
||||||
|
timerObjectPath = [mutableTimerObject];
|
||||||
|
timerView = timerViewProvider.view(mutableTimerObject, timerObjectPath);
|
||||||
|
timerView.show(child);
|
||||||
|
|
||||||
|
await Vue.nextTick();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should migrate old object properties to the configuration section", () => {
|
||||||
|
openmct.objects.applyGetInterceptors(timerViewObject.identifier, timerViewObject);
|
||||||
|
expect(timerViewObject.configuration.timerFormat).toBe('short');
|
||||||
|
expect(timerViewObject.configuration.timestamp).toBe(relativeTimestamp);
|
||||||
|
expect(timerViewObject.configuration.timerState).toBe('paused');
|
||||||
|
expect(timerViewObject.configuration.pausedTime).toBe(relativeTimestamp);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("Timer view:", () => {
|
||||||
|
let timerViewProvider;
|
||||||
|
let timerView;
|
||||||
|
let timerViewObject;
|
||||||
|
let mutableTimerObject;
|
||||||
|
let timerObjectPath;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await setupTimer();
|
||||||
|
|
||||||
|
spyOnBuiltins(['requestAnimationFrame']);
|
||||||
|
window.requestAnimationFrame.and.callFake((cb) => setTimeout(cb, 500));
|
||||||
|
const baseTimestamp = 1634688000000; // Oct 20, 2021, 12:00 AM
|
||||||
|
const relativeTimestamp = 1634774400000; // Oct 21 2021, 12:00 AM
|
||||||
|
|
||||||
|
jasmine.clock().install();
|
||||||
|
const baseTime = new Date(baseTimestamp);
|
||||||
|
jasmine.clock().mockDate(baseTime);
|
||||||
|
|
||||||
|
timerViewObject = {
|
||||||
|
...timerDomainObject,
|
||||||
|
id: "test-object",
|
||||||
|
name: 'Timer',
|
||||||
|
configuration: {
|
||||||
|
timerFormat: 'long',
|
||||||
|
timestamp: relativeTimestamp,
|
||||||
|
timezone: 'UTC',
|
||||||
|
timerState: undefined,
|
||||||
|
pausedTime: undefined
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
spyOn(openmct.objects, 'get').and.returnValue(Promise.resolve(timerViewObject));
|
||||||
|
spyOn(openmct.objects, 'save').and.returnValue(Promise.resolve(true));
|
||||||
|
|
||||||
|
const applicableViews = openmct.objectViews.get(timerViewObject, [timerViewObject]);
|
||||||
|
timerViewProvider = applicableViews.find(viewProvider => viewProvider.key === 'timer.view');
|
||||||
|
|
||||||
|
mutableTimerObject = await openmct.objects.getMutable(timerViewObject.identifier);
|
||||||
|
|
||||||
|
timerObjectPath = [mutableTimerObject];
|
||||||
|
timerView = timerViewProvider.view(mutableTimerObject, timerObjectPath);
|
||||||
|
timerView.show(child);
|
||||||
|
|
||||||
|
await Vue.nextTick();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
jasmine.clock().uninstall();
|
||||||
|
timerView.destroy();
|
||||||
|
openmct.objects.destroyMutable(mutableTimerObject);
|
||||||
|
if (appHolder) {
|
||||||
|
appHolder.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
return resetApplicationState(openmct);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("has name as Timer", () => {
|
||||||
|
expect(timerDefinition.name).toEqual('Timer');
|
||||||
|
});
|
||||||
|
|
||||||
|
it("is creatable", () => {
|
||||||
|
expect(timerDefinition.creatable).toEqual(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("provides timer view", () => {
|
||||||
|
expect(timerViewProvider).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders timer element", () => {
|
||||||
|
const timerElement = element.querySelectorAll('.c-timer');
|
||||||
|
expect(timerElement.length).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders major elements", () => {
|
||||||
|
const timerElement = element.querySelector('.c-timer');
|
||||||
|
const resetButton = timerElement.querySelector('.c-timer__ctrl-reset');
|
||||||
|
const pausePlayButton = timerElement.querySelector('.c-timer__ctrl-pause-play');
|
||||||
|
const timerDirectionIcon = timerElement.querySelector('.c-timer__direction');
|
||||||
|
const timerValue = timerElement.querySelector('.c-timer__value');
|
||||||
|
const hasMajorElements = Boolean(resetButton && pausePlayButton && timerDirectionIcon && timerValue);
|
||||||
|
|
||||||
|
expect(hasMajorElements).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("gets errors from actions if configuration is not passed", async () => {
|
||||||
|
await Vue.nextTick();
|
||||||
|
const objectPath = _.cloneDeep(timerObjectPath);
|
||||||
|
delete objectPath[0].configuration;
|
||||||
|
|
||||||
|
let action = openmct.actions.getAction('timer.start');
|
||||||
|
let actionResults = action.invoke(objectPath);
|
||||||
|
let actionFilterWithoutConfig = action.appliesTo(objectPath);
|
||||||
|
await openmct.objects.mutate(timerObjectPath[0], 'configuration', { timerState: 'started' });
|
||||||
|
let actionFilterWithConfig = action.appliesTo(timerObjectPath);
|
||||||
|
|
||||||
|
let actionError = new Error('Unable to run start timer action. No domainObject provided.');
|
||||||
|
expect(actionResults).toEqual(actionError);
|
||||||
|
expect(actionFilterWithoutConfig).toBe(undefined);
|
||||||
|
expect(actionFilterWithConfig).toBe(false);
|
||||||
|
|
||||||
|
action = openmct.actions.getAction('timer.stop');
|
||||||
|
actionResults = action.invoke(objectPath);
|
||||||
|
actionFilterWithoutConfig = action.appliesTo(objectPath);
|
||||||
|
await openmct.objects.mutate(timerObjectPath[0], 'configuration', { timerState: 'stopped' });
|
||||||
|
actionFilterWithConfig = action.appliesTo(timerObjectPath);
|
||||||
|
|
||||||
|
actionError = new Error('Unable to run stop timer action. No domainObject provided.');
|
||||||
|
expect(actionResults).toEqual(actionError);
|
||||||
|
expect(actionFilterWithoutConfig).toBe(undefined);
|
||||||
|
expect(actionFilterWithConfig).toBe(false);
|
||||||
|
|
||||||
|
action = openmct.actions.getAction('timer.pause');
|
||||||
|
actionResults = action.invoke(objectPath);
|
||||||
|
actionFilterWithoutConfig = action.appliesTo(objectPath);
|
||||||
|
await openmct.objects.mutate(timerObjectPath[0], 'configuration', { timerState: 'paused' });
|
||||||
|
actionFilterWithConfig = action.appliesTo(timerObjectPath);
|
||||||
|
|
||||||
|
actionError = new Error('Unable to run pause timer action. No domainObject provided.');
|
||||||
|
expect(actionResults).toEqual(actionError);
|
||||||
|
expect(actionFilterWithoutConfig).toBe(undefined);
|
||||||
|
expect(actionFilterWithConfig).toBe(false);
|
||||||
|
|
||||||
|
action = openmct.actions.getAction('timer.restart');
|
||||||
|
actionResults = action.invoke(objectPath);
|
||||||
|
actionFilterWithoutConfig = action.appliesTo(objectPath);
|
||||||
|
await openmct.objects.mutate(timerObjectPath[0], 'configuration', { timerState: 'stopped' });
|
||||||
|
actionFilterWithConfig = action.appliesTo(timerObjectPath);
|
||||||
|
|
||||||
|
actionError = new Error('Unable to run restart timer action. No domainObject provided.');
|
||||||
|
expect(actionResults).toEqual(actionError);
|
||||||
|
expect(actionFilterWithoutConfig).toBe(undefined);
|
||||||
|
expect(actionFilterWithConfig).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("displays a started timer ticking down to a future date", async () => {
|
||||||
|
const newBaseTime = 1634774400000; // Oct 21 2021, 12:00 AM
|
||||||
|
openmct.objects.mutate(timerViewObject, 'configuration.timestamp', newBaseTime);
|
||||||
|
|
||||||
|
jasmine.clock().tick(5000);
|
||||||
|
await Vue.nextTick();
|
||||||
|
|
||||||
|
const timerElement = element.querySelector('.c-timer');
|
||||||
|
const timerPausePlayButton = timerElement.querySelector('.c-timer__ctrl-pause-play');
|
||||||
|
const timerDirectionIcon = timerElement.querySelector('.c-timer__direction');
|
||||||
|
const timerValue = timerElement.querySelector('.c-timer__value').innerText;
|
||||||
|
|
||||||
|
expect(timerPausePlayButton.classList.contains('icon-pause')).toBe(true);
|
||||||
|
expect(timerDirectionIcon.classList.contains('icon-minus')).toBe(true);
|
||||||
|
expect(timerValue).toBe('0D 23:59:55');
|
||||||
|
});
|
||||||
|
|
||||||
|
it("displays a started timer ticking up from a past date", async () => {
|
||||||
|
const newBaseTime = 1634601600000; // Oct 19, 2021, 12:00 AM
|
||||||
|
openmct.objects.mutate(timerViewObject, 'configuration.timestamp', newBaseTime);
|
||||||
|
|
||||||
|
jasmine.clock().tick(5000);
|
||||||
|
await Vue.nextTick();
|
||||||
|
|
||||||
|
const timerElement = element.querySelector('.c-timer');
|
||||||
|
const timerPausePlayButton = timerElement.querySelector('.c-timer__ctrl-pause-play');
|
||||||
|
const timerDirectionIcon = timerElement.querySelector('.c-timer__direction');
|
||||||
|
const timerValue = timerElement.querySelector('.c-timer__value').innerText;
|
||||||
|
|
||||||
|
expect(timerPausePlayButton.classList.contains('icon-pause')).toBe(true);
|
||||||
|
expect(timerDirectionIcon.classList.contains('icon-plus')).toBe(true);
|
||||||
|
expect(timerValue).toBe('1D 00:00:05');
|
||||||
|
});
|
||||||
|
|
||||||
|
it("displays a paused timer correctly in the DOM", async () => {
|
||||||
|
jasmine.clock().tick(5000);
|
||||||
|
await Vue.nextTick();
|
||||||
|
|
||||||
|
let action = openmct.actions.getAction('timer.pause');
|
||||||
|
if (action) {
|
||||||
|
action.invoke(timerObjectPath, timerView);
|
||||||
|
}
|
||||||
|
|
||||||
|
await Vue.nextTick();
|
||||||
|
const timerElement = element.querySelector('.c-timer');
|
||||||
|
const timerPausePlayButton = timerElement.querySelector('.c-timer__ctrl-pause-play');
|
||||||
|
let timerValue = timerElement.querySelector('.c-timer__value').innerText;
|
||||||
|
|
||||||
|
expect(timerPausePlayButton.classList.contains('icon-play')).toBe(true);
|
||||||
|
expect(timerValue).toBe('0D 23:59:55');
|
||||||
|
|
||||||
|
jasmine.clock().tick(5000);
|
||||||
|
await Vue.nextTick();
|
||||||
|
expect(timerValue).toBe('0D 23:59:55');
|
||||||
|
|
||||||
|
action = openmct.actions.getAction('timer.start');
|
||||||
|
if (action) {
|
||||||
|
action.invoke(timerObjectPath, timerView);
|
||||||
|
}
|
||||||
|
|
||||||
|
await Vue.nextTick();
|
||||||
|
action = openmct.actions.getAction('timer.pause');
|
||||||
|
if (action) {
|
||||||
|
action.invoke(timerObjectPath, timerView);
|
||||||
|
}
|
||||||
|
|
||||||
|
await Vue.nextTick();
|
||||||
|
timerValue = timerElement.querySelector('.c-timer__value').innerText;
|
||||||
|
expect(timerValue).toBe('1D 00:00:00');
|
||||||
|
});
|
||||||
|
|
||||||
|
it("displays a stopped timer correctly in the DOM", async () => {
|
||||||
|
const action = openmct.actions.getAction('timer.stop');
|
||||||
|
if (action) {
|
||||||
|
action.invoke(timerObjectPath, timerView);
|
||||||
|
}
|
||||||
|
|
||||||
|
await Vue.nextTick();
|
||||||
|
const timerElement = element.querySelector('.c-timer');
|
||||||
|
const timerValue = timerElement.querySelector('.c-timer__value').innerText;
|
||||||
|
const timerResetButton = timerElement.querySelector('.c-timer__ctrl-reset');
|
||||||
|
const timerPausePlayButton = timerElement.querySelector('.c-timer__ctrl-pause-play');
|
||||||
|
|
||||||
|
expect(timerResetButton.classList.contains('hide')).toBe(true);
|
||||||
|
expect(timerPausePlayButton.classList.contains('icon-play')).toBe(true);
|
||||||
|
expect(timerValue).toBe('--:--:--');
|
||||||
|
});
|
||||||
|
|
||||||
|
it("displays a restarted timer correctly in the DOM", async () => {
|
||||||
|
const action = openmct.actions.getAction('timer.restart');
|
||||||
|
if (action) {
|
||||||
|
action.invoke(timerObjectPath, timerView);
|
||||||
|
}
|
||||||
|
|
||||||
|
jasmine.clock().tick(5000);
|
||||||
|
await Vue.nextTick();
|
||||||
|
const timerElement = element.querySelector('.c-timer');
|
||||||
|
const timerValue = timerElement.querySelector('.c-timer__value').innerText;
|
||||||
|
const timerPausePlayButton = timerElement.querySelector('.c-timer__ctrl-pause-play');
|
||||||
|
|
||||||
|
expect(timerPausePlayButton.classList.contains('icon-pause')).toBe(true);
|
||||||
|
expect(timerValue).toBe('0D 00:00:05');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
81
src/utils/clock/Ticker.js
Normal file
81
src/utils/clock/Ticker.js
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2009-2021, 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.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
class Ticker {
|
||||||
|
constructor() {
|
||||||
|
this.callbacks = [];
|
||||||
|
this.last = new Date() - 1000;
|
||||||
|
|
||||||
|
this.tick();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calls functions every second, as close to the actual second
|
||||||
|
* tick as is feasible.
|
||||||
|
* @constructor
|
||||||
|
* @memberof utils/clock
|
||||||
|
*/
|
||||||
|
tick() {
|
||||||
|
const timestamp = new Date();
|
||||||
|
const millis = timestamp % 1000;
|
||||||
|
|
||||||
|
// Only update callbacks if a second has actually passed.
|
||||||
|
if (timestamp >= this.last + 1000) {
|
||||||
|
this.callbacks.forEach(function (callback) {
|
||||||
|
callback(timestamp);
|
||||||
|
});
|
||||||
|
this.last = timestamp - millis;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to update at exactly the next second
|
||||||
|
setTimeout(() => {
|
||||||
|
this.tick();
|
||||||
|
}, 1000 - millis, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listen for clock ticks. The provided callback will
|
||||||
|
* be invoked with the current timestamp (in milliseconds
|
||||||
|
* since Jan 1 1970) at regular intervals, as near to the
|
||||||
|
* second boundary as possible.
|
||||||
|
*
|
||||||
|
* @param {Function} callback callback to invoke
|
||||||
|
* @returns {Function} a function to unregister this listener
|
||||||
|
*/
|
||||||
|
listen(callback) {
|
||||||
|
this.callbacks.push(callback);
|
||||||
|
|
||||||
|
// Provide immediate feedback
|
||||||
|
callback(this.last);
|
||||||
|
|
||||||
|
// Provide a deregistration function
|
||||||
|
return () => {
|
||||||
|
this.callbacks = this.callbacks.filter(function (cb) {
|
||||||
|
return cb !== callback;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let ticker = new Ticker();
|
||||||
|
|
||||||
|
export default ticker;
|
Loading…
x
Reference in New Issue
Block a user