[Clocks / Timers]  adding ability to pause and resume

added the alternating pause and resume timer
This commit is contained in:
DJ 2017-01-14 16:43:20 -06:00
parent 9df59522d9
commit 165bd4f638
9 changed files with 431 additions and 7 deletions

View File

@ -29,6 +29,8 @@ define([
"./src/actions/StartTimerAction",
"./src/actions/RestartTimerAction",
"./src/actions/StopTimerAction",
"./src/actions/PauseTimerAction",
"./src/actions/ResumeTimerAction",
"text!./res/templates/clock.html",
"text!./res/templates/timer.html",
'legacyRegistry'
@ -41,6 +43,8 @@ define([
StartTimerAction,
RestartTimerAction,
StopTimerAction,
PauseTimerAction,
ResumeTimerAction,
clockTemplate,
timerTemplate,
legacyRegistry
@ -152,6 +156,28 @@ define([
"cssclass": "icon-refresh",
"priority": "preferred"
},
{
"key": "timer.pause",
"implementation": PauseTimerAction,
"depends": [
"now"
],
"category": "contextual",
"name": "Pause",
"cssclass": "icon-pause",
"priority": "preferred"
},
{
"key": "timer.resume",
"implementation": ResumeTimerAction,
"depends": [
"now"
],
"category": "contextual",
"name": "Resume",
"cssclass": "icon-play",
"priority": "preferred"
},
{
"key": "timer.stop",
"implementation": StopTimerAction,
@ -251,6 +277,16 @@ define([
"name": "hh:mm:ss"
}
]
},
{
"key": "paused",
"control": "boolean",
"name": "PauseCheck"
},
{
"key": "pausedTime",
"control": "long",
"name": "TimeOfPause"
}
],
"model": {

View File

@ -53,7 +53,12 @@ define(
model.timestamp = now();
}
return domainObject.useCapability('mutation', setTimestamp);
function setPaused(model) {
model.paused = false;
}
return domainObject.useCapability('mutation', setTimestamp) &&
domainObject.useCapability('mutation', setPaused);
};
return AbstractTimerAction;

View File

@ -0,0 +1,78 @@
/*****************************************************************************
* 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(
['./AbstractTimerAction'],
function (AbstractTimerAction) {
/**
* Implements the "Start" action for timers.
*
* Sets the reference timestamp in a timer to the current
* time, such that it begins counting up.
*
* @extends {platform/features/clock.AbstractTimerAction}
* @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) {
AbstractTimerAction.apply(this, [now, context]);
}
PauseTimerAction.prototype =
Object.create(AbstractTimerAction.prototype);
PauseTimerAction.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.timestamp !== undefined && !model.paused;
};
PauseTimerAction.prototype.perform = function () {
var domainObject = this.domainObject,
now = this.now;
function setPaused(model) {
model.paused = true;
}
function setPausedTime(model) {
model.pausedTime = now();
}
return domainObject.useCapability('mutation', setPaused) &&
domainObject.useCapability('mutation', setPausedTime);
};
return PauseTimerAction;
}
);

View File

@ -0,0 +1,85 @@
/*****************************************************************************
* 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(
['./AbstractTimerAction'],
function (AbstractTimerAction) {
/**
* Implements the "Start" action for timers.
*
* Sets the reference timestamp in a timer to the current
* time, such that it begins counting up.
*
* @extends {platform/features/clock.AbstractTimerAction}
* @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 ResumeTimerAction(now, context) {
AbstractTimerAction.apply(this, [now, context]);
}
ResumeTimerAction.prototype =
Object.create(AbstractTimerAction.prototype);
ResumeTimerAction.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.timestamp !== undefined &&
model.paused;
};
ResumeTimerAction.prototype.perform = function () {
var domainObject = this.domainObject,
now = this.now;
function setPaused(model) {
model.paused = false;
}
function setTimestamp(model) {
var timeShift = now() - model.pausedTime;
model.timestamp = model.timestamp + timeShift;
}
function setPausedTime(model) {
model.pausedTime = undefined;
}
return domainObject.useCapability('mutation', setPaused) &&
domainObject.useCapability('mutation', setTimestamp) &&
domainObject.useCapability('mutation', setPausedTime);
};
return ResumeTimerAction;
}
);

View File

@ -57,6 +57,5 @@ define(
};
return StartTimerAction;
}
);

View File

@ -64,10 +64,14 @@ define(
model.timestamp = undefined;
}
return domainObject.useCapability('mutation', setTimestamp);
function setPaused(model) {
model.paused = false;
}
return domainObject.useCapability('mutation', setTimestamp) &&
domainObject.useCapability('mutation', setPaused);
};
return StopTimerAction;
}
);

View File

@ -74,7 +74,15 @@ define(
formatKey = model.timerFormat,
actionCapability = domainObject.getCapability('action'),
actionKey = (timestamp === undefined) ?
'timer.start' : 'timer.restart';
'timer.start' : 'timer.restart';
self.paused = model.paused;
self.pausedTime = model.pausedTime;
//if paused on startup show last known position
if (self.paused && !lastTimestamp){
lastTimestamp = self.pausedTime;
}
updateFormat(formatKey);
updateTimestamp(timestamp);
@ -98,8 +106,11 @@ define(
function tick() {
var lastSign = self.signValue,
lastText = self.textValue;
lastTimestamp = now();
update();
if (!self.paused) {
lastTimestamp = now();
update();
}
// We're running in an animation frame, not in a digest cycle.
// We need to trigger a digest cycle if our displayable data
// changes.

View File

@ -0,0 +1,103 @@
/*****************************************************************************
* 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));
}
};
}
beforeEach(function () {
mockNow = jasmine.createSpy('now');
mockDomainObject = jasmine.createSpyObj(
'domainObject',
['getCapability', 'useCapability', 'getModel']
);
mockDomainObject.useCapability.andCallFake(function (c, v) {
if (c === 'mutation') {
testModel = v(testModel) || testModel;
return asPromise(true);
}
});
mockDomainObject.getModel.andCallFake(function () {
return testModel;
});
testModel = {};
testContext = { domainObject: mockDomainObject };
action = new PauseTimerAction(mockNow, testContext);
});
it("updates the model with a timestamp", function () {
mockNow.andReturn(12000);
action.perform();
expect(testModel.timestamp).toEqual(12000);
});
it("applies only to timers without a target time", function () {
//Timer is on
testModel.type = 'timer';
testModel.timestamp = 12000;
testModel.paused = true;
expect(PauseTimerAction.appliesTo(testContext)).toBeFalsy();
testModel.paused = false;
expect(PauseTimerAction.appliesTo(testContext)).toBeTruthy();
//Timer has not started
testModel.timestamp = undefined;
testModel.paused = true;
expect(PauseTimerAction.appliesTo(testContext)).toBeFalsy();
testModel.paused = false;
expect(PauseTimerAction.appliesTo(testContext)).toBeFalsy();
//Timer is actually a clock
testModel.type = 'clock';
testModel.timestamp = 12000;
testModel.paused = true;
expect(PauseTimerAction.appliesTo(testContext)).toBeFalsy();
testModel.paused = false;
expect(PauseTimerAction.appliesTo(testContext)).toBeFalsy();
});
});
}
);

View File

@ -0,0 +1,103 @@
/*****************************************************************************
* 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/ResumeTimerAction"],
function (ResumeTimerAction) {
describe("A timer's Resume action", function () {
var mockNow,
mockDomainObject,
testModel,
testContext,
action;
function asPromise(value) {
return (value || {}).then ? value : {
then: function (callback) {
return asPromise(callback(value));
}
};
}
beforeEach(function () {
mockNow = jasmine.createSpy('now');
mockDomainObject = jasmine.createSpyObj(
'domainObject',
['getCapability', 'useCapability', 'getModel']
);
mockDomainObject.useCapability.andCallFake(function (c, v) {
if (c === 'mutation') {
testModel = v(testModel) || testModel;
return asPromise(true);
}
});
mockDomainObject.getModel.andCallFake(function () {
return testModel;
});
testModel = {};
testContext = { domainObject: mockDomainObject };
action = new ResumeTimerAction(mockNow, testContext);
});
it("updates the model with a timestamp", function () {
mockNow.andReturn(12000);
action.perform();
expect(testModel.timestamp).toEqual(12000);
});
it("applies only to timers without a target time", function () {
//Timer is on
testModel.type = 'timer';
testModel.timestamp = 12000;
testModel.paused = true;
expect(ResumeTimerAction.appliesTo(testContext)).toBeTruthy();
testModel.paused = false;
expect(ResumeTimerAction.appliesTo(testContext)).toBeFalsy();
//Timer has not started
testModel.timestamp = undefined;
testModel.paused = true;
expect(ResumeTimerAction.appliesTo(testContext)).toBeFalsy();
testModel.paused = false;
expect(ResumeTimerAction.appliesTo(testContext)).toBeFalsy();
//Timer is actually a clock
testModel.type = 'clock';
testModel.timestamp = 12000;
testModel.paused = true;
expect(ResumeTimerAction.appliesTo(testContext)).toBeFalsy();
testModel.paused = false;
expect(ResumeTimerAction.appliesTo(testContext)).toBeFalsy();
});
});
}
);