|
The Gravey 2.0 Framework | |||||||
| PREV NEXT | FRAMES NO FRAMES | |||||||
Collection of AJAX support routines.
Version: 2.0
Requires:
| Class Summary | |
| XMLreq | Constructor for XMLreq "object" which encapsulates a REST-style request/reply transaction that returns XML or Text. |
| Method Summary | |
static Object
|
grvGetXslDOM( xslURL )
retrieve XSL DOM from given URL |
static String
|
grvXformDOM( xslDOM, xmlDOM )
transform given XML DOM using given XSLT DOM |
static String
|
grvXformURL( xslURL, xmlDOM )
transform given XML DOM using an XSLT retrieved from given URL |
// This file uses JSDoc-friendly comments [ http://jsdoc.sourceforge.net/ ] /** * @file grvAJAX.js * @fileoverview Collection of AJAX support routines. * @author Bruce Wallace (PolyGlotInc.com) * @requires grvUtils.js * @requires grvValidate.js * @version 2.0 */ ////////////////////////////////////////////////////////////////// // GRAVEY LEXICAL CODING CONVENTIONS: // (*) All private variables or functions start with "_" // (*) All variables and functions start with a lowercase letter // (*) All Classes start with an uppercase letter // (*) All Class methods and instance variables start with lowercase // (*) All Class "static" methods and variables start with uppercase // (*) All constants start with "k" // (*) All global variables start with "g" // (*) All event handler functions start with "on" // // (*) All Gravey utility global variables start with "gGrv" // (*) All Gravey MVC global variables start with "gMVC" // (*) All Gravey EDO global variables start with "gEDO" // (*) All Gravey utility functions start with "grv" // (*) All Gravey MVC functions start with "mvc" // (*) All Gravey MVC event handler functions start with "onMVC" // (*) All Gravey EDO event handler functions start with "onEDO" // (*) All Gravey MVC classes start with "MVC" // (*) All Gravey EDO classes start with "EDO" ////////////////////////////////////////////////////////////////// Class(XMLreq,["url"]); /** * @class Constructor for XMLreq "object" which encapsulates a REST-style * request/reply transaction that returns XML or Text. This class makes * multiple simultaneous requests possible, however, a separate instance * of this class is required for each request. This constructor will * automatically cause this request to be immediately launched unless * launch is suppressed.<p> * If post data is defined then this request is made via a POST (otherwise * via a GET) HTTP request.<p> * Any instance of this class can be created in "test mode" that reads * XML directly from an XML file rather than making a POST/GET request for XML. * This class has helper methods that will transform the response XML via * an XSL document specified via filename or URL. * @author Bruce Wallace (PolyGlotInc.com) * @version 2.0 */ function XMLreq() { /** * @param {String} url the URL to request XML from (or XML file path in test mode) * @param {Function} userCallbackFunction the callback to handle the XML when it arrives * [note: The callback will have this XMLreq object passed to it via * both "this", and, as a single function argument.] * @param {String} optPostData optional post data string (should be "undefined" if not a POST req.) * @param {boolean} optWaitFlag optional "wait for reply" flag (i.e. DONT do this async if true) * @param {boolean} optSuppressLaunchFlag optional "suppress launch" flag * @param {boolean} optTestFlag optional "read test files" flag (i.e. read XML file rather than ask server) * @throws ErrMsg if missing required parameter(s) */ this.konstructor = function( url, userCallbackFunction, optPostData, optWaitFlag, optTestFlag, optSuppressLaunchFlag ) { // initialize instance data this.name = "XMLreq" + grvTimestamp(); //mostly unique name this.url = url; this.post = optPostData; this.test = grvIsUndefined(optTestFlag) ? _kGrvAjaxTestData : optTestFlag; this.async = optWaitFlag?false:true; this.usercb = userCallbackFunction || function(){ grvError("Unhandled Reply=["+this.getResponseText()+"]"); }; this.cb = new Function( "grvGetGlobalVar(\""+ this.name +"\").cbwrapper()" ); // save reference to "this" in page-level variable (to be retrieved in callback) grvSetGlobalVar( this.name, this ); if (!optSuppressLaunchFlag) this.launch(); } /** method to return "this" as a human-readable string @type String */ this.toString = function(){ return grvObjectToString(this); } /** method to create new XMLHttpRequest object for "this" request * @return "XMLHttpRequest object" @type Object * @throws ErrMsg if XML Request Objects arent supported by Browser */ this.newRequestObj = function() { function getObj( xmlReq ) { // if in test mode, return an XML document if (xmlReq.test){ var XMLDoc = new ActiveXObject("MSXML2.DOMDocument"); XMLDoc.async = xmlReq.async; return XMLDoc; } // has native XMLHttpRequest object? if (window.XMLHttpRequest) return new XMLHttpRequest(); // has IE/Windows ActiveX version? if (window.ActiveXObject) { try { return new ActiveXObject("Msxml2.XMLHTTP" ); } catch(e) { return new ActiveXObject("Microsoft.XMLHTTP"); } } throw "XML Request Objects are not supported by this Browser."; } var o = getObj( this ); o.onreadystatechange = this.cb; return o; } /** callback wrapper method to relieve user callback from gory details of * XMLHttpRequest state transition handling. */ this.cbwrapper = function() { // Once send() has been called, XMLHttpRequest will contact the server // and retrieve the data we requested; however, this process takes an // indeterminate amount of time. In order to find out when the object // has finished retrieving data, we must use an event listener. In the // case of an XMLHttpRequest object, we need to listen for changes in // its readyState variable. This variable specifies the status of the // object's connection, and can be any of the following: // 0 - Uninitialised // 1 - Loading // 2 - Loaded // 3 - Interactive // 4 - Completed // if (this.obj.readyState == 4) { // readyState increments from 0 to 4, and the onreadystatechange // event is triggered for each increment, but we really only want // to know when the connection has completed (4), so our handling // function needs to realise this. Upon the connection's completion, // we also have to check whether the XMLHttpRequest object success- // fully retrieved the data, or was given an error code, such as // 404: "Page not found". This can be determined from the object's // status property, which contains an integer code. "200" denotes // a successful completion, but this value can be any of the HTTP // codes that servers may return. If the request was not successful, // we must specify a course of action. // if (this.test || this.obj.status == 200) { this.usercb( this ); //support both method and subroutine calls grvClearGlobalVar( this.name ); //we are done so clean up persistence store } // IE returns a status code of 0 on some occasions, so ignore this case else if (this.obj.status == 0) grvBreak("DEBUG:zero xml status! msg["+ this.obj.statusText +"] for ["+this.name+"]"); else grvError( "Bad XML retrieve status["+ this.obj.statusText +"] for ["+this.name+"]"); } } /** method to launch "this" request using the following logic;<pre> * To send CGI variables using the GET request method, we have to * hardcode the variables into the open URL parameter: * this.open("GET", "/query.cgi?name=Bob&email=bob@example.com"); * this.send(null); * To send CGI variables using the POST request method, we have to * pass the variables to the send() method: * this.open("POST", "/query.cgi"); * this.send("name=Bob&email=bob@example.com"); *</pre> */ this.launch = function() { // Even though the XMLHttpRequest object allows us to call the open() // method multiple times, each object can really only be used for one // call, as the onreadystatechange event doesn't update again once // readyState changes to "4" (in Mozilla). Therefore, we have to create // a new XMLHttpRequest object every time we want to make a remote call. // this.obj = this.newRequestObj(); if (this.test) { this.obj.load( this.url ); return; } // open() initialises the connection we wish to make, and takes two // arguments, with several optionals. The first argument is the type // of request we want to send; the second argument identifies the // location from which we wish to request data. For instance, if we // wanted to use a GET request to access feed.xml at the root of our // server, we'd initialise the XMLHttpRequest object like this: // xmlReq.open("GET", "/feed.xml"); // The URL can be either relative or absolute, but due to cross-domain // security concerns, the target must reside on the same domain as the // page that requests it. // The open() method also takes an optional third boolean argument that // specifies whether the request is made asynchronously (true, the default) // or synchronously (false). With a synchronous request, the browser will // freeze, disallowing any user interaction, until the object has completed. // An asynchronous request occurs in the background, allowing other scripts // to run and letting the user continue to access their browser. It's // recommended that you use asynchronous requests; otherwise, we run the // risk of a user's browser locking up while they wait for a request that // went awry. open()'s optional fourth and fifth arguments are a username // and password for authentication when accessing a password-protected URL. // this.obj.open( this.post?"POST":"GET", this.url, this.async ); // if POST, we tell the server to expect form-type parameters if (this.post) this.obj.setRequestHeader("Content-Type","application/x-www-form-urlencoded;"); // Once open() has been used to initialise a connection, the send() method // activates the connection and makes the request. send() takes one argument, // allowing us to send extra data, such as CGI variables, along with the // call. Internet Explorer treats it as optional, but Mozilla will return // an error if no value is passed, so it's safest to call it using: // xmlReq.send(null); this.obj.send( this.post ? this.post : null ); } /** get XML returned in the reply to "this" xml request * @return XML DOM @type Object */ this.getResponseXML = function() { // return a DOM-structured object of any XML data that was // retrieved by the request. This object is navigable using // the standard JavaScript DOM access methods and properties, // such as getElementsByTagName(), childNodes[] and parentNode. // return this.test ? this.obj : this.obj.responseXML; } /** get text returned in the reply to "this" xml request * @type String */ this.getResponseText = function() { // return the data as one complete string. If the content // type of the data supplied by the server was text/plain // or text/html, then this is the only property that will // contain data. A copy of any text/xml data will be flattened // and placed here as an alternative to responseXML. // return this.test ? null : this.obj.responseText; } /** return the output from transforming the response XML * with the XSL in the specified URL/filename * @type String * @throws ErrMsg on fatal error */ this.xform = function( xslURL ) { return grvXformURL( xslURL, this.getResponseXML() ); } /** return the output from transforming the response XML * with the XSL in the specified XSL DOM * @type String * @throws ErrMsg on fatal error */ this.xform2 = function( xslDOM ) { return grvXformDOM( xslDOM, this.getResponseXML() ); } } ////////////////////////////////////////////////////////////// // Process XML via browser-side XSL... ////////////////////////////////////////////////////////////// /** retrieve XSL DOM from given URL * @return XSL DOM @type Object */ function grvGetXslDOM( xslURL ) { // load XSLT stylesheet document var xslDOM = new ActiveXObject("Msxml2.DOMDocument"); xslDOM.async = false; xslDOM.load( xslURL ); if (xslDOM.parseError.errorCode != 0) { var myErr = xmlDoc.parseError; grvError("Error loading["+xslURL+"]: " + myErr.reason); } return xslDOM; } /** transform given XML DOM using given XSLT DOM * @return transformed XML @type String * @throws ErrMsg on fatal error */ function grvXformDOM( xslDOM, xmlDOM ){ if (xslDOM.parseError.errorCode != 0) throw "XSL was not successfully loaded; errcode="+xslDOM.parseError.errorCode; return xmlDOM.transformNode( xslDOM ); } /** transform given XML DOM using an XSLT retrieved from given URL * @return transformed XML @type String * @throws ErrMsg on fatal error */ function grvXformURL( xslURL, xmlDOM ){ return grvXformDOM( grvGetXslDOM(xslURL), xmlDOM ); }
|
The Gravey 2.0 Framework | |||||||
| PREV NEXT | FRAMES NO FRAMES | |||||||