? imagefield.js
Index: imagefield.css
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/imagefield/imagefield.css,v
retrieving revision 1.2.4.2
diff -u -p -r1.2.4.2 imagefield.css
--- imagefield.css	18 Apr 2008 10:31:40 -0000	1.2.4.2
+++ imagefield.css	29 Apr 2008 19:56:01 -0000
@@ -1,9 +1,3 @@
-div.imagefield-edit-image-row {
-  border: 1px solid #e5e5e5;
-  padding: 5px;
-  margin-bottom: 10px;
-}
-
 div.imagefield-edit-preview img {
   border: 1px solid #e5e5e5;
 }
@@ -29,3 +23,6 @@ div.imagefield-edit-image-flags div.form
   float: right;
 }
 
+div.imagefield-element input.form-submit {
+  margin: 0 0.5em 0 0;
+}
Index: imagefield.info
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/imagefield/imagefield.info,v
retrieving revision 1.4.4.2
diff -u -p -r1.4.4.2 imagefield.info
--- imagefield.info	6 Dec 2007 09:25:39 -0000	1.4.4.2
+++ imagefield.info	29 Apr 2008 19:56:01 -0000
@@ -1,5 +1,6 @@
 ; $Id: imagefield.info,v 1.4.4.2 2007/12/06 09:25:39 dopry Exp $
 name = Image Field
 description = Defines an image field type.
-dependencies = content
+core = 6.x
+dependencies[] = content
 package = CCK
Index: imagefield.install
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/imagefield/imagefield.install,v
retrieving revision 1.2.4.1
diff -u -p -r1.2.4.1 imagefield.install
--- imagefield.install	18 Apr 2007 21:02:19 -0000	1.2.4.1
+++ imagefield.install	29 Apr 2008 19:56:01 -0000
@@ -5,8 +5,29 @@
  * Implementation of hook_install().
  */
 function imagefield_install() {
+  content_notify('install', 'imagefield');
 }
 
+/**
+ * Implementation of hook_uninstall().
+ */
+function imagefield_uninstall() {
+  content_notify('uninstall', 'imagefield');
+}
+
+/**
+ * Implementation of hook_enable().
+ */
+function imagefield_enable() {
+  content_notify('enable', 'imagefield');
+}
+
+/**
+ * Implementation of hook_disable().
+ */
+function imagefield_disable() {
+  content_notify('disable', 'imagefield');
+}
 
 /**
  * Data is now stored in per-field tables.
@@ -73,6 +94,30 @@ function imagefield_update_2() {
   return $ret;
 }
 
+/**
+ * Upgrade to CCK 2 and Drupal 6.
+ */
+function imagefield_update_6100() {
+  include_once('./'. drupal_get_path('module', 'content') .'/content_crud.inc');
 
+  $fields = content_fields();
+  foreach ($fields as $field) {
+    // Convert max_number_images to CCK's multiple limit.
+    if ($field['type'] == 'image' && isset($field['widget']['max_number_images'])) {
+      if ($field['widget']['max_number_images'] == 0) {
+        $field['multiple'] = 1; // 1 means "Unlimited" in CCK.
+      }
+      elseif ($field['widget']['max_number_images'] == 1) {
+        $field['multiple'] = 0; // 0 means "Not Multiple" in CCK.
+      }
+      else {
+        $field['multiple'] == $field['widget']['max_number_images'];
+      }
+      $field = array_merge($field, $field['widget']);
+      content_field_instance_update($field);
+    }
+  }
 
+  return array();
+}
 
Index: imagefield.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/imagefield/imagefield.module,v
retrieving revision 1.30.2.6.2.50
diff -u -p -r1.30.2.6.2.50 imagefield.module
--- imagefield.module	18 Apr 2008 10:31:40 -0000	1.30.2.6.2.50
+++ imagefield.module	29 Apr 2008 19:56:01 -0000
@@ -1,5 +1,5 @@
 <?php
-// $Id: imagefield.module,v 1.30.2.6.2.50 2008/04/18 10:31:40 dopry Exp $
+// $Id: imagefield.module,v 1.30.2.6.2.56 2008/04/21 13:01:34 dopry Exp $
 
 /**
  * @file
@@ -12,55 +12,14 @@
 /**
  * Implementation of hook_menu().
  */
-function imagefield_menu($maycache) {
+function imagefield_menu() {
   $items = array();
-  if ($maycache) {
-    $items[] = array(
-      'path' => 'imagefield/js',
-      'callback' => 'imagefield_js',
-      //'access' => user_access(),
-      'access' => TRUE,
-      'type' => MENU_CALLBACK
-    );
-  }
-  elseif ($_SESSION['imagefield']) {
-    // do this variable_get once....
-    $download_method = variable_get('file_downloads', FILE_DOWNLOADS_PUBLIC);
-
-    // Iterate over each field stored in session imagefield looking
-    // for files in a preview state to add menu items for. This
-    // allows us to preview new uploads before a node is submitted.
-    foreach ($_SESSION['imagefield'] as $fieldname => $files) {
-      // move on to the next field if there is nothing to process in files.
-      if (empty($files)) continue;
-
-      foreach ($files as $delta => $file) {
-        // If the file is not a preview do not display it.
-        if (empty($file['preview']))  continue;
-
-        // filepath to pass into _imagefield_preview
-        $filepath = $file['preview'];
-
-        // build url path for private files menu item.
-        if ($download_method == FILE_DOWNLOADS_PRIVATE) {
-          // strip out the file_directory_path. It shouldn't be a part
-          // of the URL with private downloads.
-          if (strpos($file['preview'], file_directory_path()) !== FALSE) {
-            $file['preview'] = trim(substr($file['preview'], strlen(file_directory_path())), '\\/');
-          }
-          $file['preview'] = 'system/files/'. $file['preview'];
-        }
-
-        $items[] = array(
-          'path' => $file['preview'],
-          'callback' => '_imagefield_preview',
-          'callback arguments' => array($filepath),
-          'access' => TRUE,
-          'type' => MENU_CALLBACK,
-        );
-      }
-    }
-  }
+  $items['imagefield/js'] = array(
+    'page callback' => 'imagefield_js',
+    'access callback' => 'user_access',
+    'access arguments' => array('access content'),
+    'type' => MENU_CALLBACK,
+  );
   return $items;
 }
 
@@ -106,7 +65,10 @@ function imagefield_perm() {
  */
 function imagefield_field_info() {
   return array(
-    'image' => array('label' => 'Image'),
+    'image' => array(
+      'label' => t('Image'),
+      'description' => t('Store an image file and text for alt and title tags.'),
+    ),
   );
 }
 
@@ -115,14 +77,12 @@ function imagefield_field_info() {
  */
 function imagefield_field_settings($op, $field) {
   switch ($op) {
-    case 'callbacks':
-      return array('view' => CONTENT_CALLBACK_CUSTOM);
-
     case 'form':
       $form = array();
       $form['default'] = array(
         '#type' => 'fieldset',
         '#title' => t('Default image'),
+        '#element_validate' => array('_imagefield_field_settings_default_validate'),
       );
       // Present a thumbnail of the current default image.
       $form['default']['use_default_image'] = array(
@@ -134,7 +94,7 @@ function imagefield_field_settings($op, 
       if (!empty($field['default_image'])) {
         $form['default']['default_image_thumbnail'] = array(
           '#type' => 'markup',
-          '#value' => theme('imagefield_image', $field['default_image'], '', '', array('width' => '150'), FALSE),
+          '#value' => theme('imagefield_image', $field['default_image'], '', '', array('width' => '150'), false),
         );
       }
       $form['default']['default_image_upload'] = array(
@@ -150,24 +110,14 @@ function imagefield_field_settings($op, 
       );
       return $form;
 
-    case 'validate':
-      // We save the upload here because we can't know the correct
-      // file path until we save the file.
-      if ($file = file_check_upload('default_image_upload')) {
-        if ($file = file_save_upload('default_image_upload', file_directory_path())) {
-          form_set_value(array('#parents' => array('default_image')), (array) $file);
-        }
-      }
-
-      break;
     case 'save':
       return array('default_image', 'use_default_image');
 
     case 'database columns':
       $columns = array(
-        'fid' => array('type' => 'int', 'not null' => TRUE, 'default' => '0'),
-        'title' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => "''", 'sortable' => TRUE),
-        'alt' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => "''", 'sortable' => TRUE),
+        'fid' => array('type' => 'int', 'not null' => true, 'default' => '0'),
+        'title' => array('type' => 'varchar', 'length' => 255, 'not null' => true, 'default' => '', 'sortable' => true),
+        'alt' => array('type' => 'varchar', 'length' => 255, 'not null' => true, 'default' => '', 'sortable' => true),
       );
       return $columns;
 
@@ -184,6 +134,54 @@ function imagefield_field_settings($op, 
 }
 
 /**
+ * Element specific validation for imagefield default value.
+ *
+ * Validated in a separate function from imagefield_field() to get access
+ * to the $form_state variable.
+ */
+function _imagefield_field_settings_default_validate($element, &$form_state) {
+  // We save the upload here because we can't know the correct
+  // file path until we save the file.
+  if ($file = file_save_upload('default_image_upload', array(), file_directory_path())) {
+    $form_state['values']['default_image'] = (array)$file;
+  }
+  
+  return;
+  
+  // D6TODO: need to figure out where to put this code:
+      // We save the upload here because we can't know the correct
+      // file path until we save the file.
+      // Check of we got an new upload.
+      if (!$file = file_check_upload('default_image_upload')) {
+        break;
+      }
+      // figure steal the file extension and construct a filename for this  
+      // fields default image. This is standardized for default image handling 
+      // with private files.
+      $ext = array_pop(explode('.', $file->filename));
+      $filename = $field['field_name'] .'.'. $ext;
+      // verify the destination exists and is writeable...
+      $dst = file_create_path('imagefield_default_images/'. $filename);
+      if (!file_check_directory(dirname($dst), FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS)) {
+        form_set_error('default_image', t("The default image could not be uploaded. The destination(%d) does not exist or is not writable by the webserver.", array('%d' => $dst)));
+        break;
+      }  
+      // save the upload to it's resting place.
+      if (!$file = file_save_upload('default_image_upload', $dst)) {
+        form_set_error('default_image', t("The default image could not be uploaded. Failed saving to destination(%d).", array('%d' => $dst)));
+        break;
+      }
+      // remove the old one...
+      unlink($field['default_image']['filepath']);
+      // set the value of the form_item so we can store this in the settings 
+      // from validate.
+      form_set_value(array('#parents' => array('default_image')), (array) $file);
+      break;
+  
+  
+}
+
+/**
  * Custom filter for imagefield NOT NULL.
  */
 function imagefield_views_handler_filter_is_not_null($op, $filter, $filterinfo, &$query) {
@@ -191,25 +189,18 @@ function imagefield_views_handler_filter
     $query->ensure_table($filterinfo['table']);
     if ($filter['value']) {
       $qs = '%s.%s > 0';
+      $query->add_where($qs, $filterinfo['table'], $filterinfo['field']);
     }
     else {
       $qs = '%s.%s = 0 OR %s.%s IS NULL';
+      $query->add_where($qs, $filterinfo['table'], $filterinfo['field'], $filterinfo['table'], $filterinfo['field']);
     }
-    $query->add_where($qs, $filterinfo['table'], $filterinfo['field'], $filterinfo['table'], $filterinfo['field']);
   }
 
 }
 
-function imagefield_default_item() {
-  return array(
-    'fid' => 0,
-    'title' => '',
-    'alt' => '',
-  );
-}
-
 /**
- * Insert a file into the database.
+ * Make a temporary file permanent in the files table.
  *
  * @param $node
  *    Node object this file is be associated with.
@@ -217,32 +208,16 @@ function imagefield_default_item() {
  *    File to be inserted, passed by reference since fid should be attached.
  */
 function imagefield_file_insert($node, &$file, $field) {
-  $fieldname = $field['field_name'];
-
-  // allow tokenized paths.
-  if (function_exists('token_replace')) {
-    global $user;
-    $widget_image_path = token_replace($field['widget']['image_path'], 'user', $user);
-  }
-  else {
-    $widget_image_path = $field['widget']['image_path'];
+  if ($file['flags']['delete'] == TRUE) {
+    if (_imagefield_file_delete($file, $field['field_name'])) {
+      return array();
+    }
   }
-
-  $filepath = file_create_path($widget_image_path) .'/'. $file['filename'];
-
-  if (imagefield_check_directory($widget_image_path) && $file = file_save_upload((object)$file, $filepath)) {
+  elseif (isset($file['fid'])) {
+    $file = (object)$file;
+    file_set_status($file, FILE_STATUS_PERMANENT);
     $file = (array)$file;
-    $file['fid'] = db_next_id('{files}_fid');
-    db_query("INSERT into {files} (fid, nid, filename, filepath, filemime, filesize)
-             VALUES (%d, %d, '%s','%s','%s',%d)",
-            $file['fid'], $node->nid, $file['filename'], $file['filepath'], $file['filemime'], $file['filesize']);
-    module_invoke_all('imagefield_file', 'save', $file);
-    return (array)$file;
-  }
-  else {
-    // Include file name in upload error.
-    form_set_error(NULL, t('Image upload was unsuccessful.'));
-    return FALSE;
+    return $file;
   }
 }
 
@@ -257,20 +232,7 @@ function imagefield_file_insert($node, &
  *   The field definition for this image field.
  */
 function imagefield_file_update($node, &$file, $field) {
-  $file = (array)$file;
-  if ($file['flags']['delete'] == TRUE) {
-    if (_imagefield_file_delete($file, $field['field_name'])) {
-      return array();
-    }
-  }
-  if ($file['fid'] == 'upload') {
-    return imagefield_file_insert($node, $file, $field);
-  }
-  else {
-    // if fid is not numeric here we should complain.
-    // else we update the file table.
-  }
-  return $file;
+  return imagefield_file_insert($node, $file, $field);
 }
 
 /**
@@ -292,67 +254,82 @@ function imagefield_field($op, $node, $f
           $items[$delta] = array_merge($item, _imagefield_file_load($item['fid']));
         }
       }
-      $items = array_values($items); // compact deltas
+      $items = array_values(array_filter($items)); // compact deltas
       return array($fieldname => $items);
       break;
 
     // called before content.module defaults.
     case 'insert':
       foreach ($items as $delta => $item) {
-        $items[$delta] = imagefield_file_insert($node, $item, $field);
-        // Remove non-existant images from items
-        if (empty($items[$delta])) {
+        if (!empty($item['flags']['delete'])) {
           unset($items[$delta]);
         }
+        else {
+          $items[$delta] = imagefield_file_insert($node, $item, $field);
+        }
       }
-      $items = array_values($items); // compact deltas
-      imagefield_clear_field_session($fieldname);
+      $items = array_values(array_filter($items)); // compact deltas
       break;
 
     // called before content.module defaults.
     case 'update':
       foreach ($items as $delta => $item) {
-
-        // If we're dealing with a single value field, and we just received
-        // a new file item, we need to mark the existing (old) one for
-        // deletion.  Otherwise, it will become orphaned.
-        if (!$field['multiple'] && (count($items) > 1) && ($delta === 0)) {
-          $item['flags']['hidden'] = TRUE;
-          $item['flags']['delete'] = TRUE;
-        }
-
         // Update each file item.
         $items[$delta] = imagefield_file_update($node, $item, $field);
 
+        // D6TODO: not sure if this bit is still relevant it was added after quicksketch's patch:
         // If the file has been deleted, unset the file entry so that it's
         // actually deleted from the database, or at least set it to a
         // default item if CCK won't delete it.
         if (empty($items[$delta])) {
-          if ($field['multiple']) {
+          if ($field['multiple'] != 1) {
             unset($items[$delta]);
           }
         }
       }
+      $items = array_values(array_filter($items)); // compact deltas
+      break;
+
+    // D6TODO: need to review this code
+    case 'delete revision':
+      $db_info = content_database_info($field);
+      foreach ($items as $delta => $item) {
+        $references = db_result(db_query("SELECT count(vid) FROM {%s} WHERE nid=%d AND %s=%d and vid!=%d", $db_info['table'], $node->nid, $db_info['columns']['fid']['column'], $item['fid'], $node->vid));
+        if ($references || _imagefield_file_delete($item, $field['field_name'])) {
+          $items[$delta] = array();
+        }
+      }
       $items = array_values($items); // compact deltas
-      imagefield_clear_field_session($fieldname);
       break;
 
+    
     case 'delete':
       foreach ($items as $delta => $item) {
         _imagefield_file_delete($item, $field['field_name']);
       }
       break;
 
-    case 'view':
-      $context = $teaser ? 'teaser' : 'full';
-      $formatter = isset($field['display_settings'][$context]['format']) ? $field['display_settings'][$context]['format'] : 'default';
-      if ($field['use_default_image'] && empty($items) ) {
-        $items[0] = $field['default_image'];
-      }
+    case 'sanitize':
       foreach ($items as $delta => $item) {
-        $items[$delta]['view'] = content_format($field, $item, $formatter, $node);
+        // Cleanup $items during node preview.
+        if (empty($item['fid']) || !empty($item['flags']['delete']) || !empty($item['flags']['hidden'])) {
+          unset($items[$delta]);
+        }
+
+        // Load the complete file if a filepath is not available.
+        if (!empty($item['fid']) && empty($item['filepath'])) {
+          $items[$delta] = array_merge($item, _imagefield_file_load($item['fid']));
+        }
+
+        // Add nid so formatters can create a link to the node.
+        $items[$delta]['nid'] = $node->nid;
+      }
+
+      // If completely empty, check for a default image.
+      if (empty($items) && $field['use_default_image'] && $field['default_image']['fid']) {
+        $items[$field['default_image']['fid']] = $field['default_image'];
+        $items[$field['default_image']['fid']] = $node->nid;
       }
-      return theme('field', $node, $field, $items, $teaser, $page);
   }
 }
 
@@ -362,8 +339,10 @@ function imagefield_field($op, $node, $f
 function imagefield_widget_info() {
   return array(
     'image' => array(
-      'label' => 'Image',
+      'label' => t('Image'),
       'field types' => array('image'),
+      'multiple values' => CONTENT_HANDLE_MODULE,
+      'callbacks' => array('default value' => CONTENT_CALLBACK_CUSTOM),
     ),
   );
 }
@@ -373,9 +352,6 @@ function imagefield_widget_info() {
  */
 function imagefield_widget_settings($op, $widget) {
   switch ($op) {
-    case 'callbacks':
-      return array('default value' => CONTENT_CALLBACK_CUSTOM);
-
     case 'form':
       $form = array();
       $form['max_resolution'] = array(
@@ -394,13 +370,6 @@ function imagefield_widget_settings($op,
         '#size' => 6,
         '#description' => t('The maximum allowed image file size expressed in kilobytes. Set to 0 for no restriction.')
       );
-      $form['max_number_images'] = array(
-        '#type' => 'textfield',
-        '#title' => t('Maximum number of images'),
-        '#default_value' => $widget['max_number_images'] ? $widget['max_number_images'] : 0,
-        '#size' => 4,
-        '#description' => t('The maximum number of images allowed. Set to 0 for no restriction. This only applies if multiple values are enabled.')
-      );
       $form['image_path'] = array(
         '#type' => 'textfield',
         '#title' => t('Image path'),
@@ -435,13 +404,13 @@ function imagefield_widget_settings($op,
       return $form;
 
     case 'validate':
-      // strip slashes from the beginning and end of $widget['image_path']
-      $widget['image_path'] = trim($widget['image_path'], '\\/');
-      form_set_value(array('#parents' => array('image_path')),  $widget['image_path']);
+      if (substr($widget['image_path'], 0, 1) == '/' || substr($widget['image_path'], -1) == '/') {
+        form_set_error('image_path', t('Image paths should not start or end with slashes.'));
+      }
       break;
 
     case 'save':
-      return array('max_resolution', 'max_filesize', 'max_number_images', 'image_path', 'file_extensions', 'custom_alt', 'custom_title');
+      return array('max_resolution', 'max_filesize', 'image_path', 'file_extensions', 'custom_alt', 'custom_title');
   }
 }
 
@@ -449,7 +418,7 @@ function imagefield_widget_settings($op,
  * Implementation of hook_form_alter(). Set the appropriate
  * attibutes to allow file uploads on the field settings form.
  */
-function imagefield_form_alter($form_id, &$form) {
+function imagefield_form_alter(&$form, $form_state, $form_id) {
   if ($form_id == '_content_admin_field') {
     $form['#attributes'] = array('enctype' => 'multipart/form-data');
   }
@@ -464,57 +433,21 @@ function imagefield_form_alter($form_id,
  * @param $form_element
  *   A form element to throw an error on if the directory is not writable
  */
-function imagefield_check_directory($directory, $form_element = array()) {
+function imagefield_check_directory($directory, $fieldname = NULL) {
   foreach (explode('/', $directory) as $dir) {
     $dirs[] = $dir;
-    $path = file_create_path(implode($dirs, '/'));
-    file_check_directory($path, FILE_CREATE_DIRECTORY, $form_element['#parents'][0]);
-  }
-  return true;
-}
-
-function _imagefield_scale_image($file, $resolution = 0) {
-  $info = image_get_info($file['filepath']);
-  if ($info) {
-    list($width, $height) = explode('x', $resolution);
-    if ($width && $height) {
-      $result = image_scale($file['filepath'], $file['filepath'], $width, $height);
-      if ($result) {
-        $file['filesize'] = filesize($file['filepath']);
-        drupal_set_message(t('The image %filename was resized to fit within the maximum allowed resolution of %resolution pixels', array('%resolution' => $resolution, '%filename' => $file['filename'])));
-      }
-    }
-  }
-  return $file;
-}
-
-function imagefield_clear_session() {
-  if (is_array($_SESSION['imagefield']) && count($_SESSION['imagefield'])) {
-    foreach (array_keys($_SESSION['imagefield']) as $fieldname) {
-      imagefield_clear_field_session($fieldname);
+    $path = file_create_path(implode($dirs,'/'));
+    if (!file_check_directory($path, FILE_CREATE_DIRECTORY, $fieldname)) {
+      return FALSE;
     }
-    unset($_SESSION['imagefield']);
-  }
-}
-
-function imagefield_clear_field_session($fieldname) {
-  if (is_array($_SESSION['imagefield'][$fieldname]) && count($_SESSION['imagefield'][$fieldname])) {
-    foreach ($_SESSION['imagefield'][$fieldname] as $delta => $file) {
-      if (is_file($file['filepath'])) {
-        file_delete($file['filepath']);
-      }
-    }
-    unset($_SESSION['imagefield'][$fieldname]);
   }
+  return TRUE;
 }
 
 function _imagefield_file_delete($file, $fieldname) {
   if (is_numeric($file['fid'])) {
     db_query('DELETE FROM {files} WHERE fid = %d', $file['fid']);
   }
-  else {
-    unset($_SESSION['imagefield'][$fieldname][$file['sessionid']]);
-  }
   module_invoke_all('imagefield_file', 'delete', $file);
   return file_delete($file['filepath']);
 }
@@ -522,362 +455,270 @@ function _imagefield_file_delete($file, 
 /**
  * Implementation of hook_widget().
  */
-function imagefield_widget($op, &$node, $field, &$items) {
-  switch ($op) {
-    case 'default value':
-      return array();
-
-    case 'prepare form values':
-      _imagefield_widget_prepare_form_values($node, $field, $items);
-      return;
-
-    case 'form':
-      return _imagefield_widget_form($node, $field, $items);
+function imagefield_widget(&$form, &$form_state, $field, $items) {
+  $element = array(
+    '#type' => $field['widget']['type'],
+    '#title' => $field['widget']['label'],
+    '#weight' => $field['widget']['weight'],
+    '#default_value' => $items,
+    '#required' => $field['required'],
+    '#multiple' => $field['multiple'] == 0 ? FALSE : TRUE,
+    '#multiple_limit' => $field['multiple'] == 1 ? 0 : $field['multiple'],
+    '#element_validate' => array('_imagefield_widget_validate'),
+    '#field' => $field,
+  );
+  return $element;
+}
 
-    case 'validate':
-      _imagefield_widget_validate($node, $field, $items);
-      return;
-  }
+/**
+ * Implementation of hook_elements().
+ */
+function imagefield_elements() {
+  $elements = array();
+  $elements['image'] =  array(
+    '#input' => TRUE,
+    '#columns' => array('fid', 'title', 'alt'),
+    '#process' => array('imagefield_element_process'),
+  );
+  return $elements;
 }
 
-function _imagefield_widget_prepare_form_values(&$node, $field, &$items) {
+/**
+ * Process the image type element before displaying the field.
+ */
+function imagefield_element_process($element, $edit, &$form_state, $form) {
+  $field = $element['#field'];
   $fieldname = $field['field_name'];
-  // clean up the session if we weren't posted.
-  if (!count($_POST)) {
-    imagefield_clear_session();
-  }
-
-  // Attach new files
-  if ($file = file_check_upload($fieldname .'_upload')) {
-    $file = (array)$file;
-
-    // Validation must happen immediately after the image is uploaded so we
-    // can discard the file if it turns out not to be a valid mime type
-    $valid_image = _imagefield_widget_upload_validate($node, $field, $items, $file);
-    //$valid_image = TRUE;
+  drupal_add_css(drupal_get_path('module', 'imagefield') .'/imagefield.css');
 
-    if ($valid_image) {
-      $file = _imagefield_scale_image($file, $field['widget']['max_resolution']);
+  // Pull in form state saved in storage.
+  form_get_cache($form_state['values']['form_build_id'], $form_state);
+  if (isset($form_state['storage'][$fieldname])) {
+    $form_state['values'][$fieldname] = $form_state['storage'][$fieldname];
+    // Unset the storage to keep the form from unnecessarily rebuilding.
+    unset($form_state['storage'][$fieldname]);
+  }
 
-      // Allow tokenized paths if available
-      if (function_exists('token_replace')) {
-        global $user;
-        $widget_image_path = token_replace($field['widget']['image_path'], 'user', $user);
-      }
-      else {
-        $widget_image_path = $field['widget']['image_path'];
-      }
-      imagefield_check_directory($widget_image_path);
-      $filepath = file_create_filename($file['filename'], file_create_path($widget_image_path));
+  // Change the type and theme to prevent FAPI from trying to output with the
+  // theme_image() function.
+  $element['#type'] = 'imagefield';
+  $element['#theme'] = 'imagefield';
+  $element['#tree'] = TRUE;
 
-      $file['fid'] = 'upload';
-      $file['preview'] = $filepath;
+  // Set an internal flag for requiredness. Prevents FAPI from interfering.
+  $element['#image_required'] = $element['#required'];
+  $element['#required'] = FALSE;
 
-      // If a single field, mark any other images for deletion and delete files in session
-      if (!$field['multiple']) {
-        if (is_array($items)) {
-          foreach ($items as $delta => $session_file) {
-            $items[$delta]['flags']['hidden'] = TRUE;
-            $items[$delta]['flags']['delete'] = TRUE;
-          }
-        }
-        imagefield_clear_field_session($fieldname);
-      }
-      // Add the file to the session
-      $file_id = count($items) + count($_SESSION['imagefield'][$fieldname]);
-      $file['sessionid'] = $file_id;
-      $_SESSION['imagefield'][$fieldname][$file_id] = $file;
+  $files = array();
+  if (isset($form_state['values'])) {
+    // Set a default value if available.
+    if (!isset($form_state[$fieldname]) && isset($element['#default_value'])) {
+      $form_state['values'][$fieldname] = $element['#default_value'];
     }
-    else {
-      // Delete the invalid file
-      file_delete($file['filepath']);
 
-      // If a single field and a valid file is in the session, mark existing image for deletion
-      if (!$field['multiple']) {
-        if (count($_SESSION['imagefield'][$fieldname]) && count($items)) {
-          foreach ($items as $delta => $session_file) {
-            $items[$delta]['flags']['hidden'] = TRUE;
-            $items[$delta]['flags']['delete'] = TRUE;
-          }
-        }
+    foreach ($form_state['values'][$fieldname] as $delta => $file) {
+      if (!empty($file['fid'])) {
+        $files[$file['fid']] = array_merge($file, _imagefield_file_load($file['fid']));
       }
     }
   }
 
-  // Load files from preview state. before committing actions.
-  if (is_array($_SESSION['imagefield'][$fieldname]) && count($_SESSION['imagefield'][$fieldname])) {
-    foreach ($_SESSION['imagefield'][$fieldname] as $delta => $file) {
-      $items[] = $file;
-    }
-  }
-}
-
-function _imagefield_widget_form($node, $field, &$items) {
-  drupal_add_js('misc/progress.js');
-  drupal_add_js('misc/upload.js');
-
-  $fieldname = $field['field_name'];
-  drupal_add_css(drupal_get_path('module', 'imagefield') .'/imagefield.css');
-
-  $form = array();
+  $form_state['values'][$fieldname] = $files;
+  $element['#files'] = $files;
 
-  $form[$fieldname] = array(
-    '#type' => 'fieldset',
-    '#title' => t($field['widget']['label']),
-    '#weight' => $field['widget']['weight'],
-    '#collapsible' => TRUE,
-    '#collapsed' => FALSE,
-    '#tree' => TRUE,
-    '#prefix' => '<div id="'. form_clean_id($fieldname .'-attach-wrapper') .'">',
-    '#suffix' => '</div>',
-  );
-
-  $form[$fieldname]['new'] = array(
-    '#tree' => FALSE,
-    '#prefix' => '<div id="'. form_clean_id($fieldname .'-attach-hide') .'">',
-    '#suffix' => '</div>',
-    '#weight' => 100,
-  );
-
-  $max_images = $field['widget']['max_number_images'];
-  if ($field['multiple'] && $max_images && $max_images <= count($items)) {
-    $form[$fieldname]['#prefix'] = '<div>';
-    $form[$fieldname]['new']['#prefix'] = '<div>';
-    $form[$fieldname]['new']['#value'] = format_plural($max_images, 'You can only attach one image to this field. Delete the image if you wish to be able to upload a different one.', 'You can only attach @count images to this field. Delete an image if you wish to be able to upload different images.');
-  }
-  else {
-    // Seperate from tree becase of that silly things won't be
-    // displayed if they are a child of '#type' = form issue
-    $form[$fieldname]['new'][$fieldname .'_upload'] = array(
-      '#type'  => 'file',
-      '#description' => $field['widget']['description'],
-      '#tree' => FALSE,
-      '#weight' => 9,
+  foreach ($files as $fid => &$file) {
+    dvm($file);
+    $element[$fid]['flags']['delete'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Delete'),
+      '#default_value' => isset($file['flags']['delete']) ? $file['flags']['delete'] : 0,
     );
 
-    $form[$fieldname]['new']['upload'] = array(
-      '#type' => 'button',
-      '#value' => t('Upload'),
-      '#name' => 'cck_imagefield_'. $fieldname .'_op',
-      '#id' => form_clean_id($fieldname .'-attach-button'),
-      '#tree' => FALSE,
-      '#weight' => 10,
+    $element[$fid]['admin_preview'] = array(
+      '#type' => 'markup',
+      '#value' => theme('imagefield_image', $file, $file['alt'], $file['title'], array('width' => '150'), FALSE),
     );
-    // The class triggers the js upload behaviour.
-    $form[$fieldname .'-attach-url'] = array('#type' => 'hidden', '#value' => url('imagefield/js', NULL, NULL, TRUE), '#attributes' => array('class' => 'upload'));
-  }
-
-  // @todo split following if block into its own function.
-  // Store the file data object to be carried on.
-  if (is_array($items) && count($items)) {
-    foreach ($items as $delta => $file) {
-      if ($file['filepath'] && !$file['flags']['hidden']) {
-        $form[$fieldname][$delta] = array(
-          '#theme' => 'imagefield_edit_image_row',
-        );
 
-        $form[$fieldname][$delta]['flags']['delete'] = array(
-          '#type' => 'checkbox',
-          '#title' => t('Delete'),
-          '#default_value' => isset($file['flags']['delete']) ? $file['flags']['delete'] : 0,
-        );
+    $element[$fid]['description'] = array(
+      '#type' => 'markup',
+      '#value' => '<strong>'. t('Filename: ') .'</strong>'. $file['filename'],
+    );
 
-        if (function_exists('token_replace')) {
-          global $user;
-          $filename = $file['fid'] == 'upload' ? file_create_filename($file['filename'], file_create_path(token_replace($field['widget']['image_path'], 'user', $user))) : $file['filepath'];
-        }
-        else {
-          $filename = $file['fid'] == 'upload' ? file_create_filename($file['filename'], file_create_path($field['widget']['image_path'])) : $file['filepath'];
-        }
+    $element[$fid]['alt'] = array(
+      '#type' => 'hidden',
+      '#value' => $file['filename'],
+    );
+    // overwrite with an input field if custom_alt is flagged;
+    if ($field['widget']['custom_alt']) {
+      $element[$fid]['alt'] = array(
+        '#type' => 'textfield',
+        '#title' =>  t('Alternate text'),
+        '#default_value' => $file['alt'],
+        '#description' => t('Alternate text to be displayed if the image cannot be displayed.'),
+        '#maxlength' => 255,
+        '#size' => 10,
+      );
+    }
 
-        $form[$fieldname][$delta]['admin_preview'] = array(
-          '#type' => 'markup',
-          '#value' => theme('imagefield_image', $file, $file['alt'], $file['title'], array('width' => '150'), FALSE),
-        );
+    $element[$fid]['title'] = array(
+      '#type' => 'hidden',
+      '#value' => $file['filename'],
+    );
+    // overwrite with an input field if custom_title is flagged;
+    if ($field['widget']['custom_title']) {
+      $element[$fid]['title'] = array(
+        '#type' => 'textfield',
+        '#title' =>  t('Title'),
+        '#default_value' =>  $file['title'],
+        '#description' => t('Text to be displayed on mouse overs.'),
+        '#maxlength' => 255,
+        '#size' => 10,
+      );
+    }
 
-        $form[$fieldname][$delta]['description'] = array(
-          '#type' => 'markup',
-          '#value' => '<strong>'. t('Filename: ') .'</strong>'. $file['filename'],
-        );
+    if ($file['filepath'] && !empty($file['flags']['hidden'])) {
+      // Render all the form values of this item if it is hidden.
+      $element[$fid]['title'] = array('#type' => 'value', '#value' => $file['title']);
+      $element[$fid]['alt'] = array('#type' => 'value', '#value' => $file['alt']);
+      $element[$fid]['flags']['delete'] = array('#type' => 'value', '#value' => !empty($file['flags']['delete']));
+    }
 
-        $form[$fieldname][$delta]['alt'] = array(
-          '#type' => 'hidden',
-          '#value' => $file['filename'],
-        );
-        // overwrite with an input field if custom_alt is flagged;
-        if ($field['widget']['custom_alt']) {
-          $form[$fieldname][$delta]['alt'] = array(
-            '#type' => 'textfield',
-            '#title' =>  t('Alternate text'),
-            '#default_value' => $file['alt'],
-            '#description' => t('Alternate text to be displayed if the image cannot be displayed.'),
-            '#maxlength' => 255,
-            '#size' => 10,
-          );
-        }
+    if ($element['#multiple']) {
+      $element[$fid]['weight'] = array(
+        '#type' => 'weight',
+        '#delta' => max('10', count($element['#files'])),
+      );
+    }
 
-        $form[$fieldname][$delta]['title'] = array(
-          '#type' => 'hidden',
-          '#value' => $file['filename'],
-        );
-        // overwrite with an input field if custom_title is flagged;
-        if ($field['widget']['custom_title']) {
-          $form[$fieldname][$delta]['title'] = array(
-            '#type' => 'textfield',
-            '#title' =>  t('Title'),
-            '#default_value' =>  $file['title'],
-            '#description' => t('Text to be displayed on mouse overs.'),
-            '#maxlength' => 255,
-            '#size' => 10,
-          );
-        }
+    $element[$fid]['flags']['hidden'] = array('#type' => 'value', '#value' => !empty($file['flags']['hidden']));
+    $element[$fid]['filename'] = array('#type' => 'value',  '#value' => $file['filename']);
+    $element[$fid]['filepath'] = array('#type' => 'value',  '#value' => $file['filepath']);
+    $element[$fid]['filemime'] = array('#type' => 'value',  '#value' => $file['filemime']);
+    $element[$fid]['filesize'] = array('#type' => 'value',  '#value' => $file['filesize']);
+    $element[$fid]['fid'] = array('#type' => 'hidden',  '#value' => $file['fid']);
+  }
 
-        // Special handling for single value fields
-        if (!$field['multiple']) {
-          $form[$fieldname][$delta]['replace'] = array(
-            '#type' => 'markup',
-            '#value' => t('If a new image is chosen, the current image will be replaced upon submitting the form.'),
-          );
-        }
-      }
-      elseif ($file['filepath'] && $file['flags']['hidden']) {
-        // Render all the form values of this item if it is hidden.
-        $form[$fieldname][$delta]['flags']['hidden'] = array('#type' => 'value', '#value' => $file['flags']['hidden']);
-        $form[$fieldname][$delta]['flags']['delete'] = array('#type' => 'value', '#value' => $file['flags']['delete']);
-        $form[$fieldname][$delta]['title'] = array('#type' => 'value', '#value' => $file['title']);
-        $form[$fieldname][$delta]['alt'] = array('#type' => 'value', '#value' => $file['alt']);
-      }
-      if (isset($file['sessionid'])) {
-        $form[$fieldname][$delta]['sessionid'] = array('#type' => 'value',  '#value' => $file['sessionid']);
-      }
-      $form[$fieldname][$delta]['filename'] = array('#type' => 'value',  '#value' => $file['filename']);
-      $form[$fieldname][$delta]['filepath'] = array('#type' => 'value',  '#value' => $file['filepath']);
-      $form[$fieldname][$delta]['preview'] = array('#type' => 'value',  '#value' => $file['preview']);
-      $form[$fieldname][$delta]['filemime'] = array('#type' => 'value',  '#value' => $file['filemime']);
-      $form[$fieldname][$delta]['filesize'] = array('#type' => 'value',  '#value' => $file['filesize']);
-      $form[$fieldname][$delta]['fid'] = array('#type' => 'value',  '#value' => $file['fid']);
-    }
+  // Special handling for single value fields
+  if (!$element['#multiple'] && count($element['#files'])) {
+    $element['replace'] = array(
+      '#type' => 'markup',
+      '#value' => t('If a new image is chosen, the current image will be replaced upon submitting the form.'),
+    );
+  }
+  elseif ($element['#multiple_limit'] != 0 && $element['#multiple_limit'] <= count($element['#files'])) {
+    $element['replace'] = array(
+      '#type' => 'markup',
+      '#value' => format_plural($element['#multiple_limit'], 'You can only attach one image to this field. Delete the image if you wish to be able to upload a different one.', 'You can only attach @count images to this field. Delete an image if you wish to be able to upload different images.'),
+    );
   }
 
-  // Some useful info for our js callback.
-  $form['vid'] = array(
-    '#type' => 'hidden',
-    '#value' => $node->vid,
+  // Seperate from tree becase of that silly things won't be
+  // displayed if they are a child of '#type' = form issue
+  $element['new'][$fieldname .'_upload'] = array(
+    '#type'  => 'file',
+    '#title' => $field['widget']['label'],
+    '#description' => $field['widget']['description'],
     '#tree' => FALSE,
+    '#weight' => 9,
   );
-  $form['nid'] = array(
-    '#type' => 'hidden',
-    '#value' => $node->nid,
-    '#tree' => FALSE,
-  );
-  $form['type'] = array(
-    '#type' => 'hidden',
-    '#value' => $node->type,
-    '#tree' => FALSE,
+
+  $element['new']['upload'] = array(
+    '#type' => 'button',
+    '#value' => t('Upload'),
+    '#ahah' => array(
+      'wrapper' => $element['#id'] .'-wrapper',
+      'path' => 'imagefield/js/'. $field['type_name'] .'/'. $field['field_name'],
+      'progress' => array('type' => 'bar', 'message' => t('Uploading image...')),
+    ),
+    '#weight' => 10,
   );
 
-  return $form;
+  return $element;
 }
 
 /**
  * Validate the widget.
  */
-function _imagefield_widget_validate($node, $field, $items) {
-
-  if ($field['required']) {
-    // Sum all the items marked for deletion, so we can make sure the end user
-    // isn't deleting all of the images.
-    $deleted = 0;
-    foreach ($items as $item) {
-      if ($item['flags']['delete']) {
-        $deleted++;
-      }
-    }
+function _imagefield_widget_validate($element, &$form_state) {
+  $field = $element['#field'];
+  $fieldname = $field['field_name'];
+  $items =& $form_state['values'][$fieldname];
+  unset($items['new']);
 
-    if (!count($items)) {
-      form_set_error($field['field_name'], t('@field is required. Please upload an image.', array('@field' => $field['widget']['label'])));
-    }
-    else if (count($items) == $deleted ) {
-      form_set_error($field['field_name'],  t('@field is required. Please uncheck at least one delete checkbox or upload another image.', array('@field' => $field['widget']['label'])));
-    }
+  // Allow tokenized paths.
+  if (function_exists('token_replace')) {
+    global $user;
+    $widget_image_path = token_replace($field['widget']['image_path'], 'user', $user);
+  }
+  else {
+    $widget_image_path = $field['widget']['image_path'];
   }
-}
 
-function _imagefield_widget_upload_validate($node, $field, $items, $file) {
-  // initialize our validation state, innocent until proven guilty.
-  $valid = TRUE;
+  $validators = array(
+    'file_validate_extensions' => array($field['widget']['file_extensions']),
+    'file_validate_size' => array($field['widget']['max_filesize']),
+    'file_validate_image_resolution' => array($field['widget']['max_resolution']),
+  );
 
-  // Do we even need to test file extensions?
-  if (!empty($field['widget']['file_extensions'])) {
-    // Pop out the extensions and turn file_extensions into an array.
-    $ext = strtolower(array_pop(explode('.', $file['filename'])));
-    $allowed_extensions = array_unique(explode(' ', strtolower(trim($field['widget']['file_extensions']))));
-    // Is it the file extension in the allowed_extensions array?
-    if (!in_array($ext, $allowed_extensions)) {
-      // Sorry no..
-      form_set_error($field['field_name'], t('Files with the extension %ext are not allowed. Please upload a file with an extension from the following list: %allowed_extensions', array('%ext' => $ext, '%allowed_extensions' => $field['widget']['file_extensions'])));
-      $valid = FALSE;
-    }
-  }
+  $complete_image_path = file_directory_path() .'/'. $widget_image_path;
 
-  // If max filesize is set.
-  if (!empty($field['widget']['max_filesize'])) {
-    if ($file['filesize'] > ($field['widget']['max_filesize'] * 1024)) {
-      form_set_error($field['field_name'], t('The file you uploaded has a filesize greater than the maximum allowed filesize of %sizekb.', array('%size' => $field['widget']['max_filesize'])));
-      $valid = FALSE;
+  // Attach new files.
+  if (imagefield_check_directory($widget_image_path, $fieldname .'_upload') && $file = file_save_upload($fieldname .'_upload', $validators, $complete_image_path)) {
+    // If a single field, mark any other images for deletion.
+    if (count($items)) {
+      foreach ($items as $delta => $item_file) {
+        if (!$element['#multiple']) {
+          $items[$delta]['flags']['hidden'] = TRUE;
+          $items[$delta]['flags']['delete'] = TRUE;
+        }
+        if (empty($items[$delta]['fid'])) {
+          unset($items[$delta]);
+        }
+      }
     }
+
+    $file = (array)$file;
+    $items[$file['fid']] = $file;
   }
 
-  // Is the mime type a match for image.
-  if (strpos($file['filemime'], 'image/') !== 0) {
-    // sorry no it isn't. do not pass go, do not collect $200.
-    form_set_error($field['field_name'], t('Mime Type mismatch. Only image files may be upload. You uploaded a file with mime type: %mime', array('%mime' => $file['filemime'])));
-    $valid = FALSE;
+  // Sum all the items marked for deletion.
+  $deleted = 0;
+  foreach ($items as $delta => $item) {
+    if (is_numeric($delta) && !empty($item['flags']['delete'])) {
+      $deleted++;
+    }
   }
 
-  // If max number of images is set
-  if ($field['multiple'] && !empty($field['widget']['max_number_images'])) {
-    $count = count($items) + count($_SESSION['imagefield'][$field['field_name']]);
-    if ($count >= $field['widget']['max_number_images']) {
-      form_set_error($field['field_name'], t('You are only allowed to upload up to %maximages images.', array('%maximages' => $field['widget']['max_number_images'])));
-      $valid = FALSE;
+  // Insure at least one image is going to be saved.
+  if ($element['#image_required']) {
+    if (!count($items)) {
+      form_set_error($field['field_name'] .'_upload', t('@field is required. Please upload an image.', array('@field' => $field['widget']['label'])));
+    }
+    else if (count($items) == $deleted ) {
+      form_set_error($field['field_name'] .'_upload',  t('@field is required. Please uncheck at least one delete checkbox or upload another image.', array('@field' => $field['widget']['label'])));
     }
   }
 
-  return $valid;
+  // Prevent more than the maximum limit.
+  if ($element['#multiple'] && $element['#multiple_limit'] != 0 && count($items) - $deleted > $element['#multiple_limit']) {
+    form_set_error($field['field_name'] .'_upload', t('You are only allowed to upload up to %maximages images.', array('%maximages' => $element['#multiple_limit'])));
+  }
 }
 
-
 /**
  * Implementation of hook_field_formatter_info().
  */
 function imagefield_field_formatter_info() {
   $formatters = array(
     'default' => array(
-      'label' => 'Default',
+      'label' => t('Default'),
       'field types' => array('image'),
     ),
   );
   return $formatters;
 }
-
-/**
- * Implementation of hook_field_formatter().
- */
-function imagefield_field_formatter($field, $item, $formatter, $node = NULL) {
-  if (empty($item['fid']) && $field['use_default_image']) {
-    $item = $field['default_image'];
-  }
-  // If there is no image on the database, use default.
-  if (empty($item['filepath'])) {
-    $item = array_merge($item, _imagefield_file_load($item['fid']));
-  }
-  if (!empty($item['filepath'])) {
-    return theme('imagefield_image', $item, $item['alt'], $item['title']);
-  }
-}
-
-function _imagefield_file_load($fid = NULL) {
+  
+function _imagefield_file_load($fid = null) {
   // Don't bother if we weren't passed and fid.
   if (!empty($fid) && is_numeric($fid)) {
     $result = db_query('SELECT * FROM {files} WHERE fid = %d', $fid);
@@ -890,11 +731,96 @@ function _imagefield_file_load($fid = NU
   return array();
 }
 
-function theme_imagefield_view_image($file, $alt = '', $title = '', $attributes = NULL, $getsize = TRUE) {
-  return theme('imagefield_image', $file, $alt, $title, $attributes , $getsize);
+/**
+ * Implementation of hook_theme().
+ */
+function imagefield_theme() {
+  return array(
+    'imagefield_image' => array(
+      'arguments' => array('file' => null, 'alt' => '', 'title' => '', 'attributes' => null, 'getsize' => TRUE),
+    ),
+    'imagefield' => array(
+      'arguments' => array('element' => null),
+    ),
+    'imagefield_row' => array(
+      'arguments' => array('element' => null),
+    ),
+    'imagefield_formatter_default' => array(
+      'arguments' => array('element' => null),
+    ),
+  );
+}
+
+/**
+ * Theme function for 'default' text field formatter.
+ */
+function theme_imagefield_formatter_default($element) {
+  $item = $element['#item'];
+
+  if (!empty($item['filepath'])) {
+    return theme('imagefield_image', $item, $item['alt'], $item['title']);
+  }
+}
+
+/**
+ * FormAPI theme function. Theme the output of an image field.
+ */
+function theme_imagefield(&$element) {
+  $output = '';
+
+  // Always add tabledrag in case a table is created after uploads.
+  if ($element['#multiple']) {
+    drupal_add_tabledrag($element['#id'] .'-table', 'order', 'sibling', $element['#id'] .'-weight');
+  }
+
+  // Print out the existing images.
+  if ($element['#multiple'] && !empty($element['#files'])) {
+    $rows = array();
+    foreach ($element['#files'] as $fid => $file) {
+      $element[$fid]['weight']['#attributes']['class'] = isset($element[$fid]['weight']['#attributes']['class']) ? ($element[$fid]['weight']['#attributes']['class'] .' '. $element['#id'] .'-weight') : $element['#id'] .'-weight';
+
+      $row = array();
+      $row[] = array('data' => '', 'class' => 'content-multiple-drag');
+      $row[] = theme('imagefield_row', $element[$fid]);
+      $row[] = drupal_render($element[$fid]['weight']);
+      $rows[] = array('data' => $row, 'class' => 'draggable');
+    }
+
+    $existing_items = theme('table', array(), $rows, array('id' => $element['#id'] .'-table'));
+  }
+  elseif (!empty($element['#files'])) {
+    foreach ($element['#files'] as $file) {
+      if ($file['fid'] && empty($file['flags']['hidden'])) {
+        $existing_items = '<div class="clear-block">'. theme('imagefield_row', $element[$file['fid']]) .'</div>';
+        break;
+      }
+    }
+  }
+
+  if (isset($existing_items)) {
+    $existing_element = array(
+      '#type' => 'element',
+      '#title' => $element['#title'],
+      '#required' => $element['#image_required'],
+    );
+    $output .= theme('form_element', $existing_element, $existing_items);
+    unset($element['new'][$element['#field']['field_name'] .'_upload']['#title']);
+  }
+  else {
+    $element['new'][$element['#field']['field_name'] .'_upload']['#required'] = $element['#image_required'];
+  }
+
+  // Additional image information and upload controls.
+  if (isset($element['replace'])) {
+    $output .= '<div class="imagefield-edit-image-replace">'. drupal_render($element['replace']) .'</div>';
+  }
+  $output .= drupal_render($element['new']);
+  $output = '<div id="'. $element['#id'] .'-wrapper" class="imagefield-element clear-block">'. $output .'</div>';
+
+  return $output;
 }
 
-function theme_imagefield_edit_image_row($element) {
+function theme_imagefield_row($element) {
   $output = '<div class="imagefield-edit-preview">'. drupal_render($element['admin_preview']) .'</div>';
   $output .= '<div class="imagefield-edit-image-detail">';
   $output .= '<div class="imagefield-edit-image-flags">'. drupal_render($element['flags']) .'</div>';
@@ -902,43 +828,31 @@ function theme_imagefield_edit_image_row
   $output .= '</div>';
   $output .= drupal_render($element['alt']);
   $output .= drupal_render($element['title']);
+  $output .= drupal_render($element['fid']);
   $output .= '</div>';
-  $output = '<div class="imagefield-edit-image-row clear-block">'. $output .'</div>';
   if (isset($element['replace'])) {
     $output .= '<div class="imagefield-edit-image-replace">'. drupal_render($element['replace']) .'</div>';
   }
   return $output;
 }
 
-function theme_imagefield_image($file, $alt = '', $title = '', $attributes = NULL, $getsize = TRUE) {
+function theme_imagefield_image($file, $alt = '', $title = '', $attributes = null, $getsize = true) {
   $file = (array)$file;
   if (!is_file($file['filepath'])) {
     return;
   }
+  $image_attributes = array();
   if (!$getsize || (list($width, $height, $type, $image_attributes) = @getimagesize($file['filepath']))) {
     $attributes = drupal_attributes($attributes);
-    $path = ($file['fid'] == 'upload') ? $file['preview'] : $file['filepath'];
     $alt = empty($alt) ? $file['alt'] : $alt;
     $title = empty($title) ? $file['title'] : $title;
-    $url = file_create_url($path);
+    $url = file_create_url($file['filepath']);
     return '<img src="'. check_url($url) .'" alt="'.
         check_plain($alt) .'" title="'. check_plain($title) .'" '. $image_attributes . $attributes .' />';
   }
 }
 
 /**
- * Formats an array of images.
- *
- * @param images
- *    array of individually themed images
- * @return
- *    html string
- */
-function theme_imagefield_multiple($images) {
-  return implode("\n", $images);
-}
-
-/**
  * Implementation of hook_file_download().
  * Replicated from upload.module.
  *
@@ -948,12 +862,20 @@ function theme_imagefield_multiple($imag
 
 if (!function_exists('upload_file_download')) {
   function imagefield_file_download($file) {
-    $file = file_create_path($file);
+    // if this isn't a default image look it up from the db...
+    if (strpos($file, 'imagefield_default_images') !== false) {
+      $fieldname = array_shift(explode('.', basename($file)));
+      $field = content_fields($fieldname);
+      $file = $field['default_image'];
+    }
+    else {
+      $file = file_create_path($file);
 
-    $result = db_query("SELECT f.* FROM {files} f WHERE filepath = '%s'", $file);
-    if (!$file = db_fetch_object($result)) {
-      // We don't really care about this file.
-      return;
+      $result = db_query("SELECT f.* FROM {files} f WHERE filepath = '%s'", $file);
+      if (!$file = db_fetch_object($result)) {
+        // We don't really care about this file.
+        return;
+      }
     }
 
     // @todo: check the node for this file to be referenced in a field
@@ -964,11 +886,16 @@ if (!function_exists('upload_file_downlo
       return -1;
     }
 
-    $node = node_load($file->nid);
-    if (!node_access('view', $node)) {
-      // You don't have permission to view the node
-      // this file is attached to.
-      return -1;
+    // @hack: default images dont' have nids....
+    // I'm not going to bother checking perms for default images...
+    // it's a bug, but we'll resolve it later.
+    if (!empty($file->nid)) {
+      $node = node_load($file->nid);
+      if (!node_access('view', $node)) {
+        // You don't have permission to view the node
+        // this file is attached to.
+        return -1;
+      }
     }
 
     // Well I guess you can see this file.
@@ -988,54 +915,43 @@ if (!function_exists('upload_file_downlo
 /**
  * Menu-callback for JavaScript-based uploads.
  */
-function imagefield_js() {
-  // Parse fieldname from submit button.
-  $matches = array();
-  foreach (array_keys($_POST) as $key) {
-    if (preg_match('/cck_imagefield_(.*)_op/', $key, $matches)) {
-      break;
-    }
-  }
-  $fieldname = $matches[1];
+function imagefield_js($node_type, $fieldname) {
+  $field = content_fields($fieldname, $node_type);
 
-  $node = (object)$_POST;
-  // Load field data.
-  $field = content_fields($fieldname, $node->type);
+  $form_state = array('values' => $_POST);
+  $form_state['values'][$fieldname] = isset($form_state['values'][$fieldname]) ? $form_state['values'][$fieldname] : array();
 
-  // Load fid's stored by content.module
-  $items = array();
-  $values  = content_field('load', $node, $field, $items, FALSE, FALSE);
-  $items = $values[$fieldname];
-
-  // Load additional field data
-  imagefield_field('load', $node, $field, $items, FALSE, FALSE);
-
-  // Handle uploads and validation.
-  _imagefield_widget_prepare_form_values($node, $field, $items);
-  _imagefield_widget_validate($node, $field, $items);
+  // Load in the form cache.
+  $form = form_get_cache($_POST['form_build_id'], $form_state);
 
-  if (is_array($node->{$fieldname}) && count($node->{$fieldname}) > 0) {
-    foreach ($node->{$fieldname} as $key => $image) {
-      // Set the alt and title from POST
-      $items[$key]['alt'] = $image['alt'];
-      $items[$key]['title'] = $image['title'];
-      $items[$key]['flags']['delete'] = $image['flags']['delete'];
-    }
+  // Find field group if needed and assign the form element by reference.
+  if (function_exists('fieldgroup_get_group') && $group = fieldgroup_get_group($node_type, $fieldname)) {
+    $form_element =& $form[$group][$fieldname];
+  }
+  else {
+    $form_element =& $form[$fieldname];
   }
 
-  // Get our new form baby, yeah tiger, get em!
-  $form = _imagefield_widget_form($node, $field, $items);
+  // Handle new uploads.
+  _imagefield_widget_validate($form_element, $form_state);
 
-  foreach (module_implements('form_alter') as $module) {
-    $function = $module .'_form_alter';
-    $function('imagefield_js', $form);
-  }
-  $form = form_builder('imagefield_js', $form);
+  // Add the new element to the stored form and form_state then resave.
+  $form_element = imagefield_widget($form, $form_state, $field, $form_state['values'][$fieldname]);
+  $form_state['storage'][$fieldname] = $form_state['values'][$fieldname];
+  form_set_cache($_POST['form_build_id'], $form, $form_state);
 
-  $output =  theme('status_messages') . drupal_render($form);
+  // Render the form for output.
+  $form['#post'] = $_POST;
+  $form['#programmed'] = TRUE;
+  $form_state['submitted'] = FALSE;
+
+  drupal_alter('form', $form, $form_state, 'imagefield_js');
+  $form = form_builder('imagefield_js', $form, $form_state);
+  $output = theme('status_messages') . drupal_render($form_element);
 
   // We send the updated file attachments form.
   print drupal_to_js(array('status' => TRUE, 'data' => $output));
+
   exit;
 
 }
