? .git
Index: content.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/cck/content.module,v
retrieving revision 1.301.2.22
diff -u -p -r1.301.2.22 content.module
--- content.module	10 Jul 2008 12:49:09 -0000	1.301.2.22
+++ content.module	11 Jul 2008 19:00:43 -0000
@@ -107,8 +107,9 @@ function content_menu() {
     'type' => MENU_LOCAL_TASK,
   );
   // Callback for AHAH add more buttons.
-  $items['content/js_add_more'] = array(
-    'page callback' => 'content_add_more_js',
+  $items['content/js_add_more/%/%'] = array(
+    'page callback' => 'content_field_form_js',
+    'page arguments' => array(2, 3, 'content_add_more'),
     'access arguments' => array('access content'),
     'file' => 'includes/content.node_form.inc',
     'type' => MENU_CALLBACK,
Index: includes/content.node_form.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/cck/includes/content.node_form.inc,v
retrieving revision 1.7.2.10
diff -u -p -r1.7.2.10 content.node_form.inc
--- includes/content.node_form.inc	7 Jul 2008 13:07:32 -0000	1.7.2.10
+++ includes/content.node_form.inc	11 Jul 2008 19:00:43 -0000
@@ -193,6 +193,11 @@ function content_multiple_value_form(&$f
       }
 
       $form_element[$delta] = array_merge($element, $defaults);
+
+      if (!empty($form_state['content_add_more_ahah']) && $delta == $max) {
+        $form_element[$delta]['#prefix'] = '<div class="ahah-new-content">'. (isset($form_element[$delta]['#prefix']) ? $form_element[$delta]['#prefix'] : '');
+        $form_element[$delta]['#suffix'] = (isset($form_element[$delta]['#suffix']) ? $form_element[$delta]['#suffix'] : '') .'</div>';
+      }
     }
   }
 
@@ -252,15 +257,44 @@ function content_add_more_submit($form, 
 
 
 /**
- * Menu callback for AHAH addition of new empty widgets.
+ * "Add more" request validity callback for content_field_form_js().
+ */
+function content_add_more_js_is_valid_request($field, $callback_options) {
+  return ($field['multiple'] == 1);
+}
+
+/**
+ * "Add more" state alter callback for content_field_form_js():
+ * Set the new item count so that content_multiple_value_form() creates
+ * a table with one additional element.
+ */
+function content_add_more_js_state_alter($form, &$form_state, $field, $callback_options) {
+  $form_state['item_count'] = array(
+    $field['field_name'] => count($form_state['values'][$field['field_name']]) + 1,
+  );
+  $form_state['content_add_more_ahah'] = TRUE;
+}
+
+/**
+ * AHAH callback for updating a widget, with callbacks being able to modify
+ * the state and looks of the replacement form element.
  */
-function content_add_more_js($type_name_url, $field_name) {
-  $type = content_types($type_name_url);
+function content_field_form_js($type_name, $field_name, $callback_base, $callback_options = array()) {
+  $type = content_types($type_name);
   $field = content_fields($field_name, $type['type']);
 
-  if (($field['multiple'] != 1) || empty($_POST['form_build_id'])) {
+  // Under certain circumstances (file uploads, at least), drupal_json() will
+  // break browsers, so make it possible to specify a custom output function.
+  $js_output = isset($callback_options['js output callback'])
+               ? $callback_options['js output callback'] : 'drupal_json';
+
+  // Make sure that AHAH replacements are allowed for this field.
+  $function = $callback_base .'_js_is_valid_request';
+  $valid = function_exists($function) ? $function($field, $callback_options) : TRUE;
+
+  if (!$valid || empty($_POST['form_build_id'])) {
     // Invalid request.
-    drupal_json(array('data' => ''));
+    $js_output(array('data' => ''));
     exit;
   }
 
@@ -270,7 +304,7 @@ function content_add_more_js($type_name_
   $form = form_get_cache($form_build_id, $form_state);
   if (!$form) {
     // Invalid form_build_id.
-    drupal_json(array('data' => ''));
+    $js_output(array('data' => ''));
     exit;
   }
 
@@ -287,27 +321,31 @@ function content_add_more_js($type_name_
   // so we use copies of $form and $form_data.
   $form_copy = $form;
   $form_state_copy = $form_state;
-  $form_copy['#post'] = array();
+  $form_copy['#post'] = $_POST;
   form_builder($_POST['form_id'], $form_copy, $form_state_copy);
   // Just grab the data we need.
   $form_state['values'] = $form_state_copy['values'];
+  unset($form_state['values'][$field_name][$field_name .'_add_more']);
   // Reset cached ids, so that they don't affect the actual form we output.
   form_clean_id(NULL, TRUE);
 
+  // Let the callback do whatever it intends with the form state.
+  $function = $callback_base .'_js_state_alter';
+  if (function_exists($function)) {
+    $function($form, $form_state, $field, $callback_options);
+  }
+
   // Sort the $form_state['values'] we just built *and* the incoming $_POST data
   // according to d-n-d reordering.
-  unset($form_state['values'][$field_name][$field['field_name'] .'_add_more']);
   foreach ($_POST[$field_name] as $delta => $item) {
     $form_state['values'][$field_name][$delta]['_weight'] = $item['_weight'];
   }
   $form_state['values'][$field_name] = _content_sort_items($field, $form_state['values'][$field_name]);
-  $_POST[$field_name] = _content_sort_items($field, $_POST[$field_name]);
 
   // Build our new form element for the whole field, asking for one more element.
-  $form_state['item_count'] = array($field_name => count($_POST[$field_name]) + 1);
   $form_element = content_field_form($form, $form_state, $field);
   // Let other modules alter it.
-  drupal_alter('form', $form_element, array(), 'content_add_more_js');
+  drupal_alter('form', $form_element, array(), 'content_field_form_js');
 
   // Add the new element at the right place in the (original, unbuilt) form.
   if (module_exists('fieldgroup') && ($group_name = _fieldgroup_field_get_group($type['type'], $field_name))) {
@@ -321,22 +359,21 @@ function content_add_more_js($type_name_
   $form_state['values'] = array();
   form_set_cache($form_build_id, $form, $form_state);
 
-  // Build the new form against the incoming $_POST values so that we can
-  // render the new element.
-  $delta = max(array_keys($_POST[$field_name])) + 1;
-  $_POST[$field_name][$delta]['_weight'] = $delta;
+  // When rebuilding with changed elements, $_POST would cause Form API to
+  // unset their values instead of using default values. Therefore, no $_POST.
+  $form_id = $_POST['form_id'];
+  $_POST = array();
+
+  // Rebuild the form with the new field form.
   $form_state = array('submitted' => FALSE);
   $form += array(
     '#post' => $_POST,
     '#programmed' => FALSE,
   );
-  $form = form_builder($_POST['form_id'], $form, $form_state);
+  $form = form_builder($form_id, $form, $form_state);
 
   // Render the new output.
   $field_form = (!empty($group_name)) ? $form[$group_name][$field_name] : $form[$field_name];
-  // We add a div around the new content to receive the ahah effect.
-  $field_form[$delta]['#prefix'] = '<div class="ahah-new-content">'. (isset($field_form[$delta]['#prefix']) ? $field_form[$delta]['#prefix'] : '');
-  $field_form[$delta]['#suffix'] = (isset($field_form[$delta]['#suffix']) ? $field_form[$delta]['#suffix'] : '') .'</div>';
 
   // If a newly inserted widget contains AHAH behaviors, they normally won't
   // work because AHAH doesn't know about those - it just attaches to the exact
@@ -347,6 +384,6 @@ function content_add_more_js($type_name_
   $output_js = isset($javascript['setting']) ? '<script type="text/javascript">jQuery.extend(Drupal.settings, '. drupal_to_js(call_user_func_array('array_merge_recursive', $javascript['setting'])) .');</script>' : '';
 
   $output = theme('status_messages') . drupal_render($field_form) . $output_js;
-  drupal_json(array('status' => TRUE, 'data' => $output));
+  $js_output(array('status' => TRUE, 'data' => $output));
   exit;
 }
