/** * 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