diff --git a/core/includes/ajax.inc b/core/includes/ajax.inc
index a20acd8..6e2c66d 100644
--- a/core/includes/ajax.inc
+++ b/core/includes/ajax.inc
@@ -244,7 +244,7 @@ function ajax_render($commands = array()) {
       $items[$type] = array();
     }
     else {
-      $function = 'drupal_add_' . $type;
+      $function = '_drupal_get_' . $type;
       $items[$type] = $function();
       drupal_alter($type, $items[$type]);
       // @todo Inline CSS and JS items are indexed numerically. These can't be
@@ -289,10 +289,10 @@ function ajax_render($commands = array()) {
   }
 
   // Now add a command to merge changes and additions to Drupal.settings.
-  $scripts = drupal_add_js();
+  $scripts = _drupal_get_js();
   if (!empty($scripts['settings'])) {
     $settings = $scripts['settings'];
-    array_unshift($commands, ajax_command_settings(call_user_func_array('array_merge_recursive', $settings['data']), TRUE));
+    array_unshift($commands, ajax_command_settings($settings['data'], TRUE));
   }
 
   // Allow modules to alter any Ajax response.
diff --git a/core/includes/common.inc b/core/includes/common.inc
index 14154af..814b62e 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -2986,6 +2986,17 @@ function drupal_add_css($data = NULL, $options = NULL) {
  * @see drupal_add_css()
  */
 function drupal_get_css($css = NULL, $skip_alter = FALSE) {
+  $css = _drupal_get_css($css, $skip_alter);
+  // Render the HTML needed to load the CSS.
+  $styles = array(
+    '#type' => 'styles',
+    '#items' => $css,
+  );
+
+  return drupal_render($styles);
+}
+
+function _drupal_get_css($css = NULL, $skip_alter = FALSE) {
   if (!isset($css)) {
     $css = drupal_add_css();
   }
@@ -2998,18 +3009,6 @@ function drupal_get_css($css = NULL, $skip_alter = FALSE) {
   // Sort CSS items, so that they appear in the correct order.
   uasort($css, 'drupal_sort_css_js');
 
-  // Provide the page with information about the individual CSS files used,
-  // information not otherwise available when CSS aggregation is enabled. The
-  // setting is attached later in this function, but is set here, so that CSS
-  // files removed below are still considered "used" and prevented from being
-  // added in a later AJAX request.
-  // Skip if no files were added to the page or jQuery.extend() will overwrite
-  // the Drupal.settings.ajaxPageState.css object with an empty array.
-  if (!empty($css)) {
-    // Cast the array to an object to be on the safe side even if not empty.
-    $setting['ajaxPageState']['css'] = (object) array_fill_keys(array_keys($css), 1);
-  }
-
   // Remove the overridden CSS files. Later CSS files override former ones.
   $previous_item = array();
   foreach ($css as $key => $item) {
@@ -3024,16 +3023,7 @@ function drupal_get_css($css = NULL, $skip_alter = FALSE) {
     }
   }
 
-  // Render the HTML needed to load the CSS.
-  $styles = array(
-    '#type' => 'styles',
-    '#items' => $css,
-  );
-  if (!empty($setting)) {
-    $styles['#attached']['js'][] = array('type' => 'setting', 'data' => $setting);
-  }
-
-  return drupal_render($styles);
+  return $css;
 }
 
 /**
@@ -4051,7 +4041,7 @@ function drupal_region_class($region) {
  *
  * @see drupal_get_js()
  */
-function drupal_add_js($data = NULL, $options = NULL) {
+function &drupal_add_js($data = NULL, $options = NULL) {
   $javascript = &drupal_static(__FUNCTION__, array());
 
   // Construct the options, taking the defaults into consideration.
@@ -4073,53 +4063,22 @@ function drupal_add_js($data = NULL, $options = NULL) {
   $options['weight'] += count($javascript) / 1000;
 
   if (isset($data)) {
-    // Add jquery.js and drupal.js, as well as the basePath setting, the
-    // first time a JavaScript file is added.
-    if (empty($javascript)) {
-      // url() generates the script and prefix using hook_url_outbound_alter().
-      // Instead of running the hook_url_outbound_alter() again here, extract
-      // them from url().
-      // @todo Make this less hacky: http://drupal.org/node/1547376.
-      $scriptPath = $GLOBALS['script_path'];
-      $pathPrefix = '';
-      url('', array('script' => &$scriptPath, 'prefix' => &$pathPrefix));
-      $javascript = array(
-        'settings' => array(
-          'data' => array(
-            array('basePath' => base_path()),
-            array('scriptPath' => $scriptPath),
-            array('pathPrefix' => $pathPrefix),
-          ),
-          'type' => 'setting',
-          'scope' => 'header',
-          'group' => JS_SETTING,
-          'every_page' => TRUE,
-          'weight' => 0,
-          'browsers' => array(),
-        ),
-        'core/misc/drupal.js' => array(
-          'data' => 'core/misc/drupal.js',
-          'type' => 'file',
-          'scope' => 'header',
-          'group' => JS_LIBRARY,
-          'every_page' => TRUE,
-          'weight' => -1,
-          'preprocess' => TRUE,
-          'cache' => TRUE,
-          'defer' => FALSE,
-          'browsers' => array(),
-        ),
-      );
-      // Register all required libraries.
-      drupal_add_library('system', 'jquery', TRUE);
-      drupal_add_library('system', 'jquery.once', TRUE);
-      drupal_add_library('system', 'html5shiv', TRUE);
-    }
-
     switch ($options['type']) {
       case 'setting':
-        // All JavaScript settings are placed in the header of the page with
-        // the library weight so that inline scripts appear afterwards.
+        // Add basic structure for the settings.
+        if (!isset($javascript['settings']['data'])) {
+          $javascript += array(
+            'settings' => array(
+              'data' => array(),
+              'type' => 'setting',
+              'scope' => 'header',
+              'group' => JS_SETTING,
+              'every_page' => TRUE,
+              'weight' => 0,
+              'browsers' => array(),
+            ),
+          );
+        }
         $javascript['settings']['data'][] = $data;
         break;
 
@@ -4158,10 +4117,86 @@ function drupal_js_defaults($data = NULL) {
     'version' => NULL,
     'data' => $data,
     'browsers' => array(),
+    'jsonly' => FALSE,
   );
 }
 
 /**
+ * Conditionally adds the default Drupal/jQuery libraries to the page.
+ *
+ * @see drupal_add_js()
+ * @see drupal_get_js()
+ */
+function drupal_add_js_page_defaults() {
+  $javascript = &drupal_add_js();
+
+  $libraries_added = &drupal_static(__FUNCTION__, FALSE);
+  if (!$libraries_added) {
+    $libraries_added = TRUE;
+    // Check if there's only pure javascript added, in this case we don't need
+    // to our default libraries.
+    $own_js_needed = FALSE;
+    foreach ($javascript as $key => $js) {
+      // if there're settings added we need our default libraries
+      if ($key == 'settings') {
+        $own_js_needed = TRUE;
+        break;
+      }
+      elseif (!isset($js['jsonly']) || !$js['jsonly']) {
+        $own_js_needed = TRUE;
+        break;
+      }
+    }
+
+    if ($own_js_needed) {
+      // url() generates the script and prefix using hook_url_outbound_alter().
+      // Instead of running the hook_url_outbound_alter() again here, extract
+      // them from url().
+      // @todo Make this less hacky: http://drupal.org/node/1547376.
+      $scriptPath = $GLOBALS['script_path'];
+      $pathPrefix = '';
+      url('', array('script' => &$scriptPath, 'prefix' => &$pathPrefix));
+      drupal_add_js(array('basePath' => base_path()), 'setting');
+      drupal_add_js(array('scriptPath' => $scriptPath), 'setting');
+      drupal_add_js(array('pathPrefix' => $pathPrefix), 'setting');
+
+      // Provide the page with information about the theme that's used, so that a
+      // later Ajax request can be rendered using the same theme.
+      // @see ajax_base_page_theme()
+      if (!defined('MAINTENANCE_MODE') || MAINTENANCE_MODE !== 'install') {
+        global $theme_key;
+        $settings['ajaxPageState'] = array(
+          'theme' => $theme_key,
+          'theme_token' => drupal_get_token($theme_key),
+        );
+        drupal_add_js($settings, 'setting');
+      }
+
+      // Add drupal.js.
+      drupal_add_js('core/misc/drupal.js', array(
+        'data' => 'core/misc/drupal.js',
+        'type' => 'file',
+        'scope' => 'header',
+        'group' => JS_LIBRARY,
+        'every_page' => TRUE,
+        'weight' => -1,
+        'preprocess' => TRUE,
+        'cache' => TRUE,
+        'defer' => FALSE,
+        'browsers' => array(),
+      ));
+
+      // Add required libraries.
+      drupal_add_library('system', 'jquery', TRUE);
+      drupal_add_library('system', 'jquery.once', TRUE);
+    }
+    // Unconditionally add the html5shiv to all pages; it is required for
+    // backwards-compatible CSS styling and has no dependencies.
+    drupal_add_library('system', 'html5shiv', TRUE);
+  }
+}
+
+/**
  * Returns a themed presentation of all JavaScript code for the current page.
  *
  * References to JavaScript files are placed in a certain order: first, all
@@ -4190,18 +4225,61 @@ function drupal_js_defaults($data = NULL) {
  * @return
  *   All JavaScript code segments and includes for the scope as HTML tags.
  *
+ * @see _drupal_get_js()
  * @see drupal_add_js()
  * @see locale_js_alter()
  * @see drupal_js_defaults()
  */
 function drupal_get_js($scope = 'header', $javascript = NULL, $skip_alter = FALSE) {
+  $items = _drupal_get_js($scope, $javascript, $skip_alter);
+
+  // Make sure we have an array, otherwise drupal_group_js will fail
+  if (empty($items) && !is_array($items)) {
+    $items = array();
+    // Unconditionally add the html5shiv to all pages; it is required for
+    // backwards-compatible CSS styling and has no dependencies.
+    // @TODO: find a better way
+    if ($scope == 'header' && !isset($_POST['ajax_page_state'])) {
+      if ($library = drupal_get_library('system', 'html5shiv')) {
+        if ($library['js']) {
+          $js = $library['js'];
+          $key = key($js);
+          $js[$key]['data'] = $key;
+          $js[$key]['type'] = 'file';
+          $js[$key]['preprocess'] = FALSE;
+          $js[$key]['cache'] = TRUE;
+          $items = $js;
+        }
+      }
+    }
+  }
+
+  // Render the HTML needed to load the JavaScript.
+  $elements = array(
+    '#type' => 'scripts',
+    '#items' => $items,
+  );
+
+  return drupal_render($elements);
+}
+
+/**
+ * Returns the structured array of javascript.
+ *
+ * @see drupal_get_js()
+ */
+function _drupal_get_js($scope = 'header', $javascript = NULL, $skip_alter = FALSE) {
   if (!isset($javascript)) {
-    $javascript = drupal_add_js();
+    $javascript = &drupal_add_js();
   }
+
   if (empty($javascript)) {
     return '';
   }
 
+  // Add default libraries
+  drupal_add_js_page_defaults();
+
   // Allow modules to alter the JavaScript.
   if (!$skip_alter) {
     drupal_alter('js', $javascript);
@@ -4218,12 +4296,6 @@ function drupal_get_js($scope = 'header', $javascript = NULL, $skip_alter = FALS
   // Sort the JavaScript so that it appears in the correct order.
   uasort($items, 'drupal_sort_css_js');
 
-  // Provide the page with information about the individual JavaScript files
-  // used, information not otherwise available when aggregation is enabled.
-  $setting['ajaxPageState']['js'] = array_fill_keys(array_keys($items), 1);
-  unset($setting['ajaxPageState']['js']['settings']);
-  drupal_add_js($setting, 'setting');
-
   // If we're outputting the header scope, then this might be the final time
   // that drupal_get_js() is running, so add the setting to this output as well
   // as to the drupal_add_js() cache. If $items['settings'] doesn't exist, it's
@@ -4231,16 +4303,32 @@ function drupal_get_js($scope = 'header', $javascript = NULL, $skip_alter = FALS
   // stripped of settings, potentially in order to override how settings get
   // output, so in this case, do not add the setting to this output.
   if ($scope == 'header' && isset($items['settings'])) {
+    // Provide the page with information about the individual JavaScript files
+    // used, information not otherwise available when aggregation is enabled.
+    // This uses $javascript so everything is added regardless of the scope.
+    foreach ($javascript as $key => $item) {
+      $setting['ajaxPageState']['js'][$key] = 1;
+    }
+    unset($setting['ajaxPageState']['js']['settings']);
+
+    // Provide the page with information about the individual CSS files used,
+    // information not otherwise available when CSS aggregation is enabled. The
+    // setting is attached later in this function, but is set here, so that CSS
+    // files removed below are still considered "used" and prevented from being
+    // added in a later AJAX request.
+    // Skip if no files were added to the page or jQuery.extend() will overwrite
+    // the Drupal.settings.ajaxPageState.css object with an empty array.
+    $css = _drupal_get_css(NULL, $skip_alter);
+    if (!empty($css)) {
+      // Cast the array to an object to be on the safe side even if not empty.
+      $setting['ajaxPageState']['css'] = (object) array_fill_keys(array_keys($css), 1);
+    }
+
     $items['settings']['data'][] = $setting;
+    $items['settings']['data'] = drupal_array_merge_deep_array($items['settings']['data']);
   }
 
-  // Render the HTML needed to load the JavaScript.
-  $elements = array(
-    '#type' => 'scripts',
-    '#items' => $items,
-  );
-
-  return drupal_render($elements);
+  return $items;
 }
 
 /**
@@ -4330,7 +4418,7 @@ function drupal_pre_render_scripts($elements) {
         switch ($item['type']) {
           case 'setting':
             $element['#value_prefix'] = $embed_prefix;
-            $element['#value'] = 'jQuery.extend(Drupal.settings, ' . drupal_json_encode(drupal_array_merge_deep_array($item['data'])) . ");";
+            $element['#value'] = 'jQuery.extend(Drupal.settings, ' . drupal_json_encode($item['data']) . ");";
             $element['#value_suffix'] = $embed_suffix;
             break;
 
diff --git a/core/includes/theme.inc b/core/includes/theme.inc
index 2a88969..73ec3b7 100644
--- a/core/includes/theme.inc
+++ b/core/includes/theme.inc
@@ -101,15 +101,6 @@ function drupal_theme_initialize() {
 
   // Themes can have alter functions, so reset the drupal_alter() cache.
   drupal_static_reset('drupal_alter');
-
-  // Provide the page with information about the theme that's used, so that a
-  // later Ajax request can be rendered using the same theme.
-  // @see ajax_base_page_theme()
-  $setting['ajaxPageState'] = array(
-    'theme' => $theme_key,
-    'theme_token' => drupal_get_token($theme_key),
-  );
-  drupal_add_js($setting, 'setting');
 }
 
 /**
diff --git a/core/modules/file/file.module b/core/modules/file/file.module
index 0aef8de..4d01bcc 100644
--- a/core/modules/file/file.module
+++ b/core/modules/file/file.module
@@ -279,8 +279,8 @@ function file_ajax_upload() {
   }
 
   $output = theme('status_messages') . drupal_render($form);
-  $js = drupal_add_js();
-  $settings = call_user_func_array('array_merge_recursive', $js['settings']['data']);
+  $js = _drupal_get_js();
+  $settings = $js['settings']['data'];
 
   $commands = array();
   $commands[] = ajax_command_replace(NULL, $output, $settings);
diff --git a/core/modules/simpletest/drupal_web_test_case.php b/core/modules/simpletest/drupal_web_test_case.php
index 23fa526..eb78c1f 100644
--- a/core/modules/simpletest/drupal_web_test_case.php
+++ b/core/modules/simpletest/drupal_web_test_case.php
@@ -2127,7 +2127,9 @@ class DrupalWebTestCase extends DrupalTestCase {
     }
     if (isset($drupal_settings['ajaxPageState'])) {
       $extra_post .= '&' . urlencode('ajax_page_state[theme]') . '=' . urlencode($drupal_settings['ajaxPageState']['theme']);
-      $extra_post .= '&' . urlencode('ajax_page_state[theme_token]') . '=' . urlencode($drupal_settings['ajaxPageState']['theme_token']);
+      if (isset($drupal_settings['ajaxPageState']['theme_token'])) {
+        $extra_post .= '&' . urlencode('ajax_page_state[theme_token]') . '=' . urlencode($drupal_settings['ajaxPageState']['theme_token']);
+      }
       foreach ($drupal_settings['ajaxPageState']['css'] as $key => $value) {
         $extra_post .= '&' . urlencode("ajax_page_state[css][$key]") . '=1';
       }
diff --git a/core/modules/system/tests/common.test b/core/modules/system/tests/common.test
index 46b379e..76d5ab5 100644
--- a/core/modules/system/tests/common.test
+++ b/core/modules/system/tests/common.test
@@ -1128,6 +1128,7 @@ class CommonJavaScriptTestCase extends DrupalWebTestCase {
     // Reset drupal_add_js() and drupal_add_library() statics before each test.
     drupal_static_reset('drupal_add_js');
     drupal_static_reset('drupal_add_library');
+    drupal_static_reset('_drupal_get_js');
   }
 
   function tearDown() {
@@ -1149,23 +1150,25 @@ class CommonJavaScriptTestCase extends DrupalWebTestCase {
    * Test adding a JavaScript file.
    */
   function testAddFile() {
-    $javascript = drupal_add_js('core/misc/collapse.js');
+    drupal_add_js('core/misc/collapse.js');
+    $javascript = _drupal_get_js();
     $this->assertTrue(array_key_exists('core/misc/jquery.js', $javascript), t('jQuery is added when a file is added.'));
     $this->assertTrue(array_key_exists('core/misc/drupal.js', $javascript), t('Drupal.js is added when file is added.'));
     $this->assertTrue(array_key_exists('core/misc/html5.js', $javascript), t('html5.js is added when file is added.'));
     $this->assertTrue(array_key_exists('core/misc/collapse.js', $javascript), t('JavaScript files are correctly added.'));
-    $this->assertEqual(base_path(), $javascript['settings']['data'][0]['basePath'], t('Base path JavaScript setting is correctly set.'));
-    $this->assertIdentical($GLOBALS['script_path'], $javascript['settings']['data'][1]['scriptPath'], t('Script path JavaScript setting is correctly set.'));
-    $this->assertIdentical('', $javascript['settings']['data'][2]['pathPrefix'], t('Path prefix JavaScript setting is correctly set.'));
+    $this->assertEqual(base_path(), $javascript['settings']['data']['basePath'], t('Base path JavaScript setting is correctly set.'));
+    $this->assertIdentical($GLOBALS['script_path'], $javascript['settings']['data']['scriptPath'], t('Script path JavaScript setting is correctly set.'));
+    $this->assertIdentical('', $javascript['settings']['data']['pathPrefix'], t('Path prefix JavaScript setting is correctly set.'));
   }
 
   /**
    * Test adding settings.
    */
   function testAddSetting() {
-    $javascript = drupal_add_js(array('drupal' => 'rocks', 'dries' => 280342800), 'setting');
-    $this->assertEqual(280342800, $javascript['settings']['data'][3]['dries'], t('JavaScript setting is set correctly.'));
-    $this->assertEqual('rocks', $javascript['settings']['data'][3]['drupal'], t('The other JavaScript setting is set correctly.'));
+    drupal_add_js(array('drupal' => 'rocks', 'dries' => 280342800), 'setting');
+    $javascript = _drupal_get_js();
+    $this->assertEqual(280342800, $javascript['settings']['data']['dries'], t('JavaScript setting is set correctly.'));
+    $this->assertEqual('rocks', $javascript['settings']['data']['drupal'], t('The other JavaScript setting is set correctly.'));
   }
 
   /**
@@ -1181,6 +1184,7 @@ class CommonJavaScriptTestCase extends DrupalWebTestCase {
    * Test drupal_get_js() for JavaScript settings.
    */
   function testHeaderSetting() {
+    drupal_static_reset('_drupal_get_js');
     // Only the second of these two entries should appear in Drupal.settings.
     drupal_add_js(array('commonTest' => 'commonTestShouldNotAppear'), 'setting');
     drupal_add_js(array('commonTest' => 'commonTestShouldAppear'), 'setting');
@@ -1192,7 +1196,7 @@ class CommonJavaScriptTestCase extends DrupalWebTestCase {
     drupal_add_js(array('commonTestArray' => array('key' => 'commonTestOldValue')), 'setting');
     drupal_add_js(array('commonTestArray' => array('key' => 'commonTestNewValue')), 'setting');
 
-    $javascript = drupal_get_js('header');
+    $javascript = drupal_get_js();
     $this->assertTrue(strpos($javascript, 'basePath') > 0, t('Rendered JavaScript header returns basePath setting.'));
     $this->assertTrue(strpos($javascript, 'scriptPath') > 0, t('Rendered JavaScript header returns scriptPath setting.'));
     $this->assertTrue(strpos($javascript, 'pathPrefix') > 0, t('Rendered JavaScript header returns pathPrefix setting.'));
@@ -1226,11 +1230,13 @@ class CommonJavaScriptTestCase extends DrupalWebTestCase {
    * Test adding inline scripts.
    */
   function testAddInline() {
+    drupal_static_reset('_drupal_get_js');
     $inline = 'jQuery(function () { });';
-    $javascript = drupal_add_js($inline, array('type' => 'inline', 'scope' => 'footer'));
+    drupal_add_js($inline, array('type' => 'inline', 'scope' => 'footer'));
+    $javascript = _drupal_get_js();
     $this->assertTrue(array_key_exists('core/misc/jquery.js', $javascript), t('jQuery is added when inline scripts are added.'));
-    $data = end($javascript);
-    $this->assertEqual($inline, $data['data'], t('Inline JavaScript is correctly added to the footer.'));
+    $data = drupal_get_js('footer');
+    $this->assertEqual(strpos($data, $inline) > 0, t('Inline JavaScript is correctly added to the footer.'));
   }
 
   /**
@@ -1274,7 +1280,8 @@ class CommonJavaScriptTestCase extends DrupalWebTestCase {
    * Test adding a JavaScript file with a different weight.
    */
   function testDifferentWeight() {
-    $javascript = drupal_add_js('core/misc/collapse.js', array('weight' => 2));
+    drupal_add_js('core/misc/collapse.js', array('weight' => 2));
+    $javascript = _drupal_get_js();
     $this->assertEqual($javascript['core/misc/collapse.js']['weight'], 2, t('Adding a JavaScript file with a different weight caches the given weight.'));
   }
 
@@ -1333,6 +1340,7 @@ class CommonJavaScriptTestCase extends DrupalWebTestCase {
     // Now ensure that with aggregation on, one file is made for the
     // 'every_page' files, and one file is made for the others.
     drupal_static_reset('drupal_add_js');
+    drupal_static_reset('drupal_add_js_page_defaults');
     $config = config('system.performance');
     $config->set('preprocess_js', 1);
     $config->save();
@@ -1340,7 +1348,7 @@ class CommonJavaScriptTestCase extends DrupalWebTestCase {
     drupal_add_js('core/misc/authorize.js', array('every_page' => TRUE));
     drupal_add_js('core/misc/autocomplete.js');
     drupal_add_js('core/misc/batch.js', array('every_page' => TRUE));
-    $js_items = drupal_add_js();
+    $js_items = _drupal_get_js();
     $javascript = drupal_get_js();
     $expected = implode("\n", array(
       '<script type="text/javascript" src="' . file_create_url(drupal_build_js_cache(array('core/misc/authorize.js' => $js_items['core/misc/authorize.js'], 'core/misc/batch.js' => $js_items['core/misc/batch.js']))) . '"></script>',
@@ -1553,6 +1561,40 @@ class CommonJavaScriptTestCase extends DrupalWebTestCase {
     $query_string = variable_get('css_js_query_string', '0');
     $this->assertRaw(drupal_get_path('module', 'node') . '/node.js?' . $query_string, t('Query string was appended correctly to js.'));
   }
+
+  /**
+   * Tests that Drupal.settings aren't added when not needed.
+   */
+  function testPageWithoutJavascript() {
+    $this->drupalGet('');
+    $content = $this->drupalGetContent();
+    $this->assertTrue(strpos($content, 'Drupal.settings') === FALSE, t('Drupal.settings is not added to the page.'));
+    $this->assertTrue(strpos($content, 'jquery.js') === FALSE, t('No default javascript is added to the page.'));
+    $this->assertTrue(strpos($content, 'html5.js') !== FALSE, t('html5shiv is added to the page.'));
+  }
+
+  /**
+   * Tests that Drupal.settings aren't added when not needed.
+   */
+  function testPageWithOnlyPureJavascript() {
+    drupal_add_js(drupal_get_path('module', 'simpletest') . '/simpletest.js', array('jsonly' => TRUE));
+    $scripts = drupal_get_js();
+    $this->assertTrue(strpos($scripts, 'Drupal.settings') === FALSE, t('Drupal.settings is not added to the page.'));
+    $this->assertTrue(strpos($scripts, 'jquery.js') === FALSE, t('No default javascript is added to the page.'));
+    $this->assertTrue(strpos($scripts, 'simpletest.js') !== FALSE, t('simpletest.js is added to the page.'));
+    $this->assertTrue(strpos($scripts, 'html5.js') !== FALSE, t('html5shiv is added to the page.'));
+  }
+
+  /**
+  * Tests that Drupal.settings are added when only a settings is added.
+  */
+  function testPageWithOnlyJavascriptSetting() {
+    $this->drupalGet('common-test/form-with-only-settings');
+    $content = $this->drupalGetContent();
+    $this->assertTrue(strpos($content, 'Drupal.settings') > 0, t('Drupal.settings is added to the page.'));
+    $this->assertTrue(strpos($content, '.js') > 0, t('Javascript files are added to the page.'));
+  }
+
 }
 
 /**
diff --git a/core/modules/system/tests/modules/common_test/common_test.module b/core/modules/system/tests/modules/common_test/common_test.module
index 187fee5..03d89c2 100644
--- a/core/modules/system/tests/modules/common_test/common_test.module
+++ b/core/modules/system/tests/modules/common_test/common_test.module
@@ -58,6 +58,12 @@ function common_test_menu() {
     'access arguments' => array('access content'),
     'type' => MENU_CALLBACK,
   );
+  $items['common-test/form-with-only-settings'] = array(
+    'title' => 'Form that adds only a javascript setting',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('common_test_form_with_only_settings_form'),
+    'access callback' => TRUE,
+  );
   return $items;
 }
 
@@ -288,3 +294,24 @@ function common_test_js_and_css_querystring() {
 function common_test_cron() {
   throw new Exception(t('Uncaught exception'));
 }
+
+/**
+ * A basic form that adds only a javascript setting.
+ */
+function common_test_form_with_only_settings_form($form, &$form_state) {
+  drupal_add_js(array('drupal' => 'rocks', 'dries' => 280342800), 'setting');
+  $form = array();
+  $form['select'] = array(
+    '#type' => 'select',
+    '#options' => array(
+      'red' => 'red',
+      'green' => 'green',
+      'blue' => 'blue'),
+  );
+
+  $form['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('submit'),
+  );
+  return $form;
+}
diff --git a/core/modules/system/tests/theme.test b/core/modules/system/tests/theme.test
index 025ae8d..7cb0a48 100644
--- a/core/modules/system/tests/theme.test
+++ b/core/modules/system/tests/theme.test
@@ -188,10 +188,11 @@ class ThemeTableUnitTest extends DrupalWebTestCase {
     $header = array('one', 'two', 'three');
     $rows = array(array(1,2,3), array(4,5,6), array(7,8,9));
     $this->content = theme('table', array('header' => $header, 'rows' => $rows));
-    $js = drupal_add_js();
+    $js = _drupal_get_js();
     $this->assertTrue(isset($js['core/misc/tableheader.js']), t('tableheader.js was included when $sticky = TRUE.'));
     $this->assertRaw('sticky-enabled',  t('Table has a class of sticky-enabled when $sticky = TRUE.'));
     drupal_static_reset('drupal_add_js');
+    drupal_static_reset('drupal_add_js_page_defaults');
   }
 
   /**
@@ -204,10 +205,11 @@ class ThemeTableUnitTest extends DrupalWebTestCase {
     $caption = NULL;
     $colgroups = array();
     $this->content = theme('table', array('header' => $header, 'rows' => $rows, 'attributes' => $attributes, 'caption' => $caption, 'colgroups' => $colgroups, 'sticky' => FALSE));
-    $js = drupal_add_js();
+    $js = _drupal_get_js();
     $this->assertFalse(isset($js['core/misc/tableheader.js']), t('tableheader.js was not included because $sticky = FALSE.'));
     $this->assertNoRaw('sticky-enabled',  t('Table does not have a class of sticky-enabled because $sticky = FALSE.'));
     drupal_static_reset('drupal_add_js');
+    drupal_static_reset('drupal_add_js_page_defaults');
   }
 
   /**
