Search This Blog

A Complete Javascript AJAX library

simple = {
    version : 0.1
}
simple.http = {
    lastModified : {},
    createRequest : function() {
        if (typeof XMLHttpRequest !== 'undefined') {
            try {
                return new XMLHttpRequest();
            } catch (e) {
            }
        }
        if (typeof ActiveXObject !== 'undefined') {
            var msxml = ['MSXML2.XMLHTTP.6.0', 'MSXML2.XMLHTTP.3.0',
                    'MSXML2.XMLHTTP', 'Microsoft.XMLHTTP'];
            for (var i = 0, len = msxml.length; i < len; ++i) {
                try {
                    return new ActiveXObject(msxml[i]);
                } catch (e) {
                }
            }
        }
        throw new Error('This browser does not support XMLHttpRequest.');
    },
    sendRequest : function(o) {
        o = o || {};
        o = {
            method : typeof o.method == 'string'
                    ? o.method.toUpperCase()
                    : 'GET',
            url : o.url || location.href,
            async : o.async || true,
            data : o.data || null,
            user : o.user || null,
            cached : o.cached || true,
            password : o.password || null,
            contentType : o.contentType || 'application/x-www-form-urlencoded',
            ifModified : o.ifModified || null,
            timeout : o.timeout || null,
            onSuccess : o.onSuccess || function() {
            },
            onFailure : o.onFailure || function() {
            },
            onTimeout : o.onTimeout || function() {
            },
            onProgress : o.onProgress || function() {
            },
            scope : o.scope || null
        }
        var request = simple.http.createRequest();
        var progress = 0;
        var timeoutId;
        if (o.timeout) {
            timeoutId = setTimeout(function() {
                        request.abort();
                        onTimeout();
                    }, o.timeout);
        }
        request.onreadystatechange = function() {
            if (request.readyState === 4) {
                if (timeoutId) {
                    clearTimeout(timeoutId);
                }
                if ((request.status >= 200 && request.status < 300)
                        || request.status === 1223
                        || request.status === 304
                        || (!request.status && location.protocol == 'file:')
                        || (navigator.userAgent.indexOf('Safari') >= 0 && typeof request.status == 'undefined')) {
                    //
                    // Success
                    //
                    if (o.ifModified) {
                        simple.http.lastModified(o.url) = request
                                .getResponseHeader("Last-Modified");
                    }
                    var responseData;
                    if (o.method == 'HEAD') {
                        responseData = request.getAllResponseHeaders();
                    } else {
                        if (request.getResponseHeader('Content-Type')
                                .indexOf('xml') != -1) {
                            responseData = request.responseXML;
                        } else {
                            responseData = request.responseText;
                        }
                    }
                    if (o.scope) {
                        o.onSuccess.apply(o.scope, responseData);
                    } else {
                        o.onSuccess(responseData);
                    }
                } else {
                    o.onFailure(request.status, request.statusText);
                }
            } else {
                o.onProgress(progress);
            }
        }
        if (o.method == 'GET') {
            if (o.data) {
                o.url = o.url + ((o.url.indexOf('?') == -1) ? '?' : '&')
                        + o.data;
                o.data = null;
            }
            if (!o.cached) {
                o.url = appendTimeStamp(o.url);
            }
        }
        if (o.user && o.password) {
            request.open(o.method, o.url, o.async, o.user, o.password);
        } else {
            request.open(o.method, o.url, o.async);
        }
        request.setRequestHeader('Content-Type', o.contentType);
        request.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
        if (o.ifModified) {
            request.setRequestHeader("If-Modified-Since",
                    simple.http.lastModified[o.url] || new Date(0));
        }
        request.send(o.data);
        if (!o.async) {
            request.onreadystatechange();
        }
        //
        // inner functions
        //
        function appendTimeStamp(url) {
            var ts = +new Date();
            // try replacing _= if it is there
            var ret = url.replace(/(\?|&)_=.*?(&|$)/, "$1_=" + ts + "$2");
            // if nothing was replaced, add timestamp to the end
            return ret
                    + ((ret == url)
                            ? (url.match(/\?/) ? "&" : "?") + "_=" + ts
                            : "");
        }
    },
    get : function(o) {
        o.method = 'GET';
        simple.http.sendRequest(o);
    },
    getAsync : function(o) {
        o.async = true;
        simple.http.get(o);
    },
    getSync : function(o) {
        o.async = false;
        simple.http.get(o);
    },
    post : function(o) {
        o.method = 'POST';
        simple.http.sendRequest(o);
    },
    postAsync : function(o) {
        o.async = true;
        simple.http.post(o);
    },
    postSync : function(o) {
        o.async = false;
        simple.http.post(o);
    },
    head : function(o) {
        o.method = 'HEAD';
        simple.http.sendRequest(o);
    }
};
simple.xml = {
    createDocument : function(rootTagName, namespaceURI) {
        rootTagName = rootTagName || '';
        namespaceURI = namespaceURI || '';
        if (document.implementation && document.implementation.createDocument) {
            // W3C way
            document.implementation.createDocument(namespaceURI, rootTagName,
                    null);
        } else {
            // IE way
            var doc = new ActiveXObject('MSXML2.DOMDocument');
            if (rootTagName) {
                var prefix = '';
                var tagname = rootTagName;
                var p = rootTagName.indexOf(':');
                if (p != -1) {
                    prefix = rootTagName.substring(0, p);
                    tagname = rootTagName.substring(p + 1);
                }
                if (namespaceURI) {
                    if (!prefix) {
                        prefix = 'a0';
                    }
                } else {
                    prefix = '';
                }
                var text = '<'
                        + (prefix ? (prefix + ':') : '')
                        + tagname
                        + (namespaceURI ? (' xmlns:' + prefix + '="'
                                + namespaceURI + '"') : '') + '/>';
                doc.loadXML(text);
            }
            return doc;
        }
    },
    loadSync : function(url) {
        var xmldoc = simple.xml.createDocument();
        xmldoc.async = false;
        xmldoc.load(url);
        return xmldoc;
    },
    loadAsync : function(url, callback) {
        var xmldoc = simple.xml.createDocument();
        if (document.implementation && document.implementation.createDocument) {
            // FF
            xmldoc.onload = function() {
                callback(xmldoc);
            };
        } else {
            // IE
            xmldoc.onreadystatechange = function() {
                if (xmldco.readyState == 4) {
                    callback(xmldoc);
                }
            }
        }
        xmldoc.load(url);
    },
    parse : function(text) {
        if (typeof DOMParser != 'undefined') {
            // Mozilla, Firefox and related browsers
            return (new DOMParser()).parseFromString(text, 'application/xml');
        } else if (typeof ActiveXObject != 'undefined') {
            // Internet Explorer
            var doc = simple.xml.createDocument();
            doc.loadXML(text);
            return doc;
        } else {
            var url = 'data:text/xml;charset=utf-8,' + encodeURIComponent(text);
            var request = new XMLHttpRequest();
            request.open('GET', url, false);
            request.send(null);
            return request.responseXML;
        }
    },
    serialize : function(node) {
        if (typeof XMLSerializer != "undefined") {
            return (new XMLSerializer()).serializeToString(node);
        } else if (node.xml) {
            return node.xml;
        } else {
            throw new Error("XML.serialize is not supported or can't serialize "
                    + node);
        }
    },
    getNodes : function(context, xpathExpr, namespaces) {
        return (new simple.xml.XPathExpression(xpathExpr, namespaces))
                .getNodes(context);
    },
    getNode : function(context, xpathExpr, namespaces) {
        return (new simple.xml.XPathExpression(xpathExpr, namespaces))
                .getNode(context);
    }
};
simple.xml.XPathExpression = function(xpathText, namespaces) {
    this.xpathText = xpathText; // Save the text of the expression
    this.namespaces = namespaces; // And the namespace mapping
    if (document.createExpression) {
        // If we're in a W3C-compliant browser, use the W3C API
        // to compile the text of the XPath query
        this.xpathExpr = document.createExpression(xpathText,
                // This function is passed a
                // namespace prefix and returns the URL.
                function(prefix) {
            return namespaces[prefix];
        });
    } else {
        // Otherwise, we assume for now that we're in IE and convert the
        // namespaces object into the textual form that IE requires.
        this.namespaceString = "";
        if (namespaces != null) {
            for (var prefix in namespaces) {
                // Add a space if there is already something there
                if (this.namespaceString)
                    this.namespaceString += ' ';
                // And add the namespace
                this.namespaceString += 'xmlns:' + prefix + '="'
                        + namespaces[prefix] + '"';
            }
        }
    }
};
simple.xml.XPathExpression.prototype.getNodes = function(context) {
    if (this.xpathExpr) {
        // If we are in a W3C-compliant browser, we compiled the
        // expression in the constructor. We now evaluate that compiled
        // expression in the specified context.
        var result = this.xpathExpr.evaluate(context,
                // This is the result type we want
                XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
        // Copy the results we get into an array.
        var a = new Array(result.snapshotLength);
        for (var i = 0; i < result.snapshotLength; i++) {
            a[i] = result.snapshotItem(i);
        }
        return a;
    } else {
        // If we are not in a W3C-compliant browser, attempt to evaluate
        // the expression using the IE API.
        try {
            // We need the Document object to specify namespaces
            var doc = context.ownerDocument;
            // If the context doesn't have ownerDocument, it is the Document
            if (doc == null) {
                doc = context;
            }
            // This is IE-specific magic to specify prefix-to-URL mapping
            doc.setProperty("SelectionLanguage", "XPath");
            doc.setProperty("SelectionNamespaces", this.namespaceString);
            // In IE, the context must be an Element not a Document,
            // so if context is a document, use documentElement instead
            if (context == doc) {
                context = doc.documentElement;
            }
            // Now use the IE method selectNodes( ) to evaluate the expression
            return context.selectNodes(this.xpathText);
        } catch (e) {
            // If the IE API doesn't work, we just give up
            throw new Error("XPath not supported by this browser.");
        }
    }
};
simple.xml.XPathExpression.prototype.getNode = function(context) {
    if (this.xpathExpr) {
        var result = this.xpathExpr.evaluate(context,
                // We just want the first match
                XPathResult.FIRST_ORDERED_NODE_TYPE, null);
        return result.singleNodeValue;
    } else {
        try {
            var doc = context.ownerDocument;
            if (doc == null) {
                doc = context;
            }
            doc.setProperty("SelectionLanguage", "XPath");
            doc.setProperty("SelectionNamespaces", this.namespaceString);
            if (context == doc) {
                context = doc.documentElement;
            }
            // In IE call selectSingleNode instead of selectNodes
            return context.selectSingleNode(this.xpathText);
        } catch (e) {
            throw new Error("XPath not supported by this browser.");
        }
    }
};

1 comment:

  1. You left out Microsoft.XMLDOM. Why? This is what actually finally worked for me, though I had to write a function to use it:
    var xmlDOC;
    function loadXMLString(txt) {
    if (window.DOMParser)
    var parser = new DOMParser();
    xmlDOC = parser.parseFromString(txt, "text/xml");
    } else {
    xmlDOC = new ActiveXObject("Microsoft.XMLDOM");
    xmlDOC.async = false;
    xmlDOC.loadXML(txt);
    }
    return xmlDOC;
    }
    and to use this:
    var xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
    xmlDoc = loadXMLString(xmlResponseText);
    var xmlNodes = xmlDoc.getElementsByTagName("z:row");

    ReplyDelete