summaryrefslogtreecommitdiff
path: root/includes/ajax.inc
diff options
context:
space:
mode:
authorDries Buytaert <dries@buytaert.net>2010-03-13 06:55:50 +0000
committerDries Buytaert <dries@buytaert.net>2010-03-13 06:55:50 +0000
commit5e32593f3d7c1dd7412e9f918efa3121ff9e6565 (patch)
tree25896319767e65552e98f7246c89748d9297ab20 /includes/ajax.inc
parent1106db64560976f8baa1e7ebaa45fd7c4917c2e1 (diff)
downloadbrdo-5e32593f3d7c1dd7412e9f918efa3121ff9e6565.tar.gz
brdo-5e32593f3d7c1dd7412e9f918efa3121ff9e6565.tar.bz2
- Patch #716602 by effulgentsia: refactor ajax_render() and clean up 'ajax' element type.
Diffstat (limited to 'includes/ajax.inc')
-rw-r--r--includes/ajax.inc119
1 files changed, 69 insertions, 50 deletions
diff --git a/includes/ajax.inc b/includes/ajax.inc
index 2c5f3a9cf..7ef523cce 100644
--- a/includes/ajax.inc
+++ b/includes/ajax.inc
@@ -166,9 +166,10 @@
* $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');
- * // Output new markup to the browser and end the request.
- * // Note: Only custom AJAX paths/page callbacks need to do this manually.
- * ajax_render($commands);
+ * // Menu 'page callback' and #ajax['callback'] functions are supposed to
+ * // return render arrays. If returning an AJAX commands array, it must be
+ * // encapsulated in a render array structure.
+ * return array('#type' => 'ajax', '#commands' => $commands);
* @endcode
*
* When returning an AJAX command array, it is often useful to have
@@ -178,28 +179,20 @@
* $commands = array();
* $commands[] = ajax_command_replace(NULL, $output);
* $commands[] = ajax_command_prepend(NULL, theme('status_messages'));
- * return $commands;
+ * return array('#type' => 'ajax', '#commands' => $commands);
* @endcode
*
* See @link ajax_commands AJAX framework commands @endlink
*/
/**
- * Render a commands array into JSON and exit.
- *
- * Commands are immediately handed back to the AJAX requester. This function
- * will render and immediately exit.
+ * Render a commands array into JSON.
*
* @param $commands
* A list of macro commands generated by the use of ajax_command_*()
* functions.
- * @param $header
- * If set to FALSE the 'text/javascript' header used by drupal_json_output()
- * will not be used, which is necessary when using an IFRAME. If set to
- * 'multipart' the output will be wrapped in a textarea, which can also be
- * used as an alternative method when uploading files.
*/
-function ajax_render($commands = array(), $header = TRUE) {
+function ajax_render($commands = array()) {
// Automatically extract any 'settings' added via drupal_add_js() and make
// them the first command.
$scripts = drupal_add_js(NULL, NULL);
@@ -210,36 +203,7 @@ function ajax_render($commands = array(), $header = TRUE) {
// Allow modules to alter any AJAX response.
drupal_alter('ajax_render', $commands);
- // Use === here so that bool TRUE doesn't match 'multipart'.
- if ($header === 'multipart') {
- // We do not use drupal_json_output() here because the header is not true.
- // We are not really returning JSON, strictly-speaking, but rather JSON
- // content wrapped in a textarea as per the "file uploads" example here:
- // http://malsup.com/jquery/form/#code-samples
- print '<textarea>' . drupal_json_encode($commands) . '</textarea>';
- }
- elseif ($header) {
- drupal_json_output($commands);
- }
- else {
- print drupal_json_encode($commands);
- }
- drupal_exit();
-}
-
-/**
- * Send an error response back via AJAX and immediately exit.
- *
- * This function can be used to quickly create a command array with an error
- * string and send it, short-circuiting the error handling process.
- *
- * @param $error
- * A string to display in an alert.
- */
-function ajax_render_error($error = '') {
- $commands = array();
- $commands[] = ajax_command_alert(empty($error) ? t('An error occurred while handling the request: The server received invalid input.') : $error);
- ajax_render($commands);
+ return drupal_json_encode($commands);
}
/**
@@ -368,6 +332,10 @@ function ajax_form_callback() {
*/
function ajax_deliver($page_callback_result) {
$commands = array();
+ $header = TRUE;
+
+ // Normalize whatever was returned by the page callback to an AJAX commands
+ // array.
if (!isset($page_callback_result)) {
// Simply delivering an empty commands array is sufficient. This results
// in the AJAX request being completed, but nothing being done to the page.
@@ -388,11 +356,20 @@ function ajax_deliver($page_callback_result) {
break;
}
}
- elseif (is_array($page_callback_result) && isset($page_callback_result['#type']) && ($page_callback_result['#type'] == 'ajax_commands')) {
- // Complex AJAX callbacks can return a result that contains a specific
- // set of commands to send to the browser.
- if (isset($page_callback_result['#ajax_commands'])) {
- $commands = $page_callback_result['#ajax_commands'];
+ elseif (is_array($page_callback_result) && isset($page_callback_result['#type']) && ($page_callback_result['#type'] == 'ajax')) {
+ // Complex AJAX callbacks can return a result that contains an error message
+ // or a specific set of commands to send to the browser.
+ $page_callback_result += element_info('ajax');
+ $header = $page_callback_result['#header'];
+ $error = $page_callback_result['#error'];
+ if (isset($error) && $error !== FALSE) {
+ if ((empty($error) || $error === TRUE)) {
+ $error = t('An error occurred while handling the request: The server received invalid input.');
+ }
+ $commands[] = ajax_command_alert($error);
+ }
+ else {
+ $commands = $page_callback_result['#commands'];
}
}
else {
@@ -405,7 +382,49 @@ function ajax_deliver($page_callback_result) {
$commands[] = ajax_command_replace(NULL, $html);
$commands[] = ajax_command_prepend(NULL, theme('status_messages'));
}
- ajax_render($commands);
+
+ // This function needs to do the same thing that drupal_deliver_html_page()
+ // does: add any needed http headers, print rendered output, and perform
+ // end-of-request tasks. By default, $header=TRUE, and we add a
+ // 'text/javascript' header. The page callback can override $header by
+ // returning an 'ajax' element with a #header property. This can be set to
+ // FALSE to prevent the 'text/javascript' header from being output, necessary
+ // when outputting to an IFRAME. This can also be set to 'multipart', in which
+ // case, we don't output JSON, but JSON content wrapped in a textarea, making
+ // a 'text/javascript' header incorrect.
+ if ($header && $header !== 'multipart') {
+ drupal_add_http_header('Content-Type', 'text/javascript; charset=utf-8');
+ }
+ $output = ajax_render($commands);
+ if ($header === 'multipart') {
+ // jQuery file uploads: http://malsup.com/jquery/form/#code-samples
+ $output = '<textarea>' . $output . '</textarea>';
+ }
+ print $output;
+ ajax_footer();
+}
+
+/**
+ * Perform end-of-AJAX-request tasks.
+ *
+ * This function is the equivalent of drupal_page_footer(), but for AJAX
+ * requests.
+ *
+ * @see drupal_page_footer()
+ */
+function ajax_footer() {
+ // Even for AJAX requests, invoke hook_exit() implementations. There may be
+ // modules that need very fast AJAX responses, and therefore, run AJAX
+ // requests with an early bootstrap.
+ if (drupal_get_bootstrap_phase() == DRUPAL_BOOTSTRAP_FULL && (!defined('MAINTENANCE_MODE') || MAINTENANCE_MODE != 'update')) {
+ module_invoke_all('exit');
+ }
+
+ // Commit the user session. See above comment about the possibility of this
+ // function running without session.inc loaded.
+ if (function_exists('drupal_session_commit')) {
+ drupal_session_commit();
+ }
}
/**