Index: includes/ajax.inc
===================================================================
RCS file: includes/ajax.inc
diff -N includes/ajax.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ includes/ajax.inc	9 Aug 2009 21:23:54 -0000
@@ -0,0 +1,575 @@
+<?php
+// $Id: $
+
+/**
+ * @file
+ * Functions for use with Drupal's AJAX framework.
+ */
+
+/**
+ * @defgroup ajax AJAX Framework
+ *
+ * Drupal's AJAX framework creates a PHP macro language that can be used to
+ * instruct javascript to perform actions on the client browser. When using
+ * forms, this framework can be used automatically with the #ajax property.
+ *
+ * @todo Flesh the #ajax portion of the documentation out here.
+ *
+ * @todo Discuss how links may be ajax enabled.
+ *
+ * @todo Discuss how submit buttons can be ajax enabled.
+ *
+ * When responding to other requests, the ajax_render() function will convert
+ * a command array into a JSON object to give to the javascript. Drupal's
+ * ajax responder will iterate through these commands and do whatever it was
+ * instructed to do.
+ *
+ * Each command is an object. $object->command is the type of command and
+ * will be used to find the function (it will correllate directly to
+ * a function in the Drupal.AJAX.Command space). The object can
+ * contain any other data that the command needs to process.
+ *
+ * Built in commands include:
+ * - replace
+ *   - selector: The CSS selector. This can be any selector jquery uses in $().
+ *   - data: The data to use with the jquery replace() function.
+ *   - settings: An optional array of settings that will be used for just this
+ *     command.
+ *
+ * - prepend
+ *   - selector: The CSS selector. This can be any selector jquery uses in $().
+ *   - data: The data to use with the jquery prepend() function.
+ *   - settings: An optional array of settings that will be used for just this
+ *     command.
+ *
+ * - append
+ *   - selector: The CSS selector. This can be any selector jquery uses in $().
+ *   - data: The data to use with the jquery append() function.
+ *   - settings: An optional array of settings that will be used for just this
+ *     command.
+ *
+ * - after
+ *   - selector: The CSS selector. This can be any selector jquery uses in $().
+ *   - data: The data to use with the jquery after() function.
+ *   - settings: An optional array of settings that will be used for just this
+ *     command.
+ *
+ * - before
+ *   - selector: The CSS selector. This can be any selector jquery uses in $().
+ *   - data: The data to use with the jquery before() function.
+ *   - settings: An optional array of settings that will be used for just this
+ *     command.
+ *
+ * - remove
+ *   - selector: The CSS selector. This can be any selector jquery uses in $().
+ *
+ * - changed
+ *   - selector: The CSS selector. This selector will have 'changed' added as a clas.
+ *   - star: If set, will add a star to this selector. It must be within the 'selector' above.
+ *
+ * - alert
+ *   - title: The title of the alert.
+ *   - data: The data in the alert.
+ *
+ * - css
+ *   - selector: The CSS selector to add CSS to.
+ *   - argument: An array of 'key': 'value' CSS selectors to set.
+ *
+ * - settings
+ *   - argument: An array of settings to use for later commands.
+ *
+ * - data
+ *   - selector: The CSS selector. This can be any selector jquery uses in $().
+ *   - name: The name or key of the data attached to this selector.
+ *   - value: The value of the data. Not just limited to strings can be any format.
+ *
+ * Commands are usually created with a couple of helper functions, so they
+ * look like this:
+ *
+ * @code
+ *   $commands = array();
+ *   $commands[] = ajax_command_replace('#object-1', 'some html here');
+ *   $commands[] = ajax_command_changed('#object-1');
+ *   ajax_render($commands); // this function exits.
+ * @endcode
+ */
+
+/**
+ * Create a command array for the error case.
+ *
+ * @param $error
+ *   The error to render to the user.
+ *
+ * @return
+ *   An array suitable for use with the ajax_render() function.
+ */
+function ajax_command_error($error = '') {
+  return array(
+    'command' => 'alert',
+    'title' => t('Error'),
+    'text' => $error ? $error : t('Server reports invalid input error.'),
+  );
+}
+
+/**
+ * Create a replace command for the AJAX responder.
+ *
+ * The replace command will replace a portion of the current document
+ * with the specified HTML.
+ *
+ * @param $selector
+ *   The CSS selector. This can be any selector jquery uses in $().
+ * @param $html
+ *   The data to use with the jquery replace() function.
+ * @param $settings
+ *   An optional array of settings that will be used for this command only.
+ *
+ * @return
+ *   An array suitable for use with the ajax_render() function.
+ */
+function ajax_command_replace($selector, $html, $settings = NULL) {
+  return array(
+    'command' => 'insert',
+    'method' => 'replace',
+    'selector' => $selector,
+    'data' => $html,
+    'settings' => $settings,
+  );
+}
+
+/**
+ * Set the HTML of a given selector to the given data.
+ *
+ * @param $selector
+ *   The CSS selector. This can be any selector jquery uses in $().
+ * @param $html
+ *   The data to use with the jquery html() function.
+ * @param $settings
+ *   An optional array of settings that will be used for this command only.
+ *
+ * @return
+ *   An array suitable for use with the ajax_render() function.
+ */
+function ajax_command_html($selector, $html) {
+  return array(
+    'command' => 'insert',
+    'method' => 'html',
+    'selector' => $selector,
+    'data' => $html,
+    'settings' => $settings,
+  );
+}
+
+/**
+ * Create a prepend command for the AJAX responder.
+ *
+ * This will prepend the HTML to the specified selector.
+ *
+ * @param $selector
+ *   The CSS selector. This can be any selector jquery uses in $().
+ * @param $html
+ *   The data to use with the jquery prepend() function.
+ * @param $settings
+ *   An optional array of settings that will be used for this command only.
+ *
+ * @return
+ *   An array suitable for use with the ajax_render() function.
+ */
+function ajax_command_prepend($selector, $html, $settings = NULL) {
+  return array(
+    'command' => 'insert',
+    'method' => 'prepend',
+    'selector' => $selector,
+    'data' => $html,
+    'settings' => $settings,
+  );
+}
+
+/**
+ * Create an append command for the AJAX responder.
+ *
+ * This will append the HTML to the specified selector.
+ *
+ * @param $selector
+ *   The CSS selector. This can be any selector jquery uses in $().
+ * @param $html
+ *   The data to use with the jquery append() function.
+ * @param $settings
+ *   An optional array of settings that will be used for this command only.
+ *
+ * @return
+ *   An array suitable for use with the ajax_render() function.
+ */
+function ajax_command_append($selector, $html, $settings = NULL) {
+  return array(
+    'command' => 'insert',
+    'method' => 'append',
+    'selector' => $selector,
+    'data' => $html,
+    'settings' => $settings,
+  );
+}
+
+/**
+ * Create an after command for the AJAX responder.
+ *
+ * This will add the HTML after the specified selector.
+ *
+ * @param $selector
+ *   The CSS selector. This can be any selector jquery uses in $().
+ * @param $html
+ *   The data to use with the jquery after() function.
+ * @param $settings
+ *   An optional array of settings that will be used for this command only.
+ *
+ * @return
+ *   An array suitable for use with the ajax_render() function.
+ */
+function ajax_command_after($selector, $html, $settings = NULL) {
+  return array(
+    'command' => 'insert',
+    'method' => 'after',
+    'selector' => $selector,
+    'data' => $html,
+    'settings' => $settings,
+  );
+}
+
+/**
+ * Create a before command for the AJAX responder.
+ *
+ * This will add the HTML before the specified selector.
+ *
+ * @param $selector
+ *   The CSS selector. This can be any selector jquery uses in $().
+ * @param $html
+ *   The data to use with the jquery before() function.
+ * @param $settings
+ *   An optional array of settings that will be used for this command only.
+ *
+ * @return
+ *   An array suitable for use with the ajax_render() function.
+ */
+function ajax_command_before($selector, $html, $settings = NULL) {
+  return array(
+    'command' => 'insert',
+    'method' => 'before',
+    'selector' => $selector,
+    'data' => $html,
+    'settings' => $settings,
+  );
+}
+
+/**
+ * Create a remove command for the AJAX responder.
+ *
+ * This will remove the specified selector and everything within it.
+ *
+ * @param $selector
+ *   The CSS selector. This can be any selector jquery uses in $().
+ *
+ * @return
+ *   An array suitable for use with the ajax_render() function.
+ */
+function ajax_command_remove($selector) {
+  return array(
+    'command' => 'remove',
+    'selector' => $selector,
+  );
+}
+
+/**
+ * Create a changed command for the AJAX responder.
+ *
+ * This will mark an item as 'changed'.
+ *
+ * @param $selector
+ *   The CSS selector. This can be any selector jquery uses in $().
+ * @param $star
+ *   An optional CSS selector which must be inside $selector. If specified,
+ *   a star will be appended.
+ *
+ * @return
+ *   An array suitable for use with the ajax_render() function.
+ */
+function ajax_command_changed($selector, $star = '') {
+  return array(
+    'command' => 'changed',
+    'selector' => $selector,
+    'star' => $star,
+  );
+}
+
+/**
+ * Create a changed command for the AJAX responder.
+ *
+ * This will mark an item as 'changed'.
+ *
+ * @param $selector
+ *   The CSS selector. This can be any selector jquery uses in $().
+ * @param $argument
+ *   An array of key: value pairs to set in the CSS for the selector.
+ *
+ * @return
+ *   An array suitable for use with the ajax_render() function.
+ */
+function ajax_command_css($selector, $argument) {
+  return array(
+    'command' => 'css',
+    'selector' => $selector,
+    'argument' => $argument,
+  );
+}
+
+/**
+ * Create a settings command for the AJAX responder.
+ *
+ * This will extend Drupal.settings with the given array.
+ *
+ * @param $argument
+ *   An array of key: value pairs to add to the settings. This will be
+ *   utilized for all commands after this if they do not include their
+ *   own settings array.
+ *
+ * @return
+ *   An array suitable for use with the ajax_render() function.
+ */
+function ajax_command_settings($argument) {
+  return array(
+    'command' => 'settings',
+    'argument' => $argument,
+  );
+}
+
+/**
+ * Create a data command for the AJAX responder.
+ *
+ * This will attach the name=value pair of data to the selector via
+ * jquery's data cache.
+ *
+ * @param $selector
+ *   The CSS selector. This can be any selector jquery uses in $().
+ * @param $name
+ *   The name or key: of the data attached to this selector.
+ * @param $value
+ *  The value of the data. Not just limited to strings can be any format.
+ *
+ * @return
+ *   An array suitable for use with the ajax_render() function.
+ */
+function ajax_command_data($selector, $name, $value) {
+  return array(
+    'command' => 'data',
+    'selector' => $selector,
+    'name' => $name,
+    'value' => $value,
+  );
+}
+
+/**
+ * Force a table to be restriped.
+ *
+ * This is usually used after a table has been modifed by a replace or append
+ * command.
+ *
+ * @param $selector
+ *   The CSS selector. This can be any selector jquery uses in $().
+ *
+ * @return
+ *   An array suitable for use with the ajax_render() function.
+ */
+function ajax_command_restripe($selector) {
+  return array(
+    'command' => 'restripe',
+    'selector' => $selector,
+  );
+}
+
+/**
+ * Render a commands array into JSON and immediately hand this back
+ * to the AJAX requester. This function will render and immediately
+ * exit.
+ *
+ * @param $commands
+ *   A list of macro commands generated by the use of ajax_command_* functions.
+ * @param $header
+ *   If set to FALSE the text/javascript header used by drupal_json will not
+ *   be used, which is sometimes necessary when using iframe.
+ *   If set to 'multipart' the output will be wrapped in a textarea, which
+ *   can also be used when uploading files.
+ */
+function ajax_render($commands = array(), $header = TRUE) {
+  if ($header === 'multipart') {
+    // We don't use drupal_json here because the header is not true. We're not really
+    // returning JSON, strictly-speaking, but rather JSON content wrapped in a <textarea>
+    // as per the "file uploads" example here: http://malsup.com/jquery/form/#code-samples
+    print '<textarea>' . drupal_to_js($commands) . '</textarea>';
+  }
+  else if ($header) {
+    drupal_json($commands);
+  }
+  else {
+    print drupal_to_js($commands);
+  }
+  exit;
+}
+
+/**
+ * Send an error response back via AJAX and immediately exit.
+ *
+ * This funciton can be used to quickly create a command array with an
+ * error string and send it, short-circuiting the error handling process.
+ *
+ * This error will be displayed as an alert.
+ */
+function ajax_render_error($error = '') {
+  $commands = array();
+  $commands[] = ajax_command_error($error);
+  ajax_render($commands);
+}
+
+/**
+ * Menu callback for AJAX callbacks through the #ajax['callback'] FAPI property.
+ */
+function ajax_form_callback() {
+  $form_state = form_state_defaults();
+
+  $form_build_id = $_POST['form_build_id'];
+
+  // Get the form from the cache.
+  $form = form_get_cache($form_build_id, $form_state);
+  if (!$form) {
+    // If $form cannot be loaded from the cache, the form_build_id in $_POST must
+    // be invalid, which means that someone performed a POST request onto
+    // system/ajax without actually viewing the concerned form in the browser.
+    // This is likely a hacking attempt as it never happens under normal
+    // circumstances, so we just do nothing.
+    exit;
+  }
+
+  // We will run some of the submit handlers so we need to disable redirecting.
+  $form['#redirect'] = FALSE;
+
+  // We need to process the form, prepare for that by setting a few internals
+  // variables.
+  $form_state['input'] = $_POST;
+  $form_state['args'] = $form['#args'];
+  $form_id = $form['#form_id'];
+
+  // Build, validate and if possible, submit the form.
+  drupal_process_form($form_id, $form, $form_state);
+
+  // This call recreates the form relying solely on the form_state that the
+  // drupal_process_form set up.
+  $form = drupal_rebuild_form($form_id, $form_state, $form_build_id);
+
+  // Get the callback function from the clicked button.
+  $ajax = $form_state['clicked_button']['#ajax'];
+  $callback = $ajax['callback'];
+  if (drupal_function_exists($callback)) {
+    $html = $callback($form, $form_state);
+
+    // If the returned value is a string, assume it is HTML and create
+    // a command object to return automatically.
+    if (is_string($html)) {
+      $commands = array();
+      $commands[] = ajax_command_replace($ajax['target'], $html);
+      $commands[] = ajax_command_settings($settings);
+    }
+    else {
+      $commands = $html;
+    }
+
+    ajax_render($commands);
+  }
+}
+
+/**
+ * Add AJAX information about a form element to the page to communicate with
+ * javascript. If #ajax[path] is set on an element, this additional javascript is
+ * added to the page header to attach the AJAX behaviors. See ajax.js for more
+ * information.
+ *
+ * @param $element
+ *   An associative array containing the properties of the element.
+ *   Properties used: ajax[event], ajax[path], ajax[wrapper], ajax[parameters],
+ *   ajax[effect].
+ * @return
+ *   None. Additional code is added to the header of the page using
+ *   drupal_add_js.
+ */
+function ajax_process_form($element) {
+  $js_added = &drupal_static(__FUNCTION__, array());
+  // Add a reasonable default event handler if none specified.
+  if (isset($element['#ajax']) && !isset($element['#ajax']['event'])) {
+    switch ($element['#type']) {
+      case 'submit':
+      case 'button':
+      case 'image_button':
+        // Use the mousedown instead of the click event because form
+        // submission via pressing the enter key triggers a click event on
+        // submit inputs, inappropriately triggering AJAX behaviors.
+        $element['#ajax']['event'] = 'mousedown';
+        // Attach an additional event handler so that AJAX behaviors
+        // can be triggered still via keyboard input.
+        $element['#ajax']['keypress'] = TRUE;
+        break;
+      case 'password':
+      case 'textfield':
+      case 'textarea':
+        $element['#ajax']['event'] = 'blur';
+        break;
+      case 'radio':
+      case 'checkbox':
+      case 'select':
+        $element['#ajax']['event'] = 'change';
+        break;
+      default:
+        return $element;
+    }
+  }
+
+  // Adding the same javascript settings twice will cause a recursion error,
+  // we avoid the problem by checking if the javascript has already been added.
+  if ((isset($element['#ajax']['callback']) || isset($element['#ajax']['path'])) && isset($element['#ajax']['event']) && !isset($js_added[$element['#id']])) {
+    drupal_add_library('system', 'form');
+    drupal_add_js('misc/ajax.js');
+
+    $ajax_binding = array(
+      'url'      => isset($element['#ajax']['callback']) ? url('system/ajax') : url($element['#ajax']['path']),
+      'event'    => $element['#ajax']['event'],
+      'keypress' => empty($element['#ajax']['keypress']) ? NULL : $element['#ajax']['keypress'],
+      'wrapper'  => empty($element['#ajax']['wrapper']) ? NULL : $element['#ajax']['wrapper'],
+      'selector' => empty($element['#ajax']['selector']) ? '#' . $element['#id'] : $element['#ajax']['selector'],
+      'effect'   => empty($element['#ajax']['effect']) ? 'none' : $element['#ajax']['effect'],
+      'method'   => empty($element['#ajax']['method']) ? 'replace' : $element['#ajax']['method'],
+      'progress' => empty($element['#ajax']['progress']) ? array('type' => 'throbber') : $element['#ajax']['progress'],
+      'button'   => isset($element['#executes_submit_callback']) ? array($element['#name'] => $element['#value']) : FALSE,
+    );
+
+    // Convert a simple #ajax[progress] type string into an array.
+    if (is_string($ajax_binding['progress'])) {
+      $ajax_binding['progress'] = array('type' => $ajax_binding['progress']);
+    }
+    // Change progress path to a full url.
+    if (isset($ajax_binding['progress']['path'])) {
+      $ajax_binding['progress']['url'] = url($ajax_binding['progress']['path']);
+    }
+
+    // Add progress.js if we're doing a bar display.
+    if ($ajax_binding['progress']['type'] == 'bar') {
+      drupal_add_js('misc/progress.js', array('cache' => FALSE));
+    }
+
+    drupal_add_js(array('ajax' => array($element['#id'] => $ajax_binding)), 'setting');
+
+    $js_added[$element['#id']] = TRUE;
+    $element['#cache'] = TRUE;
+  }
+  return $element;
+}
+
+/**
+ * @} End of "AJAX Framework".
+ */
+
Index: includes/common.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/common.inc,v
retrieving revision 1.956
diff -u -p -r1.956 common.inc
--- includes/common.inc	8 Aug 2009 20:52:32 -0000	1.956
+++ includes/common.inc	9 Aug 2009 21:23:57 -0000
@@ -2333,14 +2333,14 @@ function drupal_map_assoc($array, $funct
  * In other words, if the timeout is the default 30 seconds, and 25 seconds
  * into script execution a call such as set_time_limit(20) is made, the
  * script will run for a total of 45 seconds before timing out.
- * 
+ *
  * It also means that it is possible to decrease the total time limit if
  * the sum of the new time limit and the current time spent running the
  * script is inferior to the original time limit. It is inherent to the way
  * set_time_limit() works, it should rather be called with an appropriate
  * value every time you need to allocate a certain amount of time
  * to execute a task than only once at the beginning of the script.
- * 
+ *
  * Before calling set_time_limit(), we check if this function is available
  * because it could be disabled by the server administrator. We also hide all
  * the errors that could occur when calling set_time_limit(), because it is
@@ -3527,6 +3527,7 @@ function _drupal_bootstrap_full() {
   require_once DRUPAL_ROOT . '/includes/form.inc';
   require_once DRUPAL_ROOT . '/includes/mail.inc';
   require_once DRUPAL_ROOT . '/includes/actions.inc';
+  require_once DRUPAL_ROOT . '/includes/ajax.inc';
   // Set the Drupal custom error handler.
   set_error_handler('_drupal_error_handler');
   set_exception_handler('_drupal_exception_handler');
Index: includes/form.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/form.inc,v
retrieving revision 1.355
diff -u -p -r1.355 form.inc
--- includes/form.inc	4 Aug 2009 06:38:56 -0000	1.355
+++ includes/form.inc	9 Aug 2009 21:23:59 -0000
@@ -1801,48 +1801,6 @@ function weight_value(&$form) {
 }
 
 /**
- * Menu callback for AHAH callbacks through the #ahah['callback'] FAPI property.
- */
-function form_ahah_callback() {
-  $form_state = form_state_defaults();
-
-  $form_build_id = $_POST['form_build_id'];
-
-  // Get the form from the cache.
-  $form = form_get_cache($form_build_id, $form_state);
-  if (!$form) {
-    // If $form cannot be loaded from the cache, the form_build_id in $_POST must
-    // be invalid, which means that someone performed a POST request onto
-    // system/ahah without actually viewing the concerned form in the browser.
-    // This is likely a hacking attempt as it never happens under normal
-    // circumstances, so we just do nothing.
-    exit;
-  }
-
-  // We will run some of the submit handlers so we need to disable redirecting.
-  $form['#redirect'] = FALSE;
-
-  // We need to process the form, prepare for that by setting a few internals
-  // variables.
-  $form_state['input'] = $_POST;
-  $form_state['args'] = $form['#args'];
-  $form_id = $form['#form_id'];
-
-  // Build, validate and if possible, submit the form.
-  drupal_process_form($form_id, $form, $form_state);
-
-  // This call recreates the form relying solely on the form_state that the
-  // drupal_process_form set up.
-  $form = drupal_rebuild_form($form_id, $form_state, $form_build_id);
-
-  // Get the callback function from the clicked button.
-  $callback = $form_state['clicked_button']['#ahah']['callback'];
-  if (drupal_function_exists($callback)) {
-    $callback($form, $form_state);
-  }
-}
-
-/**
  * Roll out a single radios element to a list of radios,
  * using the options array as index.
  */
@@ -1861,7 +1819,7 @@ function form_process_radios($element) {
           '#attributes' => $element['#attributes'],
           '#parents' => $element['#parents'],
           '#id' => form_clean_id('edit-' . implode('-', $parents_for_id)),
-          '#ahah' => isset($element['#ahah']) ? $element['#ahah'] : NULL,
+          '#ajax' => isset($element['#ajax']) ? $element['#ajax'] : NULL,
         );
       }
     }
@@ -1971,91 +1929,6 @@ function theme_text_format_wrapper($elem
 }
 
 /**
- * Add AHAH information about a form element to the page to communicate with
- * javascript. If #ahah[path] is set on an element, this additional javascript is
- * added to the page header to attach the AHAH behaviors. See ahah.js for more
- * information.
- *
- * @param $element
- *   An associative array containing the properties of the element.
- *   Properties used: ahah_event, ahah_path, ahah_wrapper, ahah_parameters,
- *   ahah_effect.
- * @return
- *   None. Additional code is added to the header of the page using
- *   drupal_add_js.
- */
-function form_process_ahah($element) {
-  $js_added = &drupal_static(__FUNCTION__, array());
-  // Add a reasonable default event handler if none specified.
-  if (isset($element['#ahah']) && !isset($element['#ahah']['event'])) {
-    switch ($element['#type']) {
-      case 'submit':
-      case 'button':
-      case 'image_button':
-        // Use the mousedown instead of the click event because form
-        // submission via pressing the enter key triggers a click event on
-        // submit inputs, inappropriately triggering AHAH behaviors.
-        $element['#ahah']['event'] = 'mousedown';
-        // Attach an additional event handler so that AHAH behaviors
-        // can be triggered still via keyboard input.
-        $element['#ahah']['keypress'] = TRUE;
-        break;
-      case 'password':
-      case 'textfield':
-      case 'textarea':
-        $element['#ahah']['event'] = 'blur';
-        break;
-      case 'radio':
-      case 'checkbox':
-      case 'select':
-        $element['#ahah']['event'] = 'change';
-        break;
-      default:
-        return $element;
-    }
-  }
-
-  // Adding the same javascript settings twice will cause a recursion error,
-  // we avoid the problem by checking if the javascript has already been added.
-  if ((isset($element['#ahah']['callback']) || isset($element['#ahah']['path'])) && isset($element['#ahah']['event']) && !isset($js_added[$element['#id']])) {
-    drupal_add_library('system', 'form');
-    drupal_add_js('misc/ahah.js');
-
-    $ahah_binding = array(
-      'url'      => isset($element['#ahah']['callback']) ? url('system/ahah') : url($element['#ahah']['path']),
-      'event'    => $element['#ahah']['event'],
-      'keypress' => empty($element['#ahah']['keypress']) ? NULL : $element['#ahah']['keypress'],
-      'wrapper'  => empty($element['#ahah']['wrapper']) ? NULL : $element['#ahah']['wrapper'],
-      'selector' => empty($element['#ahah']['selector']) ? '#' . $element['#id'] : $element['#ahah']['selector'],
-      'effect'   => empty($element['#ahah']['effect']) ? 'none' : $element['#ahah']['effect'],
-      'method'   => empty($element['#ahah']['method']) ? 'replace' : $element['#ahah']['method'],
-      'progress' => empty($element['#ahah']['progress']) ? array('type' => 'throbber') : $element['#ahah']['progress'],
-      'button'   => isset($element['#executes_submit_callback']) ? array($element['#name'] => $element['#value']) : FALSE,
-    );
-
-    // Convert a simple #ahah[progress] type string into an array.
-    if (is_string($ahah_binding['progress'])) {
-      $ahah_binding['progress'] = array('type' => $ahah_binding['progress']);
-    }
-    // Change progress path to a full url.
-    if (isset($ahah_binding['progress']['path'])) {
-      $ahah_binding['progress']['url'] = url($ahah_binding['progress']['path']);
-    }
-
-    // Add progress.js if we're doing a bar display.
-    if ($ahah_binding['progress']['type'] == 'bar') {
-      drupal_add_js('misc/progress.js', array('cache' => FALSE));
-    }
-
-    drupal_add_js(array('ahah' => array($element['#id'] => $ahah_binding)), 'setting');
-
-    $js_added[$element['#id']] = TRUE;
-    $element['#cache'] = TRUE;
-  }
-  return $element;
-}
-
-/**
  * Format a checkbox.
  *
  * @param $element
@@ -2132,7 +2005,7 @@ function form_process_checkboxes($elemen
           '#return_value' => $key,
           '#default_value' => isset($value[$key]),
           '#attributes' => $element['#attributes'],
-          '#ahah' => isset($element['#ahah']) ? $element['#ahah'] : NULL,
+          '#ajax' => isset($element['#ajax']) ? $element['#ajax'] : NULL,
         );
       }
     }
@@ -2245,7 +2118,7 @@ function form_process_tableselect($eleme
             '#return_value' => $key,
             '#default_value' => isset($value[$key]),
             '#attributes' => $element['#attributes'],
-            '#ahah' => isset($element['#ahah']) ? $element['#ahah'] : NULL,
+            '#ajax' => isset($element['#ajax']) ? $element['#ajax'] : NULL,
           );
         }
         else {
@@ -2260,7 +2133,7 @@ function form_process_tableselect($eleme
             '#attributes' => $element['#attributes'],
             '#parents' => $element['#parents'],
             '#id' => form_clean_id('edit-' . implode('-', $parents_for_id)),
-            '#ahah' => isset($element['#ahah']) ? $element['#ahah'] : NULL,
+            '#ajax' => isset($element['#ajax']) ? $element['#ajax'] : NULL,
           );
         }
       }
Index: misc/ahah.js
===================================================================
RCS file: misc/ahah.js
diff -N misc/ahah.js
--- misc/ahah.js	16 Jul 2009 02:46:13 -0000	1.17
+++ /dev/null	1 Jan 1970 00:00:00 -0000
@@ -1,259 +0,0 @@
-// $Id: ahah.js,v 1.17 2009/07/16 02:46:13 dries Exp $
-(function ($) {
-
-/**
- * Provides AJAX-like page updating via AHAH (Asynchronous HTML and HTTP).
- *
- * AHAH is a method of making a request via Javascript while viewing an HTML
- * page. The request returns a small chunk of HTML, which is then directly
- * injected into the page.
- *
- * Drupal uses this file to enhance form elements with #ahah[path] and
- * #ahah[wrapper] properties. If set, this file will automatically be included
- * to provide AHAH capabilities.
- */
-
-Drupal.ahah = Drupal.ahah || {};
-
-/**
- * Attaches the ahah behavior to each ahah form element.
- */
-Drupal.behaviors.ahah = {
-  attach: function (context, settings) {
-    for (var base in settings.ahah) {
-      if (!$('#' + base + '.ahah-processed').size()) {
-        var element_settings = settings.ahah[base];
-
-        $(element_settings.selector).each(function () {
-          element_settings.element = this;
-          Drupal.ahah[base] = new Drupal.ahah(base, element_settings);
-        });
-
-        $('#' + base).addClass('ahah-processed');
-      }
-    }
-  }
-};
-
-/**
- * AHAH object.
- *
- * All AHAH objects on a page are accessible through the global Drupal.ahah object
- * and are keyed by the submit button's ID. You can access them from your module's
- * JavaScript file to override properties or functions.
- * For example, if your AHAH enabled button has the ID 'edit-submit', you can
- * redefine the function that is called to insert the new content like this
- * (inside a Drupal.behaviors attach block):
- * @code
- *    Drupal.behaviors.myCustomAhahStuff = {
- *      attach: function(context, settings) {
- *        Drupal.ahah['edit-submit'].insertNewContent = function(response, status) {
- *          new_content = $(response.data);
- *          $('#my-wrapper').append(new_content);
- *          alert('New content was appended to #my-wrapper');
- *        }
- *      }
- *    };
- * @endcode
- */
-Drupal.ahah = function (base, element_settings) {
-  // Set the properties for this object.
-  this.element = element_settings.element;
-  this.selector = element_settings.selector;
-  this.event = element_settings.event;
-  this.keypress = element_settings.keypress;
-  this.url = element_settings.url;
-  this.wrapper = '#' + element_settings.wrapper;
-  this.effect = element_settings.effect;
-  this.method = element_settings.method;
-  this.progress = element_settings.progress;
-  this.button = element_settings.button || { };
-
-  if (this.effect == 'none') {
-    this.showEffect = 'show';
-    this.hideEffect = 'hide';
-    this.showSpeed = '';
-  }
-  else if (this.effect == 'fade') {
-    this.showEffect = 'fadeIn';
-    this.hideEffect = 'fadeOut';
-    this.showSpeed = 'slow';
-  }
-  else {
-    this.showEffect = this.effect + 'Toggle';
-    this.hideEffect = this.effect + 'Toggle';
-    this.showSpeed = 'slow';
-  }
-
-  // Record the form action and target, needed for iFrame file uploads.
-  var form = $(this.element).parents('form');
-  this.form_action = form.attr('action');
-  this.form_target = form.attr('target');
-  this.form_encattr = form.attr('encattr');
-
-  // Set the options for the ajaxSubmit function.
-  // The 'this' variable will not persist inside of the options object.
-  var ahah = this;
-  var options = {
-    url: ahah.url,
-    data: ahah.button,
-    beforeSubmit: function (form_values, element_settings, options) {
-      return ahah.beforeSubmit(form_values, element_settings, options);
-    },
-    success: function (response, status) {
-      // Sanity check for browser support (object expected).
-      // When using iFrame uploads, responses must be returned as a string.
-      if (typeof response == 'string') {
-        response = Drupal.parseJson(response);
-      }
-      return ahah.success(response, status);
-    },
-    complete: function (response, status) {
-      if (status == 'error' || status == 'parsererror') {
-        return ahah.error(response, ahah.url);
-      }
-    },
-    dataType: 'json',
-    type: 'POST'
-  };
-
-  // Bind the ajaxSubmit function to the element event.
-  $(element_settings.element).bind(element_settings.event, function () {
-    $(element_settings.element).parents('form').ajaxSubmit(options);
-    return false;
-  });
-  // If necessary, enable keyboard submission so that AHAH behaviors
-  // can be triggered through keyboard input as well as e.g. a mousedown
-  // action.
-  if (element_settings.keypress) {
-    $(element_settings.element).keypress(function (event) {
-      // Detect enter key.
-      if (event.keyCode == 13) {
-        $(element_settings.element).trigger(element_settings.event);
-        return false;
-      }
-    });
-  }
-};
-
-/**
- * Handler for the form redirection submission.
- */
-Drupal.ahah.prototype.beforeSubmit = function (form_values, element, options) {
-  // Disable the element that received the change.
-  $(this.element).addClass('progress-disabled').attr('disabled', true);
-
-  // Insert progressbar or throbber.
-  if (this.progress.type == 'bar') {
-    var progressBar = new Drupal.progressBar('ahah-progress-' + this.element.id, eval(this.progress.update_callback), this.progress.method, eval(this.progress.error_callback));
-    if (this.progress.message) {
-      progressBar.setProgress(-1, this.progress.message);
-    }
-    if (this.progress.url) {
-      progressBar.startMonitoring(this.progress.url, this.progress.interval || 1500);
-    }
-    this.progress.element = $(progressBar.element).addClass('ahah-progress ahah-progress-bar');
-    this.progress.object = progressBar;
-    $(this.element).after(this.progress.element);
-  }
-  else if (this.progress.type == 'throbber') {
-    this.progress.element = $('<div class="ahah-progress ahah-progress-throbber"><div class="throbber">&nbsp;</div></div>');
-    if (this.progress.message) {
-      $('.throbber', this.progress.element).after('<div class="message">' + this.progress.message + '</div>');
-    }
-    $(this.element).after(this.progress.element);
-  }
-};
-
-/**
- * Handler for the form redirection completion.
- */
-Drupal.ahah.prototype.success = function (response, status) {
-  var form = $(this.element).parents('form');
-
-  // Restore the previous action and target to the form.
-  form.attr('action', this.form_action);
-  this.form_target ? form.attr('target', this.form_target) : form.removeAttr('target');
-  this.form_encattr ? form.attr('target', this.form_encattr) : form.removeAttr('encattr');
-
-  // Remove the progress element.
-  if (this.progress.element) {
-    $(this.progress.element).remove();
-  }
-  if (this.progress.object) {
-    this.progress.object.stopMonitoring();
-  }
-  $(this.element).removeClass('progress-disabled').attr('disabled', false);
-
-  Drupal.freezeHeight();
-
-  // Call the insertNewContent handler to insert the new content into the page.
-  this.insertNewContent(response, status);
-
-  Drupal.unfreezeHeight();
-};
-
-/**
- * Handler to insert the new content into the page.
- */
-Drupal.ahah.prototype.insertNewContent = function (response, status) {
-  var wrapper = $(this.wrapper);
-
-  // Manually insert HTML into the jQuery object, using $() directly crashes
-  // Safari with long string lengths. http://dev.jquery.com/ticket/1152
-  var new_content = $('<div></div>').html(response.data);
-
-  // Add the new content to the page.
-  if (this.method == 'replace') {
-    wrapper.empty().append(new_content);
-  }
-  else {
-    wrapper[this.method](new_content);
-  }
-
-  // Immediately hide the new content if we're using any effects.
-  if (this.showEffect != 'show') {
-    new_content.hide();
-  }
-
-  // Determine what effect use and what content will receive the effect, then
-  // show the new content.
-  if ($('.ahah-new-content', new_content).size() > 0) {
-    $('.ahah-new-content', new_content).hide();
-    new_content.show();
-    $('.ahah-new-content', new_content)[this.showEffect](this.showSpeed);
-  }
-  else if (this.showEffect != 'show') {
-    new_content[this.showEffect](this.showSpeed);
-  }
-
-  // Attach all javascript behaviors to the new content, if it was successfully
-  // added to the page, this if statement allows #ahah[wrapper] to be optional.
-  if (new_content.parents('html').length > 0) {
-    // Apply any settings from the returned JSON if available.
-    var settings = response.settings || Drupal.settings;
-    Drupal.attachBehaviors(new_content, settings);
-  }
-};
-
-/**
- * Handler for the form redirection error.
- */
-Drupal.ahah.prototype.error = function (response, uri) {
-  alert(Drupal.ahahError(response, uri));
-  // Resore the previous action and target to the form.
-  $(this.element).parent('form').attr({ action: this.form_action, target: this.form_target });
-  // Remove the progress element.
-  if (this.progress.element) {
-    $(this.progress.element).remove();
-  }
-  if (this.progress.object) {
-    this.progress.object.stopMonitoring();
-  }
-  // Undo hide.
-  $(this.wrapper).show();
-  // Re-enable the element.
-  $(this.element).removeClass('progress-disabled').attr('disabled', false);
-};
-
-})(jQuery);
Index: misc/ajax.js
===================================================================
RCS file: misc/ajax.js
diff -N misc/ajax.js
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ misc/ajax.js	9 Aug 2009 21:24:00 -0000
@@ -0,0 +1,391 @@
+// $Id: AJAX.js,v 1.17 2009/07/16 02:46:13 dries Exp $
+(function ($) {
+
+/**
+ * Provides AJAX-like page updating via AJAX (Asynchronous HTML and HTTP).
+ *
+ * AJAX is a method of making a request via Javascript while viewing an HTML
+ * page. The request returns an array of commands encoded in JSON, which is
+ * then executed to make whatever hanges are necessary to the page.
+ *
+ * Drupal uses this file to enhance form elements with #ajax[path] and
+ * #ajax[wrapper] properties. If set, this file will automatically be included
+ * to provide AJAX capabilities.
+ */
+
+Drupal.AJAX = Drupal.AJAX || {};
+
+/**
+ * Attaches the AJAX behavior to each AJAX form element.
+ */
+Drupal.behaviors.AJAX = {
+  attach: function (context, settings) {
+    for (var base in settings.ajax) {
+      if (!$('#' + base + '.ajax-processed').size()) {
+        var element_settings = settings.ajax[base];
+
+        $(element_settings.selector).each(function () {
+          Drupal.AJAX[base] = new Drupal.AJAX(base, this, element_settings);
+        });
+
+        $('#' + base).addClass('ajax-processed');
+      }
+    }
+
+    // Also bind based on classes.
+    $('.use-ajax:not(.ajax-processed)').each(function() {
+      var element_settings = { };
+
+      // For anchor tags, these will go to the target of the anchor rather
+      // than the usual location.
+      if ($(this).attr('href')) {
+        element_settings.url = $(this).attr('href');
+      }
+      var base = $(this).attr('id');
+      Drupal.AJAX[base] = new Drupal.AJAX(base, this, element_settings);
+    }).addClass('ajax-processed');
+
+    // This class means to submit the form to the action using ajax.
+    $('.use-ajax-submit:not(.ajax-processed)').each(function() {
+      var element_settings = { };
+
+      element_settings.url = $(this.form).attr('action');
+      element_settings.set_click = TRUE;
+
+      var base = $(this).attr('id');
+      Drupal.AJAX[base] = new Drupal.AJAX(base, this, element_settings);
+    }).addClass('ajax-processed');
+  }
+};
+
+/**
+ * AJAX object.
+ *
+ * All AJAX objects on a page are accessible through the global Drupal.AJAX object
+ * and are keyed by the submit button's ID. You can access them from your module's
+ * JavaScript file to override properties or functions.
+ * For example, if your AJAX enabled button has the ID 'edit-submit', you can
+ * redefine the function that is called to insert the new content like this
+ * (inside a Drupal.behaviors attach block):
+ * @code
+ *    Drupal.behaviors.myCustomAJAXStuff = {
+ *      attach: function(context, settings) {
+ *        Drupal.AJAX['edit-submit'].insertNewContent = function(response, status) {
+ *          new_content = $(response.data);
+ *          $('#my-wrapper').append(new_content);
+ *          alert('New content was appended to #my-wrapper');
+ *        }
+ *      }
+ *    };
+ * @endcode
+ */
+Drupal.AJAX = function (base, element, element_settings) {
+  var defaults = {
+    url: "system/ajax",
+    event: "mousedown",
+    keypress: true,
+    selector: "#" + base,
+    effect: "none",
+    speed: "slow",
+    method: "replace",
+    progress: {
+      type: "bar",
+      message: "Please wait..."
+    },
+    button: { },
+  };
+
+  jQuery.extend(this, defaults, element_settings);
+
+  this.element = element;
+
+  // Replacing nojs with ajax allows for an easy method to detect when we
+  // need to degrade.
+  this.url = element_settings.url.replace('/nojs/', '/ajax/');
+  this.wrapper = '#' + element_settings.wrapper;
+
+  // If there isn't a form, jQuery.ajax will be used instead, allowing us to
+  // bind ajax to links as well.
+  if (this.element.form) {
+    this.form = $(this.element.form);
+  }
+
+  // Set the options for the ajaxSubmit function.
+  // The 'this' variable will not persist inside of the options object.
+  var AJAX = this;
+  var options = {
+    url: AJAX.url,
+    data: AJAX.button,
+    beforeSubmit: function (form_values, element_settings, options) {
+      return AJAX.beforeSubmit(form_values, element_settings, options);
+    },
+    success: function (response, status) {
+      // Sanity check for browser support (object expected).
+      // When using iFrame uploads, responses must be returned as a string.
+      if (typeof response == 'string') {
+        response = Drupal.parseJson(response);
+      }
+      return AJAX.success(response, status);
+    },
+    complete: function (response, status) {
+      if (status == 'error' || status == 'parsererror') {
+        return AJAX.error(response, AJAX.url);
+      }
+    },
+    dataType: 'json',
+    type: 'POST'
+  };
+
+  // Bind the ajaxSubmit function to the element event.
+  $(this.element).bind(element_settings.event, function () {
+    if (AJAX.form) {
+      // If setClick is set, we must set this to ensure that the button's
+      // value is passed.
+      if (AJAX.setClick) {
+        // Put our button in.
+        AJAX.form.clk = this.element;
+      }
+
+      AJAX.form.ajaxSubmit(options);
+    }
+    else {
+      jQuery.ajax(options);
+    }
+
+    return false;
+  });
+  // If necessary, enable keyboard submission so that AJAX behaviors
+  // can be triggered through keyboard input as well as e.g. a mousedown
+  // action.
+  if (element_settings.keypress) {
+    $(element_settings.element).keypress(function (event) {
+      // Detect enter key.
+      if (event.keyCode == 13) {
+        $(element_settings.element).trigger(element_settings.event);
+        return false;
+      }
+    });
+  }
+};
+
+/**
+ * Handler for the form redirection submission.
+ */
+Drupal.AJAX.prototype.beforeSubmit = function (form_values, element, options) {
+  // Disable the element that received the change.
+  $(this.element).addClass('progress-disabled').attr('disabled', true);
+
+  // Insert progressbar or throbber.
+  if (this.progress.type == 'bar') {
+    var progressBar = new Drupal.progressBar('AJAX-progress-' + this.element.id, eval(this.progress.update_callback), this.progress.method, eval(this.progress.error_callback));
+    if (this.progress.message) {
+      progressBar.setProgress(-1, this.progress.message);
+    }
+    if (this.progress.url) {
+      progressBar.startMonitoring(this.progress.url, this.progress.interval || 1500);
+    }
+    this.progress.element = $(progressBar.element).addClass('AJAX-progress AJAX-progress-bar');
+    this.progress.object = progressBar;
+    $(this.element).after(this.progress.element);
+  }
+  else if (this.progress.type == 'throbber') {
+    this.progress.element = $('<div class="AJAX-progress AJAX-progress-throbber"><div class="throbber">&nbsp;</div></div>');
+    if (this.progress.message) {
+      $('.throbber', this.progress.element).after('<div class="message">' + this.progress.message + '</div>');
+    }
+    $(this.element).after(this.progress.element);
+  }
+};
+
+/**
+ * Handler for the form redirection completion.
+ */
+Drupal.AJAX.prototype.success = function (response, status) {
+  // Remove the progress element.
+  if (this.progress.element) {
+    $(this.progress.element).remove();
+  }
+  if (this.progress.object) {
+    this.progress.object.stopMonitoring();
+  }
+  $(this.element).removeClass('progress-disabled').attr('disabled', false);
+
+  Drupal.freezeHeight();
+
+  for (i in response) {
+    if (response[i]['command'] && this.commands[response[i]['command']]) {
+      this.commands[response[i]['command']](this, response[i], status);
+    }
+  }
+
+  Drupal.unfreezeHeight();
+
+  // Remove any response-specific settings so they don't get used on the next
+  // call by mistake.
+  this.settings = {};
+};
+
+/**
+ * Build an effect object which tells us how to apply the effect when
+ * adding new html.
+ */
+Drupal.AJAX.prototype.getEffect = function(response) {
+  var type = response.effect || this.effect;
+  var speed = response.speed || this.speed;
+
+  var effect = {};
+  if (type == 'none') {
+    effect.showEffect = 'show';
+    effect.hideEffect = 'hide';
+    effect.showSpeed = '';
+  }
+  else if (type == 'fade') {
+    effect.showEffect = 'fadeIn';
+    effect.hideEffect = 'fadeOut';
+    effect.showSpeed = speed;
+  }
+  else {
+    effect.showEffect = type + 'Toggle';
+    effect.hideEffect = type + 'Toggle';
+    effect.showSpeed = speed;
+  }
+
+  return effect;
+}
+
+/**
+ * Handler to insert the new content into the page.
+ */
+Drupal.AJAX.prototype.insertNewContent = function (response, status) {
+  // Get information from the response. If it is not there, default to
+  // our presets.
+  var wrapper = response.selector ? $(response.selector) : $(this.wrapper);
+  var method = response.method || this.method;
+  var effect = this.getEffect(response);
+
+  // Manually insert HTML into the jQuery object, using $() directly crashes
+  // Safari with long string lengths. http://dev.jquery.com/ticket/1152
+  var new_content = $('<div></div>').html(response.data);
+
+  // Add the new content to the page.
+  if (method == 'replace') {
+    wrapper.empty().append(new_content);
+  }
+  else {
+    wrapper[method](new_content);
+  }
+
+  // Immediately hide the new content if we're using any effects.
+  if (effect.showEffect != 'show') {
+    new_content.hide();
+  }
+
+  // Determine what effect use and what content will receive the effect, then
+  // show the new content.
+  if ($('.AJAX-new-content', new_content).size() > 0) {
+    $('.AJAX-new-content', new_content).hide();
+    new_content.show();
+    $('.AJAX-new-content', new_content)[effect.showEffect](effect.showSpeed);
+  }
+  else if (effect.showEffect != 'show') {
+    new_content[effect.showEffect](effect.showSpeed);
+  }
+
+  // Attach all javascript behaviors to the new content, if it was successfully
+  // added to the page, this if statement allows #ajax[wrapper] to be optional.
+  if (new_content.parents('html').length > 0) {
+    // Apply any settings from the returned JSON if available.
+    var settings = response.settings || this.settings || Drupal.settings;
+    Drupal.attachBehaviors(new_content, settings);
+  }
+};
+
+/**
+ * Handler for the form redirection error.
+ */
+Drupal.AJAX.prototype.error = function (response, uri) {
+  alert(Drupal.ajaxError(response, uri));
+  // Remove the progress element.
+  if (this.progress.element) {
+    $(this.progress.element).remove();
+  }
+  if (this.progress.object) {
+    this.progress.object.stopMonitoring();
+  }
+  // Undo hide.
+  $(this.wrapper).show();
+  // Re-enable the element.
+  $(this.element).removeClass('progress-disabled').attr('disabled', false);
+};
+
+/**
+ * Provide a series of commands that the server can request the client perform.
+ */
+Drupal.AJAX.prototype.commands = {
+
+  /**
+   * Command to insert new content into the DOM
+   */
+  insert: function(ajax, response, status) {
+    ajax.insertNewContent(response, status);
+  },
+
+  /**
+   * Command to remove a chunk from the page.
+   */
+  remove: function(ajax, response, status) {
+    $(response.selector).remove();
+  },
+
+  /**
+   * Command to mark a chunk changed.
+   */
+  changed: function(ajax, response, status) {
+    if (!$(response.selector).hasClass('changed')) {
+      $(response.selector).addClass('changed');
+      if (response.star) {
+        $(response.selector).find(response.star).append(' <span class="star">*</span> ');
+      }
+    }
+  },
+
+  /**
+   * Command to provide an alert.
+   */
+  alert: function(response, status) {
+    alert(response.text, response.title);
+  },
+
+  /**
+   * Command to set the settings that will be used for other commands in this
+   * response.
+   */
+  settings: function(response, status) {
+    this.settings = response.settings;
+  },
+
+  /**
+   * Command to attach data using jQuery's data API.
+   */
+  data: function(response, status) {
+    $(response.selector).data(response.name, response.value);
+  },
+
+  /**
+   * Command to restripe a table.
+   */
+  restripe: function(response, status) {
+    // :even and :odd are reversed because jquery counts from 0 and
+    // we count from 1, so we're out of sync.
+    $('tbody tr:not(:hidden)', $(response.selector))
+      .removeClass('even')
+      .removeClass('odd')
+      .filter(':even')
+        .addClass('odd')
+      .end()
+      .filter(':odd')
+        .addClass('even');
+  }
+};
+
+})(jQuery);
Index: misc/autocomplete.js
===================================================================
RCS file: /cvs/drupal/drupal/misc/autocomplete.js,v
retrieving revision 1.31
diff -u -p -r1.31 autocomplete.js
--- misc/autocomplete.js	3 Jul 2009 19:21:54 -0000	1.31
+++ misc/autocomplete.js	9 Aug 2009 21:24:00 -0000
@@ -289,7 +289,7 @@ Drupal.ACDB.prototype.search = function 
         }
       },
       error: function (xmlhttp) {
-        alert(Drupal.ahahError(xmlhttp, db.uri));
+        alert(Drupal.ajaxError(xmlhttp, db.uri));
       }
     });
   }, this.delay);
Index: misc/drupal.js
===================================================================
RCS file: /cvs/drupal/drupal/misc/drupal.js,v
retrieving revision 1.56
diff -u -p -r1.56 drupal.js
--- misc/drupal.js	3 Jul 2009 19:21:54 -0000	1.56
+++ misc/drupal.js	9 Aug 2009 21:24:00 -0000
@@ -294,9 +294,9 @@ Drupal.getSelection = function (element)
 };
 
 /**
- * Build an error message from ahah response.
+ * Build an error message from ajax response.
  */
-Drupal.ahahError = function (xmlhttp, uri) {
+Drupal.ajaxError = function (xmlhttp, uri) {
   if (xmlhttp.status == 200 || (xmlhttp.status == 500 && xmlhttp.statusText == 'Service unavailable (with message)')) {
     if ($.trim(xmlhttp.responseText)) {
       var message = Drupal.t("An error occurred. \nPath: @uri\nMessage: !text", { '@uri': uri, '!text': xmlhttp.responseText });
Index: misc/progress.js
===================================================================
RCS file: /cvs/drupal/drupal/misc/progress.js,v
retrieving revision 1.24
diff -u -p -r1.24 progress.js
--- misc/progress.js	27 Apr 2009 20:19:35 -0000	1.24
+++ misc/progress.js	9 Aug 2009 21:24:00 -0000
@@ -84,7 +84,7 @@ Drupal.progressBar.prototype.sendPing = 
         pb.timer = setTimeout(function () { pb.sendPing(); }, pb.delay);
       },
       error: function (xmlhttp) {
-        pb.displayError(Drupal.ahahError(xmlhttp, pb.uri));
+        pb.displayError(Drupal.ajaxError(xmlhttp, pb.uri));
       }
     });
   }
Index: modules/book/book.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/book/book.module,v
retrieving revision 1.501
diff -u -p -r1.501 book.module
--- modules/book/book.module	30 Jul 2009 19:24:20 -0000	1.501
+++ modules/book/book.module	9 Aug 2009 21:24:01 -0000
@@ -490,7 +490,7 @@ function _book_add_form_elements(&$form,
     '#description' => t('Your page will be a part of the selected book.'),
     '#weight' => -5,
     '#attributes' => array('class' => 'book-title-select'),
-    '#ahah' => array(
+    '#ajax' => array(
       'path' => 'book/js/form',
       'wrapper' => 'edit-book-plid-wrapper',
       'effect' => 'slide',
Index: modules/field/field.form.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/field/field.form.inc,v
retrieving revision 1.12
diff -u -p -r1.12 field.form.inc
--- modules/field/field.form.inc	27 Jul 2009 20:19:20 -0000	1.12
+++ modules/field/field.form.inc	9 Aug 2009 21:24:01 -0000
@@ -191,7 +191,7 @@ function field_multiple_value_form($fiel
         '#weight' => $instance['weight'] + $max + 1,
         // Submit callback for disabled JavaScript.
         '#submit' => array('field_add_more_submit'),
-        '#ahah' => array(
+        '#ajax' => array(
           'path' => 'field/js_add_more/' . $bundle_name_url_css . '/' . $field_name_url_css,
           'wrapper' => $field_name_url_css . '-wrapper',
           'method' => 'replace',
Index: modules/poll/poll.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/poll/poll.module,v
retrieving revision 1.302
diff -u -p -r1.302 poll.module
--- modules/poll/poll.module	3 Aug 2009 17:30:33 -0000	1.302
+++ modules/poll/poll.module	9 Aug 2009 21:24:02 -0000
@@ -270,7 +270,7 @@ function poll_form($node, $form_state) {
     '#description' => t("If the amount of boxes above isn't enough, click here to add more choices."),
     '#weight' => 1,
     '#submit' => array('poll_more_choices_submit'), // If no javascript action.
-    '#ahah' => array(
+    '#ajax' => array(
       'callback' => 'poll_choice_js',
       'wrapper' => 'poll-choices',
       'method' => 'replace',
@@ -320,7 +320,7 @@ function poll_more_choices_submit($form,
 
   // Make the changes we want to the form state.
   if ($form_state['values']['poll_more']) {
-    $n = $_GET['q'] == 'system/ahah' ? 1 : 5;
+    $n = $_GET['q'] == 'system/ajax' ? 1 : 5;
     $form_state['choice_count'] = count($form_state['values']['choice']) + $n;
   }
 }
@@ -373,9 +373,7 @@ function poll_choice_js($form, $form_sta
 
   // Prevent duplicate wrappers.
   unset($choice_form['#prefix'], $choice_form['#suffix']);
-  $output = theme('status_messages') . drupal_render($choice_form);
-
-  drupal_json(array('status' => TRUE, 'data' => $output));
+  return theme('status_messages') . drupal_render($choice_form);
 }
 
 /**
Index: modules/poll/poll.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/poll/poll.test,v
retrieving revision 1.21
diff -u -p -r1.21 poll.test
--- modules/poll/poll.test	20 Jul 2009 18:51:33 -0000	1.21
+++ modules/poll/poll.test	9 Aug 2009 21:24:02 -0000
@@ -340,7 +340,7 @@ class PollJSAddChoice extends DrupalWebT
     // @TODO: the framework should make it possible to submit a form to a
     // different URL than its action or the current. For now, we can just force
     // it.
-    $this->additionalCurlOptions[CURLOPT_URL] = url('system/ahah', array('absolute' => TRUE));
+    $this->additionalCurlOptions[CURLOPT_URL] = url('system/ajax', array('absolute' => TRUE));
     $this->drupalPost(NULL, $edit, t('More choices'));
     unset($this->additionalCurlOptions[CURLOPT_URL]);
 
Index: modules/system/system.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.module,v
retrieving revision 1.737
diff -u -p -r1.737 system.module
--- modules/system/system.module	5 Aug 2009 19:40:55 -0000	1.737
+++ modules/system/system.module	9 Aug 2009 21:24:05 -0000
@@ -286,7 +286,7 @@ function system_elements() {
     '#name' => 'op',
     '#button_type' => 'submit',
     '#executes_submit_callback' => TRUE,
-    '#process' => array('form_process_ahah'),
+    '#process' => array('ajax_process_form'),
     '#theme_wrappers' => array('button'),
   );
 
@@ -295,7 +295,7 @@ function system_elements() {
     '#name' => 'op',
     '#button_type' => 'submit',
     '#executes_submit_callback' => FALSE,
-    '#process' => array('form_process_ahah'),
+    '#process' => array('ajax_process_form'),
     '#theme_wrappers' => array('button'),
   );
 
@@ -303,7 +303,7 @@ function system_elements() {
     '#input' => TRUE,
     '#button_type' => 'submit',
     '#executes_submit_callback' => TRUE,
-    '#process' => array('form_process_ahah'),
+    '#process' => array('ajax_process_form'),
     '#return_value' => TRUE,
     '#has_garbage_value' => TRUE,
     '#src' => NULL,
@@ -315,7 +315,7 @@ function system_elements() {
     '#size' => 60,
     '#maxlength' => 128,
     '#autocomplete_path' => FALSE,
-    '#process' => array('form_process_text_format', 'form_process_ahah'),
+    '#process' => array('form_process_text_format', 'ajax_process_form'),
     '#theme' => 'textfield',
     '#theme_wrappers' => array('form_element'),
   );
@@ -324,7 +324,7 @@ function system_elements() {
     '#input' => TRUE,
     '#size' => 60,
     '#maxlength' => 128,
-    '#process' => array('form_process_ahah'),
+    '#process' => array('ajax_process_form'),
     '#theme' => 'password',
     '#theme_wrappers' => array('form_element'),
   );
@@ -340,7 +340,7 @@ function system_elements() {
     '#cols' => 60,
     '#rows' => 5,
     '#resizable' => TRUE,
-    '#process' => array('form_process_text_format', 'form_process_ahah'),
+    '#process' => array('form_process_text_format', 'ajax_process_form'),
     '#theme' => 'textarea',
     '#theme_wrappers' => array('form_element'),
   );
@@ -355,7 +355,7 @@ function system_elements() {
   $type['radio'] = array(
     '#input' => TRUE,
     '#default_value' => NULL,
-    '#process' => array('form_process_ahah'),
+    '#process' => array('ajax_process_form'),
     '#theme' => 'radio',
     '#theme_wrappers' => array('form_element'),
     '#form_element_skip_title' => TRUE,
@@ -372,7 +372,7 @@ function system_elements() {
   $type['checkbox'] = array(
     '#input' => TRUE,
     '#return_value' => 1,
-    '#process' => array('form_process_ahah'),
+    '#process' => array('ajax_process_form'),
     '#theme' => 'checkbox',
     '#theme_wrappers' => array('form_element'),
     '#form_element_skip_title' => TRUE,
@@ -382,7 +382,7 @@ function system_elements() {
     '#input' => TRUE,
     '#size' => 0,
     '#multiple' => FALSE,
-    '#process' => array('form_process_ahah'),
+    '#process' => array('ajax_process_form'),
     '#theme' => 'select',
     '#theme_wrappers' => array('form_element'),
   );
@@ -391,7 +391,7 @@ function system_elements() {
     '#input' => TRUE,
     '#delta' => 10,
     '#default_value' => 0,
-    '#process' => array('form_process_weight', 'form_process_ahah'),
+    '#process' => array('form_process_weight', 'ajax_process_form'),
   );
 
   $type['date'] = array(
@@ -430,7 +430,7 @@ function system_elements() {
 
   $type['hidden'] = array(
     '#input' => TRUE,
-    '#process' => array('form_process_ahah'),
+    '#process' => array('ajax_process_form'),
     '#theme' => 'hidden',
   );
 
@@ -447,7 +447,7 @@ function system_elements() {
     '#collapsible' => FALSE,
     '#collapsed' => FALSE,
     '#value' => NULL,
-    '#process' => array('form_process_fieldset', 'form_process_ahah'),
+    '#process' => array('form_process_fieldset', 'ajax_process_form'),
     '#pre_render' => array('form_pre_render_fieldset'),
     '#theme_wrappers' => array('fieldset'),
   );
@@ -476,9 +476,9 @@ function system_menu() {
     'access callback' => TRUE,
     'type' => MENU_CALLBACK,
   );
-  $items['system/ahah'] = array(
+  $items['system/ajax'] = array(
     'title' => 'AHAH callback',
-    'page callback' => 'form_ahah_callback',
+    'page callback' => 'ajax_form_callback',
     'access callback' => TRUE,
     'type' => MENU_CALLBACK,
   );
@@ -1221,7 +1221,7 @@ function system_filetransfer_backends() 
       'weight' => 0,
     );
   }
-  
+
   if (ini_get('allow_url_fopen')) {
     $backends['ftp_wrapper'] = array(
       'title' => t('FTP using file streams'),
@@ -1230,7 +1230,7 @@ function system_filetransfer_backends() 
       'weight' => 10,
     );
   }
-  
+
   // SSH2 lib connection is only available if the proper PHP extension is
   // installed.
   if (function_exists('ssh2_connect')) {
@@ -1256,7 +1256,7 @@ function system_filetransfer_backends() 
 function system_get_filetransfer_settings_form($filetransfer_backend_name, $defaults) {
   $available_backends = module_invoke_all('filetransfer_backends');
   $form = call_user_func($available_backends[$filetransfer_backend_name]['settings_form']);
-  
+
   foreach ($form as $name => &$element) {
     if (isset($defaults[$name])) {
       $element['#default_value'] = $defaults[$name];
@@ -1288,30 +1288,30 @@ function system_filetransfer_backend_for
  */
 function _system_filetransfer_backend_form_common() {
   $form = array();
-  
+
   $form['hostname'] = array (
     '#type' => 'textfield',
     '#title' => t('Host'),
     '#default_value' => 'localhost',
   );
-  
+
   $form['port'] = array (
     '#type' => 'textfield',
     '#title' => t('Port'),
     '#default_value' => NULL,
   );
-  
+
   $form['username'] = array (
     '#type' => 'textfield',
     '#title' => t('Username'),
   );
-  
+
   $form['password'] = array (
     '#type' => 'password',
     '#title' => t('Password'),
     '#description' => t('This is not saved in the database and is only used to test the connection'),
   );
-  
+
   return $form;
 }
 
@@ -3005,17 +3005,17 @@ function system_retrieve_file($url, $des
   }
   $parsed_url = parse_url($url);
   $local = is_dir(file_directory_path() . '/' . $destination) ? $destination . '/' . basename($parsed_url['path']) : $destination;
-  
+
   if (!$overwrite && file_exists($local)) {
     drupal_set_message(t('@remote could not be saved. @local already exists', array('@remote' => $url, '@local' => $local)), 'error');
     return FALSE;
   }
-  
+
   $result = drupal_http_request($url);
   if ($result->code != 200 || !file_save_data($result->data, $local)) {
     drupal_set_message(t('@remote could not be saved.', array('@remote' => $url)), 'error');
     return FALSE;
   }
-  
+
   return $local;
 }
Index: modules/upload/upload.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/upload/upload.module,v
retrieving revision 1.245
diff -u -p -r1.245 upload.module
--- modules/upload/upload.module	31 Jul 2009 19:01:02 -0000	1.245
+++ modules/upload/upload.module	9 Aug 2009 21:24:05 -0000
@@ -60,7 +60,7 @@ function upload_permission() {
  */
 function upload_node_links($node, $build_mode) {
   $links = array();
-    
+
   // Display a link with the number of attachments
   $num_files = 0;
   foreach ($node->files as $file) {
@@ -582,7 +582,7 @@ function _upload_form($node) {
       '#type' => 'submit',
       '#value' => t('Attach'),
       '#name' => 'attach',
-      '#ahah' => array(
+      '#ajax' => array(
         'path' => 'upload/js',
         'wrapper' => 'attach-wrapper',
         'progress' => array('type' => 'bar', 'message' => t('Please wait...')),
