Add PDoc for most of Ajax section.

This commit is contained in:
Andrew Dupont 2009-03-07 15:43:20 -06:00
parent 8c2af9bd66
commit 449e532f9a
7 changed files with 432 additions and 1 deletions

View File

@ -1,3 +1,112 @@
/**
* == Ajax ==
*
* Prototype's APIs around the `XmlHttpRequest` object.
*
* The Prototype framework enables you to deal with Ajax calls in a manner that is
* both easy and compatible with all modern browsers.
*
* Actual requests are made by creating instances of [[Ajax.Request]].
*
* <h4>Request headers</h4>
*
* The following headers are sent with all Ajax requests (and can be
* overridden with the `requestHeaders` option described below):
*
* * `X-Requested-With` is set to `XMLHttpRequest`.
* * `X-Prototype-Version` is set to Prototype's current version (e.g.,
* `1.6.0.3`).
* * `Accept` is set to `text/javascript, text/html, application/xml,
* text/xml, * / *`
* * `Content-type` is automatically determined based on the `contentType`
* and `encoding` options.
*
* <h4>Ajax options</h4>
*
* All Ajax classes share a common set of _options_ and _callbacks_.
* Callbacks are called at various points in the life-cycle of a request, and
* always feature the same list of arguments.
*
* <h5>Common options</h5>
*
* * `asynchronous` ([[Boolean]]; default `true`): Determines whether
* `XMLHttpRequest` is used asynchronously or not. Synchronous usage is
* seriously discouraged it halts all script execution for the duration of
* the request _and_ blocks the browser UI.
* * `contentType` ([[String]]; default `application/x-www-form-urlencoded`):
* The `Content-type` header for your request. Change this header if you
* want to send data in another format (like XML).
* * `encoding` ([[String]]; default `UTF-8`): The encoding for the contents
* of your request. It is best left as-is, but should weird encoding issues
* arise, you may have to tweak this.
* * `method` ([[String]]; default `post`): The HTTP method to use for the
* request. The other common possibility is `get`. Abiding by Rails
* conventions, Prototype also reacts to other HTTP verbs (such as `put` and
* `delete`) by submitting via `post` and adding a extra `_method` parameter
* with the originally-requested method.
* * `parameters` ([[String]]): The parameters for the request, which will be
* encoded into the URL for a `get` method, or into the request body for the
* other methods. This can be provided either as a URL-encoded string, a
* [[Hash]], or a plain [[Object]].
* * `postBody` ([[String]]): Specific contents for the request body on a
* `post` method. If it is not provided, the contents of the `parameters`
* option will be used instead.
* * `requestHeaders` ([[Object]]): A set of key-value pairs, with properties
* representing header names.
* * `evalJS` ([[Boolean]] | [[String]]; default `true`): Automatically `eval`s
* the content of [[Ajax.Response#responseText]] and populates
* [[Ajax.Response#responseJSON]] with it if the `Content-type` returned by
* the server is set to `application/json`. If the request doesn't obey
* same-origin policy, the content is sanitized before evaluation. If you
* need to force evalutation, pass `'force'`. To prevent it altogether, pass
* `false`.
* * `sanitizeJSON` ([[Boolean]]; default is `false` for same-origin requests,
* `true` otherwise): Sanitizes the contents of
* [[Ajax.Response#responseText]] before evaluating it.
*
* <h4>Common callbacks</h4>
*
* When used on individual instances, all callbacks (except `onException`) are
* invoked with two parameters: the `XMLHttpRequest` object and the result of
* evaluating the `X-JSON` response header, if any (can be `null`).
*
* For another way of describing their chronological order and which callbacks
* are mutually exclusive, see [[Ajax.Request]].
*
* * `onCreate`: Triggered when the [[Ajax.Request]] object is initialized.
* This is _after_ the parameters and the URL have been processed, but
* _before_ opening the connection via the XHR object.
* * `onUninitialized` (*Not guaranteed*): Invoked just after the XHR object
* is created.
* * `onLoading` (*Not guaranteed*): Triggered when the underlying XHR object
* is being setup, and its connection opened.
* * `onLoaded` (*Not guaranteed*): Triggered once the underlying XHR object
* is setup, the connection is open, and it is ready to send its actual
* request.
* * `onInteractive` (*Not guaranteed*): Triggered whenever the requester
* receives a part of the response (but not the final part), should it
* be sent in several packets.
* * `onSuccess`: Invoked when a request completes and its status code is
* `undefined` or belongs in the `2xy` family. This is skipped if a
* code-specific callback is defined (e.g., `on200`), and happens _before_
* `onComplete`.
* * `onFailure`: Invoked when a request completes and its status code exists
* but _is not_ in the `2xy` family. This is skipped if a code-specific
* callback is defined (e.g. `on403`), and happens _before_ `onComplete`.
* * `onXYZ` (_with `XYZ` representing any HTTP status code_): Invoked just
* after the response is complete _if_ the status code is the exact code
* used in the callback name. _Prevents_ execution of `onSuccess` and
* `onFailure`. Happens _before_ `onComplete`.
* * `onException`: Triggered whenever an XHR error arises. Has a custom
* signature: the first argument is the requester (i.e. an [[Ajax.Request]]
* instance), and the second is the exception object.
* * `onComplete`: Triggered at the _very end_ of a request's life-cycle, after
* the request completes, status-specific callbacks are called, and possible
* automatic behaviors are processed. Guaranteed to run regardless of what
* happened during the request.
*
**/
//= require "ajax/ajax"
//= require "ajax/responders"
//= require "ajax/base"

View File

@ -1,3 +1,7 @@
/** section: Ajax
* Ajax
**/
var Ajax = {
getTransport: function() {
return Try.these(
@ -7,5 +11,11 @@ var Ajax = {
) || false;
},
/**
* Ajax.activeRequestCount -> Number
*
* Represents the number of active XHR requests triggered through
* [[Ajax.Request]], [[Ajax.Updater]], or [[Ajax.PeriodicalUpdater]].
**/
activeRequestCount: 0
};

View File

@ -1,3 +1,4 @@
// Abstract class; does not need documentation.
Ajax.Base = Class.create({
initialize: function(options) {
this.options = {

View File

@ -1,6 +1,92 @@
/** section: Ajax
* class Ajax.Request
*
* Initiates and processes an Ajax request.
*
* `Ajax.Request` is a general-purpose class for making HTTP requests.
*
* <h4>Automatic JavaScript response evaluation</h4>
*
* If an Ajax request follows the _same-origin policy_ **and** its response
* has a JavaScript-related `Content-type`, the content of the `responseText`
* property will automatically be passed to `eval`.
*
* In other words: you don't even need to provide a callback to leverage
* pure-JavaScript AJAX responses. This is the convention that drives Rails's
* RJS.
*
* The list of JavaScript-related MIME-types handled by Prototype is:
*
* * `application/ecmascript`
* * `application/javascript`
* * `application/x-ecmascript`
* * `application/x-javascript`
* * `text/ecmascript`
* * `text/javascript`
* * `text/x-ecmascript`
* * `text/x-javascript`
*
* The MIME-type string is examined in a case-insensitive manner.
*
* <h4>Methods you may find useful</h4>
*
* Instances of the `Request` object provide several methods that can come in
* handy in your callback functions, especially once the request is complete.
*
* <h5>Is the response a successful one?</h5>
*
* The [[Ajax.Request#success]] method examines the XHR object's `status`
* property and follows general HTTP guidelines: unknown status is deemed
* successful, as is the whole `2xy` status code family. It's a generally
* better way of testing your response than the usual
* `200 == transport.status`.
*
* <h5>Getting HTTP response headers</h5>
*
* While you can obtain response headers from the XHR object using its
* `getResponseHeader` method, this makes for verbose code, and several
* implementations raise an exception when the header is not found. To make
* this easier, you can use the [[Ajax.Response#getHeader]] method, which
* delegates to the longer version and returns `null` if an exception occurs:
*
* new Ajax.Request('/your/url', {
* onSuccess: function(response) {
* // Note how we brace against null values
* if ((response.getHeader('Server') || '').match(/Apache/))
* ++gApacheCount;
* // Remainder of the code
* }
* });
*
* <h5>Evaluating JSON headers</h5>
*
* Some backends will return JSON not as response text, but in the `X-JSON`
* header. In this case, you don't even need to evaluate the returned JSON
* yourself, as Prototype automatically does so. It passes the result as the
* `headerJSON` property of the [[Ajax.Response]] object. Note that if there
* is no such header or its contents are invalid `headerJSON` will be set
* to `null`.
*
* new Ajax.Request('/your/url', {
* onSuccess: function(transport) {
* transport.headerJSON
* }
* });
**/
Ajax.Request = Class.create(Ajax.Base, {
_complete: false,
/**
* new Ajax.Request(url[, options])
* - url (String): The URL to fetch. When the _same-origin_ policy is in
* effect (as it is in most cases), `url` **must** be a relative URL or an
* absolute URL that starts with a slash (i.e., it must not begin with
* `http`).
* - options (Object): Configuration for the request. See the
* [[Ajax section]] for more information.
*
* Creates a new `Ajax.Request`.
**/
initialize: function($super, url, options) {
$super(options);
this.transport = Ajax.getTransport();
@ -95,6 +181,11 @@ Ajax.Request = Class.create(Ajax.Base, {
this.transport.setRequestHeader(name, headers[name]);
},
/**
* Ajax.Request.success() -> Boolean
*
* Tests whether the request was successful.
**/
success: function() {
var status = this.getStatus();
return !status || (status >= 200 && status < 300);
@ -148,10 +239,18 @@ Ajax.Request = Class.create(Ajax.Base, {
}));
},
/**
* Ajax.Request.getHeader(name) -> String | null
* - name (String): The name of an HTTP header that may have been part of
* the response.
*
* Returns the value of the given response header, or `null` if that header
* was not found.
**/
getHeader: function(name) {
try {
return this.transport.getResponseHeader(name) || null;
} catch (e) { return null }
} catch (e) { return null; }
},
evalResponse: function() {

View File

@ -1,3 +1,71 @@
/** section: Ajax
* Ajax.Responders
*
* A repository of global listeners notified about every step of
* Prototype-based Ajax requests.
*
* Sometimes, you need to provide generic behaviors over all Ajax operations
* happening on the page (through [[Ajax.Request]], [[Ajax.Updater]] or
* [[Ajax.PeriodicalUpdater]]).
*
* For instance, you might want to automatically show an indicator when an
* Ajax request is ongoing, and hide it when none are. You may well want to
* factor out exception handling as well, logging those somewhere on the page
* in a custom fashion. The possibilities are myriad.
*
* To achieve this, Prototype provides `Ajax.Responders`, which lets you
* register (and, if you wish, unregister later) _responders_, which are
* objects with specially-named methods. These names come from a set of
* general callbacks corresponding to different points in time (or outcomes)
* of an Ajax request's life cycle.
*
* For instance, Prototype automatically registers a responder that maintains
* a nifty variable: [[Ajax.activeRequestCount]]. This represents, at a given
* time, the number of currently active Ajax requests by monitoring their
* `onCreate` and `onComplete` events. The code for this is fairly simple:
*
* Ajax.Responders.register({
* onCreate: function() {
* Ajax.activeRequestCount++;
* },
* onComplete: function() {
* Ajax.activeRequestCount--;
* }
* });
*
* <h4>Responder callbacks</h4>
*
* The callbacks for responders are similar to the callbacks described in
* the [[Ajax section]], but take a different signature. They're invoked with
* three parameters: the requester object (i.e., the corresponding "instance"
* of [[Ajax.Request]]), the `XMLHttpRequest` object, and the result of
* evaluating the `X-JSON` response header, if any (can be `null`). They also
* execute in the context of the responder, bound to the `this` reference.
*
* * `onCreate`: Triggered whenever a requester object from the `Ajax`
* namespace is created, after its parameters are adjusted and before its
* XHR connection is opened. This takes *two* arguments: the requester
* object and the underlying XHR object.
* * `onUninitialized` (*Not guaranteed*): Invoked just after the XHR object
* is created.
* * `onLoading` (*Not guaranteed*): Triggered when the underlying XHR object
* is being setup, and its connection opened.
* * `onLoaded` (*Not guaranteed*): Triggered once the underlying XHR object
* is setup, the connection is open, and it is ready to send its actual
* request.
* * `onInteractive` (*Not guaranteed*): Triggered whenever the requester
* receives a part of the response (but not the final part), should it
* be sent in several packets.
* * `onException`: Triggered whenever an XHR error arises. Has a custom
* signature: the first argument is the requester (i.e. an [[Ajax.Request]]
* instance), and the second is the exception object.
* * `onComplete`: Triggered at the _very end_ of a request's life-cycle, after
* the request completes, status-specific callbacks are called, and possible
* automatic behaviors are processed. Guaranteed to run regardless of what
* happened during the request.
*
**/
Ajax.Responders = {
responders: [],
@ -5,11 +73,30 @@ Ajax.Responders = {
this.responders._each(iterator);
},
/**
* Ajax.Responders.register(responder) -> undefined
* - responder (Object): A list of functions with keys corresponding to the
* names of possible callbacks.
*
* Add a group of responders to all Ajax requests.
**/
register: function(responder) {
if (!this.include(responder))
this.responders.push(responder);
},
/**
* Ajax.Responders.unregister(responder) -> undefined
* - responder (Object): A list of functions with keys corresponding to the
* names of possible callbacks.
*
* Remove a previously-added group of responders.
*
* As always, unregistering something requires you to use the very same
* object you used at registration. If you plan to use `unregister`, be sure
* to assign your responder to a _variable_ before passing it into
* [[Ajax.Responders#register]] don't pass it an object literal.
**/
unregister: function(responder) {
this.responders = this.responders.without(responder);
},

View File

@ -1,4 +1,64 @@
/** section: Ajax
* class Ajax.Response
*
* A wrapper class around `XmlHttpRequest` for dealing with HTTP responses
* of Ajax requests.
*
* An instance of `Ajax.Response` is passed as the first argument of all Ajax
* requests' callbacks. You _will not_ need to create instances of
* `Ajax.Response` yourself.
**/
/**
* Ajax.Response#readyState -> Number
*
* The requests current state.
*
* `0` corresponds to `"Uninitialized"`, `1` to `"Loading"`, `2` to
* `"Loaded"`, `3` to `"Interactive"`, and `4` to `"Complete"`.
**/
/**
* Ajax.Response#responseText -> String
*
* The text body of the response.
**/
/**
* Ajax.Response#responseXML -> document | null
*
* The XML body of the response if the `Content-type` of the request is set
* to `application/xml`; `null` otherwise.
**/
/**
* Ajax.Response#responseJSON -> Object | Array | null
*
* The JSON body of the response if the `Content-type` of the request is set
* to `application/json`; `null` otherwise.
**/
/**
* Ajax.Response#headerJSON -> Object | Array | null
*
* Auto-evaluated content of the `X-JSON` header if present; `null` otherwise.
**/
/**
* Ajax.Response#request -> Ajax.Request | Ajax.Updater
*
* The request object itself (an instance of [[Ajax.Request]] or
* [[Ajax.Updater]]).
**/
/**
* Ajax.Response#transport -> XmlHttpRequest
*
* The native `XmlHttpRequest` object itself.
**/
Ajax.Response = Class.create({
// Don't document the constructor; should never be manually instantiated.
initialize: function(request){
this.request = request;
var transport = this.transport = request.transport,
@ -18,7 +78,18 @@ Ajax.Response = Class.create({
}
},
/**
* Ajax.Response#status -> Number
*
* The HTTP status code sent by the server.
**/
status: 0,
/**
* Ajax.Response#statusText -> String
*
* The HTTP status text sent by the server.
**/
statusText: '',
getStatus: Ajax.Request.prototype.getStatus,
@ -29,18 +100,44 @@ Ajax.Response = Class.create({
} catch (e) { return '' }
},
/**
* Ajax.Response#getHeader(name) -> String | null
*
* See [[Ajax.Request#getHeader]].
**/
getHeader: Ajax.Request.prototype.getHeader,
/**
* Ajax.Response#getAllHeaders() -> String | null
*
* Returns a string containing all headers separated by line breaks. _Does
* not__ throw errors if no headers are present the way its native
* counterpart does.
**/
getAllHeaders: function() {
try {
return this.getAllResponseHeaders();
} catch (e) { return null }
},
/**
* Ajax.Response.getResponseHeader(name) -> String
*
* Returns the value of the requested header if present; throws an error
* otherwise. This is just a wrapper around the `XmlHttpRequest` method of
* the same name.
**/
getResponseHeader: function(name) {
return this.transport.getResponseHeader(name);
},
/**
* Ajax.Response.getAllResponseHeaders() -> String
*
* Returns a string containing all headers separated by line breaks; throws
* an error if no headers exist. This is just a wrapper around the
* `XmlHttpRequest` method of the same name.
**/
getAllResponseHeaders: function() {
return this.transport.getAllResponseHeaders();
},

View File

@ -1,3 +1,31 @@
/** section: Ajax
* class Ajax.Updater < Ajax.Request
*
* A class that performs an Ajax request and updates a containers contents
* with the contents of the response.
*
* `Ajax.Updater` is a subclass of [[Ajax.Request]] built for a common
* use-case.
*
* <h4>Example</h4>
*
* new Ajax.Updater('items', '/items', {
* parameters: { text: $F('text') }
* });
*
* This example will make a request to the URL `/items` (with the given
* parameters); it will then replace the contents of the element with the ID
* of `items` with whatever response it receives.
*
*
*
**/
Ajax.Updater = Class.create(Ajax.Request, {
initialize: function($super, container, url, options) {
this.container = {