summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNathan Haug2009-04-04 05:45:32 (GMT)
committer Nathan Haug2009-04-04 05:45:32 (GMT)
commite3623331c8391a2bc9420fa21648900edb194631 (patch)
tree696a310935debfd9529aaba27b9ecc223826bc53
parentb703ffee4ba7fa9b3bdd303c34f45d1a140107a0 (diff)
#318960: Upload progress bar support.
-rw-r--r--filefield.css9
-rw-r--r--filefield.install50
-rw-r--r--filefield.js25
-rw-r--r--filefield.module70
-rw-r--r--filefield_widget.inc24
5 files changed, 177 insertions, 1 deletions
diff --git a/filefield.css b/filefield.css
index af4b3df..673cd6a 100644
--- a/filefield.css
+++ b/filefield.css
@@ -61,7 +61,16 @@
padding: 1px 13px 2px 3px; /* RTL */
}
+.filefield-element div.ahah-progress-bar {
+ display: none;
+ margin-top: 4px;
+ width: 28em;
+ padding: 0;
+}
+.filefield-element div.ahah-progress-bar div.bar {
+ margin: 0;
+}
/* End general widget form styles. */
diff --git a/filefield.install b/filefield.install
index f1d65e9..e047371 100644
--- a/filefield.install
+++ b/filefield.install
@@ -43,6 +43,56 @@ function filefield_disable() {
}
/**
+ * 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() {
diff --git a/filefield.js b/filefield.js
index 46e299e..e43f1a5 100644
--- a/filefield.js
+++ b/filefield.js
@@ -37,7 +37,9 @@ Drupal.behaviors.filefieldValidateAutoAttach = function(context) {
* 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 @@ Drupal.filefield = {
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);
+
+ }
}
};
diff --git a/filefield.module b/filefield.module
index 72db505..bce6d0f 100644
--- a/filefield.module
+++ b/filefield.module
@@ -39,6 +39,12 @@ function filefield_menu() {
'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;
}
@@ -510,6 +516,70 @@ function filefield_js($type_name, $field_name, $delta) {
}
/**
+ * 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) {
diff --git a/filefield_widget.inc b/filefield_widget.inc
index 48105fc..9c1b744 100644
--- a/filefield_widget.inc
+++ b/filefield_widget.inc
@@ -273,6 +273,30 @@ function filefield_widget_process($element, $edit, &$form_state, $form) {
$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;
+ }
+
// Set the FID.
$element['fid'] = array(
'#type' => 'hidden',