/*!
* @copyright Copyright © Kartik Visweswaran, Krajee.com, 2014
* @version 2.6.0
*
* File input styled for Bootstrap 3.0 that utilizes HTML5 File Input's advanced
* features including the FileReader API.
*
* The plugin drastically enhances the HTML file input to preview multiple files on the client before
* upload. In addition it provides the ability to preview content of images, text, videos, audio, html,
* flash and other objects.
*
* Author: Kartik Visweswaran
* Copyright: 2014, Kartik Visweswaran, Krajee.com
* For more JQuery plugins visit http://plugins.krajee.com
* For more Yii related demos visit http://demos.krajee.com
*/
(function ($) {
var STYLE_SETTING = 'style="width:{width};height:{height};"';
var PREVIEW_LABEL = '
{caption}
\n';
var OBJECT_PARAMS = ' \n' +
' \n' +
' \n' +
' \n' +
' \n'+
' \n';
var DEFAULT_PREVIEW = '\n' +
'
\n' +
' ';
var defaultLayoutTemplates = {
main1: '{preview}\n' +
'',
main2: '{preview}\n{remove}\n{upload}\n{browse}\n',
preview: '\n' +
'
×
\n' +
'
\n' +
'
' +
'
\n' +
'
\n' +
'
',
caption: '',
modal: '\n' +
'
\n' +
'
\n' +
' \n' +
'
\n' +
' \n' +
'
\n' +
'
\n' +
'
\n' +
'
\n'
};
var defaultPreviewTypes = ['image', 'html', 'text', 'video', 'audio', 'flash', 'object'];
var defaultPreviewTemplates = {
generic: '\n' +
' {content}\n' +
'
\n',
html: '\n' +
' \n' + PREVIEW_LABEL +
'
',
image: '\n' +
'

\n' +
'
\n',
text: '\n' +
'
\n' +
' {data}\n' +
'
\n' +
'
\n',
video: '\n' +
' \n' + PREVIEW_LABEL +
'
\n',
audio: '\n' +
'
\n' + PREVIEW_LABEL +
'
\n',
flash: '\n' +
' \n' + PREVIEW_LABEL +
'
\n',
object: '\n' +
'
\n' + PREVIEW_LABEL +
'
',
other: '\n' +
' ' + DEFAULT_PREVIEW + '\n' + PREVIEW_LABEL +
'
',
};
var defaultPreviewSettings = {
image: {width: "auto", height: "160px"},
html: {width: "320px", height: "180px"},
text: {width: "160px", height: "160px"},
video: {width: "320px", height: "240px"},
audio: {width: "320px", height: "80px"},
flash: {width: "320px", height: "240px"},
object: {width: "320px", height: "300px"},
other: {width: "160px", height: "120px"}
};
var defaultFileTypeSettings = {
image: function(vType, vName) {
return (typeof vType !== "undefined") ? vType.match('image.*') : vName.match(/\.(gif|png|jpe?g)$/i);
},
html: function(vType, vName) {
return (typeof vType !== "undefined") ? vType == 'text/html' : vName.match(/\.(htm|html)$/i);
},
text: function(vType, vName) {
return typeof vType !== "undefined" && vType.match('text.*') || vName.match(/\.(txt|md|csv|nfo|php|ini)$/i);
},
video: function (vType, vName) {
return typeof vType !== "undefined" && vType.match(/\.video\/(ogg|mp4|webm)$/i) || vName.match(/\.(og?|mp4|webm)$/i);
},
audio: function (vType, vName) {
return typeof vType !== "undefined" && vType.match(/\.audio\/(ogg|mp3|wav)$/i) || vName.match(/\.(ogg|mp3|wav)$/i);
},
flash: function (vType, vName) {
return typeof vType !== "undefined" && vType == 'application/x-shockwave-flash' || vName.match(/\.(swf)$/i);
},
object: function (vType, vName) {
return true;
},
other: function (vType, vName) {
return true;
},
};
var isEmpty = function (value, trim) {
return value === null || value === undefined || value == []
|| value === '' || trim && $.trim(value) === '';
},
isArray = function (a) {
return Array.isArray(a) || Object.prototype.toString.call(a) === '[object Array]';
},
isSet = function (needle, haystack) {
return (typeof haystack == 'object' && needle in haystack);
},
getValue = function (options, param, value) {
return (isEmpty(options) || isEmpty(options[param])) ? value : options[param];
},
getElement = function (options, param, value) {
return (isEmpty(options) || isEmpty(options[param])) ? value : $(options[param]);
},
uniqId = function () {
return Math.round(new Date().getTime() + (Math.random() * 100));
},
hasFileAPISupport = function () {
return window.File && window.FileReader && window.FileList && window.Blob;
},
htmlEncode = function(str) {
return String(str)
.replace(/&/g, '&')
.replace(/"/g, '"')
.replace(/'/g, ''')
.replace(//g, '>');
},
vUrl = window.URL || window.webkitURL;
var FileInput = function (element, options) {
this.$element = $(element);
if (hasFileAPISupport()) {
this.init(options);
this.listen();
} else {
this.$element.removeClass('file-loading');
}
};
FileInput.prototype = {
constructor: FileInput,
init: function (options) {
var self = this;
self.reader = null;
self.showCaption = options.showCaption;
self.showPreview = options.showPreview;
self.maxFileSize = options.maxFileSize;
self.maxFileCount = options.maxFileCount;
self.msgSizeTooLarge = options.msgSizeTooLarge;
self.msgFilesTooMany = options.msgFilesTooMany;
self.msgFileNotFound = options.msgFileNotFound;
self.msgFileNotReadable = options.msgFileNotReadable;
self.msgFilePreviewAborted = options.msgFilePreviewAborted;
self.msgFilePreviewError = options.msgFilePreviewError;
self.msgValidationError = options.msgValidationError;
self.msgErrorClass = options.msgErrorClass;
self.initialDelimiter = options.initialDelimiter;
self.initialPreview = options.initialPreview;
self.initialCaption = options.initialCaption;
self.initialPreviewCount = options.initialPreviewCount;
self.initialPreviewContent = options.initialPreviewContent;
self.overwriteInitial = options.overwriteInitial;
self.layoutTemplates = options.layoutTemplates;
self.previewTemplates = options.previewTemplates;
self.allowedPreviewTypes = isEmpty(options.allowedPreviewTypes) ? defaultPreviewTypes : options.allowedPreviewTypes;
self.allowedPreviewMimeTypes = options.allowedPreviewMimeTypes;
self.allowedFileTypes = options.allowedFileTypes;
self.allowedFileExtensions = options.allowedFileExtensions;
self.previewSettings = options.previewSettings;
self.fileTypeSettings = options.fileTypeSettings;
self.showRemove = options.showRemove;
self.showUpload = options.showUpload;
self.captionClass = options.captionClass;
self.previewClass = options.previewClass;
self.mainClass = options.mainClass;
self.mainTemplate = self.showCaption ? self.getLayoutTemplate('main1') : self.getLayoutTemplate('main2');
self.captionTemplate = self.getLayoutTemplate('caption');
self.previewGenericTemplate = self.getPreviewTemplate('generic');
self.browseLabel = options.browseLabel;
self.browseIcon = options.browseIcon;
self.browseClass = options.browseClass;
self.removeLabel = options.removeLabel;
self.removeIcon = options.removeIcon;
self.removeClass = options.removeClass;
self.uploadLabel = options.uploadLabel;
self.uploadIcon = options.uploadIcon;
self.uploadClass = options.uploadClass;
self.uploadUrl = options.uploadUrl;
self.msgLoading = options.msgLoading;
self.msgProgress = options.msgProgress;
self.msgSelected = options.msgSelected;
self.msgInvalidFileType = options.msgInvalidFileType;
self.msgInvalidFileExtension = options.msgInvalidFileExtension;
self.previewFileType = options.previewFileType;
self.wrapTextLength = options.wrapTextLength;
self.wrapIndicator = options.wrapIndicator;
self.isError = false;
self.isDisabled = self.$element.attr('disabled') || self.$element.attr('readonly');
if (isEmpty(self.$element.attr('id'))) {
self.$element.attr('id', uniqId());
}
if (typeof self.$container == 'undefined') {
self.$container = self.createContainer();
} else {
self.refreshContainer();
}
self.$captionContainer = getElement(options, 'elCaptionContainer', self.$container.find('.file-caption'));
self.$caption = getElement(options, 'elCaptionText', self.$container.find('.file-caption-name'));
self.$previewContainer = getElement(options, 'elPreviewContainer', self.$container.find('.file-preview'));
self.$preview = getElement(options, 'elPreviewImage', self.$container.find('.file-preview-thumbnails'));
self.$previewStatus = getElement(options, 'elPreviewStatus', self.$container.find('.file-preview-status'));
self.$errorContainer = getElement(options, 'elErrorContainer', self.$previewContainer.find('.kv-fileinput-error'));
self.$errorContainer.hide();
var content = self.initialPreview;
self.initialPreviewCount = isArray(content) ? content.length : (content.length > 0 ? content.split(self.initialDelimiter).length : 0)
self.initPreview();
self.original = {
preview: self.$preview.html(),
caption: self.$caption.html()
};
self.options = options;
self.$element.removeClass('file-loading');
},
getLayoutTemplate: function(t) {
var self = this;
return isSet(t, self.layoutTemplates) ? self.layoutTemplates[t] : defaultLayoutTemplates[t];
},
getPreviewTemplate: function(t) {
var self = this;
return isSet(t, self.previewTemplates) ? self.previewTemplates[t] : defaultPreviewTemplates[t];
},
listen: function () {
var self = this, $el = self.$element, $cap = self.$captionContainer, $btnFile = self.$btnFile;
$el.on('change', $.proxy(self.change, self));
$btnFile.on('click', function (ev) {
self.clear(false);
$cap.focus();
});
$el.closest('form').on('reset', $.proxy(self.reset, self));
self.$container.on('click', '.fileinput-remove:not([disabled])', $.proxy(self.clear, self));
},
refresh: function (options) {
var self = this, params = (arguments.length) ? $.extend(self.options, options) : self.options;
self.init(params);
},
initPreview: function () {
var self = this, html = '', content = self.initialPreview, len = self.initialPreviewCount,
cap = self.initialCaption.length, previewId = "preview-" + uniqId(),
caption = (cap > 0) ? self.initialCaption : self.msgSelected.replace(/\{n\}/g, len),
title = $(caption).text();
if (isArray(content) && len > 0) {
for (var i = 0; i < len; i++) {
previewId += '-' + i;
html += self.previewGenericTemplate.replace(/\{previewId\}/g, previewId).replace(/\{content\}/g,
content[i]);
}
if (len > 1 && cap == 0) {
caption = self.msgSelected.replace(/\{n\}/g, len);
}
} else {
if (len > 0) {
var fileList = content.split(self.initialDelimiter);
for (var i = 0; i < len; i++) {
previewId += '-' + i;
html += self.previewGenericTemplate.replace(/\{previewId\}/g, previewId).replace(/\{content\}/g,
fileList[i]);
}
if (len > 1 && cap == 0) {
caption = self.msgSelected.replace(/\{n\}/g, len);
}
} else {
if (cap > 0) {
self.$caption.html(caption);
self.$captionContainer.attr('title', title);
return;
} else {
return;
}
}
}
self.initialPreviewContent = html;
self.$preview.html(html);
self.$caption.html(caption);
self.$captionContainer.attr('title', title);
self.$container.removeClass('file-input-new');
},
clearObjects: function() {
var self = this, $preview = self.$preview;
$preview.find('video audio').each(function() {
this.pause();
delete(this);
$(this).remove();
});
$preview.find('img object div').each(function() {
delete(this);
$(this).remove();
});
},
clearFileInput: function() {
var self = this, $el = self.$element;
// Fix for IE ver < 11, that does not clear file inputs
if (/MSIE/.test(navigator.userAgent)) {
$el.wrap('