Last active
August 29, 2015 14:06
-
-
Save mrosati84/b4ab536365d05cb9cf56 to your computer and use it in GitHub Desktop.
A super-simple jQuery plugin that handles drag-to-upload files
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function(window, document, $) { | |
'use strict'; | |
if ( ! String.hasOwnProperty('hashCode') ) { | |
/** | |
* returns a hash code from a base string | |
* @return {string} | |
*/ | |
String.prototype.hashCode = function() { | |
var hash = 0, i, chr, len; | |
if (this.length === 0) return hash; | |
for (i = 0, len = this.length; i < len; i++) { | |
chr = this.charCodeAt(i); | |
hash = ((hash << 5) - hash) + chr; | |
hash |= 0; // Convert to 32bit integer | |
} | |
return hash; | |
}; | |
} | |
$.fn.upload = function(options) { | |
/* ========================= | |
* Plugin internal variables | |
======================== */ | |
var _el = this, // the object on which you called the plugin | |
_rawEl = this.get(0), // the raw HTML node | |
_settings = $.extend({ | |
'form': $('#form'), // the form | |
'trigger': $('#trigger-file'), // button to trigger file selection | |
'fallback': $('#fallback'), // the fallback input files | |
'preview': $('#preview'), // default id for the preview container | |
'maxUpload': 5, | |
'maxSize': '200000', | |
'mimeTypes': ['image/jpeg', 'image/png'] | |
}, options); | |
/** | |
* bind the drag events and form handle | |
* @return {void} | |
*/ | |
function _bindDrag() { | |
_el.on('dragover', function(e) { | |
// add 'hover' class when hovering files | |
_el.addClass('hover'); | |
e.preventDefault(); | |
return false; | |
}); | |
_el.on('dragend', function() { | |
// remove 'hover' class when drag ends | |
_el.removeClass('hover'); | |
}); | |
_el.on('dragleave', function() { | |
// remove 'hover' class when drag ends | |
_el.removeClass('hover'); | |
}); | |
_el.on('drop', function(e) { | |
_handleFileSelection(e); | |
e.preventDefault(); | |
return false; | |
}); | |
// click to remove images | |
_settings.preview.on('click', '.preview-img', function(e) { | |
$(this).remove(); | |
}); | |
// handle form submission | |
_settings.form.on('submit', function(e) { | |
var form = $(this); | |
// convert images in base64 hidden uploads | |
$('.preview-img').each(function(index, element) { | |
var input = $('<input>') | |
.attr('type', 'hidden') | |
.attr('name', 'image-' + index) | |
.val($(element).attr('src')); | |
form.append(input); | |
}); | |
// remove file input that triggers manual selection | |
_settings.trigger.remove(); | |
}); | |
_rawEl.ondrop = function(e) { | |
_el.removeClass('hover'); | |
e.preventDefault(); | |
return false; | |
}; | |
// handle "manual" file selection | |
_settings.trigger.on('change', function(e) { | |
_handleFileSelection(e); | |
}); | |
} | |
function _handleFileSelection(e) { | |
var files = (e.type === 'drop') ? e.originalEvent.dataTransfer.files : e.originalEvent.target.files, | |
filesCount = files.length; | |
// create previews | |
for ( var i = 0; i < filesCount; i++ ) { | |
var reader = new FileReader(); | |
reader.onload = _onFileLoad; | |
if ( _validateMime(files[i].type ) && _validateSize(files[i].size ) ) { | |
reader.readAsDataURL(files[i]); | |
} | |
} | |
} | |
function _onFileLoad(e) { | |
// get a hash code for this image | |
var previewHashCode = e.target.result.hashCode(); | |
// check number of dragged elements | |
if ( _settings.preview.find('img').length >= _settings.maxUpload ) { | |
return false; | |
} | |
// check if this image has already been dragged | |
if ( $('.preview-img[data-hash="'+previewHashCode+'"]').length > 0 ) { | |
return false; | |
} | |
// append preview images | |
var preview = $('<img data-hash="' + previewHashCode + '" class="preview-img">'); | |
preview.attr('src', e.target.result); | |
_settings.preview.append(preview); | |
} | |
/** | |
* check the plugin compatibility | |
* @return {boolean} | |
*/ | |
function _checkCompatibility() { | |
if ( window.hasOwnProperty('File') && | |
window.hasOwnProperty('FileReader') && | |
window.hasOwnProperty('FileList') ) { | |
return true; | |
} | |
} | |
/** | |
* validate file size | |
* @param {integer} size the size of the file | |
* @return {boolean} | |
*/ | |
function _validateSize(size) { | |
return size <= _settings.maxSize; | |
} | |
/** | |
* validate file mime type | |
* @param {string} mime the mime type of the file | |
* @return {boolean} | |
*/ | |
function _validateMime(mime) { | |
for ( var i = 0; i < _settings.mimeTypes.length; i++ ) { | |
if ( mime === _settings.mimeTypes[i] ) { | |
return true; | |
} | |
} | |
return false; | |
} | |
/* ============== | |
* Public methods | |
============= */ | |
this.api = { | |
getRawEl: function() { | |
return _rawEl; | |
} | |
}; | |
/** | |
* initialize the plugin | |
* @return {void} | |
*/ | |
function _init() { | |
if ( _checkCompatibility() ) { | |
_settings.fallback.hide(); // hide legacy file input | |
_bindDrag(); // bind the filedrag events | |
} | |
} | |
// fire plugin | |
_init(); | |
// preserve jQuery method chaining | |
return this; | |
}; | |
}(window, document, jQuery)); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Super-simple jQuery drag to upload
Usage
This is the basic HTML code you need to work with this plugin
Call the plugin like this
$('#drop').upload()
and pass in your options, or leave it blank to use the default ones. The selector#drop
points to the HTML node you will use to drop your files in. This node and the actual HTML form do not need to be related in any way, they can be completely separated.Files can be dragged or selected in the classical way. Just set-up the
trigger
option and select a valid<input type="file">
to manually open the file selection dialog window.Please note that the resulting POST request will generate
n
hidden inputs, wheren
is the number of dropped files. For each of these files the input will be populated with the base64 encoded content of the file.Note about compatibility
This plugin works starting from Internet Explorer v. 10. For earlier versions, a fallback input will be provided. You can see the fallback legacy input in the
<div id="fallback">
container.