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	13 Feb 2010 02:07:16 -0000
@@ -203,9 +203,67 @@ 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);
+  foreach ($scripts as $type => $data) {
+    switch ($type) {
+      case 'setting':
+        $settings = $data;
+        break;
+
+      case 'inline':
+        // presently we ignore inline javascript.
+        break;
+
+      default:
+        // If JS preprocessing is off, we still need to output the scripts.
+        // Additionally, go through any remaining scripts if JS preprocessing is
+        // on and output the non-cached ones.
+        foreach ($data as $path => $info) {
+          $js_files[] = base_path() . $path . ($info['cache'] ? $query_string : '?' . REQUEST_TIME);
+        }
+    }
+  }
+
+  $css = drupal_add_css();
+  foreach ($css as $media => $types) {
+    // If CSS preprocessing is off, we still need to output the styles.
+    // Additionally, go through any remaining styles if CSS preprocessing is on
+    // and output the non-cached ones.
+    foreach ($types as $type => $files) {
+      if ($type == 'module') {
+        // Setup theme overrides for module styles.
+        $theme_styles = array();
+        foreach (array_keys($css[$media]['theme']) as $theme_style) {
+          $theme_styles[] = basename($theme_style);
+        }
+      }
+      foreach ($types[$type] as $file => $preprocess) {
+        // If the theme supplies its own style using the name of the module style, skip its inclusion.
+        // This includes any RTL styles associated with its main LTR counterpart.
+        if ($type == 'module' && in_array(str_replace('-rtl.css', '.css', basename($file)), $theme_styles)) {
+          // Unset the file to prevent its inclusion when CSS aggregation is enabled.
+          unset($types[$type][$file]);
+          continue;
+        }
+        // Only include the stylesheet if it exists.
+        if (file_exists($file)) {
+          $css_files[] = array(
+            'file' => base_path() . $file . $query_string,
+            'media' => $media,
+          );
+        }
+      }
+    }
+  }
+
   if (!empty($scripts['settings'])) {
     array_unshift($commands, ajax_command_settings(call_user_func_array('array_merge_recursive', $scripts['settings']['data'])));
   }
+  if (!empty($js_files)) {
+    array_unshift($commands, ctools_ajax_command_scripts($js_files));
+  }
+  if (!empty($css_files)) {
+    array_unshift($commands, ctools_ajax_command_css_files($css_files));
+  }
 
   // Allow modules to alter any AJAX response.
   drupal_alter('ajax_render', $commands);
@@ -911,3 +969,46 @@ function ajax_command_restripe($selector
   );
 }
 
+/**
+ * Create a CSS files command for the AJAX responder.
+ *
+ * This will directly add CSS to the page.
+ *
+ * This command is implemented by Drupal.ajax.prototype.commands.css_files()
+ * defined in misc/ajax.js.
+ *
+ * @param $files
+ *   @todo
+ *
+ * @return
+ *   An array suitable for use with the ajax_render() function.
+ */
+function ajax_command_css_files($files) {
+  return array(
+    'command' => 'css_files',
+    'files' => $files,
+  );
+}
+
+/**
+ * Creates scripts command for the AJAX responder.
+ *
+ * This will add JavaScript files to the output. Files that have already
+ * been processed will not be processed again.
+ *
+ * This command is implemented by Drupal.ajax.prototype.commands.scripts()
+ * defined in misc/ajax.js.
+ *
+ * @param $files
+ *   @todo
+ *
+ * @return
+ *   An array suitable for use with the ajax_render() function.
+ */
+function ajax_command_scripts($files) {
+  return array(
+    'command' => 'scripts',
+    'files' => $files,
+  );
+}
+
Index: misc/ajax.js
===================================================================
RCS file: /cvs/drupal/drupal/misc/ajax.js,v
retrieving revision 1.10
diff -u -p -r1.10 ajax.js
--- misc/ajax.js	3 Feb 2010 08:23:12 -0000	1.10
+++ misc/ajax.js	13 Feb 2010 02:08:31 -0000
@@ -13,7 +13,7 @@
  * to provide AJAX capabilities.
  */
 
-Drupal.ajax = Drupal.ajax || {};
+Drupal.ajax = Drupal.ajax || { scripts: {}, css: {} };
 
 /**
  * Attaches the AJAX behavior to each AJAX form element.
@@ -415,6 +415,51 @@ Drupal.ajax.prototype.commands = {
   },
 
   /**
+   * @todo
+   */
+  css_files: function (ajax, response, status) {
+    // Build a list of scripts already loaded.
+    $('link:not(.ajax-temporary-css)').each(function () {
+      if (this.type == 'text/css') {
+        Drupal.ajax.css[this.href] = this.href;
+      }
+    });
+
+    var html = '';
+    for (var i in response.files) {
+      if (!Drupal.ajax.css[response.files[i].file]) {
+        html += '<link class="ajax-temporary-css" type="text/css" rel="stylesheet" media="' + response.files[i].media + '" href="' + response.files[i].file + '" />';
+      }
+    }
+    if (html) {
+      $('link.ajax-temporary-css').remove();
+      $('body').append(html);
+    }
+  },
+
+  /**
+   * @todo
+   */
+  scripts: function (ajax, response, status) {
+    // Build a list of scripts already loaded.
+    var scripts = {};
+    $('script').each(function () {
+      Drupal.ajax.scripts[this.src] = this.src;
+    });
+
+    var html = '';
+    for (var i in response.files) {
+      if (!Drupal.ajax.scripts[response.files[i]]) {
+        Drupal.ajax.scripts[response.files[i]] = response.files[i];
+        html += '<script type="text/javascript" src="' + response.files[i] + '"></script>';
+      }
+    }
+    if (html) {
+      $('body').append(html);
+    }
+  },
+
+  /**
    * Command to attach data using jQuery's data API.
    */
   data: function (ajax, response, status) {
