/**
* DataRequestor Class v: 1.7 - April 16, 2007
*
* Copyright 2007 - Mike West - http://mikewest.org/
*
* This software is licensed under the CC-GNU LGPL
*
* This class wraps the XMLHttpRequest object with a friendly API
* that makes complicated data requests trivial to impliment in
* your application.
*
* USAGE:
* ----
* BASIC
* To instantiate the object, simply call it as a constructor:
*
* var req = new DataRequestor();
*
* Once you have the object instantiated, your usage will depend
* on your needs.
*
* RETURNING TEXT
* If you want to grab data, and shove it wholesale into an element
* on the page (which I do 90% of the time), then tell the DataRequestor
* object where to stick the info by passing setObjToReplace an
* element ID or object reference, and call getURL to complete the
* process:
*
* req.setObjToReplace('objID');
* req.getURL(url);
*
*
* RETURNING A DOM OBJECT
* By default, the contents of the requested file will be passed in as
* plaintext, which can be simpler to work with than a real DOM object.
* If you'd like a DOM object to work with, then call getURL with
* _RETURN_AS_DOM as the second argument:
*
* req.getURL(url, _RETURN_AS_DOM);
*
* To avoid irritating problems, make sure you're sending a Content-type header
* of "text/xml" when you'd like your data processed as a DOM object. IE gets
* confused otherwise.
*
* RETURNING A JSON OBJECT
* If you've no idea what JSON is, visit http://www.json.org/
*
* To get a JavaScript object back from DataRequestor, call getURL with
* with _RETURN_AS_JSON as the second parameter.
*
* req.getURL(url, _RETURN_AS_JSON);
*
* This, of course, assumes that you've generated a JSON string correctly
* at the URL you've requested.
* ----
* ARGUMENTS
*
* To pass in GET or POST variables along with your request, use the
* addArg method:
*
* req.addArg(argType, argName, argValue);
* e.g.
* req.addArg(_GET, "argument_number", "1");
*
* addArg will automatically call escape() on the name and value to
* ensure they are URL escaped correctly.
*
* ARGUMENTS FROM A FORM
*
* To pass in all the arguments from a form, use the `addArgsFromForm`
* method. This will automatically call `addArg` on each of the form
* elements using the `method` attribute of the form to set the request
* method for the arguments. Each form element *must* have an ID for this
* method to function correctly.
*
* req.addArgsFromForm(formID);
* e.g.
* req.addArgsFromForm("myFormName");
* ----
* EVENT HANDLERS
*
* ON LOAD
*
* To take action when the data loads successfully, set onload to a function that
* takes two arguments: data, and obj. This will be called upon successful retrieval
* of the requested information, and will be passed the data retrieves and the object
* that will be replaced (or null if no replacement has been requested).
*
* req.onload = function (data, obj) {
* alert("Callback handler called with the following data: \n" + data);
* }
*
* The first parameter (`data`) will be one of three things:
* - text: If getURL was called without a second argument, or _RETURN_AS_TEXT,
* then `data` contains the raw text returned by the page that you loaded.
*
* - DOM object: If getURL was called with _RETURN_AS_DOM as the second argument, then
* `data` contains a DOM object, with blank whitespace nodes removed in order to
* provide a consistant experience between browsers that support the DOM standard
* and IE.
*
* - JavaScript object: If getURL was called with _RETURN_AS_JSON as the second argument,
* then `data` contains a JavaScript object generated from the JSON text that was returned
* by the page you loaded.
*
* ON REPLACE
*
* If you requested a replacement by setting an `objToReplace`, then this handler will
* be called directly after the replacement occurs, and will be passed the same variables
* as the `onload` method.
*
* req.onreplace = function (data, obj) {
* alert("Callback handler called with the following data: \n" + data);
* }
*
* ERROR HANDLING
*
* If the request fails, the XMLRequestor object defaults to simply throwing
* an error. If that's not a great solution for you, then assign a function
* to onfail that accepts a single variable: the XMLHttpRequest status
* code. If the status returned is "-1", then DataRequester encountered
* an error it didn't know what to do with. In this case, it will pass a
* second argument: the text of the thrown error. Do with it what you will:
*
* req.onfail = function (status) {
* alert("The handler died with a status of " + status);
* }
*
* PROGRESS
*
* In Mozilla, it's possible to dynamically retrieve the amount of data that
* has been downloaded so far. If you'd like to take an action on that data
* (e.g. set up some sort of progress bar) then set an onprogress handler that
* accepts two arguments, currentLength and totalLength. Curiously enough,
* these arguments will be populated with the current amount of data that's been
* retrieved and the total size (or -1 if it can't be detected)
*
* req.onprogress = function (current, total) {
* alert(current + " of " + total + " = " + ((total - current)/total) + "%");
* }
*
*/
var _RETURN_AS_JSON = 2;
var _RETURN_AS_TEXT = 1;
var _RETURN_AS_DOM = 0;
var _POST = 0;
var _GET = 1;
var _CACHE = 0;
var _NO_CACHE = 1;
function DataRequestor() {
var self = this; // workaround for scope errors: see http://www.crockford.com/javascript/private.html
/**
* Create XMLHttpRequest object: handles branching between
* versions of IE and other browers. Inital version from:
* http://jibbering.com/2002/4/httprequest.html (GREAT resource)
*
* later version adapted from:
* http://jpspan.sourceforge.net/wiki/doku.php?id=javascript:xmlhttprequest:behaviour:httpheaders
*
* @return the XMLHttpRequest object
*/
this.getXMLHTTP = function() {
var xmlHTTP = null;
try {
xmlHTTP = new XMLHttpRequest();
} catch (e) {
try {
xmlHTTP = new ActiveXObject("Msxml2.XMLHTTP")
} catch(e) {
var success = false;
var MSXML_XMLHTTP_PROGIDS = new Array(
'Microsoft.XMLHTTP',
'MSXML2.XMLHTTP',
'MSXML2.XMLHTTP.5.0',
'MSXML2.XMLHTTP.4.0',
'MSXML2.XMLHTTP.3.0'
);
for (var i=0;i < MSXML_XMLHTTP_PROGIDS.length && !success; i++) {
try {
xmlHTTP = new ActiveXObject(MSXML_XMLHTTP_PROGIDS[i]);
success = true;
} catch (e) {
xmlHTTP = null;
}
}
}
}
self._XML_REQ = xmlHTTP;
return self._XML_REQ;
}
/**
* Starts the request for a url. XMLHttpRequest will call
* the default callback method when the request is complete
* @param url the URL to request: absolute or relative will work
* @param return optional arg: defaults to _RETURN_AS_TEXT. if set to _RETURN_AS_DOM, will return a DOM object instead of a string
* @return true
*/
this.getURL = function(url) {
if (self.onLoad) {
self.onload = self.onLoad;
}
if (self.onReplace) {
self.onreplace = self.onReplace;
}
if (self.onProgress) {
self.onprogress = self.onProgress;
}
if (self.onFail) {
self.onfail = self.onFail;
}
self.userModifiedData = ""; // clear user modified data;
// DID THE USER WANT A DOM OBJECT, OR JUST THE TEXT OF THE REQUESTED DOCUMENT?
switch (arguments[1])
{
case _RETURN_AS_DOM:
case _RETURN_AS_TEXT:
case _RETURN_AS_JSON:
self.returnType = arguments[1];
break;
default:
self.returnType = _RETURN_AS_TEXT;
}
// CLEAR OUT ANY CURRENTLY ACTIVE REQUESTS
if ((typeof self._XML_REQ.abort) != "undefined" && self._XML_REQ.readyState!=0) { // Opera can't abort().
self._XML_REQ.abort();
}
// SET THE STATE CHANGE FUNCTION
self._XML_REQ.onreadystatechange = self.callback;
// GENERATE THE POST AND GET STRINGS
var requestType = "GET";
var getUrlString = (url.indexOf("?") != -1)?"&":"?";
for (i=0;i