Subversion Repositories JSX

Compare Revisions

Last modification

Ignore whitespace Rev 142 → Rev 143

/trunk/httprequest.js
1,6 → 1,6
/**
* @require
* types.js for #isMethod(),
* @requires
* object.js for jsx.object#isMethod(),
* string.js for #esc(), #escURI()
*
* @idl
24,19 → 24,19
* void HTTPRequest(string sURL);
* // URL=sURL||document.URL, method="GET", async=true, responseHandler=null,
* // errorHandler=null
*
*
* void HTTPRequest(string sURL, string sMethod);
* // URL=sURL||document.URL, method=sMethod||"GET", async=true,
* // responseHandler=null, errorHandler=null
*
*
* void HTTPRequest(string sURL, string sMethod, boolean bAsync);
* // URL=sURL||document.URL, method=sMethod||"GET", async=bAsync,
* // URL=sURL||document.URL, method=sMethod||"GET", async=bAsync,
*
* void HTTPRequest(string sURL, string sMethod, boolean bAsync,
* HTTPResponseHandler fResponseHandler);
* // URL=sURL||document.URL, method=sMethod||"GET", async=bAsync,
* // responseHandler=fResponseHandler, errorHandler=null
*
* // responseHandler=fResponseHandler, errorHandler=null
*
* void HTTPRequest(string sURL, string sMethod, boolean bAsync,
* HTTPResponseHandler fResponseHandler,
* HTTPResponseHandler fErrorHandler);
46,12 → 46,38
* boolean setRequestType(string sRequestType
* default="application/x-www-form-urlencoded");
* // requestType=sRequestType
*
*
* }
*
* @end
*/
 
/**
* Creates a new HTTPRequest object when called as constructor.
* Set up response handlers per argument (see below), or
* {@link HTTPRequest.prototype#setResponseHandler} and
* {@link HTTPRequest.prototype#setErrorHandler}, then call
* {@link HTTPRequest.prototype#send} method to send the request.
*
* @param sURL : optional string=document.URL
* Request URL. The default is the URL of the sending resource.
* @param sMethod : optional string=HTTPRequest.method.GET
* Request method. Use the <code>HTTPRequest.method.GET</code>
* (default) and <code>.POST</code> properties to avoid problems
* caused by case mismatch, and other typos.
* @param bAsync : optional boolean=true
* Pass <code>true</code> to make an asynchronous request (default),
* that is, a request that is processed in the background and does
* not interrupt user operation.
* @param fResponseHandler : optional HTTPResponseHandler=null
* The function to handle the response of a successful request
* (default: <code>null</code>).
* @param fErrorHandler : optional HTTPResponseHandler=null
* The function to handle the response of a request that failed
* (default: <code>null</code>).
* @constructor
* @return undefined
*/
function HTTPRequest(sURL, sMethod, bAsync, fResponseHandler, fErrorHandler)
{
this.setURL(sURL);
58,13 → 84,18
this.setMethod(sMethod);
this.setAsync(bAsync);
this.setResponseHandler(fResponseHandler);
this.setErrorHandler(fErrorHandler);
// this.setErrorHandler(fErrorHandler);
this.setData();
this.setRequestType();
}
 
HTTPRequest.addProperties({
jsx.object.addProperties(
{
method: {
/**
* Use the predefined properties to avoid problems
* caused by case mismatch and other typos.
*/
GET: "GET",
POST: "POST"
},
74,11 → 105,11
LOADING: 1,
LOADED: 2,
INTERACTIVE: 3,
COMPLETED: 4,
COMPLETED: 4
},
status: {
OK_EXPR: /\b[02]\d\d\b/,
OK_EXPR: /\b(0|2\d\d)\b/,
LOCAL_NONE: 0,
 
CONTINUE: 100,
129,7 → 160,8
GATEWAY_TIMEOUT: 504,
HTTP_VER_NOT_SUPP: 505
}
});
},
HTTPRequest);
 
HTTPRequest.prototype = {
constructor: HTTPRequest,
137,17 → 169,16
/**
* Sets the <code>URL</code> property.
*
* @argument sURL: string
* @param sURL : string
* If not provided or a false-value, the
* URL of the sending recource is set.
* @argument bDontEncode: optional boolean
* @param bDontEncode : optional boolean
* If <code>true</code>, do not encode the request URL
* (with <code>escURI()</code> or <code>escape()</code>).
*/
setURL: function(sURL, bDontEncode)
{
if (!bDontEncode) sURL = escURI(sURL);
  this.URL = (sURL || document.URL);
setURL: function(sURL, bDontEncode) {
if (!bDontEncode && sURL) sURL = esc(sURL);
this.URL = (sURL || document.URL);
},
 
/**
155,13 → 186,12
* <code>HTTPRequest.(GET|POST)</code> properties
* to avoid problems with character case and typos.
*
* @argument : optional string
* @param sMethod : optional string
* If not provided or a false-value, the value
* of <code>HTTPRequest.GET</code> is used.
*/
setMethod: function(sMethod)
{
  this.method =
setMethod: function(sMethod) {
this.method =
sMethod
? String(sMethod).toUpperCase()
: this.constructor.method.GET;
173,31 → 203,40
* response to be fully received in the background, this is the default
* and recommended).
*
* @argument : optional boolean
* @param bAsync : optional boolean
* If not provided or a true-value, the request will be asynchronous.
*/
setAsync: function(bAsync)
{
setAsync: function(bAsync) {
this.async = (typeof bAsync != "undefined" ? !!bAsync : true);
},
/**
* Defines the response handler method to be used for handling
* successful requests.
* successful requests. A HTTPRequest object is always initialized
* with a dummy response handler that does nothing, if you do not
* specify one. Once initialized, passing a reference to a non-callable
* object as argument, throws an InvalidArgumentException.
*
* @argument : HTTPResponseHandler
* @param fResponseHandler : HTTPResponseHandler
* @throws InvalidArgumentException
*/
setResponseHandler: function(fResponseHandler)
{
if (isMethod(fResponseHandler))
setResponseHandler: function(fResponseHandler) {
// initialization
if (typeof this.responseHandler == "undefined")
{
this.responseHandler = new HTTPResponseHandler();
return true;
}
else if (jsx.object.isMethod(fResponseHandler))
{
this.responseHandler = fResponseHandler;
return (this.responseHandler == this.responseHandler);
return (this.responseHandler == fResponseHandler);
}
else
{
_global.setErrorHandler();
eval('throw new Error("Argument is not a method");');
eval('throw new Error('
+ '"jsx:HTTPRequest::setResponseHandler: Argument is not a method");');
_global.clearErrorHandler();
return false;
}
205,14 → 244,18
 
/**
* Defines the response handler method to be used for handling
* successful requests.
* unsuccessful requests.
*
* @argument : HTTPResponseHandler
* @param : HTTPResponseHandler
*/
setErrorHandler: function(fErrorHandler)
{
if (isMethod(fErrorHandler))
/*
setErrorHandler: function(fErrorHandler) {
if (typeof this.errorHandler == "undefined")
{
this.errorHandler = new HTTPResponseHandler();
}
else if (jsx.object.isMethod(fErrorHandler))
{
this.errorHandler = fErrorHandler;
return (this.errorHandler == this.errorHandler);
}
219,30 → 262,29
else
{
_global.setErrorHandler();
eval('throw new Error("Argument is not a method");');
eval('throw new Error('
+ '"jsx:HTTPRequest::setErrorHandler: Argument is not a method");');
_global.clearErrorHandler();
return false;
}
},
 
*/
/**
* Sets the <code>data</code> property.
*
* @argument : optional string
* @param sData : optional string
* If not provided or a false-value, sets
* the property to the empty string.
* @see HTTPRequest#resetData()
* @see HTTPRequest.prototype#resetData()
*/
setData: function(sData)
{
setData: function(sData) {
this.data = (sData || "");
},
/**
* Resets the <code>data</code> property to the empty string.
*
* @see HTTPRequest#setData()
* @see HTTPRequest.prototype#setData()
*/
resetData: function()
{
253,12 → 295,12
* Retrieves the data to send in the request, and optionally the request
* method, from an (X)HTML form. TODO: select[multiple] elements
*
* @argument f: HTMLFormElement
* @argument : optional boolean
* @param f : HTMLFormElement
* @param bUseFormMethod: optional boolean
* If <code>true</code>, the form's request method becomes the
* <code>HTTPRequest</code> object's request method. The default
* is <code>false</code>.
* @type boolean
* @return boolean
*/
getDataFromForm: function(f, bUseFormMethod)
{
274,7 → 316,7
{
var o = es[i];
if (o.name)
{
{
aData.push(esc(o.name) + "=" + esc(o.value != "" ? o.value : ""));
}
}
292,63 → 334,86
* which is what Web browsers, although this media type is currently
* (June 2006 CE) not registered with IANA, send as default then.
*
* @param string sRequestType
* @param sRequestType : string
* <code>"application/x-www-form-urlencoded"</code>, if omitted or
* a false-value (like "", the empty string)
* a false-value (like "", the empty string).
*/
setRequestType: function(sRequestType)
{
setRequestType: function(sRequestType) {
this.requestType = sRequestType || "application/x-www-form-urlencoded";
},
 
send: function(
/** @type string */ sData,
/** @type string */ sURL,
/** @type string */ sMethod,
/** @type boolean */ bAsync)
{
var result = false, x = null;
/**
* @param sData : optional string
* The data to form the request body. If the request method is "GET",
* this argument is ignored and <code>null</code> is used instead (no body).
* If the request method is "POST", and this value is not provided, the
* value defaults to that of the <code>data</code> property, which is
* the empty string if not set different previously.
* @param sURL : optional string
* The request URL. If not provided, this value defaults to that of the
* <code>URL</code> property, which is the empty string if not set
* different previously.
* @param sMethod : optional string
* The request method. If not provided, this value defaults to that of
* the <code>HTTPRequest.method.GET</code> property, which is "GET".
* @param bAsync : optional boolean
* The request is asynchronous if <code>true</code> is passed, synchronous
* if <code>false</code> is passed. If not provided, this value defaults
* to that of the <code>async</code> property, which is <code>true</code>
* if not set different previously.
*/
send: function(sData, sURL, sMethod, bAsync) {
var
result = false,
jsx_object = jsx.object,
x = null;
 
// Gecko, IE 7, and Opera 8.1
if (isMethod(_global.XMLHttpRequest))
/*
* Feature detection based on Jim Ley's XML HTTP Request tutorial
* at <http://jibbering.com/2002/4/httprequest.html>
*/
 
/*
* IE 6+ (JScript allows for conditional compilation; an ordinary comment
* to other script engines). Note that IE 7 supports XMLHttpRequest() but
* currently not for `file:' URIs, so we don't prefer that wrapper (see
* <http://xhab.blogspot.com/2006/11/ie7-support-for-xmlhttprequest.html>).
*/
if (jsx_object.isMethod(jsx.global, "ActiveXObject"))
{
// eval() is needed here so that this compiles in ECMAScript < 3
// (e.g. IE 4, NS 4)
eval('try { x = new XMLHttpRequest(); } catch (e) { x = null; }');
}
// IE 6 (JScript allows for conditional compilation;
// a ordinary comment to other script engines)
if (!x && isMethod(_global.ActiveXObject))
{
/*@cc_on @*/
/*@if (@_jscript_version >= 5)
try
{
x = new ActiveXObject("Msxml2.XMLHTTP");
// MSXML 3.0-
x = new ActiveXObject("Microsoft.XMLHTTP");
}
catch (e)
{
try
{
x = new ActiveXObject("Microsoft.XMLHTTP");
}
catch (e2)
{
x = null;
}
x = null;
}
@end @*/
}
// IceBrowser
if (!x && isMethod(window.createRequest))
/* Gecko and Opera 8.1+ */
if (!x && jsx_object.isMethod(jsx.global, "XMLHttpRequest"))
{
// see above
/*
* eval() is needed here so that this compiles in ECMAScript < 3
* (e.g. IE 4, NS 4)
*/
eval('try { x = new XMLHttpRequest(); } catch (e) { x = null; }');
}
/* IceBrowser */
if (!x && typeof window != "undefined"
&& jsx_object.isMethod(window, "createRequest"))
{
/* see above */
eval('try { x = window.createRequest(); } catch (e) { x = null; }');
}
 
if (x && isMethod(x.open))
if (x) // && jsx_object.isMethod(x.open)
{
if (arguments.length < 2) sURL = this.URL;
 
358,7 → 423,7
bAsync = (arguments.length > 3) ? !!bAsync : this.async;
x.open(
sMethod,
sMethod.toUpperCase(),
sURL
+ ((bGET && sData)
? (!/[?&]$/.test(sURL)
368,46 → 433,61
: ""),
bAsync);
 
if (isMethod(x.setRequestHeader))
{
// if (jsx_object.isMethod(x.setRequestHeader))
// {
// see above
eval('try { x.setRequestHeader("Content-Type", this.requestType); }',
eval('try { x.setRequestHeader("Content-Type", this.requestType); }'
+ 'catch (e) {}');
}
// }
if (bAsync)
{
var me = this;
x.onreadystatechange = function()
{
if (this.constructor.status.OK_EXPR.test(x.status)
&& isMethod(this.responseHandler))
        {
          this.responseHandler(x);
        }
else if (isMethod(this.errorHandler))
        {
          this.errorHandler(x);
        }
if (x.readyState == this.constructor.readyState.COMPLETED) x = null;
}
// alert(x.readyState);
// alert(x.status);
// console.log("readyState = %i, status = %i", x.readyState, x.status);
// console.log(me.constructor.status.OK_EXPR);
// if (x.readyState > HTTPRequest.readyState.LOADED
// && me.constructor.status.OK_EXPR.test(x.status))
// {
me.responseHandler(x);
// }
// else
// {
// me.errorHandler(x);
// }
if (x.readyState == me.constructor.readyState.COMPLETED)
{
x = null;
}
};
}
 
x.send(bGET ? null : (sData || this.data));
eval('try { x.send(bGET ? null : (sData || this.data)); }'
+ 'catch (e) { /*this.errorHandler();*/ }');
if (!bAsync)
{
if (this.constructor.status.OK_EXPR.test(x.status)
&& isMethod(this.responseHandler))
        {
          this.responseHandler(x);
result = true;
      }
else if (this.constructor.status.FAILED_EXPR.test(x.status)
&& isMethod(this.errorHandler))
        {
          this.errorHandler(x);
      }
// if (this.constructor.status.OK_EXPR.test(x.status)
// && jsx_object.isMethod(this.responseHandler))
// {
this.responseHandler(x);
// Handle stopped servers
eval('try { if (this.constructor.status.OK_EXPR.test(x.status)) {'
+ 'result = true;'
+ '} } catch {}');
// }
// else if (this.constructor.status.FAILED_EXPR.test(x.status)
// && jsx_object.isMethod(this.errorHandler))
// {
// this.errorHandler(x);
// }
 
x = null;
}
424,7 → 504,7
*
* Recommended usage:
* <pre><code>
* var f = new HTTPResponseHandler(
* var f = HTTPResponseHandler(
* new Array(
* 'statement;',
* 'statement;'
431,17 → 511,23
* ).join(""));
* </code></pre>
*
* @param sCode
* @return Function
* A new <code>HTTPResponseHandler</code> object
*/
function HTTPResponseHandler(sCode)
{
return Function("x", sCode);
return Function("x", sCode || "");
}
 
/**
* @param x
*/
function processResponse(x)
{
  // ...
/* ... */
}
 
// var x = new HTTPRequest("", HTTPRequest.GET, processResponse);
// ...
/* ... */
// x.send();