fad6336881fbfae98fe0bda10ed9955fd7a85fe9
tdreszer
  Tue Sep 7 14:18:05 2010 -0700
Tangled code that allows form submits to wait for outstanding ajax completion.
diff --git src/hg/js/ajax.js src/hg/js/ajax.js
index f40c3e9..561c955 100644
--- src/hg/js/ajax.js
+++ src/hg/js/ajax.js
@@ -6,10 +6,107 @@
 
 function nullProcessReqChange()
 {
-    if(debug)
+    if(debug && this.readyState == 4)
             alert("req.responseText: " + req.responseText);
 }
 
+// When setting vars with ajax, it may be necessary to wait for response before newer calls
+// Therefore this counter is set up to allow an "outside callback" when the ajax is done
+// The typical scenario is setCartVar by ajax, followed immmediately by a form submit.
+// To avoid the race condition, the form gets submitted after the ajax returns
+var ajaxWaitCount = 0;
+function ajaxWaitIsDone()     { return ( ajaxWaitCount <= 0 ); }
+function ajaxWaitCountUp()    { ajaxWaitCount++; }
+function ajaxWaitCountReset() { ajaxWaitCount = 0; }
+//function ajaxWaitCountShow()  { warn("ajaxWait calls outstanding:"+ajaxWaitCount); }
+
+// Here is where the "outside callback" gets set up and called
+var ajaxWaitCallbackFunction = null;
+var ajaxWaitCallbackTimeOut = null;
+function ajaxWaitCallbackRegister(func)
+{ // register a function to be called when the ajax waiting is done.
+    if(ajaxWaitIsDone())
+        func();
+    else {
+        ajaxWaitCallbackFunction = func;
+        ajaxWaitCallbackTimeOut = setTimeout("ajaxWaitCallback();",5000);  // just in case
+    }
+}
+
+function ajaxWaitCallback()
+{ // Perform the actual function (which could have been because of a callback or a timeout)
+    // Clear the timeout if this is not due to ajaxWaitDone
+    //warn("ajaxWaitCallback: "+ajaxWaitIsDone());
+    if(ajaxWaitCallbackTimeOut != null) {
+        clearTimeout(ajaxWaitCallbackTimeOut);
+        ajaxWaitCallbackTimeOut = null;
+    }
+    // Clear the wait stack incase something failed and we are called by a timeout
+    ajaxWaitCountReset();
+
+    // Finally do the function
+    if(ajaxWaitCallbackFunction
+    && jQuery.isFunction(ajaxWaitCallbackFunction)) {
+        ajaxWaitCallbackFunction();
+    }
+    ajaxWaitCallbackFunction = null;
+}
+
+function ajaxWaitCountDown()
+{ // called whenever an ajax request is done
+    if((req && req.readyState == 4)
+    || (this.readyState == 4))
+    { // It is only state 4 that means done
+        ajaxWaitCount--;
+        if(ajaxWaitIsDone())
+            ajaxWaitCallback();
+    }
+    //warn(req.readyState + " waiters:"+ajaxWaitCount);
+}
+
+var formToSubmit = null; // multistate: null, {form}, "COMPLETE", "ONCEONLY"
+var formSubmitPhase = 0;
+function formSubmit()
+{ // This will be called as a callback on timeout or ajaxWaitCallback
+
+    if(formToSubmit != null) {
+        //warn("submitting form:"+$(formToSubmit).attr('name') + ": "+ajaxWaitIsDone());
+        var form = formToSubmit;
+        formToSubmit = "GO"; // Flag to wait no longer
+        $(form).submit();
+    }
+    waitMaskClear(); // clear any outstanding waitMask.  overkill if the form has just been submitted
+}
+function formSubmitRegister(form)
+{ // Registers the form submit to be done by ajaxWaitCallback or timeout
+    if(formToSubmit != null) // Repeated submission got through, so ignore it
+        return false;
+    waitMaskSetup(5000);     // Will prevent repeated submissions, I hope.
+    formToSubmit = form;
+    //warn("Registering form to submit:"+$(form).attr('name'));
+    ajaxWaitCallbackRegister(formSubmit);
+    return false; // Don't submit until ajax is done.
+}
+
+function formSubmitWaiter(e)
+{ // Here we will wait for up to 5 seconds before continuing.
+    if(formToSubmit == null)
+        return formSubmitRegister(e.target); // register on first time through
+
+    if(formToSubmit == "GO") {  // Called again as complete
+        //warn("formSubmitWaiter(): GO");
+        formToSubmit = "STOP";  // Do this only once!
+        return true;
+    }
+    return false;
+}
+
+function formSubmitWaitOnAjax(form)
+{ // Most typically, we block a form submit until all ajax has returned
+    $(form).unbind('submit', formSubmitWaiter ); // prevents multiple bind requests
+    $(form).bind(  'submit', formSubmitWaiter );
+}
+
 function loadXMLDoc(url)
 {
 // Load XML without a request handler; this is useful if you are sending one-way messages.
@@ -19,6 +116,7 @@
 function loadXMLDoc(url, callBack)
 {
 // From http://developer.apple.com/internet/webcontent/xmlhttpreq.html
+    //warn("AJAX started: "+url);
     if(callBack == null)
         callBack = nullProcessReqChange;
     req = false;
@@ -46,7 +144,8 @@
     if(req) {
         req.onreadystatechange = callBack;
         req.open("GET", url, true);
-        req.send("");
+        req.send();
+        //req.send("");
     }
 }
 
@@ -79,7 +178,8 @@
         if(pairs.length == 0)
             return;
         //warn(pairs);
-        loadXMLDoc(loc + pairs);
+        ajaxWaitCountUp();
+        loadXMLDoc(loc + pairs,ajaxWaitCountDown);
     }
 }