瀏覽代碼

Update to release v4.2.6 - fix #377 & fix #378

Kartik Visweswaran 9 年之前
父節點
當前提交
69e8202606

+ 3 - 1
CHANGE.md

@@ -3,10 +3,12 @@ Change Log: `bootstrap-fileinput`
 
 ## version 4.2.6
 
-**Date**: 27-Jul-2015
+**Date**: 01-Aug-2015
 
 1. (enh #373): Default delete ajax request type to POST (instead of DELETE).
 2. (enh #376): Ability to validate initial/server files for max and min file count.
+3. (enh #377): Various enhancements to text preview.
+4. (enh #378): Ability to configure different icon thumbnails for preview files.
 
 ## version 4.2.5
 

+ 78 - 19
README.md

@@ -442,7 +442,7 @@ The `layoutTemplates` if not set will default to:
         '    <div class="modal-content">\n' +
         '      <div class="modal-header">\n' +
         '        <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>\n' +
-        '        <h3 class="modal-title">Detailed Preview <small>{title}</small></h3>\n' +
+        '        <h3 class="modal-title">{heading} <small>{title}</small></h3>\n' +
         '      </div>\n' +
         '      <div class="modal-body">\n' +
         '        <textarea class="form-control" style="font-family:Monaco,Consolas,monospace; height: {height}px;" readonly>{body}</textarea>\n' +
@@ -450,6 +450,9 @@ The `layoutTemplates` if not set will default to:
         '    </div>\n' +
         '  </div>\n' +
         '</div>',
+    zoom: '<button type="button" class="btn btn-default btn-sm btn-block" title="{zoomTitle}: {caption}" onclick="{dialog}">\n' +
+        '   {zoomInd}\n' +
+        '</button>\n',
     progress: '<div class="progress">\n' +
         '    <div class="{class}" role="progressbar" aria-valuenow="{percent}" aria-valuemin="0" aria-valuemax="100" style="width:{percent}%;">\n' +
         '        {percent}%\n' +
@@ -494,6 +497,10 @@ The following tags will be parsed and replaced in each of the templates:
 - `{type}`: will be replaced with the file type.
 - `{content}`: this is applicable only for the `generic` template. It will be replaced with the raw HTML markup as set in `initialPreview`. None of 
    the above tags will be parsed for the `generic` template.
+- `{dialog}`: currently applicable only for text file previews. Will be replaced with the JS code to launch the modal dialog.
+- `{zoomTitle}`: currently applicable only for text file previews. This will be replaced with the `msgZoomTitle` property. This is the title that is displayed on hover of the zoom button (which on clicking will display the text file).
+- `{zoomInd}`: currently applicable only for text file previews. This will be replaced with the `zoomIndicator` property. This is the title that is displayed on hover of the zoom button (which on clicking will display the text file).
+- `{heading}`: currently applicable only for text file previews. This represents the modal dialog heading title. This will be replaced with the `msgZoomModalHeading` property. 
 
 As noted, if you are coming from an earlier release (before v2.4.0), all preview templates have now been combined into one property, instead of separate templates for image, text etc. 
 
@@ -515,12 +522,13 @@ The `previewTemplates` if not set will default to:
         '   <img src="{data}" class="file-preview-image" title="{caption}" alt="{caption}" ' + STYLE_SETTING + '>\n' +
         '   {footer}\n' +
         '</div>\n',
-    text: '<div class="file-preview-frame" id="{previewId}" data-fileindex="{fileindex}">\n' +
-        '   <div class="file-preview-text" title="{caption}" ' + STYLE_SETTING + '>\n' +
-        '       {data}\n' + 
-        '   </div>\n' + 
+    text: '<div class="file-preview-frame{frameClass}" id="{previewId}" data-fileindex="{fileindex}">\n' +
+        '   <pre class="file-preview-text" title="{caption}" ' + STYLE_SETTING + '>{data}</pre>\n' +
+        '   <button type="button" class="btn btn-default btn-sm btn-block" title="{zoomText}: {caption}" onclick="{dialog}">\n' +
+        '       {zoomInd}\n' +
+        '   </button>\n' +
         '   {footer}\n' +
-        '</div>\n',
+        '</div>',
     video: '<div class="file-preview-frame" id="{previewId}" data-fileindex="{fileindex}" title="{caption}" ' + STYLE_SETTING + '>\n' +
         '   <video width="{width}" height="{height}" controls>\n' +
         '       <source src="{data}" type="{type}">\n' +
@@ -548,10 +556,13 @@ The `previewTemplates` if not set will default to:
         '   </object>\n' + 
         '   {footer}\n' +
         '</div>',
-    other: '<div class="file-preview-frame{frameClass}" id="{previewId}" data-fileindex="{fileindex}" title="{caption}" ' + STYLE_SETTING + '>\n' +
+    other: '<div class="file-preview-frame{frameClass}" id="{previewId}" data-fileindex="{fileindex}"' +
+        ' title="{caption}" ' + STYLE_SETTING + '>\n' +
+        '   <div class="file-preview-other-frame">\n'+
         '   ' + DEFAULT_PREVIEW + '\n' +
-        '   {footer}\n' +
-        '</div>',
+        '   </div>\n' +
+        '   <div class="file-preview-other-footer">{footer}</div>\n' +
+        '</div>'
 }
 ```
 
@@ -566,10 +577,15 @@ OBJECT_PARAMS = '      <param name="controller" value="true" />\n' +
     '      <param name="autoStart" value="false" />\n'+
     '      <param name="quality" value="high" />\n',
 DEFAULT_PREVIEW = '<div class="file-preview-other">\n' +
-    '       <i class="glyphicon glyphicon-file"></i>\n' +
-    '   </div>'
+    '   <span class="{previewFileIconClass}">{previewFileIcon}</span>\n' +
+    '</div>'
 ```
 
+where:
+
+- `{previewFileIcon}`: corresponds to the [previewFileIcon](#option-previewfileicon) property.
+- `{previewFileIconClass}`: corresponds to the [previewFileIconClass](#option-previewfileiconclass) property.
+
 ### allowedFileTypes
 
 _array_ the list of allowed file types for upload. This by default is set to null which means the plugin supports all file types for upload. If an 
@@ -708,7 +724,49 @@ This is by default setup as following:
 ```
 
 ### previewFileIcon
-_string_ the icon to be shown in each preview file thumbnail when an unreadable file type for preview is detected. Defaults to `<i class="glyphicon glyphicon-file"></i>`.
+_string_ the default icon to be shown in each preview file thumbnail when an unreadable file type for preview is detected. Defaults to `<i class="glyphicon glyphicon-file"></i>`.
+
+### previewFileIconClass
+_string_ the CSS class to be applied to the preview file icon container. Defaults to `file-icon-4x`.
+
+### previewFileIconSettings
+_object_ the preview icon markup settings for each file extension (type). You need to set this as `key: value` pairs, where the `key` corresponds to a file extension (e.g. `doc`, `docx`, `xls` etc.), and the `value` corresponds to the markup of the icon to be rendered. If this is not set OR a file extension is not set here, the preview will default to [previewFileIcon](#option-previewfileicon). Note that displaying the icons instead of file content is controlled via [allowedPreviewTypes](#option-allowedpreviewtypes) and [allowedPreviewMimeTypes](#option-allowedpreviewmimetypes).
+
+You can setup `previewFileIconSettings` as shown below:
+
+```js
+previewFileIconSettings: {
+    'doc': '<i class="fa fa-file-word-o text-primary"></i>',
+    'xls': '<i class="fa fa-file-excel-o text-success"></i>',
+    'ppt': '<i class="fa fa-file-powerpoint-o text-danger"></i>',
+    'jpg': '<i class="fa fa-file-photo-o text-warning"></i>',
+    'pdf': '<i class="fa fa-file-pdf-o text-danger"></i>',
+    'zip': '<i class="fa fa-file-archive-o text-muted"></i>',
+}
+```
+
+### previewFileExtSettings
+_object_ the extensions to be auto derived for each file extension (type). This is useful if you want to set the same icon for multiple file extension types. You need to set this as `key: value` pairs, where the `key` corresponds to a file extension as set in [previewFileIconSettings](#option-previewfileiconsettings) (e.g. `doc`, `docx`, `xls` etc.). The `value` will be a function callback that accepts the following parameter:
+
+- `ext`: _string_, the file extension (without the `.` [dot]) of the file currently selected in the preview 
+
+You can configure the callback to match the set of file extensions (via regex or similar) for each `key` and return a boolean output if the file extension matches. 
+
+For example, you can setup `previewFileExtSettings` as shown below:
+
+```js
+previewFileExtSettings: {
+    'doc': function(ext) {
+        return ext.match(/(doc|docx)$/i);
+    },
+    'xls': function(ext) {
+        return ext.match(/(xls|xlsx)$/i);
+    },
+    'ppt': function(ext) {
+        return ext.match(/(ppt|pptx)$/i);
+    }
+}
+```
 
 ### browseLabel
 _string_ the label to display for the file picker/browse button. Defaults to `Browse &hellip;`.
@@ -809,6 +867,12 @@ _int_ the maximum number of files allowed for each multiple upload. If set to `0
 ### validateInitialCount
 _boolean_ whether to include initial preview file count (server uploaded files) in validating `minFileCount` and `maxFileCount`. Defaults to `false`.
 
+### msgZoomTitle
+_string_ the title displayed (before the file name) on hover of the zoom button for zooming the file content in a modal window. This is currently applicable only for text file previews. Defaults to `View details`.
+
+### msgZoomModalHeading
+_string_ the heading of the modal dialog that displays the zoomed file content. This is currently applicable only for text file previews.  This is currently applicable only for text file previews. Defaults to `Detailed Preview`.
+
 ### msgSizeTooLarge
 _string_ the message to be displayed when the file size exceeds maximum size. Defaults to:
 
@@ -1021,13 +1085,8 @@ _string_ the type of files that are to be displayed in the preview window. Defau
 
 Files other than `image` or `text` will be displayed as a thumbnail with the filename in the preview window.
 
-### wrapTextLength
-_integer_ the number of characters after which the content will be stripped/wrapped for text preview. Defaults to `250`.
-
-### wrapIndicator
-_string_ the type of files that are to be displayed in the preview window. Defaults to ` <span class="wrap-indicator" title="{title}">[&hellip;]</span>`.  The following variables will be replaced:
-
-- `{title}`: the content of the entire text file that will be displayed as a span title element.
+### zoomIndicator
+_string_ the icon for zooming the file content in a new modal dialog.  This is currently applicable only for text file previews. Defaults to `<i class="glyphicon glyphicon-zoom-in"></i>`.  The following variables will be replaced:
 
 ### elErrorContainer
 _string_ the identifier for the container element displaying the error (e.g. `'#id'`). If not set, will default to the container with CSS class `kv-fileinput-error` inside the preview container (identified by `elPreviewContainer`). The `msgErrorClass` will be automatically appended to this container before displaying the error.

+ 41 - 21
css/fileinput.css

@@ -38,8 +38,6 @@
     min-height: 100%;
     text-align: right;
     opacity: 0;
-    filter: alpha(opacity=0);
-    opacity: 0;
     background: none repeat scroll 0 0 transparent;
     cursor: inherit;
     display: block;
@@ -68,6 +66,19 @@
     cursor: default;
 }
 
+.file-preview-other-footer .file-actions {
+    margin-top: 10px;
+}
+
+.file-preview-other-footer .file-caption-name {
+    display: block;
+    white-space: nowrap;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    width: 160px;
+    text-align: center;
+}
+
 .kv-has-ellipsis .file-caption-ellipsis {
     display: inline;
 }
@@ -79,7 +90,7 @@
 .kv-search-container .kv-search-clear {
     position: absolute;
     padding: 10px;
-    right: 0px;
+    right: 0;
 }
 
 .file-error-message {
@@ -118,7 +129,7 @@
     margin: 8px;
     height: 160px;
     border: 1px solid #ddd;
-    box-shadow: 1px 1px 5px 0px #a2958a;
+    box-shadow: 1px 1px 5px 0 #a2958a;
     padding: 6px;
     float: left;
     text-align: center;
@@ -126,7 +137,7 @@
 }
 
 .file-preview-frame:hover {
-    box-shadow: 3px 3px 5px 0px #333;
+    box-shadow: 3px 3px 5px 0 #333;
 }
 
 .file-preview-image {
@@ -135,27 +146,46 @@
 }
 
 .file-preview-text {
+    text-align: left;
     width: 160px;
+    margin-bottom: 2px;
     color: #428bca;
-    font-size: 11px;
-    text-align: center;
+    background: #fff;
+    overflow-x: hidden;
 }
 
 .file-preview-other {
-    padding-top: 48px;
+    display: table-cell;
     text-align: center;
+    vertical-align: middle;
+    width: 160px;
+    height: 140px;
+    border: 2px dashed #999;
+    border-radius: 25px;
+    opacity: 0.8;
 }
 
-.file-preview-other i {
-    font-size: 2.4em;
+.file-preview-other:hover {
+    opacity: 1;
 }
-
 .file-other-error {
     width: 100%;
     padding-top: 30px;
     text-align: right
 }
 
+.file-icon-lg {
+    font-size: 1.2em;
+}
+
+.file-icon-2x {
+    font-size: 2.4em;
+}
+
+.file-icon-4x {
+    font-size: 4.8em;
+}
+
 .file-input-new .file-preview, .file-input-new .close, .file-input-new .glyphicon-file,
 .file-input-new .fileinput-remove-button, .file-input-new .fileinput-upload-button,
 .file-input-ajax-new .fileinput-remove-button, .file-input-ajax-new .fileinput-upload-button {
@@ -166,12 +196,6 @@
     background: transparent url('../img/loading.gif') no-repeat scroll center center content-box !important;
 }
 
-.wrap-indicator {
-    font-weight: bold;
-    color: #245269;
-    cursor: pointer;
-}
-
 .file-actions {
     text-align: left;
 }
@@ -223,8 +247,4 @@
     background-position: center bottom 10px;
     background-repeat: no-repeat;
     opacity: 0.6;
-}
-
-.file-icon-large {
-    font-size: 1.2em;
 }

文件差異過大導致無法顯示
+ 0 - 0
css/fileinput.min.css


+ 2 - 2
examples/index.html

@@ -7,7 +7,7 @@
         <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet">
         <link href="../css/fileinput.css" media="all" rel="stylesheet" type="text/css" />
         <script src="http://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
-        <script src="../js/fileinput.min.js" type="text/javascript"></script>
+        <script src="../js/fileinput.js" type="text/javascript"></script>
         <script src="../js/fileinput_locale_fr.js" type="text/javascript"></script>
         <script src="../js/fileinput_locale_es.js" type="text/javascript"></script>
         <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js" type="text/javascript"></script>
@@ -69,7 +69,7 @@
                 </div>
                 <hr>
                 <div class="form-group">
-                    <input id="file-5" class="file" type="file" multiple data-preview-file-type="any" data-upload-url="#" data-preview-file-icon="">
+                    <input id="file-5" class="file" type="file" multiple data-preview-file-type="any" data-upload-url="#">
                 </div>
             </form>
             

+ 75 - 58
js/fileinput.js

@@ -15,6 +15,7 @@
  * For more JQuery plugins visit http://plugins.krajee.com
  * For more Yii related demos visit http://demos.krajee.com
  */
+
 (function ($) {
     "use strict";
 
@@ -71,8 +72,7 @@
             },
             get: function (id, i, isDisabled) {
                 var ind = 'init_' + i, data = previewCache.data[id], config = data.config[i],
-                    previewId = data.initId + '-' + ind, out, $tmp, frameAttr = {},
-                    frameClass = ' file-preview-initial';
+                    previewId = data.initId + '-' + ind, out, $tmp, frameClass = ' file-preview-initial';
                 isDisabled = isDisabled === undefined ? true : isDisabled;
                 if (data.content[i] === null) {
                     return '';
@@ -213,8 +213,8 @@
             '      <param name="autoStart" value="false" />\n' +
             '      <param name="quality" value="high" />\n',
         DEFAULT_PREVIEW = '<div class="file-preview-other">\n' +
-            '       {previewFileIcon}\n' +
-            '   </div>',
+            '   <span class="{previewFileIconClass}">{previewFileIcon}</span>\n' +
+            '</div>',
         defaultFileActionSettings = {
             removeIcon: '<i class="glyphicon glyphicon-trash text-danger"></i>',
             removeClass: 'btn btn-xs btn-default',
@@ -223,7 +223,7 @@
             uploadClass: 'btn btn-xs btn-default',
             uploadTitle: 'Upload file',
             indicatorNew: '<i class="glyphicon glyphicon-hand-down text-warning"></i>',
-            indicatorSuccess: '<i class="glyphicon glyphicon-ok-sign file-icon-large text-success"></i>',
+            indicatorSuccess: '<i class="glyphicon glyphicon-ok-sign file-icon-lg text-success"></i>',
             indicatorError: '<i class="glyphicon glyphicon-exclamation-sign text-danger"></i>',
             indicatorLoading: '<i class="glyphicon glyphicon-hand-up text-muted"></i>',
             indicatorNewTitle: 'Not uploaded yet',
@@ -263,7 +263,7 @@
             '    <div class="modal-content">\n' +
             '      <div class="modal-header">\n' +
             '        <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>\n' +
-            '        <h3 class="modal-title">Detailed Preview <small>{title}</small></h3>\n' +
+            '        <h3 class="modal-title">{heading} <small>{title}</small></h3>\n' +
             '      </div>\n' +
             '      <div class="modal-body">\n' +
             '        <textarea class="form-control" style="font-family:Monaco,Consolas,monospace; height: {height}px;" readonly>{body}</textarea>\n' +
@@ -292,6 +292,9 @@
             'title="{removeTitle}"{dataUrl}{dataKey}>{removeIcon}</button>\n',
         tActionUpload = '<button type="button" class="kv-file-upload {uploadClass}" title="{uploadTitle}">' +
             '   {uploadIcon}\n</button>\n',
+        tZoom =  '<button type="button" class="btn btn-default btn-sm btn-block" title="{zoomTitle}: {caption}" onclick="{dialog}">\n' +
+            '   {zoomInd}\n' +
+            '</button>\n',
         tGeneric = '<div class="file-preview-frame{frameClass}" id="{previewId}" data-fileindex="{fileindex}">\n' +
             '   {content}\n' +
             '   {footer}\n' +
@@ -307,9 +310,8 @@
             '   {footer}\n' +
             '</div>\n',
         tText = '<div class="file-preview-frame{frameClass}" id="{previewId}" data-fileindex="{fileindex}">\n' +
-            '   <div class="file-preview-text" title="{caption}" ' + STYLE_SETTING + '>\n' +
-            '       {data}\n' +
-            '   </div>\n' +
+            '   <pre class="file-preview-text" title="{caption}" ' + STYLE_SETTING + '>{data}</pre>\n' +
+            '   {zoom}\n' +
             '   {footer}\n' +
             '</div>',
         tVideo = '<div class="file-preview-frame{frameClass}" id="{previewId}" data-fileindex="{fileindex}"' +
@@ -345,13 +347,16 @@
             '</div>',
         tOther = '<div class="file-preview-frame{frameClass}" id="{previewId}" data-fileindex="{fileindex}"' +
             ' title="{caption}" ' + STYLE_SETTING + '>\n' +
+            '   <div class="file-preview-other-frame">\n'+
             '   ' + DEFAULT_PREVIEW + '\n' +
-            '   {footer}\n' +
+            '   </div>\n' +
+            '   <div class="file-preview-other-footer">{footer}</div>\n' +
             '</div>',
         defaultLayoutTemplates = {
             main1: tMain1,
             main2: tMain2,
             preview: tPreview,
+            zoom: tZoom,
             icon: tIcon,
             caption: tCaption,
             modal: tModal,
@@ -391,10 +396,10 @@
                 return (vType !== undefined) ? vType === 'text/html' : vName.match(/\.(htm|html)$/i);
             },
             text: function (vType, vName) {
-                return (vType !== undefined && vType.match('text.*')) || vName.match(/\.(txt|md|csv|nfo|php|ini)$/i);
+                return (vType !== undefined && vType.match('text.*')) || vName.match(/\.(txt|md|csv|nfo|ini|json|php|js|css)$/i);
             },
             video: function (vType, vName) {
-                return (vType !== undefined && vType.match(/\.video\/(ogg|mp4|webm)$/i)) || vName.match(/\.(og?|mp4|webm)$/i);
+                return (vType !== undefined && vType.match(/\.video\/(ogg|mp4|webm|3gp)$/i)) || vName.match(/\.(og?|mp4|webm|3gp)$/i);
             },
             audio: function (vType, vName) {
                 return (vType !== undefined && vType.match(/\.audio\/(ogg|mp3|wav)$/i)) || vName.match(/\.(ogg|mp3|wav)$/i);
@@ -481,9 +486,6 @@
             });
             self.fileInputCleared = false;
             self.fileBatchCompleted = true;
-            if (isEmpty(self.allowedPreviewTypes)) {
-                self.allowedPreviewTypes = defaultPreviewTypes;
-            }
             if (!self.isPreviewable) {
                 self.showPreview = false;
             }
@@ -596,12 +598,31 @@
         getPreviewTemplate: function (t) {
             var self = this,
                 template = isSet(t, self.previewTemplates) ? self.previewTemplates[t] : defaultPreviewTemplates[t];
-            template = template.repl('{previewFileIcon}', self.previewFileIcon);
             if (isEmpty(self.customPreviewTags)) {
                 return template;
             }
             return replaceTags(template, self.customPreviewTags);
         },
+        parseFilePreviewIcon: function (content, fname) {
+            var self = this, ext, icn = self.previewFileIcon;
+            if (fname && fname.indexOf('.') > -1) {
+                ext = fname.split('.').pop();
+                if (self.previewFileIconSettings && self.previewFileIconSettings[ext]) {
+                    icn = self.previewFileIconSettings[ext];
+                }
+                if (self.previewFileExtSettings) {
+                    $.each(self.previewFileExtSettings, function(key, func) {
+                        if (self.previewFileIconSettings[key] && func(ext)) {
+                            icn = self.previewFileIconSettings[key];
+                        }
+                    });
+                }
+            }
+            if (content.indexOf('{previewFileIcon}') > -1) {
+                return content.repl('{previewFileIconClass}', self.previewFileIconClass).repl('{previewFileIcon}', icn);
+            }
+            return content;
+        },
         getOutData: function (jqXHR, responseData, filesData) {
             var self = this;
             jqXHR = jqXHR || {};
@@ -669,7 +690,7 @@
             });
         },
         submitForm: function () {
-            var self = this, $el = self.$element, files = $el.get(0).files, fileCount;
+            var self = this, $el = self.$element, files = $el.get(0).files;
             if (files && self.minFileCount > 0 && self.getFileCount(files.length) < self.minFileCount) {
                 self.noFilesError({});
                 return false;
@@ -993,7 +1014,7 @@
                 };
 
             self.$preview.find('.kv-file-remove').each(function () {
-                var $el = $(this), vUrl = $el.data('url') || self.deleteUrl, vKey = $el.data('key'), len;
+                var $el = $(this), vUrl = $el.data('url') || self.deleteUrl, vKey = $el.data('key');
                 if (isEmpty(vUrl) || vKey === undefined) {
                     return;
                 }
@@ -1457,10 +1478,9 @@
             self.ajaxSubmit(fnBefore, fnSuccess, fnComplete, fnError, previewId, i);
         },
         uploadBatch: function () {
-            var self = this, files = self.filestack, total = files.length, config,
+            var self = this, files = self.filestack, total = files.length, params = {},
                 hasPostData = self.filestack.length > 0 || !$.isEmptyObject(self.uploadExtraData),
-                setAllUploaded, enableActions, fnBefore, fnSuccess, fnComplete, fnError,
-                params = {};
+                setAllUploaded, fnBefore, fnSuccess, fnComplete, fnError;
             self.formdata = new FormData();
             if (total === 0 || !hasPostData || self.abort(params)) {
                 return;
@@ -1700,12 +1720,11 @@
             if (!this.showPreview) {
                 return;
             }
-            var self = this, data = objUrl.createObjectURL(file), $obj = $('#' + previewId),
+            var self = this, data = objUrl.createObjectURL(file), frameClass = '', fname = file ? file.name : '',
                 config = self.previewSettings.other || defaultPreviewSettings.other,
                 footer = self.renderFileFooter(file.name, config.width),
-                previewOtherTemplate = self.getPreviewTemplate('other'),
                 ind = previewId.slice(previewId.lastIndexOf('-') + 1),
-                frameClass = '';
+                previewOtherTemplate = self.parseFilePreviewIcon(self.getPreviewTemplate('other'), fname);
             if (isDisabled === true) {
                 frameClass = ' btn disabled';
                 footer += '<div class="file-other-error text-danger"><i class="glyphicon glyphicon-exclamation-sign"></i></div>';
@@ -1725,41 +1744,35 @@
             if (!this.showPreview) {
                 return;
             }
-            var self = this, cat = self.parseFileType(file), caption = self.slug(file.name), content, strText,
-                types = self.allowedPreviewTypes, mimes = self.allowedPreviewMimeTypes,
-                tmplt = self.getPreviewTemplate(cat),
+            var self = this, cat = self.parseFileType(file), fname = file ? file.name : '', caption = self.slug(fname),
+                content, strText, types = self.allowedPreviewTypes, mimes = self.allowedPreviewMimeTypes,
+                tmplt = self.getPreviewTemplate(cat), chkTypes = types && types.indexOf(cat) >= 0, id, height,
                 config = isSet(cat, self.previewSettings) ? self.previewSettings[cat] : defaultPreviewSettings[cat],
-                wrapLen = parseInt(self.wrapTextLength, 10), wrapInd = self.wrapIndicator,
-                chkTypes = types.indexOf(cat) >= 0, id, height,
-                chkMimes = isEmpty(mimes) || (!isEmpty(mimes) && mimes.indexOf(file.type) !== -1),
+                chkMimes = mimes && mimes.indexOf(file.type) !== -1, 
                 footer = self.renderFileFooter(caption, config.width), modal = '',
                 ind = previewId.slice(previewId.lastIndexOf('-') + 1);
-            if (chkTypes && chkMimes) {
+            if (chkTypes || chkMimes) {
+                tmplt = self.parseFilePreviewIcon(tmplt, fname.split('.').pop());
                 if (cat === 'text') {
                     strText = htmlEncode(theFile.target.result);
-                    if (strText.length > wrapLen) {
-                        id = 'text-' + uniqId();
-                        height = window.innerHeight * 0.75;
-                        modal = self.getLayoutTemplate('modal').repl('{id}', id)
-                            .repl('{title}', caption)
-                            .repl('{height}', height)
-                            .repl('{body}', strText);
-                        wrapInd = wrapInd
-                            .repl('{title}', caption)
-                            .repl('{dialog}', "$('#" + id + "').modal('show')");
-                        strText = strText.substring(0, (wrapLen - 1)) + wrapInd;
-                    }
-                    content = tmplt.repl('{previewId}', previewId).repl('{caption}', caption)
-                        .repl('{frameClass}', '')
-                        .repl('{type}', file.type).repl('{width}', config.width)
-                        .repl('{height}', config.height).repl('{data}', strText)
-                        .repl('{footer}', footer).repl('{fileindex}', ind) + modal;
+                    id = 'text-' + uniqId();
+                    height = window.innerHeight * 0.75;
+                    content = tmplt.repl('{zoom}',  self.getLayoutTemplate('zoom'));
+                    modal = self.getLayoutTemplate('modal').replace('{id}', id)
+                        .repl('{title}', caption).repl('{height}', height)
+                        .repl('{body}', strText).repl('{heading}', self.msgZoomModalHeading);
+                    content = content.repl('{previewId}', previewId).repl('{caption}', caption)
+                        .repl('{width}', config.width).repl('{height}', config.height)
+                        .repl('{frameClass}', '').repl('{zoomInd}', self.zoomIndicator)
+                        .repl('{footer}', footer).repl('{fileindex}', ind)
+                        .repl('{type}', file.type).repl('{zoomTitle}', self.msgZoomTitle)
+                        .repl('{dialog}', "$('#" + id + "').modal('show')")
+                        .repl('{data}', strText) + modal;
                 } else {
                     content = tmplt.repl('{previewId}', previewId).repl('{caption}', caption)
-                        .repl('{frameClass}', '')
-                        .repl('{type}', file.type).repl('{data}', data)
+                        .repl('{frameClass}', '').repl('{type}', file.type).repl('{fileindex}', ind)
                         .repl('{width}', config.width).repl('{height}', config.height)
-                        .repl('{footer}', footer).repl('{fileindex}', ind);
+                        .repl('{footer}', footer).repl('{data}', data);
                 }
                 self.$preview.append("\n" + content);
                 self.validateImage(i, previewId);
@@ -1771,7 +1784,7 @@
             return isEmpty(text) ? '' : text.split(/(\\|\/)/g).pop().replace(/[^\w\u00C0-\u017F\-.\\\/ ]+/g, '');
         },
         getFileStack: function (skipNull) {
-            var self = this, status;
+            var self = this;
             return self.filestack.filter(function (n) {
                 return (skipNull ? n !== undefined : n !== undefined && n !== null);
             });
@@ -1921,7 +1934,7 @@
                 self.initPreviewDeletes();
             }
         },
-        validateMinCount: function() {
+        validateMinCount: function () {
             var self = this, len = self.isUploadable ? self.getFileStack().length : self.$element.get(0).files.length;
             if (self.validateInitialCount && self.minFileCount > 0 && self.getFileCount(len - 1) < self.minFileCount) {
                 self.noFilesError({});
@@ -1929,7 +1942,7 @@
             }
             return true;
         },
-        getFileCount: function(fileCount) {
+        getFileCount: function (fileCount) {
             var self = this, addCount = 0;
             if (self.validateInitialCount && !self.overwriteInitial) {
                 addCount = previewCache.count(self.id);
@@ -1944,7 +1957,7 @@
                 return;
             }
             self.fileInputCleared = false;
-            var tfiles, msg, total, $preview = self.$preview, isDragDrop = arguments.length > 1,
+            var tfiles, msg, total, isDragDrop = arguments.length > 1,
                 files = isDragDrop ? e.originalEvent.dataTransfer.files : $el.get(0).files,
                 isSingleUpload = isEmpty($el.attr('multiple')), i = 0, f, n, folders = 0,
                 ctr = self.filestack.length, isAjaxUpload = self.isUploadable, len,
@@ -2007,7 +2020,7 @@
                     self.resetPreviewThumbs(isAjaxUpload);
                 }
             } else {
-                 if (!isAjaxUpload || flagSingle) {
+                if (!isAjaxUpload || flagSingle) {
                     self.resetPreviewThumbs(false);
                     if (flagSingle) {
                         self.filestack = [];
@@ -2235,6 +2248,9 @@
         previewSettings: defaultPreviewSettings,
         fileTypeSettings: defaultFileTypeSettings,
         previewFileIcon: '<i class="glyphicon glyphicon-file"></i>',
+        previewFileIconClass: 'file-icon-4x',
+        previewFileIconSettings: {},
+        previewFileExtSettings: {},
         browseIcon: '<i class="glyphicon glyphicon-folder-open"></i> &nbsp;',
         browseClass: 'btn btn-primary',
         removeIcon: '<i class="glyphicon glyphicon-trash"></i> ',
@@ -2260,8 +2276,7 @@
         progressClass: "progress-bar progress-bar-success progress-bar-striped active",
         progressCompleteClass: "progress-bar progress-bar-success",
         previewFileType: 'image',
-        wrapTextLength: 250,
-        wrapIndicator: ' <span class="wrap-indicator" title="{title}" onclick="{dialog}">[&hellip;]</span>',
+        zoomIndicator: '<i class="glyphicon glyphicon-zoom-in"></i>',
         elCaptionContainer: null,
         elCaptionText: null,
         elPreviewContainer: null,
@@ -2289,6 +2304,8 @@
         cancelTitle: 'Abort ongoing upload',
         uploadLabel: 'Upload',
         uploadTitle: 'Upload selected files',
+        msgZoomTitle: 'View details',
+        msgZoomModalHeading: 'Detailed Preview',
         msgSizeTooLarge: 'File "{name}" (<b>{size} KB</b>) exceeds maximum allowed upload size of <b>{maxSize} KB</b>.',
         msgFilesTooLess: 'You must select at least <b>{n}</b> {files} to upload.',
         msgFilesTooMany: 'Number of files selected for upload <b>({n})</b> exceeds maximum allowed limit of <b>{m}</b>.',

文件差異過大導致無法顯示
+ 0 - 0
js/fileinput.min.js


+ 2 - 0
js/fileinput_locale_LANG.js

@@ -21,6 +21,8 @@
         cancelTitle: 'Abort ongoing upload',
         uploadLabel: 'Upload',
         uploadTitle: 'Upload selected files',
+        msgZoomTitle: 'View details',
+        msgZoomModalHeading: 'Detailed Preview',
         msgSizeTooLarge: 'File "{name}" (<b>{size} KB</b>) exceeds maximum allowed upload size of <b>{maxSize} KB</b>.',
         msgFilesTooLess: 'You must select at least <b>{n}</b> {files} to upload.',
         msgFilesTooMany: 'Number of files selected for upload <b>({n})</b> exceeds maximum allowed limit of <b>{m}</b>.',

+ 2 - 0
js/fileinput_locale_bg.js

@@ -21,6 +21,8 @@
         cancelTitle: 'Откажи качването',
         uploadLabel: 'Качи',
         uploadTitle: 'Качи избраните файлове',
+        msgZoomTitle: 'Вижте детайли',
+        msgZoomModalHeading: 'Детайлен преглед',
         msgSizeTooLarge: 'Файла "{name}" (<b>{size} KB</b>) надвишава максималните разрешени <b>{maxSize} KB</b>.',
         msgFilesTooLess: 'Трябва да изберете поне <b>{n}</b> {files} файла.',
         msgFilesTooMany: 'Броя файлове избрани за качване <b>({n})</b> надвишава ограниченито от максимум <b>{m}</b>.',

+ 2 - 0
js/fileinput_locale_cz.js

@@ -21,6 +21,8 @@
         cancelTitle: 'Přerušit  nahrávání',
         uploadLabel: 'Nahrát',
         uploadTitle: 'Nahrát vybrané soubory',
+        msgZoomTitle: 'zobrazit podrobnosti',
+        msgZoomModalHeading: 'Detailní náhled',
         msgSizeTooLarge: 'Soubor "{name}" (<b>{size} KB</b>): překročení - maximální povolená velikost <b>{maxSize} KB</b>.',
         msgFilesTooLess: 'Musíte vybrat nejméně <b>{n}</b> {files} pro nahrání.',
         msgFilesTooMany: 'Počet vybraných souborů pro nahrání <b>({n})</b>: překročení - maximální povolený limit <b>{m}</b>.',

+ 2 - 0
js/fileinput_locale_de.js

@@ -19,6 +19,8 @@
         cancelTitle: 'Hochladen abbrechen',
         uploadLabel: 'Hochladen',
         uploadTitle: 'Hochladen der ausgewählten Dateien',
+        msgZoomTitle: 'Details anzeigen',
+        msgZoomModalHeading: 'ausführliche Vorschau',
         msgSizeTooLarge: 'Datei "{name}" (<b>{size} KB</b>) überschreitet maximal zulässige Upload-Größe von <b>{maxSize} KB</b>.',
         msgFilesTooLess: 'Sie müssen mindestens <b>{n}</b> {files} zum Hochladen auswählen.',
         msgFilesTooMany: 'Anzahl der Dateien für den Upload ausgewählt <b>({n})</b> überschreitet maximal zulässige Grenze von <b>{m}</b> Stück.',

+ 2 - 0
js/fileinput_locale_el.js

@@ -21,6 +21,8 @@
         cancelTitle: 'Ακύρωση μεταφόρτωσης',
         uploadLabel: 'Μεταφόρτωση',
         uploadTitle: 'Μεταφόρτωση επιλεγμένων αρχείων',
+        msgZoomTitle: 'Δείτε λεπτομέρειες',
+        msgZoomModalHeading: 'λεπτομερής Προεπισκόπηση',
         msgSizeTooLarge: 'Το αρχείο "{name}" (<b>{size} KB</b>) υπερβαίνει το μέγιστο επιτρεπόμενο μέγεθος μεταφόρτωσης <b>{maxSize} KB</b>.',
         msgFilesTooLess: 'Πρέπει να επιλέξετε τουλάχιστον <b>{n}</b> {files} για να ξεκινήσει η μεταφόρτωση.',
         msgFilesTooMany: 'Ο αριθμός των αρχείων που έχουν επιλεγεί για μεταφόρτωση <b>({n})</b> υπερβαίνει το μέγιστο επιτρεπόμενο αριθμό <b>{m}</b>.',

+ 2 - 0
js/fileinput_locale_es.js

@@ -21,6 +21,8 @@
         cancelTitle: 'Abortar la subida en curso',
         uploadLabel: 'Subir archivo',
         uploadTitle: 'Subir archivos seleccionados',
+        msgZoomTitle: 'Ver detalles',
+        msgZoomModalHeading: 'Vista previa detallada',
         msgSizeTooLarge: 'Archivo "{name}" (<b>{size} KB</b>) excede el tamaño máximo permitido de <b>{maxSize} KB</b>.',
         msgFilesTooLess: 'Debe seleccionar al menos <b>{n}</b> {files} a cargar.',
         msgFilesTooMany: 'El número de archivos seleccionados a cargar <b>({n})</b> excede el límite máximo permitido de <b>{m}</b>.',

+ 2 - 0
js/fileinput_locale_fa.js

@@ -22,6 +22,8 @@
         cancelTitle: 'لغو بارگزاری جاری',
         uploadLabel: 'بارگذاری',
         uploadTitle: 'بارگذاری فایل‌های انتخاب شده',
+        msgZoomTitle: 'دیدن جزئیات',
+        msgZoomModalHeading: 'پیشنمایش مفصل',
         msgSizeTooLarge: 'فایل "{name}" (<b>{size} کیلوبایت</b>) از حداکثر مجاز <b>{maxSize} کیلوبایت</b>.',
         msgFilesTooLess: 'شما باید حداقل <b>{n}</b> {files} فایل برای بارگذاری انتخاب کنید.',
         msgFilesTooMany: 'تعداد فایل‌های انتخاب شده برای بارگذاری <b>({n})</b> از حداکثر مجاز عبور کرده است <b>{m}</b>.',

+ 2 - 0
js/fileinput_locale_fr.js

@@ -21,6 +21,8 @@
         cancelTitle: "Annuler l'envoi en cours",
         uploadLabel: 'Transférer',
         uploadTitle: 'Transférer les fichiers sélectionnés',
+        msgZoomTitle: 'Voir les détails',
+        msgZoomModalHeading: 'Aperçu détaillé',
         msgSizeTooLarge: 'Le fichier "{name}" (<b>{size} KB</b>) dépasse la taille maximale autorisée qui est de <b>{maxSize} KB</b>.',
         msgFilesTooLess: 'Vous devez sélectionner au moins <b>{n}</b> {files} à transmetter.',
         msgFilesTooMany: 'Le nombre de fichier sélectionné <b>({n})</b> dépasse la quantité maximale autorisée qui est de <b>{m}</b>.',

+ 2 - 0
js/fileinput_locale_hu.js

@@ -21,6 +21,8 @@
         cancelTitle: 'Feltöltés megszakítása',
         uploadLabel: 'Feltöltés',
         uploadTitle: 'Kijelölt fájlok feltöltése',
+        msgZoomTitle: 'Részletek megtekintése',
+        msgZoomModalHeading: 'Részletes Preview',
         msgSizeTooLarge: '"{name}" fájl (<b>{size} KB</b>) mérete nagyobb a megengedettnél <b>{maxSize} KB</b>.',
         msgFilesTooLess: 'Legalább <b>{n}</b> {files} ki kell választania a feltöltéshez.',
         msgFilesTooMany: 'A feltölteni kívánt fájlok száma <b>({n})</b> elérte a megengedett maximumot <b>{m}</b>.',

+ 2 - 0
js/fileinput_locale_it.js

@@ -23,6 +23,8 @@
         cancelTitle: 'Annulla i caricamenti in corso',
         uploadLabel: 'Carica',
         uploadTitle: 'Carica i file selezionati',
+        msgZoomTitle: 'Guarda i dettagli',
+        msgZoomModalHeading: 'Anteprima dettagliata',
         msgSizeTooLarge: 'Il file "{name}" (<b>{size} KB</b>) eccede la dimensione massima di caricamento di <b>{maxSize} KB</b>.',
         msgFilesTooLess: 'Devi selezionare almeno <b>{n}</b> {files} da caricare.',
         msgFilesTooMany: 'Il numero di file selezionati per il caricamento <b>({n})</b> eccede il numero massimo di file accettati <b>{m}</b>.',

+ 2 - 0
js/fileinput_locale_nl.js

@@ -21,6 +21,8 @@
         cancelTitle: 'Annuleer gaande upload',
         uploadLabel: 'Upload',
         uploadTitle: 'Upload geselecteerde bestanden',
+        msgZoomTitle: 'Bekijk details',
+        msgZoomModalHeading: 'Gedetailleerde Voorbeeld',
         msgSizeTooLarge: 'Bestand "{name}" (<b>{size} KB</b>) is groter dan de toegestaande <b>{maxSize} KB</b>.',
         msgFilesTooLess: 'U moet minstens <b>{n}</b> {files} selecteren om te uploaden.',
         msgFilesTooMany: 'Aantal geselecteerde bestanden <b>({n})</b> is meer dan de toegestaande <b>{m}</b>.',

+ 2 - 0
js/fileinput_locale_pl.js

@@ -21,6 +21,8 @@
         cancelTitle: 'Anuluj wysyłanie',
         uploadLabel: 'Wgraj',
         uploadTitle: 'Wgraj zaznaczone pliki',
+        msgZoomTitle: 'Pokaż szczegóły',
+        msgZoomModalHeading: 'Szczegółowe Podgląd',
         msgSizeTooLarge: 'Plik o nazwie "{name}" (<b>{size} KB</b>) przekroczył maksymalną dopuszczalną wielkość pliku wynoszącą <b>{maxSize} KB</b>.',
         msgFilesTooLess: 'Musisz wybrać przynajmniej <b>{n}</b> {files} do wgrania.',
         msgFilesTooMany: 'Liczba plików wybranych do wgrania w liczbie <b>({n})</b>, przekracza maksymalny dozwolony limit wynoszący <b>{m}</b>.',

+ 2 - 0
js/fileinput_locale_pt-BR.js

@@ -21,6 +21,8 @@
         cancelTitle: 'Interromper envio em andamento',
         uploadLabel: 'Enviar',
         uploadTitle: 'Enviar arquivos selecionados',
+        msgZoomTitle: 'Ver detalhes',
+        msgZoomModalHeading: 'Pré-visualização detalhada',
         msgSizeTooLarge: 'O arquivo "{name}" (<b>{size} KB</b>) excede o tamanho máximo permitido de <b>{maxSize} KB</b>.',
         msgFilesTooLess: 'Você deve selecionar pelo menos <b>{n}</b> {files} para enviar.',
         msgFilesTooMany: 'O número de arquivos selecionados para o envio <b>({n})</b> excede o limite máximo permitido de <b>{m}</b>.',

+ 2 - 0
js/fileinput_locale_pt.js

@@ -21,6 +21,8 @@
         cancelTitle: 'Abortar carregamento ',
         uploadLabel: 'Carregar',
         uploadTitle: 'Carregar ficheiros seleccionados',
+        msgZoomTitle: 'Ver detalhes',
+        msgZoomModalHeading: 'Pré-visualização detalhada',
         msgSizeTooLarge: 'Ficheiro "{name}" (<b>{size} KB</b>) excede o tamanho máximo permido de <b>{maxSize} KB</b>.',
         msgFilesTooLess: 'Deve seleccionar pelo menos <b>{n}</b> {files} para fazer upload.',
         msgFilesTooMany: 'Número máximo de ficheiros seleccionados <b>({n})</b> excede o limite máximo de <b>{m}</b>.',

+ 2 - 0
js/fileinput_locale_ro.js

@@ -22,6 +22,8 @@
         cancelTitle: 'Anulează încărcarea curentă',
         uploadLabel: 'Încarcă',
         uploadTitle: 'Încarcă fișierele selectate',
+        msgZoomTitle: 'Vezi detalii',
+        msgZoomModalHeading: 'Previzualizare detaliată',
         msgSizeTooLarge: 'Fișierul "{name}" (<b>{size} KB</b>) depășește limita maximă de încărcare de <b>{maxSize} KB</b>.',
         msgFilesTooLess: 'Trebuie să selectezi cel puțin <b>{n}</b> {files} pentru a încărca.',
         msgFilesTooMany: 'Numărul fișierelor pentru încărcare <b>({n})</b> depășește limita maximă de <b>{m}</b>.',

+ 2 - 0
js/fileinput_locale_ru.js

@@ -22,6 +22,8 @@
         cancelTitle: 'Отменить текущую загрузку',
         uploadLabel: 'Загрузить',
         uploadTitle: 'Загрузить выбранные файлы',
+        msgZoomTitle: 'посмотреть детали',
+        msgZoomModalHeading: 'Подробное превью',
         msgSizeTooLarge: 'Файл "{name}" (<b>{size} KB</b>) превышает максимальный размер <b>{maxSize} KB</b>.',
         msgFilesTooLess: 'Вы должны выбрать как минимум <b>{n}</b> {files} для загрузки.',
         msgFilesTooMany: 'Количество выбранных файлов <b>({n})</b> превышает максимально допустимое количество <b>{m}</b>.',

+ 2 - 0
js/fileinput_locale_sk.js

@@ -21,6 +21,8 @@
         cancelTitle: 'Prerušiť  nahrávanie',
         uploadLabel: 'Nahrať',
         uploadTitle: 'Nahrať vybraté súbory',
+        msgZoomTitle: 'Zobraziť podrobnosti',
+        msgZoomModalHeading: 'Detailný náhľad',
         msgSizeTooLarge: 'Súbor "{name}" (<b>{size} KB</b>): prekročenie - maximálna povolená veľkosť <b>{maxSize} KB</b>.',
         msgFilesTooLess: 'Musíte vybrať najmenej <b>{n}</b> {files} pre nahranie.',
         msgFilesTooMany: 'Počet vybratých súborov pre nahranie <b>({n})</b>: prekročenie - maximálny povolený limit <b>{m}</b>.',

+ 2 - 0
js/fileinput_locale_sr.js

@@ -22,6 +22,8 @@
         cancelTitle: 'Prekini trenutno otpremanje',
         uploadLabel: 'Otpremi',
         uploadTitle: 'Otpremi označene datoteke',
+        msgZoomTitle: 'Приказ детаља',
+        msgZoomModalHeading: 'Детаљан приказ',
         msgSizeTooLarge: 'Datoteka "{name}" (<b>{size} KB</b>) prekoračuje maksimalnu dozvoljenu veličinu datoteke od <b>{maxSize} KB</b>.',
         msgFilesTooLess: 'Morate odabrati najmanje <b>{n}</b> {files} za otpremanje.',
         msgFilesTooMany: 'Broj datoteka označenih za otpremanje <b>({n})</b> prekoračuje maksimalni dozvoljeni limit od <b>{m}</b>.',

+ 2 - 0
js/fileinput_locale_th.js

@@ -21,6 +21,8 @@
         cancelTitle: 'ยกเลิกการอัพโหลด',
         uploadLabel: 'อัพโหลด',
         uploadTitle: 'อัพโหลดไฟล์ที่เลือก',
+        msgZoomTitle: 'ดูรายละเอียด',
+        msgZoomModalHeading: 'ตัวอย่างละเอียด',
         msgSizeTooLarge: 'ไฟล์ "{name}" (<b>{size} KB</b>) มีขนาดเกินที่ระบบอนุญาตที่ <b>{maxSize} KB</b>, กรุณาลองใหม่อีกครั้ง!',
         msgFilesTooLess: 'คุณต้องเลือกไฟล์จำนวนอย่างน้อย <b>{n}</b> {files} เพื่ออัพโหลด, กรุณาลองใหม่อีกครั้ง!',
         msgFilesTooMany: 'ไฟล์ที่คุณเลือกมีจำนวน <b>({n})</b> ซึ่งเกินกว่าที่ระบบอนุญาตที่ <b>{m}</b>, กรุณาลองใหม่อีกครั้ง!',

+ 2 - 0
js/fileinput_locale_tr.js

@@ -21,6 +21,8 @@
         cancelTitle: 'Devam eden yüklemeyi iptal et',
         uploadLabel: 'Yükle',
         uploadTitle: 'Seçilen dosyaları yükle',
+        msgZoomTitle: 'Ayrıntıları görüntüle',
+        msgZoomModalHeading: 'Detaylı Önizleme',
         msgSizeTooLarge: '"{name}" dosyasının boyutu (<b>{size} KB</b>) izin verilen azami dosya boyutu olan <b>{maxSize} KB</b>\'tan büyük.',
         msgFilesTooLess: 'Yüklemek için en az <b>{n}</b> {files} dosya seçmelisiniz.',
         msgFilesTooMany: 'Yüklemek için seçtiğiniz dosya sayısı <b>({n})</b> azami limitin <b>{m}</b> altında olmalıdır.',

+ 2 - 0
js/fileinput_locale_uk.js

@@ -22,6 +22,8 @@
         cancelTitle: 'Скасувати поточну загрузку',
         uploadLabel: 'Загрузити',
         uploadTitle: 'Загрузити вибрані файли',
+        msgZoomTitle: 'Подивитися деталі',
+        msgZoomModalHeading: 'Детальний превью',
         msgSizeTooLarge: 'Файл "{name}" (<b>{size} KB</b>) перевищує максимальний розмір <b>{maxSize} KB</b>.',
         msgFilesTooLess: 'Ви повинні вибрати як мінімум <b>{n}</b> {files} для загрузки.',
         msgFilesTooMany: 'Кількість вибраних файлів <b>({n})</b> перевищує максимально допустиму кількість <b>{m}</b>.',

+ 2 - 0
js/fileinput_locale_zh.js

@@ -22,6 +22,8 @@
         cancelTitle: '取消进行中的上传',
         uploadLabel: '上传',
         uploadTitle: '上传选中文件',
+        msgZoomTitle: '查看详情',
+        msgZoomModalHeading: '详细预览',
         msgSizeTooLarge: '文件 "{name}" (<b>{size} KB</b>) 超过了允许大小 <b>{maxSize} KB</b>.',
         msgFilesTooLess: '你必须选择最少 <b>{n}</b> {files} 来上传. ',
         msgFilesTooMany: '选择的上传文件个数 <b>({n})</b> 超出最大文件的限制个数 <b>{m}</b>.',

部分文件因文件數量過多而無法顯示