Merge branch 'maint'
[gitweb.git] / gitweb / static / js / blame_incremental.js
index f63f78b9ec102b35cf4db752deaa07cb36aa664b..db6eb505846aedfaca1cdbaf6f4d399d049de777 100644 (file)
@@ -7,7 +7,7 @@
  * @license GPLv2 or later
  */
 
-
+/* ============================================================ */
 /*
  * This code uses DOM methods instead of (nonstandard) innerHTML
  * to modify page.
  */
 
 
-/* ============================================================ */
+/* ............................................................ */
 /* utility/helper functions (and variables) */
 
-var xhr;        // XMLHttpRequest object
 var projectUrl; // partial query + separator ('?' or ';')
 
 // 'commits' is an associative map. It maps SHA1s to Commit objects.
@@ -132,7 +131,7 @@ function writeTimeInterval() {
 }
 
 /**
- * show an error message alert to user within page (in prohress info area)
+ * show an error message alert to user within page (in progress info area)
  * @param {String} str: plain text error message (no HTML)
  *
  * @globals div_progress_info
@@ -182,7 +181,7 @@ function getColorNo(tr) {
 
 var colorsFreq = [0, 0, 0];
 /**
- * return one of given possible colors (curently least used one)
+ * return one of given possible colors (currently least used one)
  * example: chooseColorNoFrom(2, 3) returns 2 or 3
  *
  * @param {Number[]} arguments: one or more numbers
@@ -203,8 +202,8 @@ function chooseColorNoFrom() {
 }
 
 /**
- * given two neigbour <tr> elements, find color which would be different
- * from color of both of neighbours; used to 3-color blame table
+ * given two neighbor <tr> elements, find color which would be different
+ * from color of both of neighbors; used to 3-color blame table
  *
  * @param {HTMLElement} tr_prev
  * @param {HTMLElement} tr_next
@@ -216,14 +215,14 @@ function findColorNo(tr_prev, tr_next) {
        var color_next = getColorNo(tr_next);
 
 
-       // neither of neighbours has color set
+       // neither of neighbors has color set
        // THEN we can use any of 3 possible colors
        if (!color_prev && !color_next) {
                return chooseColorNoFrom(1,2,3);
        }
 
-       // either both neighbours have the same color,
-       // or only one of neighbours have color set
+       // either both neighbors have the same color,
+       // or only one of neighbors have color set
        // THEN we can use any color except given
        var color;
        if (color_prev === color_next) {
@@ -237,7 +236,7 @@ function findColorNo(tr_prev, tr_next) {
                return chooseColorNoFrom((color % 3) + 1, ((color+1) % 3) + 1);
        }
 
-       // neighbours have different colors
+       // neighbors have different colors
        // THEN there is only one color left
        return (3 - ((color_prev + color_next) % 3));
 }
@@ -258,7 +257,7 @@ function isStartOfGroup(tr) {
 
 /**
  * change colors to use zebra coloring (2 colors) instead of 3 colors
- * concatenate neighbour commit groups belonging to the same commit
+ * concatenate neighbor commit groups belonging to the same commit
  *
  * @globals colorRe
  */
@@ -420,8 +419,6 @@ function handleLine(commit, group) {
 
 // ----------------------------------------------------------------------
 
-var inProgress = false;   // are we processing response
-
 /**#@+
  * @constant
  */
@@ -433,8 +430,6 @@ var endRe  = /^END ?([^ ]*) ?(.*)/;
 var curCommit = new Commit();
 var curGroup  = {};
 
-var pollTimer = null;
-
 /**
  * Parse output from 'git blame --incremental [...]', received via
  * XMLHttpRequest from server (blamedataUrl), and call handleLine
@@ -535,43 +530,51 @@ function processData(unprocessed, nextReadPos) {
  * Handle XMLHttpRequest errors
  *
  * @param {XMLHttpRequest} xhr: XMLHttpRequest object
+ * @param {Number} [xhr.pollTimer] ID of the timeout to clear
  *
- * @globals pollTimer, commits, inProgress
+ * @globals commits
  */
 function handleError(xhr) {
        errorInfo('Server error: ' +
                xhr.status + ' - ' + (xhr.statusText || 'Error contacting server'));
 
-       clearInterval(pollTimer);
+       if (typeof xhr.pollTimer === "number") {
+               clearTimeout(xhr.pollTimer);
+               delete xhr.pollTimer;
+       }
        commits = {}; // free memory
-
-       inProgress = false;
 }
 
 /**
  * Called after XMLHttpRequest finishes (loads)
  *
- * @param {XMLHttpRequest} xhr: XMLHttpRequest object (unused)
+ * @param {XMLHttpRequest} xhr: XMLHttpRequest object
+ * @param {Number} [xhr.pollTimer] ID of the timeout to clear
  *
- * @globals pollTimer, commits, inProgress
+ * @globals commits
  */
 function responseLoaded(xhr) {
-       clearInterval(pollTimer);
+       if (typeof xhr.pollTimer === "number") {
+               clearTimeout(xhr.pollTimer);
+               delete xhr.pollTimer;
+       }
 
        fixColorsAndGroups();
        writeTimeInterval();
        commits = {}; // free memory
-
-       inProgress = false;
 }
 
 /**
  * handler for XMLHttpRequest onreadystatechange event
  * @see startBlame
  *
- * @globals xhr, inProgress
+ * @param {XMLHttpRequest} xhr: XMLHttpRequest object
+ * @param {Number} xhr.prevDataLength: previous value of xhr.responseText.length
+ * @param {Number} xhr.nextReadPos: start of unread part of xhr.responseText
+ * @param {Number} [xhr.pollTimer] ID of the timeout (to reset or cancel)
+ * @param {Boolean} fromTimer: if handler was called from timer
  */
-function handleResponse() {
+function handleResponse(xhr, fromTimer) {
 
        /*
         * xhr.readyState
@@ -609,32 +612,31 @@ function handleResponse() {
                return;
        }
 
-       // in case we were called before finished processing
-       if (inProgress) {
-               return;
-       } else {
-               inProgress = true;
-       }
 
        // extract new whole (complete) lines, and process them
-       while (xhr.prevDataLength !== xhr.responseText.length) {
-               if (xhr.readyState === 4 &&
-                   xhr.prevDataLength === xhr.responseText.length) {
-                       break;
-               }
-
+       if (xhr.prevDataLength !== xhr.responseText.length) {
                xhr.prevDataLength = xhr.responseText.length;
                var unprocessed = xhr.responseText.substring(xhr.nextReadPos);
                xhr.nextReadPos = processData(unprocessed, xhr.nextReadPos);
-       } // end while
+       }
 
        // did we finish work?
-       if (xhr.readyState === 4 &&
-           xhr.prevDataLength === xhr.responseText.length) {
+       if (xhr.readyState === 4) {
                responseLoaded(xhr);
+               return;
        }
 
-       inProgress = false;
+       // if we get from timer, we have to restart it
+       // otherwise onreadystatechange gives us partial response, timer not needed
+       if (fromTimer) {
+               setTimeout(function () {
+                       handleResponse(xhr, true);
+               }, 1000);
+
+       } else if (typeof xhr.pollTimer === "number") {
+               clearTimeout(xhr.pollTimer);
+               delete xhr.pollTimer;
+       }
 }
 
 // ============================================================
@@ -649,11 +651,11 @@ function handleResponse() {
  * Called from 'blame_incremental' view after loading table with
  * file contents, a base for blame view.
  *
- * @globals xhr, t0, projectUrl, div_progress_bar, totalLines, pollTimer
+ * @globals t0, projectUrl, div_progress_bar, totalLines
 */
 function startBlame(blamedataUrl, bUrl) {
 
-       xhr = createRequestObject();
+       var xhr = createRequestObject();
        if (!xhr) {
                errorInfo('ERROR: XMLHttpRequest not supported');
                return;
@@ -672,8 +674,9 @@ function startBlame(blamedataUrl, bUrl) {
        xhr.prevDataLength = -1;  // used to detect if we have new data
        xhr.nextReadPos = 0;      // where unread part of response starts
 
-       xhr.onreadystatechange = handleResponse;
-       //xhr.onreadystatechange = function () { handleResponse(xhr); };
+       xhr.onreadystatechange = function () {
+               handleResponse(xhr, false);
+       };
 
        xhr.open('GET', blamedataUrl);
        xhr.setRequestHeader('Accept', 'text/plain');
@@ -681,7 +684,9 @@ function startBlame(blamedataUrl, bUrl) {
 
        // not all browsers call onreadystatechange event on each server flush
        // poll response using timer every second to handle this issue
-       pollTimer = setInterval(xhr.onreadystatechange, 1000);
+       xhr.pollTimer = setTimeout(function () {
+               handleResponse(xhr, true);
+       }, 1000);
 }
 
 /* end of blame_incremental.js */