Index: filefield.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/filefield/filefield.module,v
retrieving revision 1.176
diff -u -r1.176 filefield.module
--- filefield.module	19 Mar 2009 03:43:37 -0000	1.176
+++ filefield.module	20 Mar 2009 04:51:22 -0000
@@ -33,6 +33,12 @@
     'access arguments' => array(3),
     'type' => MENU_CALLBACK,
   );
+  $items['filefield/progress'] = array(
+    'page callback' => 'filefield_progress',
+    'access arguments' => array('access content'),
+    'type' => MENU_CALLBACK,
+  );
+
   return $items;
 }
 
@@ -492,6 +498,70 @@
 }
 
 /**
+ * Menu callback for upload progress.
+ */
+function filefield_progress($key) {
+  $progress = array(
+    'message' => t('Starting upload...'),
+    'percentage' => -1,
+  );
+
+  $implementation = filefield_progress_implementation();
+  if ($implementation == 'uploadprogress') {
+    $status = uploadprogress_get_info($key);
+    if (isset($status['bytes_uploaded']) && !empty($status['bytes_total'])) {
+      $progress['message'] = t('Uploading... (@current of @total)', array('@current' => filefield_bytes($status['bytes_uploaded']), '@total' => filefield_bytes($status['bytes_total'])));
+      $progress['percentage'] = round(100 * $status['bytes_uploaded'] / $status['bytes_total']);
+    }
+  }
+  elseif ($implementation == 'apc') {
+    $status = apc_fetch('upload_' . $key);
+    if (isset($status['current']) && !empty($status['total'])) {
+      $progress['message'] = t('Uploading... (@current of @total)', array('@current' => filefield_bytes($status['current']), '@total' => filefield_bytes($status['total'])));
+      $progress['percentage'] = round(100 * $status['current'] / $status['total']);
+    }
+  }
+
+  drupal_json($progress);
+}
+
+/**
+ * Determine which upload progress implementation to use, if any available.
+ */
+function filefield_progress_implementation() {
+  static $implementation;
+  if (!isset($implementation)) {
+    $implementation = FALSE;
+
+    // We prefer the PECL extension uploadprogress because it supports multiple
+    // simultaneous uploads. APC only supports one at a time.
+    if (extension_loaded('uploadprogress')) {
+      $implementation = 'uploadprogress';
+    }
+    elseif (extension_loaded('apc') && ini_get('apc.rfc1867')) {
+      $implementation = 'apc';
+    }
+  }
+  return $implementation;
+}
+
+/**
+ * Pretty-print a MB/KB value.
+ */
+function filefield_bytes($bytes) {
+  if ($bytes > 1073741824) {
+    return t('@size GB', array('@size' => round($bytes / 1073741824, 2)));
+  }
+  elseif ($bytes > 1048576) {
+    return t('@size MB', array('@size' => round($bytes / 1048576, 1)));
+  }
+  else {
+    return t('@size KB', array('@size' => round($bytes / 1024, 0)));
+  }
+}
+
+
+/**
  * Implementation of hook_file_references().
  */
 function filefield_file_references($file) {
Index: filefield.install
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/filefield/filefield.install,v
retrieving revision 1.26
diff -u -r1.26 filefield.install
--- filefield.install	20 Mar 2009 01:02:28 -0000	1.26
+++ filefield.install	20 Mar 2009 04:51:22 -0000
@@ -43,6 +43,56 @@
 }
 
 /**
+ * Implementation of hook_requirements().
+ *
+ * Display information about getting upload progress bars working.
+ */
+function filefield_requirements($phase) {
+  $requirements = array();
+  // Ensure translations don't break at install time
+  $t = get_t();
+
+  // Report Drupal version
+  if ($phase == 'runtime') {
+    $implementation = filefield_progress_implementation();
+    $apache = strpos($_SERVER["SERVER_SOFTWARE"], 'Apache') !== FALSE;
+    $php_52 = version_compare(phpversion(), '5.2.0', '>');
+    if (!$apache || !$php_52) {
+      $value = $t('Not enabled');
+      $description = $t('Your server is not capable of displaying file upload progress. File upload progress requires PHP 5.2 and an Apache server.');
+      $severity = REQUIREMENT_INFO;
+    }
+    elseif (!$implementation && extension_loaded('apc')) {
+      $value = $t('Not enabled');
+      $description = $t('Your server is capable of displaying file upload progress through APC, but it is not enabled. Add <code>apc.rfc1867 = 1</code> to your php.ini configuration. Alternatively, it is recommended to use <a href="http://pecl.php.net/package/uploadprogress">PECL uploadprogress</a>, which supports more than one simultaneous upload.');
+      $severity = REQUIREMENT_WARNING;
+    }
+    elseif (!$implementation) {
+      $value = $t('Not enabled');
+      $description = t('Your server is capable of displaying file upload progress, but does not have the required libraries. It is recommended to install the <a href="http://pecl.php.net/package/uploadprogress">PECL uploadprogress library<a> (prefered) or to install <a href="http://us2.php.net/apc">APC</a>.');
+      $severity = REQUIREMENT_WARNING;
+    }
+    elseif ($implementation == 'apc') {
+      $value = $t('Enabled (<a href="http://php.net/manual/en/apc.configuration.php#ini.apc.rfc1867">APC RFC1867</a>)');
+      $description = t('Your server is capable of displaying file upload progress using APC RFC1867. Note that only one upload at a time is supported. It is recommneded to use the <a href="http://pecl.php.net/package/uploadprogress">PECL uploadprogress library<a> if possible.');
+      $severity = REQUIREMENT_OK;
+    }
+    elseif ($implementation == 'uploadprogress') {
+      $value = $t('Enabled (<a href="http://pecl.php.net/package/uploadprogress">PECL uploadprogress</a>)');
+      $severity = REQUIREMENT_OK;
+    }
+    $requirements['filefield_progress'] = array(
+      'title' => $t('Upload progress'),
+      'value' => $value,
+      'severity' => $severity,
+      'description' => $description,
+    );
+  }
+
+  return $requirements;
+}
+
+/**
  * Implementation of hook_update_last_removed().
  */
 function filefield_update_last_removed() {
Index: filefield.css
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/filefield/filefield.css,v
retrieving revision 1.19
diff -u -r1.19 filefield.css
--- filefield.css	12 Mar 2009 22:22:25 -0000	1.19
+++ filefield.css	20 Mar 2009 04:51:21 -0000
@@ -61,7 +61,11 @@
   padding: 1px 13px 2px 3px; /* RTL */
 }
 
-
+.filefield-element div.ahah-progress-bar {
+  display: none;
+  margin-top: 4px;
+  width: 28em;
+}
 
 /* End general widget form styles. */
 
Index: filefield.js
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/filefield/filefield.js,v
retrieving revision 1.16
diff -u -r1.16 filefield.js
--- filefield.js	9 Mar 2009 05:07:35 -0000	1.16
+++ filefield.js	20 Mar 2009 04:51:22 -0000
@@ -37,7 +37,9 @@
  * Prevent FileField uploads when using buttons not intended to upload.
  */
 Drupal.behaviors.filefieldButtons = function(context) {
-  $('input.form-submit').bind('mousedown', Drupal.filefield.disableFields);
+  $('input.form-submit')
+    .bind('mousedown', Drupal.filefield.disableFields)
+    .bind('mousedown', Drupal.filefield.progressBar);
 };
 
 /**
@@ -87,5 +89,26 @@
     setTimeout(function(){
       $disabledFields.attr('disabled', '');
     }, 1000);
+  },
+  progressBar: function(event) {
+    var clickedButton = this;
+    var $progressId = $(clickedButton).parents('div.filefield-element').find('input.filefield-progress');
+    if ($progressId.size()) {
+      var originalName = $progressId.attr('name');
+
+      // Replace the name with the required identifier.
+      $progressId.attr('name', originalName.match(/APC_UPLOAD_PROGRESS|UPLOAD_IDENTIFIER/)[0]);
+
+      // Restore the original name after the upload begins.
+      setTimeout(function() {
+        $progressId.attr('name', originalName);
+      }, 1000);
+
+      // Show the progress bar if the upload takes longer than 3 seconds.
+      setTimeout(function() {
+        $(clickedButton).parents('div.filefield-element').find('div.ahah-progress-bar').slideDown();
+      }, 500);
+
+    }
   }
 };
Index: filefield_widget.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/filefield/filefield_widget.inc,v
retrieving revision 1.65
diff -u -r1.65 filefield_widget.inc
--- filefield_widget.inc	19 Mar 2009 03:43:37 -0000	1.65
+++ filefield_widget.inc	20 Mar 2009 04:51:22 -0000
@@ -237,6 +237,30 @@
   $element['filefield_upload']['#access'] = empty($item['fid']);
   $element['filefield_remove']['#access'] = !empty($item['fid']);
 
+  // Add progress bar support to the upload if possible.
+  if ($implementation = filefield_progress_implementation()) {
+    $upload_progress_key = md5(mt_rand());
+
+    if ($implementation == 'uploadprogress') {
+      $element['UPLOAD_IDENTIFIER'] = array(
+        '#type' => 'hidden',
+        '#value' => $upload_progress_key,
+        '#attributes' => array('class' => 'filefield-progress'),
+      );
+    }
+    elseif ($implementation == 'apc') {
+      $element['APC_UPLOAD_PROGRESS'] = array(
+        '#type' => 'hidden',
+        '#value' => $upload_progress_key,
+        '#attributes' => array('class' => 'filefield-progress'),
+      );
+    }
+
+    // Add the upload progress callback.
+    $element['filefield_upload']['#ahah']['progress']['type'] = 'bar';
+    $element['filefield_upload']['#ahah']['progress']['path'] = 'filefield/progress/' . $upload_progress_key;
+  }
+
   // Figure out our fid...
   $element['fid'] = array('#type' => 'hidden', '#value' => $item['fid']);
 
