﻿/*dependencies
    <dependencies />
dependencies*/

/*-------------------------------------------------------------------------------
 COPYRIGHT!!
 CODE WRITTEN BY ANDREW GULBRONSON
 IF YOU HAPPEN TO HAVE BEEN DIGGING THROUGH ANY OF MY CODE AND COME ACROSS THIS
 JS FILE AND DECIDE YOU WANT TO USE IT GO AHEAD, BUT YOU MUST KEEP THIS
 NOTICE IN THE CODE.
-----------------------------------------------------------------------------*/
var Document_Implementation = (document.implementation ? true : false);
var Create_Document = (document.implementation.createDocument ? true : false);
var Has_Feature = (document.implementation.hasFeature ? true : false);
var Has_ActiveX = (window.ActiveXObject ? true : false);
var Xml_Http_Request = (window.XMLHttpRequest ? true : false);
var Has_DomParser = (window.DOMParser ? true : false);
var Has_XmlSerializer = (window.XMLSerializer ? true : false);
var Has_LSSerializer = (window.createLSSerializer ? true : false);
var Has_PrintNode = (window.printNode ? true : false);

/*
ASYNC:                                      true for asynchronous ajax requests, false for non
serverurl:                                  the path to the ajax server.
errorelement (optional but recommended):    this is the element that will display errors when in debug mode
debugMode:                                  bool - true to enter debug mode
freezeelement (optional):                   this is the element to display while the main 'page' is hidden during async requests
pageelement (optional):                     the page element mentioned above that is hidden during async requests



example implementation of async:} 

    var ajax = new Ajax(true, "aspx/server.aspx", el("errorSpan"), false, Master.FreezeElement, Master.PageElement)
    var xmlDoc = ajax.GetDoc("<root><result /><zip code=\"0\" city=\"\" state=\"\" /></root>");
    
    xmlDoc.selectSingleNode("//zip").setAttribute("code", obj.value);
    
    ajax.onRequestComplete = function() {
    
        xmlDoc = ajax.XmlDoc();
        do whatever with xml.
    
    }
    
    ajax.startRequest(xmlDoc);
    
    
    
example implementation of non-async:}

    var ajax = new Ajax(false, "aspx/server.aspx", el("errorSpan"), false, Master.FreezeElement, Master.PageElement)
    var xmlDoc = ajax.GetDoc("<root><result /><zip code=\"0\" city=\"\" state=\"\" /></root>");
    
    xmlDoc.selectSingleNode("//zip").setAttribute("code", obj.value);
    xmlDoc = ajax.startRequest(xmlDoc);
    
*/

function Ajax(ASYNC, serverurl, errorelement, debugMode, freezeelement, pageelement)
{
    /* Private members*/
    var xmlHttp;                    /* xml http object*/
    var async = true;               /* determines whether request is async or not*/
    var xml = "";                   /* the xml data sent*/
    var self = this;                /* object reference to itself.*/
    var serverUrl = "";             /* page to ajax web server*/
    var error = "";                 /* error the page has encountered*/
    var method = "POST";            /* method xmlHttp will use*/
    var ErrorsEncountered = false;  /* tells if errors encountered*/
    var debug = false;              /* holds status of if object is in debug mode or not.*/
    var errorElement;               /* element to display response text in: for debugging.*/
    
    var freezeElement;              /* element to display when the page 'freezes'*/
    var pageElement;                /* element that contains all controls on the page*/
    
    var scrollLeft = 0;
    var scrollTop = 0;
    
    var arBadChars = new Array(  /*"#",*/           "&",     "<",     ">",    "\"",     "'");
    var arGoodChars = new Array(/*"&#00035;",*/ "&amp;", "&lt;", "&gt;", "&quot;",  "&apos;");
    
    this.Escape = function (s) { 
        
        //s = s.replace(/#/g, arGoodChars[0]);
        s = s.replace(/&/g, arGoodChars[0]);
        for(var i = 1; i < arBadChars.length; i++) { 
        
            var g = arGoodChars[i];
            var b = arBadChars[i];
            while(s.indexOf(b) > -1) { s = s.replace(b, g); }
            //var reg = new RegExp(arBadChars[i], "g");
            //s.replace(reg, arGoodChars[i]);
        } 
        
        return s; 
        
    }
    this.UnEscape = function (s) { 
    
        for(var i = 0; i < arBadChars.length; i++) { 
    
            var g = arGoodChars[i];
            var b = arBadChars[i];
            while(s.indexOf(g) > -1) { s = s.replace(g, b); }
            //var reg = new RegExp(arGoodChars[i], "g");
            //s.replace(reg, arBadChars[i]);
            
        }
        
        return s; 
        
    }
    
    /*--------------------- PROPERTIES*/
    
    
    /* Gets/Sets the debug status*/
    this.Debug = function (bool) { if(bool == null) { return debug; } else { debug = bool; } }
    
    /* Gets/Sets the element errors are displayed in during debug mode.*/
    this.ErrorElement = function (element) { if(element == null) { return errorElement; } else { errorElement = element; } }
    
    /* Gets/Sets the element to show when the page 'freezes'*/
    this.FreezeElement = function (element) { if(element == null) { return freezeElement; } else { freezeElement = element; } }
    
    /* Gets/Sets the element that contains all controls on the page*/
    this.PageElement = function (element) { if(element == null) { return pageElement; } else { pageElement = element; } }
        
    /* returns the error*/
    this.HasErrors = function () {return ErrorsEncountered; }
    
    /* returns the error*/
    this.Error = function () {return error; }
    
    /*Gets/Sets the method to be invoked.*/
    this.Method = function (value) { if(value == null) { return method; } else { method = value.toUpperCase(); } }
    
    /*Gets a value that indicates whether or not the call is asynchronous.*/
    this.Async = function (value) { if(value == null) { return async; } else { async = value; } }
    
    /* Gets/ Sets*/
    this.XmlDoc = function (value) { if(value == null) { return xml; } else { xml = value; } }
    
    /* sets the url to the ajax server*/
    this.ServerUrl = function (value) { if(value == null) { return serverUrl; } else { serverUrl = value; } }
    
    this.Async(ASYNC);
    this.ServerUrl(serverurl);
    this.ErrorElement(errorelement);
    this.Debug(debugMode);
    this.FreezeElement(freezeelement);
    this.PageElement(pageelement);
    
    
    /*------------------------------ Events*/
    this.onRequestComplete = function () {};    /* place holder. each instance can create this function on it's own.*/
    
    /* Starts the request to server.*/
    this.startRequest = function(xmlDoc){
    
        if(xmlDoc != null) { xml = xmlDoc; }
        ErrorsEncountered = false; 
            
        xmlHttp = self.XmlHttp();

        if(!xmlHttp) { return; }
        
        xmlHttp.onreadystatechange = function () { handleServerResponse(); }

        xmlHttp.open(method, serverUrl , async);
        xmlHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
        xmlHttp.setRequestHeader("Content-Type", "text/xml");
        
        try {
            xmlHttp.send(xml);
        }catch(x) {alert(x.message + "err");}
        if(!async) { handleServerResponse(); return xml; }
	   	
	}
		
	/* Freezes/Unfreezes the page during ajax requests*/
	this.FreezePage = function(bool) {
	
	    if(bool) {
	    
	        scrollLeft = parseInt(document.body.scrollLeft);
	        scrollTop = parseInt(document.body.scrollTop);
	        if(!async) { return; }
	        document.body.style.cursor = "wait";
	        freezeElement.style.display = "block";
	        pageElement.style.display = "none";
	    
	    } else {
	    
	        freezeElement.style.display = "none";
	        pageElement.style.display = "block";
	        document.body.style.cursor = "default";
	        document.body.scrollTop = scrollTop;
	        document.body.scrollLeft = scrollLeft;
	    
	    }
	
	}
	
	/* Handles server's response*/
    function handleServerResponse(){
        /* list of readyState codes 
            0 -- unitialized
            1 -- loading
            2 -- loaded
            3 -- interactive
            4 -- complete
        */

        if(xmlHttp.readyState == 4){
        
            /* status 200 -- ok response
               404 -- not found
               500 -- internal server error
               || xmlHttp.status == 500*/
                        
            if(xmlHttp.status == 200){
            
                xml = self.GetDoc(xmlHttp.responseText, false);
            } else {
            
                ErrorsEncountered = true;
                error = "xmlHttp status: " + xmlHttp.status;
                if(debug) { errorElement.innerHTML = "ERROR: " + xmlHttp.responseText; }
            
            }
            self.onRequestComplete();
        }
        
    }
    
    if(Has_ActiveX) {

        self.GetDoc = function (sXml, bIsFile) {
        
            var xTempDoc = new ActiveXObject("Microsoft.XMLDOM");
            if(xTempDoc == null) { xTempDoc = new ActiveXObject("msxml2.domdocument"); }
            
            if(sXml != null) {
            
                if(!bIsFile) { xTempDoc.loadXML(sXml.replace(/&/g, "&#00038;")); }
                else { xTempDoc.async = false; xTempDoc.load(sXml); }
            
            }
            return xTempDoc;
        }
        
        self.XmlHttp = function() {
        
            var xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
            if (xmlHttp ==  null) { xmlHttp = new ActiveXObject ("Msxml2.XMLHTTP"); }
            return xmlHttp;
        }
    } else if (Has_DomParser) {
        
	    XMLDocument.prototype.readyState = 0;
        /* give firefox loadXML method like IE for xmlDocs*/
        XMLDocument.prototype.loadXML = function (sXml) {
		    SetReadyState(this, 1);
		    var sOldXML = this.xml;
		    var xDoc = (new DOMParser()).parseFromString(sXml, "text/xml");
		    SetReadyState(this, 2);
		    SetReadyState(this, 3);
		    OnDocLoad(this);
		    return sOldXML;
	    }
    	    	
	    /* give firefox IE's .xml property to return the serialized xDoc.*/
	    XMLDocument.prototype.__defineGetter__(
	        "xml", 
	        function () {
		        return (new XMLSerializer()).serializeToString(this);
	        }
	    );
    	
	    /* give firefox IE's .selectNodes method*/
	    XMLDocument.prototype.selectNodes = function (sExpr, contextNode)
	    {
		    /*var nsDoc = this;*/
		    var nsResolver = this.createNSResolver(this.documentElement);
    		
            var items = this.evaluate(sExpr, (contextNode ? contextNode : this), nsResolver, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
            var nodes = new Array(items.snapshotLength);

            for(var i = 0; i < nodes.length; i++) { nodes[i] = items.snapshotItem(i); }
            return nodes;
	    };
    	
	    /* give firefox IE's .selectSingleNode method*/
	    XMLDocument.prototype.selectSingleNode = function(sExpr, contextNode)
	    {
	        var node = (contextNode ? contextNode : null);
		    var nodes = this.selectNodes(sExpr + "[1]", node);
		    return (nodes.length > 0 ? nodes[0] : null);
	    }
    	
	    /* give firefox IE's .xml property to return the serialized node.*/
	    Node.prototype.__defineGetter__(
	        "xml", 
	        function () {
		        return (new XMLSerializer()).serializeToString(this);
	        }
	    );
	    
	    /* give firefox IE's .text property to return the nodes value*/
	    Node.prototype.__defineGetter__(
	        "text", 
	        function () {
		        return this.nodeValue;
	        }
	    );
	    
	    Node.prototype.__defineSetter__("text", 
	        function (sText)
	        {
		        var s = sText;
		        this.innerHTML = s;
	        }
	    );

        function SetReadyState(xDoc, iReadyState) 
	    {
		    xDoc.readyState = iReadyState;
		    if (xDoc.onreadystatechange != null && typeof(xDoc.onreadystatechange) == "function") { xDoc.onreadystatechange(); }
	    }
    	
	    function OnDocLoad(xDoc)
	    {
		    SetReadyState(xDoc, 4);
	    }

	    self.GetDoc = function (sXml, bIsFile)
	    {
		    var xTempDoc = document.implementation.createDocument("", "", null);
		    xTempDoc.addEventListener("load", OnloadWrapper, false);
    		
		    if(sXml != null) { 
    		
		        if(!bIsFile) { xTempDoc = (new DOMParser()).parseFromString(sXml, "text/xml"); }
		        else { xTempDoc.load(sXml); }   
		    }
    		
    		
		    return xTempDoc;
	    }
    	
    	
	    self.XmlHttp = function ()
	    {
		    return new XMLHttpRequest();
	    }

        /* contains the method to be called onload*/
	    function OnloadWrapper()
	    {
		    OnDocLoad(this);
	    }
    }
    
}



