658 lines
17 KiB
JavaScript
658 lines
17 KiB
JavaScript
/*!
|
||
* =============================================================
|
||
* dropify v0.2.1 - Override your input files with style.
|
||
* https://github.com/JeremyFagis/dropify
|
||
*
|
||
* (c) 2016 - Jeremy FAGIS <jeremy@fagis.fr> (http://fagis.fr)
|
||
* =============================================================
|
||
*/
|
||
|
||
;(function(root, factory) {
|
||
if (typeof define === 'function' && define.amd) {
|
||
define(['jquery'], factory);
|
||
} else if (typeof exports === 'object') {
|
||
module.exports = factory(require('jquery'));
|
||
} else {
|
||
root.Dropify = factory(root.jQuery);
|
||
}
|
||
}(this, function($) {
|
||
var pluginName = "dropify";
|
||
|
||
/**
|
||
* Dropify plugin
|
||
*
|
||
* @param {Object} element
|
||
* @param {Array} options
|
||
*/
|
||
function Dropify(element, options) {
|
||
if (!(window.File && window.FileReader && window.FileList && window.Blob)) {
|
||
return;
|
||
}
|
||
|
||
var defaults = {
|
||
defaultFile: '',
|
||
maxFileSize: 0,
|
||
minWidth: 0,
|
||
maxWidth: 0,
|
||
minHeight: 0,
|
||
maxHeight: 0,
|
||
showRemove: true,
|
||
showLoader: true,
|
||
showErrors: true,
|
||
errorTimeout: 3000,
|
||
errorsPosition: 'overlay',
|
||
imgFileExtensions: ['png', 'jpg', 'jpeg', 'gif', 'bmp'],
|
||
maxFileSizePreview: "5M",
|
||
allowedFormats: ['portrait', 'square', 'landscape'],
|
||
allowedFileExtensions: ['*'],
|
||
messages: {
|
||
'default': 'Drag and drop a file here or click',
|
||
'replace': 'Drag and drop or click to replace',
|
||
'remove': 'Remove',
|
||
'error': 'Ooops, something wrong appended.'
|
||
},
|
||
error: {
|
||
'fileSize': 'The file size is too big ({{ value }} max).',
|
||
'minWidth': 'The image width is too small ({{ value }}}px min).',
|
||
'maxWidth': 'The image width is too big ({{ value }}}px max).',
|
||
'minHeight': 'The image height is too small ({{ value }}}px min).',
|
||
'maxHeight': 'The image height is too big ({{ value }}px max).',
|
||
'imageFormat': 'The image format is not allowed ({{ value }} only).',
|
||
'fileExtension': 'The file is not allowed ({{ value }} only).'
|
||
},
|
||
tpl: {
|
||
wrap: '<div class="dropify-wrapper"></div>',
|
||
loader: '<div class="dropify-loader"></div>',
|
||
message: '<div class="dropify-message"><span class="file-icon" /> <p>{{ default }}</p></div>',
|
||
preview: '<div class="dropify-preview"><span class="dropify-render"></span><div class="dropify-infos"><div class="dropify-infos-inner"><p class="dropify-infos-message">{{ replace }}</p></div></div></div>',
|
||
filename: '<p class="dropify-filename"><span class="file-icon"></span> <span class="dropify-filename-inner"></span></p>',
|
||
clearButton: '<button type="button" class="dropify-clear">{{ remove }}</button>',
|
||
errorLine: '<p class="dropify-error">{{ error }}</p>',
|
||
errorsContainer: '<div class="dropify-errors-container"><ul></ul></div>'
|
||
}
|
||
};
|
||
|
||
this.element = element;
|
||
this.input = $(this.element);
|
||
this.wrapper = null;
|
||
this.preview = null;
|
||
this.filenameWrapper = null;
|
||
this.settings = $.extend(true, defaults, options, this.input.data());
|
||
this.errorsEvent = $.Event('dropify.errors');
|
||
this.isDisabled = false;
|
||
this.isInit = false;
|
||
this.file = {
|
||
object: null,
|
||
name: null,
|
||
size: null,
|
||
width: null,
|
||
height: null,
|
||
type: null
|
||
};
|
||
|
||
if (!Array.isArray(this.settings.allowedFormats)) {
|
||
this.settings.allowedFormats = this.settings.allowedFormats.split(' ');
|
||
}
|
||
|
||
if (!Array.isArray(this.settings.allowedFileExtensions)) {
|
||
this.settings.allowedFileExtensions = this.settings.allowedFileExtensions.split(' ');
|
||
}
|
||
|
||
this.onChange = this.onChange.bind(this);
|
||
this.clearElement = this.clearElement.bind(this);
|
||
this.onFileReady = this.onFileReady.bind(this);
|
||
|
||
this.translateMessages();
|
||
this.createElements();
|
||
this.setContainerSize();
|
||
|
||
this.errorsEvent.errors = [];
|
||
|
||
this.input.on('change', this.onChange);
|
||
}
|
||
|
||
/**
|
||
* On change event
|
||
*/
|
||
Dropify.prototype.onChange = function()
|
||
{
|
||
this.resetPreview();
|
||
this.readFile(this.element);
|
||
};
|
||
|
||
/**
|
||
* Create dom elements
|
||
*/
|
||
Dropify.prototype.createElements = function()
|
||
{
|
||
this.isInit = true;
|
||
this.input.wrap($(this.settings.tpl.wrap));
|
||
this.wrapper = this.input.parent();
|
||
|
||
var messageWrapper = $(this.settings.tpl.message).insertBefore(this.input);
|
||
$(this.settings.tpl.errorLine).appendTo(messageWrapper);
|
||
|
||
if (this.isTouchDevice() === true) {
|
||
this.wrapper.addClass('touch-fallback');
|
||
}
|
||
|
||
if (this.input.attr('disabled')) {
|
||
this.isDisabled = true;
|
||
this.wrapper.addClass('disabled');
|
||
}
|
||
|
||
if (this.settings.showLoader === true) {
|
||
this.loader = $(this.settings.tpl.loader);
|
||
this.loader.insertBefore(this.input);
|
||
}
|
||
|
||
this.preview = $(this.settings.tpl.preview);
|
||
this.preview.insertAfter(this.input);
|
||
|
||
if (this.isDisabled === false && this.settings.showRemove === true) {
|
||
this.clearButton = $(this.settings.tpl.clearButton);
|
||
this.clearButton.insertAfter(this.input);
|
||
this.clearButton.on('click', this.clearElement);
|
||
}
|
||
|
||
this.filenameWrapper = $(this.settings.tpl.filename);
|
||
this.filenameWrapper.prependTo(this.preview.find('.dropify-infos-inner'));
|
||
|
||
if (this.settings.showErrors === true) {
|
||
this.errorsContainer = $(this.settings.tpl.errorsContainer);
|
||
|
||
if (this.settings.errorsPosition === 'outside') {
|
||
this.errorsContainer.insertAfter(this.wrapper);
|
||
} else {
|
||
this.errorsContainer.insertBefore(this.input);
|
||
}
|
||
}
|
||
|
||
var defaultFile = this.settings.defaultFile || '';
|
||
|
||
if (defaultFile.trim() !== '') {
|
||
this.file.name = this.cleanFilename(defaultFile);
|
||
this.setPreview(this.isImage(), defaultFile);
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Read the file using FileReader
|
||
*
|
||
* @param {Object} input
|
||
*/
|
||
Dropify.prototype.readFile = function(input)
|
||
{
|
||
if (input.files && input.files[0]) {
|
||
var reader = new FileReader();
|
||
var image = new Image();
|
||
var file = input.files[0];
|
||
var srcBase64 = null;
|
||
var _this = this;
|
||
var eventFileReady = $.Event("dropify.fileReady");
|
||
|
||
this.clearErrors();
|
||
this.showLoader();
|
||
this.setFileInformations(file);
|
||
this.errorsEvent.errors = [];
|
||
this.checkFileSize();
|
||
this.isFileExtensionAllowed();
|
||
|
||
if (this.isImage() && this.file.size < this.sizeToByte(this.settings.maxFileSizePreview)) {
|
||
this.input.on('dropify.fileReady', this.onFileReady);
|
||
reader.readAsDataURL(file);
|
||
reader.onload = function(_file) {
|
||
srcBase64 = _file.target.result;
|
||
image.src = _file.target.result;
|
||
image.onload = function() {
|
||
_this.setFileDimensions(this.width, this.height);
|
||
_this.validateImage();
|
||
_this.input.trigger(eventFileReady, [true, srcBase64]);
|
||
};
|
||
|
||
}.bind(this);
|
||
} else {
|
||
this.onFileReady(false);
|
||
}
|
||
}
|
||
};
|
||
|
||
/**
|
||
* On file ready to show
|
||
*
|
||
* @param {Event} event
|
||
* @param {Bool} previewable
|
||
* @param {String} src
|
||
*/
|
||
Dropify.prototype.onFileReady = function(event, previewable, src)
|
||
{
|
||
this.input.off('dropify.fileReady', this.onFileReady);
|
||
|
||
if (this.errorsEvent.errors.length === 0) {
|
||
this.setPreview(previewable, src);
|
||
} else {
|
||
this.input.trigger(this.errorsEvent, [this]);
|
||
for (var i = this.errorsEvent.errors.length - 1; i >= 0; i--) {
|
||
var errorNamespace = this.errorsEvent.errors[i].namespace;
|
||
var errorKey = errorNamespace.split('.').pop();
|
||
this.showError(errorKey);
|
||
}
|
||
|
||
if (typeof this.errorsContainer !== "undefined") {
|
||
this.errorsContainer.addClass('visible');
|
||
|
||
var errorsContainer = this.errorsContainer;
|
||
setTimeout(function(){ errorsContainer.removeClass('visible'); }, this.settings.errorTimeout);
|
||
}
|
||
|
||
this.wrapper.addClass('has-error');
|
||
this.resetPreview();
|
||
this.clearElement();
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Set file informations
|
||
*
|
||
* @param {File} file
|
||
*/
|
||
Dropify.prototype.setFileInformations = function(file)
|
||
{
|
||
this.file.object = file;
|
||
this.file.name = file.name;
|
||
this.file.size = file.size;
|
||
this.file.type = file.type;
|
||
this.file.width = null;
|
||
this.file.height = null;
|
||
};
|
||
|
||
/**
|
||
* Set file dimensions
|
||
*
|
||
* @param {Int} width
|
||
* @param {Int} height
|
||
*/
|
||
Dropify.prototype.setFileDimensions = function(width, height)
|
||
{
|
||
this.file.width = width;
|
||
this.file.height = height;
|
||
};
|
||
|
||
/**
|
||
* Set the preview and animate it
|
||
*
|
||
* @param {String} src
|
||
*/
|
||
Dropify.prototype.setPreview = function(previewable, src)
|
||
{
|
||
this.wrapper.removeClass('has-error').addClass('has-preview');
|
||
this.filenameWrapper.children('.dropify-filename-inner').html(this.file.name);
|
||
var render = this.preview.children('.dropify-render');
|
||
|
||
this.hideLoader();
|
||
|
||
if (previewable === true) {
|
||
var imgTag = $('<img />').attr('src', src);
|
||
|
||
if (this.settings.height) {
|
||
imgTag.css("max-height", this.settings.height);
|
||
}
|
||
|
||
imgTag.appendTo(render);
|
||
} else {
|
||
$('<i />').attr('class', 'dropify-font-file').appendTo(render);
|
||
$('<span class="dropify-extension" />').html(this.getFileType()).appendTo(render);
|
||
}
|
||
this.preview.fadeIn();
|
||
};
|
||
|
||
/**
|
||
* Reset the preview
|
||
*/
|
||
Dropify.prototype.resetPreview = function()
|
||
{
|
||
this.wrapper.removeClass('has-preview');
|
||
var render = this.preview.children('.dropify-render');
|
||
render.find('.dropify-extension').remove();
|
||
render.find('i').remove();
|
||
render.find('img').remove();
|
||
this.preview.hide();
|
||
this.hideLoader();
|
||
};
|
||
|
||
/**
|
||
* Clean the src and get the filename
|
||
*
|
||
* @param {String} src
|
||
*
|
||
* @return {String} filename
|
||
*/
|
||
Dropify.prototype.cleanFilename = function(src)
|
||
{
|
||
var filename = src.split('\\').pop();
|
||
if (filename == src) {
|
||
filename = src.split('/').pop();
|
||
}
|
||
|
||
return src !== "" ? filename : '';
|
||
};
|
||
|
||
/**
|
||
* Clear the element, events are available
|
||
*/
|
||
Dropify.prototype.clearElement = function()
|
||
{
|
||
if (this.errorsEvent.errors.length === 0) {
|
||
var eventBefore = $.Event("dropify.beforeClear");
|
||
this.input.trigger(eventBefore, [this]);
|
||
|
||
if (eventBefore.result !== false) {
|
||
this.resetFile();
|
||
this.input.val('');
|
||
this.resetPreview();
|
||
|
||
this.input.trigger($.Event("dropify.afterClear"), [this]);
|
||
}
|
||
} else {
|
||
this.resetFile();
|
||
this.input.val('');
|
||
this.resetPreview();
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Reset file informations
|
||
*/
|
||
Dropify.prototype.resetFile = function()
|
||
{
|
||
this.file.object = null;
|
||
this.file.name = null;
|
||
this.file.size = null;
|
||
this.file.type = null;
|
||
this.file.width = null;
|
||
this.file.height = null;
|
||
};
|
||
|
||
/**
|
||
* Set the container height
|
||
*/
|
||
Dropify.prototype.setContainerSize = function()
|
||
{
|
||
if (this.settings.height) {
|
||
this.wrapper.height(this.settings.height);
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Test if it's touch screen
|
||
*
|
||
* @return {Boolean}
|
||
*/
|
||
Dropify.prototype.isTouchDevice = function()
|
||
{
|
||
return (('ontouchstart' in window) ||
|
||
(navigator.MaxTouchPoints > 0) ||
|
||
(navigator.msMaxTouchPoints > 0));
|
||
};
|
||
|
||
/**
|
||
* Get the file type.
|
||
*
|
||
* @return {String}
|
||
*/
|
||
Dropify.prototype.getFileType = function()
|
||
{
|
||
return this.file.name.split('.').pop().toLowerCase();
|
||
};
|
||
|
||
/**
|
||
* Test if the file is an image
|
||
*
|
||
* @return {Boolean}
|
||
*/
|
||
Dropify.prototype.isImage = function()
|
||
{
|
||
if (this.settings.imgFileExtensions.indexOf(this.getFileType()) != "-1") {
|
||
return true;
|
||
}
|
||
|
||
return false;
|
||
};
|
||
|
||
/**
|
||
* Test if the file extension is allowed
|
||
*
|
||
* @return {Boolean}
|
||
*/
|
||
Dropify.prototype.isFileExtensionAllowed = function () {
|
||
|
||
if (this.settings.allowedFileExtensions.indexOf('*') != "-1" ||
|
||
this.settings.allowedFileExtensions.indexOf(this.getFileType()) != "-1") {
|
||
return true;
|
||
}
|
||
this.pushError("fileExtension");
|
||
|
||
return false;
|
||
};
|
||
|
||
/**
|
||
* Translate messages if needed.
|
||
*/
|
||
Dropify.prototype.translateMessages = function()
|
||
{
|
||
for (var name in this.settings.tpl) {
|
||
for (var key in this.settings.messages) {
|
||
this.settings.tpl[name] = this.settings.tpl[name].replace('{{ ' + key + ' }}', this.settings.messages[key]);
|
||
}
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Check the limit filesize.
|
||
*/
|
||
Dropify.prototype.checkFileSize = function()
|
||
{
|
||
if (this.sizeToByte(this.settings.maxFileSize) !== 0 && this.file.size > this.sizeToByte(this.settings.maxFileSize)) {
|
||
this.pushError("fileSize");
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Convert filesize to byte.
|
||
*
|
||
* @return {Int} value
|
||
*/
|
||
Dropify.prototype.sizeToByte = function(size)
|
||
{
|
||
var value = 0;
|
||
|
||
if (size !== 0) {
|
||
var unit = size.slice(-1).toUpperCase(),
|
||
kb = 1024,
|
||
mb = kb * 1024,
|
||
gb = mb * 1024;
|
||
|
||
if (unit === 'K') {
|
||
value = parseFloat(size) * kb;
|
||
} else if (unit === 'M') {
|
||
value = parseFloat(size) * mb;
|
||
} else if (unit === 'G') {
|
||
value = parseFloat(size) * gb;
|
||
}
|
||
}
|
||
|
||
return value;
|
||
};
|
||
|
||
/**
|
||
* Validate image dimensions and format
|
||
*/
|
||
Dropify.prototype.validateImage = function()
|
||
{
|
||
if (this.settings.minWidth !== 0 && this.settings.minWidth >= this.file.width) {
|
||
this.pushError("minWidth");
|
||
}
|
||
|
||
if (this.settings.maxWidth !== 0 && this.settings.maxWidth <= this.file.width) {
|
||
this.pushError("maxWidth");
|
||
}
|
||
|
||
if (this.settings.minHeight !== 0 && this.settings.minHeight >= this.file.height) {
|
||
this.pushError("minHeight");
|
||
}
|
||
|
||
if (this.settings.maxHeight !== 0 && this.settings.maxHeight <= this.file.height) {
|
||
this.pushError("maxHeight");
|
||
}
|
||
|
||
if (this.settings.allowedFormats.indexOf(this.getImageFormat()) == "-1") {
|
||
this.pushError("imageFormat");
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Get image format.
|
||
*
|
||
* @return {String}
|
||
*/
|
||
Dropify.prototype.getImageFormat = function()
|
||
{
|
||
if (this.file.width == this.file.height) {
|
||
return "square";
|
||
}
|
||
|
||
if (this.file.width < this.file.height) {
|
||
return "portrait";
|
||
}
|
||
|
||
if (this.file.width > this.file.height) {
|
||
return "landscape";
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Push error
|
||
*
|
||
* @param {String} errorKey
|
||
*/
|
||
Dropify.prototype.pushError = function(errorKey) {
|
||
var e = $.Event("dropify.error." + errorKey);
|
||
this.errorsEvent.errors.push(e);
|
||
this.input.trigger(e, [this]);
|
||
};
|
||
|
||
/**
|
||
* Clear errors
|
||
*/
|
||
Dropify.prototype.clearErrors = function()
|
||
{
|
||
if (typeof this.errorsContainer !== "undefined") {
|
||
this.errorsContainer.children('ul').html('');
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Show error in DOM
|
||
*
|
||
* @param {String} errorKey
|
||
*/
|
||
Dropify.prototype.showError = function(errorKey)
|
||
{
|
||
if (typeof this.errorsContainer !== "undefined") {
|
||
this.errorsContainer.children('ul').append('<li>' + this.getError(errorKey) + '</li>');
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Get error message
|
||
*
|
||
* @return {String} message
|
||
*/
|
||
Dropify.prototype.getError = function(errorKey)
|
||
{
|
||
var error = this.settings.error[errorKey],
|
||
value = '';
|
||
|
||
if (errorKey === 'fileSize') {
|
||
value = this.settings.maxFileSize;
|
||
} else if (errorKey === 'minWidth') {
|
||
value = this.settings.minWidth;
|
||
} else if (errorKey === 'maxWidth') {
|
||
value = this.settings.maxWidth;
|
||
} else if (errorKey === 'minHeight') {
|
||
value = this.settings.minHeight;
|
||
} else if (errorKey === 'maxHeight') {
|
||
value = this.settings.maxHeight;
|
||
} else if (errorKey === 'imageFormat') {
|
||
value = this.settings.allowedFormats.join(', ');
|
||
} else if (errorKey === 'fileExtension') {
|
||
value = this.settings.allowedFileExtensions.join(', ');
|
||
}
|
||
|
||
if (value !== '') {
|
||
return error.replace('{{ value }}', value);
|
||
}
|
||
|
||
return error;
|
||
};
|
||
|
||
/**
|
||
* Show the loader
|
||
*/
|
||
Dropify.prototype.showLoader = function()
|
||
{
|
||
if (typeof this.loader !== "undefined") {
|
||
this.loader.show();
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Hide the loader
|
||
*/
|
||
Dropify.prototype.hideLoader = function()
|
||
{
|
||
if (typeof this.loader !== "undefined") {
|
||
this.loader.hide();
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Destroy dropify
|
||
*/
|
||
Dropify.prototype.destroy = function()
|
||
{
|
||
this.input.siblings().remove();
|
||
this.input.unwrap();
|
||
this.isInit = false;
|
||
};
|
||
|
||
/**
|
||
* Init dropify
|
||
*/
|
||
Dropify.prototype.init = function()
|
||
{
|
||
this.createElements();
|
||
};
|
||
|
||
/**
|
||
* Test if element is init
|
||
*/
|
||
Dropify.prototype.isDropified = function()
|
||
{
|
||
return this.isInit;
|
||
};
|
||
|
||
$.fn[pluginName] = function(options) {
|
||
this.each(function() {
|
||
if (!$.data(this, pluginName)) {
|
||
$.data(this, pluginName, new Dropify(this, options));
|
||
}
|
||
});
|
||
|
||
return this;
|
||
};
|
||
|
||
|
||
return Dropify;
|
||
}));
|