[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