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 apc.rfc1867 = 1 to your php.ini configuration. Alternatively, it is recommended to use PECL uploadprogress, 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 PECL uploadprogress library (prefered) or to install APC.'); + $severity = REQUIREMENT_WARNING; + } + elseif ($implementation == 'apc') { + $value = $t('Enabled (APC RFC1867)'); + $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 PECL uploadprogress library if possible.'); + $severity = REQUIREMENT_OK; + } + elseif ($implementation == 'uploadprogress') { + $value = $t('Enabled (PECL uploadprogress)'); + $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']);