Table of Contents

Introduction

Plupload comes with a number of built-in filters that provide a way to restrict selection of files to only those that meet specific requirements.

These are:

  • mime_types - a way to constrain file dialog to only specific file types,
  • max*file*size - do not let files of size larger than the maximum to the queue, and
  • prevent_duplicates - ignore files of the same name and size.

Here is the typical usage case:

filters: {
  mime_types : [
    { title : "Image files", extensions : "jpg,gif,png" },
    { title : "Zip files", extensions : "zip" }
  ],
  max_file_size: "200mb",
  prevent_duplicates: true
}

However you might need - more! For example, restrict files by minimum size, or something even more fancier, like not allowing images that exceed specific resolution, etc. For this purpose (starting from version 2) we provide a way to define additional file filters, via a dedicated static method: plupload.addFileFilter().

plupload.addFileFilter()

plupload.addFileFilter() is used by the Plupload itself to define its internal file filters. For example this is how a definition for the max_file_size looks like:

plupload.addFileFilter('max_file_size', function(maxSize, file, cb) {
  var undef;

  // Invalid file size
  if (file.size !== undef && maxSize && file.size > maxSize) {
    this.trigger('Error', {
      code : plupload.FILE_SIZE_ERROR,
      message : plupload.translate('File size error.'),
      file : file
    });
    cb(false);
  } else {
    cb(true);
  }
}); 

And this is how you use it in your config:

filters: {
        max_file_size: "200mb"
}

As you see a logic is pretty simple there - the callback for the filter receives three arguments:

  • maxSize - the value from the config (in the case above - 200mb)
  • file - the file object that is being filtered
  • cb - the callback which the filter must invoke once it comes up with the check result

Additionally you have access to all the files that are already present in the queue, via this.files, because the callback is invoked in the context of the current uploader instance.

As you've probably noticed, filter is asynchronous. This is done because the check for requirements might include some asynchronous operations, like AJAX request or preloading the image (check Example: max_img_resolution below).

You can do all kind of checks on the file object and pass the boolean result to the callback. If you pass false the file will be filtered out and won't be added to the queue. But we still fire the Error event with an appropriate error code and message (just in case someone wants to know if file was added or - not, and - why).

Once you define the filter, every consequent Plupload instance on the page will be able to use it. You can even store it in a separate js file and include after you include the Plupload script.

Obviously if you want your filter to have any effect you should define it before you create an instance of Plupload uploader.

Example: min*file*size

For example let's create a filter that will not allow files to the queue if they are smaller than a specific size. We name it - min_file_size:

plupload.addFileFilter('min_file_size', function(minSize, file, cb) {
  var undef;

  // Invalid file size
  if (file.size !== undef && minSize && file.size < minSize) {
    this.trigger('Error', {
      code : plupload.FILE_SIZE_ERROR,
      message : plupload.translate('File size error.'),
      file : file
    });
    cb(false);
  } else {
    cb(true);
  }
}); 

I bet, by now you could have come up with something like this yourself, but anyway - let's now apply our new filter in the config:

filters: {
        min_file_size: "100kb"
}

From now on every file that is smaller than 100kb will be filtered out.

Example: max*img*resolution

As we've mentioned above, filters are asynchronous, but from the example above it is not even clear why this might come in handy. So let's try something more complicated. Let's filter out the images depending on whether they exceed the specified resolution:

plupload.addFileFilter('max_img_resolution', function(maxRes, file, cb) {
  var self = this, img = new o.Image();

  function finalize(result) {
    // cleanup
    img.destroy();
    img = null;

    // if rule has been violated in one way or another, trigger an error
    if (!result) {
      self.trigger('Error', {
        code : plupload.IMAGE_DIMENSIONS_ERROR,
        message : "Resolution exceeds the allowed limit of " + maxRes  + " pixels.",
        file : file
      });
      
    }
    cb(result);
  }

  img.onload = function() {
    // check if resolution cap is not exceeded
    finalize(img.width * img.height < maxRes);
  };

  img.onerror = function() {
    finalize(false);
  };

  img.load(file.getSource());
});

Image preloading is an asynchronous operation. We do not know when it will finish loading, so we listen to the events and resolve the filter once we have it.

Let's apply the filter in the config now:

filters: {
        max_img_resolution: 1000000 // 1MP = 1 million pixels
}

Simple, aye?

Fork me on GitHub