// ajax.js // Common Javascript methods and global objects // Ajax framework for Internet Explorer (6.0, ...) and Firefox (1.0, ...) // Copyright (c) by Matthias Hertel, http://www.mathertel.de // This work is licensed under a BSD style license. See http://www.mathertel.de/License.aspx // More information on: http://ajaxaspects.blogspot.com/ and http://ajaxaspekte.blogspot.com/ // ----- // 05.06.2005 created by Matthias Hertel. // 19.06.2005 minor corrections to webservices. // 25.06.2005 ajax action queue and timing. // 02.07.2005 queue up actions fixed. // 10.07.2005 ajax.timeout // 10.07.2005 a option object that is passed from ajax.Start() to prepare() is also queued. // 10.07.2005 a option object that is passed from ajax.Start() to prepare(), finish() // and onException() is also queued. // 12.07.2005 correct xml encoding when CallSoap() // 20.07.2005 more datatypes and XML Documents // 20.07.2005 more datatypes and XML Documents fixed // 06.08.2005 caching implemented. // 07.08.2005 bugs fixed, when queuing without a delay time. // 04.09.2005 bugs fixed, when entering non-multiple actions. // 07.09.2005 proxies.IsActive added // 27.09.2005 fixed error in handling bool as a datatype // 13.12.2005 WebServices with arrays on strings, ints, floats and booleans - still undocumented // 27.12.2005 fixed: empty string return values enabled. // 27.12.2005 enable the late binding of proxy methods. // 21.01.2006 void return bug fixed. // 18.02.2006 typo: Finsh -> Finish. // 25.02.2006 better xmlhttp request object retrieval, see http://blogs.msdn.com/ie/archive/2006/01/23/516393.aspx // 22.04.2006 progress indicator added. // 28.01.2006 void return bug fixed again? // 09.03.2006 enable late binding of prepare and finish methods by using an expression. // 14.07.2006 Safari Browser Version 2.03/Mac OS X 10.4. compatibility: xNode.textContent || xNode.innerText || xNode.text || xNode.childNodes[0].nodeValue // 10.08.2006 date to xml format fixed by Kars Veling // 16.09.2006 .postUrl -- unfinished... // 26.11.2006 enable null for xml based objects // 19.05.2007 enabling ajax engine calls with multiple parameters // 14.07.2007 xml2json added. // 14.09.2007 ajax._resolve implemented to avoid the eval function // 19.09.2007 lots of changes to get a better code as suggested by Breton Slivka (Thanks) // 01.10.2007 ... more of it. // 13.10.2007 structured parameter support for calling webservice methods // 16.10.2007 xml2json bug fixed // 10.11.2008 better documentation support. // 10.11.2008 inspectText added. // 30.11.2008 ajax.StartLocalAction added. // 03.01.2009 better handling of the result namespace // 27.04.2009 some issues when using ajax.js standalone, including the xml compatible code // in FireFOx for XMLDocument.selectSingleNode // 18.06.2011 IE9 compatibility issue with XML return values fixed. // ----- global variable for the proxies to webservices. ----- var proxies = function () { /// <summary>The root object for the proxies to webservices.</summary> }; if (window.OpenAjax && window.OpenAjax.hub) { OpenAjax.hub.registerLibrary("proxies", "http://www.mathertel.de/proxies", "1.5", {}); } // if proxies.current = null; // the current active webservice call. proxies.xmlhttp = null; // The current active xmlhttp object. // ----- global variable for the ajax engine. ----- var ajax = { /// <summary>The root object for the ajax engine implementation.</summary> /// <field name="current" type="ajax.Action">The current active AJAX action.</field> current: null, /// <field name="option" type="Object">The options for the current active AJAX action.</field> option: null, /// <field name="queue" type="Array">The pending AJAX actions.</field> queue: [], /// <field name="options" type="Array">The options for the pending AJAX actions.</field> options: [], /// <field name="isIE" type="Boolean">Detect InternetExplorer for some specific implementation differences.</field> isIE: (window.navigator.userAgent.indexOf("MSIE") > 0) }; if (window.OpenAjax && window.OpenAjax.hub) { OpenAjax.hub.registerLibrary("ajax", "http://www.mathertel.de/ajax", "1.5", {}); } // if ajax.timer = null; /// The timer for delayed actions. ajax.progress = false; /// show a progress indicator ajax.progressTimer = null; /// a timer-object that help displaying the progress indicator not too often. // ----- AJAX engine and actions implementation ----- ajax.Action = { /// <summary>An action object with default values for declaring the details of ajax actions.</summary> /// <field name="queueClear" type="Boolean">If set to true, the queue will be cleard before this action is added.</field> queueClear: false, queueTop: false, queueMultiple: true, /// <field name="call" type="Function">The call that invokes some action on the server.</field> call: null, prepare: null, finish: null }; // Action ajax.Start = function (action, options) { ///<summary>Start an AJAX action by entering it into the queue</summary> ///<param name="action" type="ajax.Action">An object declaring the ajax action that should be executed.</param> ///<param name="options" type="Object">A optional parameter that is passed to the action methods.</param> ajax.Add(action, options); // check if the action should start if ((!ajax.current) && (!ajax.timer)) { ajax._next(false); } // if }; // ajax.Start ajax.StartLocalAction = function (method, options) { ///<summary>Start an non-AJAX action that actls only locally in the browser by entering it into the queue</summary> ///<param name="method" type="Function">The method that will be called.</param> ///<param name="options" type="Object">A optional parameter that is passed to the action methods.</param> var a = { queueClear: false, queueTop: false, queueMultiple: true }; // simple action a.delay = 1; a.prepare = method; ajax.Start(a, options); }; // ajax.StartLocalAction ajax.Add = function (action, options) { ///<summary>Add an AJAX action by entering it into the queue without starting it.</summary> ///<param name="action" type="Action">An object declaring the ajax action that should be executed.</param> ///<param name="options" type="Object">A optional parameter that is passed to the action methods.</param> if (!action) { alert("ajax.Start: Argument action must be set."); return; } // if // enable the late binding of the methods by using a string that is evaluated. if (typeof (action.call) === "string") action.call = ajax._resolve(action.call); if (typeof (action.prepare) === "string") action.prepare = ajax._resolve(action.prepare); if (typeof (action.finish) === "string") action.finish = ajax._resolve(action.finish); if ((action.queueClear) && (action.queueClear === true)) { ajax.queue = []; ajax.options = []; } else if ((ajax.queue.length > 0) && ((!action.queueMultiple) || (action.queueMultiple === false))) { // remove existing action entries from the queue and clear a running timer if ((ajax.timer) && (ajax.queue[0] === action)) { window.clearTimeout(ajax.timer); ajax.timer = null; } // if var n = 0; while (n < ajax.queue.length) { if (ajax.queue[n] === action) { ajax.queue.splice(n, 1); ajax.options.splice(n, 1); } else { n++; } // if } // while } // if if ((!action.queueTop) || (action.queueTop === false)) { // to the end. ajax.queue.push(action); ajax.options.push(options); } else { // to the top ajax.queue.unshift(action); ajax.options.unshift(options); } // if }; // ajax.Add ajax._next = function (forceStart) { ///<summary>Check, if the next AJAX action can start. ///This is an internal method that should not be called from external.</summary> ///<remarks>for private use only.<remarks> var ca = null; // current action var co = null; // current opptions var data = null; if (ajax.current) return; // a call is active: wait more time if (ajax.timer) return; // a call is pendig: wait more time if (ajax.queue.length === 0) return; // nothing to do. ca = ajax.queue[0]; co = ajax.options[0]; if ((forceStart === true) || (!ca.delay) || (ca.delay === 0)) { // start top action ajax.current = ca; ajax.queue.shift(); ajax.option = co; ajax.options.shift(); // get the data if (ca.prepare) { try { data = ca.prepare(co); } catch (ex) { } } // if if (ca.call) { ajax.StartProgress(); // start the call ca.call.func = ajax.Finish; ca.call.onException = ajax.Exception; if ((data) && (data.constructor === Array) && (data.multi)) // 19.05.2007 ca.call.apply(ca, data); else ca.call(data); // start timeout timer if (ca.timeout) { ajax.timer = window.setTimeout(ajax.Cancel, ca.timeout * 1000); } // if } else if (ca.postUrl) { // post raw data to URL } else { // no call ajax.Finish(data); } // if } else { // start a timer and wait ajax.timer = window.setTimeout(ajax.EndWait, ca.delay); } // if }; // ajax._next ajax.EndWait = function () { ///<summary>The delay time of an action is over.</summary> ajax.timer = null; ajax._next(true); }; // ajax.EndWait ajax.Cancel = function () { ///<summary>The current action timed out.</summary> proxies.cancel(false); // cancel the current webservice call. ajax.timer = null; ajax.current = null; ajax.option = null; ajax.EndProgress(); window.setTimeout(ajax._next, 200); // give some to time to cancel the http connection. }; // ajax.Cancel ajax.Finish = function (data) { ///<summary>Finish an AJAX Action the normal way</summary> // clear timeout timer if set if (ajax.timer) { window.clearTimeout(ajax.timer); ajax.timer = null; } // if // use the data try { if ((ajax.current) && (ajax.current.finish)) ajax.current.finish(data, ajax.option); } catch (ex) { } // reset the running action ajax.current = null; ajax.option = null; ajax.EndProgress(); ajax._next(false); }; // ajax.Finish ajax.Exception = function (ex) { ///<summary>Finish an AJAX Action with an exception</summary> // use the data if (ajax.current.onException) ajax.current.onException(ex, ajax.option); // reset the running action ajax.current = null; ajax.option = null; ajax.EndProgress(); }; // ajax.Exception ajax.CancelAll = function () { ///<summary>Clear the current and all pending AJAX actions.</summary> ajax.Cancel(); // clear all pending AJAX actions in the queue. ajax.queue = []; ajax.options = []; }; // ajax.CancelAll // ----- show or hide a progress indicator ----- ajax.StartProgress = function () { ///<summary>Show a progress indicator if it takes longer...</summary> ajax.progress = true; if (ajax.progressTimer) window.clearTimeout(ajax.progressTimer); ajax.progressTimer = window.setTimeout(ajax.ShowProgress, 220); }; // ajax.StartProgress ajax.EndProgress = function () { ///<summary>Hide any progress indicator soon.</summary> ajax.progress = false; if (ajax.progressTimer) window.clearTimeout(ajax.progressTimer); ajax.progressTimer = window.setTimeout(ajax.ShowProgress, 20); }; // ajax.EndProgress ajax.ShowProgress = function () { ///<summary>This function is called by a timer to show or hide a progress indicator.</summary> ajax.progressTimer = null; var a = document.getElementById("AjaxProgressIndicator"); var s; if (ajax.progress && (a)) { // just display the existing object a.style.top = document.documentElement.scrollTop + 2 + "px"; a.style.display = ""; } else if (ajax.progress) { // find a relative link to the ajaxcore folder containing ajax.js var path = "../ajaxcore/"; for (var n in document.scripts) { s = document.scripts[n].src; if ((s) && (s.length >= 7) && (s.substr(s.length - 7).toLowerCase() === "ajax.js")) path = s.substr(0, s.length - 7); } // for // create new standard progress object a = document.createElement("div"); a.id = "AjaxProgressIndicator"; a.style.position = "absolute"; a.style.right = "2px"; a.style.top = document.documentElement.scrollTop + 2 + "px"; a.style.width = "98px"; a.style.height = "16px"; a.style.padding = "2px"; a.style.verticalAlign = "bottom"; a.style.backgroundColor = "#51c77d"; a.innerHTML = "<img style='vertical-align:bottom' src='" + path + "ajax-loader.gif'> please wait..."; document.body.appendChild(a); } else if (a) { a.style.display = "none"; } // if }; // ajax.ShowProgress ajax._resolve = function (s) { ///<summary>Resolve a method reference given as a string /// by following the objects from the window object down to the concrete method.</summary> var ref = null; if ((s) && (s.length != 0)) { ref = window; s = s.split('.'); for (var n = 0; (n < s.length) && (ref); n++) ref = ref[s[n]]; } // if return (ref); }; // _resolve // ----- simple http-POST server call ----- ajax.postData = function (url, data, func) { var x = proxies._getXHR(); // enable cookieless sessions: var cs = document.location.href.match(/\/\(.*\)\//); if (cs) { url = url.split('/'); url[3] += cs[0].substr(0, cs[0].length - 1); url = url.join('/'); } // if x.open("POST", url, (func)); if (func) { // async call with xmlhttp-object as parameter x.onreadystatechange = func; x.send(data); } else { // sync call x.send(data); return (x.responseText); } // if }; // ajax.postData proxies.callSoap = function (args) { ///<summary>Execute a soap call. ///Build the xml for the call of a soap method of a webservice and post it to the server.</summary> var p = args.callee; var x = null; var n; // check for existing cache-entry if (p._cache) { if ((p.params.length === 1) && (args.length === 1) && (p._cache[args[0]])) { if (p.func) { p.func(p._cache[args[0]]); return (null); } else { return (p._cache[args[0]]); } // if } else { p._cachekey = args[0]; } // if } // if proxies.current = p; x = proxies._getXHR(); proxies.xmlhttp = x; // envelope start var soap = "<?xml version='1.0' encoding='utf-8'?>" + "<soap:Envelope xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'>" + "<soap:Body>" + "<" + p.fname + " xmlns='" + p.service.ns + "'>"; // parameters for (n = 0; (n < p.params.length) && (n < args.length); n++) { var val = args[n]; var typ = p.params[n].split(':'); if ((typ.length === 1) || (typ[1] === "string")) { val = String(args[n]).replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">"); } else switch (typ[1]) { case "int": val = parseInt(args[n], 10); break; case "float": val = parseFloat(args[n]); break; case "x": if (typeof (args[n]) === "string") { val = args[n]; } else if (window.XMLSerializer) { val = (new XMLSerializer()).serializeToString(args[n].firstChild); } else if (args[n]) { val = args[n].xml; } // if break; case "ds": // 12.10.2007 complex parameter support val = ""; if (typeof (args[n]) === "string") { val = args[n]; // inner xml } else if (args[n].constructor === Object) { var obj = args[n]; for (var prop in obj) { val += "<" + prop + ">"; val += String(obj[prop]).replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">"); val += "</" + prop + ">"; } } else if (args[n]) { var xprop = args[n].documentElement.firstChild; while (xprop != null) { val += "<" + xprop.tagName + ">"; val += String(xprop.text || xprop.textContent).replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">"); val += "</" + xprop.tagName + ">"; xprop = xprop.nextSibling; } // for } // if break; case "bool": if (typeof (args[n]) === "string") { val = args[n].toLowerCase(); } else { val = String(args[n]).toLowerCase(); } // if break; case "date": // calculate the xml format for datetime objects from a javascript date object var s, ret; ret = String(val.getFullYear()); ret += "-"; s = String(val.getMonth() + 1); ret += (s.length === 1 ? "0" + s : s); ret += "-"; s = String(val.getDate()); ret += (s.length === 1 ? "0" + s : s); ret += "T"; s = String(val.getHours()); ret += (s.length === 1 ? "0" + s : s); ret += ":"; s = String(val.getMinutes()); ret += (s.length === 1 ? "0" + s : s); ret += ":"; s = String(val.getSeconds()); ret += (s.length === 1 ? "0" + s : s); val = ret; break; case "s[]": val = proxies._wrapArray2Xml(args[n], "string"); break; case "int[]": val = proxies._wrapArray2Xml(args[n], "int"); break; case "float[]": val = proxies._wrapArray2Xml(args[n], "float"); break; case "bool[]": val = proxies._wrapArray2Xml(args[n], "boolean"); break; } // switch soap += "<" + typ[0] + ">" + val + "</" + typ[0] + ">"; } // for // envelope end soap += "</" + p.fname + ">" + "</soap:Body>" + "</soap:Envelope>"; // enable cookieless sessions: var u = p.service.url; var cs = document.location.href.match(/\/\(.*\)\//); if (cs) { u = p.service.url.split('/'); u[3] += cs[0].substr(0, cs[0].length - 1); u = u.join('/'); } // if x.open("POST", u, (p.func != null)); try { x.responseType = 'msxml-document'; } catch (e) { } x.setRequestHeader("SOAPAction", p.action); x.setRequestHeader("Content-Type", "text/xml; charset=utf-8"); if (p.corefunc) { // async call with xmlhttp-object as parameter x.onreadystatechange = p.corefunc; x.send(soap); } else if (p.func) { // async call x.onreadystatechange = proxies._response; x.send(soap); } else { // sync call x.send(soap); return (proxies._response()); } // if }; // proxies.callSoap proxies.cancel = function (raise) { ///<summary>Cancel the running webservice call.</summary> //<param name="raise" type="Boolean">If set to true an exception will be thrown through the onException function.</param> var cc = proxies.current; var cx = proxies.xmlhttp; if (!raise) raise === true; if (cx) { cx.onreadystatechange = function () { }; cx.abort(); if (raise && (cc.onException)) cc.onException("WebService call was canceled."); proxies.current = null; proxies.xmlhttp = null; } // if }; // proxies.cancel proxies.EnableCache = function (px) { ///<summary>Attach an empty _cache object.</summary> ///<param name="px" type="Function">A proxies.service.func object.</param> px._cache = {}; }; // proxies.EnableCache proxies.IsActive = function () { ///<summary>Check, if a call is currently waiting for a result.</summary> return (proxies.xmlhttp); }; // proxies.IsActive proxies._response = function () { ///<summary>Callback method for a webservice call that dispatches the response to servive.func or service.onException.</summary> ///<remarks>for private use only.<remarks> var ret = null; var n = null; var x = proxies.xmlhttp; var cc = proxies.current; var rtype = null; if ((cc.rtype.length > 0) && (cc.rtype[0])) rtype = cc.rtype[0].split(':'); if ((x) && (x.readyState === 4)) { if (x.status === 200) { var xNode = null; if (rtype) { if (window.DOMParser) { // IE 9 ... var parser = new DOMParser(); xNode = parser.parseFromString(x.responseText, "text/xml"); xNode = xNode.getElementsByTagName(rtype[0])[0]; // doc->(envelope)->(body)->(response)->RESULT (avoiding namespace alias problems } else if (ajax.isIE) { // old IE versions x.responseXML.setProperty("SelectionLanguage", "XPath"); xNode = x.responseXML.selectSingleNode("//*[local-name()='" + rtype[0] + "']"); } else { //FireFox xNode = x.responseXML.getElementsByTagName(rtype[0])[0]; } // if } // if if (!xNode) { ret = null; } else if (!xNode.firstChild) { // 27.12.2005: empty string return values ret = ((rtype.length === 1) || (rtype[1] === "string") ? "" : null); } else if ((rtype.length === 1) || (rtype[1] === "string")) { ret = proxies._getAnyXmlText(xNode); } else switch (rtype[1]) { case "bool": ret = proxies._getAnyXmlText(xNode); ret = (ret === "true"); break; case "int": ret = proxies._getAnyXmlText(xNode); ret = parseInt(ret, 10); break; case "float": ret = proxies._getAnyXmlText(xNode); ret = parseFloat(ret); break; case "x": xNode = xNode.firstChild; if (xNode.xml) { ret = ajax._getXMLDOM(xNode.xml); } else if (window.XMLSerializer) { var xs = new window.XMLSerializer(); ret = xs.serializeToString(xNode); ret = ajax._getXMLDOM(ret); } // if break; case "ds": if (window.XMLSerializer) { ret = (new window.XMLSerializer()).serializeToString(xNode); ret = ajax._getXMLDOM(ret); } else { ret = xNode.xml; ret = ajax._getXMLDOM(ret); } // if break; case "s[]": // Array of strings ret = []; xNode = xNode.firstChild; while (xNode) { ret.push(proxies._getAnyXmlText(xNode)); xNode = xNode.nextSibling; } // while break; case "int[]": // Array of int ret = []; xNode = xNode.firstChild; while (xNode) { ret.push(parseInt(proxies._getAnyXmlText(xNode))); xNode = xNode.nextSibling; } // while break; case "float[]": // Array of float ret = []; xNode = xNode.firstChild; while (xNode) { ret.push(parseFloat(proxies._getAnyXmlText(xNode))); xNode = xNode.nextSibling; } // while break; case "bool[]": // Array of bool ret = []; xNode = xNode.firstChild; while (xNode) { ret.push((proxies._getAnyXmlText(xNode)).toLowerCase() === "true"); xNode = xNode.nextSibling; } // while break; default: ret = proxies._getAnyXmlText(xNode); break; } // switch // store to _cache if ((cc._cache) && (cc._cachekey)) { cc._cache[cc._cachekey] = ret; cc._cachekey = null; } // if proxies.xmlhttp = null; proxies.current = null; if (!cc.func) { return (ret); // sync } else { cc.func(ret); // async return (null); } // if } else if (!proxies.current.onException) { // no exception } else { // raise an exception ret = new Error(); if (x.status === 404) { ret.message = "The webservice could not be found."; } else if (x.status === 500) { ret.name = "SoapException"; if (ajax.isIE) x.responseXML.setProperty("SelectionLanguage", "XPath"); n = x.responseXML.selectSingleNode("//*[local-name()='Fault']/faultcode"); if (n) ret.message = n.firstChild.nodeValue; n = x.responseXML.selectSingleNode("//*[local-name()='Fault']/faultstring"); if (n) ret.description = n.firstChild.nodeValue; } else if ((x.status === 502) || (x.status === 12031)) { ret.message = "The server could not be found."; } else { // no classified response. ret.message = "Result-Status:" + x.status + "\n" + x.responseText; } // if proxies.current.onException(ret); } // if proxies.xmlhttp = null; proxies.current = null; } // if }; // proxies._response proxies.alertResult = function () { ///<summary>Callback method to show the result of a soap call in an alert box.</summary> ///<remarks>To set up a debug output in an alert box use: ///proxies.service.method.corefunc = proxies.alertResult;</remarks> var x = proxies.xmlhttp; if (x.readyState === 4) { if (x.status === 200) { if (!x.responseXML.documentElement.firstChild.firstChild.firstChild) alert("(no result)"); else alert(x.responseXML.documentElement.firstChild.firstChild.firstChild.firstChild.nodeValue); } else if (x.status === 404) { alert("Error!\n\nThe webservice could not be found."); } else if (x.status === 500) { // a SoapException var ex = new Error(); ex.name = "SoapException"; var n = x.responseXML.documentElement.firstChild.firstChild.firstChild; while (n) { if (n.nodeName === "faultcode") ex.message = n.firstChild.nodeValue; if (n.nodeName === "faultstring") ex.description = n.firstChild.nodeValue; n = n.nextSibling; } // while alert("The server threw an exception.\n\n" + ex.message + "\n\n" + ex.description); } else if (x.status === 502) { alert("Error!\n\nThe server could not be found."); } else { // no classified response. alert("Result-Status:" + x.status + "\n" + x.responseText); } // if proxies.xmlhttp = null; proxies.current = null; } // if }; // proxies.alertResult proxies.alertResponseText = function () { ///<summary>Show all the details of the returned data of a webservice call. ///Use this method for debugging transmission problems.</summary> ///<remarks>To set up a debug output in an alert box use: ///proxies.service.method.corefunc = proxies.alertResponseText;</remarks> if (proxies.xmlhttp.readyState === 4) alert("Status:" + proxies.xmlhttp.status + "\nRESULT:" + proxies.xmlhttp.responseText); }; // proxies.alertResponseText proxies.alertException = function (ex) { ///<summary>Show the details about an exception.</summary> var s = "Exception:\n\n"; if (ex.constructor === String) { s = ex; } else { if ((ex.name) && (ex.name != "")) s += "Type: " + ex.name + "\n\n"; if ((ex.message) && (ex.message != "")) s += "Message:\n" + ex.message + "\n\n"; if ((ex.description) && (ex.description != "") && (ex.message != ex.description)) s += "Description:\n" + ex.description + "\n\n"; } // if alert(s); }; // proxies.alertException proxies._getXHR = function () { ///<summary>Get a browser specific implementation of the XMLHttpRequest object.</summary> // from http://blogs.msdn.com/ie/archive/2006/01/23/516393.aspx var x = null; if (window.XMLHttpRequest) { // if IE7, Mozilla, Safari, etc: Use native object x = new XMLHttpRequest(); } else if (window.ActiveXObject) { // ...otherwise, use the ActiveX control for IE5.x and IE6 try { x = new ActiveXObject("Msxml2.XMLHTTP"); } catch (ex1) { } if (!x) { try { x = new ActiveXObject("Microsoft.XMLHTTP"); } catch (ex2) { } } // if } // if return (x); }; // proxies._getXHR ajax._getXMLDOM = function (xmlText) { ///<summary>Get a browser specific implementation of the XMLDOM object, containing a XML document.</summary> ///<param name="xmlText">the xml document as string.</param> var obj = null; if ((!ajax.isIE) && (document.implementation) && (typeof document.implementation.createDocument === "function")) { // Gecko / Mozilla / Firefox var parser = new DOMParser(); obj = parser.parseFromString(xmlText, "text/xml"); } else { // IE try { obj = new ActiveXObject("MSXML2.DOMDocument"); } catch (ex1) { } if (!obj) { try { obj = new ActiveXObject("Microsoft.XMLDOM"); } catch (ex2) { } } // if if (obj) { obj.async = false; obj.validateOnParse = false; } // if obj.loadXML(xmlText); } // if return (obj); }; // _getXMLDOM proxies.xml2json = function (xObj) { ///<summary>Convert complex XML structures to JavaScript objects (JSON).</summary> var ret = {}; if (xObj.nodeType === 9) return (this.xml2json(xObj.documentElement)); var n = xObj.firstChild; if (n === null) { if (xObj.getAttribute("xsi:nil") === "true") { ret = null; } else { ret = ""; } // if } else if (n.nodeType === 3) { // just a text node. ret = n.nodeValue; } else { // a complex node: analyse all subnodes while (n) { var nn = n.nodeName; // strip namespace aliases from node names: n1:<varname> --> <varname> if (nn.indexOf(':') > 0) { nn = nn.split(":")[1]; } // if var nv = this.xml2json(n); // recursion ! if (!ret[nn]) { // maybe just a simple nested value ret[nn] = nv; } else if (ret[nn].constructor === Array) { // nn is already an array, now with another value ret[nn].push(nv); } else { // if more than 1 element with the same name is present // an array is used to collect them all. var tmp = []; tmp[0] = ret[nn]; tmp[1] = nv; ret[nn] = tmp; } // if n = n.nextSibling; } // while } // if return (ret); }; // xml2json proxies._wrapArray2Xml = function (arr, tagname) { ///<summary>Wrap array in xml tags helper.</summary> ///<param name="arr" type="Array">An array containing values.</param> ///<param name="tagname" type="String">The tagname used in the array.</param> var ts = "<" + tagname + ">"; var te = "</" + tagname + ">"; var tm = te + ts; return (ts + arr.join(tm) + te); }; proxies._getAnyXmlText = function (node) { ///<summary>Factoring out getting text from a node.</summary> return (node.textContent || node.innerText || node.text || node.childNodes[0].nodeValue); }; function inspectObj(obj) { ///<summary>Show the details of a javascript object using an alert box.</summary> ///<remarks>This helps a lot while developing and debugging.</remarks> alert(inspectText(obj)); } // inspectObj window.inspectText = function (obj) { ///<summary>Create a textual view of the details of a javascript object.</summary> var s = "InspectObj:"; var n, p; if (!obj) { s = "(null)"; return (s); } else if (obj.constructor === String) { s = "\"" + obj + "\""; } else if (obj.constructor === Array) { s += " _ARRAY"; } else if (typeof (obj) === "function") { s += " [function]" + obj; } else if ((typeof (XMLSerializer) != "undefined") && (obj.constructor === XMLDocument)) { s = "[XMLDocument]:\n" + (new XMLSerializer()).serializeToString(obj.firstChild); return (s); } else if ((typeof (obj) === "object") && (obj.xml)) { s = "[XML]:\n" + obj.xml; return (s); } for (p in obj) { try { if (!obj[p]) { s += "\n" + String(p) + " (...)"; } else if (typeof (obj[p]) === "function") { s += "\n" + String(p) + " [function]"; } else if (obj[p].constructor === Array) { s += "\n" + String(p) + " [ARRAY]: " + obj[p]; for (n = 0; n < obj[p].length; n++) s += "\n " + n + ": " + obj[p][n]; } else { s += "\n" + String(p) + " [" + typeof (obj[p]) + "]: " + obj[p]; } // if } catch (e) { s += e; } } // for return (s); }; // inspectObj // ----- make FF more IE compatible ----- if (!ajax.isIE) { // ----- XML objects ----- // select the first node that matches the XPath expression // xPath: the XPath expression to use if (!XMLDocument.selectSingleNode) { XMLDocument.prototype.selectSingleNode = function (xPath) { var doc = this; if (doc.nodeType != 9) doc = doc.ownerDocument; if (doc.nsResolver === null) doc.nsResolver = function (prefix) { return (null); }; var node = doc.evaluate(xPath, this, doc.nsResolver, XPathResult.ANY_UNORDERED_NODE_TYPE, null); if (node) node = node.singleNodeValue; return (node); }; // selectSingleNode } // if } // if // ----- End -----
This page is part of the http://www.mathertel.de/ web site.
For updates and discussions see http://ajaxaspects.blogspot.com/.