Loading plupload.js +95 −52 Original line number Diff line number Diff line //$Id$ (function($) { Drupal.plupload = Drupal.plupload || {}; /** * Attaches the Plupload behavior to each Plupload form element. */ Drupal.behaviors.plupload = { attach: function(context, settings) { $(".plupload-element", context).once('plupload-init', function () { $this = $(this); $this.pluploadQueue({ // General settings runtimes: 'gears,browserplus,html5,flash,silverlight', url: settings.basePath + 'plupload-handle-uploads', //@todo: implement settings for these max_file_size: '10mb', chunk_size: '1mb', unique_names: true, // Specify what files to browse for // @todo: implement via settings on the element //filters: [{ // title: "Image files", // extensions: "jpg,gif,png" //}, //{ // title: "Zip files", // extensions: "zip" //}], // End of things needing settings. // Flash settings flash_swf_url: settings.plupload.libraryLocation + '/plupload/js/plupload.flash.swf', // Silverlight settings silverlight_xap_url: settings.plupload.libraryLocation + '/plupload/js/plupload.silverlight.xap' }); var $this = $(this); // Merge the default settings and the element settings to get a full // settings object to pass to the Plupload library for this element. var id = $this.attr('id'); var defaultSettings = settings.plupload['_default'] ? settings.plupload['_default'] : {}; var elementSettings = (id && settings.plupload[id]) ? settings.plupload[id] : {}; var pluploadSettings = $.extend({}, defaultSettings, elementSettings); // Do additional requirements testing to prevent a less than ideal runtime // from being used. For example, the Plupload library treats Firefox 3.5 // as supporting HTML 5, but this is incorrect, because Firefox 3.5 // doesn't support the 'multiple' attribute for file input controls. So, // if settings.plupload._requirements.html5.mozilla = '1.9.2', then we // remove 'html5' from pluploadSettings.runtimes if $.browser.mozilla is // true and if $.browser.version is less than '1.9.2'. if (settings.plupload['_requirements'] && pluploadSettings.runtimes) { var runtimes = pluploadSettings.runtimes.split(','); var filteredRuntimes = []; for (var i = 0; i < runtimes.length; i++) { var includeRuntime = true; if (settings.plupload['_requirements'][runtimes[i]]) { var requirements = settings.plupload['_requirements'][runtimes[i]]; for (var browser in requirements) { if ($.browser[browser] && Drupal.plupload.compareVersions($.browser.version, requirements[browser]) < 0) { includeRuntime = false; } } } if (includeRuntime) { filteredRuntimes.push(runtimes[i]); } } pluploadSettings.runtimes = filteredRuntimes.join(','); } // Client side form validation // Initialize Plupload for this element. $this.pluploadQueue(pluploadSettings); // Client side form validation (see // http://plupload.com/example_queuewidget.php) $this.closest('form').submit(function(e) { var uploader = $('.plupload', this).pluploadQueue(); var $form = $(this); var uploader = $('.plupload-element', this).pluploadQueue(); // Validate number of uploaded files if (uploader.total.uploaded == 0) { Loading @@ -43,7 +61,9 @@ // When all files are uploaded submit form uploader.bind('UploadProgress', function() { if (uploader.total.uploaded == uploader.files.length) $('form').submit(); if (uploader.total.uploaded == uploader.files.length) { $form.submit(); } }); uploader.start(); Loading @@ -56,4 +76,27 @@ } } /** * Helper function to compare version strings. * * Returns one of: * - A negative integer if a < b. * - A positive integer if a > b. * - 0 if a == b. */ Drupal.plupload.compareVersions = function (a, b) { a = a.split('.'); b = b.split('.'); // Return the most significant difference, if there is one. for (var i=0; i < Math.min(a.length, b.length); i++) { var compare = parseInt(a[i]) - parseInt(b[i]); if (compare != 0) { return compare; } } // If the common parts of the two version strings are equal, the greater // version number is the one with the most sections. return a.length - b.length; } })(jQuery); plupload.module +127 −13 Original line number Diff line number Diff line Loading @@ -9,7 +9,8 @@ function plupload_menu() { 'title' => 'Handles uploads', 'page callback' => 'plupload_handle_uploads', 'type' => MENU_CALLBACK, 'access arguments' => array('access content') 'access callback' => 'plupload_upload_access', 'access arguments' => array('access content'), ); $items['plupload-test'] = array( 'title' => 'Test Plupload', Loading @@ -22,6 +23,19 @@ function plupload_menu() { return $items; } /** * Verifies the token for this request. */ function plupload_upload_access() { foreach(func_get_args() as $permission) { if (!user_access($permission)) { return FALSE; } } return !empty($_REQUEST['form_token']) && drupal_valid_token($_REQUEST['form_token'], 'plupload-handle-uploads'); } function plupload_test($form, &$form_state) { $form['pud'] = array( '#type' => 'plupload', Loading Loading @@ -59,7 +73,6 @@ function plupload_test_submit($form, &$form_state) { form_set_error('pud', "Upload of {$uploaded_file['name']} failed"); } } dsm(print_r($saved_files, 1)); } /** Loading @@ -74,17 +87,20 @@ function plupload_element_info() { // @todo //'#element_validate' => array('file_managed_file_validate'), '#theme_wrappers' => array('container'), '#value_callback' => 'pluplod_element_value', '#value_callback' => 'plupload_element_value', '#attached' => array( 'library' => array(array('plupload', 'plupload')), 'js' => array($module_path . '/plupload.js'), 'css' => array($module_path . '/plupload.css'), ), '#process' => array('plupload_element_process'), '#element_validate' => array('plupload_element_validate'), '#pre_render' => array('plupload_element_pre_render'), ); return $types; } function pluplod_element_value(&$element, $input = FALSE, $form_state = NULL) { function plupload_element_value(&$element, $input = FALSE, $form_state = NULL) { $id = $element['#id']; $files = array(); foreach ($form_state['input'] as $key => $value) { Loading @@ -93,25 +109,114 @@ function pluplod_element_value(&$element, $input = FALSE, $form_state = NULL) { $key = $reg[2]; $files[$i][$key] = $value; } $files[$i]['tmppath'] = variable_get('plupload_temporary_file_scheme', 'temporary') . '://' . $files[$i]['tmpname']; $files[$i]['tmppath'] = variable_get('plupload_temporary_uri', 'temporary://') . $files[$i]['tmpname']; } return $files; } /** * #process callback. */ function plupload_element_process($element) { if (!isset($element['#upload_validators'])) { $element['#upload_validators'] = array(); } $element['#upload_validators'] += _plupload_default_upload_validators(); return $element; } /** * Element validation handler for a Plupload element. */ function plupload_element_validate($element, &$form_state) { foreach ($element['#value'] as $file_info) { // @todo Here we create a $file object for a file that doesn't exist yet, // because saving the file to its destination is done in a submit handler. // Need more investigation into what else is needed for it to be okay to // call file_validate(). For example, file_validate_size() will not have // access to a meaningful $file->filesize unless we set that here. For // now, we can at least rely on file_validate_extensions() running // successfully. $destination = variable_get('file_default_scheme', 'public') . '://' . $file_info['name']; $file = file_uri_to_object($destination); foreach (file_validate($file, $element['#upload_validators']) as $error_message) { form_error($element, $error_message); } } } /** * #pre_render callback to attach JavaScript settings for the plupload element. */ function plupload_element_pre_render($element) { $settings = isset($element['#plupload_settings']) ? $element['#plupload_settings'] : array(); // The Plupload library supports client-side validation of file extension, so // pass along the information for it to do that. However, as with all client- // side validation, this is a UI enhancement only, and not a replacement for // server-side validation. if (empty($settings['filters']) && isset($element['#upload_validators']['file_validate_extensions'][0])) { $settings['filters'][] = array( // @todo Some runtimes (e.g., flash) require a non-empty title for each // filter, but I don't know what this title is used for. Seems a shame // to hard-code it, but what's a good way to avoid that? 'title' => t('Allowed files'), 'extensions' => str_replace(' ', ',', $element['#upload_validators']['file_validate_extensions'][0]), ); } $element['#attached']['js'][] = array( 'type' => 'setting', 'data' => array('plupload' => array($element['#id'] => $settings)), ); return $element; } /** * Implements hook_library(). */ function plupload_library() { $module_path = drupal_get_path('module', 'plupload'); // @todo - itegrate with the libraries module? $library_path = drupal_get_path('module', 'plupload') . '/plupload'; $libraries['plupload'] = array( 'title' => 'Plupload', 'website' => 'http://www.plupload.com', 'version' => '1.3.9', 'js' => array( $module_path . '/plupload/js/gears_init.js' => array(), $module_path . '/plupload/js/jquery.plupload.queue.min.js' => array(), $module_path . '/plupload/js/plupload.full.min.js' => array(), array('type' => 'setting', 'data' => array('plupload' => array('libraryLocation' => $module_path))), // @todo - only add gears JS if gears is an enabled runtime. // $library_path . '/js/gears_init.js' => array(), $library_path . '/js/jquery.plupload.queue.min.js' => array(), $library_path . '/js/plupload.full.min.js' => array(), array('type' => 'setting', 'data' => array('plupload' => array( // Element-specific settings get keyed by the element id (see // plupload_element_pre_render()), so put default settings in // '_default' (Drupal element ids do not have underscores, because // they have hyphens instead). '_default' => array( // @todo Provide a settings page for configuring these. 'runtimes' => 'html5,flash,html4', 'url' => url('plupload-handle-uploads', array('query' => array('form_token' => drupal_get_token('plupload-handle-uploads')))), 'max_file_size' => '10mb', 'chunk_size' => '1mb', 'unique_names' => TRUE, 'flash_swf_url' => file_create_url($library_path . '/js/plupload.flash.swf'), 'silverlight_xap_url' => file_create_url($library_path . '/js/plupload.silverlight.xap'), ), // The plupload.js integration file in the module folder can do // additional browser checking to remove unsupported runtimes. This is // in addition to what is done by the Plupload library. '_requirements' => array( 'html5' => array( // The Plupload library recognizes Firefox 3.5 as supporting HTML 5, // but Firefox 3.5 does not support the HTML 5 "multiple" attribute // for file input controls. This makes the html5 runtime much less // appealing, so we treat all Firefox versions less than 3.6 as // ineligible for the html5 runtime. 'mozilla' => '1.9.2', ), ), ))), ), ); return $libraries; Loading @@ -123,8 +228,7 @@ function plupload_handle_uploads() { // Added a variable for this because in HA environments, temporary may need // to be a shared location for this to work. $temporary_file_scheme = variable_get('plupload_temporary_file_scheme', 'temporary'); $temp_directory = "$temporary_file_scheme://"; $temp_directory = variable_get('plupload_temporary_uri', 'temporary://'); // Chunk it? $chunk = isset($_REQUEST["chunk"]) ? $_REQUEST["chunk"] : 0; Loading Loading @@ -216,3 +320,13 @@ if (!function_exists('file_uri_to_object')) { return $file; } } /** * Helper function to add defaults to $element['#upload_validators']. */ function _plupload_default_upload_validators() { return array( // See file_save_upload() for details. 'file_validate_extensions' => array('jpg jpeg gif png txt doc xls pdf ppt pps odt ods odp'), ); } Loading
plupload.js +95 −52 Original line number Diff line number Diff line //$Id$ (function($) { Drupal.plupload = Drupal.plupload || {}; /** * Attaches the Plupload behavior to each Plupload form element. */ Drupal.behaviors.plupload = { attach: function(context, settings) { $(".plupload-element", context).once('plupload-init', function () { $this = $(this); $this.pluploadQueue({ // General settings runtimes: 'gears,browserplus,html5,flash,silverlight', url: settings.basePath + 'plupload-handle-uploads', //@todo: implement settings for these max_file_size: '10mb', chunk_size: '1mb', unique_names: true, // Specify what files to browse for // @todo: implement via settings on the element //filters: [{ // title: "Image files", // extensions: "jpg,gif,png" //}, //{ // title: "Zip files", // extensions: "zip" //}], // End of things needing settings. // Flash settings flash_swf_url: settings.plupload.libraryLocation + '/plupload/js/plupload.flash.swf', // Silverlight settings silverlight_xap_url: settings.plupload.libraryLocation + '/plupload/js/plupload.silverlight.xap' }); var $this = $(this); // Merge the default settings and the element settings to get a full // settings object to pass to the Plupload library for this element. var id = $this.attr('id'); var defaultSettings = settings.plupload['_default'] ? settings.plupload['_default'] : {}; var elementSettings = (id && settings.plupload[id]) ? settings.plupload[id] : {}; var pluploadSettings = $.extend({}, defaultSettings, elementSettings); // Do additional requirements testing to prevent a less than ideal runtime // from being used. For example, the Plupload library treats Firefox 3.5 // as supporting HTML 5, but this is incorrect, because Firefox 3.5 // doesn't support the 'multiple' attribute for file input controls. So, // if settings.plupload._requirements.html5.mozilla = '1.9.2', then we // remove 'html5' from pluploadSettings.runtimes if $.browser.mozilla is // true and if $.browser.version is less than '1.9.2'. if (settings.plupload['_requirements'] && pluploadSettings.runtimes) { var runtimes = pluploadSettings.runtimes.split(','); var filteredRuntimes = []; for (var i = 0; i < runtimes.length; i++) { var includeRuntime = true; if (settings.plupload['_requirements'][runtimes[i]]) { var requirements = settings.plupload['_requirements'][runtimes[i]]; for (var browser in requirements) { if ($.browser[browser] && Drupal.plupload.compareVersions($.browser.version, requirements[browser]) < 0) { includeRuntime = false; } } } if (includeRuntime) { filteredRuntimes.push(runtimes[i]); } } pluploadSettings.runtimes = filteredRuntimes.join(','); } // Client side form validation // Initialize Plupload for this element. $this.pluploadQueue(pluploadSettings); // Client side form validation (see // http://plupload.com/example_queuewidget.php) $this.closest('form').submit(function(e) { var uploader = $('.plupload', this).pluploadQueue(); var $form = $(this); var uploader = $('.plupload-element', this).pluploadQueue(); // Validate number of uploaded files if (uploader.total.uploaded == 0) { Loading @@ -43,7 +61,9 @@ // When all files are uploaded submit form uploader.bind('UploadProgress', function() { if (uploader.total.uploaded == uploader.files.length) $('form').submit(); if (uploader.total.uploaded == uploader.files.length) { $form.submit(); } }); uploader.start(); Loading @@ -56,4 +76,27 @@ } } /** * Helper function to compare version strings. * * Returns one of: * - A negative integer if a < b. * - A positive integer if a > b. * - 0 if a == b. */ Drupal.plupload.compareVersions = function (a, b) { a = a.split('.'); b = b.split('.'); // Return the most significant difference, if there is one. for (var i=0; i < Math.min(a.length, b.length); i++) { var compare = parseInt(a[i]) - parseInt(b[i]); if (compare != 0) { return compare; } } // If the common parts of the two version strings are equal, the greater // version number is the one with the most sections. return a.length - b.length; } })(jQuery);
plupload.module +127 −13 Original line number Diff line number Diff line Loading @@ -9,7 +9,8 @@ function plupload_menu() { 'title' => 'Handles uploads', 'page callback' => 'plupload_handle_uploads', 'type' => MENU_CALLBACK, 'access arguments' => array('access content') 'access callback' => 'plupload_upload_access', 'access arguments' => array('access content'), ); $items['plupload-test'] = array( 'title' => 'Test Plupload', Loading @@ -22,6 +23,19 @@ function plupload_menu() { return $items; } /** * Verifies the token for this request. */ function plupload_upload_access() { foreach(func_get_args() as $permission) { if (!user_access($permission)) { return FALSE; } } return !empty($_REQUEST['form_token']) && drupal_valid_token($_REQUEST['form_token'], 'plupload-handle-uploads'); } function plupload_test($form, &$form_state) { $form['pud'] = array( '#type' => 'plupload', Loading Loading @@ -59,7 +73,6 @@ function plupload_test_submit($form, &$form_state) { form_set_error('pud', "Upload of {$uploaded_file['name']} failed"); } } dsm(print_r($saved_files, 1)); } /** Loading @@ -74,17 +87,20 @@ function plupload_element_info() { // @todo //'#element_validate' => array('file_managed_file_validate'), '#theme_wrappers' => array('container'), '#value_callback' => 'pluplod_element_value', '#value_callback' => 'plupload_element_value', '#attached' => array( 'library' => array(array('plupload', 'plupload')), 'js' => array($module_path . '/plupload.js'), 'css' => array($module_path . '/plupload.css'), ), '#process' => array('plupload_element_process'), '#element_validate' => array('plupload_element_validate'), '#pre_render' => array('plupload_element_pre_render'), ); return $types; } function pluplod_element_value(&$element, $input = FALSE, $form_state = NULL) { function plupload_element_value(&$element, $input = FALSE, $form_state = NULL) { $id = $element['#id']; $files = array(); foreach ($form_state['input'] as $key => $value) { Loading @@ -93,25 +109,114 @@ function pluplod_element_value(&$element, $input = FALSE, $form_state = NULL) { $key = $reg[2]; $files[$i][$key] = $value; } $files[$i]['tmppath'] = variable_get('plupload_temporary_file_scheme', 'temporary') . '://' . $files[$i]['tmpname']; $files[$i]['tmppath'] = variable_get('plupload_temporary_uri', 'temporary://') . $files[$i]['tmpname']; } return $files; } /** * #process callback. */ function plupload_element_process($element) { if (!isset($element['#upload_validators'])) { $element['#upload_validators'] = array(); } $element['#upload_validators'] += _plupload_default_upload_validators(); return $element; } /** * Element validation handler for a Plupload element. */ function plupload_element_validate($element, &$form_state) { foreach ($element['#value'] as $file_info) { // @todo Here we create a $file object for a file that doesn't exist yet, // because saving the file to its destination is done in a submit handler. // Need more investigation into what else is needed for it to be okay to // call file_validate(). For example, file_validate_size() will not have // access to a meaningful $file->filesize unless we set that here. For // now, we can at least rely on file_validate_extensions() running // successfully. $destination = variable_get('file_default_scheme', 'public') . '://' . $file_info['name']; $file = file_uri_to_object($destination); foreach (file_validate($file, $element['#upload_validators']) as $error_message) { form_error($element, $error_message); } } } /** * #pre_render callback to attach JavaScript settings for the plupload element. */ function plupload_element_pre_render($element) { $settings = isset($element['#plupload_settings']) ? $element['#plupload_settings'] : array(); // The Plupload library supports client-side validation of file extension, so // pass along the information for it to do that. However, as with all client- // side validation, this is a UI enhancement only, and not a replacement for // server-side validation. if (empty($settings['filters']) && isset($element['#upload_validators']['file_validate_extensions'][0])) { $settings['filters'][] = array( // @todo Some runtimes (e.g., flash) require a non-empty title for each // filter, but I don't know what this title is used for. Seems a shame // to hard-code it, but what's a good way to avoid that? 'title' => t('Allowed files'), 'extensions' => str_replace(' ', ',', $element['#upload_validators']['file_validate_extensions'][0]), ); } $element['#attached']['js'][] = array( 'type' => 'setting', 'data' => array('plupload' => array($element['#id'] => $settings)), ); return $element; } /** * Implements hook_library(). */ function plupload_library() { $module_path = drupal_get_path('module', 'plupload'); // @todo - itegrate with the libraries module? $library_path = drupal_get_path('module', 'plupload') . '/plupload'; $libraries['plupload'] = array( 'title' => 'Plupload', 'website' => 'http://www.plupload.com', 'version' => '1.3.9', 'js' => array( $module_path . '/plupload/js/gears_init.js' => array(), $module_path . '/plupload/js/jquery.plupload.queue.min.js' => array(), $module_path . '/plupload/js/plupload.full.min.js' => array(), array('type' => 'setting', 'data' => array('plupload' => array('libraryLocation' => $module_path))), // @todo - only add gears JS if gears is an enabled runtime. // $library_path . '/js/gears_init.js' => array(), $library_path . '/js/jquery.plupload.queue.min.js' => array(), $library_path . '/js/plupload.full.min.js' => array(), array('type' => 'setting', 'data' => array('plupload' => array( // Element-specific settings get keyed by the element id (see // plupload_element_pre_render()), so put default settings in // '_default' (Drupal element ids do not have underscores, because // they have hyphens instead). '_default' => array( // @todo Provide a settings page for configuring these. 'runtimes' => 'html5,flash,html4', 'url' => url('plupload-handle-uploads', array('query' => array('form_token' => drupal_get_token('plupload-handle-uploads')))), 'max_file_size' => '10mb', 'chunk_size' => '1mb', 'unique_names' => TRUE, 'flash_swf_url' => file_create_url($library_path . '/js/plupload.flash.swf'), 'silverlight_xap_url' => file_create_url($library_path . '/js/plupload.silverlight.xap'), ), // The plupload.js integration file in the module folder can do // additional browser checking to remove unsupported runtimes. This is // in addition to what is done by the Plupload library. '_requirements' => array( 'html5' => array( // The Plupload library recognizes Firefox 3.5 as supporting HTML 5, // but Firefox 3.5 does not support the HTML 5 "multiple" attribute // for file input controls. This makes the html5 runtime much less // appealing, so we treat all Firefox versions less than 3.6 as // ineligible for the html5 runtime. 'mozilla' => '1.9.2', ), ), ))), ), ); return $libraries; Loading @@ -123,8 +228,7 @@ function plupload_handle_uploads() { // Added a variable for this because in HA environments, temporary may need // to be a shared location for this to work. $temporary_file_scheme = variable_get('plupload_temporary_file_scheme', 'temporary'); $temp_directory = "$temporary_file_scheme://"; $temp_directory = variable_get('plupload_temporary_uri', 'temporary://'); // Chunk it? $chunk = isset($_REQUEST["chunk"]) ? $_REQUEST["chunk"] : 0; Loading Loading @@ -216,3 +320,13 @@ if (!function_exists('file_uri_to_object')) { return $file; } } /** * Helper function to add defaults to $element['#upload_validators']. */ function _plupload_default_upload_validators() { return array( // See file_save_upload() for details. 'file_validate_extensions' => array('jpg jpeg gif png txt doc xls pdf ppt pps odt ods odp'), ); }