diff options
Diffstat (limited to 'misc/openlayers/lib/OpenLayers/Request/XMLHttpRequest.js')
-rw-r--r-- | misc/openlayers/lib/OpenLayers/Request/XMLHttpRequest.js | 458 |
1 files changed, 458 insertions, 0 deletions
diff --git a/misc/openlayers/lib/OpenLayers/Request/XMLHttpRequest.js b/misc/openlayers/lib/OpenLayers/Request/XMLHttpRequest.js new file mode 100644 index 0000000..21200a6 --- /dev/null +++ b/misc/openlayers/lib/OpenLayers/Request/XMLHttpRequest.js @@ -0,0 +1,458 @@ +// XMLHttpRequest.js Copyright (C) 2010 Sergey Ilinsky (http://www.ilinsky.com) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @requires OpenLayers/Request.js + */ + +(function () { + + // Save reference to earlier defined object implementation (if any) + var oXMLHttpRequest = window.XMLHttpRequest; + + // Define on browser type + var bGecko = !!window.controllers, + bIE = window.document.all && !window.opera, + bIE7 = bIE && window.navigator.userAgent.match(/MSIE 7.0/); + + // Enables "XMLHttpRequest()" call next to "new XMLHttpReques()" + function fXMLHttpRequest() { + this._object = oXMLHttpRequest && !bIE7 ? new oXMLHttpRequest : new window.ActiveXObject("Microsoft.XMLHTTP"); + this._listeners = []; + }; + + // Constructor + function cXMLHttpRequest() { + 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; + + // Constants + cXMLHttpRequest.UNSENT = 0; + cXMLHttpRequest.OPENED = 1; + cXMLHttpRequest.HEADERS_RECEIVED = 2; + cXMLHttpRequest.LOADING = 3; + cXMLHttpRequest.DONE = 4; + + // Public Properties + 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; + + // Class-level Events Handlers + cXMLHttpRequest.onreadystatechange = null; + cXMLHttpRequest.onopen = null; + cXMLHttpRequest.onsend = null; + cXMLHttpRequest.onabort = null; + + // Public Methods + cXMLHttpRequest.prototype.open = function(sMethod, sUrl, bAsync, sUser, sPassword) { + // 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; + + // Set the onreadystatechange handler + var oRequest = this, + nState = this.readyState, + fOnUnload; + + // BUGFIX: IE - memory leak on page unload (inter-page leak) + if (bIE && bAsync) { + fOnUnload = function() { + if (nState != cXMLHttpRequest.DONE) { + fCleanTransport(oRequest); + // Safe to abort here since onreadystatechange handler removed + oRequest.abort(); + } + }; + window.attachEvent("onunload", fOnUnload); + } + + // 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; + + // + fSynchronizeValues(oRequest); + + // BUGFIX: Firefox fires unnecessary DONE when aborting + if (oRequest._aborted) { + // Reset readyState to UNSENT + oRequest.readyState = cXMLHttpRequest.UNSENT; + + // Return now + return; + } + + if (oRequest.readyState == cXMLHttpRequest.DONE) { + // Free up queue + delete oRequest._data; +/* 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); + + // Re-send request + if (sUser) { + if (sPassword) + oRequest._object.open(sMethod, sUrl, bAsync, sUser, sPassword); + else + oRequest._object.open(sMethod, sUrl, bAsync, sUser); + } + 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) + 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 until re-sent request is finished + return; + }; +*/ + // BUGFIX: IE - memory leak in interrupted + 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; + } + }; + 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; + } + } + }; + cXMLHttpRequest.prototype.send = function(vData) { + // Add method sniffer + 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"]) + this._object.setRequestHeader("Content-Type", "application/xml"); + } + + 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() { + return this._object.getAllResponseHeaders(); + }; + cXMLHttpRequest.prototype.getResponseHeader = function(sName) { + return this._object.getResponseHeader(sName); + }; + cXMLHttpRequest.prototype.setRequestHeader = function(sName, sValue) { + // BUGFIX: IE - cache issue + 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) + 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) + break; + // Remove listener + if (oListener) + this._listeners.splice(nIndex, 1); + }; + + 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 (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] == oEventPseudo.type && !oListener[2]) + (oListener[1].handleEvent || oListener[1]).apply(this, [oEventPseudo]); + }; + + // + cXMLHttpRequest.prototype.toString = function() { + return '[' + "object" + ' ' + "XMLHttpRequest" + ']'; + }; + + cXMLHttpRequest.toString = function() { + return '[' + "XMLHttpRequest" + ']'; + }; + + // Helper function + function fReadyStateChange(oRequest) { + // Sniffing code + if (cXMLHttpRequest.onreadystatechange) + cXMLHttpRequest.onreadystatechange.apply(oRequest); + + // Fake event + oRequest.dispatchEvent({ + 'type': "readystatechange", + 'bubbles': false, + 'cancelable': false, + 'timeStamp': new Date + 0 + }); + }; + + function fGetDocument(oRequest) { + var oDocument = oRequest.responseXML, + sResponse = oRequest.responseText; + // Try parsing 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")) + 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) {} + }; + + function fCleanTransport(oRequest) { + // BUGFIX: IE - memory leak (on-page leak) + oRequest._object.onreadystatechange = new window.Function; + }; +/* + // 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; + } + } + } + }; +*/ + // Internet Explorer 5.0 (missing apply) + if (!window.Function.prototype.apply) { + 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 + /** + * Class: OpenLayers.Request.XMLHttpRequest + * Standard-compliant (W3C) cross-browser implementation of the + * XMLHttpRequest object. From + * http://code.google.com/p/xmlhttprequest/. + */ + if (!OpenLayers.Request) { + /** + * This allows for OpenLayers/Request.js to be included + * before or after this script. + */ + OpenLayers.Request = {}; + } + OpenLayers.Request.XMLHttpRequest = cXMLHttpRequest; +})(); |