Переглянути джерело

Upgraded to release v2.0.0

Kartik Visweswaran 10 роки тому
батько
коміт
259df3669f
8 змінених файлів з 294 додано та 38 видалено
  1. 20 0
      CHANGE.md
  2. 143 3
      README.md
  3. 1 1
      bower.json
  4. 8 2
      css/fileinput.css
  5. 2 3
      css/fileinput.min.css
  6. 7 3
      examples/index.html
  7. 112 25
      js/fileinput.js
  8. 1 1
      js/fileinput.min.js

+ 20 - 0
CHANGE.md

@@ -1,9 +1,29 @@
+version 2.0.0
+=============
+**Date:** 25-Jul-2014
+
+1. (enh #12, #13, #14): Various enhancements and fixes.
+2. (enh #15): Enhanced validation of file size through `maxFileSize` configuration.
+3. New plugin events added: `fileerror`, `fileloaded`, `filecleared`.
+4. New plugin methods added: `disable`, `enable`
+5. Enhanced configurable templates for previewing image, text, and other files (and a generic template).
+6. Make caption text configurable through a new parameter `msgSelected`.
+7. Correct calculation of files selected when `initPreview` is false.
+8. Automatic scale images for preview, when images are too wide to fit in container.
+9. Added delimiter option for `initialPreview` to pass multiple content delimited as a string.
+
+### Additions
+1. (enh #9): Enhanced caption template and styling for captions to prevent overflow of long file names out of the caption container.
+
 version 1.9.0
 =============
 **Date:** 21-Jul-2014
 
 1. (enh #10): Ability to display initial caption, when initialPreview is false.
 
+### Additions
+1. (enh #9): Enhanced caption template and styling for captions to prevent overflow of long file names out of the caption container.
+
 version 1.8.0
 =============
 **Date:** 15-Jul-2014

+ 143 - 3
README.md

@@ -5,7 +5,7 @@ An enhanced HTML 5 file input for Bootstrap 3.x with file preview for images and
 
 ![File Input Screenshot](https://lh6.googleusercontent.com/-2niyujIaat0/UyqzA_78OQI/AAAAAAAAADE/f6IJkr11uA8/w666-h418-no/fileinput-screenshot.jpg)
 
-> NOTE: The latest version of the plugin v1.9.0 has been released. Refer the [CHANGE LOG](https://github.com/kartik-v/bootstrap-fileinput/blob/master/CHANGE.md) for details.
+> NOTE: The latest version of the plugin v2.0.0 has been released. Refer the [CHANGE LOG](https://github.com/kartik-v/bootstrap-fileinput/blob/master/CHANGE.md) for details.
 
 ## Features  
 
@@ -32,7 +32,19 @@ An enhanced HTML 5 file input for Bootstrap 3.x with file preview for images and
 11. Upload action defaults to form submit. Supports an upload route/server action parameter for custom ajax based upload.
 12. Triggers JQuery events for advanced development. Events currently available are `filereset` and `fileclear`.
 13. Disabled and readonly file input support.
-14. Size of the entire plugin is about 5KB if gzipped. The minified assets are less than 12KB (about 10KB for the minified JS and 2KB for the minified CSS). 
+14. Size of the entire plugin is less than 6KB if gzipped. The minified assets are less than 16KB (about 13KB for the minified JS and 3KB for the minified CSS). 
+
+## Release 2.0.0 Features
+
+1. (enh #12, #13): Various enhancements and fixes.
+2. (enh #15): Enhanced validation of file size through `maxFileSize` configuration.
+3. New plugin events added: `fileerror`, `fileloaded`, `filecleared`.
+4. New plugin methods added: `disable`, `enable`
+5. Enhanced configurable templates for previewing image, text, and other files (and a generic template).
+6. Make caption text configurable through a new parameter `msgSelected`.
+7. Correct calculation of files selected when `initPreview` is false.
+8. Automatic scale images for preview, when images are too wide to fit in container.
+9. Added delimiter option for `initialPreview` to pass multiple content delimited as a string.
 
 ## Demo
 
@@ -156,6 +168,10 @@ The `mainTemplate` if not passed, will be automatically set based on `showCaptio
 {preview}\n{remove}\n{upload}\n{browse}\n
 ```
 
+#### initialDelimiter
+_string_, the delimiter to be used to allow passing multiple content delimited as a string to `initialPreview`. Defaults to `'*$$*'`.
+
+
 #### initialPreview
 _string | array_ the initial preview content to be displayed. You can pass the minimal HTML markup for displaying your image, text, or file. 
 If set as a string, this will display a single file in the initial preview. If set as an array, it will display all files in the array as an 
@@ -193,6 +209,10 @@ _string_ the initial preview caption text to be displayed. If you do not set a v
 `true` this will default to `"{preview-file-count} files selected"`, where `{preview-file-count}` is the count of the 
 files passed in `initialPreview`.
 
+#### initialNbPreview
+_int_, the count of initial preview items for calculating the files selected in preview and displayed in caption (applicable when 
+`overwriteInitial` is set to `false`).
+
 #### overwriteInitial
 _boolean_ whether you wish to overwrite the initial preview content and caption setup. This defaults to `true`, whereby, any `initialPreview` content set 
 will be overwritten, when new file is uploaded or when files are cleared. Setting it to `false` will help displaying a saved image or file from database always - 
@@ -225,9 +245,68 @@ The `previewTemplate` if not set will default to:
 </div>
 ```
 
+#### previewGenericTemplate
+_string_ the generic preview template markup used within the preview container. Defaults to `IMAGE_TEMPLATE` as shown below.
+The following variables will be parsed:
+
+- `{content}`: the file preview content
+- `{previewId}`: the previewed file container identifier
+
+```html
+<div class="file-preview-frame" id="{previewId}">
+    {content}
+</div>
+```
+
+#### previewImageTemplate
+_string_ the template markup for previewing image files within the preview container. Defaults to `IMAGE_TEMPLATE` as shown below.
+The following variables will be parsed:
+
+- `{content}`: the file preview content
+- `{previewId}`: the previewed file container identifier
+
+```html
+<div class="file-preview-frame" id="{previewId}">
+    {content}
+</div>
+```
+
+#### previewTextTemplate
+_string_ the template markup for previewing text files within the preview container. Defaults to `TEXT_TEMPLATE` as shown below.
+The following variables will be parsed:
+
+- `{strText}`: the file text content
+- `{caption}`: the file name to be displayed on hover
+- `{previewId}`: the previewed file container identifier
+
+```html
+<div class="file-preview-frame" id="{previewId}">
+    <div class="file-preview-text" title="{caption}">
+        {strText}
+    </div>
+</div>
+```
+
+#### previewOtherTemplate
+_string_ the template markup for previewing all other files within the preview container. Defaults to `OTHER_TEMPLATE` as shown below.
+The following variables will be parsed:
+
+- `{caption}`: the file name to be displayed 
+- `{previewId}`: the previewed file container identifier
+
+```html
+<div class="file-preview-frame" id="{previewId}">
+   <div class="file-preview-other">
+       <h2><i class="glyphicon glyphicon-file"></i></h2>
+       {caption}
+   </div>
+</div>
+```
+
 #### browseLabel
 _string_ the label to display for the file picker/browse button. Defaults to `Browse &hellip;`.
 
+
 #### browseIcon
 _string_ the icon to display before the label for the file picker/browse button. Defaults to `<i class="glyphicon glyphicon-folder-open"></i> &nbsp;`.
 
@@ -255,6 +334,24 @@ _string_ the CSS class for the file upload button. Defaults to `btn btn-default`
 #### uploadUrl
 _string_ the URL for the upload processing action (typically for ajax based processing). Defaults to `null`. If this is not set or `null`, then the upload button action will default to form submission.
 
+#### maxFileSize
+_float_ the maximum file size for upload in KB. 
+
+#### msgSizeTooLarge
+_string_ the message to be displayed when the file size exceeds maximum size. Defaults to:
+
+```
+File "{name}" (<b>{size} KB</b>) exceeds maximum allowed upload size of <b>{maxSize} KB</b>. Please retry your upload!
+```
+where:
+
+`{name}`: will be replaced by the file name being uploaded
+`{size}`: will be replaced by the uploaded file size
+`{maxSize}`: will be replaced by the `maxFileSize` parameter.
+
+#### msgErrorClass
+_string_ the css class for the error message to be displayed in the preview window when the file size exceeds `maxSize`. Defaults to `file-error-message`.
+
 #### msgLoading
 _string_ the message displayed when the files are getting read and loaded for preview. Defaults to `Loading &hellip;`.
 
@@ -305,7 +402,7 @@ _string_ the identifier for the element containing the preview progress status (
 The plugin supports these events:
 
 #### fileclear
-This event is triggered when the file input is cleared with the remove button.
+This event is triggered when the file input the remove button is pressed for clearing the file preview.
 
 **Example:**
 ```js
@@ -314,6 +411,39 @@ $('#input-id').on('fileclear', function(event) {
 });
 ```
 
+#### filecleared
+This event is triggered after the files in the preview are cleared.
+
+**Example:**
+```js
+$('#input-id').on('filecleared', function(event) {
+    console.log("filecleared");
+});
+```
+
+#### fileerror
+This event is triggered when a client validation error is encountered for an uploaded file. 
+Additional parameters available are: `file` (FileReader instance) and `previewId` the 
+identifier for the preview file container.
+
+**Example:**
+```js
+$('#input-id').on('fileerror', function(event, file, previewId) {
+    console.log("fileerror");
+});
+```
+
+#### fileloaded
+This event is triggered after a file is loaded in the preview. Additional parameters available 
+are: `file` (FileReader instance) and `previewId` the identifier for the preview file container.
+
+**Example:**
+```js
+$('#input-id').on('fileloaded', function(event, file, previewId) {
+    console.log("fileloaded");
+});
+```
+
 #### filereset
 This event is triggered when the file input is reset to initial value.
 
@@ -327,6 +457,16 @@ $('#input-id').on('filereset', function(event) {
 ### Plugin Methods
 The plugin supports these methods:
 
+#### disable
+Disable the file input.
+```js
+$('#input-id').fileinput('disable');
+
+#### enable
+Enable the file input.
+```js
+$('#input-id').fileinput('enable');
+
 #### reset
 Reset the file input.
 ```js

+ 1 - 1
bower.json

@@ -1,6 +1,6 @@
 {
     "name": "bootstrap-fileinput",
-    "version": "1.9.0",
+    "version": "2.0.0",
     "homepage": "https://github.com/kartik-v/bootstrap-fileinput",
     "authors": [
         "Kartik Visweswaran <[email protected]>"

+ 8 - 2
css/fileinput.css

@@ -1,7 +1,7 @@
 /*!
  * @copyright Copyright &copy; Kartik Visweswaran, Krajee.com, 2014
  * @package bootstrap-fileinput
- * @version 1.9.0
+ * @version 2.0.0
  *
  * File input styling for Bootstrap 3.0
  * Built for Yii Framework 2.0
@@ -59,7 +59,13 @@
     text-overflow: ellipsis;
     width: 85%;
 }
-
+.file-error-message {
+    background-color: #f2dede;
+    color: #a94442;
+    text-align: center;
+    border-radius: 5px;
+    padding: 5px;
+}
 .file-caption-disabled {
     background-color: #EEEEEE;
     cursor: not-allowed;

+ 2 - 3
css/fileinput.min.css

@@ -1,12 +1,11 @@
 /*!
  * @copyright Copyright &copy; Kartik Visweswaran, Krajee.com, 2014
  * @package bootstrap-fileinput
- * @version 1.9.0
+ * @version 2.0.0
  *
  * File input styling for Bootstrap 3.0
  * Built for Yii Framework 2.0
  * Author: Kartik Visweswaran
  * Year: 2013
  * For more Yii related demos visit http://demos.krajee.com
- */
-.file-input{overflow-x: auto}.file-loading{top:0;right:0;width:25px;height:25px;font-size:999px;text-align:right;color:#fff;background:transparent url(../img/loading.gif) top left no-repeat;border:none}.btn-file{position:relative;overflow:hidden}.btn-file input[type=file]{position:absolute;top:0;right:0;min-width:100%;min-height:100%;font-size:999px;text-align:right;filter:alpha(opacity=0);opacity:0;background:red;cursor:inherit;display:block}.file-caption .glyphicon{display:inline-block;min-width:18px;float:left;margin-top:2px}.file-caption-name{display:inline-block;float:left;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;width:85%}.file-caption-disabled{background-color:#EEE;cursor:not-allowed;opacity:1}.file-input .btn .disabled,.file-input .btn[disabled]{cursor:not-allowed}.file-preview{border-radius:5px;border:1px solid #ddd;padding:5px;width:100%;margin-bottom:5px}.file-preview-frame{display:table;margin:8px;height:160px;border:1px solid #ddd;box-shadow:1px 1px 5px 0 #a2958a;padding:6px;float:left;text-align:center}.file-preview-frame:hover{background-color:#eee;box-shadow:2px 2px 5px 0 #333}.file-preview-image{height:150px;vertical-align:text-center}.file-preview-text{display:table-cell;width:150px;height:150px;color:#428bca;font-size:11px;vertical-align:middle;text-align:center}.file-preview-other{display:table-cell;width:150px;height:150px;font-family:Monaco,Consolas,monospace;font-size:11px;vertical-align:middle;text-align:center}.file-input-new .close,.file-input-new .file-preview,.file-input-new .fileinput-remove-button,.file-input-new .fileinput-upload-button,.file-input-new .glyphicon-file{display:none}.loading{background:transparent url(../img/loading.gif) no-repeat scroll center center content-box!important}.wrap-indicator{font-weight:700;color:#245269;cursor:pointer}
+ */.file-input{overflow-x:auto}.file-loading{top:0;right:0;width:25px;height:25px;font-size:999px;text-align:right;color:#fff;background:transparent url(../img/loading.gif) top left no-repeat;border:none}.btn-file{position:relative;overflow:hidden}.btn-file input[type=file]{position:absolute;top:0;right:0;min-width:100%;min-height:100%;font-size:999px;text-align:right;filter:alpha(opacity=0);opacity:0;background:red;cursor:inherit;display:block}.file-caption .glyphicon{display:inline-block;min-width:18px;float:left;margin-top:2px}.file-caption-name{display:inline-block;float:left;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;width:85%}.file-error-message{background-color:#f2dede;color:#a94442;text-align:center;border-radius:5px;padding:5px}.file-caption-disabled{background-color:#EEE;cursor:not-allowed;opacity:1}.file-input .btn .disabled,.file-input .btn[disabled]{cursor:not-allowed}.file-preview{border-radius:5px;border:1px solid #ddd;padding:5px;width:100%;margin-bottom:5px}.file-preview-frame{display:table;margin:8px;height:160px;border:1px solid #ddd;box-shadow:1px 1px 5px 0 #a2958a;padding:6px;float:left;text-align:center}.file-preview-frame:hover{background-color:#eee;box-shadow:2px 2px 5px 0 #333}.file-preview-image{height:150px;vertical-align:text-center}.file-preview-text{display:table-cell;width:150px;height:150px;color:#428bca;font-size:11px;vertical-align:middle;text-align:center}.file-preview-other{display:table-cell;width:150px;height:150px;font-family:Monaco,Consolas,monospace;font-size:11px;vertical-align:middle;text-align:center}.file-input-new .close,.file-input-new .file-preview,.file-input-new .fileinput-remove-button,.file-input-new .fileinput-upload-button,.file-input-new .glyphicon-file{display:none}.loading{background:transparent url(../img/loading.gif) no-repeat scroll center center content-box!important}.wrap-indicator{font-weight:700;color:#245269;cursor:pointer}

+ 7 - 3
examples/index.html

@@ -38,7 +38,8 @@
 	<script>
     $("#file-1").fileinput({
         initialPreview: ["<img src='Desert.jpg' class='file-preview-image'>", "<img src='Jellyfish.jpg' class='file-preview-image'>"],
-        overwriteInitial: true
+        overwriteInitial: false,
+        maxFileSize: 100
 	});
 	$("#file-3").fileinput({
 		showCaption: false,
@@ -46,8 +47,11 @@
 		fileType: "any"
 	});
     $(".btn-warning").on('click', function() {
-        $("#file-4").attr('disabled', 'disabled');
-        $('#file-4').fileinput('refresh', {browseLabel: 'Kartik'});
+        if ($('#file-4').attr('disabled')) {
+            $('#file-4').fileinput('enable');
+        } else {
+            $('#file-4').fileinput('disable');
+        }
     });
 	</script>
 </html>

+ 112 - 25
js/fileinput.js

@@ -1,6 +1,6 @@
 /*!
  * @copyright Copyright &copy; Kartik Visweswaran, Krajee.com, 2014
- * @version 1.9.0
+ * @version 2.0.0
  *
  * File input styled for Bootstrap 3.0 that utilizes HTML5 File Input's advanced 
  * features including the FileReader API. This plugin is inspired by the blog article at
@@ -53,6 +53,23 @@
         '  </div>\n' +
         '</div>\n';
 
+    var IMAGE_TEMPLATE = '<div class="file-preview-frame" id="{previewId}">\n' +
+        '   {content}\n' +
+        '</div>\n';
+
+    var TEXT_TEMPLATE = '<div class="file-preview-frame" id="{previewId}">\n' +
+        '   <div class="file-preview-text" title="{caption}">\n' +
+        '       {strText}\n' +
+        '   </div>\n' +
+        '</div>\n';
+
+    var OTHER_TEMPLATE = '<div class="file-preview-frame" id="{previewId}">\n' +
+        '   <div class="file-preview-other">\n' +
+        '       <h2><i class="glyphicon glyphicon-file"></i></h2>\n' +
+        '           {caption}\n' +
+        '   </div>\n' +
+        '</div>';
+
     var isEmpty = function (value, trim) {
         return value === null || value === undefined || value == []
             || value === '' || trim && $.trim(value) === '';
@@ -87,6 +104,10 @@
             var self = this;
             self.showCaption = options.showCaption;
             self.showPreview = options.showPreview;
+            self.maxFileSize = options.maxFileSize;
+            self.msgSizeTooLarge = options.msgSizeTooLarge;
+            self.msgErrorClass = options.msgErrorClass;
+            self.initialDelimiter = options.initialDelimiter;
             self.initialPreview = options.initialPreview;
             self.initialCaption = options.initialCaption;
             self.overwriteInitial = options.overwriteInitial;
@@ -102,6 +123,10 @@
                 self.mainTemplate = options.mainTemplate;
             }
             self.previewTemplate = (self.showPreview) ? options.previewTemplate : '';
+            self.previewGenericTemplate = options.previewGenericTemplate;
+            self.previewImageTemplate = options.previewImageTemplate;
+            self.previewTextTemplate = options.previewTextTemplate;
+            self.previewOtherTemplate = options.previewOtherTemplate;
             self.captionTemplate = options.captionTemplate;
             self.browseLabel = options.browseLabel;
             self.browseIcon = options.browseIcon;
@@ -147,7 +172,7 @@
             var self = this;
             self.$element.on('change', $.proxy(self.change, self));
             $(self.$element[0].form).on('reset', $.proxy(self.reset, self));
-            self.$container.find('.fileinput-remove').on('click', $.proxy(self.clear, 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;
@@ -156,19 +181,27 @@
         initPreview: function () {
             var self = this, html = '',
                 content = self.initialPreview,
-                len = self.initialPreview.length,
-                cap = self.initialCaption.length,
-                caption = (cap > 0) ? self.initialCaption : len + ' file selected';
+                len = isArray(content) ? content.length : (content.length > 0 ? content.split(self.initialDelimiter).length : 0),
+                cap = self.initialCaption.length, previewId = "preview-" + uniqId(),
+                caption = (cap > 0) ? self.initialCaption : self.msgSelected.replace("{n}", len);
             if (isArray(content) && len > 0) {
                 for (var i = 0; i < len; i++) {
-                    html += '<div class="file-preview-frame">' + content[i] + "</div>\n";
+                    previewId += '-' + i;
+                    html += self.previewGenericTemplate.replace("{previewId}", previewId).replace("{content}", content[i]);
                 }
                 if (len > 1 && cap == 0) {
-                    caption = len + ' files selected';
+                    caption = self.msgSelected.replace("{n}", len);
                 }
             }
             else if (len > 0) {
-                html = '<div class="file-preview-frame">' + content + '</div>';
+                var fileList = content.split(self.initialDelimiter);
+                for (var i = 0; i < len; i++) {
+                    previewId += '-' + i;
+                    html += self.previewGenericTemplate.replace("{previewId}", previewId).replace("{content}", fileList[i]);
+                }
+                if (len > 1 && cap == 0) {
+                    caption = self.msgSelected.replace("{n}", len);
+                }
             }
             else if (cap > 0) {
                 self.$caption.html(caption);
@@ -179,6 +212,7 @@
             else {
                 return;
             }
+            self.initialNbPreview = len;
             self.initialPreviewContent = html;
             self.$preview.html(html);
             self.$caption.html(caption);
@@ -191,6 +225,7 @@
                 e.preventDefault();
             }
             self.$element.val('');
+            self.$previewContainer.find('.kv-fileinput-error').fadeOut('slow');
             if (e !== false) {
                 self.$element.trigger('change');
                 self.$element.trigger('fileclear');
@@ -202,7 +237,7 @@
             }
             else {
                 self.$preview.html('');
-                var cap = (!self.overwriteInitial && self.initialCaption.length > 0) ? 
+                var cap = (!self.overwriteInitial && self.initialCaption.length > 0) ?
                     self.original.caption : '';
                 self.$caption.html(cap);
                 self.$captionContainer.attr('title', '');
@@ -211,6 +246,7 @@
             if (self.overwriteInitial) {
                 self.$captionContainer.find('.kv-caption-icon').hide();
             }
+            self.$element.trigger('filecleared');
         },
         reset: function (e) {
             var self = this;
@@ -223,14 +259,28 @@
                 self.$container.removeClass('file-input-new');
             }
         },
+        disable: function (e) {
+            var self = this;
+            self.isDisabled = true;
+            self.$element.attr('disabled', 'disabled');
+            self.$container.find(".kv-fileinput-caption").addClass("file-caption-disabled");
+            self.$container.find(".btn-file, .fileinput-remove, .kv-fileinput-upload").attr("disabled", true);
+        },
+        enable: function (e) {
+            var self = this;
+            self.isDisabled = false;
+            self.$element.removeAttr('disabled');
+            self.$container.find(".kv-fileinput-caption").removeClass("file-caption-disabled");
+            self.$container.find(".btn-file, .fileinput-remove, .kv-fileinput-upload").removeAttr("disabled");
+        },
         change: function (e) {
             var self = this;
-            var elem = self.$element, files = elem.get(0).files, numFiles = files ? files.length : 1,
-                label = elem.val().replace(/\\/g, '/').replace(/.*\//, ''), $preview = self.$preview,
+            var $el = self.$element, files = $el.get(0).files, numFiles = files ? (files.length + self.initialNbPreview) : 1,
+                label = $el.val().replace(/\\/g, '/').replace(/.*\//, ''), $preview = self.$preview,
                 $container = self.$previewContainer, $status = self.$previewStatus, msgLoading = self.msgLoading,
                 msgProgress = self.msgProgress, msgSelected = self.msgSelected, tfiles,
                 fileType = self.previewFileType, wrapLen = parseInt(self.wrapTextLength),
-                wrapInd = self.wrapIndicator;
+                wrapInd = self.wrapIndicator, previewId = "preview-" + uniqId(), isError = false;
 
             if (e.target.files === undefined) {
                 tfiles = e.target && e.target.value ? [
@@ -250,9 +300,24 @@
             var total = tfiles.length;
             for (var i = 0; i < total; i++) {
                 (function (file) {
-                    var caption = file.name;
-                    var isImg = isImageFile(file.type, file.name);
-                    var isTxt = isTextFile(file.type, file.name);
+                    previewId += "-" + i;
+                    var caption = file.name, isImg = isImageFile(file.type, file.name), isTxt = isTextFile(file.type, file.name),
+                        fileSize = (file.size ? file.size : 0) / 1000;
+                    fileSize = fileSize.toFixed(2);
+                    self.$previewContainer.find('.kv-fileinput-error').remove();
+                    if (self.maxFileSize > 0 && fileSize > self.maxFileSize) {
+                        var msg = self.msgSizeTooLarge.replace('{name}', caption).replace('{size}', fileSize).replace('{maxSize}', self.maxFileSize),
+                            errorMsg = '<div class="kv-fileinput-error ' + self.msgErrorClass + '">' + msg + '</div>';
+                        self.$element.val('');
+                        self.$previewContainer.append(errorMsg);
+                        var $error = self.$previewContainer.find('.kv-fileinput-error');
+                        $error.hide();
+                        $error.fadeIn(800);
+                        self.$element.trigger('fileerror', [file, previewId]);
+                        isError = true;
+                        return;
+                    }
+
                     if ($preview.length > 0 && (fileType == "any" ? (isImg || isTxt) : (fileType == "text" ? isTxt : isImg)) && typeof FileReader !== "undefined") {
                         var reader = new FileReader();
                         $status.html(msgLoading);
@@ -267,16 +332,26 @@
                                     wrapInd = wrapInd.replace("{title}", caption).replace("{dialog}", "$('#" + id + "').modal('show')");
                                     strText = strText.substring(0, (wrapLen - 1)) + wrapInd;
                                 }
-                                content = '<div class="file-preview-frame"><div class="file-preview-text" title="' + caption + '">' + strText + '</div></div>' + modal;
+                                content = self.previewTextTemplate.replace("{previewId}", previewId).replace("{caption}", caption).replace("{strText}", strText) + modal;
                             }
                             else {
-                                content = '<div class="file-preview-frame"><img src="' + theFile.target.result + '" class="file-preview-image" title="' + caption + '" alt="' + caption + '"></div>';
+                                content = self.previewImageTemplate.replace("{previewId}", previewId).replace("{content}", '<img src="' + theFile.target.result + '" class="file-preview-image" title="' + caption + '" alt="' + caption + '">');
                             }
                             $preview.append("\n" + content);
+
+                            // we check here if the picture is not too wide. If it's the case, we
+                            // scale the picture on the width and not on the height.
+                            var $image = $preview.find("#" + previewId + " img");
+                            if ($image.width() > $preview.width()) {
+                                $image.width("100%");
+                                $image.height("auto");
+                            }
+
                             if (i >= total - 1) {
                                 $container.removeClass('loading');
                                 $status.html('');
                             }
+                            $el.trigger('fileloaded', [file, previewId]);
                         };
                         reader.onprogress = function (data) {
                             if (data.lengthComputable) {
@@ -293,16 +368,19 @@
                         }
                     }
                     else {
-                        $preview.append("\n" + '<div class="file-preview-frame"><div class="file-preview-other"><h2><i class="glyphicon glyphicon-file"></i></h2>' + caption + '</div></div>');
+                        $preview.append("\n" + self.previewOtherTemplate.replace("{previewId}", previewId).replace("{caption}", caption));
+                        $el.trigger('fileloaded', [file, previewId]);
                     }
                 })(tfiles[i]);
             }
-
             var log = numFiles > 1 ? msgSelected.replace('{n}', numFiles) : label;
+            if (isError) {
+                log = numFiles > 1 ? msgSelected.replace('{n}', numFiles - 1) : '&nbsp;';
+            }
             self.$caption.html(log);
             self.$captionContainer.attr('title', log);
             self.$container.removeClass('file-input-new');
-            elem.trigger('fileselect', [numFiles, label]);
+            $el.trigger('fileselect', [numFiles, label]);
         },
         createContainer: function () {
             var self = this;
@@ -321,7 +399,7 @@
             var self = this;
             var preview = self.previewTemplate.replace('{class}', self.previewClass);
             var css = self.isDisabled ? self.captionClass + ' file-caption-disabled' : self.captionClass;
-            var caption = self.captionTemplate.replace('{class}', css);
+            var caption = self.captionTemplate.replace('{class}', css + ' kv-fileinput-caption');
             return self.mainTemplate.replace('{class}', self.mainClass).
                 replace('{preview}', preview).
                 replace('{caption}', caption).
@@ -347,7 +425,7 @@
             return '<button type="button" class="' + css + '"' + status + '>' + self.removeIcon + self.removeLabel + '</button>';
         },
         renderUpload: function () {
-            var self = this, content = '', status = '';
+            var self = this, css = self.uploadClass + ' kv-fileinput-upload', content = '', status = '';
             if (!self.showUpload) {
                 return '';
             }
@@ -355,13 +433,13 @@
                 status = ' disabled ';
             }
             if (isEmpty(self.uploadUrl)) {
-                content = '<button type="submit" class="' + self.uploadClass + '"' + status + '>' + self.uploadIcon + self.uploadLabel + '</button>';
+                content = '<button type="submit" class="' + css + '"' + status + '>' + self.uploadIcon + self.uploadLabel + '</button>';
             }
             else {
                 content = '<a href="' + self.uploadUrl + '" class="' + self.uploadClass + '"' + status + '>' + self.uploadIcon + self.uploadLabel + '</a>';
             }
             return content;
-        },
+        }
     }
 
     $.fn.fileinput = function (options) {
@@ -404,11 +482,17 @@
         previewClass: '',
         mainClass: '',
         mainTemplate: null,
+        initialDelimiter: '*$$*',
         initialPreview: '',
         initialCaption: '',
+        initialNbPreview: 0,
         initialPreviewContent: '',
         overwriteInitial: true,
         previewTemplate: PREVIEW_TEMPLATE,
+        previewGenericTemplate: IMAGE_TEMPLATE,
+        previewImageTemplate: IMAGE_TEMPLATE,
+        previewTextTemplate: TEXT_TEMPLATE,
+        previewOtherTemplate: OTHER_TEMPLATE,
         captionTemplate: CAPTION_TEMPLATE,
         browseLabel: 'Browse &hellip;',
         browseIcon: '<i class="glyphicon glyphicon-folder-open"></i> &nbsp;',
@@ -420,6 +504,9 @@
         uploadIcon: '<i class="glyphicon glyphicon-upload"></i> ',
         uploadClass: 'btn btn-default',
         uploadUrl: null,
+        maxFileSize: 0,
+        msgSizeTooLarge: 'File "{name}" (<b>{size} KB</b>) exceeds maximum allowed upload size of <b>{maxSize} KB</b>. Please retry your upload!',
+        msgErrorClass: 'file-error-message',
         msgLoading: 'Loading &hellip;',
         msgProgress: 'Loaded {percent}% of {file}',
         msgSelected: '{n} files selected',
@@ -432,7 +519,7 @@
         elPreviewImage: null,
         elPreviewStatus: null
     };
-    
+
     /**
      * Convert automatically file inputs with class 'file'
      * into a bootstrap fileinput control.

Різницю між файлами не показано, бо вона завелика
+ 1 - 1
js/fileinput.min.js


Деякі файли не було показано, через те що забагато файлів було змінено