Skip to content

A jQuery plugin to convert the HTML file input type into a fancy file uploader under a MIT or LGPL license. Mobile-friendly too!

Notifications You must be signed in to change notification settings

orderamidchaos/jquery-fancyfileuploader

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

27 Commits
 
 
 
 
 
 

Repository files navigation

jQuery Fancy File Uploader

A jQuery plugin to convert the HTML file input type into a mobile-friendly fancy file uploader. Choose from a MIT or LGPL license.

Also available in FlexForms Modules.

Screenshot

Live demo via Admin Pack (This plugin is located near the bottom of that page.)

Also used by Cool File Transfer.

Donate

Features

  • Beautiful and fully responsive layout.
  • Drag-and-drop dropzone with paste support.
  • Full keyboard navigation.
  • Client-side file naming with auto-sanitizing.
  • Preview support for images, audio, and video.
  • Chunked file upload support.
  • Lots of useful callbacks.
  • Automatic retries with exponential fallback.
  • Multilingual support.
  • Has a liberal open source license. MIT or LGPL, your choice.
  • Designed for relatively painless integration into your project.
  • Sits on GitHub for all of that pull request and issue tracker goodness to easily submit changes and ideas respectively.

Getting Started

jQuery is required to use this software so hopefully that doesn't come as a surprise to anyone. Parts of this plugin require the jQuery UI widget factory. If you are already including jQuery UI on your webpage, then you already have the widget factory and don't need to do anything else. Otherwise, add this line after including jQuery:

<script type="text/javascript" src="fancy-file-uploader/jquery.ui.widget.js"></script>

Now you can include Fancy File Uploader:

<link rel="stylesheet" href="fancy-file-uploader/fancy_fileupload.css" type="text/css" media="all" />
<script type="text/javascript" src="fancy-file-uploader/jquery.fileupload.js"></script>
<script type="text/javascript" src="fancy-file-uploader/jquery.iframe-transport.js"></script>
<script type="text/javascript" src="fancy-file-uploader/jquery.fancy-fileupload.js"></script>

Let's say you have a file input element somewhere on the same page that looks like:

<input id="thefiles" type="file" name="files" accept=".jpg, .png, image/jpeg, image/png" multiple>

To transform that file input into something fancy, pass in some options to the plugin and let the magic happen:

<script type="text/javascript">
$(function() {
	$('#thefiles').FancyFileUpload({
		params : {
			action : 'fileuploader'
		},
		maxfilesize : 1000000
	});
});
</script>

If you don't have the page realestate available to support the large dropzone and instead want a regular upload button, but still retain all of the other fancy features, simply add a value to the input element, and that value will be the text of the button:

<input id="thefiles" type="file" name="files" accept=".jpg, .png, image/jpeg, image/png" multiple value="Upload File">

Drag-and-drop is still available on the smaller button.

Other than handling the files on the server side of things and leveraging the various callbacks, that's pretty much it for basic usage.

Server-Side Processing

The server should reply with the following JSON object format for successful uploads:

{
	"success" : true
}

The server should reply with the following JSON object format for error conditions:

{
	"success" : false,
	"error" : "Human-readable, possibly translated error.",
	"errorcode" : "relevant_error_code"
}

See FlexForms Modules, Admin Pack, and FlexForms for example usage with open source CubicleSoft products that handle Fancy File Uploader submissions.

Fancy File Uploader works with most server-side languages. For basic server-side PHP integration with Fancy File Uploader, you can use the included server-side helper class:

<?php
	require_once "fancy_file_uploader_helper.php";

	// Depending on your server, you might have to use $_POST instead of $_REQUEST.
	if (isset($_REQUEST["fileuploader"]))
	{
		header("Content-Type: application/json");

		$allowedexts = array(
			"jpg" => true,
			"png" => true,
		);

		$files = FancyFileUploaderHelper::NormalizeFiles("files");
		if (!isset($files[0]))  $result = array("success" => false, "error" => "File data was submitted but is missing.", "errorcode" => "bad_input");
		else if (!$files[0]["success"])  $result = $files[0];
		else if (!isset($allowedexts[strtolower($files[0]["ext"])]))
		{
			$result = array(
				"success" => false,
				"error" => "Invalid file extension.  Must be '.jpg' or '.png'.",
				"errorcode" => "invalid_file_ext"
			);
		}
		else
		{
			// For chunked file uploads, get the current filename and starting position from the incoming headers.
			$name = FancyFileUploaderHelper::GetChunkFilename();
			if ($name !== false)
			{
				$startpos = FancyFileUploaderHelper::GetFileStartPosition();

				// [Do stuff with the file chunk.]
			}
			else
			{
				// [Do stuff with the file here.]
				// copy($files[0]["file"], __DIR__ . "/images/" . $id . "." . strtolower($files[0]["ext"]));
			}

			$result = array(
				"success" => true
			);
		}

		echo json_encode($result, JSON_UNESCAPED_SLASHES);
		exit();
	}
?>

The class also contains FancyFileUploaderHelper::GetMaxUploadFileSize(), which determines the maximum allowed file/chunk upload size that PHP allows.

Additional Examples

To automatically start every upload as soon as it is added, do something similar to this:

<script type="text/javascript">
$(function() {
	$('#thefiles').FancyFileUpload({
		params : {
			action : 'fileuploader'
		},
		edit : false,
		maxfilesize : 1000000,
		added : function(e, data) {
			// It is okay to simulate clicking the start upload button.
			this.find('.ff_fileupload_actions button.ff_fileupload_start_upload').click();
		}
	});
});
</script>

It is possible to add a button to the screen to start all of the uploads at once that are able to be started:

<button type="button" onclick="$('#thefiles').next().find('.ff_fileupload_actions button.ff_fileupload_start_upload').click(); return false;">Upload all files</button>

To hide per-file upload buttons and force all pending uploads to only go through the above external button, pass the option "multionly: true" to the FancyFileUpload() constructor.

The specialized function data.ff_info.RemoveFile() can be used at any time to remove a file from the list which will immediately abort any upload in progress, remove the associated UI elements, and clean up internal structures:

<script type="text/javascript">
$(function() {
	var token;

	$('#thefiles').FancyFileUpload({
		params : {
			action : 'fileuploader'
		},
		maxfilesize : 1000000,
		multionly : true,
		startupload : function(SubmitUpload, e, data) {
			$.ajax({
				'url' : 'gettoken.php',
				'dataType' : 'json',
				'success' : function(tokendata) {
					token = tokendata;

					SubmitUpload();
				}
			});
		},
		continueupload : function(e, data) {
			var ts = Math.round(new Date().getTime() / 1000);

			// Alternatively, just call data.abort() or return false here to terminate the upload but leave the UI elements alone.
			if (token.expires < ts)  data.ff_info.RemoveFile();
		},
		uploadcompleted : function(e, data) {
			data.ff_info.RemoveFile();
		}
	});
});
</script>

To sanitize filenames when they're added or changed client-side, pass in a sanitize callback. This function accepts the filename as a parameter and requires a filename to be returned. This provides an opportunity to modify any filename according to your particular standards, such as stripping out special characters that will cause errors on your server's file system or database, forcing length restrictions, or appending a timestamp.

<script type="text/javascript">
$(function() {
	$('#thefiles').FancyFileUpload({
		params : {
			action : 'fileuploader'
		},
		edit : true,
		sanitize: function (filename) // return a valid filename whenever a file is added or changed
		{
			console.log("Sanitizing filename "+filename);
			filename = String(filename).replace(/\s/gm,"_");		// replace spaces with underscores
			filename = String(filename).replace(/[^A-Za-z0-9_\-.]/gm,"");	// remove anything not valid in a filename
			if (!filename) {						// handle an empty string
				console.log("No filename found, so adding a default.");
				let date = new Date();
				filename = "file_"+date.getFullYear()+"-"+date.getMonth()+"-"+date.getDate()+"_"+date.getHours()+"-"+date.getMinutes()+"-"+date.getSeconds(); }
			console.log("Sanitized filename to "+filename);
			return filename;
		},
	});
});
</script>

To use chunked uploads for handling large file transfers, read up on jQuery File Upload chunked file uploads and do something like:

<script type="text/javascript">
$(function() {
	$('#thefiles').FancyFileUpload({
		params : {
			action : 'fileuploader'
		},
		fileupload : {
			maxChunkSize : 1000000
		}
	});
});
</script>

To remove the widget altogether and restore the original file input, call: $('#thefiles').FancyFileUpload('destroy');

Options

This plugin accepts the following options:

  • url - A string containing the destination URL to use to send the data. The default behavior is to locate the action of the nearest form element to the matching input file element and use that (Default is '').
  • params - An object containing key-value pairs to send to the server when submitting file data (Default is an empty object).
  • edit - A boolean indicating whether or not to allow the user to enter a filename minus the file extension after selecting a file but before the upload process has started (Default is true).
  • maxfilesize - An integer containing the maximum size, in bytes, to allow for file upload (Default is -1, which means no limit).
  • accept - An array containing a list of allowed file extensions (Default is null, which allows all file extensions). Note that the server is still responsible for validating uploads.
  • displayunits - A string containing one of 'iec_windows', 'iec_formal', or 'si' to specify what units to use when displaying file sizes to the user (Default is 'iec_windows').
  • adjustprecision - A boolean indicating whether or not to adjust the final precision when displaying file sizes to the user (Default is true).
  • retries - An integer containing the number of retries to perform before giving up (Default is 5).
  • retrydelay - An integer containing the base delay, in milliseconds, to apply between retries (Default is 500). Note that the delay is multiplied by 2 for exponential fallback.
  • preinit - A valid callback function that is called during initialization to allow for last second changes to the settings. Useful for altering fileupload options on the fly. The callback function must accept one parameter - callback(settings).
  • added - A valid callback function that is called for each item after its UI has been added to the DOM. The callback function must accept two parameters - callback(e, data).
  • showpreview - A valid callback function that is called after the preview dialog appears. Useful for temporarily preventing unwanted UI interactions elsewhere. The callback function must accept three parameters - callback(data, preview, previewclone).
  • hidepreview - A valid callback function that is called after the preview dialog disappears. The callback function must accept three parameters - callback(data, preview, previewclone).
  • startupload - A valid callback function that is called when the button is clicked to start the upload. The callback function must accept three parameters - callback(SubmitUpload, e, data). The callback is expected to call the SubmitUpload() function when it is ready to start the file upload.
  • continueupload - A valid callback function that is called whenever progress is updated (default is every 100 milliseconds). The callback function must accept three parameters - callback(e, data). The callback may return false or call data.abort() to cancel the upload.
  • uploadcancelled - A valid callback function that is called whenever an upload has been cancelled. The callback function must accept two parameters - callback(e, data).
  • uploadcompleted - A valid callback function that is called whenever an upload has successfully completed. The callback function must accept two parameters - callback(e, data).
  • fileupload - An object containing jQuery File Upload options (Default is an empty object). The following options are immutable cannot be changed: singleFileUploads (always true), dropZone, add, progress, fail, done, chunksend, and chunkdone. The dataType option must be 'json' (the default) or 'jsonp' as the plugin depends on a valid JSON response for correct operation.
  • langmap - An object containing translation strings. Support exists for most of the user interface (Default is an empty object).
  • multionly - A boolean that disables per-file upload buttons when true.
  • sanitize - A valid callback function that is called whenever a file is added or a filename has changed client-side (triggers on blur). Accepts a filename as a parameter and must return a filename.

All callbacks have a this containing the jQuery object for the current UI table row. Use the jQuery this.find(selector) syntax to locate relevant UI elements.

The default settings can be adjusted before creating any instances via $.FancyFileUpload.defaults. The most common use-case is to apply a set of translation strings to langmap.

Under the Hood

jQuery Fancy File Uploader uses the core plugin from blueimp jQuery File Upload and then wraps the core plugin up in the custom user interface that users interact with.

About

A jQuery plugin to convert the HTML file input type into a fancy file uploader under a MIT or LGPL license. Mobile-friendly too!

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • JavaScript 88.2%
  • PHP 11.8%