### Eclipse Workspace Patch 1.0
#P CCK 6.x
Index: theme/content.css
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/cck/theme/content.css,v
retrieving revision 1.12.2.1
diff -u -r1.12.2.1 content.css
--- theme/content.css	11 Aug 2008 17:17:42 -0000	1.12.2.1
+++ theme/content.css	11 Aug 2008 22:30:48 -0000
@@ -32,14 +32,11 @@
 }
 
 /* 'Manage fields' overview */
-table.content-field-overview, table.content-field-overview fieldset table {
-  width:100%;
+tr.content-add-new .tabledrag-changed {
+  display: none;
 }
-table.content-field-overview td {
-  width:14%;
-}
-.content-field-overview-empty {
-  text-align:center;
+.content-default-value {
+  color: #999;
 }
 
 
Index: modules/fieldgroup/fieldgroup.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/cck/modules/fieldgroup/fieldgroup.module,v
retrieving revision 1.79.2.8
diff -u -r1.79.2.8 fieldgroup.module
--- modules/fieldgroup/fieldgroup.module	8 Aug 2008 14:11:10 -0000	1.79.2.8
+++ modules/fieldgroup/fieldgroup.module	11 Aug 2008 22:30:48 -0000
@@ -354,8 +354,9 @@
     $form['widget']['description']['#weight'] = 7;
     $form['#submit'][] = 'fieldgroup_content_admin_form_submit';
   }
-  elseif ($form_id == 'content_admin_field_overview_form' && !empty($form['#groups'])) {
-    $form['#submit'][] = 'fieldgroup_content_overview_form_submit';
+  elseif ($form_id == 'content_admin_field_overview_form') {
+    $form['#validate'][] = 'fieldgroup_field_overview_form_validate';
+    $form['#submit'][] = 'fieldgroup_field_overview_form_submit';
   }
   elseif ($form_id == 'content_admin_display_overview_form' && !empty($form['#groups'])) {
     $form['#submit'][] = 'fieldgroup_display_overview_form_submit';
@@ -373,16 +374,61 @@
   fieldgroup_update_fields($form_values);
 }
 
-function fieldgroup_content_overview_form_submit($form, &$form_state) {
+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_admin_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);
@@ -392,6 +438,17 @@
   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'),
+  );
+  foreach (array_keys(_content_admin_display_contexts(CONTENT_CONTEXTS_SIMPLE)) as $key) {
+    $settings['display'][$key] = 'fieldset';
+  }
+  return $settings;
+}
+
 function fieldgroup_display_overview_form_submit($form, &$form_state) {
   $form_values = $form_state['values'];
   $groups = fieldgroup_groups($form['#type_name']);
@@ -565,7 +622,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'];
@@ -589,14 +646,14 @@
     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 {
     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']);
     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.28
diff -u -r1.181.2.28 content.admin.inc
--- includes/content.admin.inc	9 Aug 2008 17:49:49 -0000	1.181.2.28
+++ includes/content.admin.inc	11 Aug 2008 22:30:47 -0000
@@ -111,16 +111,13 @@
   $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
@@ -142,8 +139,8 @@
   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')),
@@ -151,59 +148,156 @@
       '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;
     }
+    $dummy[$name] = array('#weight' => $weight, '#value' => $name .' ');
   }
 
   // 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),
       '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]);
-    }
   }
 
   // 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(),
+      'label' => array('#value' => t($extra[$name]['label'])),
+      'description' => array('#value' => isset($extra[$name]['description']) ? $extra[$name]['description'] : ''),
       'weight' => array('#type' => 'textfield', '#default_value' => $weight),
       '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',
+    );
+    $dummy[$name] = array('#weight' => $weight, '#value' => $name .' ');
+  }
+
+  // Additional row : add new field.
+  $weight = 1000;
+  $field_type_options = content_field_type_options();
+  array_unshift($field_type_options, t('- Select a field type -'));
+  $widget_type_options = content_widget_type_options(NULL, TRUE);
+  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),
+      'field_name' => array('#type' => 'textfield', '#field_prefix' => 'field_', '#size' => 15),
+      'type' => array('#type' => 'select', '#options' => $field_type_options),
+      'widget_type' => array('#type' => 'select', '#options' => $widget_type_options),
+      'weight' => array('#type' => 'textfield', '#default_value' => $weight),
+      'parent' => array('#type' => 'select', '#options' => $group_options, '#default_value' => ''),
+      'hidden_name' => array('#type' => 'hidden', '#default_value' => $name),
+      '#leaf' => TRUE,
+      '#add_new' => TRUE,
+      '#row_type' => $name,
     );
     $dummy[$name] = array('#weight' => $weight, '#value' => $name .' ');
   }
 
+  // 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),
+      'field_name' => array('#type' => 'select', '#options' => $existing_field_options),
+      'widget_type' => array('#type' => 'select', '#options' => $widget_type_options),
+      'weight' => array('#type' => 'textfield', '#default_value' => $weight),
+      'parent' => array('#type' => 'select', '#options' => $group_options, '#default_value' => ''),
+      'hidden_name' => array('#type' => 'hidden', '#default_value' => $name),
+      '#leaf' => TRUE,
+      '#add_new' => TRUE,
+      '#row_type' => $name,
+    );
+    $dummy[$name] = array('#weight' => $weight, '#value' => $name .' ');
+  }
+
+  // Additional row : add new group.
+  if (module_exists('fieldgroup')) {
+    $weight++;
+    $name = '_add_new_group';
+    $form[$name] = array(
+      'label' => array('#type' => 'textfield', '#size' => 15),
+      'weight' => array('#type' => 'textfield', '#default_value' => $weight),
+      'parent' => array('#type' => 'hidden', '#default_value' => ''),
+      'hidden_name' => array('#type' => 'hidden', '#default_value' => $name),
+      '#root' => TRUE,
+      '#add_new' => TRUE,
+      '#row_type' => $name,
+    );
+    $dummy[$name] = array('#weight' => $weight, '#value' => $name .' ');
+  }
+
+  // TODO : problem with 'default-value' JS script on failed validation.
+
+  // TODO : explain...
+  // When validation fails, we need the incoming values of 'weight' and 'parent'
+  // to display rows with the correct order and indentation.
+  $post = $form_state['post'];
+
+  $field_rows = array_merge($form['#fields'], array('_add_new_field', '_add_existing_field'));
+  $group_rows = array_merge($form['#groups'], array('_add_new_group'));
+
+  // Field rows: account for weight and parenting.
+  foreach ($field_rows as $name) {
+    // Account for weight.
+    if (isset($post[$name]['weight']) && is_numeric($post[$name]['weight'])) {
+      $dummy[$name]['#weight'] = $post[$name]['weight'];
+    }
+
+    // Account for parenting.
+    if (module_exists('fieldgroup')) {
+      // Consider incoming values first, then current group assignment.
+      if (isset($post[$name]['parent']) && in_array($post[$name]['parent'], $group_rows)) {
+        $form[$name]['#depth'] = 1;
+        $dummy[$post[$name]['parent']][$name] = $dummy[$name];
+        unset($dummy[$name]);
+      }
+      else {
+        foreach ($groups as $group_name => $group) {
+          if (isset($group['fields'][$name])) {
+            $form[$name]['#depth'] = 1;
+            $form[$name]['parent']['#default_value'] = $group_name;
+            $dummy[$group_name][$name] = $dummy[$name];
+            unset($dummy[$name]);
+            break;
+          }
+        }
+      }
+    }
+  }
+  // Group rows: account for weight.
+  if (module_exists('fieldgroup')) {
+    foreach ($group_rows as $name) {
+      if (isset($post[$name]['weight']) && is_numeric($post[$name]['weight'])) {
+        $dummy[$name]['#weight'] = $post[$name]['weight'];
+      }
+    }
+  }
+
   // Let drupal_render figure out the right order for the rows.
   $form['#order'] = explode(' ', trim(drupal_render($dummy)));
 
@@ -212,60 +306,240 @@
 }
 
 /**
- *  Theme the field overview table.
+ * Theme the field overview table.
  */
 function theme_content_admin_field_overview_form($form) {
-  if (empty($form['#order'])) {
-    return;
-  }
   $header = array(t('Label'), t('Weight'), t('Name'), t('Type'), t('Operations'));
   $rows = array();
 
-  foreach ($form['#order'] as $key) {
+  while ($form['#order']) {
     $row = array();
+    $key = reset($form['#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($form['#order'], array('_add_new_field', '_add_existing_field', '_add_new_group'));
+      if (empty($remaining_rows) && empty($element['#depth'])) {
+        $rows[] = array('data' => array(array('data' => t('Add'), 'colspan' => 4, 'class' => 'region')), 'class' => 'tabledrag-leaf region');
+        $added_separator = TRUE;
+      }
+    }
+
     $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);
-    }
-    else {
-      $row[] = drupal_render($element['name']);
-      $row[] = drupal_render($element['type']);
-      $row[] = drupal_render($element['configure']) .'&nbsp;&nbsp;'. drupal_render($element['remove']);
+    $indent = theme('indentation', isset($element['#depth']) ? $element['#depth'] : 0);
+    switch ($element['#row_type']) {
+      case 'field':
+        $row[] = $indent . drupal_render($element['label']);
+        // 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']);
+        $row[] = drupal_render($element['field_name']);
+        $row[] = drupal_render($element['type']);
+        $row[] = drupal_render($element['configure']) .'&nbsp;&nbsp;'. drupal_render($element['remove']);
+        break;
+      case 'group':
+        $element['label']['#prefix'] = '<strong>';
+        $element['label']['#suffix'] = '</strong>';
+        $row[] = $indent . drupal_render($element['label']);
+        $row[] = drupal_render($element['weight']) . drupal_render($element['parent']) . drupal_render($element['hidden_name']);
+        $row[] = drupal_render($element['group_name']);
+        $row[] = '';
+        $row[] = drupal_render($element['configure']) .'&nbsp;&nbsp;'. drupal_render($element['remove']);
+        break;
+      case 'extra':
+        $row[] = $indent . drupal_render($element['label']);
+        $row[] = drupal_render($element['weight']) . drupal_render($element['parent']) . drupal_render($element['hidden_name']);
+        $row[] = array('data' => drupal_render($element['description']), 'colspan' => 3);
+        break;
+      case '_add_new_field';
+        $element['type']['#attributes'] = array('class' => 'content-field-type-select');
+        $element['widget_type']['#attributes'] = array('class' => 'content-widget-type-select');
+        if (empty($element['label']['#value'])) {
+          $element['label']['#value'] = t('New field');
+          $element['label']['#attributes'] = array('class' => 'content-default-value');
+        }
+        $row[] = $indent . drupal_render($element['label']);
+        $row[] = drupal_render($element['weight']) . drupal_render($element['parent']) . drupal_render($element['hidden_name']);
+        $row[] = drupal_render($element['field_name']);
+        $row[] = drupal_render($element['type']);
+        $row[] = drupal_render($element['widget_type']);
+        break;
+      case '_add_existing_field':
+        $element['field_name']['#attributes'] = array('class' => 'content-field-select');
+        $element['widget_type']['#attributes'] = array('class' => 'content-widget-type-select');
+        $element['label']['#attributes'] = array('class' => 'content-label-textfield');
+        if (empty($element['label']['#value'])) {
+          $element['label']['#value'] = t('Existing field');
+          $element['label']['#attributes']['class'] .= ' content-default-value';
+        }
+        $row[] = $indent . drupal_render($element['label']);
+        $row[] = drupal_render($element['weight']) . drupal_render($element['parent']) . drupal_render($element['hidden_name']);
+        $row[] = array('data' => drupal_render($element['field_name']), 'colspan' => 2);
+        $row[] = drupal_render($element['widget_type']);
+        break;
+      case '_add_new_group':
+        if (empty($element['label']['#value'])) {
+          $element['label']['#value'] = t('New group');
+          $element['label']['#attributes'] = array('class' => 'content-default-value');
+        }
+        $row[] = $indent . drupal_render($element['label']);
+        $row[] = drupal_render($element['weight']) . drupal_render($element['parent']) . drupal_render($element['hidden_name']);
+        $row[] = '';
+        $row[] = '';
+        $row[] = '';
+        break;
     }
 
     $class = 'draggable';
     $class .= isset($element['#disabled_row']) ? ' menu-disabled' : '';
+    $class .= isset($element['#add_new']) ? ' content-add-new' : '';
     $class .= isset($element['#leaf']) ? ' tabledrag-leaf' : '';
     $class .= isset($element['#root']) ? ' tabledrag-root' : '';
     $rows[] = array('data' => $row, 'class' => $class);
+
+    array_shift($form['#order']);
   }
 
   $output  = theme('table', $header, $rows, array('id' => 'content-field-overview'));
-
+//  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');
 
-  // 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');
+  $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']);
+  }
+
+  $js_setting = array(
+    'contentWidgetTypes' => content_widget_type_options(),
+    'contentFields' => $js_fields,
+  );
+  drupal_add_js($js_setting, 'setting');
   drupal_add_js(drupal_get_path('module', 'content') .'/content.js');
+  drupal_add_css(drupal_get_path('module', 'content') .'/theme/content.css');
 
   $output .= drupal_render($form);
 
   return $output;
 }
 
+function content_admin_field_overview_form_validate($form, &$form_state) {
+  _content_admin_field_overview_form_validate_add_new($form, &$form_state);
+  _content_admin_field_overview_form_validate_add_existing($form, &$form_state);
+}
+
+/**
+ * Helper function for content_admin_field_overview_form_validate.
+ *
+ * Validate the 'add new field' row.
+ */
+function _content_admin_field_overview_form_validate_add_new($form, &$form_state) {
+  $field = $form_state['values']['_add_new_field'];
+
+  // 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.'));
+    }
+
+    // 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'];
+
+      // 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);
+      }
+
+      // 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."));
+      }
+
+      // 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)));
+      }
+    }
+
+    // No field type.
+    if (!$field['type']) {
+      form_set_error('_add_new_field][type', t('Add new field: you need to select a field type.'));
+    }
+
+    // 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.'));
+      }
+    }
+  }
+}
+
+/**
+ * Helper function for content_admin_field_overview_form_validate.
+ *
+ * Validate the 'add existing field' row.
+ */
+function _content_admin_field_overview_form_validate_add_existing($form, &$form_state) {
+  $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_admin_field_overview_form_submit($form, &$form_state) {
   $form_values = $form_state['values'];
 
@@ -290,6 +564,49 @@
   }
 
   content_clear_type_cache();
+
+  // TODO : weights > 1000
+
+  // 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)) {
+      drupal_set_message(t('Created field %label.', array(
+        '%label' => $field['label'])));
+      $form_state['fields_added']['_add_new_field'] = $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)) {
+        drupal_set_message(t('Added field %label.', array(
+          '%label' => $field['field_name'])));
+        $form_state['fields_added']['_add_existing_field'] = $field['field_name'];
+      }
+      else {
+        drupal_set_message(t('There was a problem adding field %label.', array(
+          '%label' => $field['field_name'])));
+      }
+    }
+  }
 }
 
 /**
@@ -516,36 +833,56 @@
 
 /**
  * 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_admin_field_add_existing(&$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();
-
   $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'] .')';
     }
   }
-  if ($options) {
+  return $options;
+}
+
+function _content_admin_field_add_existing(&$form_state, $type_name) {
+  $form = array();
+  if ($options = content_existing_field_options($type_name)) {
     $form['existing'] = array(
       '#type' => 'fieldset',
       '#title' => t('Add existing field'),
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	11 Aug 2008 22:30:45 -0000
@@ -1,20 +1,73 @@
 // $Id: content.js,v 1.1 2008/03/02 23:18:08 yched Exp $
 
+Drupal.behaviors.cckManageFields = function(context) {
+  defaultValues(context);
+  updateSelects(context);
+};
+
 /**
- * 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');
-    }
-  }
+ * (borrowed from quicksketch's webforms.module)
+ **/
+function defaultValues(context) {
+  var fields = $('#content-field-overview .content-default-value', context);
+  var forms = fields.parents('form:first');
+  fields.each(function() {
+    this.defaultValue = this.value;
+    $(this).focus(function() {
+      if (this.value == this.defaultValue) {
+        this.value = '';
+        $(this).removeClass('content-default-value');
+      }
+    });
+    $(this).blur(function() {
+      if (this.value == '') {
+        $(this).addClass('content-default-value');
+        this.value = this.defaultValue;
+      }
+    });
+  });
+
+  // Clear all the form elements before submission.
+  forms.submit(function() {
+    fields.focus();
+  });
 };
 
+function updateSelects(context) {
+  $('#content-field-overview .content-field-type-select', context).each(function() {
+    $(this).change(function() {
+      var widgetTypes = Drupal.settings.contentWidgetTypes;
+      var selectedFieldType = this.options[this.selectedIndex].value;
+
+      var newOptions = widgetTypes[selectedFieldType];
+      var targetSelect = $('.content-widget-type-select', $(this).parents('tr'));
+      targetSelect.empty();
+      jQuery.each(newOptions, function(key, value) {
+        targetSelect.append('<option value="' + key + '">' + value + '</option>');
+      });
+    });
+  });
+
+  $('#content-field-overview .content-field-select', context).each(function() {
+    $(this).change(function() {
+      var widgetTypes = Drupal.settings.contentWidgetTypes;
+      var fields = Drupal.settings.contentFields;
+      var selectedField = this.options[this.selectedIndex].value;
+      var selectedFieldType = fields[selectedField].type;
+
+      var newOptions = widgetTypes[selectedFieldType];
+      var targetSelect = $('.content-widget-type-select', $(this).parents('tr'));
+      targetSelect.empty();
+      jQuery.each(newOptions, function(key, value) {
+        targetSelect.append('<option value="' + key + '">' + value + '</option>');
+      });
+
+      var selectedFieldLabel = fields[selectedField].label;
+      var targetTextfield = $('.content-label-textfield', $(this).parents('tr'));
+      targetTextfield
+        .attr('value', selectedFieldLabel)
+        .removeClass('content-default-value');
+    });
+  });
+}
+
