diff options
author | Dries Buytaert <dries@buytaert.net> | 2010-03-13 06:55:50 +0000 |
---|---|---|
committer | Dries Buytaert <dries@buytaert.net> | 2010-03-13 06:55:50 +0000 |
commit | 5e32593f3d7c1dd7412e9f918efa3121ff9e6565 (patch) | |
tree | 25896319767e65552e98f7246c89748d9297ab20 /includes/ajax.inc | |
parent | 1106db64560976f8baa1e7ebaa45fd7c4917c2e1 (diff) | |
download | brdo-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.inc | 119 |
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(); + } } /** |