diff --git a/imagefield_zip.ahah.inc b/imagefield_zip.ahah.inc
index 051d322..c69ec6f 100644
--- a/imagefield_zip.ahah.inc
+++ b/imagefield_zip.ahah.inc
@@ -1,4 +1,5 @@
 <?php
+
 /**
  * AHAH menu callback.
  */
@@ -14,7 +15,7 @@ function imagefield_zip_js($type_name, $field_name) {
     'imagefield_zip_is_valid_zip' => array(),
   );
 
-  if ($file = file_save_upload($field_name .'_zip', $validators)) {
+  if ($file = file_save_upload($field_name . '_zip', $validators)) {
     // Extract all files.
     $extracted = imagefield_zip_extract($file->filepath);
     if (!empty($extracted)) {
@@ -33,28 +34,37 @@ function imagefield_zip_js($type_name, $field_name) {
   }
 
   // Generate HTML for the images that where uploaded
-  $result = _imagefield_zip_js($type_name, $field_name, $images);
+  $result = imagefield_zip_add_files_to_form($type_name, $field_name, $images);
 
   // Theme HTML
   $data = theme('status_messages') . $result;
-  if ($result !== false) {
-    $return = array('data' => $data, 'status' => true);
+  if ($result !== FALSE) {
+    $return = array('data' => $data, 'status' => TRUE);
   }
   else {
     $return = array('data' => $data);
   }
 
-  // Converts a PHP variable into its Javascript equivalent.
+  // For some reason, file uploads don't like drupal_json() with its manual
+  // setting of the text/javascript HTTP header. So use this one instead.
   print drupal_to_js($return);
   exit;
 }
 
-function _imagefield_zip_js($type_name, $field_name, $files) {
+/**
+ * AHAH addition of new widgets containing the uploaded files.
+ */
+function imagefield_zip_add_files_to_form($type_name, $field_name, $files) {
   $field = content_fields($field_name, $type_name);
 
+  // Immediately disable devel shutdown functions so that it doesn't botch our
+  // JSON output.
+  $GLOBALS['devel_shutdown'] = FALSE;
+
   if (empty($field) || empty($_POST['form_build_id'])) {
     // Invalid request.
-    return false;
+    drupal_set_message(t('An unrecoverable error occurred. The uploaded file likely exceeded the maximum file size (@size) that this server supports.', array('@size' => format_size(file_upload_max_size()))), 'error');
+    return FALSE;
   }
 
   // Build the new form.
@@ -64,119 +74,147 @@ function _imagefield_zip_js($type_name, $field_name, $files) {
 
   if (!$form) {
     // Invalid form_build_id.
-    return false;
+    drupal_set_message(t('An unrecoverable error occurred. This form was missing from the server cache. Try reloading the page and submitting again.'), 'error');
+    return FALSE;
   }
 
-  // form_get_cache() doesn't yield the original $form_state,
-  // but form_builder() does. Needed for retrieving the file array.
-  $built_form = $form;
-  $built_form_state = $form_state;
-
-  $built_form += array('#post' => $_POST);
-  $built_form = form_builder($_POST['form_id'], $built_form, $built_form_state);
-
-  // Clean ids, so that the same element doesn't get a different element id
-  // when rendered once more further down.
-  form_clean_id(NULL, TRUE);
-
-  // Ask CCK for the replacement form element. Going through CCK gets us
-  // the benefit of nice stuff like '#required' merged in correctly.
+  // Include files we need and gather some other helpful info.
   module_load_include('inc', 'content', 'includes/content.node_form');
-  $field_element = content_field_form($form, $built_form_state, $field);
   $dest = filefield_widget_file_path($field);
   $widget_function = $field['widget']['module'] .'_widget';
 
-  // Remove any unused previous fields to tidy things up
-  foreach (element_children($field_element[$field_name]) as $existing_field) {
-    if ($field_element[$field_name][$existing_field]['#type'] == 'imagefield_widget') {
-      if (empty($field_element[$field_name][$existing_field]['#default_value']['fid'])) {
-        unset($field_element[$field_name][$existing_field]);
-      }
-    }
-  }
+  // We don't simply return a new empty widget to append to existing ones, because
+  // - ahah.js won't simply let us add a new row to a table
+  // - attaching the 'draggable' behavior won't be easy
+  // So we resort to rebuilding the whole table of widgets including the existing ones,
+  // which makes us jump through a few hoops.
+
+  // The form that we get from the cache is unbuilt. We need to build it so that
+  // _value callbacks can be executed and $form_state['values'] populated.
+  // We only want to affect $form_state['values'], not the $form itself
+  // (built forms aren't supposed to enter the cache) nor the rest of $form_data,
+  // so we use copies of $form and $form_data.
+  $form_copy = $form;
+  $form_state_copy = $form_state;
+  $form_copy['#post'] = array();
+  form_builder($_POST['form_id'], $form_copy, $form_state_copy);
+  // Just grab the data we need.
+  $form_state['values'] = $form_state_copy['values'];
+  // Reset cached ids, so that they don't affect the actual form we output.
+  form_clean_id(NULL, TRUE);
 
-  // Go through each file and create and append it to an imagefield
-  for ($delta = 0, $file = reset($files); $file; ++$delta) {
-    if (!isset($field_element[$field_name][$delta]) || empty($field_element[$field_name][$delta]['#default_value'])) {
-      $delta_element = $widget_function($built_form, $built_form_state, $field, array(), $delta);
-
-      if ($file = field_file_save_file($file->filepath, $delta_element['#upload_validators'], $dest)) {
-        // Set the default value of the widget to the extracted file.
-        // Element requires #field_name and #type_name to be set
-        // or it triggers PHP notices later on within content.module.
-        $delta_element['#field_name'] = $field_name;
-        $delta_element['#type_name'] = $type_name;
-        $delta_element['#delta'] = $delta;
-        $delta_element['#array_parents'][] = $field_name;
-
-        $delta_element['#default_value'] = filefield_widget_value($delta_element, (array) $file);
-        // We add a div around the new content to tell AHAH to let this fade in.
-        $delta_element['#prefix'] = '<div class="ahah-new-content">';
-        $delta_element['#suffix'] = '</div>';
-
-        // theme_content_multiple_values() does not use default element order
-        // or #weight
-        // Need to explicitly set this value or import order gets randomized.
-        $delta_element['_weight'] = array(
-          '#type' => 'weight',
-          '#default_value' => $delta,
-        );
-
-        $field_element[$field_name][$delta] = $delta_element;
-      }
-      // If the file isn't valid then don't include the widget into the form but reuse the delta index.
-      // Don't worry, we're still counting the file index so there won't be an infinate loop... I hope.
-      else {
-        --$delta;
-      }
-      $file = next($files);
-    }
+  // 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][$delta]['_remove'] = isset($item['_remove']) ? $item['_remove'] : 0;
   }
-  $field_element['#programmed'] = FALSE;
-  $field_element['#tree'] = FALSE;
+  $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.
+  $form_state['item_count'] = array($field_name => count($_POST[$field_name]));
+  $form_element = content_field_form($form, $form_state, $field);
+
+  // Go through each file and add it the newly crated element from above.
+  $delta = 0;
+  $delta_used = array();
+  foreach ($files as $file) {
+    // Get an empty delta.
+    while (!empty($form_element[$field_name][$delta]['#default_value'])) {
+      $delta++;
+    }
 
-  // Add the new element at the right place in the form.
-  if (module_exists('fieldgroup') && ($group_name = _fieldgroup_field_get_group($type_name, $field_name))) {
-    $form[$group_name][$field_name] = form_builder($_POST['form_id'], $field_element, $built_form_state);
-  }
-  else {
-    $form[$field_name] = form_builder($_POST['form_id'], $field_element, $built_form_state);
+    // Create a new element.
+    $delta_element = $widget_function($built_form, $built_form_state, $field, array(), $delta);
+
+    // Put the file in the new element.
+    if ($file = field_file_save_file($file->filepath, $delta_element['#upload_validators'], $dest)) {
+      // Set the default value of the widget to the extracted file.
+      // Element requires #field_name and #type_name to be set
+      // or it triggers PHP notices later on within content.module.
+      $delta_element['#field_name'] = $field_name;
+      $delta_element['#type_name'] = $type_name;
+      $delta_element['#delta'] = $delta;
+      $delta_element['#array_parents'][] = $field_name;
+
+      $delta_element['#default_value'] = filefield_widget_value($delta_element, (array) $file);
+      // We add a div around the new content to tell AHAH to let this fade in.
+      $delta_element['#prefix'] = '<div class="ahah-new-content">';
+      $delta_element['#suffix'] = '</div>';
+
+      // theme_content_multiple_values() does not use default element order
+      // or #weight
+      // Need to explicitly set this value or import order gets randomized.
+      $delta_element['_weight'] = array(
+        '#type' => 'weight',
+        '#default_value' => $delta,
+      );
+      $delta_used[] = $delta;
+      $form_element[$field_name][$delta] = $delta_element;
+    }
   }
 
-  // Write the (unbuilt, updated) form back to the form cache.
+  // Let other modules alter it.
+  // We pass an empty array as hook_form_alter's usual 'form_state' parameter,
+  // instead of $form_atate (for reasons we may never remember).
+  // However, this argument is still expected to be passed by-reference
+  // (and PHP5.3 will throw an error if it isn't.) This leads to:
+  $data = &$form_element;
+  $empty_form_state = array();
+  $data['__drupal_alter_by_ref'] = array(&$empty_form_state);
+  drupal_alter('form', $data, 'content_add_more_js');
+
+  // Add the new element at the right place in the (original, unbuilt) form.
+  $success = content_set_nested_elements($form, $field_name, $form_element[$field_name]);
+
+  // Save the new definition of the form.
+  $form_state['values'] = array();
   form_set_cache($form_build_id, $form, $form_state);
 
-  // Render the form for output.
+  // Build the new form against the incoming $_POST values so that we can
+  // render the new element.
+  $form_state = array('submitted' => FALSE);
   $form += array(
     '#post' => $_POST,
     '#programmed' => FALSE,
   );
-  drupal_alter('form', $form, array(), 'imagefield_zip_js');
-  $form_state = array('submitted' => FALSE);
-  $form = form_builder('imagefield_zip_js', $form, $built_form_state);
-  $field_form = empty($group_name) ? $form[$field_name] : $form[$group_name][$field_name];
+  $form = form_builder($_POST['form_id'], $form, $form_state);
+
+  // Render the new output.
+  $field_form = array_shift(content_get_nested_elements($form, $field_name));
+
+  // We add a div around the new content to receive the ahah effect.
+  foreach ($delta_used as $delta) {
+    $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>';
+  }
+  // Prevent duplicate wrapper.
+  unset($field_form['#prefix'], $field_form['#suffix']);
 
   $output = drupal_render($field_form);
 
-  // AHAH is not being nice to us and doesn't know the "other" button (that is,
-  // either "Upload" or "Delete") yet. Which in turn causes it not to attach
-  // AHAH behaviours after replacing the element. So we need to tell it first.
+  // 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
+  // form elements that were initially specified in the Drupal.settings object.
+  // The new ones didn't exist then, so we need to update Drupal.settings
+  // by ourselves in order to let AHAH know about those new form elements.
   $javascript = drupal_add_js(NULL, NULL);
-  $id = 'edit-' . str_replace('_', '-', $field_name) . '-upload';
-  if (isset($javascript['setting'])) {
-    $output .= '<script type="text/javascript">jQuery.extend(Drupal.settings, '. drupal_to_js(call_user_func_array('array_merge_recursive', $javascript['setting'])) .');</script>';
-  }
+  $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>' : '';
 
   // Destory the orginal zip upload form and replace it with the clean clone.
-  $output .= '<script type="text/javascript">
+  $id = 'edit-' . str_replace('_', '-', $field_name) . '-upload';
+  $output_js .= '<script type="text/javascript">
   _imagefield_zip_' . $field_name . '_cloned.insertAfter(_imagefield_zip_' . $field_name . '_real);
   _imagefield_zip_' . $field_name . '_real.remove();
   _imagefield_zip_' . $field_name . '_real = $("#' . $id . '");
   _imagefield_zip_' . $field_name . '_cloned = _imagefield_zip_' . $field_name . '_real.clone(true);
   </script>';
 
-  // For some reason, file uploads don't like drupal_json() with its manual
-  // setting of the text/javascript HTTP header. So use this one instead.
-  $GLOBALS['devel_shutdown'] = false;
-  return $output;
+  // Using drupal_json() breaks filefield's file upload, because the jQuery
+  // Form plugin handles file uploads in a way that is not compatible with
+  // 'text/javascript' response type.
+  $GLOBALS['devel_shutdown'] =  FALSE;
+  return $output . $output_js;
 }
diff --git a/imagefield_zip.module b/imagefield_zip.module
index 3cf11d1..61fb7ff 100644
--- a/imagefield_zip.module
+++ b/imagefield_zip.module
@@ -66,6 +66,8 @@ function imagefield_zip_extract($filepath) {
  * Implementation of hook_form_alter().
  */
 function imagefield_zip_form_alter(&$form, $form_state, $form_id) {
+
+
   if (isset($form['type']) && isset($form['#node']) && $form['type']['#value'] .'_node_form' == $form_id && ($type = content_types($form['#node']->type))) {
     $form['#after_build'][] = '_imagefield_zip_form_after_build';
 
@@ -162,21 +164,33 @@ function _imagefield_zip_form(&$form, $field_name, $node) {
       //'#imagefield' => &$form[$field_name],
     );
 
+    // Code adapted from content_multiple_value_form().
+    // Make sure the form is cached so ahah can work.
+    $form['#cache'] = TRUE;
+    $field_name_css = str_replace('_', '-', $form[$field_name]['#field_name']);
+
     $form[$field_name .'_zip'][$field_name . '_button'] = array(
       '#type' => 'submit',
       '#value' => t('Upload'),
-      '#process' => array('form_expand_ahah'),
-      '#submit' => array('node_form_submit_build_node'),
+      // Submit callback for disabled JavaScript. drupal_get_form() might get
+      // the form from the cache, so we can't rely on content_form_alter()
+      // including this file. Therefore, call a proxy function to do this.
+      '#submit' => array('content_add_more_submit_proxy'),
       '#ahah' => array(
         'path' => 'imagefield_zip/ahah/'. $node->type .'/'. $field_name,
-        'wrapper' => str_replace('_', '-', $form[$field_name]['#field_name']) .'-items',
+        'wrapper' => $field_name_css .'-items',
         'method' => 'replace',
         'effect' => 'fade',
       ),
-      '#suffix' => '<br />',
+      // When JS is disabled, the content_add_more_submit handler will find
+      // the relevant field using these entries.
+      '#field_name' => $field_name,
+      '#type_name' => $form['type']['#value'],
+      '#prefix' => '<div class="clear-block">',
+      '#suffix' => '</div>',
     );
 
-    $form[$field_name]['#prefix'] .= '<div id="'. str_replace('_', '-', $form[$field_name]['#field_name']) .'-items">';
+    $form[$field_name]['#prefix'] .= '<div id="'. $field_name_css .'-items">';
     $form[$field_name]['#suffix'] .= '</div>';
 
     return TRUE;
