From 59ce12a51b352bc800a3347b00df80a296a84e62 Mon Sep 17 00:00:00 2001 From: Francis Lachapelle Date: Tue, 17 Dec 2013 16:39:30 -0500 Subject: [PATCH] Load XMLHttpRequest conditionally (< IE9) --- NEWS | 1 + UI/SOGoElements/SOGoIEConditional.h | 5 +- UI/SOGoElements/SOGoIEConditional.m | 20 +- UI/Templates/UIxPageFrame.wox | 8 +- UI/WebServerResources/XMLHttpRequest.js | 627 +++++++++++++++--------- 5 files changed, 422 insertions(+), 239 deletions(-) diff --git a/NEWS b/NEWS index 88d21c80d..7a1224ab4 100644 --- a/NEWS +++ b/NEWS @@ -9,6 +9,7 @@ Enhancements - we now automatically convert into file attachments using CIDs. This prevents Outlook issues. - updated Finnish translation + - XMLHttpRequest is now loaded conditionaly (< IE9) Bug fixes - diff --git a/UI/SOGoElements/SOGoIEConditional.h b/UI/SOGoElements/SOGoIEConditional.h index e59ed63ac..23779f800 100644 --- a/UI/SOGoElements/SOGoIEConditional.h +++ b/UI/SOGoElements/SOGoIEConditional.h @@ -1,8 +1,8 @@ /* SOGoIEConditional.h - this file is part of SOGo * - * Copyright (C) 2007 Inverse inc. + * Copyright (C) 2007-2013 Inverse inc. * - * Author: Wolfgang Sourdeau + * Author: Inverse * * This file is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -32,6 +32,7 @@ @interface SOGoIEConditional : WODynamicElement { WOElement *template; + WOAssociation *lte; // int } - (void) appendToResponse: (WOResponse *) _response diff --git a/UI/SOGoElements/SOGoIEConditional.m b/UI/SOGoElements/SOGoIEConditional.m index e3ac46bab..09f156e48 100644 --- a/UI/SOGoElements/SOGoIEConditional.m +++ b/UI/SOGoElements/SOGoIEConditional.m @@ -1,8 +1,8 @@ /* SOGoIEConditional.m - this file is part of SOGo * - * Copyright (C) 2007 Inverse inc. + * Copyright (C) 2007-2013 Inverse inc. * - * Author: Wolfgang Sourdeau + * Author: Inverse * * This file is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,6 +22,7 @@ #import #import +#import #import "SOGoIEConditional.h" @@ -34,7 +35,10 @@ if ((self = [super initWithName: name associations: associations template: newTemplate])) - ASSIGN (template, newTemplate); + { + ASSIGN (template, newTemplate); + lte = OWGetProperty(associations, @"lte"); + } return self; } @@ -42,13 +46,21 @@ - (void) dealloc { [template release]; + [lte release]; [super dealloc]; } - (void) appendToResponse: (WOResponse *) response inContext: (WOContext *) context { - [response appendContentString: @""]; } diff --git a/UI/Templates/UIxPageFrame.wox b/UI/Templates/UIxPageFrame.wox index 095634ae7..9095bf27f 100644 --- a/UI/Templates/UIxPageFrame.wox +++ b/UI/Templates/UIxPageFrame.wox @@ -34,9 +34,10 @@ > - + + + - diff --git a/UI/WebServerResources/XMLHttpRequest.js b/UI/WebServerResources/XMLHttpRequest.js index 1597d48b3..4c2ca215e 100644 --- a/UI/WebServerResources/XMLHttpRequest.js +++ b/UI/WebServerResources/XMLHttpRequest.js @@ -1,80 +1,123 @@ -// XMLHttpRequest.js Copyright (C) 2008 Sergey Ilinsky (http://www.ilinsky.com) -// -// This work is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. - -// This work is distributed in the hope that it will be useful, -// but without any warranty; without even the implied warranty of -// merchantability or fitness for a particular purpose. See the -// GNU Lesser General Public License for more details. - -// You should have received a copy of the GNU Lesser General Public License -// along with this library; if not, write to the Free Software Foundation, Inc., -// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/** +* XMLHttpRequest.js Copyright (C) 2011 Sergey Ilinsky (http://www.ilinsky.com) +* +* This work is free software; you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License as published by +* the Free Software Foundation; either version 2.1 of the License, or +* (at your option) any later version. +* +* This work is distributed in the hope that it will be useful, +* but without any warranty; without even the implied warranty of +* merchantability or fitness for a particular purpose. See the +* GNU Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this library; if not, write to the Free Software Foundation, Inc., +* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ (function () { // Save reference to earlier defined object implementation (if any) - var oXMLHttpRequest = window.XMLHttpRequest; - + var oXMLHttpRequest = window.XMLHttpRequest; + // Define on browser type - var bGecko = !!window.controllers, - bIE = window.document.all && !window.opera; + var bGecko = !!window.controllers; + var bIE = !!window.document.namespaces; + var bIE7 = bIE && window.navigator.userAgent.match(/MSIE 7.0/); + + // Enables "XMLHttpRequest()" call next to "new XMLHttpRequest()" + function fXMLHttpRequest() { + if (!window.XMLHttpRequest || bIE7) { + this._object = new window.ActiveXObject("Microsoft.XMLHTTP"); + } // only use initial XHR object internally if current reference to XHR is our normalized replacement + else if (window.XMLHttpRequest.isNormalizedObject) { + this._object = new oXMLHttpRequest(); + } // otherwise use whatever is currently referenced by XMLHttpRequest + else { + this._object = new window.XMLHttpRequest(); + } + this._listeners = []; + } // Constructor function cXMLHttpRequest() { - this._object = oXMLHttpRequest ? new oXMLHttpRequest : new window.ActiveXObject("Microsoft.XMLHTTP"); - this._listeners = []; - }; + return new fXMLHttpRequest; + } + cXMLHttpRequest.prototype = fXMLHttpRequest.prototype; // BUGFIX: Firefox with Firebug installed would break pages if not executed - if (bGecko && oXMLHttpRequest.wrapped) - cXMLHttpRequest.wrapped = oXMLHttpRequest.wrapped; + if (bGecko && oXMLHttpRequest.wrapped) { + cXMLHttpRequest.wrapped = oXMLHttpRequest.wrapped; + } + + // Marker to be able to easily identify our object + cXMLHttpRequest.isNormalizedObject = true; // Constants - cXMLHttpRequest.UNSENT = 0; - cXMLHttpRequest.OPENED = 1; - cXMLHttpRequest.HEADERS_RECEIVED = 2; - cXMLHttpRequest.LOADING = 3; - cXMLHttpRequest.DONE = 4; + cXMLHttpRequest.UNSENT = 0; + cXMLHttpRequest.OPENED = 1; + cXMLHttpRequest.HEADERS_RECEIVED = 2; + cXMLHttpRequest.LOADING = 3; + cXMLHttpRequest.DONE = 4; + + // Interface level constants + cXMLHttpRequest.prototype.UNSENT = cXMLHttpRequest.UNSENT; + cXMLHttpRequest.prototype.OPENED = cXMLHttpRequest.OPENED; + cXMLHttpRequest.prototype.HEADERS_RECEIVED = cXMLHttpRequest.HEADERS_RECEIVED; + cXMLHttpRequest.prototype.LOADING = cXMLHttpRequest.LOADING; + cXMLHttpRequest.prototype.DONE = cXMLHttpRequest.DONE; // Public Properties - cXMLHttpRequest.prototype.readyState = cXMLHttpRequest.UNSENT; - cXMLHttpRequest.prototype.responseText = ''; - cXMLHttpRequest.prototype.responseXML = null; - cXMLHttpRequest.prototype.status = 0; - cXMLHttpRequest.prototype.statusText = ''; + cXMLHttpRequest.prototype.readyState = cXMLHttpRequest.UNSENT; + cXMLHttpRequest.prototype.responseText = ''; + cXMLHttpRequest.prototype.responseXML = null; + cXMLHttpRequest.prototype.status = 0; + cXMLHttpRequest.prototype.statusText = ''; + + // Priority proposal + cXMLHttpRequest.prototype.priority = "NORMAL"; // Instance-level Events Handlers - cXMLHttpRequest.prototype.onreadystatechange = null; + cXMLHttpRequest.prototype.onreadystatechange = null; // Class-level Events Handlers - cXMLHttpRequest.onreadystatechange = null; - cXMLHttpRequest.onopen = null; - cXMLHttpRequest.onsend = null; - cXMLHttpRequest.onabort = null; + cXMLHttpRequest.onreadystatechange = null; + cXMLHttpRequest.onopen = null; + cXMLHttpRequest.onsend = null; + cXMLHttpRequest.onabort = null; // Public Methods - cXMLHttpRequest.prototype.open = function(sMethod, sUrl, bAsync, sUser, sPassword) { + cXMLHttpRequest.prototype.open = function(sMethod, sUrl, bAsync, sUser, sPassword) { + // http://www.w3.org/TR/XMLHttpRequest/#the-open-method + var sLowerCaseMethod = sMethod.toLowerCase(); + if (sLowerCaseMethod == "connect" || sLowerCaseMethod == "trace" || sLowerCaseMethod == "track") { + // Using a generic error and an int - not too sure all browsers support correctly + // http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#securityerror, so, this is safer + // XXX should do better than that, but this is OT to XHR. + throw new Error(18); + } - // When bAsync parameter value is ommited, use true as default - if (arguments.length < 3) - bAsync = true; + // Delete headers, required when object is reused + delete this._headers; + + // When bAsync parameter value is omitted, use true as default + if (arguments.length < 3) { + bAsync = true; + } // Save async parameter for fixing Gecko bug with missing readystatechange in synchronous requests - this._async = bAsync; + this._async = bAsync; // Set the onreadystatechange handler - var oRequest = this, - nState = this.readyState, - fOnUnload; + var oRequest = this; + var nState = this.readyState; + var fOnUnload = null; // BUGFIX: IE - memory leak on page unload (inter-page leak) if (bIE && bAsync) { fOnUnload = function() { - if (oRequest._object.readyState != cXMLHttpRequest.DONE) { + if (nState != cXMLHttpRequest.DONE) { fCleanTransport(oRequest); // Safe to abort here since onreadystatechange handler removed oRequest.abort(); @@ -83,285 +126,411 @@ window.attachEvent("onunload", fOnUnload); } - this._object.onreadystatechange = function() { - if (bGecko && !bAsync) + // Add method sniffer + if (cXMLHttpRequest.onopen) { + cXMLHttpRequest.onopen.apply(this, arguments); + } + + if (arguments.length > 4) { + this._object.open(sMethod, sUrl, bAsync, sUser, sPassword); + } else if (arguments.length > 3) { + this._object.open(sMethod, sUrl, bAsync, sUser); + } else { + this._object.open(sMethod, sUrl, bAsync); + } + + this.readyState = cXMLHttpRequest.OPENED; + fReadyStateChange(this); + + this._object.onreadystatechange = function() { + if (bGecko && !bAsync) { return; + } // Synchronize state - oRequest.readyState = oRequest._object.readyState; - - // + oRequest.readyState = oRequest._object.readyState; fSynchronizeValues(oRequest); - // BUGFIX: Firefox fires unneccesary DONE when aborting + // BUGFIX: Firefox fires unnecessary DONE when aborting if (oRequest._aborted) { // Reset readyState to UNSENT - oRequest.readyState = cXMLHttpRequest.UNSENT; + oRequest.readyState = cXMLHttpRequest.UNSENT; // Return now return; } if (oRequest.readyState == cXMLHttpRequest.DONE) { - // + // Free up queue + delete oRequest._data; + + // Uncomment these lines for bAsync + /** + * if (bAsync) { + * fQueue_remove(oRequest); + * } + */ + fCleanTransport(oRequest); -// Uncomment this block if you need a fix for IE cache -/* - // BUGFIX: IE - cache issue - if (!oRequest._object.getResponseHeader("Date")) { - // Save object to cache - oRequest._cached = oRequest._object; - // Instantiate a new transport object - cXMLHttpRequest.call(oRequest); + // Uncomment this block if you need a fix for IE cache + /** + * // BUGFIX: IE - cache issue + * if (!oRequest._object.getResponseHeader("Date")) { + * // Save object to cache + * oRequest._cached = oRequest._object; + * + * // Instantiate a new transport object + * cXMLHttpRequest.call(oRequest); + * + * // Re-send request + * if (sUser) { + * if (sPassword) { + * oRequest._object.open(sMethod, sUrl, bAsync, sUser, sPassword); + * } else { + * oRequest._object.open(sMethod, sUrl, bAsync); + * } + * + * oRequest._object.setRequestHeader("If-Modified-Since", oRequest._cached.getResponseHeader("Last-Modified") || new window.Date(0)); + * // Copy headers set + * if (oRequest._headers) { + * for (var sHeader in oRequest._headers) { + * // Some frameworks prototype objects with functions + * if (typeof oRequest._headers[sHeader] == "string") { + * oRequest._object.setRequestHeader(sHeader, oRequest._headers[sHeader]); + * } + * } + * } + * oRequest._object.onreadystatechange = function() { + * // Synchronize state + * oRequest.readyState = oRequest._object.readyState; + * + * if (oRequest._aborted) { + * // + * oRequest.readyState = cXMLHttpRequest.UNSENT; + * + * // Return + * return; + * } + * + * if (oRequest.readyState == cXMLHttpRequest.DONE) { + * // Clean Object + * fCleanTransport(oRequest); + * + * // get cached request + * if (oRequest.status == 304) { + * oRequest._object = oRequest._cached; + * } + * + * // + * delete oRequest._cached; + * + * // + * fSynchronizeValues(oRequest); + * + * // + * fReadyStateChange(oRequest); + * + * // BUGFIX: IE - memory leak in interrupted + * if (bIE && bAsync) { + * window.detachEvent("onunload", fOnUnload); + * } + * + * } + * }; + * oRequest._object.send(null); + * + * // Return now - wait until re-sent request is finished + * return; + * }; + */ - // Re-send request - oRequest._object.open(sMethod, sUrl, bAsync, sUser, sPassword); - oRequest._object.setRequestHeader("If-Modified-Since", oRequest._cached.getResponseHeader("Last-Modified") || new window.Date(0)); - // Copy headers set - if (oRequest._headers) - for (var sHeader in oRequest._headers) - if (typeof oRequest._headers[sHeader] == "string") // Some frameworks prototype objects with functions - oRequest._object.setRequestHeader(sHeader, oRequest._headers[sHeader]); - - oRequest._object.onreadystatechange = function() { - // Synchronize state - oRequest.readyState = oRequest._object.readyState; - - if (oRequest._aborted) { - // - oRequest.readyState = cXMLHttpRequest.UNSENT; - - // Return - return; - } - - if (oRequest.readyState == cXMLHttpRequest.DONE) { - // Clean Object - fCleanTransport(oRequest); - - // get cached request - if (oRequest.status == 304) - oRequest._object = oRequest._cached; - - // - delete oRequest._cached; - - // - fSynchronizeValues(oRequest); - - // - fReadyStateChange(oRequest); - - // BUGFIX: IE - memory leak in interrupted - if (bIE && bAsync) - window.detachEvent("onunload", fOnUnload); - } - }; - oRequest._object.send(null); - - // Return now - wait untill re-sent request is finished - return; - }; -*/ // BUGFIX: IE - memory leak in interrupted - if (bIE && bAsync) + if (bIE && bAsync) { window.detachEvent("onunload", fOnUnload); + } + + // BUGFIX: Some browsers (Internet Explorer, Gecko) fire OPEN readystate twice + if (nState != oRequest.readyState) { + fReadyStateChange(oRequest); + } + + nState = oRequest.readyState; } - - // BUGFIX: Some browsers (Internet Explorer, Gecko) fire OPEN readystate twice - if (nState != oRequest.readyState) - fReadyStateChange(oRequest); - - nState = oRequest.readyState; }; - // Add method sniffer - if (cXMLHttpRequest.onopen) - cXMLHttpRequest.onopen.apply(this, arguments); - - if (arguments.length > 4) - this._object.open(sMethod, sUrl, bAsync, sUser, sPassword); - else - if (arguments.length > 3) - this._object.open(sMethod, sUrl, bAsync, sUser); - else - this._object.open(sMethod, sUrl, bAsync); - - // BUGFIX: Gecko - missing readystatechange calls in synchronous requests - if (!bAsync && bGecko) { - this.readyState = cXMLHttpRequest.OPENED; - - fReadyStateChange(this); - } }; - cXMLHttpRequest.prototype.send = function(vData) { + + cXMLHttpRequest.prototype.send = function(vData) { // Add method sniffer - if (cXMLHttpRequest.onsend) + if (cXMLHttpRequest.onsend) { cXMLHttpRequest.onsend.apply(this, arguments); + } + + if (!arguments.length) { + vData = null; + } // BUGFIX: Safari - fails sending documents created/modified dynamically, so an explicit serialization required // BUGFIX: IE - rewrites any custom mime-type to "text/xml" in case an XMLNode is sent // BUGFIX: Gecko - fails sending Element (this is up to the implementation either to standard) if (vData && vData.nodeType) { - vData = window.XMLSerializer ? new window.XMLSerializer().serializeToString(vData) : vData.xml; - if (!this._headers["Content-Type"]) + vData = window.XMLSerializer ? new window.XMLSerializer().serializeToString(vData) : vData.xml; + if (!this._headers["Content-Type"]) { this._object.setRequestHeader("Content-Type", "application/xml"); - } - - this._object.send(vData); - - // BUGFIX: Gecko - missing readystatechange calls in synchronous requests - if (bGecko && !this._async) { - this.readyState = cXMLHttpRequest.OPENED; - - // Synchronize state - fSynchronizeValues(this); - - // Simulate missing states - while (this.readyState < cXMLHttpRequest.DONE) { - this.readyState++; - fReadyStateChange(this); - // Check if we are aborted - if (this._aborted) - return; } } - }; - cXMLHttpRequest.prototype.abort = function() { - // Add method sniffer - if (cXMLHttpRequest.onabort) - cXMLHttpRequest.onabort.apply(this, arguments); - // BUGFIX: Gecko - unneccesary DONE when aborting - if (this.readyState > cXMLHttpRequest.UNSENT) - this._aborted = true; + this._data = vData; + + /** + * // Add to queue + * if (this._async) { + * fQueue_add(this); + * } else { */ + fXMLHttpRequest_send(this); + /** + * } + */ + }; + + cXMLHttpRequest.prototype.abort = function() { + // Add method sniffer + if (cXMLHttpRequest.onabort) { + cXMLHttpRequest.onabort.apply(this, arguments); + } + + // BUGFIX: Gecko - unnecessary DONE when aborting + if (this.readyState > cXMLHttpRequest.UNSENT) { + this._aborted = true; + } this._object.abort(); // BUGFIX: IE - memory leak fCleanTransport(this); + + this.readyState = cXMLHttpRequest.UNSENT; + + delete this._data; + + /* if (this._async) { + * fQueue_remove(this); + * } + */ }; - cXMLHttpRequest.prototype.getAllResponseHeaders = function() { + + cXMLHttpRequest.prototype.getAllResponseHeaders = function() { return this._object.getAllResponseHeaders(); }; - cXMLHttpRequest.prototype.getResponseHeader = function(sName) { + + cXMLHttpRequest.prototype.getResponseHeader = function(sName) { return this._object.getResponseHeader(sName); }; - cXMLHttpRequest.prototype.setRequestHeader = function(sName, sValue) { + + cXMLHttpRequest.prototype.setRequestHeader = function(sName, sValue) { // BUGFIX: IE - cache issue - if (!this._headers) - this._headers = {}; - this._headers[sName] = sValue; + if (!this._headers) { + this._headers = {}; + } + + this._headers[sName] = sValue; return this._object.setRequestHeader(sName, sValue); }; // EventTarget interface implementation - cXMLHttpRequest.prototype.addEventListener = function(sName, fHandler, bUseCapture) { - for (var nIndex = 0, oListener; oListener = this._listeners[nIndex]; nIndex++) - if (oListener[0] == sName && oListener[1] == fHandler && oListener[2] == bUseCapture) + cXMLHttpRequest.prototype.addEventListener = function(sName, fHandler, bUseCapture) { + for (var nIndex = 0, oListener; oListener = this._listeners[nIndex]; nIndex++) { + if (oListener[0] == sName && oListener[1] == fHandler && oListener[2] == bUseCapture) { return; + } + } + // Add listener this._listeners.push([sName, fHandler, bUseCapture]); }; - cXMLHttpRequest.prototype.removeEventListener = function(sName, fHandler, bUseCapture) { - for (var nIndex = 0, oListener; oListener = this._listeners[nIndex]; nIndex++) - if (oListener[0] == sName && oListener[1] == fHandler && oListener[2] == bUseCapture) + cXMLHttpRequest.prototype.removeEventListener = function(sName, fHandler, bUseCapture) { + for (var nIndex = 0, oListener; oListener = this._listeners[nIndex]; nIndex++) { + if (oListener[0] == sName && oListener[1] == fHandler && oListener[2] == bUseCapture) { break; + } + } + // Remove listener - if (oListener) + if (oListener) { this._listeners.splice(nIndex, 1); + } }; - cXMLHttpRequest.prototype.dispatchEvent = function(oEvent) { - var oEvent = { - 'type': oEvent.type, - 'target': this, - 'currentTarget':this, - 'eventPhase': 2, - 'bubbles': oEvent.bubbles, - 'cancelable': oEvent.cancelable, - 'timeStamp': oEvent.timeStamp, - 'stopPropagation': function() {}, // There is no flow - 'preventDefault': function() {}, // There is no default action - 'initEvent': function() {} // Original event object should be inited + cXMLHttpRequest.prototype.dispatchEvent = function(oEvent) { + var oEventPseudo = { + 'type': oEvent.type, + 'target': this, + 'currentTarget': this, + 'eventPhase': 2, + 'bubbles': oEvent.bubbles, + 'cancelable': oEvent.cancelable, + 'timeStamp': oEvent.timeStamp, + 'stopPropagation': function() {}, // There is no flow + 'preventDefault': function() {}, // There is no default action + 'initEvent': function() {} // Original event object should be initialized }; // Execute onreadystatechange - if (oEvent.type == "readystatechange" && this.onreadystatechange) - (this.onreadystatechange.handleEvent || this.onreadystatechange).apply(this, [oEvent]); + if (oEventPseudo.type == "readystatechange" && this.onreadystatechange) { + (this.onreadystatechange.handleEvent || this.onreadystatechange).apply(this, [oEventPseudo]); + } + // Execute listeners - for (var nIndex = 0, oListener; oListener = this._listeners[nIndex]; nIndex++) - if (oListener[0] == oEvent.type && !oListener[2]) - (oListener[1].handleEvent || oListener[1]).apply(this, [oEvent]); + for (var nIndex = 0, oListener; oListener = this._listeners[nIndex]; nIndex++) { + if (oListener[0] == oEventPseudo.type && !oListener[2]) { + (oListener[1].handleEvent || oListener[1]).apply(this, [oEventPseudo]); + } + } + }; // - cXMLHttpRequest.prototype.toString = function() { + cXMLHttpRequest.prototype.toString = function() { return '[' + "object" + ' ' + "XMLHttpRequest" + ']'; }; - cXMLHttpRequest.toString = function() { + cXMLHttpRequest.toString = function() { return '[' + "XMLHttpRequest" + ']'; }; + /** + * // Queue manager + * var oQueuePending = {"CRITICAL":[],"HIGH":[],"NORMAL":[],"LOW":[],"LOWEST":[]}, + * aQueueRunning = []; + * function fQueue_add(oRequest) { + * oQueuePending[oRequest.priority in oQueuePending ? oRequest.priority : "NORMAL"].push(oRequest); + * // + * setTimeout(fQueue_process); + * }; + * + * function fQueue_remove(oRequest) { + * for (var nIndex = 0, bFound = false; nIndex < aQueueRunning.length; nIndex++) + * if (bFound) { + * aQueueRunning[nIndex - 1] = aQueueRunning[nIndex]; + * } else { + * if (aQueueRunning[nIndex] == oRequest) { + * bFound = true; + * } + * } + * + * if (bFound) { + * aQueueRunning.length--; + * } + * + * + * // + * setTimeout(fQueue_process); + * }; + * + * function fQueue_process() { + * if (aQueueRunning.length < 6) { + * for (var sPriority in oQueuePending) { + * if (oQueuePending[sPriority].length) { + * var oRequest = oQueuePending[sPriority][0]; + * oQueuePending[sPriority] = oQueuePending[sPriority].slice(1); + * // + * aQueueRunning.push(oRequest); + * // Send request + * fXMLHttpRequest_send(oRequest); + * break; + * } + * } + * } + * }; + */ + // Helper function + function fXMLHttpRequest_send(oRequest) { + oRequest._object.send(oRequest._data); + + // BUGFIX: Gecko - missing readystatechange calls in synchronous requests + if (bGecko && !oRequest._async) { + oRequest.readyState = cXMLHttpRequest.OPENED; + + // Synchronize state + fSynchronizeValues(oRequest); + + // Simulate missing states + while (oRequest.readyState < cXMLHttpRequest.DONE) { + oRequest.readyState++; + fReadyStateChange(oRequest); + // Check if we are aborted + if (oRequest._aborted) { + return; + } + } + } + } + function fReadyStateChange(oRequest) { // Sniffing code - if (cXMLHttpRequest.onreadystatechange) + if (cXMLHttpRequest.onreadystatechange){ cXMLHttpRequest.onreadystatechange.apply(oRequest); + } + // Fake event oRequest.dispatchEvent({ - 'type': "readystatechange", - 'bubbles': false, - 'cancelable': false, - 'timeStamp': new Date + 0 + 'type': "readystatechange", + 'bubbles': false, + 'cancelable': false, + 'timeStamp': new Date().getTime() }); - }; + } function fGetDocument(oRequest) { - var oDocument = oRequest.responseXML; + var oDocument = oRequest.responseXML; + var sResponse = oRequest.responseText; // Try parsing responseText - if (bIE && oDocument && !oDocument.documentElement && oRequest.getResponseHeader("Content-Type").match(/[^\/]+\/[^\+]+\+xml/)) { - oDocument = new window.ActiveXObject("Microsoft.XMLDOM"); - oDocument.loadXML(oRequest.responseText); + if (bIE && sResponse && oDocument && !oDocument.documentElement && oRequest.getResponseHeader("Content-Type").match(/[^\/]+\/[^\+]+\+xml/)) { + oDocument = new window.ActiveXObject("Microsoft.XMLDOM"); + oDocument.async = false; + oDocument.validateOnParse = false; + oDocument.loadXML(sResponse); } + // Check if there is no error in document - if (oDocument) - if ((bIE && oDocument.parseError != 0) || !oDocument.documentElement || (oDocument.documentElement && oDocument.documentElement.tagName == "parsererror")) + if (oDocument){ + if ((bIE && oDocument.parseError != 0) || !oDocument.documentElement || (oDocument.documentElement && oDocument.documentElement.tagName == "parsererror")) { return null; + } + } return oDocument; - }; + } function fSynchronizeValues(oRequest) { - try { oRequest.responseText = oRequest._object.responseText; } catch (e) {} - try { oRequest.responseXML = fGetDocument(oRequest._object); } catch (e) {} - try { oRequest.status = oRequest._object.status; } catch (e) {} - try { oRequest.statusText = oRequest._object.statusText; } catch (e) {} - }; + try { oRequest.responseText = oRequest._object.responseText; } catch (e) {} + try { oRequest.responseXML = fGetDocument(oRequest._object); } catch (e) {} + try { oRequest.status = oRequest._object.status; } catch (e) {} + try { oRequest.statusText = oRequest._object.statusText; } catch (e) {} + } function fCleanTransport(oRequest) { // BUGFIX: IE - memory leak (on-page leak) - oRequest._object.onreadystatechange = new window.Function; - - // Delete private properties - delete oRequest._headers; - }; + oRequest._object.onreadystatechange = new window.Function; + } // Internet Explorer 5.0 (missing apply) if (!window.Function.prototype.apply) { - window.Function.prototype.apply = function(oRequest, oArguments) { - if (!oArguments) - oArguments = []; - oRequest.__func = this; + window.Function.prototype.apply = function(oRequest, oArguments) { + if (!oArguments) { + oArguments = []; + } + oRequest.__func = this; oRequest.__func(oArguments[0], oArguments[1], oArguments[2], oArguments[3], oArguments[4]); delete oRequest.__func; }; - }; + } // Register new object with window - window.XMLHttpRequest = cXMLHttpRequest; + window.XMLHttpRequest = cXMLHttpRequest; + })();