[Rt-commit] rt branch, 4.4/background-ticket-timer, created. rt-4.4.0-85-g100b9c7
Shawn Moore
shawn at bestpractical.com
Thu May 5 16:19:39 EDT 2016
The branch, 4.4/background-ticket-timer has been created
at 100b9c755a056b282e88a615d112664bc6f68e24 (commit)
- Log -----------------------------------------------------------------
commit 100b9c755a056b282e88a615d112664bc6f68e24
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Thu May 5 20:06:58 2016 +0000
Change ticket timer from ticking seconds to measuring duration
There are several problems with incrementing a counter every second. It
boils down to the fact that setInterval is certainly not a guarantee,
it's more of a best effort. In particular, on mobile devices, browsers
will not waste precious battery and CPU cycles to run timers for tabs in
the background. So when you come back to your ticket timer after minutes
or hours of work, the browser will not have been calling setInterval,
causing you to lose all that time worked.
Rather than incrementing a seconds counter every second, we instead
track when the last unpause happened, and take its difference from the
current time. If the user pauses and unpauses repeatedly, we also track
"committed seconds". Any time we need the duration (for display in the
UI or for submitting as time worked) we sum the two. The result is that
when the browser resumes calling setInterval after being backgrounded
away for hours, that duration will be accurate, since it's directly
measuring time passed rather than relying on setInterval having been
called regularly. setInterval is now used _only_ for updating the
display, so it can be called as frequently or rarely as the browser
decides.
Fixes: I#31707
diff --git a/share/html/Helpers/TicketTimer b/share/html/Helpers/TicketTimer
index c0f58c2..5774cf1 100644
--- a/share/html/Helpers/TicketTimer
+++ b/share/html/Helpers/TicketTimer
@@ -65,7 +65,26 @@ my $submit_url = RT->Config->Get('WebPath') . '/Helpers/AddTimeWorked';
<script type="text/javascript">
jQuery( function() {
var Interval;
- var Seconds = 0;
+
+ // LastUnpause tracks when the current timer started. Then we render
+ // (current time - LastUnpause). This is more reliable than a timer
+ // that ticks up every second. For example, if JavaScript is temporarily
+ // paused (such as being on a background browser tab on a mobile device),
+ // the seconds ticker doesn't run. When the timer is paused, LastUnpaused
+ // will be a false value.
+ var LastUnpause = (new Date).getTime() / 1000;
+
+ // How many seconds has passed since the current timer started?
+ var CurrentSeconds = function () {
+ if (!LastUnpause) return 0;
+ return Math.floor(((new Date).getTime() / 1000) - LastUnpause);
+ };
+
+ // CommittedSeconds tracks how long we've "committed" time, which is
+ // different from when the timer was initially launched, due to unpausing.
+ // Every time we pause, we add (current time - LastUnpause) to
+ // CommittedSeconds.
+ var CommittedSeconds = 0;
var readout = jQuery('.readout');
var playpause = jQuery('.playpause');
@@ -90,8 +109,7 @@ jQuery( function() {
};
var tick = function () {
- Seconds++;
- renderReadout(Seconds);
+ renderReadout(CommittedSeconds + CurrentSeconds());
};
jQuery('.playpause').click(function () {
@@ -99,6 +117,8 @@ jQuery( function() {
// pause
clearInterval(Interval);
Interval = false;
+ CommittedSeconds += CurrentSeconds();
+ LastUnpause = false;
playpause_img.attr('src', <% $unpause_img |n,j %>);
playpause_img.attr('alt', unpause_alt);
playpause_img.attr('title', unpause_alt);
@@ -106,6 +126,7 @@ jQuery( function() {
else {
// unpause
Interval = setInterval(tick, 1000);
+ LastUnpause = new Date().getTime() / 1000;
playpause_img.attr('src', <% $pause_img |n,j %>);
playpause_img.attr('alt', pause_alt);
playpause_img.attr('title', pause_alt);
@@ -116,16 +137,17 @@ jQuery( function() {
jQuery('.submit-time').click(function () {
clearInterval(Interval);
jQuery('.control-line a').hide();
+ CommittedSeconds += CurrentSeconds();
var payload = {
id: <% $Ticket->id %>,
- seconds: Seconds
+ seconds: CommittedSeconds
};
readout.text('<% loc("Submitting") %>');
var renderSubmitError = function (reason) {
- renderReadout(Seconds);
+ renderReadout(CommittedSeconds);
jQuery('.ticket-timer').addClass('error');
// give the browser a chance to redraw the readout
@@ -161,8 +183,8 @@ jQuery( function() {
return false;
});
- renderReadout(Seconds);
- Interval = setInterval(tick, 1000);
+ tick();
+ Interval = setInterval(tick, 500);
});
</script>
-----------------------------------------------------------------------
More information about the rt-commit
mailing list