To make custom builds easier, it's convenient to have a OpenLayers.Request depend on OpenLayers.Request.XMLHttpRequest (see 18b4d6808d). This makes it so we don't know which is going to be included first. To get around this, we can be careful about when we define OpenLayers.Request.
459 lines
17 KiB
JavaScript
459 lines
17 KiB
JavaScript
// 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;
|
|
})();
|