Index: content_multigroup.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/cck/modules/content_multigroup/Attic/content_multigroup.module,v
retrieving revision 1.1.2.4
diff -u -r1.1.2.4 content_multigroup.module
--- content_multigroup.module	22 Oct 2008 11:02:41 -0000	1.1.2.4
+++ content_multigroup.module	6 Dec 2008 15:18:09 -0000
@@ -61,7 +61,7 @@
     module_load_include('inc', 'content', 'includes/content.admin');
     $settings = array('multigroup' => array('multiple' => 1));
     foreach (array_keys(content_build_modes()) as $key) {
-      $settings['multigroup']['display_settings'][$key]['format'] = 'fieldset';
+      $settings['display'][$key]['format'] = 'fieldset';
     }
     return $settings;
   }
@@ -108,12 +108,12 @@
     content_multigroup_field_overview_form($form, $form_state);
     $form['#validate'][] = 'content_multigroup_field_overview_form_validate';
   }
-  elseif ($form_id == 'content_display_overview_form') {
+  elseif ($form_id == 'content_display_overview_form' && !empty($form['#groups'])) {
     content_multigroup_display_overview_form($form, $form_state, $form_id);
     $form['#submit'] = array_merge(array('content_multigroup_display_overview_form_submit'), $form['#submit']);
   }
   elseif ($form_id == 'fieldgroup_group_edit_form') {
-    return content_multigroup_group_edit_form($form, $form_state, $form_id);
+    content_multigroup_group_edit_form($form, $form_state, $form_id);
   }
 }
 
@@ -180,39 +180,37 @@
     }
   }
 
-  if (!empty($fields)) {
-    foreach ($fields as $field_name => $field) {
-      $new_group = $form_values[$field_name]['parent'];
-      $old_group = $form_values[$field_name]['prev_parent'];
-      if (!empty($new_group) && isset($groups[$new_group]) && $groups[$new_group]['group_type'] == 'multigroup') {
-        $allowed_in = content_multigroup_allowed_in($field, $groups[$new_group]);
-        if (!$allowed_in['allowed']) {
-          form_set_error($field_name, $allowed_in['message']);
-        }
-        else {
-          if (!empty($allowed_in['message'])) {
-            drupal_set_message($allowed_in['message']);
-          }
-          module_load_include('inc', 'content', 'includes/content.crud');
-          $content_type = content_types($type_name);
-          $multiple = $groups[$new_group]['settings']['multigroup']['multiple'];
-          $multiple_values = content_multigroup_multiple_values();
-          $field = $content_type['fields'][$field_name];
-          $field['multiple'] = $multiple;
-          $field = content_field_instance_collapse($field);
-          content_field_instance_update($field);
-          drupal_set_message(t('The field %field has been updated to use %multiple values, to match the multiple value setting of the Multigroup %group.', array(
-            '%field' => $field['label'], '%multiple' => $multiple_values[$multiple], '%group' => $groups[$new_group]['label'])));
-        }
+  foreach ($fields as $field_name => $field) {
+    $new_group = $form_values[$field_name]['parent'];
+    $old_group = $form_values[$field_name]['prev_parent'];
+    if (!empty($new_group) && isset($groups[$new_group]) && $groups[$new_group]['group_type'] == 'multigroup') {
+      $allowed_in = content_multigroup_allowed_in($field, $groups[$new_group]);
+      if (!$allowed_in['allowed']) {
+        form_set_error($field_name, $allowed_in['message']);
       }
-      elseif (!empty($old_group) && isset($groups[$old_group]) && $groups[$old_group]['group_type'] == 'multigroup') {
-        $allowed_out = content_multigroup_allowed_out($field, $groups[$old_group]);
-        if (!$allowed_out['allowed']) {
-          form_set_error($field_name, $allowed_out['message']);
-        }
-        elseif (!empty($allowed_out['message'])) {
-          drupal_set_message($allowed_out['message']);
+      else {
+        if (!empty($allowed_in['message'])) {
+          drupal_set_message($allowed_in['message']);
         }
+        module_load_include('inc', 'content', 'includes/content.crud');
+        $content_type = content_types($type_name);
+        $group_multiple = $groups[$new_group]['settings']['multigroup']['multiple'];
+        $multiple_values = content_multigroup_multiple_values();
+        $field = $content_type['fields'][$field_name];
+        $field['multiple'] = $group_multiple;
+        $field = content_field_instance_collapse($field);
+        content_field_instance_update($field);
+        drupal_set_message(t('The field %field has been updated to use %multiple values, to match the multiple value setting of the Multigroup %group.', array(
+          '%field' => $field['label'], '%multiple' => $multiple_values[$group_multiple], '%group' => $groups[$new_group]['label'])));
+      }
+    }
+    elseif (!empty($old_group) && isset($groups[$old_group]) && $groups[$old_group]['group_type'] == 'multigroup') {
+      $allowed_out = content_multigroup_allowed_out($field, $groups[$old_group]);
+      if (!$allowed_out['allowed']) {
+        form_set_error($field_name, $allowed_out['message']);
+      }
+      elseif (!empty($allowed_out['message'])) {
+        drupal_set_message($allowed_out['message']);
       }
     }
   }
@@ -230,12 +228,12 @@
   // We can't allow fields with more multiple values than the group has
   // to be moved into it.
   $max_existing = content_max_delta($field['field_name']);
-  $group_max = $group['settings']['multigroup']['multiple'];
+  $group_multiple = $group['settings']['multigroup']['multiple'];
   $multiple_values = content_multigroup_multiple_values();
-  if ($group_max != 1 && $max_existing > $group_max) {
+  if ($group_multiple != 1 && $max_existing > $group_multiple) {
     return array(
       'allowed' => FALSE,
-      'message' => t('This change is not allowed. The field %field already has %multiple values in the database but the group %group only allows %group_max. Making this change would result in the loss of data.', array('%field' => $field['widget']['label'], '%multiple' => $max_existing, '%group' => $group['label'], '%group_max' => $multiple_values[$group_max]))
+      'message' => t('This change is not allowed. The field %field already has %multiple values in the database but the group %group only allows %group_max. Making this change would result in the loss of data.', array('%field' => $field['widget']['label'], '%multiple' => $max_existing, '%group' => $group['label'], '%group_max' => $multiple_values[$group_multiple]))
     );
   }
 
@@ -254,7 +252,7 @@
       'nodereference_select',
       'userreference_buttons',
       'userreference_select',
-      );
+    );
     $allowed_widgets = array_merge($allowed_widgets, module_invoke_all('content_multigroup_allowed_widgets'));
     if (!in_array($field['widget']['type'], $allowed_widgets)) {
       return array(
@@ -295,14 +293,14 @@
 
   $max_existing = content_max_delta($field['field_name']);
   $no_remove_widgets = array(
-      'optionwidgets_select',
-      'optionwidgets_buttons',
-      'optionwidgets_onoff',
-      'nodereference_buttons',
-      'nodereference_select',
-      'userreference_buttons',
-      'userreference_select',
-      );
+    'optionwidgets_select',
+    'optionwidgets_buttons',
+    'optionwidgets_onoff',
+    'nodereference_buttons',
+    'nodereference_select',
+    'userreference_buttons',
+    'userreference_select',
+  );
   $no_remove_widgets = array_merge($no_remove_widgets, module_invoke_all('content_multigroup_no_remove_widgets'));
   if (in_array($field['widget']['type'], $no_remove_widgets) && $max_existing > 0) {
     return array(
@@ -336,14 +334,17 @@
   $contexts_selector = $form['#contexts'];
 
   // Gather type information.
-  $type = content_types($type_name);
-  $field_types = _content_field_types();
-  $fields = $type['fields'];
+  $content_type = content_types($type_name);
+
+  // The content module stops building the form if the type has no fields.
+  if (empty($content_type['fields'])) {
+    return;
+  }
 
   $groups = $group_options = array();
   if (module_exists('fieldgroup')) {
-    $groups = fieldgroup_groups($type['type']);
-    $group_options = _fieldgroup_groups_label($type['type']);
+    $groups = fieldgroup_groups($type_name);
+    $group_options = _fieldgroup_groups_label($type_name);
   }
   $contexts = content_build_modes($contexts_selector);
 
@@ -363,7 +364,7 @@
     if ($group['group_type'] != 'multigroup') {
       continue;
     }
-    $defaults = $group['settings']['multigroup']['display_settings'];
+    $defaults = $group['settings']['display'];
 
     $form_name = $name .'_subgroup';
     $form['#fields'] = array_merge(array($form_name), $form['#fields']);
@@ -383,11 +384,16 @@
       $form[$form_name][$key]['format'] = array(
         '#type' => 'select',
         '#options' => $options,
-        '#default_value' => isset($defaults[$key]) ? $defaults[$key] : 'fieldset',
+        '#default_value' => isset($defaults[$key]['format']) ? $defaults[$key]['format'] : 'fieldset',
+      );
+      // exclude in $content
+      $form[$form_name][$key]['exclude'] = array(
+        '#type' => 'checkbox',
+        '#options' => array(0 => t('Include'), 1 => t('Exclude')),
+        '#default_value' => isset($defaults[$key]['exclude']) ? $defaults[$key]['exclude'] : 0,
       );
     }
   }
-  return $form;
 }
 
 /**
@@ -409,7 +415,7 @@
 
       // We have some numeric keys here, so we can't use array_merge.
       foreach ($values as $k => $v) {
-        $group['settings']['multigroup']['display_settings'][$k] = $v;
+        $group['settings']['display'][$k] = $v;
       }
       fieldgroup_save_group($form['#type_name'], $group);
 
@@ -430,7 +436,7 @@
   $group_name = $form['group_name']['#default_value'];
 
   $content_type = content_types($type_name);
-  $groups = fieldgroup_groups($content_type['type']);
+  $groups = fieldgroup_groups($type_name);
   $group = $groups[$group_name];
 
   if ($group['group_type'] != 'multigroup') {
@@ -442,7 +448,7 @@
   $form['group_type'] = array(
     '#type' => 'hidden',
     '#value' => $group['group_type'],
-    );
+  );
   $form['settings']['multigroup'] = array(
     '#type' => 'fieldset',
     '#title' => t('Other settings'),
@@ -454,13 +460,13 @@
   $description .= t("'Unlimited' will provide an 'Add more' button so the users can add repeat it as many times as they like.") . ' ';
   $description .= t('All fields in this group will automatically be set to allow this number of values.');
 
-  $multiple = isset($group['settings']['multigroup']['multiple']) ? $group['settings']['multigroup']['multiple'] : 1;
+  $group_multiple = isset($group['settings']['multigroup']['multiple']) ? $group['settings']['multigroup']['multiple'] : 1;
   $form['settings']['multigroup']['multiple'] = array(
     '#tree' => TRUE,
     '#type' => 'select',
     '#title' => t('Number of repeats'),
     '#options' => content_multigroup_multiple_values(),
-    '#default_value' => $multiple,
+    '#default_value' => $group_multiple,
     '#description' => $description,
   );
 
@@ -469,8 +475,8 @@
     '#title' => t('Labels'),
     '#description' => t("Labels for each subgroup of fields. Labels can be hidden or shown in various contexts using the 'Display fields' screen."),
   );
-  if ($multiple < 2) {
-    $multiple = 0;
+  if ($group_multiple < 2) {
+    $group_multiple = 0;
   }
   for ($i = 0; $i < 10; $i++) {
     $form['settings']['multigroup']['labels'][$i] = array(
@@ -482,7 +488,6 @@
 
   $form['#validate'][] = 'content_multigroup_group_edit_form_validate';
   $form['#submit'][] = 'content_multigroup_group_edit_form_submit';
-  return $form;
 }
 
 /**
@@ -523,10 +528,9 @@
   $content_type = $form['#content_type'];
   $groups = fieldgroup_groups($content_type['type']);
   $group = $groups[$form_values['group_name']];
-  $multiple = $form_values['settings']['multigroup']['multiple'];
-  foreach ($group['fields'] as $field_name => $data) {
-    $field = $content_type['fields'][$field_name];
-    $field['multiple'] = $multiple;
+  $group_fields = array_intersect_key($content_type['fields'], $group['fields']);
+  foreach ($group_fields as $field_name => $field) {
+    $field['multiple'] = $form_values['settings']['multigroup']['multiple'];
     $field = content_field_instance_collapse($field);
     content_field_instance_update($field);
   }
@@ -547,59 +551,63 @@
   }
 
   $node = $form['#node'];
-  $fields = $group['fields'];
-  $content_fields = content_fields();
+  $content_type = content_types($group['type_name']);
   $group_name = $group['group_name'];
+  $group_fields = array_intersect_key($content_type['fields'], $group['fields']);
+  $group_multiple = $group['settings']['multigroup']['multiple'];
 
-  // Use the first field in the group to get the item counts.
-  $first_field_name = array_shift(array_keys($group['fields']));
-  $first_field = isset($content_fields[$first_field_name]) ? $content_fields[$first_field_name] : array();
-  $first_field_items = isset($node->$first_field_name) ? $node->$first_field_name : array();
-
-  $group['multiple'] = $group['settings']['multigroup']['multiple'];
-  switch ($group['multiple']) {
+  switch ($group_multiple) {
     case 0:
-      $max = 0;
+      $group_deltas = array(0);
+      $max_delta = 0;
       break;
+
     case 1:
-      // Is this a new node?
-      if (empty($first_field_items)) {
-        $max = 1;
+      $group_deltas = array();
+      $max_delta = -1;
+      foreach ($group_fields as $field_name => $field) {
+        $field_items = isset($node->$field_name) ? $node->$field_name : array();
+        if (!empty($field_items)) {
+          $field = $group_fields[$field_name];
+          $field_deltas = array_keys(content_set_empty($field, $field_items));
+          $field_max = (!empty($field_deltas) ? max($field_deltas) : 0);
+          if ($field_max > $max_delta || empty($group_deltas)) {
+            $max_delta = $field_max;
+            $group_deltas = $field_deltas;
+          }
+        }
       }
-      else {
-        $filled_items = content_set_empty($first_field, $first_field_items);
-        $current_item_count = isset($form_state['item_count'][$group_name])
-                            ? $form_state['item_count'][$group_name]
-                            : count($first_field_items);
-        // We always want at least one empty icon for the user to fill in.
-        $max = ($current_item_count > count($filled_items))
-              ? $current_item_count - 1
-              : count($filled_items);
+      $current_item_count = (isset($form_state['item_count'][$group_name]) ? $form_state['item_count'][$group_name] : count($group_deltas) + 1);
+      while (count($group_deltas) < $current_item_count) {
+        $max_delta++;
+        $group_deltas[] = $max_delta;
       }
       break;
+
     default:
-      $max = $group['multiple'] - 1;
+      $group_deltas = array_keys(array_fill(0, $group_multiple, 0));
+      $max_delta = $group_multiple - 1;
       break;
   }
 
   $form[$group_name]['#theme'] = 'content_multigroup_node_form';
-  $form[$group_name]['#multiple'] = !empty($max);
+  $form[$group_name]['#item_count'] = count($group_deltas);
   $form[$group_name]['#type_name'] = $group['type_name'];
   $form[$group_name]['#group_name'] = $group_name;
   $form[$group_name]['#group_label'] = $group['label'];
   $form[$group_name]['#element_validate'] = array('content_multigroup_node_form_validate');
   $form[$group_name]['#tree'] = TRUE;
 
-  for ($delta = 0; $delta <= $max; $delta++) {
+  foreach ($group_deltas as $delta) {
     content_multigroup_group_form($form, $form_state, $group, $delta);
   }
 
   // Unset the original group field values now that we've moved them.
-  foreach ($fields as $field_name => $field) {
+  foreach (array_keys($group_fields) as $field_name) {
     unset($form[$group_name][$field_name]);
   }
 
-  if ($add_more = content_multigroup_add_more($form, $form_state, $group)) {
+  if (($add_more = content_multigroup_add_more($form, $form_state, $group)) !== FALSE) {
     $form[$group_name] += $add_more;
   }
 }
@@ -617,13 +625,13 @@
   module_load_include('inc', 'content', 'includes/content.node_form');
 
   $node = $form['#node'];
-  $fields = $group['fields'];
-  $content_fields = content_fields();
+  $content_type = content_types($group['type_name']);
+  $group_fields = array_intersect_key($content_type['fields'], $group['fields']);
   $group_name = $group['group_name'];
-  $group['multiple'] = $group['settings']['multigroup']['multiple'];
-  $form[$group_name]['#fields'] = array_keys($group['fields']);
+  $group_multiple = $group['settings']['multigroup']['multiple'];
+  $form[$group_name]['#fields'] = array_keys($group_fields);
 
-  foreach ($fields as $field_name => $group_field) {
+  foreach ($group_fields as $field_name => $field) {
     if (empty($form[$group_name][$delta])) {
       $form[$group_name] += array($delta => array($field_name => array()));
     }
@@ -631,19 +639,13 @@
       $form[$group_name][$delta][$field_name] = array();
     }
 
+    $weight_delta = (isset($form_state['item_count'][$group_name]) ? $form_state['item_count'][$group_name] : $form[$group_name]['#item_count']);
     $form[$group_name][$delta]['_weight'] = array(
       '#type' => 'weight',
-      '#delta' => $delta, // this 'delta' is the 'weight' element's property
+      '#delta' => $weight_delta, // this 'delta' is the 'weight' element's property
       '#default_value' => $delta,
       '#weight' => 100,
     );
-    $form[$group_name][$delta]['_delta'] = array(
-      '#type' => 'hidden',
-      '#value' => $delta,
-    );
-
-
-    $field = $content_fields[$field_name];
 
     // Make each field into a pseudo single value field
     // with the right delta value.
@@ -680,89 +682,86 @@
     }
     $form[$group_name][$delta][$field_name]['#weight'] = $field['widget']['weight'];
 
-    // Add in our validation step, and make sure it preceeds other
-    // processing so we can massage the element back to the normal position.
-    if (empty($form[$group_name][$delta][$field_name]['#element_validate'])) {
-      $form[$group_name][$delta][$field_name]['#element_validate'] = array();
-    }
-    array_unshift($form[$group_name][$delta][$field_name]['#element_validate'], 'content_multigroup_node_item_validate');
+    // By default keep empty items unless all fields in a delta group are empty.
+    // See content_set_empty() and content_multigroup_node_form_validate().
+    $form[$group_name][$delta][$field_name]['_keep_empty'] = array('#type' => 'hidden', '#value' => 1);
   }
 
   // Reset the form '#node' back to its original value.
   $form['#node'] = $node;
-
-  return $form;
 }
 
 /**
- * Swap transposed field/delta values back
- * to their normal positions in the node.
+ * Validation for the whole node group.
  */
-function content_multigroup_node_item_validate($element, &$form_state) {
-  static $weights = array();
+function content_multigroup_node_form_validate($element, &$form_state) {
+  $group_name = $element['#parents'][count($element['#parents']) - 1];
+  $groups = fieldgroup_groups($element['#type_name']);
+  $group = $groups[$group_name];
+  $content_type = content_types($group['type_name']);
+  $group_fields = array_intersect_key($content_type['fields'], $group['fields']);
 
-  //dsm($form_state['values']);
+  // It's very important to use $form_values instead of $element['#value']
+  // here, because $element['#value'] is sometimes missing changes made in
+  // #element_validate processing done by other modules.
   $form_values = $form_state['values'];
-  $field_name = array_pop($element['#parents']);
-  $delta = array_pop($element['#parents']);
-  $group_name = array_pop($element['#parents']);
-
-  // Identify the new delta value for each field.
-
-  // Find the original delta values for this group, save as static value
-  // because the group will acquire and lose values while we process it.
-  if (!array_key_exists($group_name, $weights)) {
-    $items = $form_state['values'][$group_name];
-    $weights[$group_name] = array();
-    foreach ($items as $count => $value) {
-      // Allow for the possibility of matching _weights and missing deltas.
-      $weight = floatval($value['_weight']);
-      $old_delta = intval($value['_delta']);
-      if (empty($weights[$group_name][$weight]) || !in_array($old_delta, $weights[$group_name][$weight])) {
-        $weights[$group_name][$weight][] = $old_delta;
+
+  // Move group data from group->delta->field to field->delta.
+  $group_data = array();
+  $empty_deltas = array();
+  foreach ($form_values[$group_name] as $delta => $items) {
+    if (is_array($items) && isset($items['_weight'])) {
+      // If all fields in the delta group are empty, then we can let the
+      // content module remove them. See content_set_empty().
+      $is_empty = TRUE;
+      foreach ($group_fields as $field_name => $field) {
+        if (!isset($group_data[$field_name])) {
+          $group_data[$field_name] = array();
+        }
+        // If this particular field is empty, we want to keep all fields in
+        // the same delta group, even those that are empty.
+        $function = $field['module'] .'_content_is_empty';
+        if (!$function($items[$field_name], $field)) {
+          $is_empty = FALSE;
+        }
+        $group_data[$field_name][$delta] = array_merge($items[$field_name], array(
+          '_weight' => $items['_weight'],
+          '_keep_empty' => $items[$field_name]['_keep_empty'],
+        ));
+      }
+      if ($is_empty && isset($group_data[$field_name])) {
+        $empty_deltas[] = $delta;
       }
     }
-    ksort($weights[$group_name]);
   }
-  $count = 0;
-  foreach ($weights[$group_name] as $weight => $values) {
-    foreach ($values as $old_delta) {
-      if ($old_delta === $delta) {
-        $delta = $count;
-        //dsm('moving delta values: '.$group_name.'>'.$field_name.'>'.'from '. $old_delta .' to '. $delta);
-        break 2;
+  foreach ($empty_deltas as $delta) {
+    foreach ($group_data as $field_name => $items) {
+      foreach (array_keys($items) as $key) {
+        if ($delta == $key) {
+          $group_data[$field_name][$delta]['_keep_empty'] = 0;
+        }
       }
-      $count++;
     }
   }
-  // We figured out what the new order for the fields is,
-  // so set the value for the new delta.
 
-  // We move these new values back up to the top level of the
-  // node and out of the group so the Content module will find and
-  // save the new values and so they don't get mixed into the
-  // remaining, unaltered, values in the group.
-  array_push($element['#parents'], $field_name);
-  array_push($element['#parents'], $delta);
+  // Move the field values back up to the top level of the node and out of
+  // the group so the Content module will find and save the new values.
+  foreach ($group_data as $field_name => $items) {
+
+    // Sort field items according to drag-n-drop reordering. Deltas are also
+    // rebuilt to start counting from 0 to n. Since all fields in the group
+    // share the same weight, all fields in the same delta remain in sync.
+    usort($items, '_content_sort_items_helper');
+
+    // Move field items back to it's original position on the form.
+    $element_copy = $element;
+    array_pop($element_copy['#parents']);
+    array_push($element_copy['#parents'], $field_name);
+    form_set_value($element_copy, $items, $form_state);
+  }
 
-  // It's very important to use $form_values instead of $element['#value']
-  // here, because $element['#value'] is sometimes missing changes
-  // made in #element_validate processing done by other modules.
-  $value = isset($form_values[$group_name][$delta][$field_name]) ? $form_values[$group_name][$delta][$field_name] : NULL;
-
-  // Fields that use optionwidgets have an extra array level in the value
-  // because of the optionwidgets transposition that forces a delta value
-  // into the result array. This works fine when a delta value is between
-  // the field name and the field value, as in normal nodes, but not when
-  // we reverse the field and the delta, so in this case we need to
-  // promote the nested delta value back up to the field level.
-  if (is_array($value) && content_multigroup_uses_optionwidgets($field_name, $element['#type_name'])) {
-    $value = array_shift($value);
-  }
-
-  //dsm('setting value of '. $field_name.'>'.$delta);
-  //dsm($value);
-  form_set_value($element, $value, $form_state);
+  // Finally, get rid of the group data from the form.
+  form_set_value($element, NULL, $form_state);
 }
 
 /**
@@ -771,7 +770,7 @@
  */
 function content_multigroup_uses_optionwidgets($field_name, $type_name) {
   static $optionwidgets;
-  if (empty($optionwidgets)) {
+  if (!isset($optionwidgets)) {
     $optionwidgets = array(
       'optionwidgets_select',
       'optionwidgets_buttons',
@@ -780,32 +779,19 @@
       'nodereference_select',
       'userreference_buttons',
       'userreference_select',
-      );
+    );
     // Add hook where other widgets that use optionwidgets can announce it.
     $optionwidgets = array_merge($optionwidgets, module_invoke_all('content_multigroup_uses_optionwidgets'));
   }
 
-  $types = content_types($type_name);
-  $fields = $types['fields'];
-  $field = $fields[$field_name];
-  if (in_array($field['widget']['type'], $optionwidgets)) {
+  $content_type = content_types($type_name);
+  if (in_array($content_type['fields'][$field_name]['widget']['type'], $optionwidgets)) {
     return TRUE;
   }
   return FALSE;
 }
 
 /**
- * Validation for the whole node group.
- */
-function content_multigroup_node_form_validate($element, $form_state) {
-  // We moved all the new field values out of the field group
-  // and up to the top level of the node, now get rid of the
-  // original group values.
-  form_set_value($element, NULL, $form_state);
-  return;
-}
-
-/**
  * Implementation of hook_fieldgroup_view().
  */
 function content_multigroup_fieldgroup_view(&$node, &$element, $group, $context) {
@@ -815,69 +801,74 @@
 
   $group_name = $group['group_name'];
   $node_copy = drupal_clone($node);
-  $max = $group['settings']['multigroup']['multiple'];
-
-  $count = 0;
-  foreach ($group['fields'] as $field_name => $field) {
-    $count = max($count, count($node->$field_name));
-  }
 
-  $group['multiple'] = isset($group['settings']['multigroup']['multiple']) ? $group['settings']['multigroup']['multiple'] : 1;
+  $group_multiple = $group['settings']['multigroup']['multiple'];
   $labels = isset($group['settings']['multigroup']['labels']) ? $group['settings']['multigroup']['labels'] : array();
-  $format = isset($group['settings']['multigroup']['display_settings'][$context]['format']) ? $group['settings']['multigroup']['display_settings'][$context]['format'] : 'fieldset';
-  $show_label = isset($group['settings']['multigroup']['display_settings']['label']) ? $group['settings']['multigroup']['display_settings']['label'] : 'above';
+  $format = isset($group['settings']['display'][$context]['format']) ? $group['settings']['display'][$context]['format'] : 'fieldset';
+  $show_label = isset($group['settings']['display']['label']) ? $group['settings']['display']['label'] : 'above';
+  $group_field_names = array_keys($group['fields']);
 
-  switch ($group['multiple']) {
+  switch ($group_multiple) {
     case 0:
-      $max = 0;
+      $group_deltas = array(0);
       break;
+
     case 1:
-      $max = $count;
+      // Compute deltas based on the field with the highest number of items.
+      $group_deltas = array();
+      $max_delta = -1;
+      foreach ($group_field_names as $field_name) {
+        $field_deltas = is_array($node->content[$field_name]['field']['items']) ? array_keys($node->content[$field_name]['field']['items']) : array();
+        $field_max = (!empty($field_deltas) ? max($field_deltas) : 0);
+        if ($field_max > $max_delta) {
+          $max_delta = $field_max;
+          $group_deltas = $field_deltas;
+        }
+      }
       break;
+
     default:
-      $max = $group['multiple'];
+      $group_deltas = array_keys(array_fill(0, $group_multiple - 1, 0));
       break;
   }
 
-  for ($delta = 0; $delta < $max; $delta++) {
-    $element[$delta] = array('#weight' => $delta);
-
-    $label = !empty($labels[$delta]) && $show_label == 'above' ? $labels[$delta] : '';
+  foreach ($group_deltas as $delta) {
+    $element[$delta] = array(
+      '#weight' => $delta,
+      '#title' => !empty($labels[$delta]) && $show_label == 'above' ? $labels[$delta] : '',
+    );
 
-    foreach ($group['fields'] as $field_name => $field) {
+    foreach ($group_field_names as $field_name) {
 
       // Create a pseudo node that only has the value we want
       // in this group and pass it to the formatter.
       if (isset($node->content[$field_name])) {
         $node_copy->content[$field_name]['field']['items'] = array(
           $delta => isset($node->content[$field_name]['field']['items'][$delta]) ? $node->content[$field_name]['field']['items'][$delta] : NULL,
-          );
+        );
         $element[$delta][$field_name] = $node_copy->content[$field_name];
         $element[$delta][$field_name]['#delta'] = $delta;
       }
     }
+
     switch ($format) {
       case 'table':
         $element[$delta]['#theme'] = 'content_multigroup_display_table';
-        $element[$delta]['#title'] = $label;
         break;
       case 'fieldset':
         $element[$delta]['#type'] = 'fieldset';
-        $element[$delta]['#title'] = $label;
         break;
       case 'hr':
         $element[$delta]['#theme'] = 'content_multigroup_display_hr';
-        $element[$delta]['#title'] = $label;
         break;
       default:
         $element[$delta]['#theme'] = 'content_multigroup_display_simple';
-        $element[$delta]['#title'] = $label;
         break;
     }
 
   }
 
-  foreach ($group['fields'] as $field_name => $field) {
+  foreach ($group_field_names as $field_name) {
     if (isset($element[$field_name])) {
       unset($element[$field_name]);
     }
@@ -890,11 +881,18 @@
  * Combine multiple values into a table with drag-n-drop reordering.
  */
 function theme_content_multigroup_node_form($element) {
+  $groups = fieldgroup_groups($element['#type_name']);
+  $group_name = $element['#group_name'];
+  $group = $groups[$group_name];
+  $group_multiple = $group['settings']['multigroup']['multiple'];
   $output = '';
-  if ($element['#multiple'] >= 1) {
+
+  if ($group_multiple >= 1) {
     $table_id = $element['#group_name'] .'_values';
     $order_class = $element['#group_name'] .'-delta-order';
 
+    $labels = isset($group['settings']['multigroup']['labels']) ? $group['settings']['multigroup']['labels'] : array();
+
     $header = array(
       array(
         'data' => '',
@@ -903,14 +901,10 @@
       t('Order'),
     );
     $rows = array();
-    $groups = fieldgroup_groups($element['#type_name']);
-    $group = $groups[$element['#group_name']];
-    $labels = isset($group['settings']['multigroup']['labels']) ? $group['settings']['multigroup']['labels'] : array();
-    $multiple = isset($group['settings']['multigroup']['multiple']) ? $group['settings']['multigroup']['multiple'] : 1;
 
     $i = 0;
     foreach (element_children($element) as $delta => $key) {
-      if ($key !== $element['#group_name'] .'_add_more') {
+      if ($key !== $group_name .'_add_more') {
         $label = !empty($labels[$i]) ? theme('content_multigroup_node_label', $labels[$i]) : '';
         $element[$key]['_weight']['#attributes']['class'] = $order_class;
         $delta_element = drupal_render($element[$key]['_weight']);
@@ -933,7 +927,7 @@
 
     $output .= theme('table', $header, $rows, array('id' => $table_id, 'class' => 'content-multiple-table'));
     $output .= $element['#description'] ? '<div class="description">'. $element['#description'] .'</div>' : '';
-    $output .= drupal_render($element[$element['#group_name'] .'_add_more']);
+    $output .= drupal_render($element[$group_name .'_add_more']);
 
     drupal_add_tabledrag($table_id, 'order', 'sibling', $order_class);
   }
@@ -946,47 +940,46 @@
   return $output;
 }
 
+/**
+ * Add AHAH add more button, if not working with a programmed form.
+ */
 function content_multigroup_add_more(&$form, &$form_state, $group) {
-  // Add AHAH add more button, if not working with a programmed form.
-  $multiple = $group['settings']['multigroup']['multiple'];
-  $form_element = array();
-  if ($multiple != 1 || !empty($form['#programmed'])) {
-    return $form_element;
+  $group_multiple = $group['settings']['multigroup']['multiple'];
+  if ($group_multiple != 1 || !empty($form['#programmed'])) {
+    return FALSE;
   }
-  else {
-    // Make sure the form is cached so ahah can work.
-    $form['#cache'] = TRUE;
-    $content_type = content_types($group['type_name']);
-    $group_name = $group['group_name'];
-    $group_name_css = str_replace('_', '-', $group_name);
-
-    $form_element[$group_name .'_add_more'] = array(
-      '#type' => 'submit',
-      '#name' => $group_name .'_add_more',
-      '#value' => t('Add more values'),
-      '#weight' => $multiple + 1,
-      // 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_multigroup_add_more_submit_proxy'),
-      '#ahah' => array(
-        'path' => 'content_multigroup/js_add_more/'. $content_type['url_str'] .'/'. $group_name,
-        'wrapper' => $group_name_css .'-items',
-        'method' => 'replace',
-        'effect' => 'fade',
-      ),
-      // When JS is disabled, the content_add_more_submit handler will find
-      // the relevant field using these entries.
-      '#group_name' => $group_name,
-      '#type_name' => $group['type_name'],
-    );
 
-    // Add wrappers for the group and 'more' button.
-    // TODO: could be simplified ?
-    $form_element['#prefix'] = '<div class="clear-block" id="'. $group_name_css .'-add-more-wrapper"><div id="'. $group_name_css .'-items">';
-    $form_element[$group_name .'_add_more']['#prefix'] = '<div class="content-add-more">';
-    $form_element[$group_name .'_add_more']['#suffix'] =  '</div></div></div>';
-  }
+  // Make sure the form is cached so ahah can work.
+  $form['#cache'] = TRUE;
+  $content_type = content_types($group['type_name']);
+  $group_name = $group['group_name'];
+  $group_name_css = str_replace('_', '-', $group_name);
+
+  $form_element = array();
+  $form_element[$group_name .'_add_more'] = array(
+    '#type' => 'submit',
+    '#name' => $group_name .'_add_more',
+    '#value' => t('Add more values'),
+    '#weight' => $group_multiple + 1,
+    '#submit' => array('content_multigroup_add_more_submit'),
+    '#ahah' => array(
+      'path' => 'content_multigroup/js_add_more/'. $content_type['url_str'] .'/'. $group_name,
+      'wrapper' => $group_name_css .'-items',
+      'method' => 'replace',
+      'effect' => 'fade',
+    ),
+    // When JS is disabled, the content_multigroup_add_more_submit handler will
+    // find the relevant field using these entries.
+    '#group_name' => $group_name,
+    '#type_name' => $group['type_name'],
+  );
+
+  // Add wrappers for the group and 'more' button.
+  // TODO: could be simplified ?
+  $form_element['#prefix'] = '<div class="clear-block" id="'. $group_name_css .'-add-more-wrapper"><div id="'. $group_name_css .'-items">';
+  $form_element[$group_name .'_add_more']['#prefix'] = '<div class="content-add-more">';
+  $form_element[$group_name .'_add_more']['#suffix'] =  '</div></div></div>';
+
   return $form_element;
 }
 
@@ -1013,12 +1006,11 @@
  * Adapted from content_add_more_js to work with groups instead of fields.
  */
 function content_multigroup_add_more_js($type_name_url, $group_name) {
-  $type = content_types($type_name_url);
-  $groups = fieldgroup_groups($type['type']);
+  $content_type = content_types($type_name_url);
+  $groups = fieldgroup_groups($content_type['type']);
   $group = $groups[$group_name];
-  $group['multiple'] = $group['settings']['multigroup']['multiple'];
 
-  if (($group['multiple'] != 1) || empty($_POST['form_build_id'])) {
+  if (($group['settings']['multigroup']['multiple'] != 1) || empty($_POST['form_build_id'])) {
     // Invalid request.
     drupal_json(array('data' => ''));
     exit;
@@ -1059,17 +1051,23 @@
   unset($form_state['values'][$group_name][$group['group_name'] .'_add_more']);
   foreach ($_POST[$group_name] as $delta => $item) {
     $form_state['values'][$group_name][$delta]['_weight'] = $item['_weight'];
-    $form_state['values'][$group_name][$delta]['_delta'] = $item['_delta'];
   }
+  $group['multiple'] = $group['settings']['multigroup']['multiple'];
   $form_state['values'][$group_name] = _content_sort_items($group, $form_state['values'][$group_name]);
   $_POST[$group_name] = _content_sort_items($group, $_POST[$group_name]);
 
   // Build our new form element for the whole group, asking for one more element.
-
-  $form_state['item_count'] = array($group_name => count($_POST[$group_name]) + 1);
   $delta = max(array_keys($_POST[$group_name])) + 1;
+  $form_state['item_count'] = array($group_name => count($_POST[$group_name]) + 1);
   content_multigroup_group_form($form, $form_state, $group, $delta);
 
+  // Rebuild weight deltas to make sure they all are equally dimensioned.
+  foreach ($form[$group_name] as $key => $item) {
+    if (is_numeric($key) && isset($item['_weight']) && is_array($item['_weight'])) {
+      $form[$group_name][$key]['_weight']['#delta'] = $delta;
+    }
+  }
+
   // Save the new definition of the form.
   $form_state['values'] = array();
   form_set_cache($form_build_id, $form, $form_state);
@@ -1086,7 +1084,6 @@
 
   // Render the new output.
   $group_form = $form[$group_name];
-
   // We add a div around the new content to receive the ahah effect.
   $group_form[$delta]['#prefix'] = '<div class="ahah-new-content">'. (isset($group_form[$delta]['#prefix']) ? $group_form[$delta]['#prefix'] : '');
   $group_form[$delta]['#suffix'] = (isset($group_form[$delta]['#suffix']) ? $group_form[$delta]['#suffix'] : '') .'</div>';
@@ -1147,4 +1144,4 @@
     $output .= drupal_render($element[$key]);
   }
   return $output;
-}
\ No newline at end of file
+}

