diff --git a/includes/common.inc b/includes/common.inc
index 865877df4ca489bd3e3cabe1fa5c34a131b8fade..cbdb54f73c9a3ff8eed61e02e1c3d70ddb96f89a 100644
--- a/includes/common.inc
+++ b/includes/common.inc
@@ -1276,44 +1276,129 @@ function drupal_get_css($css = NULL) {
 }
 
 /**
- * Add a JavaScript file to the output.
+ * Add a JavaScript file, setting or inline code to the page.
  *
- * The first time this function is invoked per page request,
- * it adds "misc/drupal.js" to the output. Other scripts
- * depends on the 'killswitch' inside it.
+ * The behavior of this function depends on the parameters it is called with.
+ * Generally, it handles the addition of JavaScript to the page, either as
+ * reference to an existing file or as inline code. The following actions can be
+ * performed using this function:
+ *
+ * - Add a file ('core', 'module' and 'theme'):
+ *   Adds a reference to a JavaScript file to the page. JavaScript files
+ *   are placed in a certain order, from 'core' first, to 'module' and finally
+ *   'theme' so that files, that are added later, can override previously added
+ *   files with ease.
+ *
+ * - Add inline JavaScript code ('inline'):
+ *   Executes a piece of JavaScript code on the current page by placing the code
+ *   directly in the page. This can, for example, be useful to tell the user that
+ *   a new message arrived, by opening a pop up, alert box etc.
+ *
+ * - Add settings ('setting'):
+ *   Adds a setting to Drupal's global storage of JavaScript settings. Per-page
+ *   settings are required by some modules to function properly. The settings
+ *   will be accessible at Drupal.settings.
+ *
+ * @param $data
+ *   (optional) If given, the value depends on the $type parameter:
+ *   - 'core', 'module' or 'theme': Path to the file relative to base_path().
+ *   - 'inline': The JavaScript code that should be placed in the given scope.
+ *   - 'setting': An array with configuration options as associative array. The
+ *       array is directly placed in Drupal.settings. You might want to wrap your
+ *       actual configuration settings in another variable to prevent the pollution
+ *       of the Drupal.settings namespace.
+ * @param $type
+ *   (optional) The type of JavaScript that should be added to the page. Allowed
+ *   values are 'core', 'module', 'theme', 'inline' and 'setting'. You
+ *   can, however, specify any value. It is treated as a reference to a JavaScript
+ *   file. Defaults to 'module'.
+ * @param $scope
+ *   (optional) The location in which you want to place the script. Possible
+ *   values are 'header' and 'footer' by default. If your theme implements
+ *   different locations, however, you can also use these.
+ * @param $defer
+ *   (optional) If set to TRUE, the defer attribute is set on the <script> tag.
+ *   Defaults to FALSE. This parameter is not used with $type == 'setting'.
+ * @param $cache
+ *   (optional) If set to FALSE, the JavaScript file is loaded anew on every page
+ *   call, that means, it is not cached. Defaults to TRUE. Used only when $type
+ *   references a JavaScript file.
+ * @return
+ *   If the first parameter is NULL, the JavaScript array that has been built so
+ *   far for $scope is returned.
  */
-function drupal_add_js($file, $nocache = FALSE) {
-  static $sent = array();
+function drupal_add_js($data = NULL, $type = 'module', $scope = 'header', $defer = FALSE, $cache = TRUE) {
+  static $javascript = array();
+
+  if (!isset($javascript[$scope])) {
+    $javascript[$scope] = array('core' => array(), 'module' => array(), 'theme' => array(), 'setting' => array(), 'inline' => array());
 
-  $postfix = $nocache ? '?'. time() : '';
-  if (!isset($sent['misc/drupal.js'])) {
-    drupal_set_html_head('<script type="text/javascript" src="'. base_path() .'misc/drupal.js'. $postfix .'"></script>');
-    $sent['misc/drupal.js'] = TRUE;
+    if (empty($javascript['header']['core']['misc/drupal.js'])) {
+      drupal_add_js('misc/drupal.js', 'core');
+    }
+  }
+
+  if (!isset($javascript[$scope][$type])) {
+    $javascript[$scope][$type] = array();
   }
-  if (!isset($sent[$file])) {
-    drupal_set_html_head('<script type="text/javascript" src="'. check_url(base_path() . $file) . $postfix .'"></script>');
-    $sent[$file] = TRUE;
+
+  if (!is_null($data)) {
+    switch ($type) {
+      case 'setting':
+        $javascript[$scope][$type][] = $data;
+        break;
+      case 'inline':
+        $javascript[$scope][$type][] = array('code' => $data, 'defer' => $defer);
+        break;
+      default:
+        $javascript[$scope][$type][$data] = array('cache' => $cache, 'defer' => $defer);
+    }
   }
+
+  return $javascript[$scope];
 }
 
 /**
- * Generates a Javascript call, while importing the arguments as is.
- * PHP arrays are turned into JS objects to preserve keys. This means the array
- * keys must conform to JS's member naming rules.
+ * Returns a themed presentation of all JavaScript code for the current page.
+ * References to JavaScript files are placed in a certain order: first, all
+ * 'core' files, then all 'module' and finally all 'theme' JavaScript files
+ * are added to the page. Then, all settings are output, followed by 'inline'
+ * JavaScript code.
  *
- * @param $function
- *   The name of the function to call.
- * @param $arguments
- *   An array of arguments.
- */
-function drupal_call_js($function) {
-  $arguments = func_get_args();
-  array_shift($arguments);
-  $args = array();
-  foreach ($arguments as $arg) {
-    $args[] = drupal_to_js($arg);
-  }
-  $output = '<script type="text/javascript">'. $function .'('. implode(', ', $args) .');</script>';
+ * @parameter $scope
+ *   (optional) The scope for which the JavaScript rules should be returned.
+ *   Defaults to 'header'.
+ * @parameter $javascript
+ *   (optional) An array with all JavaScript code. Defaults to the default
+ *   JavaScript array for the given scope.
+ * @return
+ *   All JavaScript code segments and includes for the scope as HTML tags.
+ */
+function drupal_get_js($scope = 'header', $javascript = NULL) {
+  $output = '';
+  if (is_null($javascript)) {
+    $javascript = drupal_add_js(NULL, NULL, $scope);
+  }
+
+  foreach ($javascript as $type => $data) {
+    if (!$data) continue;
+
+    switch ($type) {
+      case 'setting':
+        $output .= '<script type="text/javascript">Drupal.extend({ settings: '. drupal_to_js(call_user_func_array('array_merge_recursive', $data)) ." });</script>\n";
+        break;
+      case 'inline':
+        foreach ($data as $info) {
+          $output .= '<script type="text/javascript"'. ($info['defer'] ? ' defer="defer"' : '') .'>'. $info['code'] ."</script>\n";
+        }
+        break;
+      default:
+        foreach ($data as $path => $flags) {
+          $output .= '<script type="text/javascript"'. ($info['defer'] ? ' defer="defer"' : '') .' src="'. check_url(base_path() . $path) . ($flags['cache'] ? '' : '?'. time()) ."\"></script>\n";
+        }
+    }
+  }
+
   return $output;
 }
 
diff --git a/includes/theme.inc b/includes/theme.inc
index 54ee5af0377b4fc410a562b3184cab75524e4420..2635c4e14486838cbbbde217de05dae1c4bac5b7 100644
--- a/includes/theme.inc
+++ b/includes/theme.inc
@@ -365,6 +365,7 @@ function theme_page($content) {
   $output .= ' <title>'. (drupal_get_title() ? strip_tags(drupal_get_title()) : variable_get('site_name', 'drupal')) .'</title>';
   $output .= drupal_get_html_head();
   $output .= drupal_get_css();
+  $output .= drupal_get_js();
 
   $output .= ' </head>';
   $output .= ' <body style="background-color: #fff; color: #000;">';
@@ -406,6 +407,7 @@ function theme_maintenance_page($content, $messages = TRUE, $partial = FALSE) {
   $output .= ' <title>'. strip_tags(drupal_get_title()) .'</title>';
   $output .= drupal_get_html_head();
   $output .= drupal_get_css();
+  $output .= drupal_get_js();
   $output .= '</head>';
   $output .= '<body>';
   $output .= '<h1>' . drupal_get_title() . '</h1>';
@@ -435,6 +437,7 @@ function theme_install_page($content) {
   $output .= ' <title>'. strip_tags(drupal_get_title()) .'</title>';
   $output .= drupal_get_html_head();
   $output .= drupal_get_css();
+  $output .= drupal_get_js();
   $output .= '</head>';
   $output .= '<body>';
   $output .= '<h1>' . drupal_get_title() . '</h1>';
@@ -920,7 +923,7 @@ function theme_feed_icon($url) {
  */
 function theme_closure($main = 0) {
   $footer = module_invoke_all('footer', $main);
-  return implode("\n", $footer);
+  return implode("\n", $footer) . drupal_get_js('footer');
 }
 
 /**
diff --git a/misc/drupal.js b/misc/drupal.js
index 4fd53646348761a7e218e04e64ba4a0dc24d48cf..6fb336b56ec854eb2ece59af0b1e7fe3637cd0d3 100644
--- a/misc/drupal.js
+++ b/misc/drupal.js
@@ -21,6 +21,19 @@ if (isJsEnabled()) {
   document.documentElement.className = 'js';
 }
 
+Drupal = { };
+
+Drupal.extend = function(obj) {
+  for (var i in obj) {
+    if (this[i]) {
+      Drupal.extend.apply(this[i], [obj[i]]);
+    }
+    else {
+      this[i] = obj[i];
+    }
+  }
+}
+
 /**
  * Make IE's XMLHTTP object accessible through XMLHttpRequest()
  */
diff --git a/themes/bluemarine/page.tpl.php b/themes/bluemarine/page.tpl.php
index e65278d6af71f520e6f9bd2d4d04b0f6758967b0..385df6fa9dbee70deecb34c21864cbaf27b03a04 100644
--- a/themes/bluemarine/page.tpl.php
+++ b/themes/bluemarine/page.tpl.php
@@ -5,6 +5,7 @@
   <title><?php print $head_title ?></title>
   <?php print $head ?>
   <?php print $styles ?>
+  <?php print $scripts ?>
   <script type="text/javascript"><?php /* Needed to avoid Flash of Unstyle Content in IE */ ?> </script>
 </head>
 
diff --git a/themes/chameleon/chameleon.theme b/themes/chameleon/chameleon.theme
index fd1580d5243048abe1e196a3ca06b2250b3e116f..056ffdf4c55e34fb917432c17cca0d2744302a1d 100644
--- a/themes/chameleon/chameleon.theme
+++ b/themes/chameleon/chameleon.theme
@@ -38,6 +38,7 @@ function chameleon_page($content) {
   $output .= " <title>". ($title ? strip_tags($title) ." | ". variable_get("site_name", "drupal") : variable_get("site_name", "drupal") ." | ". variable_get("site_slogan", "")) ."</title>\n";
   $output .= drupal_get_html_head();
   $output .= drupal_get_css();
+  $output .= drupal_get_js();
   $output .= "</head>";
   $output .= "<body>\n";
   $output .= " <div id=\"header\">";
diff --git a/themes/engines/phptemplate/phptemplate.engine b/themes/engines/phptemplate/phptemplate.engine
index 79f0f989a942574765d1c9178cadce1f351d09c3..7533888fccb7c2c38741a7ec55638c3ebdbc9b49 100644
--- a/themes/engines/phptemplate/phptemplate.engine
+++ b/themes/engines/phptemplate/phptemplate.engine
@@ -214,6 +214,7 @@ function phptemplate_page($content) {
     'site_slogan'         => (theme_get_setting('toggle_slogan') ? variable_get('site_slogan', '') : ''),
     'css'                 => drupal_add_css(),
     'styles'              => drupal_get_css(),
+    'scripts'             => drupal_get_js(),
     'tabs'                => theme('menu_local_tasks'),
     'title'               => drupal_get_title()
   );
diff --git a/themes/pushbutton/page.tpl.php b/themes/pushbutton/page.tpl.php
index 33fb1d3175cfc64ddaa3c1be4cbc7583594ad3da..3b8219556d144195df1614d7cebb5d6129ea9d5e 100644
--- a/themes/pushbutton/page.tpl.php
+++ b/themes/pushbutton/page.tpl.php
@@ -5,6 +5,7 @@
   <meta http-equiv="Content-Style-Type" content="text/css" />
   <?php print $head ?>
   <?php print $styles ?>
+  <?php print $scripts ?>
 </head>
 
 <body bgcolor="#ffffff">