### Eclipse Workspace Patch 1.0
#P CCK 6.x
Index: modules/optionwidgets/optionwidgets.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/cck/modules/optionwidgets/optionwidgets.module,v
retrieving revision 1.69.2.14
diff -u -r1.69.2.14 optionwidgets.module
--- modules/optionwidgets/optionwidgets.module	6 Sep 2008 15:54:34 -0000	1.69.2.14
+++ modules/optionwidgets/optionwidgets.module	9 Sep 2008 17:36:55 -0000
@@ -12,10 +12,11 @@
 function optionwidgets_form_alter(&$form, $form_state, $form_id) {
   // Provide additional help for the field settings form.
   if ($form_id == 'content_field_edit_form' && isset($form['widget'])) {
-    $widget_type = $form['main']['widget_type']['#default_value'];
-    $field_type = $form['main']['type']['#value'];
+    $widget_type = $form['#field']['widget']['type'];
+    $field_type = $form['#field']['type'];
+    $label = $form['#field']['widget']['label'];
 
-    $output = '<p>'. t('Create a list of options as a list in <strong>Allowed values list</strong> or as an array in PHP code. These values will be the same for %field in all content types.', array('%field' => $form['main']['label']['#value'])) .'</p>';
+    $output = '<p>'. t('Create a list of options as a list in <strong>Allowed values list</strong> or as an array in PHP code. These values will be the same for %field in all content types.', array('%field' => $label)) .'</p>';
 
     if ($widget_type == 'optionwidgets_onoff') {
       $output .= '<p>'. t("For a 'single on/off checkbox' widget, define the 'off' value first, then the 'on' value in the <strong>Allowed values</strong> section. Note that the checkbox will be labeled with the label of the 'on' value.") .'</p>';
Index: theme/content.css
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/cck/theme/content.css,v
retrieving revision 1.12.2.3
diff -u -r1.12.2.3 content.css
--- theme/content.css	22 Aug 2008 22:10:57 -0000	1.12.2.3
+++ theme/content.css	9 Sep 2008 17:36:55 -0000
@@ -51,14 +51,34 @@
 }
 
 /* 'Manage fields' overview */
-table.content-field-overview, table.content-field-overview fieldset table {
-  width:100%;
+#content-field-overview-form .advanced-help-link,
+#content-display-overview-form .advanced-help-link {
+  margin: 4px 4px 0 0;
 }
-table.content-field-overview td {
-  width:14%;
+#content-field-overview-form .label-group,
+#content-display-overview-form .label-group {
+  font-weight: bold;
 }
-.content-field-overview-empty {
-  text-align:center;
+table#content-field-overview tr.content-add-new .tabledrag-changed {
+  display: none;
+}
+table#content-field-overview tr.content-add-new .description {
+  margin-bottom: 0;
+}
+table#content-field-overview .label-wrapper {
+  float: left;
+}
+table#content-field-overview .content-new {
+  font-weight: bold;
+  padding-bottom: .5em;
+}
+
+/* 'Advanced help' pages */
+.advanced-help-topic dt {
+  font-weight: bold;
+}
+.advanced-help-topic dd {
+  margin-bottom: 1em;
 }
 
 
Index: modules/fieldgroup/fieldgroup.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/cck/modules/fieldgroup/fieldgroup.module,v
retrieving revision 1.79.2.19
diff -u -r1.79.2.19 fieldgroup.module
--- modules/fieldgroup/fieldgroup.module	9 Sep 2008 15:39:43 -0000	1.79.2.19
+++ modules/fieldgroup/fieldgroup.module	9 Sep 2008 17:36:54 -0000
@@ -25,18 +25,10 @@
       $type_name = $type->type;
       $content_type = content_types($type_name);
       $type_url_str = $content_type['url_str'];
-      $items['admin/content/node-type/'. $type_url_str .'/add_group'] = array(
-        'title' => 'Add group',
-        'page callback' => 'drupal_get_form',
-        'page arguments' => array('fieldgroup_group_edit_form', $type_name, '', 'add'),
-        'access arguments' => array('administer content types'),
-        'type' => MENU_LOCAL_TASK,
-        'weight' => 3,
-      );
       $items['admin/content/node-type/'. $type_url_str .'/groups/%'] = array(
         'title' => 'Edit group',
         'page callback' => 'drupal_get_form',
-        'page arguments' => array('fieldgroup_group_edit_form', $type_name, 5, 'edit'),
+        'page arguments' => array('fieldgroup_group_edit_form', $type_name, 5),
         'access arguments' => array('administer content types'),
         'type' => MENU_CALLBACK,
       );
@@ -92,27 +84,11 @@
   cache_clear_all('fieldgroup_data', content_cache_tablename());
 }
 
-function fieldgroup_group_edit_form(&$form_state, $type_name, $group_name, $action) {
+function fieldgroup_group_edit_form(&$form_state, $type_name, $group_name) {
   $content_type = content_types($type_name);
   $groups = fieldgroup_groups($content_type['type']);
 
-  if ($action == 'add') {
-    //adding a new one
-    $group = array();
-    $form['submit'] = array(
-      '#type' => 'submit',
-      '#value' => t('Add'),
-      '#weight' => 10,
-    );
-  }
-  elseif ($group = $groups[$group_name]) {
-    $form['submit'] = array(
-      '#type' => 'submit',
-      '#value' => t('Save'),
-      '#weight' => 10,
-    );
-  }
-  else {
+  if (!$group = $groups[$group_name]) {
     drupal_not_found();
     exit;
   }
@@ -120,7 +96,7 @@
   $form['label'] = array(
     '#type' => 'textfield',
     '#title' => t('Label'),
-    '#default_value' => isset($group['label']) ? $group['label'] : '',
+    '#default_value' => $group['label'],
     '#required' => TRUE,
   );
   $form['settings']['#tree'] = TRUE;
@@ -132,7 +108,7 @@
   $form['settings']['form']['style'] = array(
     '#type' => 'radios',
     '#title' => t('Style'),
-    '#default_value' => isset($group['settings']['form']['style']) ? $group['settings']['form']['style'] : 'fieldset',
+    '#default_value' => $group['settings']['form']['style'],
     '#options' => array(
       'fieldset' => t('always open'),
       'fieldset_collapsible' => t('collapsible'),
@@ -142,7 +118,7 @@
   $form['settings']['form']['description'] = array(
     '#type' => 'textarea',
     '#title' => t('Help text'),
-    '#default_value' => isset($group['settings']['form']['description']) ? $group['settings']['form']['description'] : '',
+    '#default_value' => $group['settings']['form']['description'],
     '#rows' => 5,
     '#description' => t('Instructions to present to the user on the editing form.'),
     '#required' => FALSE,
@@ -155,27 +131,31 @@
   $form['settings']['display']['description'] = array(
     '#type' => 'textarea',
     '#title' => t('Description'),
-    '#default_value' => isset($group['settings']['display']['description']) ? $group['settings']['display']['description'] : '',
+    '#default_value' => $group['settings']['display']['description'],
     '#rows' => 5,
     '#description' => t('A description of the group.'),
     '#required' => FALSE,
   );
   module_load_include('inc', 'content', 'includes/content.admin');
   foreach (array_merge(array_keys(_content_admin_display_contexts(CONTENT_CONTEXTS_SIMPLE)), array('label')) as $key) {
-    $default = ($key == 'label') ? 'above' : array('format' => 'fieldset');
-    $form['settings']['display'][$key] = array('#type' => 'value', '#value' => isset($group['settings']['display'][$key]) ? $group['settings']['display'][$key] : $default);
+    $form['settings']['display'][$key] = array('#type' => 'value', '#value' => $group['settings']['display'][$key]);
   }
-  $form['weight'] = array('#type' => 'hidden', '#default_value' => isset($group['weight']) ? $group['weight'] : 0);
+  $form['weight'] = array('#type' => 'hidden', '#default_value' => $group['weight']);
   $form['group_name'] = array('#type' => 'hidden', '#default_value' => $group_name);
 
   $form['#content_type'] = $content_type;
-  $form['#group_action'] = $action;
+
+  $form['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Save'),
+    '#weight' => 10,
+  );
 
   return $form;
 }
 
 /**
- *  Group name validation for programmatic group addition.
+ * Group name validation for programmatic group addition.
  *
  * @todo
  * Come back here and do the same thing for groups as we've done for fields,
@@ -185,22 +165,23 @@
 function fieldgroup_group_edit_form_validate($form, &$form_state) {
   $form_values = $form_state['values'];
   $content_type = $form['#content_type'];
-  $action = $form['#group_action'];
-
-  if (!empty($form_values['group_name']) && $action == 'add') {
 
-    $groups = fieldgroup_groups($content_type['type']);
-    $group = $groups[$form_values['group_name']];
-
-    if (isset($group[$form_values['group_name']])) {
-      form_set_error('group_name', t('The group name %name already exists.', array(
-        '%group_name' => $form_values['group_name'])));
-    }
-    if (!preg_match('!^[a-z0-9_]+$!', $form_values['group_name'])) {
-      form_set_error('group_name', t('The group name %name is invalid.', array(
-        '%group_name' => $form_values['group_name'])));
-    }
-  }
+  // TODO : integrate this in overview_validate
+//  $action = $form['#group_action'];
+//  if (!empty($form_values['group_name']) && $action == 'add') {
+//
+//    $groups = fieldgroup_groups($content_type['type']);
+//    $group = $groups[$form_values['group_name']];
+//
+//    if (isset($group[$form_values['group_name']])) {
+//      form_set_error('group_name', t('The group name %name already exists.', array(
+//        '%group_name' => $form_values['group_name'])));
+//    }
+//    if (!preg_match('!^[a-z0-9_]+$!', $form_values['group_name'])) {
+//      form_set_error('group_name', t('The group name %name is invalid.', array(
+//        '%group_name' => $form_values['group_name'])));
+//    }
+//  }
 }
 
 function fieldgroup_group_edit_form_submit($form, &$form_state) {
@@ -345,7 +326,8 @@
       '#value' => _fieldgroup_field_get_group($content_type['type'], $form['field_name']['#value']),
     );
   }
-  elseif ($form_id == 'content_field_overview_form' && !empty($form['#groups'])) {
+  elseif ($form_id == 'content_field_overview_form') {
+    $form['#validate'][] = 'fieldgroup_field_overview_form_validate';
     $form['#submit'][] = 'fieldgroup_field_overview_form_submit';
   }
   elseif ($form_id == 'content_display_overview_form' && !empty($form['#groups'])) {
@@ -359,16 +341,61 @@
   }
 }
 
+function fieldgroup_field_overview_form_validate($form, &$form_state) {
+  $form_values = $form_state['values'];
+  $group = $form_values['_add_new_group'];
+
+  // Fail validation if attempt to nest fields under a new group without a label.
+  if (!$group['label']) {
+    foreach ($form_values as $key => $values) {
+      if ($values['parent'] == '_add_new_group') {
+        form_set_error('_add_new_group][label', t('Add new group: you need to provide a label.'));
+        break;
+      }
+    }
+  }
+}
+
 function fieldgroup_field_overview_form_submit($form, &$form_state) {
   $form_values = $form_state['values'];
   $type_name = $form['#type_name'];
+
+  // Create new group if needed.
+  if (!empty($form_values['_add_new_group']['label'])) {
+    $group = $form_values['_add_new_group'];
+    $group['settings'] = _field_group_default_settings();
+    $new_group_name = fieldgroup_save_group($type_name, $group);
+  }
+
+  // Parse incoming rows.
+  $add_field_rows = array('_add_new_field', '_add_existing_field');
+  $field_rows = array_merge($form['#fields'], $add_field_rows);
   foreach ($form_values as $key => $values) {
-    // Update field parenting.
-    if (in_array($key, $form['#fields'])) {
+    // If 'field' row: update field parenting.
+    if (in_array($key, $field_rows)) {
+      // If newly added fields were added to a group:
+      if (in_array($key, $add_field_rows)) {
+        // We replace the '_add_*_field' key with the actual name of
+        // the field that got added.
+        // content_field_overview_form_submit() placed those
+        // in $form_state['fields_added'] for us.
+        if (isset($form_state['fields_added'][$key])) {
+          $key = $form_state['fields_added'][$key];
+        }
+        else {
+          // No field was actually created : skip to next row.
+          continue;
+        }
+      }
+      // If the field was added to the newly created group, replace the
+      // '_add_new_group' value with the actual name of the group.
+      $parent = ($values['parent'] == '_add_new_group' && isset($new_group_name)) ? $new_group_name : $values['parent'];
       // TODO: check the parent group does exist ?
-      fieldgroup_update_fields(array('field_name' => $key, 'group' => $values['parent'], 'type_name' => $type_name));
+      fieldgroup_update_fields(array('field_name' => $key, 'group' => $parent, 'type_name' => $type_name));
     }
-    // Update groups weights.
+
+    // If 'group' row:  update groups weights
+    // (possible newly created group has already been taken care of).
     elseif (in_array($key, $form['#groups'])) {
       db_query("UPDATE {". fieldgroup_tablename() ."} SET weight = %d WHERE type_name = '%s' AND group_name = '%s'",
         $values['weight'], $type_name, $key);
@@ -378,6 +405,18 @@
   cache_clear_all('fieldgroup_data', content_cache_tablename());
 }
 
+function _field_group_default_settings() {
+  $settings = array(
+    'form' => array('style' => 'fieldset', 'description' => ''),
+    'display' => array('description' => '', 'label' => 'above'),
+  );
+  module_load_include('inc', 'content', 'includes/content.admin');
+  foreach (array_keys(_content_admin_display_contexts(CONTENT_CONTEXTS_SIMPLE)) as $key) {
+    $settings['display'][$key]['format'] = 'fieldset';
+  }
+  return $settings;
+}
+
 function fieldgroup_display_overview_form_submit($form, &$form_state) {
   $form_values = $form_state['values'];
   $groups = fieldgroup_groups($form['#type_name']);
@@ -520,7 +559,7 @@
 function fieldgroup_save_group($type_name, $group) {
   $groups = fieldgroup_groups($type_name);
 
-  if (!isset($groups[$group['group_name']])) {
+  if (!isset($group['group_name']) || !isset($groups[$group['group_name']])) {
     // Accept group name from programmed submissions if valid.
     if (!empty($group['group_name'])) {
       $group_name = $group['group_name'];
@@ -544,14 +583,15 @@
     db_query("INSERT INTO {". fieldgroup_tablename() ."} (type_name, group_name, label, settings, weight)
              VALUES ('%s', '%s', '%s', '%s', %d)", $type_name, $group_name, $group['label'], serialize($group['settings']), $group['weight']);
     cache_clear_all('fieldgroup_data', content_cache_tablename());
-    return SAVED_NEW;
+    return $group_name;
   }
   else {
+    $group_name = $group['group_name'];
     db_query("UPDATE {". fieldgroup_tablename() ."} SET label = '%s', settings = '%s', weight = %d ".
              "WHERE type_name = '%s' AND group_name = '%s'",
-             $group['label'], serialize($group['settings']), $group['weight'], $type_name, $group['group_name']);
+             $group['label'], serialize($group['settings']), $group['weight'], $type_name, $group_name);
     cache_clear_all('fieldgroup_data', content_cache_tablename());
-    return SAVED_UPDATED;
+    return $group_name;
   }
 }
 
Index: includes/content.admin.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/cck/includes/content.admin.inc,v
retrieving revision 1.181.2.36
diff -u -r1.181.2.36 content.admin.inc
--- includes/content.admin.inc	6 Sep 2008 16:51:37 -0000	1.181.2.36
+++ includes/content.admin.inc	9 Sep 2008 17:36:54 -0000
@@ -30,7 +30,6 @@
       $row[] = array('data' => l(t('edit'), 'admin/content/node-type/'. $type_url_str));
       // Set links for managing fields.
       // TODO: a hook to allow other content modules to add more stuff?
-      $row[] = array('data' => l(t('add field'), 'admin/content/node-type/'. $type_url_str .'/add_field'));
       $row[] = array('data' => l(t('manage fields'), 'admin/content/node-type/'. $type_url_str .'/fields'));
       // Set the delete column.
       if ($type->custom) {
@@ -100,7 +99,7 @@
  * JS drag-n-drop. Non-CCK form elements can also be moved around.
  */
 function content_field_overview_form(&$form_state, $type_name) {
-  // When displaying the form, make sure the list of 'extra' fields
+  // When displaying the form, make sure the list of fields
   // is up-to-date.
   if (empty($form_state['post'])) {
     content_clear_type_cache();
@@ -111,22 +110,18 @@
   $fields = $type['fields'];
   $field_types = _content_field_types();
 
-  if (empty($fields) && empty($form_state['post'])) {
-    drupal_set_message(t('There are no fields configured for this content type. You can !link.', array(
-      '!link' => l(t('Add a new field'), str_replace('/fields', '/add_field', $_GET['q'])))), 'warning');
-  }
-
   $extra = $type['extra'];
   $groups = $group_options = array();
   if (module_exists('fieldgroup')) {
     $groups = fieldgroup_groups($type['type']);
     $group_options = _fieldgroup_groups_label($type['type']);
+    // Add the ability to group under the newly created row.
+    $group_options['_add_new_group'] = '_add_new_group';
   }
 
-  // Rows in this table are essentially nested, but for the simplicity of
-  // theme and submit functions, we keep them in a flat array, and use a
-  // $dummy render structure to figure the right display order.
-  $dummy = array();
+  // Store the default weights as we meet them, to be able to put the
+  //'add new' rows after them.
+  $weights = array();
 
   $form = array(
     '#tree' => TRUE,
@@ -134,136 +129,284 @@
     '#fields' => array_keys($fields),
     '#groups' => array_keys($groups),
     '#extra' => array_keys($extra),
+    '#field_rows' => array(),
+    '#group_rows' => array(),
     '#order' => array(),
-    '#prefix' => '<p>'. t('To change the order of a field, grab a drag-and-drop handle under the Label column and drag the field to a new location in the list. (Grab a handle by clicking and holding the mouse while hovering over a handle icon.) Remember that your changes will not be saved until you click the Save button at the bottom of the page.') .'</p>',
   );
 
   // Fields.
   foreach ($fields as $name => $field) {
     $weight = $field['widget']['weight'];
     $form[$name] = array(
-      'human_name' => array('#value' => check_plain($field['widget']['label'])),
-      'name' => array('#value' => $field['field_name']),
+      'label' => array('#value' => check_plain($field['widget']['label'])),
+      'field_name' => array('#value' => $field['field_name']),
       'type' => array('#value' => t($field_types[$field['type']]['label'])),
       'configure' => array('#value' => l(t('Configure'), 'admin/content/node-type/'. $type['url_str'] .'/fields/'. $field['field_name'])),
       'remove' => array('#value' => l(t('Remove'), 'admin/content/node-type/'. $type['url_str'] .'/fields/'. $field['field_name'] .'/remove')),
-      'weight' => array('#type' => 'textfield', '#default_value' => $weight),
+      'weight' => array('#type' => 'textfield', '#default_value' => $weight, '#size' => 3),
       'parent' => array('#type' => 'select', '#options' => $group_options, '#default_value' => ''),
       'hidden_name' => array('#type' => 'hidden', '#default_value' => $field['field_name']),
       '#leaf' => TRUE,
+      '#row_type' => 'field',
     );
-    $dummy[$name] = array('#weight' => $weight, '#value' => $name .' ');
     if ($field['locked']) {
       $form[$name]['configure'] = array('#value' => t('Locked'));
       $form[$name]['remove'] = array();
       $form[$name]['#disabled_row'] = true;
     }
+    $form['#field_rows'][] = $name;
+    $weights[] = $weight;
   }
 
   // Groups.
   foreach ($groups as $name => $group) {
     $weight = $group['weight'];
     $form[$name] = array(
-      'human_name' => array('#value' => check_plain($group['label'])),
-      'name' => array('#value' => $group['group_name']),
-      'type' => array(),
+      'label' => array('#value' => check_plain($group['label'])),
+      'group_name' => array('#value' => $group['group_name']),
       'configure' => array('#value' => l(t('Configure'), 'admin/content/node-type/'. $type['url_str'] .'/groups/'. $group['group_name'])),
       'remove' => array('#value' => l(t('Remove'), 'admin/content/node-type/'. $type['url_str'] .'/groups/'. $group['group_name'] .'/remove')),
-      'weight' => array('#type' => 'textfield', '#default_value' => $weight),
+      'weight' => array('#type' => 'textfield', '#default_value' => $weight, '#size' => 3),
       'parent' => array('#type' => 'hidden', '#default_value' => ''),
       'hidden_name' => array('#type' => 'hidden', '#default_value' => $group['group_name']),
       '#root' => TRUE,
+      '#row_type' => 'group',
     );
-    $dummy[$name] = array('#weight' => $weight, '#value' => $name .' ');
     // Adjust child fields rows.
     foreach ($group['fields'] as $field_name => $field) {
-      $form[$field_name]['#depth'] = 1;
       $form[$field_name]['parent']['#default_value'] = $name;
-      $dummy[$name][$field_name] = $dummy[$field_name];
-      unset($dummy[$field_name]);
     }
+    $form['#group_rows'][] = $name;
+    $weights[] = $weight;
   }
 
   // Non-CCK 'fields'.
   foreach ($extra as $name => $label) {
     $weight = $extra[$name]['weight'];
     $form[$name] = array(
-      'human_name' => array('#value' => t($extra[$name]['label'])),
-      'name' => array('#value' => isset($extra[$name]['description']) ? $extra[$name]['description'] : ''),
-      'type' => array(),
-      'configure' => array(),
-      'remove' => array(),
-      'weight' => array('#type' => 'textfield', '#default_value' => $weight),
+      'label' => array('#value' => t($extra[$name]['label'])),
+      'description' => array('#value' => isset($extra[$name]['description']) ? $extra[$name]['description'] : ''),
+      'weight' => array('#type' => 'textfield', '#default_value' => $weight, '#size' => 3),
       'parent' => array('#type' => 'hidden', '#default_value' => ''),
       'hidden_name' => array('#type' => 'hidden', '#default_value' => $name),
       '#leaf' => TRUE,
       '#root' => TRUE,
       '#disabled_row' => TRUE,
-      '#extra_field' => TRUE,
+      '#row_type' => 'extra',
+    );
+    $form['#field_rows'][] = $name;
+    $weights[] = $weight;
+  }
+
+  // Additional row : add new field.
+  $weight = max($weights) + 1;
+  $field_type_options = content_field_type_options();
+  $widget_type_options = content_widget_type_options(NULL, TRUE);
+  array_unshift($field_type_options, t('- Select a field type -'));
+  array_unshift($widget_type_options, t('- Select a widget -'));
+  if ($field_type_options && $widget_type_options) {
+    $name = '_add_new_field';
+    $form[$name] = array(
+      'label' => array(
+        '#type' => 'textfield',
+        '#size' => 15,
+        '#description' => t('Label'),
+      ),
+      'field_name' => array(
+        '#type' => 'textfield',
+        '#field_prefix' => 'field_',
+        '#size' => 15,
+        '#description' => t('Field name (a-z, 0-9, _)'),
+      ),
+      'type' => array(
+        '#type' => 'select',
+        '#options' => $field_type_options,
+        '#description' => t('Type of data to store.'),
+      ),
+      'widget_type' => array(
+        '#type' => 'select',
+        '#options' => $widget_type_options,
+        '#description' => t('Form element to edit the data.'),
+      ),
+      'weight' => array('#type' => 'textfield', '#default_value' => $weight, '#size' => 3),
+      'parent' => array('#type' => 'select', '#options' => $group_options, '#default_value' => ''),
+      'hidden_name' => array('#type' => 'hidden', '#default_value' => $name),
+      '#leaf' => TRUE,
+      '#add_new' => TRUE,
+      '#row_type' => 'add_new_field',
     );
-    $dummy[$name] = array('#weight' => $weight, '#value' => $name .' ');
+    $form['#field_rows'][] = $name;
   }
 
-  // Let drupal_render figure out the right order for the rows.
-  $form['#order'] = explode(' ', trim(drupal_render($dummy)));
+  // Additional row : add existing field.
+  $existing_field_options = content_existing_field_options($type_name);
+  if ($existing_field_options && $widget_type_options) {
+    $weight++;
+    array_unshift($existing_field_options, t('- Select an existing field -'));
+    $name = '_add_existing_field';
+    $form[$name] = array(
+      'label' => array(
+        '#type' => 'textfield',
+        '#size' => 15,
+        '#description' => t('Label'),
+      ),
+      'field_name' => array(
+        '#type' => 'select',
+        '#options' => $existing_field_options,
+        '#description' => t('Field to share'),
+      ),
+      'widget_type' => array(
+        '#type' => 'select',
+        '#options' => $widget_type_options,
+        '#description' => t('Form element to edit the data.'),
+      ),
+      'weight' => array('#type' => 'textfield', '#default_value' => $weight, '#size' => 3),
+      'parent' => array('#type' => 'select', '#options' => $group_options, '#default_value' => ''),
+      'hidden_name' => array('#type' => 'hidden', '#default_value' => $name),
+      '#leaf' => TRUE,
+      '#add_new' => TRUE,
+      '#row_type' => 'add_existing_field',
+    );
+    $form['#field_rows'][] = $name;
+  }
+
+  // Additional row : add new group.
+  if (module_exists('fieldgroup')) {
+    $weight++;
+    $name = '_add_new_group';
+    $form[$name] = array(
+      'label' => array(
+        '#type' => 'textfield',
+        '#size' => 15,
+        '#description' => t('Label'),
+      ),
+      'weight' => array('#type' => 'textfield', '#default_value' => $weight, '#size' => 3),
+      'parent' => array('#type' => 'hidden', '#default_value' => ''),
+      'hidden_name' => array('#type' => 'hidden', '#default_value' => $name),
+      '#root' => TRUE,
+      '#add_new' => TRUE,
+      '#row_type' => 'add_new_group',
+    );
+    $form['#group_rows'][] = $name;
+  }
 
   $form['submit'] = array('#type' => 'submit', '#value' => t('Save'));
   return $form;
 }
 
+function content_field_overview_form_validate($form, &$form_state) {
+  _content_field_overview_form_validate_add_new($form, &$form_state);
+  _content_field_overview_form_validate_add_existing($form, &$form_state);
+}
+
 /**
- * Theme the field overview table.
+ * Helper function for content_field_overview_form_validate.
+ *
+ * Validate the 'add new field' row.
  */
-function theme_content_field_overview_form($form) {
-  if (empty($form['#order'])) {
-    return;
-  }
-  $header = array(t('Label'), t('Weight'), t('Name'), t('Type'), t('Operations'));
-  $rows = array();
+function _content_field_overview_form_validate_add_new($form, &$form_state) {
+  $field = $form_state['values']['_add_new_field'];
 
-  foreach ($form['#order'] as $key) {
-    $row = array();
-    $element = &$form[$key];
-    $element['weight']['#attributes']['class'] = 'field-weight';
-    $element['parent']['#attributes']['class'] = 'group-parent';
-    $element['hidden_name']['#attributes']['class'] = 'field-name';
-    if (in_array($key, $form['#groups'])) {
-      $element['human_name']['#prefix'] = '<strong>';
-      $element['human_name']['#suffix'] = '</strong>';
-    }
-    $row[] = theme('indentation', isset($element['#depth']) ? $element['#depth'] : 0) . drupal_render($element['human_name']);
-    // tabledrag.js cell hiding doesn't work well with colspans in table rows,
-    // so we add the cell to hide *before* the ones with colspans.
-    $row[] = drupal_render($element['weight']) . drupal_render($element['parent']) . drupal_render($element['hidden_name']);
-    if (isset($element['#extra_field'])) {
-      $row[] = array('data' => drupal_render($element['name']), 'colspan' => 3);
+  // Validate if any information was provided in the 'add new field' row.
+  if (array_filter(array($field['label'], $field['field_name'], $field['type'], $field['widget_type']))) {
+    // No label.
+    if (!$field['label']) {
+      form_set_error('_add_new_field][label', t('Add new field: you need to provide a label.'));
     }
-    else {
-      $row[] = drupal_render($element['name']);
-      $row[] = drupal_render($element['type']);
-      $row[] = drupal_render($element['configure']) .'&nbsp;&nbsp;'. drupal_render($element['remove']);
+
+    // No field name.
+    if (!$field['field_name']) {
+      form_set_error('_add_new_field][field_name', t('Add new field: you need to provide a field name.'));
     }
+    // Field name validation.
+    else {
+      $field_name = $field['field_name'];
 
-    $class = 'draggable';
-    $class .= isset($element['#disabled_row']) ? ' menu-disabled' : '';
-    $class .= isset($element['#leaf']) ? ' tabledrag-leaf' : '';
-    $class .= isset($element['#root']) ? ' tabledrag-root' : '';
-    $rows[] = array('data' => $row, 'class' => $class);
-  }
+      // Add the 'field_' prefix.
+      if (substr($field_name, 0, 6) != 'field_') {
+        $field_name = 'field_'. $field_name;
+        form_set_value($form['_add_new_field']['field_name'], $field_name, $form_state);
+      }
 
-  $output  = theme('table', $header, $rows, array('id' => 'content-field-overview'));
+      // Invalid field name.
+      if (!preg_match('!^field_[a-z0-9_]+$!', $field_name)) {
+        form_set_error('_add_new_field][field_name', t('Add new field: the field name %field_name is invalid. The name must include only lowercase unaccentuated letters, numbers, and underscores.', array('%field_name' => $field_name)));
+      }
+      if (strlen($field_name) > 32) {
+        form_set_error('_add_new_field][field_name', t('Add new field: the field name %field_name is too long. The name is limited to 32 characters, including the \'field_\' prefix.', array('%field_name' => $field_name)));
+      }
+      if ($field_name == 'field_instance') {
+        form_set_error('_add_new_field][field_name', t("Add new field: the name 'field_instance' is a reserved name."));
+      }
 
-  drupal_add_tabledrag('content-field-overview', 'match', 'parent', 'group-parent', 'group-parent', 'field-name', TRUE, 1);
-  drupal_add_tabledrag('content-field-overview', 'order', 'sibling', 'field-weight');
+      // Field name already exists.
+      // We need to check inactive fields as well, so we can't use content_fields().
+      module_load_include('inc', 'content', 'includes/content.crud');
+      $fields = content_field_instance_read(array(), TRUE);
+      $used = FALSE;
+      foreach ($fields as $existing_field) {
+        $used |= ($existing_field['field_name'] == $field_name);
+      }
+      if ($used) {
+        form_set_error('_add_new_field][field_name', t('Add new field: the field name %field_name already exists.', array('%field_name' => $field_name)));
+      }
+    }
 
-  // Hide the 'Save' button, show it when fields are swapped.
-  $form['submit']['#attributes']['class'] = 'content-admin-field-overview-submit';
-  drupal_add_js('if (Drupal.jsEnabled) { $(document).ready(function() { $(".content-admin-field-overview-submit").hide(); }); }', 'inline');
-  drupal_add_js(drupal_get_path('module', 'content') .'/content.js');
+    // No field type.
+    if (!$field['type']) {
+      form_set_error('_add_new_field][type', t('Add new field: you need to select a field type.'));
+    }
 
-  $output .= drupal_render($form);
+    // No widget type.
+    if (!$field['widget_type']) {
+      form_set_error('_add_new_field][widget_type', t('Add new field: you need to select a widget.'));
+    }
+    // Wrong widget type.
+    elseif ($field['type']) {
+      $widget_types = content_widget_type_options($field['type']);
+      if (!isset($widget_types[$field['widget_type']])) {
+        form_set_error('_add_new_field][widget_type', t('Add new field: invalid widget.'));
+      }
+    }
+  }
+}
 
-  return $output;
+/**
+ * Helper function for content_field_overview_form_validate.
+ *
+ * Validate the 'add existing field' row.
+ */
+function _content_field_overview_form_validate_add_existing($form, &$form_state) {
+  // The form element might be absent if no existing fields can be added to
+  // this content type
+  if (isset($form_state['values']['_add_existing_field'])) {
+    $field = $form_state['values']['_add_existing_field'];
+
+    // Validate if any information was provided in the 'add existing field' row.
+    if (array_filter(array($field['label'], $field['field_name'], $field['widget_type']))) {
+      // No label.
+      if (!$field['label']) {
+        form_set_error('_add_existing_field][label', t('Add existing field: you need to provide a label.'));
+      }
+
+      // No existing field.
+      if (!$field['field_name']) {
+        form_set_error('_add_existing_field][field_name', t('Add existing field: you need to select a field.'));
+      }
+
+      // No widget type.
+      if (!$field['widget_type']) {
+        form_set_error('_add_existing_field][widget_type', t('Add existing field: you need to select a widget.'));
+      }
+      // Wrong widget type.
+      elseif ($field['field_name'] && ($existing_field = content_fields($field['field_name']))) {
+        $widget_types = content_widget_type_options($existing_field['type']);
+        if (!isset($widget_types[$field['widget_type']])) {
+          form_set_error('_add_existing_field][widget_type', t('Add existing field: invalid widget.'));
+        }
+      }
+    }
+  }
 }
 
 function content_field_overview_form_submit($form, &$form_state) {
@@ -290,6 +433,54 @@
   }
 
   content_clear_type_cache();
+
+  $destinations = array();
+
+  // Create new field.
+  if (!empty($form_values['_add_new_field']['field_name'])) {
+    $field = $form_values['_add_new_field'];
+    $field['type_name'] = $form['#type_name'];
+
+    module_load_include('inc', 'content', 'includes/content.crud');
+    if (content_field_instance_create($field)) {
+      // Store new field information for fieldgroup submit handler.
+      $form_state['fields_added']['_add_new_field'] = $field['field_name'];
+      $destinations[] = 'admin/content/node-type/'. $field['type_name'] .'/fields/'. $field['field_name'];
+    }
+    else {
+      drupal_set_message(t('There was a problem creating field %label.', array(
+        '%label' => $field['label'])));
+    }
+  }
+
+  // Add existing field.
+  if (!empty($form_values['_add_existing_field']['field_name'])) {
+    $field = $form_values['_add_existing_field'];
+    $field['type_name'] = $form['#type_name'];
+    $existing_field = content_fields($field['field_name']);
+
+    if ($existing_field['locked']) {
+      drupal_set_message(t('The field %label cannot be added to a content type because it is locked.', array('%label' => $field['field_name'])));
+    }
+    else {
+      module_load_include('inc', 'content', 'includes/content.crud');
+      if (content_field_instance_create($field)) {
+        // Store new field information for fieldgroup submit handler.
+        $form_state['fields_added']['_add_existing_field'] = $field['field_name'];
+        $destinations[] = 'admin/content/node-type/'. $field['type_name'] .'/fields/'. $field['field_name'];
+      }
+      else {
+        drupal_set_message(t('There was a problem adding field %label.', array('%label' => $field['field_name'])));
+      }
+    }
+  }
+
+  if ($destinations) {
+    $destinations[] = urldecode(substr(drupal_get_destination(), 12));
+    unset($_REQUEST['destination']);
+    $form_state['redirect'] = content_get_destinations($destinations);
+  }
+
 }
 
 /**
@@ -316,11 +507,6 @@
   }
   $contexts = _content_admin_display_contexts($contexts_selector);
 
-  // Rows in this table are essentially nested, but for the simplicity of
-  // theme and submit functions, we keep them in a flat array, and use a
-  // $dummy render structure to figure the right display order.
-  $dummy = array();
-
   $form = array(
     '#tree' => TRUE,
     '#type_name' => $type['type'],
@@ -342,7 +528,9 @@
     $weight = $field['widget']['weight'];
 
     $form[$name] = array(
-      'human_name' => array('#value' => check_plain($field['widget']['label'])), // OK
+      'human_name' => array('#value' => check_plain($field['widget']['label'])),
+      'weight' => array('#type' => 'value', '#value' => $weight),
+      'parent' => array('#type' => 'value', '#value' => ''),
     );
 
     // Label
@@ -367,8 +555,6 @@
         '#default_value' => isset($defaults[$key]['format']) ? $defaults[$key]['format'] : 'default',
       );
     }
-
-    $dummy[$name] = array('#weight' => $weight, '#value' => $name .' ');
   }
 
   // Groups.
@@ -390,6 +576,7 @@
 
     $form[$name] = array(
       'human_name' => array('#value' => check_plain($group['label'])),
+      'weight' => array('#type' => 'value', '#value' => $weight),
     );
     if ($contexts_selector == CONTENT_CONTEXTS_SIMPLE) {
       $form[$name]['label'] = array(
@@ -405,64 +592,16 @@
         '#default_value' => isset($defaults[$key]) ? $defaults[$key] : 'fieldset',
       );
     }
-    $dummy[$name] = array('#weight' => $weight, '#value' => $name .' ');
-    // Adjust child fields rows.
     foreach ($group['fields'] as $field_name => $field) {
-      $form[$field_name]['#depth'] = 1;
-      $dummy[$name][$field_name] = $dummy[$field_name];
-      unset($dummy[$field_name]);
+      $form[$field_name]['parent']['#value'] = $name;
     }
   }
 
-  // Let drupal_render figure out the right order for the rows.
-  $form['#order'] = explode(' ', trim(drupal_render($dummy)));
-
   $form['submit'] = array('#type' => 'submit', '#value' => t('Save'));
   return $form;
 }
 
 /**
- *  Theme the display overview table.
- */
-function theme_content_display_overview_form($form) {
-  $output = '';
-  if (isset($form['#order'])) {
-    $contexts_selector = $form['#contexts'];
-    $contexts = _content_admin_display_contexts($contexts_selector);
-    $header = array(t('Field'));
-    if ($contexts_selector == CONTENT_CONTEXTS_SIMPLE) {
-      $header[] = t('Label');
-    }
-    foreach ($contexts as $key => $title) {
-      $header[] = $title;
-    }
-    $rows = array();
-
-    foreach ($form['#order'] as $key) {
-      $row = array();
-      $element = &$form[$key];
-      if (in_array($key, $form['#groups'])) {
-        $element['human_name']['#prefix'] = '<strong>';
-        $element['human_name']['#suffix'] = '</strong>';
-      }
-      $row[] = theme('indentation', isset($element['#depth']) ? $element['#depth'] : 0) . drupal_render($element['human_name']);
-      if ($contexts_selector == CONTENT_CONTEXTS_SIMPLE) {
-        $row[] = drupal_render($element['label']);
-      }
-      foreach ($contexts as $context => $title) {
-        $row[] = drupal_render($element[$context]['format']);
-      }
-      $rows[] = $row;
-    }
-
-    $output .= theme('table', $header, $rows);
-  }
-
-  $output .= drupal_render($form);
-  return $output;
-}
-
-/**
  * Submit handler for the display overview form.
  */
 function content_display_overview_form_submit($form, &$form_state) {
@@ -483,25 +622,6 @@
 }
 
 /**
- * Menu callback; presents the form for adding a new field.
- */
-function content_field_add($type_name) {
-  // make sure the old field list gets cleared before creating the new one
-  if (!isset($_POST['edit'])) {
-    content_clear_type_cache();
-  }
-  $output = '';
-  $options = content_field_type_options();
-  if (!empty($options)) {
-    $output .= drupal_get_form('content_field_main_form', array('type_name' => $type_name));
-  }
-  else {
-    drupal_set_message(t('No field modules are enabled. You need to <a href="!modules_url">enable one</a>, such as text.module, before you can add new fields.', array('!modules_url' => url('admin/build/modules'))), 'error');
-  }
-  return $output;
-}
-
-/**
  * Return an array of field_type options.
  */
 function content_field_type_options() {
@@ -524,292 +644,151 @@
 
 /**
  * Return an array of widget type options for a field type.
+ *
+ * If no field type is provided, returns a nested array of
+ * all widget types, keyed by field type human name
  */
-function content_widget_type_options($field_type) {
+function content_widget_type_options($field_type = NULL, $by_label = FALSE) {
   static $options;
 
   if (!isset($options)) {
-    $widget_types = _content_widget_types();
     $options = array();
-    foreach ($widget_types as $widget_type_name => $widget_type) {
+    foreach (_content_widget_types() as $widget_type_name => $widget_type) {
       foreach($widget_type['field types'] as $widget_field_type) {
         $options[$widget_field_type][$widget_type_name] = t($widget_type['label']);
       }
     }
   }
 
-  return !empty($options[$field_type]) ? $options[$field_type] : array();
+  if ($field_type) {
+    return !empty($options[$field_type]) ? $options[$field_type] : array();
+  }
+  elseif ($by_label) {
+    $field_types = _content_field_types();
+    $options_by_label = array();
+    foreach ($options as $field_type => $widgets) {
+      $options_by_label[t($field_types[$field_type]['label'])] = $widgets;
+    }
+    return $options_by_label;
+  }
+  else {
+    return $options;
+  }
 }
 
-function content_field_add_existing_form(&$form_state, $type_name) {
-  $output = '';
+/**
+ * Return an array of existing field to be added to a node type.
+ */
+function content_existing_field_options($type_name) {
   $type = content_types($type_name);
   $fields = content_fields();
-  $form = array();
+  $field_types = _content_field_types();
 
   $options = array();
   foreach ($fields as $field) {
     if (!isset($type['fields'][$field['field_name']]) && !$field['locked']) {
-      $options[$field['field_name']] = t($field['widget']['label']) .' ('. $field['field_name'] .')';
+      $field_type = $field_types[$field['type']];
+      $options[$field['field_name']] = t('@type: @label (@field)', array('@type' => t($field_type['label']), '@label' => t($field['widget']['label']), '@field' => $field['field_name']));
     }
   }
-  if ($options) {
-    $form['existing'] = array(
-      '#type' => 'fieldset',
-      '#title' => t('Add existing field'),
-    );
-    $form['existing']['existing_field_name'] = array(
-      '#type' => 'select',
-      '#required' => TRUE,
-      '#options' => $options,
-    );
-    $form['existing']['submit'] = array(
-      '#type' => 'submit',
-      '#value' => t('Add field'),
-    );
-    $form['existing']['type_name'] = array(
-      '#type' => 'value',
-      '#value' => $type_name,
-    );
-  }
-  return $form;
+  return $options;
 }
 
 /**
- * Add an existing field to a content type.
+ * A form element for selecting field, widget, and label.
  */
-function content_field_add_existing_form_submit($form, &$form_state) {
+function content_field_basic_form(&$form_state, $form_values) {
   module_load_include('inc', 'content', 'includes/content.crud');
-  $form_values = $form_state['values'];
-  $form_values['field_name'] = $form_values['existing_field_name'];
-  $field = content_fields($form_values['field_name']);
 
-  if ($field['locked']) {
-    drupal_set_message(t('The field %label cannot be added to a content type because it is locked.',
-                       array('%label' => $form_values['field_name'])));
-    return;
-  }
-
-  if (content_field_instance_create($form_values)) {
-    drupal_set_message(t('Added field %label.', array(
-      '%label' => $form_values['field_name'])));  }
-  else {
-    drupal_set_message(t('There was a problem adding field %label.', array(
-      '%label' => $form_values['field_name'])));
-  }
+  $type_name = $form_values['type_name'];
   $type = content_types($form_values['type_name']);
-  $form_state['redirect'] = 'admin/content/node-type/'. $type['url_str'] .'/fields';
-}
+  $field_name = $form_values['field_name'];
+  $field_type = $form_values['type'];
+  $label = $form_values['label'];
 
-/**
- * A form element for selecting field, widget, and label.
- */
-function content_field_main_form(&$form_state, $form_values) {
-  module_load_include('inc', 'content', 'includes/content.crud');
   $form = array();
-  if (!empty($form_state['storage'])) {
-    $form_values = $form_state['storage'];
-  }
 
-  $type_name = $form_values['type_name'];
-  $type = content_types($type_name);
-  $field_name = isset($form_values['field_name']) ? $form_values['field_name'] : '';
-  $field_type = isset($form_values['type']) ? $form_values['type'] : '';
-  $label = isset($form_values['label']) ? $form_values['label'] : '';
-
-  // Remove the 'field_' prefix from the field name.
-  $trimmed_field_name = $field_name;
-  if (substr($field_name, 0, 6) == 'field_') {
-    $trimmed_field_name = substr($field_name, 6);
-  }
-
-  // If we haven't chosen a field name yet, include an option to
-  // share an existing field instead.
-  if (empty($field_name)) {
-    $form['#prefix'] = drupal_get_form('content_field_add_existing_form', $type_name);
-  }
-
-  // See if we're editing an existing field or a new field.
-  $instances = content_field_instance_read(array('field_name' => $field_name, 'type_name' => $type_name));
-  if (count($instances) < 1) {
-    $form['new'] = array(
-      '#type' => 'fieldset',
-      '#title' => t('Create new field'),
-    );
-    $new = TRUE;
-  }
-  else {
-    $form['new'] = array(
-      '#type' => 'fieldset',
-      '#title' => t('Edit basic information'),
-    );
-    $new = FALSE;
-  }
-  $form['new']['field_name'] = array(
+  $form['basic'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Edit basic information'),
+  );
+  $form['basic']['field_name'] = array(
     '#title' => t('Field name'),
     '#type' => 'textfield',
-    '#default_value' => $trimmed_field_name,
-    '#field_prefix' => 'field_',
-    '#description' => t("The machine-readable name of the field."),
-    '#required' => TRUE,
+    '#value' => $field_name,
+    '#description' => t("The machine-readable name of the field. This name cannot be changed."),
+    '#disabled' => TRUE,
   );
-  if (!empty($field_name)) {
-    $form['new']['field_name']['#description'] .= ' '. t("This name cannot be changed.");
-    $form['new']['field_name']['#disabled'] = TRUE;
-    $form['new']['field_name']['#required'] = FALSE;
-    $form['new']['field_name']['#value'] = $field_name;
-    $form['new']['field_name']['#field_prefix'] = '';
-    $form['new_field_name'] = array('#type' => 'hidden', '#value' => FALSE);
-  }
-  else {
-    $form['new']['field_name']['#description'] .= ' '. t("This name cannot be changed later! The name will be prefixed with 'field_' and can include lowercase unaccented letters, numbers, and underscores. The length of the name, including the prefix, is limited to no more than 32 characters.");
-    $form['new_field_name'] = array('#type' => 'hidden', '#value' => TRUE);
-  }
-  $form['new']['label'] = array(
+  $form['basic']['label'] = array(
     '#type' => 'textfield',
     '#title' => t('Label'),
     '#default_value' => $label,
     '#required' => TRUE,
     '#description' => t('A human-readable name to be used as the label for this field in the %type content type.', array('%type' => $type['name'])),
   );
-
-  if (empty($field_type)) {
-    $form['new']['type'] = array(
-      '#type' => 'select',
-      '#title' => t('Field type'),
-      '#required' => TRUE,
-      '#options' => content_field_type_options(),
-      '#default_value' => NULL,
-      '#description' => t('The type of data you would like to store in the database with this field.'),
-    );
-    $form['widget_type'] = array('#type' => 'hidden', '#value' => '');
-  }
-  else {
-    $form['new']['type'] = array(
-      '#type' => 'select',
-      '#title' => t('Field type'),
-      '#options' => content_field_type_options(),
-      '#default_value' => $field_type,
-      '#description' => t('The type of data you would like to store in the database with this field. This option cannot be changed.'),
-      '#disabled' => TRUE,
-    );
-    $form['new']['widget_type'] = array(
-      '#type' => 'select',
-      '#title' => t('Widget type'),
-      '#required' => TRUE,
-      '#options' => content_widget_type_options($field_type),
-      '#default_value' => $form_values['widget_type'],
-      '#description' => t('The type of form element you would like to present to the user when creating this field in the %type content type.', array('%type' => $type['name'])),
-    );
-  }
+  $form['basic']['type'] = array(
+    '#type' => 'select',
+    '#title' => t('Field type'),
+    '#options' => content_field_type_options(),
+    '#default_value' => $field_type,
+    '#description' => t('The type of data you would like to store in the database with this field. This option cannot be changed.'),
+    '#disabled' => TRUE,
+  );
+  $form['basic']['widget_type'] = array(
+    '#type' => 'select',
+    '#title' => t('Widget type'),
+    '#required' => TRUE,
+    '#options' => content_widget_type_options($field_type),
+    '#default_value' => $form_values['widget_type'],
+    '#description' => t('The type of form element you would like to present to the user when creating this field in the %type content type.', array('%type' => $type['name'])),
+  );
 
   $form['type_name'] = array(
     '#type' => 'value',
     '#value' => $type_name,
   );
-  $form['needs_update'] = array(
-    '#type' => 'hidden',
-    '#value' => !empty($form_values['needs_update']),
-  );
+
   $form['submit'] = array(
     '#type' => 'submit',
     '#value' => t('Continue'),
   );
-  $form['#validate'] = array('content_field_main_form_validate');
-  $form['#submit'] = array('content_field_main_form_submit');
-  return $form;
-}
 
-/**
- *  Field name validation.
- */
-function content_field_main_form_validate($form, &$form_state) {
-  $form_values = $form_state['values'];
-  $field_name = $form_values['field_name'];
+  $form['#validate'] = array();
+  $form['#submit'] = array('content_field_basic_form_submit');
 
-  // Add the 'field_' prefix.
-  if (!empty($field_name) && substr($field_name, 0, 6) != 'field_') {
-    $field_name = 'field_'. $field_name;
-    form_set_value($form['new']['field_name'], $field_name, $form_state);
-  }
-
-  // Testing for a valid name only needs to be done the first time through.
-  if (isset($form_values['new_field_name']) && $form_values['new_field_name']) {
-    if (!preg_match('!^field_[a-z0-9_]+$!', $field_name)) {
-      form_set_error('field_name', t('The field name %field_name is invalid. The name must include only lowercase unaccentuated letters, numbers, and underscores.', array('%field_name' => $field_name)));
-    }
-    if (strlen($field_name) > 32) {
-      form_set_error('field_name', t('The field name %field_name is too long. The name is limited to 32 characters, including the \'field_\' prefix.', array('%field_name' => $field_name)));
-    }
-    // Check the name is not used by another field.
-    // We need to check inactive fields as well, so we can't use content_fields().
-    module_load_include('inc', 'content', 'includes/content.crud');
-    $fields = content_field_instance_read(array(), TRUE);
-    $used = FALSE;
-    foreach ($fields as $field) {
-      $used |= ($field['field_name'] == $field_name);
-    }
-    if ($used) {
-      form_set_error('field_name', t('The field name %field_name already exists.', array('%field_name' => $field_name)));
-    }
-    elseif ($field_name == 'field_instance') {
-      form_set_error('field_name', t("The name 'field_instance' is a reserved name."));
-    }
-  }
+  return $form;
 }
 
 /**
  * Create a new field for a content type.
  */
-function content_field_main_form_submit($form, &$form_state) {
+function content_field_basic_form_submit($form, &$form_state) {
   $form_values = $form_state['values'];
-  $form_state['storage'] = $form_values;
-  if (empty($form_values['type']) || empty($form_values['widget_type'])) {
-    $form_state['rebuild'] = TRUE;
-  }
-  else {
-    module_load_include('inc', 'content', 'includes/content.crud');
-    // Unset $form_state['storage'] so FAPI doesn't force
-    // $form_state['rebuild'] to TRUE.
-    unset($form_state['storage']);
-    $form_state['rebuild'] = FALSE;
 
-    $label = $form_values['label'];
+  $label = $form_values['label'];
 
-    // Set the right module information
-    $field_types = _content_field_types();
-    $widget_types = _content_widget_types();
-    $form_values['module'] = $field_types[$form_values['type']]['module'];
-    $form_values['widget_module'] = $widget_types[$form_values['widget_type']]['module'];
-    // Are we creating or updating this field?
-    $instances = content_field_instance_read(array('field_name' => $form_values['field_name'], 'type_name' => $form_values['type_name']));
-    if (sizeof($instances) < 1) {
-      if (content_field_instance_create($form_values)) {
-        drupal_set_message(t('Created field %label.', array(
-          '%label' => $label)));
-      }
-      else {
-        drupal_set_message(t('There was a problem creating field %label.', array(
-          '%label' => $label)));
-      }
-    }
-    else {
-      // If we're updating, make sure we retain previous values and
-      // only over-write changed values.
-      $field = array_merge(content_field_instance_collapse($instances[0]), $form_values);
-      if (content_field_instance_update($field)) {
-        drupal_set_message(t('Updated field %label.', array(
-          '%label' => $label)));
-      }
-      else {
-        drupal_set_message(t('There was a problem updating field %label.', array(
-          '%label' => $label)));
-      }
-    }
+  // Set the right module information
+  $field_types = _content_field_types();
+  $widget_types = _content_widget_types();
+  $form_values['module'] = $field_types[$form_values['type']]['module'];
+  $form_values['widget_module'] = $widget_types[$form_values['widget_type']]['module'];
 
-    $type = content_types($form_values['type_name']);
-    $form_state['redirect'] = 'admin/content/node-type/'. $type['url_str'] .'/fields/'. $form_values['field_name'];
+  // Make sure we retain previous values and only over-write changed values.
+  module_load_include('inc', 'content', 'includes/content.crud');
+  $instances = content_field_instance_read(array('field_name' => $form_values['field_name'], 'type_name' => $form_values['type_name']));
+  $field = array_merge(content_field_instance_collapse($instances[0]), $form_values);
+  if (content_field_instance_update($field)) {
+    drupal_set_message(t('Updated field %label.', array(
+      '%label' => $label)));
   }
+  else {
+    drupal_set_message(t('There was a problem updating field %label.', array(
+      '%label' => $label)));
+  }
+
+  $type = content_types($form_values['type_name']);
+  $form_state['redirect'] = 'admin/content/node-type/'. $type['url_str'] .'/fields/'. $form_values['field_name'];
+  $form_state['rebuild'] = FALSE;
 }
 
 /**
@@ -902,41 +881,53 @@
   if (isset($form_state['change_basic'])) {
     module_load_include('inc', 'content', 'includes/content.crud');
     $field_values = content_field_instance_collapse($field);
-    return content_field_main_form($form_state, $field_values);
+    return content_field_basic_form($form_state, $field_values);
+  }
+
+  $add_new_sequence = isset($_REQUEST['destinations']);
+
+  // Remove menu tabs when we are in an 'add new' sequence.
+  if ($add_new_sequence) {
+    menu_set_item(NULL, menu_get_item('node'));
   }
 
   $form = array();
-  $form['main'] = array(
+  $form['#field'] = $field;
+  $form['#type'] = $type;
+
+  // Basic iformation : hide when we are in an 'add new' sequence.
+  $form['basic'] = array(
     '#type' => 'fieldset',
     '#title' => t('%type basic information', array('%type' => $type['name'])),
+    '#access' => !$add_new_sequence,
   );
-  $form['main']['label'] = array(
+  $form['basic']['label'] = array(
     '#type' => 'textfield',
     '#title' => t('Label'),
     '#value' => $field['widget']['label'],
     '#disabled' => TRUE,
   );
-  $form['main']['field_name'] = array(
+  $form['basic']['field_name'] = array(
     '#type' => 'hidden',
     '#title' => t('Field name'),
     '#value' => $field['field_name'],
     '#disabled' => TRUE,
   );
-  $form['main']['type'] = array(
+  $form['basic']['type'] = array(
     '#type' => 'hidden',
     '#title' => t('Field type'),
     '#options' => content_field_type_options(),
     '#value' => $field['type'],
     '#disabled' => TRUE,
   );
-  $form['main']['widget_type'] = array(
+  $form['basic']['widget_type'] = array(
     '#type' => 'select',
     '#title' => t('Widget type'),
     '#options' => content_widget_type_options($field['type']),
     '#default_value' => $field['widget']['type'] ? $field['widget']['type'] : $default_widget,
     '#disabled' => TRUE,
   );
-  $form['main']['change'] = array(
+  $form['basic']['change'] = array(
     '#type' => 'submit',
     '#value' => t('Change basic information'),
     '#submit' => array('content_field_edit_form_submit_update_basic'),
@@ -1239,9 +1230,27 @@
   $form_values = $form_state['values'];
   content_field_instance_update($form_values);
 
-  drupal_set_message(t('Saved field %label.', array('%label' => $form_values['label'])));
-  $type   = content_types($form_values['type_name']);
-  $form_state['redirect'] = 'admin/content/node-type/'. $type['url_str'] .'/fields';
+  if (isset($_REQUEST['destinations'])) {
+    drupal_set_message(t('Added field %label.', array('%label' => $form_values['label'])));
+    $form_state['redirect'] = content_get_destinations($_REQUEST['destinations']);
+  }
+  else {
+    drupal_set_message(t('Saved field %label.', array('%label' => $form_values['label'])));
+    $type = content_types($form_values['type_name']);
+    $form_state['redirect'] = 'admin/content/node-type/'. $type['url_str'] .'/fields';
+  }
+}
+
+/**
+ * Helper function to handle multipage redirects.
+ */
+function content_get_destinations($destinations) {
+  $query = array();
+  $path = array_shift($destinations);
+  if ($destinations) {
+    $query['destinations'] = $destinations;
+  }
+  return array($path, $query);
 }
 
 /**
Index: content.js
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/cck/content.js,v
retrieving revision 1.1
diff -u -r1.1 content.js
--- content.js	2 Mar 2008 23:18:08 -0000	1.1
+++ content.js	9 Sep 2008 17:36:52 -0000
@@ -1,20 +1,72 @@
 // $Id: content.js,v 1.1 2008/03/02 23:18:08 yched Exp $
 
-/**
- * Show the Save button when fields are swapped.
- *
- * This behavior is dependent on the tableDrag behavior, since it uses the
- * objects initialized in that behavior to update the row.
- */
-Drupal.behaviors.cckFieldDrag = function(context) {
-  var tableDrag = Drupal.tableDrag['content-field-overview']; // Get the tableDrag object.
-
-  // Add a handler for when a row is dropped,
-  // show Save button if the table has been changed.
-  tableDrag.onDrop = function() {
-    if (tableDrag.changed) {
-      $('.content-admin-field-overview-submit').fadeIn('slow');
-    }
-  }
+Drupal.behaviors.cckManageFields = function(context) {
+  attachUpdateSelects(context);
 };
 
+function attachUpdateSelects(context) {
+  var widgetTypes = Drupal.settings.contentWidgetTypes;
+  var fields = Drupal.settings.contentFields;
+
+  // Store the default text of widget selects.
+  $('#content-field-overview .content-widget-type-select', context).each(function() {
+    this.initialValue = this.options[0].text;
+  });
+
+  // Field type select updates its widget select.
+  $('#content-field-overview .content-field-type-select', context).each(function() {
+    this.targetSelect = $('.content-widget-type-select', $(this).parents('tr'));
+
+    $(this).change(function() {
+      var selectedFieldType = this.options[this.selectedIndex].value;
+      var options = (selectedFieldType in widgetTypes) ? widgetTypes[selectedFieldType] : [ ];
+      this.targetSelect.contentOptions(options);
+    });
+
+    $(this).trigger('change');
+  });
+
+  // Existing field select updates its widget select and label textfield.
+  $('#content-field-overview .content-field-select', context).each(function() {
+    this.targetSelect = $('.content-widget-type-select', $(this).parents('tr'));
+    this.targetTextfield = $('.content-label-textfield', $(this).parents('tr'));
+
+    $(this).change(function(e, updateText) {
+      var updateText = (typeof(updateText) == 'undefined') ? true : updateText;
+      var selectedField = this.options[this.selectedIndex].value;
+      var selectedFieldType = (selectedField in fields) ? fields[selectedField].type : null;
+      var selectedFieldWidget = (selectedField in fields) ? fields[selectedField].widget : null
+      var options = (selectedFieldType && (selectedFieldType in widgetTypes)) ? widgetTypes[selectedFieldType] : [ ];
+      this.targetSelect.contentOptions(options, selectedFieldWidget);
+
+      if (updateText) {
+        $(this.targetTextfield)
+          .attr('value', (selectedField in fields) ? fields[selectedField].label : '');
+      }
+    });
+
+    $(this).trigger('change', false);
+  });
+}
+
+jQuery.fn.contentOptions = function(options, selected) {
+  return this.each(function() {
+    var disabled = false;
+    if (options.length == 0) {
+      options = [this.initialValue];
+      disabled = true;
+    }
+
+    var selectValue = selected || this.options[this.selectedIndex].value;
+
+    var html = '';
+    jQuery.each(options, function(value, text) {
+      selected = (value == selectValue) ? ' selected="selected"' : '';
+      html += '<option value="' + value + '"' + selected +'>' + text + '</option>';
+    });
+
+    $(this)
+      .html(html)
+      .attr('disabled', disabled ? 'disabled' : '');
+  });
+}
\ No newline at end of file
Index: content.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/cck/content.module,v
retrieving revision 1.301.2.47
diff -u -r1.301.2.47 content.module
--- content.module	9 Sep 2008 15:39:43 -0000	1.301.2.47
+++ content.module	9 Sep 2008 17:36:53 -0000
@@ -35,18 +35,6 @@
       $output .= '<p>'. t('For more information, see the online handbook entry for <a href="@handbook-cck">CCK</a> or the <a href="@project-cck">CCK project page</a>.', array('@handbook-cck' => 'http://drupal.org/handbook/modules/cck', '@project-cck' => 'http://drupal.org/project/cck')) .'</p>';
       return $output;
   }
-
-  if (preg_match('!^admin/content/node-type/.*/display!', $path)) {
-    if (preg_match('!^admin/content/node-type/.*/display$!', $path)) {
-      return t("Configure how this content type's fields and field labels should be displayed when it's viewed in teaser and full-page mode.");
-    }
-    else {
-      return t("Configure how this content type's fields should be displayed when it's rendered in the following contexts.");
-    }
-  }
-  if (preg_match('!^admin/content/node-type/.*/fields$!', $path)) {
-    return t('Control the order of fields in the input form.');
-  }
 }
 
 /**
@@ -152,15 +140,6 @@
         'type' => MENU_LOCAL_TASK,
         'weight' => 1,
       );
-      $items['admin/content/node-type/'. $type_url_str .'/add_field'] = array(
-        'title' => 'Add field',
-        'page callback' => 'content_field_add',
-        'page arguments' => array($type_name),
-        'access arguments' => array('administer content types'),
-        'file' => 'includes/content.admin.inc',
-        'type' => MENU_LOCAL_TASK,
-        'weight' => 3,
-      );
       // Cast as an array in case this is called before any fields have
       // been added, like when a new content type is created.
       foreach ((array) $content_type['fields'] as $field) {
@@ -210,6 +189,7 @@
  */
 function content_theme() {
   $path = drupal_get_path('module', 'content') .'/theme';
+  require_once "./$path/theme.inc";
 
   return array(
     'content_field' => array(
@@ -221,12 +201,15 @@
       'arguments' => array(),
     ),
     'content_field_overview_form' => array(
+      'template' => 'content-admin-field-overview-form',
+      'file' => 'theme.inc',
+      'path' => $path,
       'arguments' => array('form' => NULL),
     ),
     'content_display_overview_form' => array(
-      'arguments' => array('form' => NULL),
-    ),
-    'content_admin_field_add_new_field_widget_type' => array(
+      'template' => 'content-admin-display-overview-form',
+      'file' => 'theme.inc',
+      'path' => $path,
       'arguments' => array('form' => NULL),
     ),
     'content_view_multiple_field' => array(
@@ -1888,7 +1871,7 @@
 }
 
 /**
- * Process variables for field.tpl.php.
+ * Theme preprocess function for field.tpl.php.
  *
  * The $variables array contains the following arguments:
  * - $node
@@ -1898,6 +1881,9 @@
  * - $page
  *
  * @see field.tpl.php
+ *
+ * TODO : this should live in theme/theme.inc, but then the preprocessor
+ * doesn't get called when the theme overrides the template. Bug in theme layer ?
  */
 function content_preprocess_content_field(&$variables) {
   $element = $variables['element'];
Index: tests/content.crud.test
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/cck/tests/content.crud.test,v
retrieving revision 1.4.2.12
diff -u -r1.4.2.12 content.crud.test
--- tests/content.crud.test	6 Sep 2008 15:54:33 -0000	1.4.2.12
+++ tests/content.crud.test	9 Sep 2008 17:36:55 -0000
@@ -374,7 +374,7 @@
 class ContentCrudBasicTest extends ContentCrudTestCase {
   function getInfo() {
     return array(
-      'name' => t('CCK CRUD API - Basic API tests'),
+      'name' => t('CRUD - Basic API tests'),
       'description' => t('Tests the field CRUD (create, read, update, delete) API. <b>Requires !schema_link.</b>', array('!schema_link' => l('Schema module', 'http://www.drupal.org/projects/schema'))),
       'group' => t('CCK'),
     );
@@ -430,7 +430,7 @@
 class ContentCrudSingleToMultipleTest extends ContentCrudTestCase {
   function getInfo() {
     return array(
-      'name' => t('CCK CRUD API - Single to multiple'),
+      'name' => t('CRUD - Single to multiple'),
       'description' => t('Tests the field CRUD (create, read, update, delete) API by creating a single value field and changing it to a multivalue field, sharing it between several content types. <b>Requires !schema_link.</b>', array('!schema_link' => l('Schema module', 'http://www.drupal.org/projects/schema'))),
       'group' => t('CCK'),
     );
@@ -505,7 +505,7 @@
 class ContentCrudMultipleToSingleTest extends ContentCrudTestCase {
   function getInfo() {
     return array(
-      'name' => t('CCK CRUD API - Multiple to single'),
+      'name' => t('CRUD - Multiple to single'),
       'description' => t('Tests the field CRUD (create, read, update, delete) API by creating a multivalue field and changing it to a single value field, sharing it between several content types. <b>Requires !schema_link.</b>', array('!schema_link' => l('Schema module', 'http://www.drupal.org/projects/schema'))),
       'group' => t('CCK'),
     );
@@ -639,70 +639,195 @@
 class ContentUICrud extends ContentCrudTestCase {
   function getInfo() {
     return array(
-      'name' => t('Create and Tests Fields via the UI'),
+      'name' => t('Admin UI'),
       'description' => t('Tests the CRUD (create, read, update, delete) operations for content fields via the UI. <b>Requires !schema_link.</b>', array('!schema_link' => l('Schema module', 'http://www.drupal.org/projects/schema'))),
       'group' => t('CCK'),
     );
   }
 
   function setUp() {
-    parent::setUp();
+    parent::setUp('fieldgroup');
     $this->loginWithPermissions();
   }
 
   function testAddFieldUI() {
     // Add a content type with a random name (to avoid schema module problems).
-    $edit = array();
     $type1 = 'simpletest'. mt_rand();
-    $admin_type1_url = 'admin/content/node-type/'. $type1;
-    $edit['name']  = $this->randomName(10);
-    $edit['type']  = $type1;
+    $type1_name = $this->randomName(10);
+    $edit = array(
+      'type' => $type1,
+      'name' => $type1_name,
+    );
     $this->drupalPost('admin/content/types/add', $edit, 'Save content type');
+    $admin_type1_url = 'admin/content/node-type/'. $type1;
 
     // Create a text field via the UI.
+    $field_name = strtolower($this->randomName(10));
+    $field_label = $this->randomName(10);
+    $edit = array(
+      '_add_new_field[label]' => $field_label,
+      '_add_new_field[field_name]' => $field_name,
+      '_add_new_field[type]' => 'text',
+      '_add_new_field[widget_type]' => 'text_textfield',
+    );
+    $this->drupalPost($admin_type1_url .'/fields', $edit, 'Save');
+    $this->assertRaw('These settings apply only to the <em>'. $field_label .'</em> field', 'Field settings page displayed');
+    $this->assertRaw('Size of textfield', 'Field and widget types correct.');
+    $this->assertNoRaw('Change basic information', 'No basic information displayed');
+    $field_name = 'field_'. $field_name;
+
     $edit = array();
-    $edit['field_name']  = strtolower($this->randomName(10));
-    $edit['label']       = $this->randomName(20);
-    $edit['type']        = 'text';
-    $this->drupalPost($admin_type1_url .'/add_field', $edit, 'Continue');
-    $field_url = 'field_'. $edit['field_name'];
-    $field_label = $edit['label'];
-    $edit = array();
-    $edit["widget_type"] = 'text_textfield';
     // POST to the page without reloading.
-    $this->drupalPost(NULL, $edit, 'Continue');
-    $this->assertRaw('Created field <em>'. $field_label, 'Success message displayed');
-    $this->drupalPost($admin_type1_url .'/fields/'. $field_url, array(), 'Save field settings');
+    $this->drupalPost(NULL, $edit, 'Save field settings');
+    $this->assertRaw('Added field <em>'. $field_label .'</em>.', 'Field settings saved');
+    $field_type1_url = $admin_type1_url .'/fields/'. $field_name;
+    $this->assertRaw($field_type1_url, 'Field displayed on overview.');
+
     // Check the schema - the values should be in the per-type table.
     $this->assertSchemaMatchesTables(array(
       'per_type' => array(
-        $type1 => array($field_url => array('value')),
+        $type1 => array($field_name => array('value')),
       ),
     ));
 
+
     // Add a second content type.
-    $edit = array();
     $type2 = 'simpletest'. mt_rand();
-    $admin_type2_url = 'admin/content/node-type/'. $type2;
-    $edit['name']  = $this->randomName(10);
-    $edit['type']  = $type2;
+    $type2_name = $this->randomName(10);
+    $edit = array(
+      'type' => $type2,
+      'name' => $type2_name,
+    );
     $this->drupalPost('admin/content/types/add', $edit, 'Save content type');
+    $admin_type2_url = 'admin/content/node-type/'. $type2;
+
+    // Add the same field to the second content type.
+    $edit = array(
+      '_add_existing_field[label]' => $field_label,
+      '_add_existing_field[field_name]' => $field_name,
+      '_add_existing_field[widget_type]' => 'text_textarea',
+    );
+    $this->drupalPost($admin_type2_url .'/fields', $edit, 'Save');
+    $this->assertRaw('These settings apply only to the <em>'. $field_label .'</em> field', 'Field settings page displayed');
+    $this->assertRaw('Rows', 'Field and widget types correct.');
+    $this->assertNoRaw('Change basic information', 'No basic information displayed');
+
+    $edit = array();
+    $this->drupalPost(NULL, $edit, 'Save field settings');
+    $this->assertRaw('Added field <em>'. $field_label .'</em>.', 'Field settings saved');
+    $field_type2_url = $admin_type2_url .'/fields/'. $field_name;
+    $this->assertRaw($field_type2_url, 'Field displayed on overview.');
 
-    // Add the same field to a second content type.
-    $edit = array();
-    $edit['existing_field_name'] = $field_url;
-    $this->drupalPost($admin_type2_url .'/add_field', $edit, 'Add field');
     // Check that a separate table is created for the shared field, and
     // that it's values are no longer in the per-type tables.
     $this->assertSchemaMatchesTables(array(
       'per_field' => array(
-        $field_url => array($field_url => array('value')),
+        $field_name => array($field_name => array('value')),
       ),
       'per_type' => array(
         $type1 => array(),
         $type2 => array(),
       ),
     ));
+
+
+    // Chancge the basic settings for this field.
+    $edit = array();
+    $this->drupalPost($field_type2_url, $edit, 'Change basic information');
+    $this->assertRaw('Edit basic information', 'Basic information form displayed');
+
+    $field_label2 = $this->randomName(10);
+    $edit = array(
+      'label' => $field_label2,
+      'widget_type' => 'text_textfield',
+    );
+    $this->drupalPost(NULL, $edit, 'Continue');
+    $this->assertRaw('These settings apply only to the <em>'. $field_label2 .'</em> field', 'Label changed');
+    $this->assertRaw('Size of textfield', 'Widget changed');
+
+    $edit = array();
+    // POST to the page without reloading.
+    $this->drupalPost(NULL, $edit, 'Save field settings');
+    $this->assertRaw('Saved field <em>'. $field_label2 .'</em>.', 'Field settings saved');
+
+
+    // Add a group to the second content type.
+    $group1_label = $this->randomName(10);
+    $group1_name = 'group_'.strtolower($group1_label);
+    $edit = array(
+      '_add_new_group[label]' => $group1_label,
+    );
+    $this->drupalPost($admin_type2_url .'/fields', $edit, 'Save');
+    $this->assertRaw($admin_type2_url .'/groups/'. $group1_name, 'Group created');
+
+
+    // Remove the field from the second type.
+    $edit = array();
+    $this->drupalPost($field_type2_url .'/remove', $edit, 'Remove');
+    $this->assertRaw('Removed field <em>'. $field_label2 .'</em> from <em>'. $type2_name .'</em>', 'Field removed');
+    $this->assertNoRaw($field_type2_url, 'Field not displayed on overview.');
+
+    // Check the schema - the values should be in the per-type table.
+    $this->assertSchemaMatchesTables(array(
+      'per_type' => array(
+        $type1 => array($field_name => array('value')),
+      ),
+    ));
+
+    // Add a new field, an existing field, and a group in the same submit.
+    $field2_label = $this->randomName(10);
+    $field2_name = strtolower($this->randomName(10));
+    $group2_label = $this->randomName(10);
+    $group2_name = 'group_'.strtolower($group2_label);
+    $edit = array(
+      '_add_new_field[label]' => $field2_label,
+      '_add_new_field[field_name]' => $field2_name,
+      '_add_new_field[type]' => 'text',
+      '_add_new_field[widget_type]' => 'text_textfield',
+      '_add_new_field[parent]' => $group1_name,
+      '_add_existing_field[label]' => $field_label,
+      '_add_existing_field[field_name]' => $field_name,
+      '_add_existing_field[widget_type]' => 'text_textarea',
+      '_add_existing_field[parent]' => '_add_new_group',
+      '_add_new_group[label]' => $group2_label,
+    );
+    $this->drupalPost($admin_type2_url .'/fields', $edit, 'Save');
+    $this->assertRaw('These settings apply only to the <em>'. $field2_label .'</em> field', 'Field settings page for new field displayed');
+    // Submit new field settings
+    $edit = array();
+    $this->drupalPost(NULL, $edit, 'Save field settings');
+    $this->assertRaw('Added field <em>'. $field2_label .'</em>.', 'Field settings for new field saved');
+    $this->assertRaw('These settings apply only to the <em>'. $field_label .'</em> field', 'Field settings page for existing field displayed');
+    // Submit existing field settings
+    $edit = array();
+    $this->drupalPost(NULL, $edit, 'Save field settings');
+    $this->assertRaw('Added field <em>'. $field_label .'</em>.', 'Field settings for existing field saved');
+    $field2_name = 'field_'. $field2_name;
+    $field2_type2_url = $admin_type2_url .'/fields/'. $field2_name;
+    $this->assertRaw($field2_type2_url, 'New field displayed in overview');
+    $this->assertRaw($field_type2_url, 'Existing field displayed in overview');
+    $this->assertRaw($admin_type2_url .'/groups/'. $group2_name, 'New group displayed in overview');
+
+    // Check Parenting
+    $groups = fieldgroup_groups($type2, FALSE, TRUE);
+    $this->assertTrue(isset($groups[$group1_name]['fields'][$field2_name]), 'New field in correct group');
+    $this->assertTrue(isset($groups[$group2_name]['fields'][$field_name]), 'Existing field in correct group');
+    $this->assertFieldByXPath('//select[@id="edit-'. strtr($field2_name, '_', '-') .'-parent"]//option[@selected]', $group1_name, 'Parenting for new field correct in overview');
+    $this->assertFieldByXPath('//select[@id="edit-'. strtr($field_name, '_', '-') .'-parent"]//option[@selected]', $group2_name, 'Parenting for existing field correct in overview');
+
+    // Check the schema : field1 is shared, field2 is in the per-type table.
+    $this->assertSchemaMatchesTables(array(
+      'per_field' => array(
+        $field_name => array($field_name => array('value')),
+      ),
+      'per_type' => array(
+        $type1 => array(),
+        $type2 => array($field2_name => array('value')),
+      ),
+    ));
+
+    // TODO : test validation failures...
+    // TODO : test ordering and extra fields...
   }
 
   function testFieldContentUI() {
Index: help/remove.html
===================================================================
RCS file: help/remove.html
diff -N help/remove.html
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ help/remove.html	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,9 @@
+<p>When you remove a field from a content type, the data it holds are
+<strong>permanently</strong> erased. You will be asked to confirm this action</p>
+
+<p>>You will have to manually update your Views, pathauto settings, etc... if
+needed.</p>
+
+<p>Note : if the field is shared across several content types, removing it from
+one content type does <strong>not</strong> affect the data for the other content
+types.</p>
Index: help/content.help.ini
===================================================================
RCS file: help/content.help.ini
diff -N help/content.help.ini
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ help/content.help.ini	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,35 @@
+; $Id: advanced_help.help.ini,v 1.3 2008/04/28 18:48:07 merlinofchaos Exp $
+
+[manage-fields]
+title = 'Manage fields' tab
+
+[add]
+title = Add fields and groups
+parent = manage-fields
+weight = 1
+
+[add-new-field]
+title = Add a new field
+parent = add
+weight = 1
+
+[add-existing-field]
+title = Add an existing field : share a field across content types
+parent = add
+weight = 2
+
+[add-new-group]
+title = Add a new group
+parent = add
+weight = 3
+
+[rearrange]
+title = Rearrange fields and groups
+parent = manage-fields
+weight = 2
+
+[remove-field]
+title = Remove a field from a content type
+parent = manage-fields
+weight = 3
+
Index: help/rearrange.html
===================================================================
RCS file: help/rearrange.html
diff -N help/rearrange.html
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ help/rearrange.html	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,24 @@
+<p>To change the order of fields, grab a drag-and-drop handle
+<img src="path:draggable.png"> and drag the field to a new location in the list
+(grab a handle by clicking and holding the mouse while hovering over a handle
+icon). Remember that your changes will not be saved until you click the
+<strong>Save</strong> button at the bottom of the page.</p>
+
+<p>The order you define will be used both on input forms (when creating or
+editing a post), and on content display (teasers, content page, RSS items...)</p>
+<p>You can also change the order of non-CCK 'fields' like <strong>Title</strong>
+or <strong>File attachments</strong>. Depending on the 'field', this will
+affect input forms and/or content display (some of those 'fields' are not
+displayed in both contexts).</p>
+<p>If your content type has groups (requires the Fieldgroup module), you can
+move a field inside a group by dragging it below the row of the group, and
+then slightly to the right before dropping it. Note that groups can also be
+reordered, but can currently not be nested inside other groups.</p>
+
+<img src="path:drag-groups.png">
+
+<p>When adding a field or a group, you can drag them directly to the
+intended spot in the list of fields and groups that are already present in your
+content type before, clicking <strong>Save</strong>:</p>
+
+<img src="path:drag-new.png">
Index: theme/content-admin-display-overview-form.tpl.php
===================================================================
RCS file: theme/content-admin-display-overview-form.tpl.php
diff -N theme/content-admin-display-overview-form.tpl.php
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ theme/content-admin-display-overview-form.tpl.php	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,38 @@
+<?php
+// $Id:$
+?>
+<div>
+  <?php print $help; ?>
+</div>
+<?php if ($rows): ?>
+  <table id="content-display-overview" class="sticky-enabled">
+    <thead>
+      <tr>
+        <th><?php print t('Field'); ?></th>
+        <?php if ($simple): ?>
+          <th><?php print t('Label'); ?></th>
+        <?php endif; ?>
+        <?php foreach ($contexts as $context => $title): ?>
+          <th><?php print $title; ?></th>
+        <?php endforeach; ?>
+      </tr>
+    </thead>
+    <tbody>
+      <?php
+      $count = 0;
+      foreach ($rows as $row): ?>
+        <tr class="<?php print $count % 2 == 0 ? 'odd' : 'even'; ?>">
+          <td><?php print $row->indentation; ?><div class="<?php print $row->label_class; ?>"><?php print $row->human_name; ?></div></td>
+          <?php if ($simple): ?>
+            <td><?php print $row->label; ?></td>
+          <?php endif; ?>
+          <?php foreach ($contexts as $context => $title): ?>
+            <td><?php print $row->{$context}; ?></td>
+          <?php endforeach; ?>
+        </tr>
+        <?php $count++;
+      endforeach; ?>
+    </tbody>
+  </table>
+  <?php print $submit; ?>
+<?php endif; ?>
Index: help/manage-fields.html
===================================================================
RCS file: help/manage-fields.html
diff -N help/manage-fields.html
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ help/manage-fields.html	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,10 @@
+<p>This page lets you manage the CCK fields in your content type : add fields and
+groups, rearrange them, access their configuration pages, remove them from the
+content type.</p>
+
+
+
+
+
+
+
Index: help/add-new-field.html
===================================================================
RCS file: help/add-new-field.html
diff -N help/add-new-field.html
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ help/add-new-field.html	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,55 @@
+<p>At the bottom of the <strong>Manage fields</strong> page for a content type,
+you'll find this:</p>
+
+<img src="path:add-new-field.png">
+
+<p>In order to add a new field to a content type, you need to provide the
+following information:</p>
+<dl>
+  <dt>Label:</dt>
+  <dd>
+    A human-readable name for the field. It will be used in input forms and
+    on displayed content.<br/>
+    All characters are allowed, including spaces, accentuated or non-european
+    characters.
+  </dd>
+
+  <dt>Field name:</dt>
+  <dd>
+    A machine-readable name for the field. It is used internally to identify
+    the field and handle database storage. When doing custom theming, it is
+    this identifier that you'll need to refer to.<br/>
+    Allowed characters: a-z (unaccentuated), 0-9 and the underscore (_).<br/>
+    The length of the field name cannot exceed 32 characters (including the
+    'field_' prefix that gets added automatically - that is, 26 free characters)<br/>
+    <strong>Important:</strong> This value cannot be changed once the field has been
+    created.
+  </dd>
+
+  <dt>Field type:</dt>
+  <dd>
+    The type of data to be stored in that field. The available field types
+    depend on the modules you have enabled on your site. CCK comes with 6
+    basic field types :
+    <ul>
+      <li>Text</li>
+      <li>Integer</li>
+      <li>Float</li>
+      <li>Decimal</li>
+      <li>Node reference</li>
+      <li>User reference</li>
+    </ul>
+    Additional modules can be downloaded to handle other field types such as
+    dates, files, images... Look at the
+    <a href="http://www.drupal.org/project/cck" target="_blank"> CCK project page</a>
+    and the <a href="http://drupal.org/project/Modules/category/88" target="_blank">complete list of CCK-related modules</a>.
+  </dd>
+
+  <dt>Widget:</dt>
+  <dd>
+    The form element that will be used to input data for this field on
+    content forms : text input, select list, etc...<br/>
+    Each field type has its own list of available widgets. When selecting a
+    field type, the list of widgets you can select is automatically updated.
+  </dd>
+</dl>
Index: theme/content-admin-field-overview-form.tpl.php
===================================================================
RCS file: theme/content-admin-field-overview-form.tpl.php
diff -N theme/content-admin-field-overview-form.tpl.php
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ theme/content-admin-field-overview-form.tpl.php	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,99 @@
+<?php
+// $Id:$
+?>
+<div>
+  <?php print $help; ?>
+</div>
+<table id="content-field-overview" class="sticky-enabled">
+  <thead>
+    <tr>
+      <th><?php print t('Label'); ?></th>
+      <th><?php print t('Weight'); ?></th>
+      <th><?php print t('Name'); ?></th>
+      <th><?php print t('Type'); ?></th>
+      <th><?php print t('Operations'); ?></th>
+    </tr>
+  </thead>
+  <tbody>
+    <?php
+    $count = 0;
+    foreach ($rows as $row): ?>
+      <tr class="<?php print $count % 2 == 0 ? 'odd' : 'even'; ?> <?php print $row->class ?>">
+      <?php
+      switch ($row->row_type):
+        case 'field': ?>
+          <td>
+            <?php print $row->indentation; ?>
+            <div class="label-wrapper <?php print $row->label_class; ?>"><?php print $row->label; ?></div>
+          </td>
+          <td><?php print $row->weight . $row->parent . $row->hidden_name; ?></td>
+          <td><?php print $row->field_name; ?></td>
+          <td><?php print $row->type; ?></td>
+          <td><?php print $row->configure; ?>&nbsp;&nbsp;<?php print $row->remove; ?></td>
+          <?php break;
+        case 'group': ?>
+          <td>
+            <?php print $row->indentation; ?>
+            <div class="label-wrapper <?php print $row->label_class; ?>"><?php print $row->label; ?></div>
+          </td>
+          <td><?php print $row->weight . $row->parent . $row->hidden_name; ?></td>
+          <td><?php print $row->group_name; ?></td>
+          <td></td>
+          <td><?php print $row->configure; ?>&nbsp;&nbsp;<?php print $row->remove; ?></td>
+          <?php break;
+        case 'extra': ?>
+          <td>
+            <?php print $row->indentation; ?>
+            <div class="label-wrapper"><?php print $row->label; ?></div>
+          </td>
+          <td><?php print $row->weight . $row->parent . $row->hidden_name; ?></td>
+          <td colspan="3"><?php print $row->description; ?></td>
+          <?php break;
+        case 'separator': ?>
+          <td colspan="5" class="region"><?php print t('Add'); ?></td>
+          <?php break;
+        case 'add_new_field': ?>
+          <td>
+            <?php print $row->indentation; ?>
+            <div class="label-wrapper">
+              <div class="content-new"><?php print theme('advanced_help_topic', 'content', 'add-new-field') . t('New field'); ?></div>
+              <?php print $row->label; ?>
+            </div>
+          </td>
+          <td><div class="content-new">&nbsp;</div><?php print $row->weight . $row->parent . $row->hidden_name; ?></td>
+          <td><div class="content-new">&nbsp;</div><?php print $row->field_name; ?></td>
+          <td><div class="content-new">&nbsp;</div><?php print $row->type; ?></td>
+          <td><div class="content-new">&nbsp;</div><?php print $row->widget_type; ?></td>
+          <?php break;
+        case 'add_existing_field': ?>
+          <td>
+            <?php print $row->indentation; ?>
+            <div class="label-wrapper">
+              <div class="content-new"><?php print theme('advanced_help_topic', 'content', 'add-existing-field') . t('Existing field'); ?></div>
+              <?php print $row->label; ?>
+            </div>
+          </td>
+          <td><div class="content-new">&nbsp;</div><?php print $row->weight . $row->parent . $row->hidden_name; ?></td>
+          <td colspan="2"><div class="content-new">&nbsp;</div><?php print $row->field_name; ?></td>
+          <td><div class="content-new">&nbsp;</div><?php print $row->widget_type; ?></td>
+          <?php break;
+          case 'add_new_group': ?>
+          <td>
+            <?php print $row->indentation; ?>
+            <div class="label-wrapper">
+              <div class="content-new"><?php print theme('advanced_help_topic', 'content', 'add-new-group') . t('New group'); ?></div>
+              <?php print $row->label; ?>
+            </div>
+          </td>
+          <td><div class="content-new">&nbsp;</div><?php print $row->weight . $row->parent . $row->hidden_name; ?></td>
+          <td colspan="3"></td>
+        <?php break;
+      endswitch; ?>
+      </tr>
+      <?php $count++;
+    endforeach; ?>
+  </tbody>
+</table>
+
+<?php print $submit; ?>
+
Index: help/add-existing-field.html
===================================================================
RCS file: help/add-existing-field.html
diff -N help/add-existing-field.html
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ help/add-existing-field.html	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,46 @@
+<p>Using a field across several content type can be handy if a piece of data
+is relevant for several content types. A typical use case is a 'Phone number'
+field, used in both 'Restaurant' and 'Hotel' content types, even if hotels
+and restaurants are different enough to deserve their own specific set of
+fields and thus their own dedicated content types.</p>
+
+<p>When a field has been added to more than one content type, we also say it is
+"shared", and that it as "several instances".</p>
+
+<p>At the bottom of the <strong>Manage fields</strong> page for a content type,
+you'll find this:</p>
+
+<img src="path:add-existing-field.png">
+
+<p>In order to add a new instance of an existing field to a content type, you
+need to provide the following information:</p>
+<dl>
+  <dt><strong>Label</strong></dt>
+  <dd>
+    A human-readable name for the field. It will be used in input forms and
+    on displayed content.<br/>
+    All characters are allowed, including spaces, accentuated or non-european
+    characters.<br/>
+  </dd>
+
+  <dt><strong>Field:</strong></dt>
+  <dd>
+    The field to be shared.<br/>
+    A field cannot appear more than once in each content type. Thus, only
+    fields that are not already present in the current content type will be
+    proposed as "shareable". If none, the <strong>Add existing field</strong>
+    option is not available on the <strong>Manage fields</strong> page for
+    this content type.<br/>
+    Selecting a field automatically populates the <strong>Label</strong> and
+    <strong>Widget</strong> values with the ones used by the previous field
+    instance, but you can change them if needed before submitting the form.
+  </dd>
+
+  <dt><strong>Widget:</strong></dt>
+  <dd>
+    The form element that will be used to input data for this field on
+    content forms : text input, select list, etc...<br/>
+    Each field type has its own list of available widgets. When selecting a
+    field to share, the list of widgets you can select is automatically updated.
+  </dd>
+</dl>
Index: help/add-new-group.html
===================================================================
RCS file: help/add-new-group.html
diff -N help/add-new-group.html
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ help/add-new-group.html	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,27 @@
+<p>Field groups are used to visually gather several fields that are associated
+by some sort of logic, for instance several text fields that hold the different
+parts of an 'Adress'. On input forms and displayed content, the corresponding
+fields are enclosed inside an HTML fieldset.</p>
+
+<img style="vertical-align:top" src="path:group-node-edit-form.png">
+<img style="vertical-align:top" src="path:group-node-display.png">
+
+<p>At the bottom of the <strong>Manage fields</strong> page for a content type,
+you'll find this:</p>
+
+<img src="path:add-new-group.png">
+
+<p>In order to add a new group to a content type, you need to provide the
+following information:</p>
+<dl>
+  <dt><strong>Label</strong></dt>
+  <dd>
+    A human-readable name for the group. It will be used in input forms and
+    on displayed content.<br/>
+    All characters are allowed, including spaces, accentuated or non-european
+    characters.<br/>
+  </dd>
+</dl>
+
+<p>Once a group has been created, you can define what fields it will enclose by
+<a href="topic:content/rearrange">rearranging fields and groups</a>.</p>
Index: help/add.html
===================================================================
RCS file: help/add.html
diff -N help/add.html
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ help/add.html	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,15 @@
+<p>The form elements at the bottom of the <strong>Manage fields</strong> page
+let you add fields and groups to your content types.</p>
+
+<img src="path:add-new.png">
+
+<p style="font-size:smaller">(The <strong>Add existing field</strong> row is
+displayed only if there are fields available in other content types.
+The <strong>Add new group</strong> rows is displayed only if Fieldgroup module
+is enabled.)</p>
+<p>Your fields and groups will be created after you click the <strong>Save</strong>
+button at the bottom of the page. In subsequent pages you will be presented
+with the settings form for each field you added.</p>
+
+<p>You will find more details on the required informations in the
+following pages:</p>
Index: theme/theme.inc
===================================================================
RCS file: theme/theme.inc
diff -N theme/theme.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ theme/theme.inc	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,162 @@
+<?php
+// $Id:$
+
+/**
+ * Theme preprocess function for content-admin-field-overview-form.tpl.php.
+ */
+function template_preprocess_content_field_overview_form(&$vars) {
+  $form = &$vars['form'];
+
+  // Put weight and parenting values into a $dummy render structure
+  // that will figure out the corresponding row order.
+  $dummy = array();
+  // Group rows: account for weight.
+  foreach ($form['#group_rows'] as $name) {
+    $dummy[$name] = array('#weight' => $form[$name]['weight']['#value'], '#value' => $name .' ');
+  }
+  // Field rows : account for weight and parenting.
+  foreach ($form['#field_rows'] as $name) {
+    $dummy[$name] = array('#weight' => $form[$name]['weight']['#value'], '#value' => $name .' ');
+    if (module_exists('fieldgroup')) {
+      if ($parent = $form[$name]['parent']['#value']) {
+        $form[$name]['#depth'] = 1;
+        $dummy[$parent][$name] = $dummy[$name];
+        unset($dummy[$name]);
+      }
+    }
+  }
+  $order = explode(' ', trim(drupal_render($dummy)));
+
+  $vars['help'] = theme('advanced_help_topic', 'content', 'manage-fields') . t('Add fields and groups to the content type, and arrange them on content display and input forms.');
+
+  $rows = array();
+  while ($order) {
+    $key = reset($order);
+    $element = &$form[$key];
+
+    // Only display the 'Add' separator if the 'add' rows are still
+    // at the end of the table.
+    if (!isset($added_separator)) {
+      $remaining_rows = array_diff($order, array('_add_new_field', '_add_existing_field', '_add_new_group'));
+      if (empty($remaining_rows) && empty($element['#depth'])) {
+        $row = new stdClass();
+        $row->row_type = 'separator';
+        $row->class = 'tabledrag-leaf region';
+        $rows[] = $row;
+        $added_separator = TRUE;
+      }
+    }
+
+    $row = new stdClass();
+
+    // Add target classes for the tabledrag behavior.
+    $element['weight']['#attributes']['class'] = 'field-weight';
+    $element['parent']['#attributes']['class'] = 'group-parent';
+    $element['hidden_name']['#attributes']['class'] = 'field-name';
+    // Add target classes for the update selects behavior.
+    switch ($element['#row_type']) {
+      case 'add_new_field':
+        $element['type']['#attributes']['class'] = 'content-field-type-select';
+        $element['widget_type']['#attributes']['class'] = 'content-widget-type-select';
+        break;
+      case 'add_existing_field':
+        $element['field_name']['#attributes']['class'] = 'content-field-select';
+        $element['widget_type']['#attributes']['class'] = 'content-widget-type-select';
+        $element['label']['#attributes']['class'] = 'content-label-textfield';
+        break;
+    }
+    foreach (element_children($element) as $child) {
+      $row->{$child} = drupal_render($element[$child]);
+    }
+    $row->label_class = 'label-'. $element['#row_type'];
+    $row->row_type = $element['#row_type'];
+    $row->indentation = theme('indentation', isset($element['#depth']) ? $element['#depth'] : 0);
+    $row->class = 'draggable';
+    $row->class .= isset($element['#disabled_row']) ? ' menu-disabled' : '';
+    $row->class .= isset($element['#add_new']) ? ' content-add-new' : '';
+    $row->class .= isset($element['#leaf']) ? ' tabledrag-leaf' : '';
+    $row->class .= isset($element['#root']) ? ' tabledrag-root' : '';
+
+    $rows[] = $row;
+    array_shift($order);
+  }
+  $vars['rows'] = $rows;
+  $vars['submit'] = drupal_render($form);
+
+  // Add tabledrag behavior.
+//  drupal_add_tabledrag('content-field-overview', 'match', 'parent', 'group-parent', 'group-parent', 'field-name', FALSE, 1);
+  drupal_add_tabledrag('content-field-overview', 'match', 'parent', 'group-parent', 'group-parent', 'field-name', TRUE, 1);
+//  drupal_add_tabledrag('content-field-overview', 'order', 'sibling', 'field-weight', NULL, NULL, FALSE);
+  drupal_add_tabledrag('content-field-overview', 'order', 'sibling', 'field-weight');
+
+  // Add settings for the update selects behavior.
+  $js_fields = array();
+  foreach (array_keys(content_existing_field_options($form['#type_name'])) as $field_name) {
+    $field = content_fields($field_name);
+    $js_fields[$field_name] = array('label' => $field['widget']['label'], 'type' => $field['type'], 'widget' => $field['widget']['type']);
+  }
+  drupal_add_js(array('contentWidgetTypes' => content_widget_type_options(), 'contentFields' => $js_fields), 'setting');
+  drupal_add_js(drupal_get_path('module', 'content') .'/content.js');
+}
+
+/**
+ * Theme preprocess function for content-admin-display-overview-form.tpl.php.
+ */
+function template_preprocess_content_display_overview_form(&$vars) {
+  $form = &$vars['form'];
+  $contexts_selector = $form['#contexts'];
+
+  // Put weight and parenting values into a $dummy render structure
+  // that will figure out the corresponding row order.
+  $dummy = array();
+  // Group rows: account for weight.
+  if (module_exists('fieldgroup')) {
+    foreach ($form['#groups'] as $name) {
+      $dummy[$name] = array('#weight' => $form[$name]['weight']['#value'], '#value' => $name .' ');
+    }
+  }
+  // Field rows : account for weight and parenting.
+  foreach ($form['#fields'] as $name) {
+    $dummy[$name] = array('#weight' => $form[$name]['weight']['#value'], '#value' => $name .' ');
+    if (module_exists('fieldgroup')) {
+      if ($parent = $form[$name]['parent']['#value']) {
+        $form[$name]['#depth'] = 1;
+        $dummy[$parent][$name] = $dummy[$name];
+        unset($dummy[$name]);
+      }
+    }
+  }
+  $order = explode(' ', trim(drupal_render($dummy)));
+
+  if ($contexts_selector == CONTENT_CONTEXTS_SIMPLE) {
+    $help = t("Configure how this content type's fields and field labels should be displayed when it's viewed in teaser and full-page mode.");
+  }
+  else {
+    $help = t("Configure how this content type's fields should be displayed when it's rendered in the following contexts.");
+  }
+  $vars['help'] = $help;
+
+  if (empty($order)) {
+    $vars['rows'] = array();
+    $vars['submit'] = '';
+    return;
+  }
+
+  $vars['simple'] = $contexts_selector == CONTENT_CONTEXTS_SIMPLE;
+  $vars['contexts'] = _content_admin_display_contexts($contexts_selector);
+
+  $rows = array();
+  foreach ($order as $key) {
+    $element = &$form[$key];
+    $row = new stdClass();
+    foreach (element_children($element) as $child) {
+      $row->{$child} = drupal_render($element[$child]);
+    }
+    $row->label_class = in_array($key, $form['#groups']) ? 'label-group' : 'label-field';
+    $row->indentation = theme('indentation', isset($element['#depth']) ? $element['#depth'] : 0);
+    $rows[] = $row;
+  }
+  $vars['rows'] = $rows;
+  $vars['submit'] = drupal_render($form);
+}
+
