Newer
Older
<?php
// $Id$
/**
* @file
* Functions for use with Drupal's AJAX framework.
*/
/**
* @defgroup ajax AJAX framework
* @{
* Drupal's AJAX framework is used to dynamically update parts of a page's HTML
* based on data from the server. Upon a specified event, such as a button
* click, a callback function is triggered which performs server-side logic and
* may return updated markup, which is then replaced on-the-fly with no page
* refresh necessary.
*
* This framework creates a PHP macro language that allows the server to
* instruct JavaScript to perform actions on the client browser. When using
* forms, it can be used with the #ajax property.
* The #ajax property can be used to bind events to the AJAX framework. By
* default, #ajax uses 'system/ajax' as its path for submission and thus calls

Dries Buytaert
committed
* ajax_form_callback() and a defined #ajax['callback'] function.
* However, you may optionally specify a different path to request or a
* different callback function to invoke, which can return updated HTML or can
* also return a richer set of @link ajax_commands AJAX framework commands @endlink.
* Standard form handling is as follows:

Dries Buytaert
committed
* - A form element has a #ajax property that includes #ajax['callback'] and
* omits #ajax['path']. See below about using #ajax['path'] to implement
* advanced use-cases that require something other than standard form
* handling.
* - On the specified element, AJAX processing is triggered by a change to
* that element.

Dries Buytaert
committed
* - The browser submits an HTTP POST request to the 'system/ajax' Drupal
* path.
* - The menu page callback for 'system/ajax', ajax_form_callback(), calls
* drupal_process_form() to process the form submission and rebuild the
* form if necessary. The form is processed in much the same way as if it
* were submitted without AJAX, with the same #process functions and
* validation and submission handlers called in either case, making it easy
* to create AJAX-enabled forms that degrade gracefully when JavaScript is
* disabled.
* - After form processing is complete, ajax_form_callback() calls the
* function named by #ajax['callback'], which returns the form element that
* has been updated and needs to be returned to the browser, or
* alternatively, an array of custom AJAX commands.
* - The page delivery callback for 'system/ajax', ajax_deliver(), renders the
* element returned by #ajax['callback'], and returns the JSON string
* created by ajax_render() to the browser.
* - The browser unserializes the returned JSON string into an array of
* command objects and executes each command, resulting in the old page
* content within and including the HTML element specified by
* #ajax['wrapper'] being replaced by the new content returned by
* #ajax['callback'], using a JavaScript animation effect specified by
* #ajax['effect'].
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
*
* A simple example of basic AJAX use from the
* @link http://drupal.org/project/examples Examples module @endlink follows:
* @code
* function main_page() {
* return drupal_get_form('ajax_example_simplest');
* }
*
* function ajax_example_simplest($form, &$form_state) {
* $form = array();
* $form['changethis'] = array(
* '#type' => 'select',
* '#options' => array(
* 'one' => 'one',
* 'two' => 'two',
* 'three' => 'three',
* ),
* '#ajax' => array(
* 'callback' => 'ajax_example_simplest_callback',
* 'wrapper' => 'replace_textfield_div',
* ),
* );
* // This entire form element will be replaced with an updated value.
* $form['replace_textfield'] = array(
* '#type' => 'textfield',
* '#title' => t("The default value will be changed"),
* '#description' => t("Say something about why you chose") . "'" .
* (!empty($form_state['values']['changethis'])
* ? $form_state['values']['changethis'] : t("Not changed yet")) . "'",
* '#prefix' => '<div id="replace_textfield_div">',
* '#suffix' => '</div>',
* );
* return $form;
* }
*
* function ajax_example_simplest_callback($form, $form_state) {
* // The form has already been submitted and updated. We can return the replaced
* // item as it is.
* return $form['replace_textfield'];
* }
* @endcode
* In the above example, the 'changethis' element is AJAX-enabled. The default
* #ajax['event'] is 'change', so when the 'changethis' element changes,
* an AJAX call is made. The form is submitted and reprocessed, and then the
* callback is called. In this case, the form has been automatically
* built changing $form['replace_textfield']['#description'], so the callback
* just returns that part of the form.
*
* To implement AJAX handling in a form, add '#ajax' to the form
* definition of a field. That field will trigger an AJAX event when it is
* clicked (or changed, depending on the kind of field). #ajax supports
* the following parameters (either 'path' or 'callback' is required at least):
* - #ajax['callback']: The callback to invoke to handle the server side of the
* AJAX event, which will receive a $form and $form_state as arguments, and
* returns a renderable array (most often a form or form fragment), an HTML
* string, or an array of AJAX commands. If returning a renderable array or
* a string, the value will replace the original element named in
* #ajax['wrapper'], and
* theme_status_messages()
* will be prepended to that
* element. (If the status messages are not wanted, return an array
* of AJAX commands instead.)
* #ajax['wrapper']. If an array of AJAX commands is returned, it will be
* executed by the calling code.
* - #ajax['path']: The menu path to use for the request. This is often omitted
* and the default is used. This path should map

Dries Buytaert
committed
* to a menu page callback that returns data using ajax_render(). Defaults to
* 'system/ajax', which invokes ajax_form_callback(), eventually calling
* the function named in #ajax['callback']. If you use a custom
* path, you must set up the menu entry and handle the entire callback in your
* own code.
* - #ajax['wrapper']: The CSS ID of the area to be replaced by the content
* returned by the #ajax['callback'] function. The content returned from
* the callback will replace the entire element named by #ajax['wrapper'].
* The wrapper is usually created using #prefix and #suffix properties in the
* form. Note that this is the wrapper ID, not a CSS selector. So to replace
* the element referred to by the CSS selector #some-selector on the page,
* use #ajax['wrapper'] = 'some-selector', not '#some-selector'.
* - #ajax['effect']: The jQuery effect to use when placing the new HTML.
* Defaults to no effect. Valid options are 'none', 'slide', or 'fade'.
* - #ajax['speed']: The effect speed to use. Defaults to 'slow'. May be
* 'slow', 'fast' or a number in milliseconds which represents the length
* of time the effect should run.
* - #ajax['event']: The JavaScript event to respond to. This is normally
* selected automatically for the type of form widget being used, and
* is only needed if you need to override the default behavior.
* - #ajax['method']: The jQuery method to use to place the new HTML.

Dries Buytaert
committed
* Defaults to 'replaceWith'. May be: 'replaceWith', 'append', 'prepend',
* 'before', 'after', or 'html'. See the
* @link http://api.jquery.com/category/manipulation/ jQuery manipulators documentation @endlink
* for more information on these methods.
* - #ajax['progress']: Choose either a throbber or progress bar that is
* displayed while awaiting a response from the callback, and add an optional
* message. Possible keys: 'type', 'message', 'url', 'interval'.
* More information is available in the
* @link http://api.drupal.org/api/drupal/developer--topics--forms_api_reference.html/7 Form API Reference @endlink
*
* In addition to using Form API for doing in-form modification, AJAX may be
* enabled by adding classes to buttons and links. By adding the 'use-ajax'
* class to a link, the link will be loaded via an AJAX call. When using this
* method, the href of the link can contain '/nojs/' as part of the path. When
* the AJAX framework makes the request, it will convert this to '/ajax/'.
* The server is then able to easily tell if this request was made through an
* actual AJAX request or in a degraded state, and respond appropriately.
*
* Similarly, submit buttons can be given the class 'use-ajax-submit'. The
* form will then be submitted via AJAX to the path specified in the #action.
* Like the ajax-submit class above, this path will have '/nojs/' replaced with
* '/ajax/' so that the submit handler can tell if the form was submitted
* in a degraded state or not.
*
* When responding to AJAX requests, the server should do what it needs to do
* for that request, then create a commands array. This commands array will
* be converted to a JSON object and returned to the client, which will then
* iterate over the array and process it like a macro language.
*
* Each command item is an associative array which will be converted to a command
* object on the JavaScript side. $command_item['command'] is the type of
* command, e.g. 'alert' or 'replace', and will correspond to a method in the
* Drupal.ajax[command] space. The command array may contain any other data
* that the command needs to process, e.g. 'method', 'selector', 'settings', etc.
*
* Commands are usually created with a couple of helper functions, so they
* look like this:
* @code
* $commands = array();
* // Replace the content of '#object-1' on the page with 'some html here'.
* $commands[] = ajax_command_replace('#object-1', 'some html here');
* // Add a visual "changed" marker to the '#object-1' element.
* $commands[] = ajax_command_changed('#object-1');

Dries Buytaert
committed
* // Menu 'page callback' and #ajax['callback'] functions are supposed to
* // return render arrays. If returning an AJAX commands array, it must be

Dries Buytaert
committed
* // encapsulated in a render array structure.

Dries Buytaert
committed
* return array('#type' => 'ajax', '#commands' => $commands);
* @endcode

Dries Buytaert
committed
*
* When returning an AJAX command array, it is often useful to have
* status messages rendered along with other tasks in the command array.
* In that case the the AJAX commands array may be constructed like this:

Dries Buytaert
committed
* @code
* $commands = array();
* $commands[] = ajax_command_replace(NULL, $output);
Loading
Loading full blame...