/*
  WHAT:       SIMPLE AJAX FRAMEWORK
  AUTHOR:     ERIC NORDENG
  DATE:       06-29-2006  (1.0)
  VERSION:    2.1
  FILE NAME:  AJAX_2_1.js
  
  UPDATES:  07-20-2006  (2.0)
            Redesign framework to support multiple threads.
            This framework will not support version 1.0 (AJAX.js)
            
            08-10-2006  (2.1)
            Bug Fix: Move the send call in the 'sendXMLHttpRequest' function after the onreadystatechange assignment.

  
  DOCUMENTATION:
  
  => This framework allows multi-threaded AJAX calls and does not rely on global variables
  
  => The general order of tasks for using the framework are as follows:
  
     · Create the document object(s)
     · Build the document object with XML
     · Create the request object(s)
     · Send request(s) to the server
     · Use a callback function to process the data that is returned from the server
  
  
  => There are two things that need to be explained:
  
     · The sendXMLHttpRequest function takes 8 parameters:
  
       1 - The request object [object]
       2 - The URL of the server page to be called [string]
       3 - The document object [object]
       4 - The id of the div area to display server-side errors [string]
       5 - The id of the div area to display a message while the server page is running [string]
       6 - The message to be displayed while the server page is running [string]
       7 - The name of the callback function to run after the server page is done running [string]
       8 - Flag to assign whether or not the request should be asyncronous [true/false]
       
     · The request object is automatically sent to the callback function
     
     
  => Below is an example of how your code may look if your running 3 independent requests to the server:
   
     function buttonClicked()
     {
       // CREATE DOCUMENT OBJECTS FOR XML
       var objXMLDoc1 = createDocumentObject('','');
       var objXMLDoc2 = createDocumentObject('','');
       var objXMLDoc3 = createDocumentObject('','');
 
 
       // BUILD XML FOR SERVER PAGE TO PARSE
       addNode(objXMLDoc1,'nodeName','nodeValue');
       addNode(objXMLDoc1,'nodeName','nodeValue');
       
       addNode(objXMLDoc2,'nodeName','nodeValue');
       addNode(objXMLDoc2,'nodeName','nodeValue');
       
       addNode(objXMLDoc3,'nodeName','nodeValue');
       addNode(objXMLDoc3,'nodeName','nodeValue');
 
 
       // CREATE THE REQUEST OBJECTS
       var objReq1 = createRequestObject();
       var objReq2 = createRequestObject();
       var objReq3 = createRequestObject();
       
       
       // SEND REQUEST TO SERVER
       sendXMLHttpRequest(objReq1,"ajaxTest1.asp",objXMLDoc1,'div_errors1','div_message1','please wait for request 1...','allDone1',true);
       sendXMLHttpRequest(objReq2,"ajaxTest2.asp",objXMLDoc2,'div_errors2','div_message2','please wait for request 2...','allDone2',true);
       sendXMLHttpRequest(objReq3,"ajaxTest3.asp",objXMLDoc3,'div_errors3','div_message3','please wait for request 3...','allDone3',true);
     }
     
     function allDone1(objReq)
     {
       // DISPLAY XHTML THAT WAS RETURNED FROM THE SERVER
       changeInnerHTML("divID1",objReq.responseText);
       
       -- OR --
       
       // CREATE OBJECT TO HOLD XML DATA THAT WAS RETURNED FROM THE SERVER (AND PARSE IT)
       var objDOMParser = createParserObject(objReq.responseText);
       var nodeValue = getNodeVal(objDOMParser,"nodeName");
     }
     
     function allDone2(objReq)
     {
       // DISPLAY XHTML THAT WAS RETURNED FROM THE SERVER
       changeInnerHTML("divID2",objReq.responseText);
       
       -- OR --
       
       // CREATE OBJECT TO HOLD XML DATA THAT WAS RETURNED FROM THE SERVER (AND PARSE IT)
       var objDOMParser = createParserObject(objReq.responseText);
       var nodeValue = getNodeVal(objDOMParser,"nodeName");
     } 
     
     function allDone3(objReq)
     {
       // DISPLAY XHTML THAT WAS RETURNED FROM THE SERVER
       changeInnerHTML("divID3",objReq.responseText);
       
       -- OR --
       
       // CREATE OBJECT TO HOLD XML DATA THAT WAS RETURNED FROM THE SERVER (AND PARSE IT)
       var objDOMParser = createParserObject(objReq.responseText);
       var nodeValue = getNodeVal(objDOMParser,"nodeName");
     }
*/

/* ------------------------------------------------------------------------------------- */

function createRequestObject()
{
  objReq = null;
  if (window.ActiveXObject)
  {
    objReq = new ActiveXObject("Microsoft.XMLHTTP");
  }
  else if (window.XMLHttpRequest)
  {
    objReq  = new XMLHttpRequest();
  }
  return objReq;
}

/* ------------------------------------------------------------------------------------- */

function sendXMLHttpRequest(objReq,url,objXMLDoc,divAreaErrors,divAreaMessageID,message,callBackFunc,async)
{
  objReq.open("post", url, async);
  objReq.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded;');
  objReq.onreadystatechange = function() 
                              { 
                                if (objReq.readyState == 4)  // REQUEST IS FINISHED
                                {
                                  if (objReq.status == 200)  // REQUEST WAS SUCCESSFUL
                                  {
                                    if (callBackFunc.length > 0)
                                    {
                                      callBackFunc = eval(callBackFunc);
                                      callBackFunc(objReq);
                                    }
                                    if (divAreaMessageID.length > 0 && message.length > 0)    
                                    {
                                      changeInnerHTML(divAreaMessageID,"&nbsp;");
                                    }
                                  }
                                  else if (divAreaErrors.length > 0)  // REQUEST FAILED
                                  {
                                    changeInnerHTML(divAreaErrors,objReq.responseText);
                                  }
                                }
                                else if (divAreaMessageID.length > 0 && message.length > 0)  // REQUEST IS RUNNING
                                {
                                  changeInnerHTML(divAreaMessageID,message);
                                }
                              }
  objReq.send(objXMLDoc);
}

/* ------------------------------------------------------------------------------------- */

function createParserObject(strXML)
{  
  var browser = navigator.appName;
  
  if (browser == "Microsoft Internet Explorer")
  {
    var xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
    xmlDoc.loadXML(strXML);
  } 
  else
  {
    var objDOMParser = new DOMParser();
    var xmlDoc = objDOMParser.parseFromString(strXML,"text/xml");
  }
  return xmlDoc;
}

/* ------------------------------------------------------------------------------------- */

function createDocumentObject(nameSpace,rootName)
{
  var xmlDoc;
  var browser = navigator.appName;
  
  if (rootName.length == 0)
  {
    rootName = "XMLroot";
  }
  
  if (browser == "Microsoft Internet Explorer")
  {
    xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
    xmlDoc.loadXML("<" + rootName + "/>");
  } 
  else
  {  
    xmlDoc = document.implementation.createDocument(nameSpace,rootName,null);
    if (xmlDoc.documentElement == null)
    {
      xmlDoc.appendChild(xmlDoc.createElement(rootName));
    }
    if (navigator.userAgent.indexOf("Safari") == -1)
    {
      // STANDARDIZE the loadXML FUNCTION AND THE xml PROPERTY
      Document.prototype.loadXML = function(strXML)
      {
        var objDOMParser = new DOMParser();
        var objDoc = objDOMParser.parseFromString(strXML,"text/xml");
      }
  
      Document.prototype.__defineGetter__("xml", function () 
      {
         return (new XMLSerializer()).serializeToString(this);
      });
    }
  }
  return xmlDoc;
}

/* ------------------------------------------------------------------------------------- */

function addNode(XMLDoc,name,val)
{
  if (val == '&')
  {
    val = replace(val,'&','&amp;');
  }
  if (val == '"')
  {
    val = replace(val,'"','&quot;');
  }
  if (val == '<')
  {
    val = replace(val,'<','&lt;');
  }
  if (val == '>')
  {
    val = replace(val,'>','&gt;');
  }
  var root = XMLDoc.documentElement;
  var newNode = XMLDoc.createElement(name);
  var newTextNode = XMLDoc.createTextNode(val);
  newNode.appendChild(newTextNode);
  root.appendChild(newNode);
}

/* ------------------------------------------------------------------------------------- */

function getNodeVal(objParser,nodeName)
{
  if (objParser.getElementsByTagName(nodeName)[0].firstChild)
  {
    return objParser.getElementsByTagName(nodeName)[0].firstChild.nodeValue;
  }
  else
  {
    return "";
  }
}

/* ------------------------------------------------------------------------------------- */

function changeInnerHTML(divId,html)
{
  if (document.getElementById)
  {
    document.getElementById(divId).innerHTML= html;
  }
  else
  {
    document.layers[divId].document.open();
    document.layers[divId].document.write(html);
    document.layers[divId].document.close();
  }
}

/* ------------------------------------------------------------------------------------- */