Commit d7609cd9 authored by Jacob Singh's avatar Jacob Singh
Browse files

#880288 by efflugentsia and pwolanin: polish on D7 version, validation

parent bd88c94c
Loading
Loading
Loading
Loading
+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) {
@@ -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();
@@ -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);
+127 −13
Original line number Diff line number Diff line
@@ -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',
@@ -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',
@@ -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));
}

/**
@@ -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) {
@@ -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;
@@ -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;
@@ -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'),
  );
}