Index: includes/ajax.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/ajax.inc,v retrieving revision 1.25 diff -u -p -r1.25 ajax.inc --- includes/ajax.inc 27 Jan 2010 11:19:11 -0000 1.25 +++ includes/ajax.inc 17 Feb 2010 04:43:39 -0000 @@ -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', '#ajax_commands' => $commands); * @endcode * * When returning an AJAX command array, it is often useful to have @@ -178,17 +179,16 @@ * $commands = array(); * $commands[] = ajax_command_replace(NULL, $output); * $commands[] = ajax_command_prepend(NULL, theme('status_messages')); - * return $commands; + * return array('#type' => 'ajax_commands', '#ajax_commands' => $commands); * @endcode * * See @link ajax_commands AJAX framework commands @endlink */ /** - * Render a commands array into JSON and exit. + * Render a commands array into JSON. * - * Commands are immediately handed back to the AJAX requester. This function - * will render and immediately exit. + * Commands are immediately handed back to the AJAX requester. * * @param $commands * A list of macro commands generated by the use of ajax_command_*() @@ -224,11 +224,10 @@ function ajax_render($commands = array() else { print drupal_json_encode($commands); } - drupal_exit(); } /** - * Send an error response back via AJAX and immediately exit. + * Send an error response back via AJAX. * * This function can be used to quickly create a command array with an error * string and send it, short-circuiting the error handling process. @@ -368,6 +367,8 @@ function ajax_form_callback() { */ function ajax_deliver($page_callback_result) { $commands = array(); + $header = TRUE; + 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. @@ -391,9 +392,9 @@ function ajax_deliver($page_callback_res 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']; - } + $page_callback_result += element_info('ajax_commands'); + $commands = $page_callback_result['#ajax_commands']; + $header = $page_callback_result['#ajax_header']; } else { // Like normal page callbacks, simple AJAX callbacks can return html @@ -405,7 +406,8 @@ function ajax_deliver($page_callback_res $commands[] = ajax_command_replace(NULL, $html); $commands[] = ajax_command_prepend(NULL, theme('status_messages')); } - ajax_render($commands); + + ajax_render($commands, $header); } /** Index: modules/field/field.form.inc =================================================================== RCS file: /cvs/drupal/drupal/modules/field/field.form.inc,v retrieving revision 1.42 diff -u -p -r1.42 field.form.inc --- modules/field/field.form.inc 12 Feb 2010 05:38:09 -0000 1.42 +++ modules/field/field.form.inc 17 Feb 2010 04:43:40 -0000 @@ -397,7 +397,7 @@ function field_add_more_js($form, $form_ $field = $field_info['field']; if ($field['cardinality'] != FIELD_CARDINALITY_UNLIMITED) { - ajax_render(array()); + return; } // Navigate to the right element in the the form. Index: modules/file/file.module =================================================================== RCS file: /cvs/drupal/drupal/modules/file/file.module,v retrieving revision 1.19 diff -u -p -r1.19 file.module --- modules/file/file.module 11 Feb 2010 17:44:47 -0000 1.19 +++ modules/file/file.module 17 Feb 2010 04:43:40 -0000 @@ -214,7 +214,7 @@ function file_ajax_upload() { drupal_set_message(t('An unrecoverable error occurred. The uploaded file likely exceeded the maximum file size (@size) that this server supports.', array('@size' => format_size(file_upload_max_size()))), 'error'); $commands = array(); $commands[] = ajax_command_replace(NULL, theme('status_messages')); - ajax_render($commands, FALSE); + return array('#type' => 'ajax_commands', '#ajax_commands' => $commands, '#ajax_header' => FALSE); } list($form, $form_state, $form_id, $form_build_id) = ajax_get_form(); @@ -224,7 +224,7 @@ function file_ajax_upload() { drupal_set_message(t('An unrecoverable error occurred. Use of this form has expired. Try reloading the page and submitting again.'), 'error'); $commands = array(); $commands[] = ajax_command_replace(NULL, theme('status_messages')); - ajax_render($commands, FALSE); + return array('#type' => 'ajax_commands', '#ajax_commands' => $commands, '#ajax_header' => FALSE); } // Get the current element and count the number of files. @@ -261,7 +261,7 @@ function file_ajax_upload() { $commands = array(); $commands[] = ajax_command_replace(NULL, $output, $settings); - ajax_render($commands, FALSE); + return array('#type' => 'ajax_commands', '#ajax_commands' => $commands, '#ajax_header' => FALSE); } /** Index: modules/simpletest/tests/ajax_test.module =================================================================== RCS file: /cvs/drupal/drupal/modules/simpletest/tests/ajax_test.module,v retrieving revision 1.2 diff -u -p -r1.2 ajax_test.module --- modules/simpletest/tests/ajax_test.module 4 Dec 2009 16:49:47 -0000 1.2 +++ modules/simpletest/tests/ajax_test.module 17 Feb 2010 04:43:41 -0000 @@ -13,12 +13,14 @@ function ajax_test_menu() { $items['ajax-test/render'] = array( 'title' => 'ajax_render', 'page callback' => 'ajax_test_render', + 'delivery callback' => 'ajax_deliver', 'access callback' => TRUE, 'type' => MENU_CALLBACK, ); $items['ajax-test/render-error'] = array( 'title' => 'ajax_render_error', 'page callback' => 'ajax_test_render_error', + 'delivery callback' => 'ajax_deliver', 'access callback' => TRUE, 'type' => MENU_CALLBACK, ); @@ -26,7 +28,7 @@ function ajax_test_menu() { } /** - * Menu callback; Copies $_GET['commands'] into $commands and ajax_render()s that. + * Menu callback; Returns $_GET['commands'] suitable for use by ajax_deliver(). * * Additionally ensures that ajax_render() incorporates JavaScript settings * by invoking drupal_add_js() with a dummy setting. @@ -40,8 +42,7 @@ function ajax_test_render() { // Add a dummy JS setting. drupal_add_js(array('ajax' => 'test'), 'setting'); - // Output AJAX commands and end the request. - ajax_render($commands); + return array('#type' => 'ajax_commands', '#ajax_commands' => $commands); } /** @@ -54,6 +55,14 @@ function ajax_test_render_error() { if (!empty($_GET['message'])) { $message = $_GET['message']; } + // AJAX callbacks are discouraged from calling ajax_render() or + // ajax_render_error() and are instead encouraged to return a render array, + // which could be an element of type 'ajax_commands' containing the desired + // commands. Here, however, we want to test the ajax_render_error() function + // explicitly. But then we must exit so that ajax_deliver() doesn't issue a + // second ajax_render() call. A real AJAX callback wishing to return an error + // message should return a render array with '#ajax_commands' including a + // ajax_command_alert() command. ajax_render_error($message); + drupal_exit(); } - Index: modules/system/system.module =================================================================== RCS file: /cvs/drupal/drupal/modules/system/system.module,v retrieving revision 1.889 diff -u -p -r1.889 system.module --- modules/system/system.module 13 Feb 2010 21:41:58 -0000 1.889 +++ modules/system/system.module 17 Feb 2010 04:43:42 -0000 @@ -310,6 +310,7 @@ function system_element_info() { // debugging page that displays rather than executes AJAX commands). $types['ajax_commands'] = array( '#ajax_commands' => array(), + '#ajax_header' => TRUE, ); $types['html_tag'] = array(