diff --git includes/admin.inc includes/admin.inc
index 3973f94..56e8942 100644
--- includes/admin.inc
+++ includes/admin.inc
@@ -1667,7 +1667,7 @@ function views_ui_ajax_form($js, $key, $view, $display_id) {
     $output[] = views_ajax_command_disable_buttons();
   }
 
-  return $js ? array('#type' => 'ajax_commands', '#ajax_commands' => $output) : $output;
+  return $js ? array('#type' => 'ajax', '#commands' => $output) : $output;
 }
 
 /**
@@ -1698,7 +1698,7 @@ function views_ui_add_display($js, $view) {
       $output = array();
       $output[] = views_ajax_command_add_tab($id, $title, $body);
     }
-    $output = array('#type' => 'ajax_commands', '#ajax_commands' => $output);
+    $output = array('#type' => 'ajax', '#commands' => $output);
   }
 
   // But the non-js variant will return output if it didn't redirect us.
@@ -1829,7 +1829,7 @@ function views_ui_analyze_view($js, $view) {
     }
     $commands = array();
     $commands[] = views_ajax_command_set_form($output, t('Analyse'));
-    return $js ? array('#type' => 'ajax_commands', '#ajax_commands' => $commands) : $commands;
+    return $js ? array('#type' => 'ajax', '#commands' => $commands) : $commands;
   }
   return $output;
 }
@@ -1903,7 +1903,7 @@ function views_ui_edit_details($js, $view) {
     if (empty($output)) {
       return views_ui_regenerate_tabs($view);
     }
-    return $js ? array('#type' => 'ajax_commands', '#ajax_commands' => $output) : $output;
+    return $js ? array('#type' => 'ajax', '#commands' => $output) : $output;
 
   }
   return $output;
diff --git includes/ajax.inc includes/ajax.inc
index 1e984e9..41c9a6c 100644
--- includes/ajax.inc
+++ includes/ajax.inc
@@ -21,7 +21,6 @@ function views_ajax() {
     $path = isset($_REQUEST['view_path']) ? $_REQUEST['view_path'] : NULL;
     $dom_id = isset($_REQUEST['view_dom_id']) ? $_REQUEST['view_dom_id'] : NULL;
     $pager_element = isset($_REQUEST['pager_element']) ? $_REQUEST['pager_element'] : NULL;
-    views_include('ajax');
 
     $commands = array();
 
@@ -64,7 +63,7 @@ function views_ajax() {
     $messages = theme('status_messages');
     $commands[] = ajax_command_replace('.views-messages', $messages);
 
-    ajax_render($commands);
+    return $commands;
   }
 }
 
@@ -190,7 +189,7 @@ function views_ajax_command_trigger_preview() {
 function views_ajax_error($message) {
   $commands = array();
   $commands[] = views_ajax_command_set_form($message, t('Error'));
-  ajax_render($commands);
+  return $commands;
 }
 
 /**
diff --git views_ui.module views_ui.module
index 8091eba..c46fbeb 100644
--- views_ui.module
+++ views_ui.module
@@ -330,11 +330,11 @@ function views_ui_ajax_deliver($page_callback_result) {
         break;
     }
   }
-  elseif (is_array($page_callback_result) && isset($page_callback_result['#type']) && ($page_callback_result['#type'] == '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 a specific
     // set of commands to send to the browser.
-    if (isset($page_callback_result['#ajax_commands'])) {
-      $commands = $page_callback_result['#ajax_commands'];
+    if (isset($page_callback_result['#commands'])) {
+      $commands = $page_callback_result['#commands'];
     }
   }
   else {
@@ -349,5 +349,24 @@ function views_ui_ajax_deliver($page_callback_result) {
   }
   $js = drupal_add_js();
   $commands[] = ajax_command_settings($js['settings']['data']);
-  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();
 }
