diff --git a/src/ajax.js b/src/ajax.js
index 98cf975..2771fd8 100644
--- a/src/ajax.js
+++ b/src/ajax.js
@@ -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]].
+ *
+ *
Request headers
+ *
+ * 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.
+ *
+ * Ajax options
+ *
+ * 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.
+ *
+ * Common options
+ *
+ * * `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.
+ *
+ * Common callbacks
+ *
+ * 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"
diff --git a/src/ajax/ajax.js b/src/ajax/ajax.js
index 4895a10..d8174f2 100644
--- a/src/ajax/ajax.js
+++ b/src/ajax/ajax.js
@@ -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
};
diff --git a/src/ajax/base.js b/src/ajax/base.js
index b6413db..0be66bc 100644
--- a/src/ajax/base.js
+++ b/src/ajax/base.js
@@ -1,3 +1,4 @@
+// Abstract class; does not need documentation.
Ajax.Base = Class.create({
initialize: function(options) {
this.options = {
diff --git a/src/ajax/request.js b/src/ajax/request.js
index 6937b5d..d09d53d 100644
--- a/src/ajax/request.js
+++ b/src/ajax/request.js
@@ -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.
+ *
+ * Automatic JavaScript response evaluation
+ *
+ * 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.
+ *
+ * Methods you may find useful
+ *
+ * Instances of the `Request` object provide several methods that can come in
+ * handy in your callback functions, especially once the request is complete.
+ *
+ * Is the response a successful one?
+ *
+ * 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`.
+ *
+ * Getting HTTP response headers
+ *
+ * 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
+ * }
+ * });
+ *
+ * Evaluating JSON headers
+ *
+ * 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() {
diff --git a/src/ajax/responders.js b/src/ajax/responders.js
index a317a90..80a8e37 100644
--- a/src/ajax/responders.js
+++ b/src/ajax/responders.js
@@ -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--;
+ * }
+ * });
+ *
+ * Responder callbacks
+ *
+ * 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);
},
diff --git a/src/ajax/response.js b/src/ajax/response.js
index c8bc2f8..6224426 100644
--- a/src/ajax/response.js
+++ b/src/ajax/response.js
@@ -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 request’s 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();
},
diff --git a/src/ajax/updater.js b/src/ajax/updater.js
index 262c7f6..e1efa98 100644
--- a/src/ajax/updater.js
+++ b/src/ajax/updater.js
@@ -1,3 +1,31 @@
+/** section: Ajax
+ * class Ajax.Updater < Ajax.Request
+ *
+ * A class that performs an Ajax request and updates a container’s contents
+ * with the contents of the response.
+ *
+ * `Ajax.Updater` is a subclass of [[Ajax.Request]] built for a common
+ * use-case.
+ *
+ * Example
+ *
+ * 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 = {