Index: filefield.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/filefield/filefield.module,v
retrieving revision 1.23
diff -u -r1.23 filefield.module
--- filefield.module	30 Mar 2007 03:20:24 -0000	1.23
+++ filefield.module	17 May 2007 17:40:08 -0000
@@ -13,7 +13,16 @@
 function filefield_menu($maycache) {
   $items = array();
 
-  if (!$may_cache && $_SESSION['filefield']) {
+  if ($maycache) {
+    $items[] = array(
+      'path' => 'filefield/js',
+      'callback' => 'filefield_js',
+      //'access' => user_access(),
+      'access' => TRUE,
+      'type' => MENU_CALLBACK
+    );
+  }
+  else if ($_SESSION['filefield']) {
     // Add handlers for previewing new uploads.
     foreach ($_SESSION['filefield'] as $fieldname => $files) {
       if (is_array($files)) {
@@ -276,7 +285,7 @@
   $fieldname = $field['field_name'];
   switch ($op) {
     case 'prepare form values':
-      _filefield_widget_prepare($node, $field, $node_field);
+      _filefield_widget_prepare_form_values($node, $field, $node_field);
       break;
 
     case 'form':
@@ -288,7 +297,7 @@
   }
 }
 
-function _filefield_widget_prepare($node, $field, &$node_field) {
+function _filefield_widget_prepare_form_values($node, $field, &$node_field) {
   $fieldname = $field['field_name'];
 
   // @todo split this into its own function. determine if we can make it a form element.
@@ -298,9 +307,9 @@
   // Attach new files 
   if ($file = file_check_upload($fieldname . '_upload')) {
     $file = (array)$file;
-    // test allowed extensions. We do this when the file is uploaded, rather than waiting for the
-    // field itseld to reach op==validate.
-    $ext = array_pop(explode('.',$file['filename']));
+    // test allowed extensions. We do this when the file is uploaded,
+    // rather than waiting for the field itself to reach op==validate.
+    $ext = array_pop(explode('.', $file['filename']));
     $allowed_extensions = array_unique(explode(' ', trim($field['widget']['file_extensions'])));
 
     $valid = in_array($ext, $allowed_extensions);
@@ -359,6 +368,9 @@
 }
 
 function _filefield_widget_form($node, $field, &$node_field) {
+  drupal_add_js('misc/progress.js');
+  drupal_add_js('misc/upload.js');
+
   $fieldname = $field['field_name'];
   drupal_add_css(drupal_get_path('module', 'filefield') .'/filefield.css');
  
@@ -370,21 +382,34 @@
     '#collapsible' => TRUE,
     '#collapsed' => FALSE,
     '#tree' => TRUE,
-    '#theme' => 'filefield_current',
+    '#prefix' => '<div id="'. form_clean_id($fieldname .'-attach-wrapper') .'">',
+    '#suffix' => '</div>',
   );
-  
-  $form[$fieldname][$fieldname .'_upload'] = array(
+
+  $form[$fieldname]['new'] = array(
+    '#tree' => FALSE,
+    '#prefix' => '<div id="'. form_clean_id($fieldname .'-attach-hide') .'">',
+    '#suffix' => '</div>',
+    '#weight' => 100,
+  );
+
+  // Separate 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'] . t('<br />allowed extensions(%ext)', array('%ext' => $field['widget']['file_extensions'])),
-    '#weight' => 9,
+    '#description' => $field['widget']['description'] .
+                      t('<br />allowed extensions(%ext)',
+                        array('%ext' => $field['widget']['file_extensions'])
+                      ),
     '#tree' => FALSE,
+    '#weight' => 9,
   );
 
-  $form[$fieldname]['update'] = array(
+  $form[$fieldname]['new']['upload'] = array(
     '#type' => 'button',
     '#value' => t('Upload'),
-    '#name' => 'cck_filefield_'.$fieldname.'_op',
-    '#attributes' => array('id' => $fieldname.'-attach-button'),
+    '#name' => 'cck_filefield_'. $fieldname .'_op',
+    '#id' => form_clean_id($fieldname .'-attach-button'),
     '#tree' => FALSE,
     '#weight' => 10,
   );
@@ -403,6 +428,31 @@
       }
     }
   }
+
+  // The class triggers the js upload behaviour.
+  $form[$fieldname.'-attach-url'] = array(
+    '#type' => 'hidden',
+    '#value' => url('filefield/js', NULL, NULL, TRUE),
+    '#attributes' => array('class' => 'upload')
+  );
+
+  // Some useful info for our js callback.
+  $form['vid'] = array(
+    '#type' => 'hidden',
+    '#value' => $node->vid,
+    '#tree' => FALSE,
+  );
+  $form['nid'] = array(
+    '#type' => 'hidden',
+    '#value' => $node->nid,
+    '#tree' => FALSE,
+  );
+  $form['type'] = array(
+    '#type' => 'hidden',
+    '#value' => $node->type,
+    '#tree' => FALSE,
+  );
+
   return $form;
 }
 
@@ -609,5 +659,49 @@
     $path = file_create_path(implode($dirs,'/'));
     file_check_directory($path, FILE_CREATE_DIRECTORY, $form_element['#parents'][0]);
   }
-  return true;
+  return TRUE;
+}
+
+/**
+ * Menu callback for JavaScript-based uploads.
+ */
+function filefield_js() {
+  // Parse fieldname from submit button.
+  $matches = array();
+  foreach(array_keys($_POST) as $key) {
+    if (preg_match('/cck_filefield_(.*)_op/', $key, $matches)) {
+      $fieldname = $matches[1];
+      break;
+    }
+  }
+
+  $node = (object)$_POST;
+  $field = content_fields($fieldname, $node->type); // load field data
+
+  // Load fids stored by content.module
+  $node_field = array();
+  $values = content_field('load', $node, $field, $node_field, FALSE, FALSE);
+  $node_field = $values[$fieldname];
+
+  // Load additional field data
+  filefield_field('load', $node, $field, $node_field, FALSE, FALSE);
+
+  // Handle uploads and validation.
+  _filefield_widget_prepare_form_values($node, $field, $node_field);
+  _filefield_widget_validate($node, $field, $node_field);
+
+  // Get our new form baby, yeah tiger, get em!
+  $form = _filefield_widget_form($node, $field, $node_field);
+
+  foreach (module_implements('form_alter') as $module) {
+    $function = $module .'_form_alter';
+    $function('filefield_js', $form);
+  }
+  $form = form_builder('filefield_js', $form);
+
+  $output = theme('status_messages') . drupal_render($form);
+
+  // We send the updated file attachments form.
+  print drupal_to_js(array('status' => TRUE, 'data' => $output));
+  exit();
 }
