ソースを参照

Update to release v4.2.6

Kartik Visweswaran 9 年 前
コミット
ac15ba52bd

+ 2 - 2
.gitignore

@@ -1,3 +1,3 @@
-nuget/content/
-nuget/bootstrap-fileinput.*.nupkg
+nuget/content/
+nuget/bootstrap-fileinput.*.nupkg
 .DS_Store
 .DS_Store

+ 564 - 558
CHANGE.md

@@ -1,558 +1,564 @@
-Change Log: `bootstrap-fileinput`
-=================================
-
-## version 4.2.5
-
-**Date**: 27-Jul-2015
-
-1. (enh #362): Add Bulgarian translations.
-2. (bug #370): Reverts #342 with better fix.
-3. (enh #371): Ability to replace files in the preview. New `autoReplace` property.
-4. (enh #372): Create new event `filepreajax`.
-
-## version 4.2.4
-
-**Date**: 22-Jul-2015
-
-1. (enh #340): Receive `previewId` and `index` in extra data for individual thumbnail uploads (ajax).
-2. (enh #342): Add ability to modify extra data before ajax upload in `beforeSend` events.
-3. (enh #351): Updates to Ukranian & Russian translations.
-4. (enh #356): Implement `destroy` method.
-5. (enh #357): Enhanced and better `refresh` method.
-6. (enh #358): Implement event namespaces and enhance event handling process.
-
-## version 4.2.3
-
-**Date**: 21-Jun-2015
-
-1. (enh #336): Fixes to reset preview via `initUploadSuccess`.
-
-## version 4.2.2
-
-**Date**: 18-Jun-2015
-
-1. (enh #332): Bump nuget and bower package versions.
-
-## version 4.2.1
-
-**Date**: 15-Jun-2015
-
-1. (enh #279, #280): Fixed error for failed response types.
-2. (enh #287): Add Brazilian Portugese (pt-BR) translations.
-3. (bug #295): Validate `overwriteInitial` correctly for ajax uploads.
-4. (enh #296): Fixed license identifiers in bower.json and composer.json.
-5. (enh #297): Add Romanian translations.
-6. (enh #299): Enhancements for displaying uploaded file thumbnails.
-    - New property `showUploadedThumbs` that will display uploaded thumbnails until the remove/clear button is explicitly pressed.
-    - New event `filesuccessremove`. This will be triggered on removing the uploaded thumbnail using the thumbnail delete button. The event shares the following parameters:
-        - `id`: the HTML id attribute of the thumbnail container 
-      The `event` can be set to return `false` to abort the thumbnail removal.
-7. (enh #302): Add Greek (el) translations.
-8. (enh #303): Validate only files to be dragged and dropped.
-9. (enh #305): Implement better cleanup of memory with `revokeObjectURL`.
-10. (enh #307): Allow setting thumbnail frame css class and attributes via `initialPreviewConfig`.
-11. (enh #308): Better check for `data.error` being empty.
-12. (enh #309): Fixes for older browsers.
-13. (bug #310): Set missing caption icon on error.
-14. (bug #315): Fix parsing of preview settings for default (other) preview.
-15. (bug #327): More correct clearing of preview.
-16. (bug #328): Implement image dimension validations.
-    - New properties added to the plugin:
-        - `minImageWidth`
-        - `minImageHeight`
-        - `maxImageWidth`
-        - `maxImageHeight`
-        - `msgImageWidthSmall`
-        - `msgImageHeightSmall`
-        - `msgImageWidthLarge`
-        - `msgImageHeightLarge`
-17. (enh #329): Message translation updates.
-18. (enh #330): Minor enhancements in validating preview and progress bar display.
-
-## version 4.2.0
-
-**Date**: 11-May-2015
-
-1. (enh #275): Add Czech & Slovakian translations.
-2. (enh #277): New `language` property to allow configuring multi lang widgets on same page.
-
-## version 4.1.9
-
-**Date**: 02-May-2015
-
-1. (enh #232): Update docs to reflect updated bootstrap CDN domain.
-2. (enh #237): Better styling of file caption icon.
-3. (bug #238): Correct initialization of plugin variables when other than maxFileCount & maxFileSize.
-4. (enh #241): Enhancements to initial preview delete to perform validations before delete.
-5. (bug #243): Correct sending of `deleteExtraData`.
-6. (enh #244): Add Serbian translations.
-7. (enh #245): Allow initial caption to be set without initial preview.
-8. (bug #247): Correct mime types validation.
-9. (enh #248): keep chinese characters in file caption.
-10. (bug #249): Fix error message content display.
-11. (enh #250): Change default slug routine to allow umlauts in filenames.
-12. (enh #251): Add Italian localizations.
-13. (enh #252): Enhance async batch completion.
-14. (bug #253): Fix initial preview delete cache initialization.
-15. (bug #257): Fix upload single to replace thumbs correctly.
-16. (enh #258): Enhance messages to include file plural and single.
-17. (enh #259): Add Polish translations.
-18. (enh #263): Enhance parsing of file preview thumbnails and actions.
-19. (enh #264): Validate input type of file before initializing plugin.
-20. (enh #269, #272): Add Turkish translations.
-21. (enh #270): Add Portugese translations.
-22. (enh #271): Add Dutch translations.
-23. (bug #273): Reset caption correctly after all initial preview is deleted.
-
-## version 4.1.8
-
-**Date**: 30-Mar-2015
-
-1. (bug #171): Fix typo for files validation.
-2. (enh #167, #173): New `deleteExtraData` property for ajax deletions.
-3. (enh #174): New `deleteUrl` property.
-4. (enh #175): Ability to override delete extra data in `initialPreviewConfig`.
-5. (enh #176): Wrong file in README installation steps fixed.
-6. (enh #177): Trigger filebatchpreupload if showPreview is `false`.
-7. (enh #178): Updated README for cancel button configuration.
-8. (enh #179): Validate and cast `maxFileSize` and `maxFileCount` to numeric - even if they have been setup as a string.
-9. (enh #181): Fix change event triggered for IE 11 when file input is set to empty.
-10. (enh #183): Delete extra data enhancements.
-11. (enh #184): Fix documentation for filedeleted event.
-12. (enh #187): New property `previewFileIcon` to configure file icon shown in preview for unreadable file types.
-13. (enh #188): Clear fileinput more correctly for all browsers when initialPreview is set enhancement
-14. (enh #189): Reinitialize initial preview delete events correctly on file selection.
-15. (enh #192): Ability to extend and add one's own ajax settings.
-    - New property `ajaxDeleteSettings` to help extend and add to delete ajax settings. 
-    - `ajaxSettings` to help extend and add upload ajax settings
-16. (bug #193): Better validation for triggering `filebatchuploadcomplete` on async batch upload completion.
-17. (enh #202): Ability to add Translations / Locales.
-    - Identify and group all messages that need to be translated configurable via `$.fn.fileinput.locales['<lang-code>']`
-    - Set default english messages configuration `$.fn.fileinput.locales['en']` within the plugin core code
-    - Individual locale files need to be created as separate js files e.g. `fileinput_locale_<lang>.js`
-18. (enh #203): Enhancements and revamp of all error events.
-    - fileerror
-    - fileuploaderror
-    - filebatchuploaderror
-    - filedeleteerror
-    - filefoldererror (new event - see #209)
-    - filecustomerror (new event - see #206)
-19. (enh #204): New properties `fileMinCount` and `msgFilesTooLess` (useful to make file input mandatory).
-    - The `fileMinCount` property will allow to set the minimum file count needed before triggering upload. It will work for both `ajax` uploads and `normal form based submission`.
-    - This will enable you to set the file input to be a mandatory / required input. (e.g. `fileMinCount` = `1`). The `msgFilesTooLess` will be displayed and error raised.
-    - If `fileMinCount` is set to `0` it will be treated as files are optional and no error will be triggered.
-20. (enh #205): Allow to auto set initialPreview within `filebatchuploadcomplete` & `filebatchuploadsuccess`.
-    - Allows you to auto define the `initialPreview` and  `initialPreviewConfig` after an ajax upload by returning these within the data object from your ajax response on `fileuploaded` & `filebatchuploadsuccess`. 
-21. (enh #206): Ability to add custom validation and trigger custom error to abort upload.
-    - This enhancement will enable you to add your additional custom validations to enhance the fileinput to be used for innumerous scenarios. It will allow an ability to return an associative object with any of the fileinput events (except the error events and the `filebatchuploadsuccess` or `filebatchuploadcomplete`) e.g. `change`, `fileselect`, `filepreupload`, `filebatchpreupload` etc. The object can return the following keys:
-        - `message`: _string_, the validation error message to be displayed before upload. If this is set the plugin will automatically abort the upload whenever called and display this as an error message. You can use this property for example to read a file and perform your own custom validation.
-        - `data`: _object_, an optional associative array of additional data that you can pass for usage later. 
-    - You can get this data by reading `abortData` in the parameters for the new `filecustomerror` event. This new event will be triggered during upload, when  you have triggered an abort from any of the other events. 
-22. (enh #209): Better validation for folder drag and drop and auto-skip any dropped folders. New property `msgFoldersNotAllowed` added to the plugin to allow configuring the message shown. The event `filefoldererror` is triggered when a folder is dragged.
-23. (enh #211): Add ability to show detailed server error stack via `showAjaxErrorDetails`.
-24. (enh #212): Revamp preview to use a new preview caching object.
-25. (enh #213): Code cleanup, eliminate change event on clear and properly reset preview cache after ajax deletes.
-26. (enh #215): Set default delete method REST compliant.
-27. (enh #216): Add Hungarian Translations.
-28. (enh #217): Ensure `filebatchselected` event is triggered after FileReader completes reading files selected.
-29. (enh #218): Do not clear preview for ajaxuploads until remove button clicked.
-30. (enh #222): Enhance to include dynamically replaceable thumbnail tags. Two new properties `previewThumbTags` and `initialPreviewThumbTags` will be available for configuration.
-31. (enh #225): Create Russian translations.
-32. (enh #226): Create Spanish (Latin American) translations.
-33. (enh #227): Created Ukranian translations and updated Russian translations.
-34. (enh #228): Created Thai translations.
-35. (enh #229): Created French translations.
-36. (enh #230): More correct initial preview delete reset.
-
-## version 4.1.7
-
-**Date**: 13-Feb-2015
-
-1. (enh #149): Custom tags support for layoutTemplates and previewTemplates (new properties `customLayoutTags` and `customPreviewTags` included).
-2. (enh #151): New `filebatchselected` event triggered after every batch of files are selected.
-3. (enh #152): New faster `replaceAll` method instead of regexp parsing to replace tags in templates.
-4. (enh #153): Improve error handler for trapping FileReader security exceptions and new property `msgFileSecured` will display the security exception message.
-5. (enh #154): Code cleanup and restructure for JS lint changes (using JSHint Code cleanup library).
-6. (enh #155): Allow display of long file names without spaces/word breaks.
-7. (enh #156): Fix reset of file stack for various upload modes (single, batch async and batch sync).
-8. (enh #157): Upload progress bar styling enhancements.
-    - Allow upload progress bar css class to be configurable 
-    - Create and allow two different styles/css classes for progress bar
-       - `progressClass`: styling for progress bar when upload is in process
-       - `progressCompleteClass`: styling for progress bar when upload is complete
-9. (bug #159): Ensure filestack is passed correctly with `outData` for events.
-10. (bug #160): Correct documentation typo for usage.
-11. (enh #162): New property ajaxSettings to allow configuring ajax params.
-12. Set copyright year to current.
-13. Relocate sample files from examples directory to [bootstrap-fileinput-samples](https://github.com/kartik-v/bootstrap-fileinput-samples) repo.
-
-## version 4.1.6
-
-**Date:** 20-Jan-2015
-
-1. (enh #124): Allow submission of extra data even if no files are selected.
-2. (enh #131): Allow empty values in extra data to be submitted.
-3. (enh #136):Create new upload method that can be called externally.
-4. (enh #137): Trigger new events - `filedisabled` and `fileenabled`.
-5. (enh #139): Reset file stack correctly on ajax upload completion.
-
-## version 4.1.5
-
-**Date:** 12-Jan-2015
-
-1. (bug #100, #101): Set right params for error thrown during reading of files.
-2. (bug #104): Fix formdata not defined.
-3. (enh #105): Expose current jqXHR object on ajax events.
-4. (enh #106): Enhance events for ajax requests and enable cancelling sync uploads
-5. (enh #108): Add nuget package.
-6. (bug #112): Fix undefined filestack for individual file upload within preview.
-7. (bug #113): Icon layout template undefined when using user template.
-8. (bug #114): Prevent multiple file selection when using single file configuration.
-9. (enh #115): Autosize file caption responsively on window resize.
-10. (enh #116): Hide remove and upload buttons until unless file(s) are selected.
-11. (enh #119): Enhance caption to include ellipsis for long file names
-12. (bug #120): Correct multiple iterations of upload for async batch uploads.
-13. (enh #121): Animate progress bars by default for upload progress.
-
-## version 4.1.4
-
-**Date:** 26-Dec-2014
-
-1. (enh #88): Allow uploadExtraData to be passed as a callback.
-2. (enh #89): New `otherActionButtons` to allow adding customized initial preview content actions.
-3. (enh #90): New event `filebatchpreupload` for both synchronous and asynchronous batch uploads.
-4. (enh #91): Pass FileReader instance with outData in events.
-5. (enh #92): Realign event triggering timing for batch uploads to ensure outData is available.
-6. (enh #93): Better styling of file upload icon indicators in thumbnails.
-7. Code cleanup with reusable methods for event raising and outData generation.
-8. (bug #95): Correct event off for drag & drop in plugin refresh method.
-9. (bug #97): Reset events correctly with plugin refresh method.
-
-## version 4.1.3
-
-**Date:** 20-Dec-2014
-
-1. (enh #85): Combine output data as a single object, that is sent for various file upload events. 
-    - `filepreupload`
-    - `fileuploaded`
-    - `fileuploaderror`
-    - `filebatchuploaderror`
-    - `filebatchuploadsuccess`
-    - `filebatchuploadcomplete`
-2. (enh #86): Disable thumbnail action buttons when upload is in progress.
-3. (enh #87): More correct progress indicator percentage for asynchronous upload.
-
-## version 4.1.2
-
-**Date:** 19-Dec-2014
-
-1. (enh #81): Add new events:
-    - `filebatchuploadsuccess`
-    - `filebatchuploadcomplete` 
-2. (enh #80): Allow access to `uploadExtraData` and `responseData` to following events
-    - `filepreupload`
-    - `fileuploaded`
-    - `fileuploaderror`
-    - `filebatchuploaderror`
-    - `filebatchuploadsuccess`
-    - `filebatchuploadcomplete`
-    - `filelock`
-    - `fileunlock`
-
-## version 4.1.1
-
-**Date:** 18-Dec-2014
-
-1. (bug #76): Update filestack when `showPreview` is false.
-2. (bug #78): Set uploadExtraData parameters to be correctly sent via POST.
-3. (enh #58): Set a new property `textEncoding` for reading the text files with right encoding.
-
-## version 4.1.0
-
-**Date:** 17-Dec-2014
-
-1. (enh #74): Enhancements to file validation errors for both FORM and AJAX uploads.
-    - For normal Form based uploads automatically disable the Upload button
-    - Display a separate error styled thumbnail for the file that faced the validation error.
-    - Reset errors correctly to overwrite files with a new change or drag/drop
-2. (enh #75): Better validation of browser support for drag and drop.
-
-## version 4.0.0
-
-**Date:** 14-Dec-2014
-
-1. (enh #70): Version 4.0 enhancements.
-2. Renamed `initialDelimiter` to `initialPreviewDelimiter`
-3. (bug #72): Fix bootstrap ## version constraint.
-
-### Version 4.0 Features
-
-1. Add functionality for AJAX based UPLOAD using HTML5 FormData (most modern browsers support it). Will degrade to normal Form Based File submission if this is not supported.
-2. To use AJAX Upload, the `uploadUrl` property is MANDATORY and must be set.
-3. Enhance plugin to now allow files to be added, appended, removed (based on FEEDBACK from many). Thus one can append files to preview.
-4. New DRAG & DROP zone available in preview to drag and drop files and append.
-5. Delete or upload files one by one OR in batch.
-6. If `showPreview` is set to false, or uploadUrl is not supported plugin will degrade to normal form based upload.
-7. Configurable indicators for file awaiting upload, file successfully uploaded, files errored in upload.
-8. Ability to add extra form data with ajax based uploads.
-9. Upload progress bar and individual thumbnail upload indicators.
-10. Ability to cancel and abort ongoing AJAX uploads.
-11. Templates have been revamped and enhanced for each file type.
-12. Ensure plugin is still lean in size and optimized for performance inspite of the above features by optimally utilizing HTML5 & jquery features only.
-
-### New properties added
-
-1. `showCancel`: shows a cancel button for aborting ajax uploads (defaults to `true`).
-2. `cancelLabel`: label for the cancel button.
-3. `cancelTitle`: title for the cancel button on hover.
-4. `cancelIcon`: icon markup for the cancel button
-5. `cancelClass`: CSS class for the cancel button.
-6. `removeTitle`: title for the remove button on hover.
-7. `uploadTitle`: title for the upload button on hover.
-8. `uploadUrl`: the url that will be used to process AJAX based uploads (using FormData XHR2).
-9. `uploadExtraData`: extra data that will be passed as data to the url/AJAX server call via POST
-10. `uploadAsync`: whether the batch upload of multiple files will be asynchronous/in parallel. Defaults to `true`.
-11. `initialPreviewShowDelete`:  shows a delete button for each initial preview content's thumbnail (defaults to `true`).
-12. `initialPreviewConfig`: configuration for setting up each `initialPreviewContent` item (associative array/object)
-    - `caption`: The caption or filename to display for each initial preview item content.
-    - `width`: The CSS width of the image/content displayed.
-    - `url`: The URL for deleting the image/content via AJAX (shown only for `initialPreviewContent`).
-    - `key`: The key that will be passed to the URL via POST (shown only for `initialPreviewContent`).
-13. `dropZoneEnabled`: Enable a drag and drop zone for dragging files and is available only for ajax based uploads (defaults to `true`). 
-14. `dropZoneTitle`: Title to be displayed in the drag & drop zone. 
-15. `dropZoneTitleClass`: CSS class for the drag & drop zone title.
-16. `fileActionSettings`: configuration for setting up actions for newly selected file thumbnails in the preview (associative array/object)
-    - `removeIcon`: icon for remove button to be displayed in each file thumbnail.
-    - `removeClass`: CSS class for the remove button in each file thumbnail.
-    - `removeTitle`: title for remove button in each file thumbnail.
-    - `uploadIcon`: icon for upload button to be displayed in each file thumbnail.
-    - `uploadClass`: CSS class for the remove button in each file thumbnail.
-    - `uploadTitle`: title for remove button in each file thumbnail.
-    - `indicatorNew`: an indicator (HTML markup) for new pending upload displayed in each file thumbnail.
-    - `indicatorSuccess`: an indicator (HTML markup) for successful upload displayed in each file thumbnail.
-    - `indicatorError`: an indicator (HTML markup) for error in upload displayed in each file thumbnail.
-    - `indicatorLoading`: an indicator (HTML markup) for ongoing upload displayed in each file thumbnail.
-    - `indicatorNewTitle`: title to display on hover of indicator for new pending upload in each file thumbnail.
-    - `indicatorSuccessTitle`: title to display on hover of indicator for successful in each file thumbnail.
-    - `indicatorErrorTitle`: title to display on hover of indicator for error in upload in each file thumbnail.
-    - `indicatorLoadingTitle`: title to display on hover of indicator for ongoing upload in each file thumbnail.
-
-## version 3.0.0
-
-**Date:** 08-Dec-2014
-
-1. (enh #60): Enhance upload button for disable/enable when used with `<a>` tag.
-2. (bug #61): Refresh preview to show errors correctly after each file is validated.
-3. (enh #64): Add ability to override the slug method with a `slugCallback` property.
-4. (enh #65): Correct validation of `refreshPreview` using `updateFileDetails`.
-5. (enh #67): Enhance support for IE browsers
-    - Add specific validations for parsing IE versions rightly
-    - Enhance plugin to extend styling support to IE 9 (with the limitation that IE 9 does not support HTML 5 features like multiple file upload)
-    - Fix clearing of file input rightly for IE 9 & IE 10
-    - Degrade plugin automatically to a native file input for older IE versions
-    - Prevent change method firing twice when file is cleared after error is encountered in IE 11.
-6. (bug #68): Fix refresh method of the fileinput to trigger change correctly.
-
-## version 2.9.0
-
-**Date:** 23-Nov-2014
-
-1. (enh #53): Validations and events for right reset of files when browse button is clicked.
-2. (enh #55): Clear the files when file browse dialog is cancelled only if the browser clears the native file input.
-3. (enh #56): Trigger new events `filebrowse` and `fileselectnone`.
-
-## version 2.8.0
-
-**Date:** 13-Nov-2014
-
-1. (enh #50): Dynamically auto size file captions for long file names exceeding container width. New property `autoFitCaption` 
-   is added which defaults to `true`. When this is `true` the plugin will auto fit caption text within the container dynamically
-   and responsively based on window size.
-2. (enh #51): Autosize preview images when they exceed the size of the preview container.
-3. (enh #52): Raise new `fileimageloaded` event.
-
-## version 2.7.0
-
-**Date:** 11-Nov-2014
-
-1. Set release to stable in composer.json.
-2. (enh #48): Trigger `fileloaded` event when `showPreview` is `false`.
-3. (enh #49): Set image preview dimensions to auto fit and center
-
-## version 2.6.0
-
-**Date:** 15-Oct-2014
-
-- (bug #40): More correct fix for IE (ver < 11) inability to clear fileinput values.
-- Templatize errorContainer for display within the preview window.
-- (enh #42): Enhance plugin to configure the `elErrorContainer` for displaying validation errors.
-- (bug #43): Validate special characters in filename before generating caption.
-- (bug #44): Browser IE10 hangs on file clear.
-
-## version 2.5.0
-
-**Date:** 09-Oct-2014
-
-- (enh #36): New feature. Validation routine for checking allowed file types and extensions.
-- (bug #37): HTML encode text content for preview in modal.
-- (enh #38): Highlight error CSS in file caption on validation error.
-- (bug #39): HTML encode caption hover title.
-- (bug #40): Fix IE (ver < 11) inability to clear fileinput values.
-
-## version 2.4.0
-
-**Date:** 20-Sep-2014
-
-- (enh #30): Enhanced generic support for more preview formats (audio, video, html, flash, and other objects).
-- (enh #31): Better control and configuration of preview templates.
-- (enh #32): Added checks for file api support.
-- (enh #33): Better text format validation and correct modal preview.
-
-> **Note:** There are BC Breaking Changes with release v2.4.0.
-
-With release v2.4.0, the plugin has been revamped to support and configure a wide variety of file formats for preview. This may break some
-backward compatibility (BC) for older versions that use custom templates. 
-
-The following are the major changes with release v2.4.0:
-
-- Plugin has been revamped to build preview intelligence based on various file preview types. The inbuilt file support types are categorized as 
-  `image`, `text`, `html`, `video`,  `audio`, `flash`, `object`, and `other`.
-- `allowedPreviewTypes`: You can now configure which all file types are allowed to be shown as a preview. This defaults to `['image', 'html', 'text', 'video', 'audio', 'flash', 'object']`.
-   Thus all file types are treated as an object to preview by default. For exampleTo preview only `image` and `video`, you can set this to `['image', 'video']`.
-- `allowedPreviewMimeTypes`: In addition to `allowedPreviewTypes`, you can also control which all mime types can be displayed for preview. This defaults to null,
-   meaning all mime types are supported.
-- `layoutTemplates`: Allows you to configure all layout template settings within one property. The layout objects that can be configured are: `main1`, `main2`,
-   `preview`, `caption`, and `modal`.
-- `previewTemplates`: All preview templates for **each preview type** have been combined into one property, instead of separate templates for image, text etc. 
-   The keys are the formats as set in `allowedPreviewTypes` and values are the templates used for previewing. There are default prebuilt templates for each 
-   preview file type (`generic`, `image`, `text`, `html`, `video`,  `audio`, `flash`, `object`, and `other`). The `generic` template is used only for displaying
-   `initialPreview` content using direct markup.
-- `previewSettings`: Allows you to configure width and height for each preview image type. The plugin has default widths and heights predefined for each type i.e
-   `image`, `text`, `html`, `video`,  `audio`, `flash`, and `object`.
-- `fileTypeSettings`: Allows you to configure and identify each preview file type using a callback. The plugin has default callbacks predefined to identify each type i.e
-   `image`, `text`, `html`, `video`,  `audio`, `flash`, and `object`.
-- Replacing tags within templates has been enhanced. With this release it will automatically check for multiple occurrences of each tag to replace within a template string.
-
-> NOTE: Flash preview will require Shockwave flash to be installed and supported by the client browser. The flash preview currently works successfully with webkit browsers only. Video & Audio formats are however supported by all modern browsers 
-that support the HTML5 `video`/`audio` tags. Note that browsers have limited number of video/audio formats supported by the HTML5 video element (e.g. mp4, webm, ogg, mp3, wav). The size of video files are recommended to be small (to be controlled 
-through `maxFileSize` property) so that it does not affect the preview performance. You can copy a few files from the `examples` directory of this plugin repo, to test a few examples of flash and video files.
-
-## version 2.3.0
-
-**Date:** 19-Sep-2014
-
-1. (enh #28, #29): Added support for previewing flash and video files.
-2. Better replacement of tags in templates. Replaces all tag occurences with this new release.
-
-## version 2.2.0
-
-**Date:** 19-Aug-2014
-
-1. (enh #24): Update readAsBinaryString to readAsArrayBuffer
-2. (enh #25): Graceful degrade to normal file input for older browsers (including previous versions of Safari).
-
-## version 2.1.0
-
-**Date:** 11-Aug-2014
-
-1. (enh #16, #17): Added exception handling for trapping FileReader API errors
-2. New configuration property added: `maxFilesCount`. Defaults to `0` which means unlimited.
-3. New configurable error messages added: `msgFilesTooMany`, `msgFileNotFound`, `msgFileNotReadable`, `msgFilePreviewAborted`, and `msgFilePreviewError`.
-4. Enhanced plugin to improve browser performance when loading and previewing multiple image files.
-5. (enh #18): Better validation for older browsers (not supporting HTML5) to degrade to normal file input.
-6. (enh #19): Synchronize preview with file browse dialog behavior, when cancel button is pressed in file dialog window.
-7. (enh #20): Fix `fileloaded` event to increment `previewId` and enhance to return file index.
-8. (enh #21): Enhance multiple file upload and preview performance using setTimeout.
-9. (enh #21): Enhance loading progress message and message templates for multiple file uploads.
-10. (enh #22): Enhance file caption message display for validation errors.
-11. Other minor bug fixes.
-
-## 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.
-
-## version 1.9.0
-
-**Date:** 21-Jul-2014
-
-1. (enh #9): Enhanced caption template and styling for captions to prevent overflow of long file names out of the caption container.
-2. (enh #10): Ability to display initial caption, when initialPreview is false.
-
-## version 1.8.0
-
-**Date:** 15-Jul-2014
-
-### 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.7.0
-
-**Date:** 02-Jul-2014
-
-### Additions
-1. The plugin now offers an additional `overwriteInitial` option. This is by default set 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 - useful especially when using the `multiple` file upload feature.
-
-## version 1.6.0
-
-**Date:** 03-Jun-2014
-
-### Additions
-1. The plugin now offers an additional `refresh` method. This enables you to dynamically change element attributes or plugin options
-   at runtime and refresh the widget.
-
-## version 1.5.0
-
-**Date:** 23-May-2014
-
-### Additions
-1. The plugin now offers an option to display initial preview of images/text/other files. This is useful
-   for record update scenarios. This can be a single image/file or an array of images/files.
-2. Extending to the above feature, the plugin also allows you to set a preview caption for the initial preview field.
-
-### Changes
-3. The following element identifiers need to be passed as a string like '#id' instead of a JQuery object:
-    
-- elCaptionContainer
-- elCaptionText
-- elPreviewContainer
-- elPreviewImage
-- elPreviewStatus
-
-## version 1.0.0
-
-**Date:** 01-Jan-2014 
-
-Initial release. The following features are included in this release:
-
-1. The plugin will convert a simple HTML file input to an advanced file picker control. Will help fallback to a file input for browsers not supporting JQuery or Javascript.
-2. The file input consists of the following three sections with options and templates to control the display:
-   - file caption section: to display a brief information of the file(s) selected
-   - file action buttons section: to browse, remove, and upload files.
-   - file preview section: to display the selected files on client for preview (supports images and text file types). Other file types will be displayed as normal thumbnails.
-3. The plugin automatically converts an input with `type = file` to an advanced file picker input if you set its `class = file`. All options to the input can be passed as HTML5 `data` attributes.
-4. Ability to select and preview multiple files. Uses HTML 5 File reader API to read and preview files. Displays the progress of files being being loaded onto the preview zone, in case many files are chosen.
-5. Offers predefined templates and CSS classes which can be changed to style your file-input display as per your needs.
-6. Option to show/hide any or all of the following:
-   - caption section
-   - preview section
-   - upload button
-   - remove button
-7. Customise the location of the target container elements to display the entire plugin, the caption container, the caption text, the preview container, preview image, and preview status.
-8. For text file previews, autowrap the text to the thumbnail width, and show a wrap indicator link to display complete text on hover. You can customize the wrap indicator (which defaults to &hellip;).
-9. Customise the messages for preview, progress, and files selected.
-10. Upload action defaults to form submit. Supports an upload route/server action parameter for custom ajax based upload.
-11. Triggers JQuery events for advanced development. Events currently available are `filereset` and `fileclear`.
-12. Disabled and readonly file input support.
-13. Size of the entire plugin is less than 11KB (about 9KB for the minified JS and 2KB for the minified CSS).
+Change Log: `bootstrap-fileinput`
+=================================
+
+## version 4.2.6
+
+**Date**: 27-Jul-2015
+
+1. (enh #373): Default delete ajax request type to POST (instead of DELETE).
+
+## version 4.2.5
+
+**Date**: 27-Jul-2015
+
+1. (enh #362): Add Bulgarian translations.
+2. (bug #370): Reverts #342 with better fix.
+3. (enh #371): Ability to replace files in the preview. New `autoReplace` property.
+4. (enh #372): Create new event `filepreajax`.
+
+## version 4.2.4
+
+**Date**: 22-Jul-2015
+
+1. (enh #340): Receive `previewId` and `index` in extra data for individual thumbnail uploads (ajax).
+2. (enh #342): Add ability to modify extra data before ajax upload in `beforeSend` events.
+3. (enh #351): Updates to Ukranian & Russian translations.
+4. (enh #356): Implement `destroy` method.
+5. (enh #357): Enhanced and better `refresh` method.
+6. (enh #358): Implement event namespaces and enhance event handling process.
+
+## version 4.2.3
+
+**Date**: 21-Jun-2015
+
+1. (enh #336): Fixes to reset preview via `initUploadSuccess`.
+
+## version 4.2.2
+
+**Date**: 18-Jun-2015
+
+1. (enh #332): Bump nuget and bower package versions.
+
+## version 4.2.1
+
+**Date**: 15-Jun-2015
+
+1. (enh #279, #280): Fixed error for failed response types.
+2. (enh #287): Add Brazilian Portugese (pt-BR) translations.
+3. (bug #295): Validate `overwriteInitial` correctly for ajax uploads.
+4. (enh #296): Fixed license identifiers in bower.json and composer.json.
+5. (enh #297): Add Romanian translations.
+6. (enh #299): Enhancements for displaying uploaded file thumbnails.
+    - New property `showUploadedThumbs` that will display uploaded thumbnails until the remove/clear button is explicitly pressed.
+    - New event `filesuccessremove`. This will be triggered on removing the uploaded thumbnail using the thumbnail delete button. The event shares the following parameters:
+        - `id`: the HTML id attribute of the thumbnail container 
+      The `event` can be set to return `false` to abort the thumbnail removal.
+7. (enh #302): Add Greek (el) translations.
+8. (enh #303): Validate only files to be dragged and dropped.
+9. (enh #305): Implement better cleanup of memory with `revokeObjectURL`.
+10. (enh #307): Allow setting thumbnail frame css class and attributes via `initialPreviewConfig`.
+11. (enh #308): Better check for `data.error` being empty.
+12. (enh #309): Fixes for older browsers.
+13. (bug #310): Set missing caption icon on error.
+14. (bug #315): Fix parsing of preview settings for default (other) preview.
+15. (bug #327): More correct clearing of preview.
+16. (bug #328): Implement image dimension validations.
+    - New properties added to the plugin:
+        - `minImageWidth`
+        - `minImageHeight`
+        - `maxImageWidth`
+        - `maxImageHeight`
+        - `msgImageWidthSmall`
+        - `msgImageHeightSmall`
+        - `msgImageWidthLarge`
+        - `msgImageHeightLarge`
+17. (enh #329): Message translation updates.
+18. (enh #330): Minor enhancements in validating preview and progress bar display.
+
+## version 4.2.0
+
+**Date**: 11-May-2015
+
+1. (enh #275): Add Czech & Slovakian translations.
+2. (enh #277): New `language` property to allow configuring multi lang widgets on same page.
+
+## version 4.1.9
+
+**Date**: 02-May-2015
+
+1. (enh #232): Update docs to reflect updated bootstrap CDN domain.
+2. (enh #237): Better styling of file caption icon.
+3. (bug #238): Correct initialization of plugin variables when other than maxFileCount & maxFileSize.
+4. (enh #241): Enhancements to initial preview delete to perform validations before delete.
+5. (bug #243): Correct sending of `deleteExtraData`.
+6. (enh #244): Add Serbian translations.
+7. (enh #245): Allow initial caption to be set without initial preview.
+8. (bug #247): Correct mime types validation.
+9. (enh #248): keep chinese characters in file caption.
+10. (bug #249): Fix error message content display.
+11. (enh #250): Change default slug routine to allow umlauts in filenames.
+12. (enh #251): Add Italian localizations.
+13. (enh #252): Enhance async batch completion.
+14. (bug #253): Fix initial preview delete cache initialization.
+15. (bug #257): Fix upload single to replace thumbs correctly.
+16. (enh #258): Enhance messages to include file plural and single.
+17. (enh #259): Add Polish translations.
+18. (enh #263): Enhance parsing of file preview thumbnails and actions.
+19. (enh #264): Validate input type of file before initializing plugin.
+20. (enh #269, #272): Add Turkish translations.
+21. (enh #270): Add Portugese translations.
+22. (enh #271): Add Dutch translations.
+23. (bug #273): Reset caption correctly after all initial preview is deleted.
+
+## version 4.1.8
+
+**Date**: 30-Mar-2015
+
+1. (bug #171): Fix typo for files validation.
+2. (enh #167, #173): New `deleteExtraData` property for ajax deletions.
+3. (enh #174): New `deleteUrl` property.
+4. (enh #175): Ability to override delete extra data in `initialPreviewConfig`.
+5. (enh #176): Wrong file in README installation steps fixed.
+6. (enh #177): Trigger filebatchpreupload if showPreview is `false`.
+7. (enh #178): Updated README for cancel button configuration.
+8. (enh #179): Validate and cast `maxFileSize` and `maxFileCount` to numeric - even if they have been setup as a string.
+9. (enh #181): Fix change event triggered for IE 11 when file input is set to empty.
+10. (enh #183): Delete extra data enhancements.
+11. (enh #184): Fix documentation for filedeleted event.
+12. (enh #187): New property `previewFileIcon` to configure file icon shown in preview for unreadable file types.
+13. (enh #188): Clear fileinput more correctly for all browsers when initialPreview is set enhancement
+14. (enh #189): Reinitialize initial preview delete events correctly on file selection.
+15. (enh #192): Ability to extend and add one's own ajax settings.
+    - New property `ajaxDeleteSettings` to help extend and add to delete ajax settings. 
+    - `ajaxSettings` to help extend and add upload ajax settings
+16. (bug #193): Better validation for triggering `filebatchuploadcomplete` on async batch upload completion.
+17. (enh #202): Ability to add Translations / Locales.
+    - Identify and group all messages that need to be translated configurable via `$.fn.fileinput.locales['<lang-code>']`
+    - Set default english messages configuration `$.fn.fileinput.locales['en']` within the plugin core code
+    - Individual locale files need to be created as separate js files e.g. `fileinput_locale_<lang>.js`
+18. (enh #203): Enhancements and revamp of all error events.
+    - fileerror
+    - fileuploaderror
+    - filebatchuploaderror
+    - filedeleteerror
+    - filefoldererror (new event - see #209)
+    - filecustomerror (new event - see #206)
+19. (enh #204): New properties `fileMinCount` and `msgFilesTooLess` (useful to make file input mandatory).
+    - The `fileMinCount` property will allow to set the minimum file count needed before triggering upload. It will work for both `ajax` uploads and `normal form based submission`.
+    - This will enable you to set the file input to be a mandatory / required input. (e.g. `fileMinCount` = `1`). The `msgFilesTooLess` will be displayed and error raised.
+    - If `fileMinCount` is set to `0` it will be treated as files are optional and no error will be triggered.
+20. (enh #205): Allow to auto set initialPreview within `filebatchuploadcomplete` & `filebatchuploadsuccess`.
+    - Allows you to auto define the `initialPreview` and  `initialPreviewConfig` after an ajax upload by returning these within the data object from your ajax response on `fileuploaded` & `filebatchuploadsuccess`. 
+21. (enh #206): Ability to add custom validation and trigger custom error to abort upload.
+    - This enhancement will enable you to add your additional custom validations to enhance the fileinput to be used for innumerous scenarios. It will allow an ability to return an associative object with any of the fileinput events (except the error events and the `filebatchuploadsuccess` or `filebatchuploadcomplete`) e.g. `change`, `fileselect`, `filepreupload`, `filebatchpreupload` etc. The object can return the following keys:
+        - `message`: _string_, the validation error message to be displayed before upload. If this is set the plugin will automatically abort the upload whenever called and display this as an error message. You can use this property for example to read a file and perform your own custom validation.
+        - `data`: _object_, an optional associative array of additional data that you can pass for usage later. 
+    - You can get this data by reading `abortData` in the parameters for the new `filecustomerror` event. This new event will be triggered during upload, when  you have triggered an abort from any of the other events. 
+22. (enh #209): Better validation for folder drag and drop and auto-skip any dropped folders. New property `msgFoldersNotAllowed` added to the plugin to allow configuring the message shown. The event `filefoldererror` is triggered when a folder is dragged.
+23. (enh #211): Add ability to show detailed server error stack via `showAjaxErrorDetails`.
+24. (enh #212): Revamp preview to use a new preview caching object.
+25. (enh #213): Code cleanup, eliminate change event on clear and properly reset preview cache after ajax deletes.
+26. (enh #215): Set default delete method REST compliant.
+27. (enh #216): Add Hungarian Translations.
+28. (enh #217): Ensure `filebatchselected` event is triggered after FileReader completes reading files selected.
+29. (enh #218): Do not clear preview for ajaxuploads until remove button clicked.
+30. (enh #222): Enhance to include dynamically replaceable thumbnail tags. Two new properties `previewThumbTags` and `initialPreviewThumbTags` will be available for configuration.
+31. (enh #225): Create Russian translations.
+32. (enh #226): Create Spanish (Latin American) translations.
+33. (enh #227): Created Ukranian translations and updated Russian translations.
+34. (enh #228): Created Thai translations.
+35. (enh #229): Created French translations.
+36. (enh #230): More correct initial preview delete reset.
+
+## version 4.1.7
+
+**Date**: 13-Feb-2015
+
+1. (enh #149): Custom tags support for layoutTemplates and previewTemplates (new properties `customLayoutTags` and `customPreviewTags` included).
+2. (enh #151): New `filebatchselected` event triggered after every batch of files are selected.
+3. (enh #152): New faster `replaceAll` method instead of regexp parsing to replace tags in templates.
+4. (enh #153): Improve error handler for trapping FileReader security exceptions and new property `msgFileSecured` will display the security exception message.
+5. (enh #154): Code cleanup and restructure for JS lint changes (using JSHint Code cleanup library).
+6. (enh #155): Allow display of long file names without spaces/word breaks.
+7. (enh #156): Fix reset of file stack for various upload modes (single, batch async and batch sync).
+8. (enh #157): Upload progress bar styling enhancements.
+    - Allow upload progress bar css class to be configurable 
+    - Create and allow two different styles/css classes for progress bar
+       - `progressClass`: styling for progress bar when upload is in process
+       - `progressCompleteClass`: styling for progress bar when upload is complete
+9. (bug #159): Ensure filestack is passed correctly with `outData` for events.
+10. (bug #160): Correct documentation typo for usage.
+11. (enh #162): New property ajaxSettings to allow configuring ajax params.
+12. Set copyright year to current.
+13. Relocate sample files from examples directory to [bootstrap-fileinput-samples](https://github.com/kartik-v/bootstrap-fileinput-samples) repo.
+
+## version 4.1.6
+
+**Date:** 20-Jan-2015
+
+1. (enh #124): Allow submission of extra data even if no files are selected.
+2. (enh #131): Allow empty values in extra data to be submitted.
+3. (enh #136):Create new upload method that can be called externally.
+4. (enh #137): Trigger new events - `filedisabled` and `fileenabled`.
+5. (enh #139): Reset file stack correctly on ajax upload completion.
+
+## version 4.1.5
+
+**Date:** 12-Jan-2015
+
+1. (bug #100, #101): Set right params for error thrown during reading of files.
+2. (bug #104): Fix formdata not defined.
+3. (enh #105): Expose current jqXHR object on ajax events.
+4. (enh #106): Enhance events for ajax requests and enable cancelling sync uploads
+5. (enh #108): Add nuget package.
+6. (bug #112): Fix undefined filestack for individual file upload within preview.
+7. (bug #113): Icon layout template undefined when using user template.
+8. (bug #114): Prevent multiple file selection when using single file configuration.
+9. (enh #115): Autosize file caption responsively on window resize.
+10. (enh #116): Hide remove and upload buttons until unless file(s) are selected.
+11. (enh #119): Enhance caption to include ellipsis for long file names
+12. (bug #120): Correct multiple iterations of upload for async batch uploads.
+13. (enh #121): Animate progress bars by default for upload progress.
+
+## version 4.1.4
+
+**Date:** 26-Dec-2014
+
+1. (enh #88): Allow uploadExtraData to be passed as a callback.
+2. (enh #89): New `otherActionButtons` to allow adding customized initial preview content actions.
+3. (enh #90): New event `filebatchpreupload` for both synchronous and asynchronous batch uploads.
+4. (enh #91): Pass FileReader instance with outData in events.
+5. (enh #92): Realign event triggering timing for batch uploads to ensure outData is available.
+6. (enh #93): Better styling of file upload icon indicators in thumbnails.
+7. Code cleanup with reusable methods for event raising and outData generation.
+8. (bug #95): Correct event off for drag & drop in plugin refresh method.
+9. (bug #97): Reset events correctly with plugin refresh method.
+
+## version 4.1.3
+
+**Date:** 20-Dec-2014
+
+1. (enh #85): Combine output data as a single object, that is sent for various file upload events. 
+    - `filepreupload`
+    - `fileuploaded`
+    - `fileuploaderror`
+    - `filebatchuploaderror`
+    - `filebatchuploadsuccess`
+    - `filebatchuploadcomplete`
+2. (enh #86): Disable thumbnail action buttons when upload is in progress.
+3. (enh #87): More correct progress indicator percentage for asynchronous upload.
+
+## version 4.1.2
+
+**Date:** 19-Dec-2014
+
+1. (enh #81): Add new events:
+    - `filebatchuploadsuccess`
+    - `filebatchuploadcomplete` 
+2. (enh #80): Allow access to `uploadExtraData` and `responseData` to following events
+    - `filepreupload`
+    - `fileuploaded`
+    - `fileuploaderror`
+    - `filebatchuploaderror`
+    - `filebatchuploadsuccess`
+    - `filebatchuploadcomplete`
+    - `filelock`
+    - `fileunlock`
+
+## version 4.1.1
+
+**Date:** 18-Dec-2014
+
+1. (bug #76): Update filestack when `showPreview` is false.
+2. (bug #78): Set uploadExtraData parameters to be correctly sent via POST.
+3. (enh #58): Set a new property `textEncoding` for reading the text files with right encoding.
+
+## version 4.1.0
+
+**Date:** 17-Dec-2014
+
+1. (enh #74): Enhancements to file validation errors for both FORM and AJAX uploads.
+    - For normal Form based uploads automatically disable the Upload button
+    - Display a separate error styled thumbnail for the file that faced the validation error.
+    - Reset errors correctly to overwrite files with a new change or drag/drop
+2. (enh #75): Better validation of browser support for drag and drop.
+
+## version 4.0.0
+
+**Date:** 14-Dec-2014
+
+1. (enh #70): Version 4.0 enhancements.
+2. Renamed `initialDelimiter` to `initialPreviewDelimiter`
+3. (bug #72): Fix bootstrap ## version constraint.
+
+### Version 4.0 Features
+
+1. Add functionality for AJAX based UPLOAD using HTML5 FormData (most modern browsers support it). Will degrade to normal Form Based File submission if this is not supported.
+2. To use AJAX Upload, the `uploadUrl` property is MANDATORY and must be set.
+3. Enhance plugin to now allow files to be added, appended, removed (based on FEEDBACK from many). Thus one can append files to preview.
+4. New DRAG & DROP zone available in preview to drag and drop files and append.
+5. Delete or upload files one by one OR in batch.
+6. If `showPreview` is set to false, or uploadUrl is not supported plugin will degrade to normal form based upload.
+7. Configurable indicators for file awaiting upload, file successfully uploaded, files errored in upload.
+8. Ability to add extra form data with ajax based uploads.
+9. Upload progress bar and individual thumbnail upload indicators.
+10. Ability to cancel and abort ongoing AJAX uploads.
+11. Templates have been revamped and enhanced for each file type.
+12. Ensure plugin is still lean in size and optimized for performance inspite of the above features by optimally utilizing HTML5 & jquery features only.
+
+### New properties added
+
+1. `showCancel`: shows a cancel button for aborting ajax uploads (defaults to `true`).
+2. `cancelLabel`: label for the cancel button.
+3. `cancelTitle`: title for the cancel button on hover.
+4. `cancelIcon`: icon markup for the cancel button
+5. `cancelClass`: CSS class for the cancel button.
+6. `removeTitle`: title for the remove button on hover.
+7. `uploadTitle`: title for the upload button on hover.
+8. `uploadUrl`: the url that will be used to process AJAX based uploads (using FormData XHR2).
+9. `uploadExtraData`: extra data that will be passed as data to the url/AJAX server call via POST
+10. `uploadAsync`: whether the batch upload of multiple files will be asynchronous/in parallel. Defaults to `true`.
+11. `initialPreviewShowDelete`:  shows a delete button for each initial preview content's thumbnail (defaults to `true`).
+12. `initialPreviewConfig`: configuration for setting up each `initialPreviewContent` item (associative array/object)
+    - `caption`: The caption or filename to display for each initial preview item content.
+    - `width`: The CSS width of the image/content displayed.
+    - `url`: The URL for deleting the image/content via AJAX (shown only for `initialPreviewContent`).
+    - `key`: The key that will be passed to the URL via POST (shown only for `initialPreviewContent`).
+13. `dropZoneEnabled`: Enable a drag and drop zone for dragging files and is available only for ajax based uploads (defaults to `true`). 
+14. `dropZoneTitle`: Title to be displayed in the drag & drop zone. 
+15. `dropZoneTitleClass`: CSS class for the drag & drop zone title.
+16. `fileActionSettings`: configuration for setting up actions for newly selected file thumbnails in the preview (associative array/object)
+    - `removeIcon`: icon for remove button to be displayed in each file thumbnail.
+    - `removeClass`: CSS class for the remove button in each file thumbnail.
+    - `removeTitle`: title for remove button in each file thumbnail.
+    - `uploadIcon`: icon for upload button to be displayed in each file thumbnail.
+    - `uploadClass`: CSS class for the remove button in each file thumbnail.
+    - `uploadTitle`: title for remove button in each file thumbnail.
+    - `indicatorNew`: an indicator (HTML markup) for new pending upload displayed in each file thumbnail.
+    - `indicatorSuccess`: an indicator (HTML markup) for successful upload displayed in each file thumbnail.
+    - `indicatorError`: an indicator (HTML markup) for error in upload displayed in each file thumbnail.
+    - `indicatorLoading`: an indicator (HTML markup) for ongoing upload displayed in each file thumbnail.
+    - `indicatorNewTitle`: title to display on hover of indicator for new pending upload in each file thumbnail.
+    - `indicatorSuccessTitle`: title to display on hover of indicator for successful in each file thumbnail.
+    - `indicatorErrorTitle`: title to display on hover of indicator for error in upload in each file thumbnail.
+    - `indicatorLoadingTitle`: title to display on hover of indicator for ongoing upload in each file thumbnail.
+
+## version 3.0.0
+
+**Date:** 08-Dec-2014
+
+1. (enh #60): Enhance upload button for disable/enable when used with `<a>` tag.
+2. (bug #61): Refresh preview to show errors correctly after each file is validated.
+3. (enh #64): Add ability to override the slug method with a `slugCallback` property.
+4. (enh #65): Correct validation of `refreshPreview` using `updateFileDetails`.
+5. (enh #67): Enhance support for IE browsers
+    - Add specific validations for parsing IE versions rightly
+    - Enhance plugin to extend styling support to IE 9 (with the limitation that IE 9 does not support HTML 5 features like multiple file upload)
+    - Fix clearing of file input rightly for IE 9 & IE 10
+    - Degrade plugin automatically to a native file input for older IE versions
+    - Prevent change method firing twice when file is cleared after error is encountered in IE 11.
+6. (bug #68): Fix refresh method of the fileinput to trigger change correctly.
+
+## version 2.9.0
+
+**Date:** 23-Nov-2014
+
+1. (enh #53): Validations and events for right reset of files when browse button is clicked.
+2. (enh #55): Clear the files when file browse dialog is cancelled only if the browser clears the native file input.
+3. (enh #56): Trigger new events `filebrowse` and `fileselectnone`.
+
+## version 2.8.0
+
+**Date:** 13-Nov-2014
+
+1. (enh #50): Dynamically auto size file captions for long file names exceeding container width. New property `autoFitCaption` 
+   is added which defaults to `true`. When this is `true` the plugin will auto fit caption text within the container dynamically
+   and responsively based on window size.
+2. (enh #51): Autosize preview images when they exceed the size of the preview container.
+3. (enh #52): Raise new `fileimageloaded` event.
+
+## version 2.7.0
+
+**Date:** 11-Nov-2014
+
+1. Set release to stable in composer.json.
+2. (enh #48): Trigger `fileloaded` event when `showPreview` is `false`.
+3. (enh #49): Set image preview dimensions to auto fit and center
+
+## version 2.6.0
+
+**Date:** 15-Oct-2014
+
+- (bug #40): More correct fix for IE (ver < 11) inability to clear fileinput values.
+- Templatize errorContainer for display within the preview window.
+- (enh #42): Enhance plugin to configure the `elErrorContainer` for displaying validation errors.
+- (bug #43): Validate special characters in filename before generating caption.
+- (bug #44): Browser IE10 hangs on file clear.
+
+## version 2.5.0
+
+**Date:** 09-Oct-2014
+
+- (enh #36): New feature. Validation routine for checking allowed file types and extensions.
+- (bug #37): HTML encode text content for preview in modal.
+- (enh #38): Highlight error CSS in file caption on validation error.
+- (bug #39): HTML encode caption hover title.
+- (bug #40): Fix IE (ver < 11) inability to clear fileinput values.
+
+## version 2.4.0
+
+**Date:** 20-Sep-2014
+
+- (enh #30): Enhanced generic support for more preview formats (audio, video, html, flash, and other objects).
+- (enh #31): Better control and configuration of preview templates.
+- (enh #32): Added checks for file api support.
+- (enh #33): Better text format validation and correct modal preview.
+
+> **Note:** There are BC Breaking Changes with release v2.4.0.
+
+With release v2.4.0, the plugin has been revamped to support and configure a wide variety of file formats for preview. This may break some
+backward compatibility (BC) for older versions that use custom templates. 
+
+The following are the major changes with release v2.4.0:
+
+- Plugin has been revamped to build preview intelligence based on various file preview types. The inbuilt file support types are categorized as 
+  `image`, `text`, `html`, `video`,  `audio`, `flash`, `object`, and `other`.
+- `allowedPreviewTypes`: You can now configure which all file types are allowed to be shown as a preview. This defaults to `['image', 'html', 'text', 'video', 'audio', 'flash', 'object']`.
+   Thus all file types are treated as an object to preview by default. For exampleTo preview only `image` and `video`, you can set this to `['image', 'video']`.
+- `allowedPreviewMimeTypes`: In addition to `allowedPreviewTypes`, you can also control which all mime types can be displayed for preview. This defaults to null,
+   meaning all mime types are supported.
+- `layoutTemplates`: Allows you to configure all layout template settings within one property. The layout objects that can be configured are: `main1`, `main2`,
+   `preview`, `caption`, and `modal`.
+- `previewTemplates`: All preview templates for **each preview type** have been combined into one property, instead of separate templates for image, text etc. 
+   The keys are the formats as set in `allowedPreviewTypes` and values are the templates used for previewing. There are default prebuilt templates for each 
+   preview file type (`generic`, `image`, `text`, `html`, `video`,  `audio`, `flash`, `object`, and `other`). The `generic` template is used only for displaying
+   `initialPreview` content using direct markup.
+- `previewSettings`: Allows you to configure width and height for each preview image type. The plugin has default widths and heights predefined for each type i.e
+   `image`, `text`, `html`, `video`,  `audio`, `flash`, and `object`.
+- `fileTypeSettings`: Allows you to configure and identify each preview file type using a callback. The plugin has default callbacks predefined to identify each type i.e
+   `image`, `text`, `html`, `video`,  `audio`, `flash`, and `object`.
+- Replacing tags within templates has been enhanced. With this release it will automatically check for multiple occurrences of each tag to replace within a template string.
+
+> NOTE: Flash preview will require Shockwave flash to be installed and supported by the client browser. The flash preview currently works successfully with webkit browsers only. Video & Audio formats are however supported by all modern browsers 
+that support the HTML5 `video`/`audio` tags. Note that browsers have limited number of video/audio formats supported by the HTML5 video element (e.g. mp4, webm, ogg, mp3, wav). The size of video files are recommended to be small (to be controlled 
+through `maxFileSize` property) so that it does not affect the preview performance. You can copy a few files from the `examples` directory of this plugin repo, to test a few examples of flash and video files.
+
+## version 2.3.0
+
+**Date:** 19-Sep-2014
+
+1. (enh #28, #29): Added support for previewing flash and video files.
+2. Better replacement of tags in templates. Replaces all tag occurences with this new release.
+
+## version 2.2.0
+
+**Date:** 19-Aug-2014
+
+1. (enh #24): Update readAsBinaryString to readAsArrayBuffer
+2. (enh #25): Graceful degrade to normal file input for older browsers (including previous versions of Safari).
+
+## version 2.1.0
+
+**Date:** 11-Aug-2014
+
+1. (enh #16, #17): Added exception handling for trapping FileReader API errors
+2. New configuration property added: `maxFilesCount`. Defaults to `0` which means unlimited.
+3. New configurable error messages added: `msgFilesTooMany`, `msgFileNotFound`, `msgFileNotReadable`, `msgFilePreviewAborted`, and `msgFilePreviewError`.
+4. Enhanced plugin to improve browser performance when loading and previewing multiple image files.
+5. (enh #18): Better validation for older browsers (not supporting HTML5) to degrade to normal file input.
+6. (enh #19): Synchronize preview with file browse dialog behavior, when cancel button is pressed in file dialog window.
+7. (enh #20): Fix `fileloaded` event to increment `previewId` and enhance to return file index.
+8. (enh #21): Enhance multiple file upload and preview performance using setTimeout.
+9. (enh #21): Enhance loading progress message and message templates for multiple file uploads.
+10. (enh #22): Enhance file caption message display for validation errors.
+11. Other minor bug fixes.
+
+## 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.
+
+## version 1.9.0
+
+**Date:** 21-Jul-2014
+
+1. (enh #9): Enhanced caption template and styling for captions to prevent overflow of long file names out of the caption container.
+2. (enh #10): Ability to display initial caption, when initialPreview is false.
+
+## version 1.8.0
+
+**Date:** 15-Jul-2014
+
+### 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.7.0
+
+**Date:** 02-Jul-2014
+
+### Additions
+1. The plugin now offers an additional `overwriteInitial` option. This is by default set 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 - useful especially when using the `multiple` file upload feature.
+
+## version 1.6.0
+
+**Date:** 03-Jun-2014
+
+### Additions
+1. The plugin now offers an additional `refresh` method. This enables you to dynamically change element attributes or plugin options
+   at runtime and refresh the widget.
+
+## version 1.5.0
+
+**Date:** 23-May-2014
+
+### Additions
+1. The plugin now offers an option to display initial preview of images/text/other files. This is useful
+   for record update scenarios. This can be a single image/file or an array of images/files.
+2. Extending to the above feature, the plugin also allows you to set a preview caption for the initial preview field.
+
+### Changes
+3. The following element identifiers need to be passed as a string like '#id' instead of a JQuery object:
+    
+- elCaptionContainer
+- elCaptionText
+- elPreviewContainer
+- elPreviewImage
+- elPreviewStatus
+
+## version 1.0.0
+
+**Date:** 01-Jan-2014 
+
+Initial release. The following features are included in this release:
+
+1. The plugin will convert a simple HTML file input to an advanced file picker control. Will help fallback to a file input for browsers not supporting JQuery or Javascript.
+2. The file input consists of the following three sections with options and templates to control the display:
+   - file caption section: to display a brief information of the file(s) selected
+   - file action buttons section: to browse, remove, and upload files.
+   - file preview section: to display the selected files on client for preview (supports images and text file types). Other file types will be displayed as normal thumbnails.
+3. The plugin automatically converts an input with `type = file` to an advanced file picker input if you set its `class = file`. All options to the input can be passed as HTML5 `data` attributes.
+4. Ability to select and preview multiple files. Uses HTML 5 File reader API to read and preview files. Displays the progress of files being being loaded onto the preview zone, in case many files are chosen.
+5. Offers predefined templates and CSS classes which can be changed to style your file-input display as per your needs.
+6. Option to show/hide any or all of the following:
+   - caption section
+   - preview section
+   - upload button
+   - remove button
+7. Customise the location of the target container elements to display the entire plugin, the caption container, the caption text, the preview container, preview image, and preview status.
+8. For text file previews, autowrap the text to the thumbnail width, and show a wrap indicator link to display complete text on hover. You can customize the wrap indicator (which defaults to &hellip;).
+9. Customise the messages for preview, progress, and files selected.
+10. Upload action defaults to form submit. Supports an upload route/server action parameter for custom ajax based upload.
+11. Triggers JQuery events for advanced development. Events currently available are `filereset` and `fileclear`.
+12. Disabled and readonly file input support.
+13. Size of the entire plugin is less than 11KB (about 9KB for the minified JS and 2KB for the minified CSS).

+ 27 - 27
LICENSE.md

@@ -1,28 +1,28 @@
-Copyright (c) 2014 - 2015, Kartik Visweswaran  
-Krajee.com  
-All rights reserved.  
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-* Redistributions of source code must retain the above copyright notice, this
-  list of conditions and the following disclaimer.
-
-* Redistributions in binary form must reproduce the above copyright notice, this
-  list of conditions and the following disclaimer in the documentation and/or
-  other materials provided with the distribution.
-
-* Neither the names of Kartik Visweswaran or Krajee nor the names of its
-  contributors may be used to endorse or promote products derived from
-  this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+Copyright (c) 2014 - 2015, Kartik Visweswaran  
+Krajee.com  
+All rights reserved.  
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+  list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice, this
+  list of conditions and the following disclaimer in the documentation and/or
+  other materials provided with the distribution.
+
+* Neither the names of Kartik Visweswaran or Krajee nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 1663 - 1663
README.md

@@ -1,1663 +1,1663 @@
-bootstrap-fileinput
-====================
-
-[![Bower version](https://badge.fury.io/bo/bootstrap-fileinput.svg)](http://badge.fury.io/bo/bootstrap-fileinput)
-[![Latest Stable Version](https://poser.pugx.org/kartik-v/bootstrap-fileinput/v/stable)](https://packagist.org/packages/kartik-v/bootstrap-fileinput)
-[![License](https://poser.pugx.org/kartik-v/bootstrap-fileinput/license)](https://packagist.org/packages/kartik-v/bootstrap-fileinput)
-[![Packagist Downloads](https://poser.pugx.org/kartik-v/bootstrap-fileinput/downloads)](https://packagist.org/packages/kartik-v/bootstrap-fileinput)
-[![Monthly Downloads](https://poser.pugx.org/kartik-v/bootstrap-fileinput/d/monthly)](https://packagist.org/packages/kartik-v/bootstrap-fileinput)
-
-An enhanced HTML 5 file input for Bootstrap 3.x with file preview for various files, offers multiple selection, and more. The plugin allows you a simple way to setup an advanced file picker/upload control built to work specially with Bootstrap CSS3 styles. It enhances the file input functionality further, by offering support to preview a wide variety of files i.e. images, text, html, video, audio, flash, and objects. In addition, it includes AJAX based uploads, dragging &amp; dropping files, viewing upload progress, and selectively previewing, adding, or deleting files.
-![File Input Screenshot](https://lh3.googleusercontent.com/-3FiEmc_okc4/VBw_d2LBAJI/AAAAAAAAAL8/KbVj5X9Dus0/w596-h454-no/FileInput.jpg)
-
-This plugin was initially inspired by [this blog article](http://www.abeautifulsite.net/blog/2013/08/whipping-file-inputs-into-shape-with-bootstrap-3/) and [Jasny's File Input plugin](http://jasny.github.io/bootstrap/javascript/#fileinput). But the plugin has now matured with various additional features and enhancements to be a complete (yet simple) file management tool and solution for web developers. 
-
-> NOTE: The latest version of the plugin v4.2.5 has been released. Refer the [CHANGE LOG](https://github.com/kartik-v/bootstrap-fileinput/blob/master/CHANGE.md) for details. 
-
-## Features  
-
-### File Input Features
-
-1. The plugin will convert a simple HTML file input to an advanced file picker control. Will help fallback to a normal HTML file input for browsers not supporting JQuery or Javascript.
-2. The file input consists of the following three sections with options and templates to control the display:
-   - **_file caption section_**: to display a brief information of the file(s) selected
-   - **_file action buttons section_**: to browse, remove, and upload files.
-   - **_file preview section_**: to display the selected files on client for preview (supports preview of image, text, flash, and video file types). Other file types will be displayed as normal thumbnails.
-3. The plugin automatically converts an input with `type = file` to an advanced file picker input if you set its `class = file`. All options to the input can be passed as HTML5 `data` attributes.
-4. Ability to select and preview multiple files. Uses HTML 5 File reader API to read and preview files. Displays the progress of files being being loaded onto the preview zone, in case many files are chosen.
-5. Offers predefined templates and CSS classes which can be changed to style your file-input display as per your needs.
-6. With **v1.5.0**, you can now configure the plugin to show an **initial preview of images/files** with **initial caption** 
-   (more useful for record update scenarios). Refer the [`initialPreview`](https://github.com/kartik-v/bootstrap-fileinput/blob/master/README.md#initialpreview) 
-   and [`initialCaption`](https://github.com/kartik-v/bootstrap-fileinput/blob/master/README.md#initialcaption) properties in the plugin options
-   section for configuring this.
-7. Option to show/hide any or all of the following:
-   - caption section
-   - preview section
-   - upload button
-   - remove button
-8. Customise the location of the target container elements to display the entire plugin, the caption container, the caption text, the preview container, preview image, and preview status.
-9. For text file previews, autowrap the text to the thumbnail width, and show a wrap indicator link to display complete text on hover. You can customize the wrap indicator (which defaults to &hellip;).
-10. Customise the messages for preview, progress, and files selected.
-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`, `fileclear`, `filecleared`, `fileloaded`, and `fileerror`.
-13. Disabled and readonly file input support.
-14. Dynamically auto size the file captions for long file names exceeding container width. 
-15. Raise new `fileimageuploaded` event that fires after image is completely loaded on the preview container.
-16. Autosize preview images when they exceed the size of the preview container.
-17. Completely templatized and extensible to allow configuration of the file-input the way the developer wants.
-18. Preview intelligence based on various file preview types. The inbuilt file support types are categorized as `image`, `text`, `html`, `video`,  `audio`, `flash`, `object`, and `other`.
-19. `allowedPreviewTypes`: You can now configure which all file types are allowed to be shown as a preview. This defaults to `['image', 'html', 'text', 'video', 'audio', 'flash', 'object']`. Thus all file types are treated as an object to preview by default. For exampleTo preview only `image` and `video`, you can set this to `['image', 'video']`.
-20. `allowedPreviewMimeTypes`: In addition to `allowedPreviewTypes`, you can also control which all mime types can be displayed for preview. This defaults to null, meaning all mime types are supported.
-   >NOTE: With release 2.5.0 you can now control which file types or extensions are allowed for upload by setting `allowedFileTypes` and `allowedFileExtensions`.
-21. `layoutTemplates`: Allows you to configure all layout template settings within one property. The layout objects that can be configured are: `main1`, `main2`, `preview`, `caption`, and `modal`.
-22. `previewTemplates`: All preview templates for **each preview type** have been combined into one property, instead of separate templates for image, text etc. The keys are the formats as set in `allowedPreviewTypes` and values are the templates used for previewing. There are default prebuilt templates for each preview file type (`generic`, `image`, `text`, `html`, `video`,  `audio`, `flash`, `object`, and `other`). The `generic` template is used only for displaying `initialPreview` content using direct markup.
-23. `previewSettings`: Allows you to configure width and height for each preview image type. The plugin has default widths and heights predefined for each type i.e `image`, `text`, `html`, `video`,  `audio`, `flash`, and `object`.
-24. `fileTypeSettings`: Allows you to configure and identify each preview file type using a callback. The plugin has default callbacks predefined to identify each type i.e `image`, `text`, `html`, `video`,  `audio`, `flash`, and `object`.
-25. Replacing tags within templates has been enhanced. With this release it will automatically check for multiple occurrences of each tag to replace within a template string.
-26. Manipulate events and add your own custom validation messages easily by returning output to abort uploads in any of the other events.
-27. Support for translations and locales.
-
-### File Upload Features
-
-With release 4.0.0, the plugin now also includes inbuilt support for AJAX Uploads and selectively adding or deleting files. AJAX upload functionality are 
-built upon HTML5 FormData and XMLHttpRequest Level 2 standards. Most modern browsers do support this standard, but the plugin will automatically degrade to normal form based submission for unsupported browsers.
-
-1. Add functionality for AJAX based UPLOAD using HTML5 FormData (most modern browsers support it). Will degrade to normal Form Based File submission if this is not supported.
-2. To use AJAX Upload, one must set the `uploadUrl` property.
-3. Enhance plugin to now allow files to be added, appended, removed (based on FEEDBACK from many). Thus one can append files to preview.
-4. New DRAG & DROP zone available in preview to drag and drop files and append.
-5. Delete or upload files one by one OR in batch.
-6. If `showPreview` is set to false, or uploadUrl is not supported plugin will degrade to normal form based upload.
-7. Configurable indicators for file awaiting upload, file successfully uploaded, files errored in upload.
-8. Ability to add extra form data with ajax based uploads.
-9. Upload progress bar and individual thumbnail upload indicators.
-10. Ability to cancel and abort ongoing AJAX uploads.
-11. Build up initial preview content (e.g. gallery of saved images). You can set initial preview actions (prebuilt support for initial preview delete). Other custom action buttons can be set for initial preview thumbnails as well. 
-12. Ensure plugin is still lean in size and optimized for performance inspite of the above features by optimally utilizing HTML5 & jquery features only.
-13. Automatically refresh preview with content from server as soon as an ajax upload finishes.
-
-> NOTE: Drag and Drop zone functionality, selectively appending or deleting files, and upload indicator with progress are ONLY AVAILABLE if you use AJAX BASED uploads (by setting `uploadUrl`).
-
-## Demo
-
-View the [plugin documentation](http://plugins.krajee.com/file-input) and [plugin demos](http://plugins.krajee.com/file-input/demo) at Krajee JQuery plugins. 
-
-## Pre-requisites  
-
-1. [Bootstrap 3.x](http://getbootstrap.com/)
-2. Latest [JQuery](http://jquery.com/)
-3. Most modern browsers supporting HTML5 (inputs and FileReader API) including CSS3 & JQuery. For Internet Explorer, one must use IE versions 10 and above. IE9 and below will work as a normal file input, and will not support multiple file selection or the HTML 5 FileReader API.
-4. With release 4.0, AJAX uploads are supported. AJAX uploads require that the browser support HTML5 FormData and XHR2 (XMLHttpRequest 2). Most modern browsers support FormData and XHR2. The plugin will automatically degrade to normal form based submission for browsers not supporting AJAX uploads.
-
-## Installation
-
-### Using Bower
-You can use the `bower` package manager to install. Run:
-
-    bower install bootstrap-fileinput
-
-### Using Composer
-You can use the `composer` package manager to install. Either run:
-
-    $ php composer.phar require kartik-v/bootstrap-fileinput "@dev"
-
-or add:
-
-    "kartik-v/bootstrap-fileinput": "@dev"
-
-to your composer.json file
-
-### Manual Install
-
-You can also manually install the plugin easily to your project. Just download the source [ZIP](https://github.com/kartik-v/bootstrap-fileinput/zipball/master) or [TAR ball](https://github.com/kartik-v/bootstrap-fileinput/tarball/master) and extract the plugin assets (css and js folders) into your project.
-
-## Usage
-
-Step 1: Load the following assets in your header. 
-
-```html
-<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet">
-<link href="path/to/css/fileinput.min.css" media="all" rel="stylesheet" type="text/css" />
-<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
-<script src="path/to/js/fileinput.min.js"></script>
-<!-- bootstrap.js below is only needed if you wish to the feature of viewing details
-     of text file preview via modal dialog -->
-<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js" type="text/javascript"></script>
-<!-- optionally if you need translation for your language then include 
-    locale file as mentioned below -->
-<script src="path/to/js/fileinput_locale_<lang>.js"></script>
-```
-
-If you noticed, you need to load the `jquery.min.js` and `bootstrap.min.css` in addition to the `fileinput.min.css` and `fileinput.min.js`. The locale file `fileinput_locale_<lang>.js` can be optionally included for translating for your language if needed.
-
-Step 2: Initialize the plugin on your page. For example,
-
-```js
-// initialize with defaults
-$("#input-id").fileinput();
-
-// with plugin options
-$("#input-id").fileinput({'showUpload':false, 'previewFileType':'any'});
-```
-
-The `#input-id` is the identifier for the input (e.g. `type = file`) on your page, which is hidden automatically by the plugin. 
-
-Alternatively, you can directly call the plugin options by setting data attributes to your input field.
-
-```html
-<input id="input-id" type="file" class="file" data-preview-file-type="text" >
-```
-
-## Translations
-
-As shown in the installation section, translations are now enabled with release 4.1.8. You can load a locale file `/fileinput_locale_<lang>.js` after the core `fileinput.min.js` file, where `<lang>` is the language code (e.g. `de`, `fr` etc.). If  locale file does not exist, you can submit a translation for the new language via a [new pull request to add to this folder](https://github.com/kartik-v/bootstrap-fileinput/tree/master/js). Use the [sample locale file](https://github.com/kartik-v/bootstrap-fileinput/tree/master/js/fileinput_locale_LANG.js) to copy and create a translation configuration for your own language.
-
-## Plugin Options
-The plugin supports these following options:
-
-### language
-_string_ language configuration for the plugin to enable the plugin to display messages for your locale (you must set the ISO code for the language). You can have multiple language widgets on the same page. The locale JS file for the language code must be defined as mentioned in the translations section. The file must be loaded after `fileinput.js`.
-
-### showCaption
-_boolean_ whether to display the file caption. Defaults to `true`.
-
-### showPreview
-_boolean_ whether to display the file preview. Defaults to `true`.
-
-### showRemove
-_boolean_ whether to display the file remove/clear button. Defaults to `true`.
-
-### showUpload
-_boolean_ whether to display the file upload button. Defaults to `true`. This will default to a form submit button, unless the uploadUrl is specified.
-
-### showCancel
-_boolean_ whether to display the file upload cancel button. Defaults to `true`. This will be only enabled and displayed when an AJAX upload is in process.
-
-### showUploadedThumbs
-_boolean_ whether to persist display of the uploaded file thumbnails in the preview window (for ajax uploads) until the remove/clear button is pressed. Defaults to `true`.  When set to `false`, a next batch of files selected for upload will clear these thumbnails from preview.
-
-### autoReplace
-_boolean_ whether to automatically replace the files in the preview after the `maxFileCount` limit is reached and a new set of file(s) is/are selected. This will only work if a valid  `maxFileCount` is set. Defaults to `false`.
-
-### captionClass
-_string_ any additional CSS class to append to the caption container.
-
-### previewClass
-_string_ any additional CSS class to append to the preview container.
-
-### mainClass
-_string_ any additional CSS class to append to the main plugin container.
-
-### 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 there is no delimiter. You can set a delimiter (as defined 
-in `initialDelimiter`) to show multiple files in initial preview.  If set as an array, it will display all files in the array as an 
-initial preview (useful for multiple file upload scenarios).
-
-The following CSS classes will need to be added for displaying each file type as per the plugin style theme:
-
-- **image files:** Include CSS class `file-preview-image`
-- **text files:** Include CSS class `file-preview-text`
-- **other files:** Include CSS class `file-preview-other`
-
-Examples of how you can setup various files for initial preview:
-
-```js
-// for image files
-initialPreview: [
-    "<img src='/images/desert.jpg' class='file-preview-image' alt='Desert' title='Desert'>",
-    "<img src='/images/jellyfish.jpg' class='file-preview-image' alt='Jelly Fish' title='Jelly Fish'>",
-],
-
-// for text files
-initialPreview: "<div class='file-preview-text' title='NOTES.txt'>" +
-    "This is the sample text file content upto wrapTextLength of 250 characters" +
-    "<span class='wrap-indicator' onclick='$(\"#show-detailed-text\").modal(\"show\")' title='NOTES.txt'>[…]</span>" +
-    "</div>"
-
-// for other files    
-initialPreview: "<div class='file-preview-text'>" + 
-    "<h2><i class='glyphicon glyphicon-file'></i></h2>" +
-    "Filename.xlsx" + "</div>"
-```
-
-### initialPreviewCount
-_int_, the count of initial preview items that will be added to the count of files selected in preview. This is applicable when displaying
-the right caption, when `overwriteInitial` is set to `false`.
-
-### initialPreviewDelimiter
-_string_, the delimiter to be used for splitting the initial preview content as individual file thumbnails (applicable only if `initialPreview` is passed as a _string_ instead of _array_). Defaults to `*$$*`.
-
-### initialPreviewConfig
-_array_, the configuration for setting up important properties for each `initialPreview` item (that is setup as part of `initialPreview`). Each element in the array should be an object/associative array consisting of the following keys:
-
-    - `caption`: _string_, the caption or filename to display for each initial preview item content.
-    - `width`: _string_, the CSS width of the image/content displayed.
-    - `url`: _string_, the URL for deleting the image/content in the initial preview via AJAX post response. This will default to `deleteUrl` if not set.
-    - `key`: _string|object_, the key that will be passed as data to the `url` via AJAX POST.
-    - `frameClass`: _string_, the additional frame css class to set for the file's thumbnail frame.
-    - `frameAttr`: _object_, the HTML attribute settings (set as key:value pairs) for the thumbnail frame.
-    - `extra`: _object|function_, the extra data that will be passed as data to the initial preview delete url/AJAX server call via POST. This will default to `deleteExtraData` if not set.
-
-An example configuration of `initialPreviewConfig` (for the previously set `initialPreviewContent`) can be:
-
-```js
-// setup initial preview with data keys 
-initialPreview: [
-    "<img src='/images/desert.jpg' class='file-preview-image' alt='Desert' title='Desert'>",
-    "<img src='/images/jellyfish.jpg' class='file-preview-image' alt='Jelly Fish' title='Jelly Fish'>",
-],
-// initial preview configuration
-initialPreviewConfig: [
-    {
-        caption: 'desert.jpg', 
-        width: '120px', 
-        url: '/localhost/avatar/delete', 
-        key: 100, 
-        extra: {id: 100}
-    },
-    {
-        caption: 'jellyfish.jpg', 
-        width: '120px', 
-        url: '/localhost/avatar/delete', 
-        key: 101, 
-        frameClass: 'my-custom-frame-css',
-        frameAttr: {
-            style: 'height:80px',
-            title: 'My Custom Title',
-        },
-        extra: function() { 
-            return {id: $("#id").val()};
-        },
-    }
-]
-```
-
-> Note: The ajax delete action will send the following data to server via POST:
-- `key`: the key setting as setup in `initialPreviewConfig['key']`
-- any other extra data as `key: value` pairs passed either via `initialPreviewConfig['extra']` OR `deleteExtraData` format if former is not set.
-
-### initialPreviewShowDelete
-_bool_, whether the delete button will be displayed for each thumbnail that has been created with `initialPreview`.
-
-### previewThumbTags
-_array_, this will be a list of tags used in thumbnail templates that will be replaced dynamically within the thumbnail markup, when the thumbnail is rendered. For example:
-
-```js
-// change thumbnail footer template
-layoutTemplates.footer = '<div class="file-thumbnail-footer">\n' +
-'    <div class="file-caption-name">{caption}</div>\n' +
-'    {CUSTOM_TAG_NEW}\n' +
-'    {CUSTOM_TAG_INIT}\n' +
-'    {actions}\n' +
-'</div>';
-
-// set preview template tags
-previewThumbTags = {
-    '{CUSTOM_TAG_NEW}': '<span class="custom-css">CUSTOM MARKUP</span>',
-    '{CUSTOM_TAG_INIT}': '&nbsp;'
-};
-```
-
-### initialPreviewThumbTags
-_array_, this is an extension of `previewThumbTags` specifically for initial preview content - but will be configured as an array of objects corresponding to each initial preview thumbnail. The initial preview thumbnails set via `initialPreview` will read this configuration for replacing tags. Extending example above:
-
-
-```js
-// change thumbnail footer template
-layoutTemplates.footer = '<div class="file-thumbnail-footer">\n' +
-'    <div class="file-caption-name">{caption}</div>\n' +
-'    {CUSTOM_TAG_NEW}\n' +
-'    {CUSTOM_TAG_INIT}\n' +
-'    {actions}\n' +
-'</div>';
-
-// setup initial preview with data keys 
-initialPreview: [
-    "<img src='/images/desert.jpg' class='file-preview-image' alt='Desert' title='Desert'>",
-    "<img src='/images/jellyfish.jpg' class='file-preview-image' alt='Jelly Fish' title='Jelly Fish'>",
-],
-
-// set initial preview template tags
-initialPreviewThumbTags = {
-    '{CUSTOM_TAG_NEW}': '&nbsp;',
-    '{CUSTOM_TAG_INIT}': '<span class="custom-css">CUSTOM MARKUP</span>'
-};
-```
-
-### deleteExtraData
-_object | function_ the extra data that will be passed as data to the initial preview delete url/AJAX server call via POST. This will be overridden by the `initialPreviewConfig['extra']` property. This can be setup either as an object (associative array of keys and values) or as a function callback. As an object, it can be set for example as:
-
-```js
- {id: 100, value: '100 Details'}
-```
-
-As a function callback, it can be setup for example as:
-
-```js
-function() {
-    var obj = {};
-    $('.your-form-class').find('input').each(function() {
-        var id = $(this).attr('id'), val = $(this).val();
-        obj[id] = val;
-    });
-    return obj;
-}
-```
-### deleteUrl
-_object | function_ the URL for deleting the image/content in the initial preview via AJAX post response. This will be overridden by the `initialPreviewConfig['url']` property.
-
-### initialCaption
-_string_ the initial preview caption text to be displayed. If you do not set a value here and `initialPreview` is set to 
-`true` this will default to `"{preview-file-count} files selected"`, where `{preview-file-count}` is the count of the 
-files passed in `initialPreview`.
-
-### 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 - 
-useful especially when using the `multiple` file upload feature.
- 
-### layoutTemplates
-
-_object_ the templates configuration for rendering each part of the layout. You can set the following templates to control the widget layout:
-
-- `main1`: the template for rendering the widget with caption.
-- `main2`: the template for rendering the widget without caption.
-- `preview`: the template for rendering the preview.
-- `icon`: the icon to render before the caption text.
-- `caption`: the template for rendering the caption.
-- `modal`: the template for rendering the modal (for text file preview zooming).
-- `progress`: the template for the progress bar when upload is in progress (for batch/mass uploads). The following tags will be parsed and replaced automatically:
-    - `{percent}`: will be replaced with the upload progress percentage.
-- `footer`: the template for the footer section of each file preview thumbnail. The following tags will be parsed and replaced automatically:
-    - `{actions}`: will be replaced with the output of the `actions` template.
-- `actions`: the template for the file action buttons to be displayed within the thumbnail `footer`. The following tags will be parsed and replaced automatically:
-    - `{upload}`: will be replaced with the output of the `actionUpload` template.
-    - `{delete}`: will be replaced with the output of the `actionDelete` template.
-- `actionDelete`: the template for the file delete action button within the thumbnail `footer`. The following tags will be parsed and replaced automatically:
-    - `{removeClass}`: the css class for the remove button. Will be replaced with the `removeClass` set within `fileActionSettings`.
-    - `{removeIcon}`: the icon for the remove button. Will be replaced with the `removeIcon` set within `fileActionSettings`.
-    - `{removeTitle}`: the title to display on hover for the remove button. Will be replaced with the `removeTitle` set within `fileActionSettings`.
-    - `{dataUrl}`: the URL for deleting the file thumbnail for `initialPreview` content only. Will be replaced with the `url` set within `initialPreviewConfig`.
-    - `{dataKey}`: the key (additional data) that will be passed to the URL above via POST to the AJAX call. Will be replaced with the `key` set within `initialPreviewConfig`.
-- `actionUpload`: the template for the file upload action button within the thumbnail `footer`.
-    - `{uploadClass}`: the css class for the upload button. Will be replaced with the `uploadClass` set within `fileActionSettings`.
-    - `{uploadIcon}`: the icon for the upload button. Will be replaced with the `uploadIcon` set within `fileActionSettings`.
-    - `{uploadTitle}`: the title to display on hover for the upload button. Will be replaced with the `uploadTitle` set within `fileActionSettings`.
-
-The `main1` and `main2` templates would automatically parse the following tags for replacement:
-
-- `{class}`: the CSS class as set in the `mainClass` property.
-- `{preview}`: the content parsed by the `previewTemplate` and will be displayed only if `showPreview` is `true`.
-- `{caption}`: the content parsed by the `captionTemplate` and will be displayed only if `showCaption` is `true`.
-- `{remove}`: the file remove/clear button and will be displayed only if `showRemove` is `true`.
-- `{upload}`: the file upload button and will be displayed only if `showUpload` is `true`.
-- `{cancel}`: the file upload cancel button that will be displayed when AJAX upload is in process to abort the AJAX upload.
-- `{browse}`: the main file browse button to select your files for input.
-
-The `preview` and `caption` templates can understand the following special tags which will be replaced:
-
-- `{class}`: the CSS class as set in the `mainClass`, `captionClass` or `previewClass` properties.
-
-Similarly, the `progress` layout template can understand the following special tags which will be replaced:
-
-- `{class}`: the CSS class as set in the `progressClass` or `progressCompleteClass` properties.
-
-The `layoutTemplates` if not set will default to:
-
-```js
-{
-    main1: '{preview}\n' +
-        '<div class="kv-upload-progress hide"></div>\n' +
-        '<div class="input-group {class}">\n' +
-        '   {caption}\n' +
-        '   <div class="input-group-btn">\n' +
-        '       {remove}\n' +
-        '       {cancel}\n' +
-        '       {upload}\n' +
-        '       {browse}\n' +
-        '   </div>\n' +
-        '</div>',
-    main2: '{preview}\n<div class="kv-upload-progress hide"></div>\n{remove}\n{cancel}\n{upload}\n{browse}\n',
-    preview: '<div class="file-preview {class}">\n' +
-        '    <div class="close fileinput-remove">&times;</div>\n' +
-        '    <div class="{dropClass}">\n' +
-        '    <div class="file-preview-thumbnails">\n' +
-        '    </div>\n' +
-        '    <div class="clearfix"></div>' +
-        '    <div class="file-preview-status text-center text-success"></div>\n' +
-        '    <div class="kv-fileinput-error"></div>\n' +
-        '    </div>\n' +
-        '</div>',
-    icon: '<span class="glyphicon glyphicon-file kv-caption-icon"></span>',
-    caption: '<div tabindex="-1" class="form-control file-caption {class}">\n' +
-        '   <span class="file-caption-ellipsis">&hellip;</span>\n' +
-        '   <div class="file-caption-name"></div>\n' +
-        '</div>',
-    modal: '<div id="{id}" class="modal fade">\n' +
-        '  <div class="modal-dialog modal-lg">\n' +
-        '    <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' +
-        '      </div>\n' +
-        '      <div class="modal-body">\n' +
-        '        <textarea class="form-control" style="font-family:Monaco,Consolas,monospace; height: {height}px;" readonly>{body}</textarea>\n' +
-        '      </div>\n' +
-        '    </div>\n' +
-        '  </div>\n' +
-        '</div>',
-    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' +
-        '     </div>\n' +
-        '</div>',
-    footer: '<div class="file-thumbnail-footer">\n' +
-        '    <div class="file-caption-name" style="width:{width}">{caption}</div>\n' +
-        '    {actions}\n' +
-        '</div>',
-    actions: '<div class="file-actions">\n' +
-        '    <div class="file-footer-buttons">\n' +
-        '        {upload}{delete}{other}' +
-        '    </div>\n' +
-        '    <div class="file-upload-indicator" tabindex="-1" title="{indicatorTitle}">{indicator}</div>\n' +
-        '    <div class="clearfix"></div>\n' +
-        '</div>',
-    actionDelete: '<button type="button" class="kv-file-remove {removeClass}" title="{removeTitle}"{dataUrl}{dataKey}>{removeIcon}</button>\n',
-    actionUpload: '<button type="button" class="kv-file-upload {uploadClass}" title="{uploadTitle}">{uploadIcon}</button>\n'
-};
-```
-
-### previewTemplates
-
-_object_ the templates configuration for rendering each preview file type. The following file types are recognized:
-
-- `image`: the preview template for image files.
-- `text`: the  preview template for text files.
-- `html`: the preview template for html files.
-- `video`: the preview template for video files (supported by HTML 5 video tag).
-- `audio`: the preview template for audio files (supported by HTML 5 audio tag).
-- `flash`: the preview template for flash files (supported currently on webkit browsers).
-- `object`: the preview template for all other files - by default treated as object. To disable this behavior, configure the `allowedPreviewTypes` property.
-- `generic`: this template is used ONLY for rendering the `initialPreview` markup content passed directly as a raw format. 
-
-The following tags will be parsed and replaced in each of the templates:
-
-- `{previewId}`: will be replaced with the generated identifier for the preview frame container.
-- `{data}`: will be replaced with the data source for each preview type.
-- `{width}`: will be replaced with the width for the file type as set in `previewSettings`.
-- `{height}`: will be replaced with the height for the file type as set in `previewSettings`.
-- `{caption}`: will be replaced with the file name.
-- `{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.
-
-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. 
-
-The `previewTemplates` if not set will default to:
-
-```js
-{
-    generic: '<div class="file-preview-frame" id="{previewId}" data-fileindex="{fileindex}">\n' +
-        '   {content}\n' +
-        '   {footer}\n' +
-        '</div>\n',
-    html: '<div class="file-preview-frame" id="{previewId}" data-fileindex="{fileindex}">\n' +
-        '    <object data="{data}" type="{type}" width="{width}" height="{height}">\n' +
-        '       ' + DEFAULT_PREVIEW + '\n' +
-        '    </object>\n' + 
-        '   {footer}\n' +
-        '</div>',
-    image: '<div class="file-preview-frame" id="{previewId}" data-fileindex="{fileindex}">\n' +
-        '   <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' + 
-        '   {footer}\n' +
-        '</div>\n',
-    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' +
-        '       ' + DEFAULT_PREVIEW + '\n' +
-        '   </video>\n' + 
-        '   {footer}\n' +
-        '</div>\n',
-    audio: '<div class="file-preview-frame" id="{previewId}" data-fileindex="{fileindex}" title="{caption}" ' + STYLE_SETTING + '>\n' +
-        '   <audio controls>\n' +
-        '       <source src="{data}" type="{type}">\n' +
-        '       ' + DEFAULT_PREVIEW + '\n' +
-        '   </audio>\n' + 
-        '   {footer}\n' +
-        '</div>\n',
-    flash: '<div class="file-preview-frame" id="{previewId}" data-fileindex="{fileindex}" title="{caption}" ' + STYLE_SETTING + '>\n' +
-        '   <object type="application/x-shockwave-flash" width="{width}" height="{height}" data="{data}">\n' +
-        OBJECT_PARAMS + '       ' + DEFAULT_PREVIEW + '\n' +
-        '   </object>\n' + 
-        '   {footer}\n' +
-        '</div>\n',
-    object: '<div class="file-preview-frame" id="{previewId}" data-fileindex="{fileindex}" title="{caption}" ' + STYLE_SETTING + '>\n' +
-        '    <object data="{data}" type="{type}" width="{width}" height="{height}">\n' +
-        '      <param name="movie" value="{caption}" />\n' +
-        OBJECT_PARAMS + '           ' + DEFAULT_PREVIEW + '\n' +
-        '   </object>\n' + 
-        '   {footer}\n' +
-        '</div>',
-    other: '<div class="file-preview-frame{frameClass}" id="{previewId}" data-fileindex="{fileindex}" title="{caption}" ' + STYLE_SETTING + '>\n' +
-        '   ' + DEFAULT_PREVIEW + '\n' +
-        '   {footer}\n' +
-        '</div>',
-}
-```
-
-The values of the constants used in the above templates are as follows:
-
-```js
-STYLE_SETTING = 'style="width:{width};height:{height};"',
-OBJECT_PARAMS = '      <param name="controller" value="true" />\n' +
-    '      <param name="allowFullScreen" value="true" />\n' +
-    '      <param name="allowScriptAccess" value="always" />\n' +
-    '      <param name="autoPlay" value="false" />\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>'
-```
-
-### 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 
-invalid file type is found, then a validation error message as set in `msgInvalidFileType` will be raised. The following types as set in `fileTypeSettings` 
-are available for setup. 
-
-```js
-['image', 'html', 'text', 'video', 'audio', 'flash', 'object']
-```
-
-### allowedFileExtensions
-
-_array_ the list of allowed file extensions for upload. This by default is set to null which means the plugin supports all file extensions for upload. If an 
-invalid file extension is found, then a validation error message as set in `msgInvalidFileExtension` will be raised. An example of setting this could be:
-
-```js
-['jpg', 'gif', 'png', 'txt']
-```
-
-> NOTE: You need to be careful in case you are setting both `allowedFileTypes` and `allowedFileExtensions`. In this case, the `allowedFileTypes` property 
-is validated first and generally precedes the `allowedFileExtensions` setting (and the latter validation maybe skipped).
-
-### allowedPreviewTypes
-
-_array_ the list of allowed preview types for your widget. This by default supports all file types for preview. The plugin by default treats each
-file as an object if it does not match any of the previous types. To disable this behavior, you can remove `object` from the list of `allowedPreviewTypes`
-OR fine tune it through `allowedPreviewMimeTypes`.
-
-This is by default setup as following:
-```js
-['image', 'html', 'text', 'video', 'audio', 'flash', 'object']
-```
-
-### allowedPreviewMimeTypes
-
-_array_ the list of allowed mime types for preview. This is set to null by default which means all possible mime types are allowed. This setting works in combination with `allowedPreviewTypes` to filter only the needed file types allowed for preview. You can check this [list of allowed mime types](http://www.sitepoint.com/web-foundations/mime-types-complete-list/) to add to this list if needed.
-
-### customLayoutTags
-
-_object_ the list of additional custom tags that will be replaced in the **layout** templates. This should be an associative array object of `key: value` pairs, where:
-
-- `key`: _string_, is the tag to be replaced and as a standard is recommended to be enclosed between braces.
-- `value`: _string|function_, is the value that will replace the tag key above. This can be setup either as a string or callback function.
-
-For example:
-
-```js
-// example 1 - tags with value set as string
-customLayoutTags: {
-    '{tagA}': '<span class="label label-default">Tag A</span>',
-    '{tagB}': 'Tag B',
-}
-
-// example 2 - tags with value set as callback
-customLayoutTags: {
-    '{tagC}': function() {
-        return $("#element-id").val();
-    }
-}
-```
-
-### customPreviewTags
-
-_object_ the list of additional custom tags that will be replaced in the **preview** templates. This should be an associative array object of `key: value` pairs, where:
-
-- `key`: _string_, is the tag to be replaced and as a standard is recommended to be enclosed between braces.
-- `value`: _string|function_, is the value that will replace the tag key above. This can be setup either as a string or callback function.
-
-For example:
-
-```js
-// example 1 - tags with value set as string
-customPreviewTags: {
-    '{tagA}': '<span class="label label-default">Tag A</span>',
-    '{tagB}': 'Tag B',
-}
-
-// example 2 - tags with value set as callback
-customPreviewTags: {
-    '{tagC}': function() {
-        return $("#element-id").val();
-    }
-}
-```
-### previewSettings
-
-_object_ the format settings (width and height) for rendering each preview file type. This is by default setup as following:
-
-```js
-{
-    image: {width: "auto", height: "160px"},
-    html: {width: "213px", height: "160px"},
-    text: {width: "160px", height: "160px"},
-    video: {width: "213px", height: "160px"},
-    audio: {width: "213px", height: "80px"},
-    flash: {width: "213px", height: "160px"},
-    object: {width: "160px", height: "160px"},
-    other: {width: "160px", height: "160px"}
-}
-```
-
-### fileTypeSettings
-
-_object_ the settings to validate and identify each file type when a file is selected for upload. This is a list of callbacks, which accepts the file mime type and file name as a parameter.
-This is by default setup as following:
-
-```js
-// vType: is the file mime type
-// vName: is the file name
-{
-	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;
-	},
-}
-```
-
-### 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>`.
-
-### 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;`.
-
-### browseClass
-_string_ the CSS class for the file picker/browse button. Defaults to `btn btn-primary`.
-
-### removeLabel
-_string_ the label to display for the file remove button. Defaults to `Remove`.
-
-### removeIcon
-_string_ the icon to display before the label for the file picker/remove button. Defaults to `<i class="glyphicon glyphicon-trash"></i> &nbsp;`.
-
-### removeClass
-_string_ the CSS class for the file remove button. Defaults to `btn btn-default`.
-
-### removeTitle
-_string_ the title to display on hover for the file remove button. Defaults to `Clear selected files`.
-
-### cancelLabel
-_string_ the label to display for the file cancel button. Defaults to `Cancel`.
-
-### cancelIcon
-_string_ the icon to display before the label for the file picker/remove button. Defaults to `<i class="glyphicon glyphicon-ban-circle"></i> &nbsp;`.
-
-### cancelClass
-_string_ the CSS class for the file cancel button. Defaults to `btn btn-default`.
-
-### cancelTitle
-_string_ the title to display on hover for the file cancel button. Defaults to `Abort ongoing upload`.
-
-### uploadLabel
-_string_ the label to display for the file upload button. Defaults to `Upload`.
-
-### uploadIcon
-_string_ the icon to display before the label for the file upload button. Defaults to `<i class="glyphicon glyphicon-upload"></i> &nbsp;`.
-
-### uploadClass
-_string_ the CSS class for the file upload button. Defaults to `btn btn-default`.
-
-### uploadTitle
-_string_ the title to display on hover for the file remove button. Defaults to `Upload selected files`.
-
-### 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. NOTE: This is MANDATORY if you want to use advanced features like drag & drop, append/remove files, selectively upload files via ajax etc.
-
-### uploadAsync
-_bool_ whether the batch upload of multiple files will be asynchronous/in parallel. Defaults to `true`.
-
-### uploadExtraData
-_object | function_ the extra data that will be passed as data to the url/AJAX server call via POST. This can be setup either as an object (associative array of keys and values) or as a function callback. As an object, it can be set for example as:
-
-```js
- {id: 100, value: '100 Details'}
-```
-
-As a function callback, the `uploadExtraData` can be setup as shown below. Note that for uploading individual file via thumbnail, the callback can also receive the thumbnail `previewId` and `index` as parameters. These are described below:
-
-- `previewId`: the identifier for the preview file container (only available when uploading each thumbnail file)
-- `index`: the zero-based sequential index of the loaded file in the preview list (only available when uploading each thumbnail file)
-
-```js
-// previewId and index is only available for individual file upload via the thumbnail
-function (previewId, index) {
-    var obj = {};
-    $('.your-form-class').find('input').each(function() {
-        var id = $(this).attr('id'), val = $(this).val();
-        obj[id] = val;
-    });
-    return obj;
-}
-```
-
-### maxImageWidth
-_int_ the maximum allowed image width in `px` if you are uploading image files. Defaults to `null` which means no limit on image width.
-
-### maxImageHeight
-_int_ the maximum allowed image height in `px` if you are uploading image files. Defaults to `null` which means no limit on image height.
-
-### minImageWidth
-_int_ the minimum allowed image width in `px` if you are uploading image files. Defaults to `null` which means no limit on image width.
-
-### minImageHeight
-_int_ the minimum allowed image height in `px` if you are uploading image files. Defaults to `null` which means no limit on image height.
-
-### maxFileSize
-_float_ the maximum file size for upload in KB.  If set to `0`, it means size allowed is unlimited. Defaults to `0`.
-
-### minFileCount
-_int_ the minimum number of files allowed for each multiple upload. If set to `0`, it means number of files are optional. Defaults to `0`.
-
-### maxFileCount
-_int_ the maximum number of files allowed for each multiple upload. If set to `0`, it means number of files allowed is unlimited. Defaults to `0`.
-
-### 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.
-
-### msgFilesTooLess
-_string_ the message to be displayed when the file count is less than the minimum count as set in `minFileCount`. Defaults to:
-
-```
-You must select at least <b>{n}</b> {files} to upload. Please retry your upload!
-```
-
-where:
-
-- `{n}`: will be replaced by the allowed minimum files as set in `minFileCount`
-- `{files}`: will be replaced with `fileSingle` or `filePlural` properties in locale file depending on the `minFileCount`.
-
-### msgFilesTooMany
-_string_ the message to be displayed when the file count exceeds maximum count as set in `maxFileCount`. Defaults to:
-
-```
-Number of files selected for upload <b>({n})</b> exceeds maximum allowed limit of <b>{m}</b>. Please retry your upload!
-```
-
-where:
-
-- `{n}`: will be replaced by number of files selected for upload
-- `{m}`: will be replaced by the allowed maximum files as set in `maxFileCount`
-
-### msgFileNotFound
-_string_ the exception message to be displayed when the file selected is not found by the FileReader. Defaults to:
-
-```
-File "{name}" not found!
-```
-where:
-
-- `{name}`: will be replaced by the file name being uploaded
-
-### msgFileSecured
-_string_ the exception message to be displayed when the file selected is not allowed to be accessed due to a security exception. Defaults to:
-
-```
-Security restrictions prevent reading the file "{name}".
-```
-where:
-
-- `{name}`: will be replaced by the file name being uploaded
-
-### msgFileNotReadable
-_string_ the exception message to be displayed when the file selected is not readable by the FileReader API. Defaults to:
-
-```
-File "{name}" is not readable.
-```
-where:
-
-- `{name}`: will be replaced by the file name being uploaded
-
-### msgFilePreviewAborted
-_string_ the exception message to be displayed when the file preview upload is aborted. Defaults to:
-
-```
-File preview aborted for "{name}".
-```
-where:
-
-- `{name}`: will be replaced by the file name being uploaded
-
-### msgFilePreviewError
-_string_ the exception message to be displayed for any other error when previewing the file. Defaults to:
-
-```
-An error occurred while reading the file "{name}".
-```
-where:
-
-- `{name}`: will be replaced by the file name being uploaded
-
-### msgInvalidFileType
-_string_ the message to be displayed when the file type is not in one of the file types set in `allowedFileTypes`. Defaults to:
-
-```
-Invalid type for file "{name}". Only "{types}" files are supported.
-```
-where:
-
-- `{name}`: will be replaced by the file name being uploaded
-- `{types}`: will be replaced by the comma separated list of types defined in `allowedFileTypes`.
-
-### msgInvalidFileExtension
-_string_ the message to be displayed when the file type is not in one of the file extensions set in `allowedFileExtensions`. Defaults to:
-
-```
-Invalid extension for file "{name}". Only "{extensions}" files are supported.
-```
-where:
-
-- `{name}`: will be replaced by the file name being uploaded
-- `{extensions}`: will be replaced by the comma separated list of extensions defined in `allowedFileExtensions`.
-
-### msgValidationError
-_string_ the exception message to be displayed within the caption container (instead of `msgFilesSelected`), 
-when a validation error is encountered. Defaults to `File Upload Error`.
-
-### msgValidationErrorClass
-_string_ the css class for the validation error message displayed in the caption container. Defaults to `text-danger`.
-
-### msgValidationErrorIcon
-_string_ the icon to be displayed before the validation error in the caption container. Defaults to `<i class="glyphicon glyphicon-exclamation-sign"></i> `.
-
-### 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  file {index} of {files} &hellip;```
-
-The following special variables will be replaced:
-
-- `{index}`: the sequence number of the current file being loaded.
-- `{files}`: the total number of files selected for upload.
-
-### msgProgress
-_string_ the progress message displayed as each file is loaded for preview. Defaults to:
-
-```Loading file {index} of {files} - {name} - {percent}% completed.```
-
-The following variables will be replaced:
-
-- `{index}`: the sequence number of the current file being loaded.
-- `{files}`: the total number of files selected for upload.
-- `{percent}`: the percentage of file read and loaded.
-- `{name}`: the name of the current file being loaded.
-
-### msgSelected
-_string_ the progress message displayed in caption window when multiple (more than one) files are selected. Defaults to `{n} files selected`. The following variables will be replaced:
-
-- `{n}`: the number of files selected.
-
-### msgFoldersNotAllowed
-_string_ the message displayed when a folder has been dragged to the drop zone. Defaults to `Drag & drop files only! {n} folder(s) dropped were skipped.`. The following variables will be replaced The following variables will be replaced:
-
-- `{n}`: the number of folders dropped.
-
-### msgImageWidthSmall
-_string_ the exception message to be displayed when the file selected for preview is an image and its width is less than the `minImageWidth` setting. Defaults to:
-
-```
-Width of image file "{name}" must be at least {size} px.
-```
-where:
-
-- `{name}`: will be replaced by the file name being uploaded
-- `{size}`: will be replaced by the `minImageWidth` setting.
-
-### msgImageHeightSmall
-_string_ the exception message to be displayed when the file selected for preview is an image and its height is less than the `minImageHeight` setting. Defaults to:
-
-```
-Width of image file "{name}" must be at least {size} px.
-```
-where:
-
-- `{name}`: will be replaced by the file name being uploaded
-- `{size}`: will be replaced by the `minImageHeight` setting.
-
-### msgImageWidthLarge
-_string_ the exception message to be displayed when the file selected for preview is an image and its width exceeds the `maxImageWidth` setting. Defaults to:
-
-```
-Width of image file "{name}" cannot exceed {size} px.
-```
-where:
-
-- `{name}`: will be replaced by the file name being uploaded
-- `{size}`: will be replaced by the `maxImageWidth` setting.
-
-### msgImageHeightLarge
-_string_ the exception message to be displayed when the file selected for preview is an image and its height exceeds the `maxImageHeight` setting. Defaults to:
-
-```
-Height of image file "{name}" cannot exceed {size} px.
-```
-where:
-
-- `{name}`: will be replaced by the file name being uploaded
-- `{size}`: will be replaced by the `maxImageHeight` setting.
-
-### progressClass
-_string_ the upload progress bar CSS class to be applied when AJAX upload is in process (applicable only for ajax uploads). Defaults to `progress-bar progress-bar-success progress-bar-striped active`. 
-
-### progressCompleteClass
-_string_ the upload progress bar CSS class to be applied when AJAX upload is complete. Defaults to `progress-bar progress-bar-success`. 
-
-### previewFileType
-_string_ the type of files that are to be displayed in the preview window. Defaults to `image`. Can be one of the following:
-
-- `image`: Only `image` type files will be shown in preview.
-- `text`:  Only `text` type files will be shown in preview.
-- `any`: Both `image` and `text` files content will be shown in preview.
-
-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.
-
-### 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.
-
-### elCaptionContainer
-_string_ the identifier for the container element containing the caption (e.g. `'#id'`). If not set, will default to the container with CSS class `file-caption` inside the main plugin container.
-
-### elCaptionText
-_string_ the identifier for the container element containing the caption text (e.g. `'#id'`). If not set, will default to the container with CSS class `file-caption-name` inside the main plugin container.
-
-### elPreviewContainer
-_string_ the identifier for the container element containing the preview (e.g. `'#id'`). If not set, will default to the container with CSS class `file-preview` inside the main plugin container.
-
-### elPreviewImage
-_string_ the identifier for the element containing the preview image thumbnails (e.g. `'#id'`). If not set, will default to the container with CSS class `file-preview-thumbnails` inside the main plugin container.
-
-### elPreviewStatus
-_string_ the identifier for the element containing the preview progress status (e.g. `'#id'`). If not set, will default to the container with CSS class `file-preview-status` inside the main plugin container.
-
-### slugCallback
-_function_ a callback to convert the filename as a slug string eliminating special characters. If not set, it will use the plugin's own internal `slugDefault` method. This callback function includes the filename as parameter and must return a converted filename string.
-
-**Example:**
-
-```js
-slugCallback: function(filename) {
-    return filename.replace('(', '_');
-}
-```
-
-### dropZoneEnabled
-_bool_ whether to enable a drag and drop zone for dragging and dropping files to. This is available only for ajax based uploads. Defaults to `true`. 
-
-### dropZoneTitle
-_string_ title to be displayed in the drag and drop zone. This is available only for ajax based uploads. Defaults to `Drag & drop files here &hellip;`. 
-
-### dropZoneTitleClass
-_string_ CSS class for the drag & drop zone title. Defaults to `file-drop-zone-title`. 
-
-### fileActionSettings
-_object_ configuration for setting up file actions for newly selected file thumbnails in the preview window. The following properties can be set:
-    - `removeIcon`: _string_, icon for remove button to be displayed in each file thumbnail.
-    - `removeClass`: _string_, CSS class for the remove button in each file thumbnail.
-    - `removeTitle`: _string_, title for remove button in each file thumbnail.
-    - `uploadIcon`: _string_, icon for upload button to be displayed in each file thumbnail.
-    - `uploadClass`: _string_, CSS class for the remove button in each file thumbnail.
-    - `uploadTitle`: _string_, title for remove button in each file thumbnail.
-    - `indicatorNew`: _string_, an indicator (HTML markup) for new pending upload displayed in each file thumbnail.
-    - `indicatorSuccess`: _string_, an indicator (HTML markup) for successful upload displayed in each file thumbnail.
-    - `indicatorError`: _string_, an indicator (HTML markup) for error in upload displayed in each file thumbnail.
-    - `indicatorLoading`: _string_, an indicator (HTML markup) for ongoing upload displayed in each file thumbnail.
-    - `indicatorNewTitle`: _string_, title to display on hover of indicator for new pending upload in each file thumbnail.
-    - `indicatorSuccessTitle`: _string_, title to display on hover of indicator for successful in each file thumbnail.
-    - `indicatorErrorTitle`: _string_, title to display on hover of indicator for error in upload in each file thumbnail.
-    - `indicatorLoadingTitle`: _string_, title to display on hover of indicator for ongoing upload in each file thumbnail.
-
-Defaults to the following setting:
-```js
-{
-    removeIcon: '<i class="glyphicon glyphicon-trash text-danger"></i>',
-    removeClass: 'btn btn-xs btn-default',
-    removeTitle: 'Remove file',
-    uploadIcon: '<i class="glyphicon glyphicon-upload text-info"></i>',
-    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>',
-    indicatorError: '<i class="glyphicon glyphicon-exclamation-sign text-danger"></i>',
-    indicatorLoading: '<i class="glyphicon glyphicon-hand-up text-muted"></i>',
-    indicatorNewTitle: 'Not uploaded yet',
-    indicatorSuccessTitle: 'Uploaded',
-    indicatorErrorTitle: 'Upload Error',
-    indicatorLoadingTitle: 'Uploading ...'
-}
-```
-
-### otherActionButtons
-_string_ markup for additional action buttons to display within the initial preview thumbnails (for example displaying an image edit button). The following tags can be used in the markup and will be automatically replaced:
-
-- `{dataKey}`: Will be replaced with the `key` set within `initialPreviewConfig`.    
-
-### textEncoding
-_string_ the encoding to be used while reading a text file. Applicable only for previewing text files. Defaults to `UTF-8`. 
-
-### ajaxSettings
-_object_ additional ajax settings to pass to the plugin before submitting the ajax request. Applicable only for ajax uploads. This can be useful to pass additional tokens to headers or one can use it for setting other ajax options for advanced cases. Refer the [jQuery ajax documentation](http://api.jquery.com/jQuery.ajax/) for the various settings you can configure.
-
-### ajaxDeleteSettings
-_object_ additional ajax settings to pass to the plugin before submitting the delete ajax request in each initial preview thumbnail. Applicable only for ajax deletions. This can be useful to pass additional tokens to headers or one can use it for setting other ajax options for advanced cases. Refer the [jQuery ajax documentation](http://api.jquery.com/jQuery.ajax/) for the various settings you can configure.
-
-### showAjaxErrorDetails
-_boolean_ whether to show details of the error stack from the server log when an error is encountered via ajax response. Defaults to `true`.
-
-## Plugin Events
-
-The plugin supports the following events. 
-
-### File Events
-
-#### fileclear
-This event is triggered when the file input the remove button is pressed for clearing the file preview.
-
-**Example:**
-```js
-$('#input-id').on('fileclear', function(event) {
-    console.log("fileclear");
-});
-```
-
-#### filecleared
-This event is triggered after the files in the preview are cleared.
-
-**Example:**
-```js
-$('#input-id').on('filecleared', function(event) {
-    console.log("filecleared");
-});
-```
-
-#### fileloaded
-This event is triggered after a file is loaded in the preview. Additional parameters available 
-are: 
-
-- `file`: the file object instance
-- `previewId`: the identifier for the preview file container
-- `index`: the zero-based sequential index of the loaded file in the preview list
-- `reader`: the FileReader instance if available
-
-**Example:**
-```js
-$('#input-id').on('fileloaded', function(event, file, previewId, index, reader) {
-    console.log("fileloaded");
-});
-```
-
-#### filereset
-This event is triggered when the file input is reset to initial value.
-
-**Example:**
-```js
-$('#input-id').on('filereset', function(event) {
-    console.log("filereset");
-});
-```
-
-#### fileimageloaded
-This event is triggered when each file image is fully loaded in the preview window. This is only applicable for image file previews and if `showPreview` is set to true. Additional parameters available are: 
-
-- `previewId`: the identifier for the preview file container
-
-**Example:**
-```js
-$('#input-id').on('fileimageloaded', function(event, previewId) {
-    console.log("fileimageloaded");
-});
-```
-#### filebrowse
-This event is triggered when the file browse button is clicked to open the file selection dialog.
-
-**Example:**
-```js
-$('#input-id').on('filebrowse', function(event) {
-    console.log("File browse triggered.");
-});
-```
-
-#### filebatchselected
-This event is triggered after a batch of files are selected and displayed in the preview.
-Additional parameters available are: 
-
-- `files`: the file stack array (or empty object if not available).
-
-```js
-$('#input-id').on('filebatchselected', function(event, files) {
-    console.log('File batch selected triggered');
-});
-```
-
-#### fileselectnone
-This event is triggered when no files are selected by the user for a repeat selection scenario (i.e. on a file input that already contains previously selected files). This event is better applicable for browsers like Google Chrome, which clear the file input when the file selection dialog is cancelled. For other browsers, this event is typically triggered only when one resets the form or clears file input (using the remove button).
-
-**Example:**
-```js
-$('#input-id').on('fileselectnone', function(event) {
-    console.log("Huh! No files were selected.");
-});
-```
-
-#### filelock
-This event is triggered when the upload process is launched by clicking a upload button, and the entire widget is locked (disabled) until upload is getting processed. Only the `Cancel` button will be enabled when the file input is locked. Additional parameters available are: 
-
-- `filestack`: the array of selected file objects.
-- `extraData`: the `uploadExtraData` settings for the plugin (will return an empty object if not set).
-
-```js
-$('#input-id').on('filelock', function(event, filestack, extraData) {
-    var fstack = filestack.filter(function(n){ return n != undefined });
-    console.log('Files selected - ' + fstack.length);
-});
-```
-
-#### fileunlock
-This event is triggered when the upload process is completed (successfully or with error). The entire widget is unlocked (enabled) and reverts to initial state. Additional parameters available are: 
-
-- `filestack`: the array of selected file objects.
-- `extraData`: the `uploadExtraData` settings for the plugin (will return an empty object if not set).
-
-```js
-$('#input-id').on('fileunlock', function(event, filestack, extraData) {
-    var fstack = filestack.filter(function(n){ return n != undefined });
-    console.log('Files selected - ' + fstack.length);
-});
-```
-
-#### filepredelete
-This event is triggered before deletion of each thumbnail file in the `initialPreview` content set. Additional parameters available are: 
-
-- `key`: the key passed within `initialPreviewConfig` for the selected file for delete.
-- `jqXHR`: the `jQuery XMLHttpRequest` object used for this transaction (if available).
-- `data`: the output of `deleteExtraData` object.
-
-```js
-$('#input-id').on('filepredelete', function(event, key, jqXHR) {
-    console.log('Key = ' + key);
-});
-```
-
-#### filedeleted
-This event is triggered after deletion of each thumbnail file in the `initialPreview` content set. Additional parameters available are: 
-
-- `key`: the key passed within `initialPreviewConfig` for the selected file that will be passed as POST data to the `url`.
-- `jqXHR`: the `jQuery XMLHttpRequest` object used for this transaction (if available).
-- `data`: the output of `deleteExtraData` object.
-
-```js
-$('#input-id').on('filedeleted', function(event, key) {
-    console.log('Key = ' + key);
-});
-```
-
-```js
-$('#input-id').on('fileunlock', function(event, filestack) {
-    var fstack = filestack.filter(function(n){ return n != undefined });
-    console.log('Files selected - ' + fstack.length);
-});
-```
-
-#### filepreajax
-This event is triggered before submission of the upload ajax request. You could use this event to manipulate the `uploadExtraData` before its submitted via ajax. The following additional parameters are also available specifically and only if the upload is triggered via each thumbnail upload button.
-
-- `previewId`: the identifier of the preview thumbnail container.
-- `index`: the zero-based index of the file in the preview container.
-
-```js
-$('#input-id').on('filepreajax', function(event, previewId, index) {
-    console.log('File pre ajax triggered');
-});
-```
-
-#### filepreupload
-This event is triggered before upload of each thumbnail file. This event is triggered after `filepreajax` and within the ajax `beforeSend`. Additional parameters available are: 
-
-- `data`: This is a data object (associative array) that sends the following information, whose keys are:
-    - `form`: the FormData object which is passed via XHR2 (or empty object if not available).
-    - `files`: the file stack array (or empty object if not available).
-    - `extra`: the `uploadExtraData` settings for the plugin (or empty object if not available).
-    - `response`: the data sent via ajax response (or empty object if not available).
-    - `reader`: the FileReader instance if available
-    - `jqXHR`: the `jQuery XMLHttpRequest` object used for this transaction (if available).
-- `previewId`: the identifier of the preview thumbnail container.
-- `index`: the zero-based index of the file in the preview container.
-
-```js
-$('#input-id').on('filepreupload', function(event, data, previewId, index, jqXHR) {
-    var form = data.form, files = data.files, extra = data.extra, 
-        response = data.response, reader = data.reader;
-    console.log('File pre upload triggered');
-});
-```
-
-#### fileuploaded
-This event is triggered after upload is completed for each thumbnail file. Note this event is also triggered for 
-asynchronous batch uploads after each file in the selection is uploaded via ajax. Additional parameters available are: 
-
-- `data`: This is a data object (associative array) that sends the following information, whose keys are:
-    - `form`: the FormData object which is passed via XHR2 (or empty object if not available).
-    - `files`: the file stack array (or empty object if not available).
-    - `extra`: the `uploadExtraData` settings for the plugin (or empty object if not available).
-    - `response`: the data sent via ajax response (or empty object if not available).
-    - `reader`: the FileReader instance if available
-    - `jqXHR`: the `jQuery XMLHttpRequest` object used for this transaction (if available).
-- `previewId`: the identifier of each file's parent thumbnail div element in the preview window.
-- `index`: the zero-based index of the file in the file stack.
-
-```js
-$('#input-id').on('fileuploaded', function(event, data, previewId, index) {
-    var form = data.form, files = data.files, extra = data.extra, 
-        response = data.response, reader = data.reader;
-    console.log('File uploaded triggered');
-});
-```
-
-#### filebatchpreupload
-This event is triggered before a batch upload (for both synchronous and asynchronous uploads) after the upload button is clicked. 
-Additional parameters available are: 
-
-- `data`: This is a data object (associative array) that sends the following information, whose keys are:
-    - `form`: the FormData object which is passed via XHR2 (or empty object if not available).
-    - `files`: the file stack array (or empty object if not available).
-    - `extra`: the `uploadExtraData` settings for the plugin (or empty object if not available).
-    - `response`: the data sent via ajax response (or empty object if not available).
-    - `reader`: the FileReader instance if available
-    - `jqXHR`: the `jQuery XMLHttpRequest` object used for this transaction (if available).
-
-```js
-$('#input-id').on('filebatchpreupload', function(event, data, jqXHR) {
-    var form = data.form, files = data.files, extra = data.extra, 
-        response = data.response, reader = data.reader;
-    console.log('File batch pre upload triggered');
-});
-```
-
-#### filebatchuploadsuccess
-This event is triggered after a successful synchronous batch upload (i.e. when `uploadAsync` is `false`). Additional parameters available are: 
-
-- `data`: This is a data object (associative array) that sends the following information, whose keys are:
-    - `form`: the FormData object which is passed via XHR2 (or empty object if not available).
-    - `files`: the file stack array (or empty object if not available).
-    - `extra`: the `uploadExtraData` settings for the plugin (or empty object if not available).
-    - `response`: the data sent via ajax response (or empty object if not available).
-    - `reader`: the FileReader instance if available
-
-```js
-$('#input-id').on('filebatchuploadsuccess', function(event, data) {
-    var form = data.form, files = data.files, extra = data.extra, 
-        response = data.response, reader = data.reader;
-    console.log('File batch upload success');
-});
-```
-
-
-#### filebatchuploadcomplete
-This event is triggered after completion of either the synchronous OR asynchronous ajax batch upload. Additional parameters available are: 
-
-- `files`: the file stack array (or empty object if not available).
-- `extra`: the `uploadExtraData` settings for the plugin (or empty object if not available).
-
-```js
-$('#input-id').on('filebatchuploadcomplete', function(event, files, extra) {
-    console.log('File batch upload complete');
-});
-```
-
-#### filesuccessremove
-This event is triggered after a successfully uploaded thumbnail is removed using the thumbnail delete button. This is usually applicable when you have **showUploadedThumbs** set to `true`. Additional parameters available are: 
-
-- `id`: the HTML ID attribute for the thumbnail container element.
-
-The event can return `false` to abort the thumbnail removal.
-
-```js
-$('#input-id').on('filesuccessremove', function(event, id) {
-    if (some_processing_function(id)) {
-       console.log('Uploaded thumbnail successfully removed');
-    } else {
-        return false; // abort the thumbnail removal
-    }
-});
-```
-#### filedisabled
-This event is triggered when the file input widget is disabled (prevents any modification) using the `disable` method.
-
-```js
-$('#input-id').on('filedisabled', function(event) {
-    console.log('File disabled.');
-});
-```
-
-#### fileenabled
-This event is triggered when the file input widget is enabled (allows modification) using the `enable` method.
-
-```js
-$('#input-id').on('fileenabled', function(event) {
-    console.log('File enabled.');
-});
-```
-
-### Error Events
-
-#### fileerror
-This event is triggered when a client validation error is encountered for an uploaded file. This allows access to an object `data` as a parameter.
-
-- `data`: object/associative array containing the following 
-    - `id`: the preview thumbnail identifier (or undefined if not available)
-    - `index`: the file index/preview thumbnail index (or undefined if not available)
-    - `file`: the file object (or undefined if not available)
-    - `reader`: the file reader instance (or undefined if not available)
-    - `files`: the file stack array (or empty object if not available).
-
-**Example:**
-```js
-$('#input-id').on('fileerror', function(event, data) {
-   console.log(data.id);
-   console.log(data.index);
-   console.log(data.file);
-   console.log(data.reader);
-   console.log(data.files);
-});
-```
-
-#### fileuploaderror
-This event is triggered when an upload or file input validation error is encountered primarily for ajax uploads (through the upload icon for each thumbnail or for every file uploaded when uploadAsync is `true`). Additional parameters available are: 
-
-- `data`: This is a data object (associative array) that sends the following information, whose keys are:
-    - `id`: the preview thumbnail identifier (or undefined if not available)
-    - `index`: the file index/preview thumbnail index (or undefined if not available).
-    - `form`: the FormData object which is passed via XHR2 (or empty object if not available).
-    - `files`: the file stack array (or empty object if not available).
-    - `extra`: the `uploadExtraData` settings for the plugin (or empty object if not available).
-    - `response`: the data sent via ajax response (or empty object if not available).
-    - `reader`: the FileReader instance if available
-    - `jqXHR`: the `jQuery XMLHttpRequest` object used for this transaction (if available).
-
-```js
-$('#input-id').on('fileuploaderror', function(event, data, previewId, index) {
-    var form = data.form, files = data.files, extra = data.extra, 
-        response = data.response, reader = data.reader;
-    console.log('File upload error');
-});
-```
-
-#### filebatchuploaderror
-This event is triggered when any error is faced in the synchronous batch upload (i.e. when `uploadAsync` is `false`). Additional parameters available are: 
-
-- `data`: This is a data object (associative array) that sends the following information, whose keys are:
-    - `form`: the FormData object which is passed via XHR2 (or empty object if not available).
-    - `files`: the file stack array (or empty object if not available).
-    - `extra`: the `uploadExtraData` settings for the plugin (or empty object if not available).
-    - `response`: the data sent via ajax response (or empty object if not available).
-    - `reader`: the FileReader instance if available
-    - `jqXHR`: the `jQuery XMLHttpRequest` object used for this transaction (if available).
-
-```js
-$('#input-id').on('filebatchuploaderror', function(event, data) {
-    var form = data.form, files = data.files, extra = data.extra, 
-        response = data.response, reader = data.reader;
-    console.log('File upload error');
-});
-```
-
-#### filedeleteerror
-This event is triggered when an error is faced in deletion of each thumbnail file in the `initialPreview` content set. Additional parameters available are: 
-
-- `data`: This is a data object (associative array) that sends the following information, whose keys are:
-    - `id`: the preview thumbnail identifier (or undefined if not available)
-    - `index`: the file index/preview thumbnail index (or undefined if not available).
-    - `response`: the data sent via ajax response (or empty object if not available).
-    - `extra`: the output of `deleteExtraData` object.
-    - `jqXHR`: the `jQuery XMLHttpRequest` object used for this transaction (if available).
-
-```js
-$('#input-id').on('filedeleteerror', function(event, data) {
-    console.log('File delete error');
-});
-```
-
-#### filefoldererror
-This event is triggered when a folder or multiple folders have been dragged & dropped to the file preview drop zone. Additional parameters available are: 
-
-- `folders`: The count of folders dropped.
-
-```js
-$('#input-id').on('filefoldererror', function(event, folders) {
-    console.log('File folder dropped error');
-});
-```
-
-#### filecustomerror
-This event is triggered manually by the user from one of the other events by returning an error object from the source event. Refer **Event Manipulation** section for details. Additional parameters available are: 
-
-- `data`: This is a data object (associative array) that sends the following information, whose keys are:
-    - `form`: the FormData object which is passed via XHR2 (or empty object if not available).
-    - `response`: the aborted data sent when returned when triggering the validation error from the source event. 
-    - `files`: the file stack array (or empty object if not available).
-    - `extra`: the `uploadExtraData` settings for the plugin (or empty object if not available).
-    - `reader`: the FileReader instance if available
-    - `jqXHR`: the `jQuery XMLHttpRequest` object used for this transaction (an empty object usually).
-
-```js
-$("#input").on('filecustomerror', function(event, params) {
-   console.log(params.id);
-   console.log(params.index);
-   console.log(params.data);
-});
-```
-
-### Event Manipulation
-With release v4.1.8, you can return data for most of the events and use it for advanced processing. This functionality is not applicable for the following events.
-
-- `fileclear`
-- `filecleared`
-- `filereset`
-- `fileerror`
-- `fileuploaderror`
-- `filebatchuploaderror`
-- `filedeleteerror`
-- `filefoldererror`
-- `filecustomerror`
-- `fileuploaded`
-- `filebatchuploadcomplete`
-- `filebatchuploadsuccess`
-
-For all the events other than ones mentioned above, you can set a custom validation error which will be triggered just before upload is initiated.
-
-This will enable you to add your additional custom validations to enhance the fileinput to be used for innumerous scenarios. It will allow an ability to return an associative object with any of the fileinput events (except the events above) e.g. `change`, `fileselect`, `filepreupload`, `filebatchpreupload` etc.
-
-The object can return the following keys:
-
-- `message`: _string_, the validation error message to be displayed before upload. If this is set the plugin will automatically abort the upload whenever called and display this as an error message. You can use this property for example to read a file and perform your own custom validation.
-- `data`: _object_, an optional associative array of additional data at abort, that you can pass for usage later. 
-
-**Example**
-
-- **STEP 1:** You can trigger an error to abort from `filepreupload`
-
-```js
-$('#input').on('filepreupload', function(event, data, previewId, index, jqXHR) {
-    // do your validation and return an error like below
-    if (customValidationFailed) {
-       return {
-           message: 'You are not allowed to do that', 
-           data: {key1: 'Key 1', detail1: 'Detail 1'}
-       };
-   }
-});
-```
-The above abort will be triggered at time of upload for (ajax uploads) OR at form submission (for non-ajax uploads).
-
-- **STEP 2:** Reading additional data at abort by trapping the `filecustomerror` event
-
-```js
-$('#input').on('filecustomerror', function(event, params) {
-   // params.abortData will contain the additional abort data passed
-   // params.abortMessage will contain the aborted error message passed
-});
-```
-
-As mentioned before, the above functionality of raising a `filecustomerror` is not supported in the following events:
-
-- `fileclear`
-- `filecleared`
-- `filereset`
-- `fileerror`
-- `fileuploaderror`
-- `filebatchuploaderror`
-- `filedeleteerror`
-- `filecustomerror`
-- `fileuploaded`
-- `filebatchuploadcomplete`
-- `filebatchuploadsuccess`
-
-### 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
-$('#input-id').fileinput('reset');
-```
-
-### destroy
-Destroys the file input.
-```js
-$('#input-id').fileinput('destroy');
-```
-
-### refresh
-Refreshes the file input plugin based on options provided. You can supply an array of plugin options as a parameter.
-```js
-// example 1 (disable at runtime)
-$('#input-id').attr('disabled', 'disabled');
-$('#input-id').fileinput('refresh');
-
-// example 2 (modify plugin options at runtime)
-$('#input-id').fileinput('refresh', {browseLabel: 'Select...', removeLabel: 'Delete'});
-```
-
-### clear
-Clear the file input and all files from preview.
-```js
-$('#input-id').fileinput('clear');
-```
-
-### upload
-Trigger ajax upload of the files that are selected. Applicable only if `uploadUrl` is set.
-
-```js
-$('#input-id').fileinput('upload');
-```
-
-### cancel
-Cancel an ongoing ajax upload of the files.
-
-```js
-$('#input-id').fileinput('cancel');
-```
-
-### lock
-Locks the file input by disabling all actions/buttons except a cancel button to abort ongoing AJAX requests (for ajax uploads only).
-
-```js
-$('#input-id').fileinput('lock');
-```
-
-### unlock
-Unlocks and enables the file input back again by reversing the outcome of the `lock` action.
-
-```js
-$('#input-id').fileinput('unlock');
-```
-
-## License
-
-**bootstrap-fileinput** is released under the BSD 3-Clause License. See the bundled `LICENSE.md` for details.
+bootstrap-fileinput
+====================
+
+[![Bower version](https://badge.fury.io/bo/bootstrap-fileinput.svg)](http://badge.fury.io/bo/bootstrap-fileinput)
+[![Latest Stable Version](https://poser.pugx.org/kartik-v/bootstrap-fileinput/v/stable)](https://packagist.org/packages/kartik-v/bootstrap-fileinput)
+[![License](https://poser.pugx.org/kartik-v/bootstrap-fileinput/license)](https://packagist.org/packages/kartik-v/bootstrap-fileinput)
+[![Packagist Downloads](https://poser.pugx.org/kartik-v/bootstrap-fileinput/downloads)](https://packagist.org/packages/kartik-v/bootstrap-fileinput)
+[![Monthly Downloads](https://poser.pugx.org/kartik-v/bootstrap-fileinput/d/monthly)](https://packagist.org/packages/kartik-v/bootstrap-fileinput)
+
+An enhanced HTML 5 file input for Bootstrap 3.x with file preview for various files, offers multiple selection, and more. The plugin allows you a simple way to setup an advanced file picker/upload control built to work specially with Bootstrap CSS3 styles. It enhances the file input functionality further, by offering support to preview a wide variety of files i.e. images, text, html, video, audio, flash, and objects. In addition, it includes AJAX based uploads, dragging &amp; dropping files, viewing upload progress, and selectively previewing, adding, or deleting files.
+![File Input Screenshot](https://lh3.googleusercontent.com/-3FiEmc_okc4/VBw_d2LBAJI/AAAAAAAAAL8/KbVj5X9Dus0/w596-h454-no/FileInput.jpg)
+
+This plugin was initially inspired by [this blog article](http://www.abeautifulsite.net/blog/2013/08/whipping-file-inputs-into-shape-with-bootstrap-3/) and [Jasny's File Input plugin](http://jasny.github.io/bootstrap/javascript/#fileinput). But the plugin has now matured with various additional features and enhancements to be a complete (yet simple) file management tool and solution for web developers. 
+
+> NOTE: The latest version of the plugin is v4.2.6 (in dev-master). Refer the [CHANGE LOG](https://github.com/kartik-v/bootstrap-fileinput/blob/master/CHANGE.md) for details. 
+
+## Features  
+
+### File Input Features
+
+1. The plugin will convert a simple HTML file input to an advanced file picker control. Will help fallback to a normal HTML file input for browsers not supporting JQuery or Javascript.
+2. The file input consists of the following three sections with options and templates to control the display:
+   - **_file caption section_**: to display a brief information of the file(s) selected
+   - **_file action buttons section_**: to browse, remove, and upload files.
+   - **_file preview section_**: to display the selected files on client for preview (supports preview of image, text, flash, and video file types). Other file types will be displayed as normal thumbnails.
+3. The plugin automatically converts an input with `type = file` to an advanced file picker input if you set its `class = file`. All options to the input can be passed as HTML5 `data` attributes.
+4. Ability to select and preview multiple files. Uses HTML 5 File reader API to read and preview files. Displays the progress of files being being loaded onto the preview zone, in case many files are chosen.
+5. Offers predefined templates and CSS classes which can be changed to style your file-input display as per your needs.
+6. With **v1.5.0**, you can now configure the plugin to show an **initial preview of images/files** with **initial caption** 
+   (more useful for record update scenarios). Refer the [`initialPreview`](https://github.com/kartik-v/bootstrap-fileinput/blob/master/README.md#initialpreview) 
+   and [`initialCaption`](https://github.com/kartik-v/bootstrap-fileinput/blob/master/README.md#initialcaption) properties in the plugin options
+   section for configuring this.
+7. Option to show/hide any or all of the following:
+   - caption section
+   - preview section
+   - upload button
+   - remove button
+8. Customise the location of the target container elements to display the entire plugin, the caption container, the caption text, the preview container, preview image, and preview status.
+9. For text file previews, autowrap the text to the thumbnail width, and show a wrap indicator link to display complete text on hover. You can customize the wrap indicator (which defaults to &hellip;).
+10. Customise the messages for preview, progress, and files selected.
+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`, `fileclear`, `filecleared`, `fileloaded`, and `fileerror`.
+13. Disabled and readonly file input support.
+14. Dynamically auto size the file captions for long file names exceeding container width. 
+15. Raise new `fileimageuploaded` event that fires after image is completely loaded on the preview container.
+16. Autosize preview images when they exceed the size of the preview container.
+17. Completely templatized and extensible to allow configuration of the file-input the way the developer wants.
+18. Preview intelligence based on various file preview types. The inbuilt file support types are categorized as `image`, `text`, `html`, `video`,  `audio`, `flash`, `object`, and `other`.
+19. `allowedPreviewTypes`: You can now configure which all file types are allowed to be shown as a preview. This defaults to `['image', 'html', 'text', 'video', 'audio', 'flash', 'object']`. Thus all file types are treated as an object to preview by default. For exampleTo preview only `image` and `video`, you can set this to `['image', 'video']`.
+20. `allowedPreviewMimeTypes`: In addition to `allowedPreviewTypes`, you can also control which all mime types can be displayed for preview. This defaults to null, meaning all mime types are supported.
+   >NOTE: With release 2.5.0 you can now control which file types or extensions are allowed for upload by setting `allowedFileTypes` and `allowedFileExtensions`.
+21. `layoutTemplates`: Allows you to configure all layout template settings within one property. The layout objects that can be configured are: `main1`, `main2`, `preview`, `caption`, and `modal`.
+22. `previewTemplates`: All preview templates for **each preview type** have been combined into one property, instead of separate templates for image, text etc. The keys are the formats as set in `allowedPreviewTypes` and values are the templates used for previewing. There are default prebuilt templates for each preview file type (`generic`, `image`, `text`, `html`, `video`,  `audio`, `flash`, `object`, and `other`). The `generic` template is used only for displaying `initialPreview` content using direct markup.
+23. `previewSettings`: Allows you to configure width and height for each preview image type. The plugin has default widths and heights predefined for each type i.e `image`, `text`, `html`, `video`,  `audio`, `flash`, and `object`.
+24. `fileTypeSettings`: Allows you to configure and identify each preview file type using a callback. The plugin has default callbacks predefined to identify each type i.e `image`, `text`, `html`, `video`,  `audio`, `flash`, and `object`.
+25. Replacing tags within templates has been enhanced. With this release it will automatically check for multiple occurrences of each tag to replace within a template string.
+26. Manipulate events and add your own custom validation messages easily by returning output to abort uploads in any of the other events.
+27. Support for translations and locales.
+
+### File Upload Features
+
+With release 4.0.0, the plugin now also includes inbuilt support for AJAX Uploads and selectively adding or deleting files. AJAX upload functionality are 
+built upon HTML5 FormData and XMLHttpRequest Level 2 standards. Most modern browsers do support this standard, but the plugin will automatically degrade to normal form based submission for unsupported browsers.
+
+1. Add functionality for AJAX based UPLOAD using HTML5 FormData (most modern browsers support it). Will degrade to normal Form Based File submission if this is not supported.
+2. To use AJAX Upload, one must set the `uploadUrl` property.
+3. Enhance plugin to now allow files to be added, appended, removed (based on FEEDBACK from many). Thus one can append files to preview.
+4. New DRAG & DROP zone available in preview to drag and drop files and append.
+5. Delete or upload files one by one OR in batch.
+6. If `showPreview` is set to false, or uploadUrl is not supported plugin will degrade to normal form based upload.
+7. Configurable indicators for file awaiting upload, file successfully uploaded, files errored in upload.
+8. Ability to add extra form data with ajax based uploads.
+9. Upload progress bar and individual thumbnail upload indicators.
+10. Ability to cancel and abort ongoing AJAX uploads.
+11. Build up initial preview content (e.g. gallery of saved images). You can set initial preview actions (prebuilt support for initial preview delete). Other custom action buttons can be set for initial preview thumbnails as well. 
+12. Ensure plugin is still lean in size and optimized for performance inspite of the above features by optimally utilizing HTML5 & jquery features only.
+13. Automatically refresh preview with content from server as soon as an ajax upload finishes.
+
+> NOTE: Drag and Drop zone functionality, selectively appending or deleting files, and upload indicator with progress are ONLY AVAILABLE if you use AJAX BASED uploads (by setting `uploadUrl`).
+
+## Demo
+
+View the [plugin documentation](http://plugins.krajee.com/file-input) and [plugin demos](http://plugins.krajee.com/file-input/demo) at Krajee JQuery plugins. 
+
+## Pre-requisites  
+
+1. [Bootstrap 3.x](http://getbootstrap.com/)
+2. Latest [JQuery](http://jquery.com/)
+3. Most modern browsers supporting HTML5 (inputs and FileReader API) including CSS3 & JQuery. For Internet Explorer, one must use IE versions 10 and above. IE9 and below will work as a normal file input, and will not support multiple file selection or the HTML 5 FileReader API.
+4. With release 4.0, AJAX uploads are supported. AJAX uploads require that the browser support HTML5 FormData and XHR2 (XMLHttpRequest 2). Most modern browsers support FormData and XHR2. The plugin will automatically degrade to normal form based submission for browsers not supporting AJAX uploads.
+
+## Installation
+
+### Using Bower
+You can use the `bower` package manager to install. Run:
+
+    bower install bootstrap-fileinput
+
+### Using Composer
+You can use the `composer` package manager to install. Either run:
+
+    $ php composer.phar require kartik-v/bootstrap-fileinput "@dev"
+
+or add:
+
+    "kartik-v/bootstrap-fileinput": "@dev"
+
+to your composer.json file
+
+### Manual Install
+
+You can also manually install the plugin easily to your project. Just download the source [ZIP](https://github.com/kartik-v/bootstrap-fileinput/zipball/master) or [TAR ball](https://github.com/kartik-v/bootstrap-fileinput/tarball/master) and extract the plugin assets (css and js folders) into your project.
+
+## Usage
+
+Step 1: Load the following assets in your header. 
+
+```html
+<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet">
+<link href="path/to/css/fileinput.min.css" media="all" rel="stylesheet" type="text/css" />
+<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
+<script src="path/to/js/fileinput.min.js"></script>
+<!-- bootstrap.js below is only needed if you wish to the feature of viewing details
+     of text file preview via modal dialog -->
+<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js" type="text/javascript"></script>
+<!-- optionally if you need translation for your language then include 
+    locale file as mentioned below -->
+<script src="path/to/js/fileinput_locale_<lang>.js"></script>
+```
+
+If you noticed, you need to load the `jquery.min.js` and `bootstrap.min.css` in addition to the `fileinput.min.css` and `fileinput.min.js`. The locale file `fileinput_locale_<lang>.js` can be optionally included for translating for your language if needed.
+
+Step 2: Initialize the plugin on your page. For example,
+
+```js
+// initialize with defaults
+$("#input-id").fileinput();
+
+// with plugin options
+$("#input-id").fileinput({'showUpload':false, 'previewFileType':'any'});
+```
+
+The `#input-id` is the identifier for the input (e.g. `type = file`) on your page, which is hidden automatically by the plugin. 
+
+Alternatively, you can directly call the plugin options by setting data attributes to your input field.
+
+```html
+<input id="input-id" type="file" class="file" data-preview-file-type="text" >
+```
+
+## Translations
+
+As shown in the installation section, translations are now enabled with release 4.1.8. You can load a locale file `/fileinput_locale_<lang>.js` after the core `fileinput.min.js` file, where `<lang>` is the language code (e.g. `de`, `fr` etc.). If  locale file does not exist, you can submit a translation for the new language via a [new pull request to add to this folder](https://github.com/kartik-v/bootstrap-fileinput/tree/master/js). Use the [sample locale file](https://github.com/kartik-v/bootstrap-fileinput/tree/master/js/fileinput_locale_LANG.js) to copy and create a translation configuration for your own language.
+
+## Plugin Options
+The plugin supports these following options:
+
+### language
+_string_ language configuration for the plugin to enable the plugin to display messages for your locale (you must set the ISO code for the language). You can have multiple language widgets on the same page. The locale JS file for the language code must be defined as mentioned in the translations section. The file must be loaded after `fileinput.js`.
+
+### showCaption
+_boolean_ whether to display the file caption. Defaults to `true`.
+
+### showPreview
+_boolean_ whether to display the file preview. Defaults to `true`.
+
+### showRemove
+_boolean_ whether to display the file remove/clear button. Defaults to `true`.
+
+### showUpload
+_boolean_ whether to display the file upload button. Defaults to `true`. This will default to a form submit button, unless the uploadUrl is specified.
+
+### showCancel
+_boolean_ whether to display the file upload cancel button. Defaults to `true`. This will be only enabled and displayed when an AJAX upload is in process.
+
+### showUploadedThumbs
+_boolean_ whether to persist display of the uploaded file thumbnails in the preview window (for ajax uploads) until the remove/clear button is pressed. Defaults to `true`.  When set to `false`, a next batch of files selected for upload will clear these thumbnails from preview.
+
+### autoReplace
+_boolean_ whether to automatically replace the files in the preview after the `maxFileCount` limit is reached and a new set of file(s) is/are selected. This will only work if a valid  `maxFileCount` is set. Defaults to `false`.
+
+### captionClass
+_string_ any additional CSS class to append to the caption container.
+
+### previewClass
+_string_ any additional CSS class to append to the preview container.
+
+### mainClass
+_string_ any additional CSS class to append to the main plugin container.
+
+### 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 there is no delimiter. You can set a delimiter (as defined 
+in `initialDelimiter`) to show multiple files in initial preview.  If set as an array, it will display all files in the array as an 
+initial preview (useful for multiple file upload scenarios).
+
+The following CSS classes will need to be added for displaying each file type as per the plugin style theme:
+
+- **image files:** Include CSS class `file-preview-image`
+- **text files:** Include CSS class `file-preview-text`
+- **other files:** Include CSS class `file-preview-other`
+
+Examples of how you can setup various files for initial preview:
+
+```js
+// for image files
+initialPreview: [
+    "<img src='/images/desert.jpg' class='file-preview-image' alt='Desert' title='Desert'>",
+    "<img src='/images/jellyfish.jpg' class='file-preview-image' alt='Jelly Fish' title='Jelly Fish'>",
+],
+
+// for text files
+initialPreview: "<div class='file-preview-text' title='NOTES.txt'>" +
+    "This is the sample text file content upto wrapTextLength of 250 characters" +
+    "<span class='wrap-indicator' onclick='$(\"#show-detailed-text\").modal(\"show\")' title='NOTES.txt'>[…]</span>" +
+    "</div>"
+
+// for other files    
+initialPreview: "<div class='file-preview-text'>" + 
+    "<h2><i class='glyphicon glyphicon-file'></i></h2>" +
+    "Filename.xlsx" + "</div>"
+```
+
+### initialPreviewCount
+_int_, the count of initial preview items that will be added to the count of files selected in preview. This is applicable when displaying
+the right caption, when `overwriteInitial` is set to `false`.
+
+### initialPreviewDelimiter
+_string_, the delimiter to be used for splitting the initial preview content as individual file thumbnails (applicable only if `initialPreview` is passed as a _string_ instead of _array_). Defaults to `*$$*`.
+
+### initialPreviewConfig
+_array_, the configuration for setting up important properties for each `initialPreview` item (that is setup as part of `initialPreview`). Each element in the array should be an object/associative array consisting of the following keys:
+
+    - `caption`: _string_, the caption or filename to display for each initial preview item content.
+    - `width`: _string_, the CSS width of the image/content displayed.
+    - `url`: _string_, the URL for deleting the image/content in the initial preview via AJAX post response. This will default to `deleteUrl` if not set.
+    - `key`: _string|object_, the key that will be passed as data to the `url` via AJAX POST.
+    - `frameClass`: _string_, the additional frame css class to set for the file's thumbnail frame.
+    - `frameAttr`: _object_, the HTML attribute settings (set as key:value pairs) for the thumbnail frame.
+    - `extra`: _object|function_, the extra data that will be passed as data to the initial preview delete url/AJAX server call via POST. This will default to `deleteExtraData` if not set.
+
+An example configuration of `initialPreviewConfig` (for the previously set `initialPreviewContent`) can be:
+
+```js
+// setup initial preview with data keys 
+initialPreview: [
+    "<img src='/images/desert.jpg' class='file-preview-image' alt='Desert' title='Desert'>",
+    "<img src='/images/jellyfish.jpg' class='file-preview-image' alt='Jelly Fish' title='Jelly Fish'>",
+],
+// initial preview configuration
+initialPreviewConfig: [
+    {
+        caption: 'desert.jpg', 
+        width: '120px', 
+        url: '/localhost/avatar/delete', 
+        key: 100, 
+        extra: {id: 100}
+    },
+    {
+        caption: 'jellyfish.jpg', 
+        width: '120px', 
+        url: '/localhost/avatar/delete', 
+        key: 101, 
+        frameClass: 'my-custom-frame-css',
+        frameAttr: {
+            style: 'height:80px',
+            title: 'My Custom Title',
+        },
+        extra: function() { 
+            return {id: $("#id").val()};
+        },
+    }
+]
+```
+
+> Note: The ajax delete action will send the following data to server via POST:
+- `key`: the key setting as setup in `initialPreviewConfig['key']`
+- any other extra data as `key: value` pairs passed either via `initialPreviewConfig['extra']` OR `deleteExtraData` format if former is not set.
+
+### initialPreviewShowDelete
+_bool_, whether the delete button will be displayed for each thumbnail that has been created with `initialPreview`.
+
+### previewThumbTags
+_array_, this will be a list of tags used in thumbnail templates that will be replaced dynamically within the thumbnail markup, when the thumbnail is rendered. For example:
+
+```js
+// change thumbnail footer template
+layoutTemplates.footer = '<div class="file-thumbnail-footer">\n' +
+'    <div class="file-caption-name">{caption}</div>\n' +
+'    {CUSTOM_TAG_NEW}\n' +
+'    {CUSTOM_TAG_INIT}\n' +
+'    {actions}\n' +
+'</div>';
+
+// set preview template tags
+previewThumbTags = {
+    '{CUSTOM_TAG_NEW}': '<span class="custom-css">CUSTOM MARKUP</span>',
+    '{CUSTOM_TAG_INIT}': '&nbsp;'
+};
+```
+
+### initialPreviewThumbTags
+_array_, this is an extension of `previewThumbTags` specifically for initial preview content - but will be configured as an array of objects corresponding to each initial preview thumbnail. The initial preview thumbnails set via `initialPreview` will read this configuration for replacing tags. Extending example above:
+
+
+```js
+// change thumbnail footer template
+layoutTemplates.footer = '<div class="file-thumbnail-footer">\n' +
+'    <div class="file-caption-name">{caption}</div>\n' +
+'    {CUSTOM_TAG_NEW}\n' +
+'    {CUSTOM_TAG_INIT}\n' +
+'    {actions}\n' +
+'</div>';
+
+// setup initial preview with data keys 
+initialPreview: [
+    "<img src='/images/desert.jpg' class='file-preview-image' alt='Desert' title='Desert'>",
+    "<img src='/images/jellyfish.jpg' class='file-preview-image' alt='Jelly Fish' title='Jelly Fish'>",
+],
+
+// set initial preview template tags
+initialPreviewThumbTags = {
+    '{CUSTOM_TAG_NEW}': '&nbsp;',
+    '{CUSTOM_TAG_INIT}': '<span class="custom-css">CUSTOM MARKUP</span>'
+};
+```
+
+### deleteExtraData
+_object | function_ the extra data that will be passed as data to the initial preview delete url/AJAX server call via POST. This will be overridden by the `initialPreviewConfig['extra']` property. This can be setup either as an object (associative array of keys and values) or as a function callback. As an object, it can be set for example as:
+
+```js
+ {id: 100, value: '100 Details'}
+```
+
+As a function callback, it can be setup for example as:
+
+```js
+function() {
+    var obj = {};
+    $('.your-form-class').find('input').each(function() {
+        var id = $(this).attr('id'), val = $(this).val();
+        obj[id] = val;
+    });
+    return obj;
+}
+```
+### deleteUrl
+_object | function_ the URL for deleting the image/content in the initial preview via AJAX post response. This will be overridden by the `initialPreviewConfig['url']` property.
+
+### initialCaption
+_string_ the initial preview caption text to be displayed. If you do not set a value here and `initialPreview` is set to 
+`true` this will default to `"{preview-file-count} files selected"`, where `{preview-file-count}` is the count of the 
+files passed in `initialPreview`.
+
+### 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 - 
+useful especially when using the `multiple` file upload feature.
+ 
+### layoutTemplates
+
+_object_ the templates configuration for rendering each part of the layout. You can set the following templates to control the widget layout:
+
+- `main1`: the template for rendering the widget with caption.
+- `main2`: the template for rendering the widget without caption.
+- `preview`: the template for rendering the preview.
+- `icon`: the icon to render before the caption text.
+- `caption`: the template for rendering the caption.
+- `modal`: the template for rendering the modal (for text file preview zooming).
+- `progress`: the template for the progress bar when upload is in progress (for batch/mass uploads). The following tags will be parsed and replaced automatically:
+    - `{percent}`: will be replaced with the upload progress percentage.
+- `footer`: the template for the footer section of each file preview thumbnail. The following tags will be parsed and replaced automatically:
+    - `{actions}`: will be replaced with the output of the `actions` template.
+- `actions`: the template for the file action buttons to be displayed within the thumbnail `footer`. The following tags will be parsed and replaced automatically:
+    - `{upload}`: will be replaced with the output of the `actionUpload` template.
+    - `{delete}`: will be replaced with the output of the `actionDelete` template.
+- `actionDelete`: the template for the file delete action button within the thumbnail `footer`. The following tags will be parsed and replaced automatically:
+    - `{removeClass}`: the css class for the remove button. Will be replaced with the `removeClass` set within `fileActionSettings`.
+    - `{removeIcon}`: the icon for the remove button. Will be replaced with the `removeIcon` set within `fileActionSettings`.
+    - `{removeTitle}`: the title to display on hover for the remove button. Will be replaced with the `removeTitle` set within `fileActionSettings`.
+    - `{dataUrl}`: the URL for deleting the file thumbnail for `initialPreview` content only. Will be replaced with the `url` set within `initialPreviewConfig`.
+    - `{dataKey}`: the key (additional data) that will be passed to the URL above via POST to the AJAX call. Will be replaced with the `key` set within `initialPreviewConfig`.
+- `actionUpload`: the template for the file upload action button within the thumbnail `footer`.
+    - `{uploadClass}`: the css class for the upload button. Will be replaced with the `uploadClass` set within `fileActionSettings`.
+    - `{uploadIcon}`: the icon for the upload button. Will be replaced with the `uploadIcon` set within `fileActionSettings`.
+    - `{uploadTitle}`: the title to display on hover for the upload button. Will be replaced with the `uploadTitle` set within `fileActionSettings`.
+
+The `main1` and `main2` templates would automatically parse the following tags for replacement:
+
+- `{class}`: the CSS class as set in the `mainClass` property.
+- `{preview}`: the content parsed by the `previewTemplate` and will be displayed only if `showPreview` is `true`.
+- `{caption}`: the content parsed by the `captionTemplate` and will be displayed only if `showCaption` is `true`.
+- `{remove}`: the file remove/clear button and will be displayed only if `showRemove` is `true`.
+- `{upload}`: the file upload button and will be displayed only if `showUpload` is `true`.
+- `{cancel}`: the file upload cancel button that will be displayed when AJAX upload is in process to abort the AJAX upload.
+- `{browse}`: the main file browse button to select your files for input.
+
+The `preview` and `caption` templates can understand the following special tags which will be replaced:
+
+- `{class}`: the CSS class as set in the `mainClass`, `captionClass` or `previewClass` properties.
+
+Similarly, the `progress` layout template can understand the following special tags which will be replaced:
+
+- `{class}`: the CSS class as set in the `progressClass` or `progressCompleteClass` properties.
+
+The `layoutTemplates` if not set will default to:
+
+```js
+{
+    main1: '{preview}\n' +
+        '<div class="kv-upload-progress hide"></div>\n' +
+        '<div class="input-group {class}">\n' +
+        '   {caption}\n' +
+        '   <div class="input-group-btn">\n' +
+        '       {remove}\n' +
+        '       {cancel}\n' +
+        '       {upload}\n' +
+        '       {browse}\n' +
+        '   </div>\n' +
+        '</div>',
+    main2: '{preview}\n<div class="kv-upload-progress hide"></div>\n{remove}\n{cancel}\n{upload}\n{browse}\n',
+    preview: '<div class="file-preview {class}">\n' +
+        '    <div class="close fileinput-remove">&times;</div>\n' +
+        '    <div class="{dropClass}">\n' +
+        '    <div class="file-preview-thumbnails">\n' +
+        '    </div>\n' +
+        '    <div class="clearfix"></div>' +
+        '    <div class="file-preview-status text-center text-success"></div>\n' +
+        '    <div class="kv-fileinput-error"></div>\n' +
+        '    </div>\n' +
+        '</div>',
+    icon: '<span class="glyphicon glyphicon-file kv-caption-icon"></span>',
+    caption: '<div tabindex="-1" class="form-control file-caption {class}">\n' +
+        '   <span class="file-caption-ellipsis">&hellip;</span>\n' +
+        '   <div class="file-caption-name"></div>\n' +
+        '</div>',
+    modal: '<div id="{id}" class="modal fade">\n' +
+        '  <div class="modal-dialog modal-lg">\n' +
+        '    <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' +
+        '      </div>\n' +
+        '      <div class="modal-body">\n' +
+        '        <textarea class="form-control" style="font-family:Monaco,Consolas,monospace; height: {height}px;" readonly>{body}</textarea>\n' +
+        '      </div>\n' +
+        '    </div>\n' +
+        '  </div>\n' +
+        '</div>',
+    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' +
+        '     </div>\n' +
+        '</div>',
+    footer: '<div class="file-thumbnail-footer">\n' +
+        '    <div class="file-caption-name" style="width:{width}">{caption}</div>\n' +
+        '    {actions}\n' +
+        '</div>',
+    actions: '<div class="file-actions">\n' +
+        '    <div class="file-footer-buttons">\n' +
+        '        {upload}{delete}{other}' +
+        '    </div>\n' +
+        '    <div class="file-upload-indicator" tabindex="-1" title="{indicatorTitle}">{indicator}</div>\n' +
+        '    <div class="clearfix"></div>\n' +
+        '</div>',
+    actionDelete: '<button type="button" class="kv-file-remove {removeClass}" title="{removeTitle}"{dataUrl}{dataKey}>{removeIcon}</button>\n',
+    actionUpload: '<button type="button" class="kv-file-upload {uploadClass}" title="{uploadTitle}">{uploadIcon}</button>\n'
+};
+```
+
+### previewTemplates
+
+_object_ the templates configuration for rendering each preview file type. The following file types are recognized:
+
+- `image`: the preview template for image files.
+- `text`: the  preview template for text files.
+- `html`: the preview template for html files.
+- `video`: the preview template for video files (supported by HTML 5 video tag).
+- `audio`: the preview template for audio files (supported by HTML 5 audio tag).
+- `flash`: the preview template for flash files (supported currently on webkit browsers).
+- `object`: the preview template for all other files - by default treated as object. To disable this behavior, configure the `allowedPreviewTypes` property.
+- `generic`: this template is used ONLY for rendering the `initialPreview` markup content passed directly as a raw format. 
+
+The following tags will be parsed and replaced in each of the templates:
+
+- `{previewId}`: will be replaced with the generated identifier for the preview frame container.
+- `{data}`: will be replaced with the data source for each preview type.
+- `{width}`: will be replaced with the width for the file type as set in `previewSettings`.
+- `{height}`: will be replaced with the height for the file type as set in `previewSettings`.
+- `{caption}`: will be replaced with the file name.
+- `{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.
+
+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. 
+
+The `previewTemplates` if not set will default to:
+
+```js
+{
+    generic: '<div class="file-preview-frame" id="{previewId}" data-fileindex="{fileindex}">\n' +
+        '   {content}\n' +
+        '   {footer}\n' +
+        '</div>\n',
+    html: '<div class="file-preview-frame" id="{previewId}" data-fileindex="{fileindex}">\n' +
+        '    <object data="{data}" type="{type}" width="{width}" height="{height}">\n' +
+        '       ' + DEFAULT_PREVIEW + '\n' +
+        '    </object>\n' + 
+        '   {footer}\n' +
+        '</div>',
+    image: '<div class="file-preview-frame" id="{previewId}" data-fileindex="{fileindex}">\n' +
+        '   <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' + 
+        '   {footer}\n' +
+        '</div>\n',
+    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' +
+        '       ' + DEFAULT_PREVIEW + '\n' +
+        '   </video>\n' + 
+        '   {footer}\n' +
+        '</div>\n',
+    audio: '<div class="file-preview-frame" id="{previewId}" data-fileindex="{fileindex}" title="{caption}" ' + STYLE_SETTING + '>\n' +
+        '   <audio controls>\n' +
+        '       <source src="{data}" type="{type}">\n' +
+        '       ' + DEFAULT_PREVIEW + '\n' +
+        '   </audio>\n' + 
+        '   {footer}\n' +
+        '</div>\n',
+    flash: '<div class="file-preview-frame" id="{previewId}" data-fileindex="{fileindex}" title="{caption}" ' + STYLE_SETTING + '>\n' +
+        '   <object type="application/x-shockwave-flash" width="{width}" height="{height}" data="{data}">\n' +
+        OBJECT_PARAMS + '       ' + DEFAULT_PREVIEW + '\n' +
+        '   </object>\n' + 
+        '   {footer}\n' +
+        '</div>\n',
+    object: '<div class="file-preview-frame" id="{previewId}" data-fileindex="{fileindex}" title="{caption}" ' + STYLE_SETTING + '>\n' +
+        '    <object data="{data}" type="{type}" width="{width}" height="{height}">\n' +
+        '      <param name="movie" value="{caption}" />\n' +
+        OBJECT_PARAMS + '           ' + DEFAULT_PREVIEW + '\n' +
+        '   </object>\n' + 
+        '   {footer}\n' +
+        '</div>',
+    other: '<div class="file-preview-frame{frameClass}" id="{previewId}" data-fileindex="{fileindex}" title="{caption}" ' + STYLE_SETTING + '>\n' +
+        '   ' + DEFAULT_PREVIEW + '\n' +
+        '   {footer}\n' +
+        '</div>',
+}
+```
+
+The values of the constants used in the above templates are as follows:
+
+```js
+STYLE_SETTING = 'style="width:{width};height:{height};"',
+OBJECT_PARAMS = '      <param name="controller" value="true" />\n' +
+    '      <param name="allowFullScreen" value="true" />\n' +
+    '      <param name="allowScriptAccess" value="always" />\n' +
+    '      <param name="autoPlay" value="false" />\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>'
+```
+
+### 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 
+invalid file type is found, then a validation error message as set in `msgInvalidFileType` will be raised. The following types as set in `fileTypeSettings` 
+are available for setup. 
+
+```js
+['image', 'html', 'text', 'video', 'audio', 'flash', 'object']
+```
+
+### allowedFileExtensions
+
+_array_ the list of allowed file extensions for upload. This by default is set to null which means the plugin supports all file extensions for upload. If an 
+invalid file extension is found, then a validation error message as set in `msgInvalidFileExtension` will be raised. An example of setting this could be:
+
+```js
+['jpg', 'gif', 'png', 'txt']
+```
+
+> NOTE: You need to be careful in case you are setting both `allowedFileTypes` and `allowedFileExtensions`. In this case, the `allowedFileTypes` property 
+is validated first and generally precedes the `allowedFileExtensions` setting (and the latter validation maybe skipped).
+
+### allowedPreviewTypes
+
+_array_ the list of allowed preview types for your widget. This by default supports all file types for preview. The plugin by default treats each
+file as an object if it does not match any of the previous types. To disable this behavior, you can remove `object` from the list of `allowedPreviewTypes`
+OR fine tune it through `allowedPreviewMimeTypes`.
+
+This is by default setup as following:
+```js
+['image', 'html', 'text', 'video', 'audio', 'flash', 'object']
+```
+
+### allowedPreviewMimeTypes
+
+_array_ the list of allowed mime types for preview. This is set to null by default which means all possible mime types are allowed. This setting works in combination with `allowedPreviewTypes` to filter only the needed file types allowed for preview. You can check this [list of allowed mime types](http://www.sitepoint.com/web-foundations/mime-types-complete-list/) to add to this list if needed.
+
+### customLayoutTags
+
+_object_ the list of additional custom tags that will be replaced in the **layout** templates. This should be an associative array object of `key: value` pairs, where:
+
+- `key`: _string_, is the tag to be replaced and as a standard is recommended to be enclosed between braces.
+- `value`: _string|function_, is the value that will replace the tag key above. This can be setup either as a string or callback function.
+
+For example:
+
+```js
+// example 1 - tags with value set as string
+customLayoutTags: {
+    '{tagA}': '<span class="label label-default">Tag A</span>',
+    '{tagB}': 'Tag B',
+}
+
+// example 2 - tags with value set as callback
+customLayoutTags: {
+    '{tagC}': function() {
+        return $("#element-id").val();
+    }
+}
+```
+
+### customPreviewTags
+
+_object_ the list of additional custom tags that will be replaced in the **preview** templates. This should be an associative array object of `key: value` pairs, where:
+
+- `key`: _string_, is the tag to be replaced and as a standard is recommended to be enclosed between braces.
+- `value`: _string|function_, is the value that will replace the tag key above. This can be setup either as a string or callback function.
+
+For example:
+
+```js
+// example 1 - tags with value set as string
+customPreviewTags: {
+    '{tagA}': '<span class="label label-default">Tag A</span>',
+    '{tagB}': 'Tag B',
+}
+
+// example 2 - tags with value set as callback
+customPreviewTags: {
+    '{tagC}': function() {
+        return $("#element-id").val();
+    }
+}
+```
+### previewSettings
+
+_object_ the format settings (width and height) for rendering each preview file type. This is by default setup as following:
+
+```js
+{
+    image: {width: "auto", height: "160px"},
+    html: {width: "213px", height: "160px"},
+    text: {width: "160px", height: "160px"},
+    video: {width: "213px", height: "160px"},
+    audio: {width: "213px", height: "80px"},
+    flash: {width: "213px", height: "160px"},
+    object: {width: "160px", height: "160px"},
+    other: {width: "160px", height: "160px"}
+}
+```
+
+### fileTypeSettings
+
+_object_ the settings to validate and identify each file type when a file is selected for upload. This is a list of callbacks, which accepts the file mime type and file name as a parameter.
+This is by default setup as following:
+
+```js
+// vType: is the file mime type
+// vName: is the file name
+{
+	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;
+	},
+}
+```
+
+### 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>`.
+
+### 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;`.
+
+### browseClass
+_string_ the CSS class for the file picker/browse button. Defaults to `btn btn-primary`.
+
+### removeLabel
+_string_ the label to display for the file remove button. Defaults to `Remove`.
+
+### removeIcon
+_string_ the icon to display before the label for the file picker/remove button. Defaults to `<i class="glyphicon glyphicon-trash"></i> &nbsp;`.
+
+### removeClass
+_string_ the CSS class for the file remove button. Defaults to `btn btn-default`.
+
+### removeTitle
+_string_ the title to display on hover for the file remove button. Defaults to `Clear selected files`.
+
+### cancelLabel
+_string_ the label to display for the file cancel button. Defaults to `Cancel`.
+
+### cancelIcon
+_string_ the icon to display before the label for the file picker/remove button. Defaults to `<i class="glyphicon glyphicon-ban-circle"></i> &nbsp;`.
+
+### cancelClass
+_string_ the CSS class for the file cancel button. Defaults to `btn btn-default`.
+
+### cancelTitle
+_string_ the title to display on hover for the file cancel button. Defaults to `Abort ongoing upload`.
+
+### uploadLabel
+_string_ the label to display for the file upload button. Defaults to `Upload`.
+
+### uploadIcon
+_string_ the icon to display before the label for the file upload button. Defaults to `<i class="glyphicon glyphicon-upload"></i> &nbsp;`.
+
+### uploadClass
+_string_ the CSS class for the file upload button. Defaults to `btn btn-default`.
+
+### uploadTitle
+_string_ the title to display on hover for the file remove button. Defaults to `Upload selected files`.
+
+### 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. NOTE: This is MANDATORY if you want to use advanced features like drag & drop, append/remove files, selectively upload files via ajax etc.
+
+### uploadAsync
+_bool_ whether the batch upload of multiple files will be asynchronous/in parallel. Defaults to `true`.
+
+### uploadExtraData
+_object | function_ the extra data that will be passed as data to the url/AJAX server call via POST. This can be setup either as an object (associative array of keys and values) or as a function callback. As an object, it can be set for example as:
+
+```js
+ {id: 100, value: '100 Details'}
+```
+
+As a function callback, the `uploadExtraData` can be setup as shown below. Note that for uploading individual file via thumbnail, the callback can also receive the thumbnail `previewId` and `index` as parameters. These are described below:
+
+- `previewId`: the identifier for the preview file container (only available when uploading each thumbnail file)
+- `index`: the zero-based sequential index of the loaded file in the preview list (only available when uploading each thumbnail file)
+
+```js
+// previewId and index is only available for individual file upload via the thumbnail
+function (previewId, index) {
+    var obj = {};
+    $('.your-form-class').find('input').each(function() {
+        var id = $(this).attr('id'), val = $(this).val();
+        obj[id] = val;
+    });
+    return obj;
+}
+```
+
+### maxImageWidth
+_int_ the maximum allowed image width in `px` if you are uploading image files. Defaults to `null` which means no limit on image width.
+
+### maxImageHeight
+_int_ the maximum allowed image height in `px` if you are uploading image files. Defaults to `null` which means no limit on image height.
+
+### minImageWidth
+_int_ the minimum allowed image width in `px` if you are uploading image files. Defaults to `null` which means no limit on image width.
+
+### minImageHeight
+_int_ the minimum allowed image height in `px` if you are uploading image files. Defaults to `null` which means no limit on image height.
+
+### maxFileSize
+_float_ the maximum file size for upload in KB.  If set to `0`, it means size allowed is unlimited. Defaults to `0`.
+
+### minFileCount
+_int_ the minimum number of files allowed for each multiple upload. If set to `0`, it means number of files are optional. Defaults to `0`.
+
+### maxFileCount
+_int_ the maximum number of files allowed for each multiple upload. If set to `0`, it means number of files allowed is unlimited. Defaults to `0`.
+
+### 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.
+
+### msgFilesTooLess
+_string_ the message to be displayed when the file count is less than the minimum count as set in `minFileCount`. Defaults to:
+
+```
+You must select at least <b>{n}</b> {files} to upload. Please retry your upload!
+```
+
+where:
+
+- `{n}`: will be replaced by the allowed minimum files as set in `minFileCount`
+- `{files}`: will be replaced with `fileSingle` or `filePlural` properties in locale file depending on the `minFileCount`.
+
+### msgFilesTooMany
+_string_ the message to be displayed when the file count exceeds maximum count as set in `maxFileCount`. Defaults to:
+
+```
+Number of files selected for upload <b>({n})</b> exceeds maximum allowed limit of <b>{m}</b>. Please retry your upload!
+```
+
+where:
+
+- `{n}`: will be replaced by number of files selected for upload
+- `{m}`: will be replaced by the allowed maximum files as set in `maxFileCount`
+
+### msgFileNotFound
+_string_ the exception message to be displayed when the file selected is not found by the FileReader. Defaults to:
+
+```
+File "{name}" not found!
+```
+where:
+
+- `{name}`: will be replaced by the file name being uploaded
+
+### msgFileSecured
+_string_ the exception message to be displayed when the file selected is not allowed to be accessed due to a security exception. Defaults to:
+
+```
+Security restrictions prevent reading the file "{name}".
+```
+where:
+
+- `{name}`: will be replaced by the file name being uploaded
+
+### msgFileNotReadable
+_string_ the exception message to be displayed when the file selected is not readable by the FileReader API. Defaults to:
+
+```
+File "{name}" is not readable.
+```
+where:
+
+- `{name}`: will be replaced by the file name being uploaded
+
+### msgFilePreviewAborted
+_string_ the exception message to be displayed when the file preview upload is aborted. Defaults to:
+
+```
+File preview aborted for "{name}".
+```
+where:
+
+- `{name}`: will be replaced by the file name being uploaded
+
+### msgFilePreviewError
+_string_ the exception message to be displayed for any other error when previewing the file. Defaults to:
+
+```
+An error occurred while reading the file "{name}".
+```
+where:
+
+- `{name}`: will be replaced by the file name being uploaded
+
+### msgInvalidFileType
+_string_ the message to be displayed when the file type is not in one of the file types set in `allowedFileTypes`. Defaults to:
+
+```
+Invalid type for file "{name}". Only "{types}" files are supported.
+```
+where:
+
+- `{name}`: will be replaced by the file name being uploaded
+- `{types}`: will be replaced by the comma separated list of types defined in `allowedFileTypes`.
+
+### msgInvalidFileExtension
+_string_ the message to be displayed when the file type is not in one of the file extensions set in `allowedFileExtensions`. Defaults to:
+
+```
+Invalid extension for file "{name}". Only "{extensions}" files are supported.
+```
+where:
+
+- `{name}`: will be replaced by the file name being uploaded
+- `{extensions}`: will be replaced by the comma separated list of extensions defined in `allowedFileExtensions`.
+
+### msgValidationError
+_string_ the exception message to be displayed within the caption container (instead of `msgFilesSelected`), 
+when a validation error is encountered. Defaults to `File Upload Error`.
+
+### msgValidationErrorClass
+_string_ the css class for the validation error message displayed in the caption container. Defaults to `text-danger`.
+
+### msgValidationErrorIcon
+_string_ the icon to be displayed before the validation error in the caption container. Defaults to `<i class="glyphicon glyphicon-exclamation-sign"></i> `.
+
+### 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  file {index} of {files} &hellip;```
+
+The following special variables will be replaced:
+
+- `{index}`: the sequence number of the current file being loaded.
+- `{files}`: the total number of files selected for upload.
+
+### msgProgress
+_string_ the progress message displayed as each file is loaded for preview. Defaults to:
+
+```Loading file {index} of {files} - {name} - {percent}% completed.```
+
+The following variables will be replaced:
+
+- `{index}`: the sequence number of the current file being loaded.
+- `{files}`: the total number of files selected for upload.
+- `{percent}`: the percentage of file read and loaded.
+- `{name}`: the name of the current file being loaded.
+
+### msgSelected
+_string_ the progress message displayed in caption window when multiple (more than one) files are selected. Defaults to `{n} files selected`. The following variables will be replaced:
+
+- `{n}`: the number of files selected.
+
+### msgFoldersNotAllowed
+_string_ the message displayed when a folder has been dragged to the drop zone. Defaults to `Drag & drop files only! {n} folder(s) dropped were skipped.`. The following variables will be replaced The following variables will be replaced:
+
+- `{n}`: the number of folders dropped.
+
+### msgImageWidthSmall
+_string_ the exception message to be displayed when the file selected for preview is an image and its width is less than the `minImageWidth` setting. Defaults to:
+
+```
+Width of image file "{name}" must be at least {size} px.
+```
+where:
+
+- `{name}`: will be replaced by the file name being uploaded
+- `{size}`: will be replaced by the `minImageWidth` setting.
+
+### msgImageHeightSmall
+_string_ the exception message to be displayed when the file selected for preview is an image and its height is less than the `minImageHeight` setting. Defaults to:
+
+```
+Width of image file "{name}" must be at least {size} px.
+```
+where:
+
+- `{name}`: will be replaced by the file name being uploaded
+- `{size}`: will be replaced by the `minImageHeight` setting.
+
+### msgImageWidthLarge
+_string_ the exception message to be displayed when the file selected for preview is an image and its width exceeds the `maxImageWidth` setting. Defaults to:
+
+```
+Width of image file "{name}" cannot exceed {size} px.
+```
+where:
+
+- `{name}`: will be replaced by the file name being uploaded
+- `{size}`: will be replaced by the `maxImageWidth` setting.
+
+### msgImageHeightLarge
+_string_ the exception message to be displayed when the file selected for preview is an image and its height exceeds the `maxImageHeight` setting. Defaults to:
+
+```
+Height of image file "{name}" cannot exceed {size} px.
+```
+where:
+
+- `{name}`: will be replaced by the file name being uploaded
+- `{size}`: will be replaced by the `maxImageHeight` setting.
+
+### progressClass
+_string_ the upload progress bar CSS class to be applied when AJAX upload is in process (applicable only for ajax uploads). Defaults to `progress-bar progress-bar-success progress-bar-striped active`. 
+
+### progressCompleteClass
+_string_ the upload progress bar CSS class to be applied when AJAX upload is complete. Defaults to `progress-bar progress-bar-success`. 
+
+### previewFileType
+_string_ the type of files that are to be displayed in the preview window. Defaults to `image`. Can be one of the following:
+
+- `image`: Only `image` type files will be shown in preview.
+- `text`:  Only `text` type files will be shown in preview.
+- `any`: Both `image` and `text` files content will be shown in preview.
+
+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.
+
+### 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.
+
+### elCaptionContainer
+_string_ the identifier for the container element containing the caption (e.g. `'#id'`). If not set, will default to the container with CSS class `file-caption` inside the main plugin container.
+
+### elCaptionText
+_string_ the identifier for the container element containing the caption text (e.g. `'#id'`). If not set, will default to the container with CSS class `file-caption-name` inside the main plugin container.
+
+### elPreviewContainer
+_string_ the identifier for the container element containing the preview (e.g. `'#id'`). If not set, will default to the container with CSS class `file-preview` inside the main plugin container.
+
+### elPreviewImage
+_string_ the identifier for the element containing the preview image thumbnails (e.g. `'#id'`). If not set, will default to the container with CSS class `file-preview-thumbnails` inside the main plugin container.
+
+### elPreviewStatus
+_string_ the identifier for the element containing the preview progress status (e.g. `'#id'`). If not set, will default to the container with CSS class `file-preview-status` inside the main plugin container.
+
+### slugCallback
+_function_ a callback to convert the filename as a slug string eliminating special characters. If not set, it will use the plugin's own internal `slugDefault` method. This callback function includes the filename as parameter and must return a converted filename string.
+
+**Example:**
+
+```js
+slugCallback: function(filename) {
+    return filename.replace('(', '_');
+}
+```
+
+### dropZoneEnabled
+_bool_ whether to enable a drag and drop zone for dragging and dropping files to. This is available only for ajax based uploads. Defaults to `true`. 
+
+### dropZoneTitle
+_string_ title to be displayed in the drag and drop zone. This is available only for ajax based uploads. Defaults to `Drag & drop files here &hellip;`. 
+
+### dropZoneTitleClass
+_string_ CSS class for the drag & drop zone title. Defaults to `file-drop-zone-title`. 
+
+### fileActionSettings
+_object_ configuration for setting up file actions for newly selected file thumbnails in the preview window. The following properties can be set:
+    - `removeIcon`: _string_, icon for remove button to be displayed in each file thumbnail.
+    - `removeClass`: _string_, CSS class for the remove button in each file thumbnail.
+    - `removeTitle`: _string_, title for remove button in each file thumbnail.
+    - `uploadIcon`: _string_, icon for upload button to be displayed in each file thumbnail.
+    - `uploadClass`: _string_, CSS class for the remove button in each file thumbnail.
+    - `uploadTitle`: _string_, title for remove button in each file thumbnail.
+    - `indicatorNew`: _string_, an indicator (HTML markup) for new pending upload displayed in each file thumbnail.
+    - `indicatorSuccess`: _string_, an indicator (HTML markup) for successful upload displayed in each file thumbnail.
+    - `indicatorError`: _string_, an indicator (HTML markup) for error in upload displayed in each file thumbnail.
+    - `indicatorLoading`: _string_, an indicator (HTML markup) for ongoing upload displayed in each file thumbnail.
+    - `indicatorNewTitle`: _string_, title to display on hover of indicator for new pending upload in each file thumbnail.
+    - `indicatorSuccessTitle`: _string_, title to display on hover of indicator for successful in each file thumbnail.
+    - `indicatorErrorTitle`: _string_, title to display on hover of indicator for error in upload in each file thumbnail.
+    - `indicatorLoadingTitle`: _string_, title to display on hover of indicator for ongoing upload in each file thumbnail.
+
+Defaults to the following setting:
+```js
+{
+    removeIcon: '<i class="glyphicon glyphicon-trash text-danger"></i>',
+    removeClass: 'btn btn-xs btn-default',
+    removeTitle: 'Remove file',
+    uploadIcon: '<i class="glyphicon glyphicon-upload text-info"></i>',
+    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>',
+    indicatorError: '<i class="glyphicon glyphicon-exclamation-sign text-danger"></i>',
+    indicatorLoading: '<i class="glyphicon glyphicon-hand-up text-muted"></i>',
+    indicatorNewTitle: 'Not uploaded yet',
+    indicatorSuccessTitle: 'Uploaded',
+    indicatorErrorTitle: 'Upload Error',
+    indicatorLoadingTitle: 'Uploading ...'
+}
+```
+
+### otherActionButtons
+_string_ markup for additional action buttons to display within the initial preview thumbnails (for example displaying an image edit button). The following tags can be used in the markup and will be automatically replaced:
+
+- `{dataKey}`: Will be replaced with the `key` set within `initialPreviewConfig`.    
+
+### textEncoding
+_string_ the encoding to be used while reading a text file. Applicable only for previewing text files. Defaults to `UTF-8`. 
+
+### ajaxSettings
+_object_ additional ajax settings to pass to the plugin before submitting the ajax request. Applicable only for ajax uploads. This can be useful to pass additional tokens to headers or one can use it for setting other ajax options for advanced cases. Refer the [jQuery ajax documentation](http://api.jquery.com/jQuery.ajax/) for the various settings you can configure.
+
+### ajaxDeleteSettings
+_object_ additional ajax settings to pass to the plugin before submitting the delete ajax request in each initial preview thumbnail. Applicable only for ajax deletions. This can be useful to pass additional tokens to headers or one can use it for setting other ajax options for advanced cases. Refer the [jQuery ajax documentation](http://api.jquery.com/jQuery.ajax/) for the various settings you can configure.
+
+### showAjaxErrorDetails
+_boolean_ whether to show details of the error stack from the server log when an error is encountered via ajax response. Defaults to `true`.
+
+## Plugin Events
+
+The plugin supports the following events. 
+
+### File Events
+
+#### fileclear
+This event is triggered when the file input the remove button is pressed for clearing the file preview.
+
+**Example:**
+```js
+$('#input-id').on('fileclear', function(event) {
+    console.log("fileclear");
+});
+```
+
+#### filecleared
+This event is triggered after the files in the preview are cleared.
+
+**Example:**
+```js
+$('#input-id').on('filecleared', function(event) {
+    console.log("filecleared");
+});
+```
+
+#### fileloaded
+This event is triggered after a file is loaded in the preview. Additional parameters available 
+are: 
+
+- `file`: the file object instance
+- `previewId`: the identifier for the preview file container
+- `index`: the zero-based sequential index of the loaded file in the preview list
+- `reader`: the FileReader instance if available
+
+**Example:**
+```js
+$('#input-id').on('fileloaded', function(event, file, previewId, index, reader) {
+    console.log("fileloaded");
+});
+```
+
+#### filereset
+This event is triggered when the file input is reset to initial value.
+
+**Example:**
+```js
+$('#input-id').on('filereset', function(event) {
+    console.log("filereset");
+});
+```
+
+#### fileimageloaded
+This event is triggered when each file image is fully loaded in the preview window. This is only applicable for image file previews and if `showPreview` is set to true. Additional parameters available are: 
+
+- `previewId`: the identifier for the preview file container
+
+**Example:**
+```js
+$('#input-id').on('fileimageloaded', function(event, previewId) {
+    console.log("fileimageloaded");
+});
+```
+#### filebrowse
+This event is triggered when the file browse button is clicked to open the file selection dialog.
+
+**Example:**
+```js
+$('#input-id').on('filebrowse', function(event) {
+    console.log("File browse triggered.");
+});
+```
+
+#### filebatchselected
+This event is triggered after a batch of files are selected and displayed in the preview.
+Additional parameters available are: 
+
+- `files`: the file stack array (or empty object if not available).
+
+```js
+$('#input-id').on('filebatchselected', function(event, files) {
+    console.log('File batch selected triggered');
+});
+```
+
+#### fileselectnone
+This event is triggered when no files are selected by the user for a repeat selection scenario (i.e. on a file input that already contains previously selected files). This event is better applicable for browsers like Google Chrome, which clear the file input when the file selection dialog is cancelled. For other browsers, this event is typically triggered only when one resets the form or clears file input (using the remove button).
+
+**Example:**
+```js
+$('#input-id').on('fileselectnone', function(event) {
+    console.log("Huh! No files were selected.");
+});
+```
+
+#### filelock
+This event is triggered when the upload process is launched by clicking a upload button, and the entire widget is locked (disabled) until upload is getting processed. Only the `Cancel` button will be enabled when the file input is locked. Additional parameters available are: 
+
+- `filestack`: the array of selected file objects.
+- `extraData`: the `uploadExtraData` settings for the plugin (will return an empty object if not set).
+
+```js
+$('#input-id').on('filelock', function(event, filestack, extraData) {
+    var fstack = filestack.filter(function(n){ return n != undefined });
+    console.log('Files selected - ' + fstack.length);
+});
+```
+
+#### fileunlock
+This event is triggered when the upload process is completed (successfully or with error). The entire widget is unlocked (enabled) and reverts to initial state. Additional parameters available are: 
+
+- `filestack`: the array of selected file objects.
+- `extraData`: the `uploadExtraData` settings for the plugin (will return an empty object if not set).
+
+```js
+$('#input-id').on('fileunlock', function(event, filestack, extraData) {
+    var fstack = filestack.filter(function(n){ return n != undefined });
+    console.log('Files selected - ' + fstack.length);
+});
+```
+
+#### filepredelete
+This event is triggered before deletion of each thumbnail file in the `initialPreview` content set. Additional parameters available are: 
+
+- `key`: the key passed within `initialPreviewConfig` for the selected file for delete.
+- `jqXHR`: the `jQuery XMLHttpRequest` object used for this transaction (if available).
+- `data`: the output of `deleteExtraData` object.
+
+```js
+$('#input-id').on('filepredelete', function(event, key, jqXHR) {
+    console.log('Key = ' + key);
+});
+```
+
+#### filedeleted
+This event is triggered after deletion of each thumbnail file in the `initialPreview` content set. Additional parameters available are: 
+
+- `key`: the key passed within `initialPreviewConfig` for the selected file that will be passed as POST data to the `url`.
+- `jqXHR`: the `jQuery XMLHttpRequest` object used for this transaction (if available).
+- `data`: the output of `deleteExtraData` object.
+
+```js
+$('#input-id').on('filedeleted', function(event, key) {
+    console.log('Key = ' + key);
+});
+```
+
+```js
+$('#input-id').on('fileunlock', function(event, filestack) {
+    var fstack = filestack.filter(function(n){ return n != undefined });
+    console.log('Files selected - ' + fstack.length);
+});
+```
+
+#### filepreajax
+This event is triggered before submission of the upload ajax request. You could use this event to manipulate the `uploadExtraData` before its submitted via ajax. The following additional parameters are also available specifically and only if the upload is triggered via each thumbnail upload button.
+
+- `previewId`: the identifier of the preview thumbnail container.
+- `index`: the zero-based index of the file in the preview container.
+
+```js
+$('#input-id').on('filepreajax', function(event, previewId, index) {
+    console.log('File pre ajax triggered');
+});
+```
+
+#### filepreupload
+This event is triggered before upload of each thumbnail file. This event is triggered after `filepreajax` and within the ajax `beforeSend`. Additional parameters available are: 
+
+- `data`: This is a data object (associative array) that sends the following information, whose keys are:
+    - `form`: the FormData object which is passed via XHR2 (or empty object if not available).
+    - `files`: the file stack array (or empty object if not available).
+    - `extra`: the `uploadExtraData` settings for the plugin (or empty object if not available).
+    - `response`: the data sent via ajax response (or empty object if not available).
+    - `reader`: the FileReader instance if available
+    - `jqXHR`: the `jQuery XMLHttpRequest` object used for this transaction (if available).
+- `previewId`: the identifier of the preview thumbnail container.
+- `index`: the zero-based index of the file in the preview container.
+
+```js
+$('#input-id').on('filepreupload', function(event, data, previewId, index, jqXHR) {
+    var form = data.form, files = data.files, extra = data.extra, 
+        response = data.response, reader = data.reader;
+    console.log('File pre upload triggered');
+});
+```
+
+#### fileuploaded
+This event is triggered after upload is completed for each thumbnail file. Note this event is also triggered for 
+asynchronous batch uploads after each file in the selection is uploaded via ajax. Additional parameters available are: 
+
+- `data`: This is a data object (associative array) that sends the following information, whose keys are:
+    - `form`: the FormData object which is passed via XHR2 (or empty object if not available).
+    - `files`: the file stack array (or empty object if not available).
+    - `extra`: the `uploadExtraData` settings for the plugin (or empty object if not available).
+    - `response`: the data sent via ajax response (or empty object if not available).
+    - `reader`: the FileReader instance if available
+    - `jqXHR`: the `jQuery XMLHttpRequest` object used for this transaction (if available).
+- `previewId`: the identifier of each file's parent thumbnail div element in the preview window.
+- `index`: the zero-based index of the file in the file stack.
+
+```js
+$('#input-id').on('fileuploaded', function(event, data, previewId, index) {
+    var form = data.form, files = data.files, extra = data.extra, 
+        response = data.response, reader = data.reader;
+    console.log('File uploaded triggered');
+});
+```
+
+#### filebatchpreupload
+This event is triggered before a batch upload (for both synchronous and asynchronous uploads) after the upload button is clicked. 
+Additional parameters available are: 
+
+- `data`: This is a data object (associative array) that sends the following information, whose keys are:
+    - `form`: the FormData object which is passed via XHR2 (or empty object if not available).
+    - `files`: the file stack array (or empty object if not available).
+    - `extra`: the `uploadExtraData` settings for the plugin (or empty object if not available).
+    - `response`: the data sent via ajax response (or empty object if not available).
+    - `reader`: the FileReader instance if available
+    - `jqXHR`: the `jQuery XMLHttpRequest` object used for this transaction (if available).
+
+```js
+$('#input-id').on('filebatchpreupload', function(event, data, jqXHR) {
+    var form = data.form, files = data.files, extra = data.extra, 
+        response = data.response, reader = data.reader;
+    console.log('File batch pre upload triggered');
+});
+```
+
+#### filebatchuploadsuccess
+This event is triggered after a successful synchronous batch upload (i.e. when `uploadAsync` is `false`). Additional parameters available are: 
+
+- `data`: This is a data object (associative array) that sends the following information, whose keys are:
+    - `form`: the FormData object which is passed via XHR2 (or empty object if not available).
+    - `files`: the file stack array (or empty object if not available).
+    - `extra`: the `uploadExtraData` settings for the plugin (or empty object if not available).
+    - `response`: the data sent via ajax response (or empty object if not available).
+    - `reader`: the FileReader instance if available
+
+```js
+$('#input-id').on('filebatchuploadsuccess', function(event, data) {
+    var form = data.form, files = data.files, extra = data.extra, 
+        response = data.response, reader = data.reader;
+    console.log('File batch upload success');
+});
+```
+
+
+#### filebatchuploadcomplete
+This event is triggered after completion of either the synchronous OR asynchronous ajax batch upload. Additional parameters available are: 
+
+- `files`: the file stack array (or empty object if not available).
+- `extra`: the `uploadExtraData` settings for the plugin (or empty object if not available).
+
+```js
+$('#input-id').on('filebatchuploadcomplete', function(event, files, extra) {
+    console.log('File batch upload complete');
+});
+```
+
+#### filesuccessremove
+This event is triggered after a successfully uploaded thumbnail is removed using the thumbnail delete button. This is usually applicable when you have **showUploadedThumbs** set to `true`. Additional parameters available are: 
+
+- `id`: the HTML ID attribute for the thumbnail container element.
+
+The event can return `false` to abort the thumbnail removal.
+
+```js
+$('#input-id').on('filesuccessremove', function(event, id) {
+    if (some_processing_function(id)) {
+       console.log('Uploaded thumbnail successfully removed');
+    } else {
+        return false; // abort the thumbnail removal
+    }
+});
+```
+#### filedisabled
+This event is triggered when the file input widget is disabled (prevents any modification) using the `disable` method.
+
+```js
+$('#input-id').on('filedisabled', function(event) {
+    console.log('File disabled.');
+});
+```
+
+#### fileenabled
+This event is triggered when the file input widget is enabled (allows modification) using the `enable` method.
+
+```js
+$('#input-id').on('fileenabled', function(event) {
+    console.log('File enabled.');
+});
+```
+
+### Error Events
+
+#### fileerror
+This event is triggered when a client validation error is encountered for an uploaded file. This allows access to an object `data` as a parameter.
+
+- `data`: object/associative array containing the following 
+    - `id`: the preview thumbnail identifier (or undefined if not available)
+    - `index`: the file index/preview thumbnail index (or undefined if not available)
+    - `file`: the file object (or undefined if not available)
+    - `reader`: the file reader instance (or undefined if not available)
+    - `files`: the file stack array (or empty object if not available).
+
+**Example:**
+```js
+$('#input-id').on('fileerror', function(event, data) {
+   console.log(data.id);
+   console.log(data.index);
+   console.log(data.file);
+   console.log(data.reader);
+   console.log(data.files);
+});
+```
+
+#### fileuploaderror
+This event is triggered when an upload or file input validation error is encountered primarily for ajax uploads (through the upload icon for each thumbnail or for every file uploaded when uploadAsync is `true`). Additional parameters available are: 
+
+- `data`: This is a data object (associative array) that sends the following information, whose keys are:
+    - `id`: the preview thumbnail identifier (or undefined if not available)
+    - `index`: the file index/preview thumbnail index (or undefined if not available).
+    - `form`: the FormData object which is passed via XHR2 (or empty object if not available).
+    - `files`: the file stack array (or empty object if not available).
+    - `extra`: the `uploadExtraData` settings for the plugin (or empty object if not available).
+    - `response`: the data sent via ajax response (or empty object if not available).
+    - `reader`: the FileReader instance if available
+    - `jqXHR`: the `jQuery XMLHttpRequest` object used for this transaction (if available).
+
+```js
+$('#input-id').on('fileuploaderror', function(event, data, previewId, index) {
+    var form = data.form, files = data.files, extra = data.extra, 
+        response = data.response, reader = data.reader;
+    console.log('File upload error');
+});
+```
+
+#### filebatchuploaderror
+This event is triggered when any error is faced in the synchronous batch upload (i.e. when `uploadAsync` is `false`). Additional parameters available are: 
+
+- `data`: This is a data object (associative array) that sends the following information, whose keys are:
+    - `form`: the FormData object which is passed via XHR2 (or empty object if not available).
+    - `files`: the file stack array (or empty object if not available).
+    - `extra`: the `uploadExtraData` settings for the plugin (or empty object if not available).
+    - `response`: the data sent via ajax response (or empty object if not available).
+    - `reader`: the FileReader instance if available
+    - `jqXHR`: the `jQuery XMLHttpRequest` object used for this transaction (if available).
+
+```js
+$('#input-id').on('filebatchuploaderror', function(event, data) {
+    var form = data.form, files = data.files, extra = data.extra, 
+        response = data.response, reader = data.reader;
+    console.log('File upload error');
+});
+```
+
+#### filedeleteerror
+This event is triggered when an error is faced in deletion of each thumbnail file in the `initialPreview` content set. Additional parameters available are: 
+
+- `data`: This is a data object (associative array) that sends the following information, whose keys are:
+    - `id`: the preview thumbnail identifier (or undefined if not available)
+    - `index`: the file index/preview thumbnail index (or undefined if not available).
+    - `response`: the data sent via ajax response (or empty object if not available).
+    - `extra`: the output of `deleteExtraData` object.
+    - `jqXHR`: the `jQuery XMLHttpRequest` object used for this transaction (if available).
+
+```js
+$('#input-id').on('filedeleteerror', function(event, data) {
+    console.log('File delete error');
+});
+```
+
+#### filefoldererror
+This event is triggered when a folder or multiple folders have been dragged & dropped to the file preview drop zone. Additional parameters available are: 
+
+- `folders`: The count of folders dropped.
+
+```js
+$('#input-id').on('filefoldererror', function(event, folders) {
+    console.log('File folder dropped error');
+});
+```
+
+#### filecustomerror
+This event is triggered manually by the user from one of the other events by returning an error object from the source event. Refer **Event Manipulation** section for details. Additional parameters available are: 
+
+- `data`: This is a data object (associative array) that sends the following information, whose keys are:
+    - `form`: the FormData object which is passed via XHR2 (or empty object if not available).
+    - `response`: the aborted data sent when returned when triggering the validation error from the source event. 
+    - `files`: the file stack array (or empty object if not available).
+    - `extra`: the `uploadExtraData` settings for the plugin (or empty object if not available).
+    - `reader`: the FileReader instance if available
+    - `jqXHR`: the `jQuery XMLHttpRequest` object used for this transaction (an empty object usually).
+
+```js
+$("#input").on('filecustomerror', function(event, params) {
+   console.log(params.id);
+   console.log(params.index);
+   console.log(params.data);
+});
+```
+
+### Event Manipulation
+With release v4.1.8, you can return data for most of the events and use it for advanced processing. This functionality is not applicable for the following events.
+
+- `fileclear`
+- `filecleared`
+- `filereset`
+- `fileerror`
+- `fileuploaderror`
+- `filebatchuploaderror`
+- `filedeleteerror`
+- `filefoldererror`
+- `filecustomerror`
+- `fileuploaded`
+- `filebatchuploadcomplete`
+- `filebatchuploadsuccess`
+
+For all the events other than ones mentioned above, you can set a custom validation error which will be triggered just before upload is initiated.
+
+This will enable you to add your additional custom validations to enhance the fileinput to be used for innumerous scenarios. It will allow an ability to return an associative object with any of the fileinput events (except the events above) e.g. `change`, `fileselect`, `filepreupload`, `filebatchpreupload` etc.
+
+The object can return the following keys:
+
+- `message`: _string_, the validation error message to be displayed before upload. If this is set the plugin will automatically abort the upload whenever called and display this as an error message. You can use this property for example to read a file and perform your own custom validation.
+- `data`: _object_, an optional associative array of additional data at abort, that you can pass for usage later. 
+
+**Example**
+
+- **STEP 1:** You can trigger an error to abort from `filepreupload`
+
+```js
+$('#input').on('filepreupload', function(event, data, previewId, index, jqXHR) {
+    // do your validation and return an error like below
+    if (customValidationFailed) {
+       return {
+           message: 'You are not allowed to do that', 
+           data: {key1: 'Key 1', detail1: 'Detail 1'}
+       };
+   }
+});
+```
+The above abort will be triggered at time of upload for (ajax uploads) OR at form submission (for non-ajax uploads).
+
+- **STEP 2:** Reading additional data at abort by trapping the `filecustomerror` event
+
+```js
+$('#input').on('filecustomerror', function(event, params) {
+   // params.abortData will contain the additional abort data passed
+   // params.abortMessage will contain the aborted error message passed
+});
+```
+
+As mentioned before, the above functionality of raising a `filecustomerror` is not supported in the following events:
+
+- `fileclear`
+- `filecleared`
+- `filereset`
+- `fileerror`
+- `fileuploaderror`
+- `filebatchuploaderror`
+- `filedeleteerror`
+- `filecustomerror`
+- `fileuploaded`
+- `filebatchuploadcomplete`
+- `filebatchuploadsuccess`
+
+### 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
+$('#input-id').fileinput('reset');
+```
+
+### destroy
+Destroys the file input.
+```js
+$('#input-id').fileinput('destroy');
+```
+
+### refresh
+Refreshes the file input plugin based on options provided. You can supply an array of plugin options as a parameter.
+```js
+// example 1 (disable at runtime)
+$('#input-id').attr('disabled', 'disabled');
+$('#input-id').fileinput('refresh');
+
+// example 2 (modify plugin options at runtime)
+$('#input-id').fileinput('refresh', {browseLabel: 'Select...', removeLabel: 'Delete'});
+```
+
+### clear
+Clear the file input and all files from preview.
+```js
+$('#input-id').fileinput('clear');
+```
+
+### upload
+Trigger ajax upload of the files that are selected. Applicable only if `uploadUrl` is set.
+
+```js
+$('#input-id').fileinput('upload');
+```
+
+### cancel
+Cancel an ongoing ajax upload of the files.
+
+```js
+$('#input-id').fileinput('cancel');
+```
+
+### lock
+Locks the file input by disabling all actions/buttons except a cancel button to abort ongoing AJAX requests (for ajax uploads only).
+
+```js
+$('#input-id').fileinput('lock');
+```
+
+### unlock
+Unlocks and enables the file input back again by reversing the outcome of the `lock` action.
+
+```js
+$('#input-id').fileinput('unlock');
+```
+
+## License
+
+**bootstrap-fileinput** is released under the BSD 3-Clause License. See the bundled `LICENSE.md` for details.

+ 39 - 39
bower.json

@@ -1,40 +1,40 @@
-{
-    "name": "bootstrap-fileinput",
-    "version": "4.2.5",
-    "homepage": "https://github.com/kartik-v/bootstrap-fileinput",
-    "authors": [
-        "Kartik Visweswaran <[email protected]>"
-    ],
-    "description": "An enhanced HTML 5 file input for Bootstrap 3.x with file preview, multiple selection, ajax uploads, and more features.",
-    "main": [
-        "./css/fileinput.min.css",
-        "./js/fileinput.min.js"
-    ],
-    "keywords": [
-        "bootstrap",
-        "file",
-        "input",
-        "preview",
-        "image",
-        "upload",
-        "ajax",
-        "multiple",
-        "delete",
-        "progress",
-        "gallery"
-    ],
-    "dependencies": {
-        "jquery": ">= 1.9.0",
-        "bootstrap": ">= 3.0.0"
-    },
-    "license": "BSD-3-Clause",
-    "ignore": [
-        "**/.*",
-        "node_modules",
-        "composer.json",
-        "examples",
-        "bower_components",
-        "test",
-        "tests"
-    ]
+{
+    "name": "bootstrap-fileinput",
+    "version": "4.2.6",
+    "homepage": "https://github.com/kartik-v/bootstrap-fileinput",
+    "authors": [
+        "Kartik Visweswaran <[email protected]>"
+    ],
+    "description": "An enhanced HTML 5 file input for Bootstrap 3.x with file preview, multiple selection, ajax uploads, and more features.",
+    "main": [
+        "./css/fileinput.min.css",
+        "./js/fileinput.min.js"
+    ],
+    "keywords": [
+        "bootstrap",
+        "file",
+        "input",
+        "preview",
+        "image",
+        "upload",
+        "ajax",
+        "multiple",
+        "delete",
+        "progress",
+        "gallery"
+    ],
+    "dependencies": {
+        "jquery": ">= 1.9.0",
+        "bootstrap": ">= 3.0.0"
+    },
+    "license": "BSD-3-Clause",
+    "ignore": [
+        "**/.*",
+        "node_modules",
+        "composer.json",
+        "examples",
+        "bower_components",
+        "test",
+        "tests"
+    ]
 }
 }

+ 18 - 18
composer.json

@@ -1,19 +1,19 @@
-{
-    "name": "kartik-v/bootstrap-fileinput",
-    "description": "An enhanced HTML 5 file input for Bootstrap 3.x with features for file preview for many file types, multiple selection, ajax uploads, and more.",
-    "keywords": ["bootstrap", "jquery", "file", "input", "preview", "upload", "image", "multiple", "ajax", "delete", "progress"],
-    "homepage": "https://github.com/kartik-v/bootstrap-fileinput",
-    "license": "BSD-3-Clause",
-    "authors": [
-        {
-            "name": "Kartik Visweswaran",
-            "email": "[email protected]",
-            "homepage": "http://www.krajee.com/"
-        }
-    ],
-    "autoload": {
-        "psr-4": {
-            "kartik\\plugins\\fileinput\\": ""
-        }
-    }
+{
+    "name": "kartik-v/bootstrap-fileinput",
+    "description": "An enhanced HTML 5 file input for Bootstrap 3.x with features for file preview for many file types, multiple selection, ajax uploads, and more.",
+    "keywords": ["bootstrap", "jquery", "file", "input", "preview", "upload", "image", "multiple", "ajax", "delete", "progress"],
+    "homepage": "https://github.com/kartik-v/bootstrap-fileinput",
+    "license": "BSD-3-Clause",
+    "authors": [
+        {
+            "name": "Kartik Visweswaran",
+            "email": "[email protected]",
+            "homepage": "http://www.krajee.com/"
+        }
+    ],
+    "autoload": {
+        "psr-4": {
+            "kartik\\plugins\\fileinput\\": ""
+        }
+    }
 }
 }

+ 229 - 229
css/fileinput.css

@@ -1,230 +1,230 @@
-/*!
- * @copyright Copyright &copy; Kartik Visweswaran, Krajee.com, 2014 - 2015
- * @package bootstrap-fileinput
- * @version 4.2.5
- *
- * File input styling for Bootstrap 3.0
- * Built for Yii Framework 2.0
- * Author: Kartik Visweswaran
- * Year: 2015
- * 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%;
-    text-align: right;
-    opacity: 0;
-    filter: alpha(opacity=0);
-    opacity: 0;
-    background: none repeat scroll 0 0 transparent;
-    cursor: inherit;
-    display: block;
-}
-
-.file-caption .glyphicon {
-    display: inline-block;
-    min-width: 18px;
-    margin-top: 2px;
-}
-
-.file-caption-name {
-    display: inline-block;
-    overflow: hidden;
-    padding-right: 10px;
-    word-break: break-all;
-}
-
-.file-caption-ellipsis {
-    position: absolute;
-    right: 10px;
-    margin-top: -6px;
-    font-size: 1.2em;
-    display: none;
-    font-weight: bold;
-    cursor: default;
-}
-
-.kv-has-ellipsis .file-caption-ellipsis {
-    display: inline;
-}
-
-.kv-has-ellipsis {
-    padding-right: 17px;
-}
-
-.kv-search-container .kv-search-clear {
-    position: absolute;
-    padding: 10px;
-    right: 0px;
-}
-
-.file-error-message {
-    background-color: #f2dede;
-    color: #a94442;
-    text-align: center;
-    border-radius: 5px;
-    padding: 5px;
-}
-
-.file-error-message pre, .file-error-message ul {
-    margin: 5px 0;
-    text-align: left;
-}
-
-.file-caption-disabled {
-    background-color: #EEEEEE;
-    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 0px #a2958a;
-    padding: 6px;
-    float: left;
-    text-align: center;
-    vertical-align: middle;
-}
-
-.file-preview-frame:hover {
-    box-shadow: 3px 3px 5px 0px #333;
-}
-
-.file-preview-image {
-    height: 160px;
-    vertical-align: text-center;
-}
-
-.file-preview-text {
-    width: 160px;
-    color: #428bca;
-    font-size: 11px;
-    text-align: center;
-}
-
-.file-preview-other {
-    padding-top: 48px;
-    text-align: center;
-}
-
-.file-preview-other i {
-    font-size: 2.4em;
-}
-
-.file-other-error {
-    width: 100%;
-    padding-top: 30px;
-    text-align: right
-}
-
-.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 {
-    display: none;
-}
-
-.loading {
-    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;
-}
-
-.file-footer-buttons {
-    float: right;
-}
-
-.file-thumbnail-footer .file-caption-name {
-    padding-top: 4px;
-    font-size: 11px;
-    color: #777;
-}
-
-.file-upload-indicator {
-    padding-top: 2px;
-    cursor: default;
-}
-
-.file-upload-indicator:hover {
-    font-size: 1.2em;
-    font-weight: bold;
-    padding-top: 0;
-}
-
-.file-drop-zone {
-    border: 1px dashed #aaa;
-    border-radius: 4px;
-    height: 100%;
-    text-align: center;
-    vertical-align: middle;
-    margin: 12px 15px 12px 12px;
-    padding: 5px;
-}
-
-.file-drop-zone-title {
-    color: #aaa;
-    font-size: 40px;
-    padding: 85px 10px;
-}
-
-.highlighted {
-    border: 2px dashed #999 !important;
-    background-color: #f0f0f0;
-}
-
-.file-uploading {
-    background-image: url('../img/loading-sm.gif');
-    background-position: center bottom 10px;
-    background-repeat: no-repeat;
-    opacity: 0.6;
-}
-
-.file-icon-large {
-    font-size: 1.2em;
+/*!
+ * @copyright Copyright &copy; Kartik Visweswaran, Krajee.com, 2014 - 2015
+ * @package bootstrap-fileinput
+ * @version 4.2.6
+ *
+ * File input styling for Bootstrap 3.0
+ * Built for Yii Framework 2.0
+ * Author: Kartik Visweswaran
+ * Year: 2015
+ * 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%;
+    text-align: right;
+    opacity: 0;
+    filter: alpha(opacity=0);
+    opacity: 0;
+    background: none repeat scroll 0 0 transparent;
+    cursor: inherit;
+    display: block;
+}
+
+.file-caption .glyphicon {
+    display: inline-block;
+    min-width: 18px;
+    margin-top: 2px;
+}
+
+.file-caption-name {
+    display: inline-block;
+    overflow: hidden;
+    padding-right: 10px;
+    word-break: break-all;
+}
+
+.file-caption-ellipsis {
+    position: absolute;
+    right: 10px;
+    margin-top: -6px;
+    font-size: 1.2em;
+    display: none;
+    font-weight: bold;
+    cursor: default;
+}
+
+.kv-has-ellipsis .file-caption-ellipsis {
+    display: inline;
+}
+
+.kv-has-ellipsis {
+    padding-right: 17px;
+}
+
+.kv-search-container .kv-search-clear {
+    position: absolute;
+    padding: 10px;
+    right: 0px;
+}
+
+.file-error-message {
+    background-color: #f2dede;
+    color: #a94442;
+    text-align: center;
+    border-radius: 5px;
+    padding: 5px;
+}
+
+.file-error-message pre, .file-error-message ul {
+    margin: 5px 0;
+    text-align: left;
+}
+
+.file-caption-disabled {
+    background-color: #EEEEEE;
+    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 0px #a2958a;
+    padding: 6px;
+    float: left;
+    text-align: center;
+    vertical-align: middle;
+}
+
+.file-preview-frame:hover {
+    box-shadow: 3px 3px 5px 0px #333;
+}
+
+.file-preview-image {
+    height: 160px;
+    vertical-align: text-center;
+}
+
+.file-preview-text {
+    width: 160px;
+    color: #428bca;
+    font-size: 11px;
+    text-align: center;
+}
+
+.file-preview-other {
+    padding-top: 48px;
+    text-align: center;
+}
+
+.file-preview-other i {
+    font-size: 2.4em;
+}
+
+.file-other-error {
+    width: 100%;
+    padding-top: 30px;
+    text-align: right
+}
+
+.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 {
+    display: none;
+}
+
+.loading {
+    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;
+}
+
+.file-footer-buttons {
+    float: right;
+}
+
+.file-thumbnail-footer .file-caption-name {
+    padding-top: 4px;
+    font-size: 11px;
+    color: #777;
+}
+
+.file-upload-indicator {
+    padding-top: 2px;
+    cursor: default;
+}
+
+.file-upload-indicator:hover {
+    font-size: 1.2em;
+    font-weight: bold;
+    padding-top: 0;
+}
+
+.file-drop-zone {
+    border: 1px dashed #aaa;
+    border-radius: 4px;
+    height: 100%;
+    text-align: center;
+    vertical-align: middle;
+    margin: 12px 15px 12px 12px;
+    padding: 5px;
+}
+
+.file-drop-zone-title {
+    color: #aaa;
+    font-size: 40px;
+    padding: 85px 10px;
+}
+
+.highlighted {
+    border: 2px dashed #999 !important;
+    background-color: #f0f0f0;
+}
+
+.file-uploading {
+    background-image: url('../img/loading-sm.gif');
+    background-position: center bottom 10px;
+    background-repeat: no-repeat;
+    opacity: 0.6;
+}
+
+.file-icon-large {
+    font-size: 1.2em;
 }
 }

ファイルの差分が大きいため隠しています
+ 10 - 10
css/fileinput.min.css


+ 1 - 1
examples/index.html

@@ -1,5 +1,5 @@
 <!DOCTYPE html>
 <!DOCTYPE html>
-<!-- release v4.2.5, copyright 2014 - 2015 Kartik Visweswaran -->
+<!-- release v4.2.6, copyright 2014 - 2015 Kartik Visweswaran -->
 <html lang="en">
 <html lang="en">
     <head>
     <head>
         <meta charset="UTF-8"/>
         <meta charset="UTF-8"/>

+ 2303 - 2303
js/fileinput.js

@@ -1,2304 +1,2304 @@
-/*!
- * @copyright Copyright &copy; Kartik Visweswaran, Krajee.com, 2014 - 2015
- * @version 4.2.5
- *
- * 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. It also offers the ability to upload and delete files using AJAX, and add 
- * files in batches (i.e. preview, append, or remove before upload).
- * 
- * Author: Kartik Visweswaran
- * Copyright: 2015, Kartik Visweswaran, Krajee.com
- * For more JQuery plugins visit http://plugins.krajee.com
- * For more Yii related demos visit http://demos.krajee.com
- */
-(function ($) {
-    "use strict";
-
-    $.fn.fileinputLocales = {};
-
-    String.prototype.repl = function (from, to) {
-        return this.split(from).join(to);
-    };
-    var isIE = function (ver) {
-            var div = document.createElement("div"), status;
-            div.innerHTML = "<!--[if IE " + ver + "]><i></i><![endif]-->";
-            status = (div.getElementsByTagName("i").length === 1);
-            document.body.appendChild(div);
-            div.parentNode.removeChild(div);
-            return status;
-        },
-        handler = function ($el, event, callback, skipNS) {
-            var ev = skipNS ? event : event + '.fileinput';
-            $el.off(ev).on(ev, callback);
-        },
-        previewCache = {
-            data: {},
-            init: function (obj) {
-                var content = obj.initialPreview, id = obj.id;
-                if (content.length > 0 && !isArray(content)) {
-                    content = content.split(obj.initialPreviewDelimiter);
-                }
-                previewCache.data[id] = {
-                    content: content,
-                    config: obj.initialPreviewConfig,
-                    tags: obj.initialPreviewThumbTags,
-                    delimiter: obj.initialPreviewDelimiter,
-                    template: obj.previewGenericTemplate,
-                    msg: function (n) {
-                        return obj.getMsgSelected(n);
-                    },
-                    initId: obj.previewInitId,
-                    footer: obj.getLayoutTemplate('footer'),
-                    isDelete: obj.initialPreviewShowDelete,
-                    caption: obj.initialCaption,
-                    actions: function (showUpload, showDelete, disabled, url, key) {
-                        return obj.renderFileActions(showUpload, showDelete, disabled, url, key);
-                    }
-                };
-            },
-            fetch: function (id) {
-                return previewCache.data[id].content.filter(function (n) {
-                    return n !== null;
-                });
-            },
-            count: function (id, all) {
-                return !!previewCache.data[id] && !!previewCache.data[id].content ?
-                    (all ? previewCache.data[id].content.length : previewCache.fetch(id).length) : 0;
-            },
-            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';
-                isDisabled = isDisabled === undefined ? true : isDisabled;
-                if (data.content[i] === null) {
-                    return '';
-                }
-                if (!isEmpty(config) && !isEmpty(config.frameClass)) {
-                    frameClass += ' ' + config.frameClass;
-                }
-                out = data.template
-                    .repl('{previewId}', previewId)
-                    .repl('{frameClass}', frameClass)
-                    .repl('{fileindex}', ind)
-                    .repl('{content}', data.content[i])
-                    .repl('{footer}', previewCache.footer(id, i, isDisabled));
-                if (data.tags.length && data.tags[i]) {
-                    out = replaceTags(out, data.tags[i]);
-                }
-                if (!isEmpty(config) && !isEmpty(config.frameAttr)) {
-                    $tmp = $(document.createElement('div')).html(out);
-                    $tmp.find('.file-preview-initial').attr(config.frameAttr);
-                    out = $tmp.html();
-                    $tmp.remove();
-                }
-                return out;
-            },
-            add: function (id, content, config, tags, append) {
-                var data = $.extend(true, {}, previewCache.data[id]), index;
-                if (!isArray(content)) {
-                    content = content.split(data.delimiter);
-                }
-                if (append) {
-                    index = data.content.push(content) - 1;
-                    data.config[index] = config;
-                    data.tags[index] = tags;
-                } else {
-                    index = content.length;
-                    data.content = content;
-                    data.config = config;
-                    data.tags = tags;
-                }
-                previewCache.data[id] = data;
-                return index;
-            },
-            set: function (id, content, config, tags, append) {
-                var data = $.extend(true, {}, previewCache.data[id]), i;
-                if (!isArray(content)) {
-                    content = content.split(data.delimiter);
-                }
-                if (append) {
-                    for (i = 0; i < content.length; i++) {
-                        data.content.push(content[i]);
-                    }
-                    for (i = 0; i < config.length; i++) {
-                        data.config.push(config[i]);
-                    }
-                    for (i = 0; i < tags.length; i++) {
-                        data.tags.push(tags[i]);
-                    }
-                } else {
-                    data.content = content;
-                    data.config = config;
-                    data.tags = tags;
-                }
-                previewCache.data[id] = data;
-            },
-            unset: function (id, index) {
-                var chk = previewCache.count(id);
-                if (!chk) {
-                    return;
-                }
-                if (chk === 1) {
-                    previewCache.data[id].content = [];
-                    previewCache.data[id].config = [];
-                    return;
-                }
-                previewCache.data[id].content[index] = null;
-                previewCache.data[id].config[index] = null;
-            },
-            out: function (id) {
-                var html = '', data = previewCache.data[id], caption, len = previewCache.count(id, true);
-                if (len === 0) {
-                    return {content: '', caption: ''};
-                }
-                for (var i = 0; i < len; i++) {
-                    html += previewCache.get(id, i);
-                }
-                caption = data.msg(previewCache.count(id));
-                return {content: html, caption: caption};
-            },
-            footer: function (id, i, isDisabled) {
-                var data = previewCache.data[id];
-                isDisabled = isDisabled === undefined ? true : isDisabled;
-                if (data.config.length === 0 || isEmpty(data.config[i])) {
-                    return '';
-                }
-                var config = data.config[i],
-                    caption = isSet('caption', config) ? config.caption : '',
-                    width = isSet('width', config) ? config.width : 'auto',
-                    url = isSet('url', config) ? config.url : false,
-                    key = isSet('key', config) ? config.key : null,
-                    disabled = (url === false) && isDisabled,
-                    actions = data.isDelete ? data.actions(false, true, disabled, url, key) : '',
-                    footer = data.footer.repl('{actions}', actions);
-                return footer
-                    .repl('{caption}', caption)
-                    .repl('{width}', width)
-                    .repl('{indicator}', '')
-                    .repl('{indicatorTitle}', '');
-            }
-        },
-        getNum = function (num, def) {
-            def = def || 0;
-            if (typeof num === "number") {
-                return num;
-            }
-            if (typeof num === "string") {
-                num = parseFloat(num);
-            }
-            return isNaN(num) ? def : num;
-        },
-        hasFileAPISupport = function () {
-            return window.File && window.FileReader;
-        },
-        hasDragDropSupport = function () {
-            var $div = document.createElement('div');
-            return !isIE(9) && ($div.draggable !== undefined || ($div.ondragstart !== undefined && $div.ondrop !== undefined));
-        },
-        hasFileUploadSupport = function () {
-            return hasFileAPISupport() && window.FormData;
-        },
-        addCss = function ($el, css) {
-            $el.removeClass(css).addClass(css);
-        },
-        STYLE_SETTING = 'style="width:{width};height:{height};"',
-        OBJECT_PARAMS = '      <param name="controller" value="true" />\n' +
-            '      <param name="allowFullScreen" value="true" />\n' +
-            '      <param name="allowScriptAccess" value="always" />\n' +
-            '      <param name="autoPlay" value="false" />\n' +
-            '      <param name="autoStart" value="false" />\n' +
-            '      <param name="quality" value="high" />\n',
-        DEFAULT_PREVIEW = '<div class="file-preview-other">\n' +
-            '       {previewFileIcon}\n' +
-            '   </div>',
-        defaultFileActionSettings = {
-            removeIcon: '<i class="glyphicon glyphicon-trash text-danger"></i>',
-            removeClass: 'btn btn-xs btn-default',
-            removeTitle: 'Remove file',
-            uploadIcon: '<i class="glyphicon glyphicon-upload text-info"></i>',
-            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>',
-            indicatorError: '<i class="glyphicon glyphicon-exclamation-sign text-danger"></i>',
-            indicatorLoading: '<i class="glyphicon glyphicon-hand-up text-muted"></i>',
-            indicatorNewTitle: 'Not uploaded yet',
-            indicatorSuccessTitle: 'Uploaded',
-            indicatorErrorTitle: 'Upload Error',
-            indicatorLoadingTitle: 'Uploading ...'
-        },
-        tMain1 = '{preview}\n' +
-            '<div class="kv-upload-progress hide"></div>\n' +
-            '<div class="input-group {class}">\n' +
-            '   {caption}\n' +
-            '   <div class="input-group-btn">\n' +
-            '       {remove}\n' +
-            '       {cancel}\n' +
-            '       {upload}\n' +
-            '       {browse}\n' +
-            '   </div>\n' +
-            '</div>',
-        tMain2 = '{preview}\n<div class="kv-upload-progress hide"></div>\n{remove}\n{cancel}\n{upload}\n{browse}\n',
-        tPreview = '<div class="file-preview {class}">\n' +
-            '    <div class="close fileinput-remove">&times;</div>\n' +
-            '    <div class="{dropClass}">\n' +
-            '    <div class="file-preview-thumbnails">\n' +
-            '    </div>\n' +
-            '    <div class="clearfix"></div>' +
-            '    <div class="file-preview-status text-center text-success"></div>\n' +
-            '    <div class="kv-fileinput-error"></div>\n' +
-            '    </div>\n' +
-            '</div>',
-        tIcon = '<span class="glyphicon glyphicon-file kv-caption-icon"></span>',
-        tCaption = '<div tabindex="-1" class="form-control file-caption {class}">\n' +
-            '   <span class="file-caption-ellipsis">&hellip;</span>\n' +
-            '   <div class="file-caption-name"></div>\n' +
-            '</div>',
-        tModal = '<div id="{id}" class="modal fade">\n' +
-            '  <div class="modal-dialog modal-lg">\n' +
-            '    <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' +
-            '      </div>\n' +
-            '      <div class="modal-body">\n' +
-            '        <textarea class="form-control" style="font-family:Monaco,Consolas,monospace; height: {height}px;" readonly>{body}</textarea>\n' +
-            '      </div>\n' +
-            '    </div>\n' +
-            '  </div>\n' +
-            '</div>',
-        tProgress = '<div class="progress">\n' +
-            '    <div class="{class}" role="progressbar"' +
-            ' aria-valuenow="{percent}" aria-valuemin="0" aria-valuemax="100" style="width:{percent}%;">\n' +
-            '        {percent}%\n' +
-            '     </div>\n' +
-            '</div>',
-        tFooter = '<div class="file-thumbnail-footer">\n' +
-            '    <div class="file-caption-name">{caption}</div>\n' +
-            '    {actions}\n' +
-            '</div>',
-        tActions = '<div class="file-actions">\n' +
-            '    <div class="file-footer-buttons">\n' +
-            '        {upload}{delete}{other}' +
-            '    </div>\n' +
-            '    <div class="file-upload-indicator" tabindex="-1" title="{indicatorTitle}">{indicator}</div>\n' +
-            '    <div class="clearfix"></div>\n' +
-            '</div>',
-        tActionDelete = '<button type="button" class="kv-file-remove {removeClass}" ' +
-            'title="{removeTitle}"{dataUrl}{dataKey}>{removeIcon}</button>\n',
-        tActionUpload = '<button type="button" class="kv-file-upload {uploadClass}" title="{uploadTitle}">' +
-            '   {uploadIcon}\n</button>\n',
-        tGeneric = '<div class="file-preview-frame{frameClass}" id="{previewId}" data-fileindex="{fileindex}">\n' +
-            '   {content}\n' +
-            '   {footer}\n' +
-            '</div>\n',
-        tHtml = '<div class="file-preview-frame{frameClass}" id="{previewId}" data-fileindex="{fileindex}">\n' +
-            '    <object data="{data}" type="{type}" width="{width}" height="{height}">\n' +
-            '       ' + DEFAULT_PREVIEW + '\n' +
-            '    </object>\n' +
-            '   {footer}\n' +
-            '</div>',
-        tImage = '<div class="file-preview-frame{frameClass}" id="{previewId}" data-fileindex="{fileindex}">\n' +
-            '   <img src="{data}" class="file-preview-image" title="{caption}" alt="{caption}" ' + STYLE_SETTING + '>\n' +
-            '   {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' +
-            '   {footer}\n' +
-            '</div>',
-        tVideo = '<div class="file-preview-frame{frameClass}" id="{previewId}" data-fileindex="{fileindex}"' +
-            ' title="{caption}" ' + STYLE_SETTING + '>\n' +
-            '   <video width="{width}" height="{height}" controls>\n' +
-            '       <source src="{data}" type="{type}">\n' +
-            '       ' + DEFAULT_PREVIEW + '\n' +
-            '   </video>\n' +
-            '   {footer}\n' +
-            '</div>\n',
-        tAudio = '<div class="file-preview-frame{frameClass}" id="{previewId}" data-fileindex="{fileindex}"' +
-            ' title="{caption}" ' + STYLE_SETTING + '>\n' +
-            '   <audio controls>\n' +
-            '       <source src="' + '{data}' + '" type="{type}">\n' +
-            '       ' + DEFAULT_PREVIEW + '\n' +
-            '   </audio>\n' +
-            '   {footer}\n' +
-            '</div>',
-        tFlash = '<div class="file-preview-frame{frameClass}" id="{previewId}" data-fileindex="{fileindex}"' +
-            ' title="{caption}" ' + STYLE_SETTING + '>\n' +
-            '   <object type="application/x-shockwave-flash" width="{width}" height="{height}" data="{data}">\n' +
-            OBJECT_PARAMS + '       ' + DEFAULT_PREVIEW + '\n' +
-            '   </object>\n' +
-            '   {footer}\n' +
-            '</div>\n',
-        tObject = '<div class="file-preview-frame{frameClass}" id="{previewId}" data-fileindex="{fileindex}"' +
-            ' title="{caption}" ' + STYLE_SETTING + '>\n' +
-            '   <object data="{data}" type="{type}" width="{width}" height="{height}">\n' +
-            '       <param name="movie" value="{caption}" />\n' +
-            OBJECT_PARAMS + '         ' + DEFAULT_PREVIEW + '\n' +
-            '   </object>\n' +
-            '   {footer}\n' +
-            '</div>',
-        tOther = '<div class="file-preview-frame{frameClass}" id="{previewId}" data-fileindex="{fileindex}"' +
-            ' title="{caption}" ' + STYLE_SETTING + '>\n' +
-            '   ' + DEFAULT_PREVIEW + '\n' +
-            '   {footer}\n' +
-            '</div>',
-        defaultLayoutTemplates = {
-            main1: tMain1,
-            main2: tMain2,
-            preview: tPreview,
-            icon: tIcon,
-            caption: tCaption,
-            modal: tModal,
-            progress: tProgress,
-            footer: tFooter,
-            actions: tActions,
-            actionDelete: tActionDelete,
-            actionUpload: tActionUpload
-        },
-        defaultPreviewTemplates = {
-            generic: tGeneric,
-            html: tHtml,
-            image: tImage,
-            text: tText,
-            video: tVideo,
-            audio: tAudio,
-            flash: tFlash,
-            object: tObject,
-            other: tOther
-        },
-        defaultPreviewTypes = ['image', 'html', 'text', 'video', 'audio', 'flash', 'object'],
-        defaultPreviewSettings = {
-            image: {width: "auto", height: "160px"},
-            html: {width: "213px", height: "160px"},
-            text: {width: "160px", height: "160px"},
-            video: {width: "213px", height: "160px"},
-            audio: {width: "213px", height: "80px"},
-            flash: {width: "213px", height: "160px"},
-            object: {width: "160px", height: "160px"},
-            other: {width: "160px", height: "160px"}
-        },
-        defaultFileTypeSettings = {
-            image: function (vType, vName) {
-                return (vType !== undefined) ? vType.match('image.*') : vName.match(/\.(gif|png|jpe?g)$/i);
-            },
-            html: function (vType, vName) {
-                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);
-            },
-            video: function (vType, vName) {
-                return (vType !== undefined && vType.match(/\.video\/(ogg|mp4|webm)$/i)) || vName.match(/\.(og?|mp4|webm)$/i);
-            },
-            audio: function (vType, vName) {
-                return (vType !== undefined && vType.match(/\.audio\/(ogg|mp3|wav)$/i)) || vName.match(/\.(ogg|mp3|wav)$/i);
-            },
-            flash: function (vType, vName) {
-                return (vType !== undefined && vType === 'application/x-shockwave-flash') || vName.match(/\.(swf)$/i);
-            },
-            object: function () {
-                return true;
-            },
-            other: function () {
-                return true;
-            }
-        },
-        isEmpty = function (value, trim) {
-            return value === null || value === undefined || value.length === 0 || (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);
-        },
-        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));
-        },
-        htmlEncode = function (str) {
-            return String(str).repl('&', '&amp;')
-                .repl('"', '&quot;')
-                .repl("'", '&#39;')
-                .repl('<', '&lt;')
-                .repl('>', '&gt;');
-        },
-        replaceTags = function (str, tags) {
-            var out = str;
-            tags = tags || {};
-            $.each(tags, function (key, value) {
-                if (typeof value === "function") {
-                    value = value();
-                }
-                out = out.repl(key, value);
-            });
-            return out;
-        },
-        objUrl = window.URL || window.webkitURL,
-        FileInput = function (element, options) {
-            var self = this;
-            self.$element = $(element);
-            if (!self.validate()) {
-                return;
-            }
-            self.isPreviewable = hasFileAPISupport();
-            self.isIE9 = isIE(9);
-            self.isIE10 = isIE(10);
-            if (self.isPreviewable || self.isIE9) {
-                self.init(options);
-                self.listen();
-            } else {
-                self.$element.removeClass('file-loading');
-            }
-        };
-
-    FileInput.prototype = {
-        constructor: FileInput,
-        validate: function () {
-            var self = this, $exception;
-            if (self.$element.attr('type') === 'file') {
-                return true;
-            }
-            $exception = '<div class="help-block alert alert-warning">' +
-            '<h4>Invalid Input Type</h4>' +
-            'You must set an input <code>type = file</code> for <b>bootstrap-fileinput</b> plugin to initialize.' +
-            '</div>';
-            self.$element.after($exception);
-            return false;
-        },
-        init: function (options) {
-            var self = this, $el = self.$element, t;
-            $.each(options, function (key, value) {
-                self[key] = (key === 'maxFileCount' || key === 'maxFileSize') ? getNum(value) : value;
-            });
-            self.fileInputCleared = false;
-            self.fileBatchCompleted = true;
-            if (isEmpty(self.allowedPreviewTypes)) {
-                self.allowedPreviewTypes = defaultPreviewTypes;
-            }
-            if (!self.isPreviewable) {
-                self.showPreview = false;
-            }
-            self.uploadFileAttr = !isEmpty($el.attr('name')) ? $el.attr('name') : 'file_data';
-            self.reader = null;
-            self.formdata = {};
-            self.filestack = [];
-            self.ajaxRequests = [];
-            self.isError = false;
-            self.ajaxAborted = false;
-            self.dropZoneEnabled = hasDragDropSupport() && self.dropZoneEnabled;
-            self.isDisabled = self.$element.attr('disabled') || self.$element.attr('readonly');
-            self.isUploadable = hasFileUploadSupport() && !isEmpty(self.uploadUrl);
-            self.slug = typeof options.slugCallback === "function" ? options.slugCallback : self.slugDefault;
-            self.mainTemplate = self.showCaption ? self.getLayoutTemplate('main1') : self.getLayoutTemplate('main2');
-            self.captionTemplate = self.getLayoutTemplate('caption');
-            self.previewGenericTemplate = self.getPreviewTemplate('generic');
-            if (isEmpty(self.$element.attr('id'))) {
-                self.$element.attr('id', uniqId());
-            }
-            if (self.$container === undefined) {
-                self.$container = self.createContainer();
-            } else {
-                self.refreshContainer();
-            }
-            self.$progress = self.$container.find('.kv-upload-progress');
-            self.$btnUpload = self.$container.find('.kv-fileinput-upload');
-            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'));
-            if (!isEmpty(self.msgErrorClass)) {
-                addCss(self.$errorContainer, self.msgErrorClass);
-            }
-            self.$errorContainer.hide();
-            self.fileActionSettings = $.extend(defaultFileActionSettings, options.fileActionSettings);
-            self.previewInitId = "preview-" + uniqId();
-            self.id = self.$element.attr('id');
-            previewCache.init(self);
-            self.initPreview(true);
-            self.initPreviewDeletes();
-            self.options = options;
-            self.setFileDropZoneTitle();
-            self.uploadCount = 0;
-            self.uploadPercent = 0;
-            self.$element.removeClass('file-loading');
-            t = self.getLayoutTemplate('progress');
-            self.progressTemplate = t.replace('{class}', self.progressClass);
-            self.progressCompleteTemplate = t.replace('{class}', self.progressCompleteClass);
-            self.setEllipsis();
-        },
-        parseError: function (jqXHR, errorThrown, fileName) {
-            var self = this, errMsg = $.trim(errorThrown + ''),
-                dot = errMsg.slice(-1) === '.' ? '' : '.',
-                text = jqXHR.responseJSON !== undefined && jqXHR.responseJSON.error !== undefined ?
-                    jqXHR.responseJSON.error : jqXHR.responseText;
-            if (self.showAjaxErrorDetails) {
-                text = $.trim(text.replace(/\n\s*\n/g, '\n'));
-                text = text.length > 0 ? '<pre>' + text + '</pre>' : '';
-                errMsg += dot + text;
-            } else {
-                errMsg += dot;
-            }
-            return fileName ? '<b>' + fileName + ': </b>' + jqXHR : errMsg;
-        },
-        raise: function (event, params) {
-            var self = this, e = $.Event(event);
-            if (params !== undefined) {
-                self.$element.trigger(e, params);
-            } else {
-                self.$element.trigger(e);
-            }
-            if (!e.result) {
-                return e.result;
-            }
-            switch (event) {
-                // ignore these events
-                case 'filebatchuploadcomplete':
-                case 'filebatchuploadsuccess':
-                case 'fileuploaded':
-                case 'fileclear':
-                case 'filecleared':
-                case 'filereset':
-                case 'fileerror':
-                case 'filefoldererror':
-                case 'fileuploaderror':
-                case 'filebatchuploaderror':
-                case 'filedeleteerror':
-                case 'filecustomerror':
-                case 'filesuccessremove':
-                    break;
-                // receive data response via `filecustomerror` event`
-                default:
-                    self.ajaxAborted = e.result;
-                    break;
-            }
-            return true;
-        },
-        getLayoutTemplate: function (t) {
-            var self = this,
-                template = isSet(t, self.layoutTemplates) ? self.layoutTemplates[t] : defaultLayoutTemplates[t];
-            if (isEmpty(self.customLayoutTags)) {
-                return template;
-            }
-            return replaceTags(template, self.customLayoutTags);
-        },
-        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);
-        },
-        getOutData: function (jqXHR, responseData, filesData) {
-            var self = this;
-            jqXHR = jqXHR || {};
-            responseData = responseData || {};
-            filesData = filesData || self.filestack.slice(0) || {};
-            return {
-                form: self.formdata,
-                files: filesData,
-                extra: self.getExtraData(),
-                response: responseData,
-                reader: self.reader,
-                jqXHR: jqXHR
-            };
-        },
-        setEllipsis: function () {
-            var self = this, $capCont = self.$captionContainer, $cap = self.$caption,
-                $div = $cap.clone().css('height', 'auto').hide();
-            $capCont.parent().before($div);
-            $capCont.removeClass('kv-has-ellipsis');
-            if ($div.outerWidth() > $cap.outerWidth()) {
-                $capCont.addClass('kv-has-ellipsis');
-            }
-            $div.remove();
-        },
-        listen: function () {
-            var self = this, $el = self.$element, $cap = self.$captionContainer, $btnFile = self.$btnFile,
-                $form = $el.closest('form'), $cont = self.$container;
-            handler($el, 'change', $.proxy(self.change, self));
-            handler($(window), 'resize', function () {
-                self.setEllipsis();
-            });
-            handler($btnFile, 'click', function () {
-                self.raise('filebrowse');
-                if (self.isError && !self.isUploadable) {
-                    self.clear();
-                }
-                $cap.focus();
-            });
-            handler($form, 'reset', $.proxy(self.reset, self));
-            handler($cont.find('.fileinput-remove:not([disabled])'), 'click', $.proxy(self.clear, self));
-            handler($cont.find('.fileinput-cancel'), 'click', $.proxy(self.cancel, self));
-            if (self.isUploadable && self.dropZoneEnabled && self.showPreview) {
-                self.initDragDrop();
-            }
-            if (!self.isUploadable) {
-                handler($form, 'submit', $.proxy(self.submitForm, self));
-            }
-            handler(self.$container.find('.kv-fileinput-upload'), 'click', function (e) {
-                var $btn = $(this), $form, isEnabled = !$btn.hasClass('disabled') && isEmpty($btn.attr('disabled'));
-                if (!self.isUploadable) {
-                    if (isEnabled && $btn.attr('type') !== 'submit') {
-                        $form = $btn.closest('form');
-                        // downgrade to normal form submit if possible
-                        if ($form.length) {
-                            $form.trigger('submit');
-                        }
-                        e.preventDefault();
-                    }
-                    return;
-                }
-                e.preventDefault();
-                if (isEnabled) {
-                    self.upload();
-                }
-            });
-        },
-        submitForm: function () {
-            var self = this, $el = self.$element, files = $el.get(0).files;
-            if (files && files.length < self.minFileCount && self.minFileCount > 0) {
-                self.noFilesError({});
-                return false;
-            }
-            return !self.abort({});
-        },
-        abort: function (params) {
-            var self = this, data;
-            if (self.ajaxAborted && typeof self.ajaxAborted === "object" && self.ajaxAborted.message !== undefined) {
-                data = $.extend(self.getOutData(), params);
-                data.abortData = self.ajaxAborted.data || {};
-                data.abortMessage = self.ajaxAborted.message;
-                self.showUploadError(self.ajaxAborted.message, data, 'filecustomerror');
-                return true;
-            }
-            return false;
-        },
-        noFilesError: function (params) {
-            var self = this, label = self.minFileCount > 1 ? self.filePlural : self.fileSingle,
-                msg = self.msgFilesTooLess.replace('{n}', self.minFileCount).replace('{files}', label),
-                $error = self.$errorContainer;
-            $error.html(msg);
-            self.isError = true;
-            self.updateFileDetails(0);
-            $error.fadeIn(800);
-            self.raise('fileerror', [params]);
-            self.clearFileInput();
-            addCss(self.$container, 'has-error');
-        },
-        setProgress: function (p) {
-            var self = this, pct = Math.min(p, 100),
-                template = pct < 100 ? self.progressTemplate : self.progressCompleteTemplate;
-            if (!isEmpty(template)) {
-                self.$progress.html(template.repl('{percent}', pct));
-            }
-        },
-        upload: function () {
-            var self = this, totLen = self.getFileStack().length, params = {},
-                i, outData, len, hasExtraData = !$.isEmptyObject(self.getExtraData());
-            if (totLen < self.minFileCount && self.minFileCount > 0) {
-                self.noFilesError(params);
-                return;
-            }
-            if (!self.isUploadable || self.isDisabled || (totLen === 0 && !hasExtraData)) {
-                return;
-            }
-            self.resetUpload();
-            self.$progress.removeClass('hide');
-            self.uploadCount = 0;
-            self.uploadPercent = 0;
-            self.lock();
-            self.setProgress(0);
-            if (totLen === 0 && hasExtraData) {
-                self.uploadExtraOnly();
-                return;
-            }
-            len = self.filestack.length;
-            self.hasInitData = false;
-            if (self.uploadAsync && self.showPreview) {
-                outData = self.getOutData();
-                self.raise('filebatchpreupload', [outData]);
-                self.fileBatchCompleted = false;
-                self.uploadCache = {content: [], config: [], tags: [], append: true};
-                for (i = 0; i < len; i += 1) {
-                    if (self.filestack[i] !== undefined) {
-                        self.uploadSingle(i, self.filestack, true);
-                    }
-                }
-                return;
-            }
-            self.uploadBatch();
-        },
-        lock: function () {
-            var self = this;
-            self.resetErrors();
-            self.disable();
-            if (self.showRemove) {
-                addCss(self.$container.find('.fileinput-remove'), 'hide');
-            }
-            if (self.showCancel) {
-                self.$container.find('.fileinput-cancel').removeClass('hide');
-            }
-            self.raise('filelock', [self.filestack, self.getExtraData()]);
-        },
-        unlock: function (reset) {
-            var self = this;
-            if (reset === undefined) {
-                reset = true;
-            }
-            self.enable();
-            if (self.showCancel) {
-                addCss(self.$container.find('.fileinput-cancel'), 'hide');
-            }
-            if (self.showRemove) {
-                self.$container.find('.fileinput-remove').removeClass('hide');
-            }
-            if (reset) {
-                self.resetFileStack();
-            }
-            self.raise('fileunlock', [self.filestack, self.getExtraData()]);
-        },
-        resetFileStack: function () {
-            var self = this, i = 0, newstack = [];
-            self.getThumbs().each(function () {
-                var $thumb = $(this), ind = $thumb.attr('data-fileindex'),
-                    file = self.filestack[ind];
-                if (ind === -1) {
-                    return;
-                }
-                if (file !== undefined) {
-                    newstack[i] = file;
-                    $thumb.attr({
-                        'id': self.previewInitId + '-' + i,
-                        'data-fileindex': i
-                    });
-                    i += 1;
-                } else {
-                    $thumb.attr({
-                        'id': 'uploaded-' + uniqId(),
-                        'data-fileindex': '-1'
-                    });
-                }
-            });
-            self.filestack = newstack;
-        },
-        destroy: function () {
-            var self = this, $cont = self.$container;
-            $cont.find('.file-drop-zone').off();
-            self.$element.insertBefore($cont).off('.fileinput').removeData();
-            $cont.off().remove();
-        },
-        refresh: function (options) {
-            var self = this, $el = self.$element;
-            options = options ? $.extend(self.options, options) : self.options;
-            self.destroy();
-            $el.fileinput(options);
-            if ($el.val()) {
-                $el.trigger('change.fileinput');
-            }
-        },
-        initDragDrop: function () {
-            var self = this, $zone = self.$container.find('.file-drop-zone'),
-                allEvents = 'dragenter.fileinput dragover.fileinput drop.fileinput';
-            handler($zone, 'dragenter.fileinput dragover.fileinput', function (e) {
-                var hasFiles = $.inArray('Files', e.originalEvent.dataTransfer.types) > -1;
-                e.stopPropagation();
-                e.preventDefault();
-                if (self.isDisabled || !hasFiles) {
-                    e.originalEvent.dataTransfer.effectAllowed = 'none';
-                    e.originalEvent.dataTransfer.dropEffect = 'none';
-                    return;
-                }
-                addCss($(this), 'highlighted');
-            }, true);
-            handler($zone, 'dragleave', function (e) {
-                e.stopPropagation();
-                e.preventDefault();
-                if (self.isDisabled) {
-                    return;
-                }
-                $(this).removeClass('highlighted');
-            });
-            handler($zone, 'drop', function (e) {
-                e.preventDefault();
-                if (self.isDisabled || isEmpty(e.originalEvent.dataTransfer.files)) {
-                    return;
-                }
-                self.change(e, 'dragdrop');
-                $(this).removeClass('highlighted');
-            });
-            handler($(document), allEvents, function (e) {
-                e.stopPropagation();
-                e.preventDefault();
-            }, true);
-        },
-        setFileDropZoneTitle: function () {
-            var self = this, $zone = self.$container.find('.file-drop-zone');
-            $zone.find('.' + self.dropZoneTitleClass).remove();
-            if (!self.isUploadable || !self.showPreview || $zone.length === 0 || self.getFileStack().length > 0 || !self.dropZoneEnabled) {
-                return;
-            }
-            if ($zone.find('.file-preview-frame').length === 0) {
-                $zone.prepend('<div class="' + self.dropZoneTitleClass + '">' + self.dropZoneTitle + '</div>');
-            }
-            self.$container.removeClass('file-input-new');
-            addCss(self.$container, 'file-input-ajax-new');
-        },
-        initFileActions: function () {
-            var self = this;
-            self.$preview.find('.kv-file-remove').each(function () {
-                var $el = $(this), $frame = $el.closest('.file-preview-frame'),
-                    ind = $frame.attr('data-fileindex'), n, cap;
-                handler($el, 'click', function () {
-                    self.cleanMemory($frame);
-                    $frame.fadeOut('slow', function () {
-                        self.filestack[ind] = undefined;
-                        self.clearObjects($frame);
-                        $frame.remove();
-                        var filestack = self.getFileStack(true), len = filestack.length,
-                            chk = previewCache.count(self.id);
-                        self.clearFileInput();
-                        if (len === 0 && chk === 0) {
-                            self.reset();
-                        } else {
-                            n = chk + len;
-                            cap = n > 1 ? self.getMsgSelected(n) : (filestack[0] ? filestack[0].name : '');
-                            self.setCaption(cap);
-                        }
-                    });
-                });
-            });
-            self.$preview.find('.kv-file-upload').each(function () {
-                var $el = $(this);
-                handler($el, 'click', function () {
-                    var $frame = $el.closest('.file-preview-frame'),
-                        ind = $frame.attr('data-fileindex');
-                    self.uploadSingle(ind, self.filestack, false);
-                });
-            });
-        },
-        getMsgSelected: function (n) {
-            var self = this, strFiles = n === 1 ? self.fileSingle : self.filePlural;
-            return self.msgSelected.replace('{n}', n).replace('{files}', strFiles);
-        },
-        renderFileFooter: function (caption, width) {
-            var self = this, config = self.fileActionSettings, footer, out,
-                template = self.getLayoutTemplate('footer');
-            if (self.isUploadable) {
-                footer = template.repl('{actions}', self.renderFileActions(true, true, false, false, false));
-                out = footer.repl('{caption}', caption)
-                    .repl('{width}', width)
-                    .repl('{indicator}', config.indicatorNew)
-                    .repl('{indicatorTitle}', config.indicatorNewTitle);
-            } else {
-                out = template.repl('{actions}', '')
-                    .repl('{caption}', caption)
-                    .repl('{width}', width)
-                    .repl('{indicator}', '')
-                    .repl('{indicatorTitle}', '');
-            }
-            out = replaceTags(out, self.previewThumbTags);
-            return out;
-        },
-        renderFileActions: function (showUpload, showDelete, disabled, url, key) {
-            if (!showUpload && !showDelete) {
-                return '';
-            }
-            var self = this,
-                vUrl = url === false ? '' : ' data-url="' + url + '"',
-                vKey = key === false ? '' : ' data-key="' + key + '"',
-                btnDelete = self.getLayoutTemplate('actionDelete'),
-                btnUpload = '',
-                template = self.getLayoutTemplate('actions'),
-                otherButtons = self.otherActionButtons.repl('{dataKey}', vKey),
-                config = self.fileActionSettings,
-                removeClass = disabled ? config.removeClass + ' disabled' : config.removeClass;
-            btnDelete = btnDelete
-                .repl('{removeClass}', removeClass)
-                .repl('{removeIcon}', config.removeIcon)
-                .repl('{removeTitle}', config.removeTitle)
-                .repl('{dataUrl}', vUrl)
-                .repl('{dataKey}', vKey);
-            if (showUpload) {
-                btnUpload = self.getLayoutTemplate('actionUpload')
-                    .repl('{uploadClass}', config.uploadClass)
-                    .repl('{uploadIcon}', config.uploadIcon)
-                    .repl('{uploadTitle}', config.uploadTitle);
-            }
-            return template
-                .repl('{delete}', btnDelete)
-                .repl('{upload}', btnUpload)
-                .repl('{other}', otherButtons);
-        },
-        setThumbStatus: function ($thumb, status) {
-            var self = this, icon = 'indicator' + status, msg = icon + 'Title',
-                css = 'file-preview-' + status.toLowerCase(),
-                $indicator = $thumb.find('.file-upload-indicator'),
-                config = self.fileActionSettings;
-            $thumb.removeClass('file-preview-success file-preview-error file-preview-loading');
-            $indicator.html(config[icon]);
-            $indicator.attr('title', config[msg]);
-            $thumb.addClass(css);
-        },
-        clearPreview: function () {
-            var self = this, $thumbs = !self.showUploadedThumbs ? self.$preview.find('.file-preview-frame') :
-                self.$preview.find('.file-preview-frame:not(.file-preview-success)');
-            $thumbs.remove();
-            if (!self.$preview.find('.file-preview-frame').length || !self.showPreview) {
-                self.resetUpload();
-            }
-        },
-        initPreview: function (isInit) {
-            var self = this, cap = self.initialCaption || '', out;
-            if (!previewCache.count(self.id)) {
-                self.clearPreview();
-                if (isInit) {
-                    self.setCaption(cap);
-                } else {
-                    self.initCaption();
-                }
-                return;
-            }
-            out = previewCache.out(self.id);
-            cap = isInit && self.initialCaption ? self.initialCaption : out.caption;
-            self.$preview.html(out.content);
-            self.setCaption(cap);
-            if (!isEmpty(out.content)) {
-                self.$container.removeClass('file-input-new');
-            }
-        },
-        initPreviewDeletes: function () {
-            var self = this, deleteExtraData = self.deleteExtraData || {},
-                resetProgress = function () {
-                    if (self.$preview.find('.kv-file-remove').length === 0) {
-                        self.reset();
-                        self.initialCaption = '';
-                    }
-                };
-
-            self.$preview.find('.kv-file-remove').each(function () {
-                var $el = $(this), vUrl = $el.data('url') || self.deleteUrl, vKey = $el.data('key');
-                if (isEmpty(vUrl) || vKey === undefined) {
-                    return;
-                }
-                var $frame = $el.closest('.file-preview-frame'), cache = previewCache.data[self.id],
-                    settings, params, index = $frame.data('fileindex'), config, extraData;
-                index = parseInt(index.replace('init_', ''));
-                config = isEmpty(cache.config) && isEmpty(cache.config[index]) ? null : cache.config[index];
-                extraData = isEmpty(config) || isEmpty(config.extra) ? deleteExtraData : config.extra;
-                if (typeof extraData === "function") {
-                    extraData = extraData();
-                }
-                params = {id: $el.attr('id'), key: vKey, extra: extraData};
-                settings = $.extend({
-                    url: vUrl,
-                    type: 'DELETE',
-                    dataType: 'json',
-                    data: $.extend({key: vKey}, extraData),
-                    beforeSend: function (jqXHR) {
-                        self.ajaxAborted = false;
-                        self.raise('filepredelete', [vKey, jqXHR, extraData]);
-                        if (self.ajaxAborted) {
-                            jqXHR.abort();
-                        } else {
-                            addCss($frame, 'file-uploading');
-                            addCss($el, 'disabled');
-                        }
-                    },
-                    success: function (data, textStatus, jqXHR) {
-                        var n, cap;
-                        if (isEmpty(data) || isEmpty(data.error)) {
-                            previewCache.unset(self.id, index);
-                            n = previewCache.count(self.id);
-                            cap = n > 0 ? self.getMsgSelected(n) : '';
-                            self.raise('filedeleted', [vKey, jqXHR, extraData]);
-                            self.setCaption(cap);
-                        } else {
-                            params.jqXHR = jqXHR;
-                            params.response = data;
-                            self.showError(data.error, params, 'filedeleteerror');
-                            $frame.removeClass('file-uploading');
-                            $el.removeClass('disabled');
-                            resetProgress();
-                            return;
-                        }
-                        $frame.removeClass('file-uploading').addClass('file-deleted');
-                        $frame.fadeOut('slow', function () {
-                            self.clearObjects($frame);
-                            $frame.remove();
-                            resetProgress();
-                            if (!n && self.getFileStack().length === 0) {
-                                self.setCaption('');
-                                self.reset();
-                            }
-                        });
-                    },
-                    error: function (jqXHR, textStatus, errorThrown) {
-                        var errMsg = self.parseError(jqXHR, errorThrown);
-                        params.jqXHR = jqXHR;
-                        params.response = {};
-                        self.showError(errMsg, params, 'filedeleteerror');
-                        $frame.removeClass('file-uploading');
-                        resetProgress();
-                    }
-                }, self.ajaxDeleteSettings);
-                handler($el, 'click', function () {
-                    $.ajax(settings);
-                });
-            });
-        },
-        clearObjects: function ($el) {
-            $el.find('video audio').each(function () {
-                this.pause();
-                $(this).remove();
-            });
-            $el.find('img object div').each(function () {
-                $(this).remove();
-            });
-        },
-        clearFileInput: function () {
-            var self = this, $el = self.$element, $srcFrm, $tmpFrm, $tmpEl;
-            if (isEmpty($el.val())) {
-                return;
-            }
-            // Fix for IE ver < 11, that does not clear file inputs
-            // Requires a sequence of steps to prevent IE crashing but
-            // still allow clearing of the file input.
-            if (self.isIE9 || self.isIE10) {
-                $srcFrm = $el.closest('form');
-                $tmpFrm = $(document.createElement('form'));
-                $tmpEl = $(document.createElement('div'));
-                $el.before($tmpEl);
-                if ($srcFrm.length) {
-                    $srcFrm.after($tmpFrm);
-                } else {
-                    $tmpEl.after($tmpFrm);
-                }
-                $tmpFrm.append($el).trigger('reset');
-                $tmpEl.before($el).remove();
-                $tmpFrm.remove();
-            } else { // normal input clear behavior for other sane browsers
-                $el.val('');
-            }
-            self.fileInputCleared = true;
-        },
-        resetUpload: function () {
-            var self = this;
-            self.uploadCache = {content: [], config: [], tags: [], append: true};
-            self.uploadCount = 0;
-            self.uploadPercent = 0;
-            self.$btnUpload.removeAttr('disabled');
-            self.setProgress(0);
-            addCss(self.$progress, 'hide');
-            self.resetErrors(false);
-            self.ajaxAborted = false;
-            self.ajaxRequests = [];
-        },
-        cancel: function () {
-            var self = this, xhr = self.ajaxRequests, len = xhr.length, i;
-            if (len > 0) {
-                for (i = 0; i < len; i += 1) {
-                    xhr[i].abort();
-                }
-            }
-            self.getThumbs().each(function () {
-                var $thumb = $(this), ind = $thumb.attr('data-fileindex');
-                $thumb.removeClass('file-uploading');
-                if (self.filestack[ind] !== undefined) {
-                    $thumb.find('.kv-file-upload').removeClass('disabled').removeAttr('disabled');
-                    $thumb.find('.kv-file-remove').removeClass('disabled').removeAttr('disabled');
-                }
-                self.unlock();
-            });
-        },
-        cleanMemory: function ($thumb) {
-            var data = $thumb.is('img') ? $thumb.attr('src') : $thumb.find('source').attr('src');
-            objUrl.revokeObjectURL(data);
-        },
-        hasInitialPreview: function () {
-            var self = this;
-            return !self.overwriteInitial && previewCache.count(self.id);
-        },
-        clear: function () {
-            var self = this, cap;
-            self.$btnUpload.removeAttr('disabled');
-            self.getThumbs().find('video,audio,img').each(function () {
-                self.cleanMemory($(this));
-            });
-            self.resetUpload();
-            self.filestack = [];
-            self.clearFileInput();
-            self.resetErrors(true);
-            self.raise('fileclear');
-            if (self.hasInitialPreview()) {
-                self.showFileIcon();
-                self.resetPreview();
-                self.setEllipsis();
-                self.initPreviewDeletes();
-                self.$container.removeClass('file-input-new');
-            } else {
-                self.getThumbs().each(function () {
-                    self.clearObjects($(this));
-                });
-                if (self.isUploadable) {
-                    previewCache.data[self.id] = {};
-                }
-                self.$preview.html('');
-                cap = (!self.overwriteInitial && self.initialCaption.length > 0) ? self.initialCaption : '';
-                self.setCaption(cap);
-                self.setEllipsis();
-                self.$caption.attr('title', '');
-                addCss(self.$container, 'file-input-new');
-            }
-            if (self.$container.find('.file-preview-frame').length === 0) {
-                if (!self.initCaption()) {
-                    self.$captionContainer.find('.kv-caption-icon').hide();
-                }
-                self.setEllipsis();
-            }
-            self.hideFileIcon();
-            self.raise('filecleared');
-            self.$captionContainer.focus();
-            self.setFileDropZoneTitle();
-        },
-        resetPreview: function () {
-            var self = this, out;
-            if (previewCache.count(self.id)) {
-                out = previewCache.out(self.id);
-                self.$preview.html(out.content);
-                self.setCaption(out.caption);
-            } else {
-                self.clearPreview();
-                self.initCaption();
-            }
-        },
-        resetPreviewThumbs: function (isAjax) {
-            var self = this, out;
-            if (isAjax) {
-                self.clearPreview();
-                self.filestack = [];
-                return;
-            }
-            if (self.hasInitialPreview()) {
-                out = previewCache.out(self.id);
-                self.$preview.html(out.content);
-                self.setCaption(out.caption);
-                self.initPreviewDeletes();
-            } else {
-                self.clearPreview();
-            }
-        },
-        reset: function () {
-            var self = this;
-            self.resetPreview();
-            self.setEllipsis();
-            self.$container.find('.fileinput-filename').text('');
-            self.raise('filereset');
-            addCss(self.$container, 'file-input-new');
-            if (self.$preview.find('.file-preview-frame').length || self.isUploadable && self.dropZoneEnabled) {
-                self.$container.removeClass('file-input-new');
-            }
-            self.setFileDropZoneTitle();
-            self.filestack = [];
-            self.formdata = {};
-        },
-        disable: function () {
-            var self = this;
-            self.isDisabled = true;
-            self.raise('filedisabled');
-            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, .file-preview-frame button").attr("disabled",
-                true);
-            self.initDragDrop();
-        },
-        enable: function () {
-            var self = this;
-            self.isDisabled = false;
-            self.raise('fileenabled');
-            self.$element.removeAttr('disabled');
-            self.$container.find(".kv-fileinput-caption").removeClass("file-caption-disabled");
-            self.$container.find(".btn-file, .fileinput-remove, .kv-fileinput-upload, .file-preview-frame button").removeAttr("disabled");
-            self.initDragDrop();
-        },
-        getThumbs: function (css) {
-            css = css || '';
-            return this.$preview.find('.file-preview-frame:not(.file-preview-initial)' + css);
-        },
-        getExtraData: function (previewId, index) {
-            var self = this, data = self.uploadExtraData;
-            if (typeof self.uploadExtraData === "function") {
-                data = self.uploadExtraData(previewId, index);
-            }
-            return data;
-        },
-        uploadExtra: function (previewId, index) {
-            var self = this, data = self.getExtraData(previewId, index);
-            if (data.length === 0) {
-                return;
-            }
-            $.each(data, function (key, value) {
-                self.formdata.append(key, value);
-            });
-        },
-        initXhr: function (xhrobj, factor) {
-            var self = this;
-            if (xhrobj.upload) {
-                xhrobj.upload.addEventListener('progress', function (event) {
-                    var pct = 0, position = event.loaded || event.position, total = event.total;
-                    if (event.lengthComputable) {
-                        pct = Math.ceil(position / total * factor);
-                    }
-                    self.uploadPercent = Math.max(pct, self.uploadPercent);
-                    self.setProgress(self.uploadPercent);
-                }, false);
-            }
-            return xhrobj;
-        },
-        ajaxSubmit: function (fnBefore, fnSuccess, fnComplete, fnError, previewId, index) {
-            var self = this, settings;
-            self.raise('filepreajax', [previewId, index]);
-            self.uploadExtra(previewId, index);
-            settings = $.extend({
-                xhr: function () {
-                    var xhrobj = $.ajaxSettings.xhr();
-                    return self.initXhr(xhrobj, 98);
-                },
-                url: self.uploadUrl,
-                type: 'POST',
-                dataType: 'json',
-                data: self.formdata,
-                cache: false,
-                processData: false,
-                contentType: false,
-                beforeSend: fnBefore,
-                success: fnSuccess,
-                complete: fnComplete,
-                error: fnError
-            }, self.ajaxSettings);
-            self.ajaxRequests.push($.ajax(settings));
-        },
-        initUploadSuccess: function (out, $thumb, allFiles) {
-            var self = this, append, data, index, $newThumb, content, config, tags;
-            if (typeof out !== 'object' || $.isEmptyObject(out)) {
-                return;
-            }
-            if (out.initialPreview !== undefined && out.initialPreview.length > 0) {
-                self.hasInitData = true;
-                content = out.initialPreview || [];
-                config = out.initialPreviewConfig || [];
-                tags = out.initialPreviewThumbTags || [];
-                append = out.append === undefined || out.append ? true : false;
-                self.overwriteInitial = false;
-                if ($thumb !== undefined && !allFiles) {
-                    index = previewCache.add(self.id, content, config[0], tags[0], append);
-                    data = previewCache.get(self.id, index, false);
-                    $newThumb = $(data).hide();
-                    $thumb.after($newThumb).fadeOut('slow', function () {
-                        $newThumb.fadeIn('slow').css('display:inline-block');
-                        self.initPreviewDeletes();
-                        self.clearFileInput();
-                        $thumb.remove();
-                    });
-                } else {
-                    if (allFiles) {
-                        self.uploadCache.content.push(content[0]);
-                        self.uploadCache.config.push(config[0]);
-                        self.uploadCache.tags.push(tags[0]);
-                        self.uploadCache.append = append;
-                    } else {
-                        previewCache.set(self.id, content, config, tags, append);
-                        self.initPreview();
-                        self.initPreviewDeletes();
-                    }
-                }
-            }
-        },
-        initSuccessThumbs: function () {
-            var self = this;
-            self.getThumbs('.file-preview-success').each(function () {
-                var $thumb = $(this), $remove = $thumb.find('.kv-file-remove');
-                $remove.removeAttr('disabled');
-                handler($remove, 'click', function () {
-                    var out = self.raise('filesuccessremove', [$thumb.attr('id'), $thumb.data('fileindex')]);
-                    self.cleanMemory($thumb);
-                    if (out === false) {
-                        return;
-                    }
-                    $thumb.fadeOut('slow', function () {
-                        $thumb.remove();
-                        if (!self.$preview.find('.file-preview-frame').length) {
-                            self.reset();
-                        }
-                    });
-                });
-            });
-        },
-        uploadSingle: function (i, files, allFiles) {
-            var self = this, total = self.getFileStack().length, formdata = new FormData(), outData,
-                previewId = self.previewInitId + "-" + i, $thumb = $('#' + previewId + ':not(.file-preview-initial)'),
-                pct, chkComplete, $btnUpload = $thumb.find('.kv-file-upload'), $btnDelete = $thumb.find('.kv-file-remove'),
-                updateProgress, hasPostData = self.filestack.length > 0 || !$.isEmptyObject(self.uploadExtraData),
-                resetActions, fnBefore, fnSuccess, fnComplete, fnError, params = {id: previewId, index: i};
-            self.formdata = formdata;
-            if (total === 0 || !hasPostData || $btnUpload.hasClass('disabled') || self.abort(params)) {
-                return;
-            }
-            chkComplete = function () {
-                var $thumbs = self.getThumbs('.file-uploading');
-                if ($thumbs.length > 0 || self.fileBatchCompleted) {
-                    return;
-                }
-                self.fileBatchCompleted = true;
-                setTimeout(function () {
-                    previewCache.set(self.id, self.uploadCache.content, self.uploadCache.config, self.uploadCache.tags,
-                        self.uploadCache.append);
-                    if (self.hasInitData) {
-                        self.initPreview();
-                        self.initPreviewDeletes();
-                    }
-                    self.setProgress(100);
-                    self.unlock();
-                    self.clearFileInput();
-                    self.raise('filebatchuploadcomplete', [self.filestack, self.getExtraData()]);
-                }, 100);
-            };
-            updateProgress = function () {
-                if (!allFiles || total === 0 || self.uploadPercent >= 100) {
-                    return;
-                }
-                self.uploadCount += 1;
-                pct = 80 + Math.ceil(self.uploadCount * 20 / total);
-                self.uploadPercent = Math.max(pct, self.uploadPercent);
-                self.setProgress(self.uploadPercent);
-                self.initPreviewDeletes();
-            };
-            resetActions = function () {
-                $btnUpload.removeAttr('disabled');
-                $btnDelete.removeAttr('disabled');
-                $thumb.removeClass('file-uploading');
-            };
-            fnBefore = function (jqXHR) {
-                outData = self.getOutData(jqXHR);
-                if (!$thumb.hasClass('file-preview-success')) {
-                    self.setThumbStatus($thumb, 'Loading');
-                    addCss($thumb, 'file-uploading');
-                }
-                $btnUpload.attr('disabled', true);
-                $btnDelete.attr('disabled', true);
-                if (!allFiles) {
-                    self.lock();
-                }
-                self.raise('filepreupload', [outData, previewId, i]);
-                params = $.extend(params, outData);
-                if (self.abort(params)) {
-                    jqXHR.abort();
-                    self.setProgress(100);
-                }
-            };
-            fnSuccess = function (data, textStatus, jqXHR) {
-                outData = self.getOutData(jqXHR, data);
-                params = $.extend(params, outData);
-                setTimeout(function () {
-                    if (isEmpty(data) || isEmpty(data.error)) {
-                        self.setThumbStatus($thumb, 'Success');
-                        $btnUpload.hide();
-                        self.filestack[i] = undefined;
-                        self.raise('fileuploaded', [outData, previewId, i]);
-                        self.initUploadSuccess(data, $thumb, allFiles);
-                        if (!allFiles) {
-                            self.resetFileStack();
-                        }
-                    } else {
-                        self.setThumbStatus($thumb, 'Error');
-                        self.showUploadError(data.error, params);
-                    }
-                }, 100);
-            };
-            fnComplete = function () {
-                setTimeout(function () {
-                    updateProgress();
-                    resetActions();
-                    if (!allFiles) {
-                        self.unlock(false);
-                    } else {
-                        chkComplete();
-                    }
-                    self.initSuccessThumbs();
-                }, 100);
-            };
-            fnError = function (jqXHR, textStatus, errorThrown) {
-                var errMsg = self.parseError(jqXHR, errorThrown, (allFiles ? files[i].name : null));
-                self.setThumbStatus($thumb, 'Error');
-                params = $.extend(params, self.getOutData(jqXHR));
-                self.showUploadError(errMsg, params);
-            };
-            formdata.append(self.uploadFileAttr, files[i]);
-            formdata.append('file_id', i);
-            self.ajaxSubmit(fnBefore, fnSuccess, fnComplete, fnError, previewId, i);
-        },
-        uploadBatch: function () {
-            var self = this, files = self.filestack, total = files.length, config,
-                hasPostData = self.filestack.length > 0 || !$.isEmptyObject(self.uploadExtraData),
-                setAllUploaded, enableActions, fnBefore, fnSuccess, fnComplete, fnError,
-                params = {};
-            self.formdata = new FormData();
-            if (total === 0 || !hasPostData || self.abort(params)) {
-                return;
-            }
-            setAllUploaded = function () {
-                $.each(files, function (key) {
-                    self.filestack[key] = undefined;
-                });
-                self.clearFileInput();
-            };
-            fnBefore = function (jqXHR) {
-                self.lock();
-                var outData = self.getOutData(jqXHR);
-                if (self.showPreview) {
-                    self.getThumbs().each(function () {
-                        var $thumb = $(this), $btnUpload = $thumb.find('.kv-file-upload'),
-                            $btnDelete = $thumb.find('.kv-file-remove');
-                        if (!$thumb.hasClass('file-preview-success')) {
-                            self.setThumbStatus($thumb, 'Loading');
-                            addCss($thumb, 'file-uploading');
-                        }
-                        $btnUpload.attr('disabled', true);
-                        $btnDelete.attr('disabled', true);
-                    });
-                }
-                self.raise('filebatchpreupload', [outData]);
-                if (self.abort(outData)) {
-                    jqXHR.abort();
-                }
-            };
-            fnSuccess = function (data, textStatus, jqXHR) {
-                var outData = self.getOutData(jqXHR, data), $thumbs = self.getThumbs(),
-                    keys = isEmpty(data.errorkeys) ? [] : data.errorkeys, key = 0;
-                if (isEmpty(data) || isEmpty(data.error)) {
-                    self.raise('filebatchuploadsuccess', [outData]);
-                    setAllUploaded();
-                    if (self.showPreview) {
-                        $thumbs.each(function () {
-                            var $thumb = $(this), $btnUpload = $thumb.find('.kv-file-upload');
-                            $thumb.find('.kv-file-upload').hide();
-                            self.setThumbStatus($thumb, 'Success');
-                            $thumb.removeClass('file-uploading');
-                            $btnUpload.removeAttr('disabled');
-                        });
-                        self.initUploadSuccess(data);
-                    } else {
-                        self.reset();
-                    }
-                } else {
-                    if (self.showPreview) {
-                        $thumbs.each(function () {
-                            var $thumb = $(this), $btnDelete = $thumb.find('.kv-file-remove'),
-                                $btnUpload = $thumb.find('.kv-file-upload');
-                            $thumb.removeClass('file-uploading');
-                            $btnUpload.removeAttr('disabled');
-                            $btnDelete.removeAttr('disabled');
-                            if (keys.length === 0) {
-                                self.setThumbStatus($thumb, 'Error');
-                                return;
-                            }
-                            if ($.inArray(key, keys) !== -1) {
-                                self.setThumbStatus($thumb, 'Error');
-                            } else {
-                                $thumb.find('.kv-file-upload').hide();
-                                self.setThumbStatus($thumb, 'Success');
-                                self.filestack[key] = undefined;
-                            }
-                            key++;
-                        });
-                        self.initUploadSuccess(data);
-                    }
-                    self.showUploadError(data.error, outData, 'filebatchuploaderror');
-                }
-            };
-            fnComplete = function () {
-                self.setProgress(100);
-                self.unlock();
-                self.initSuccessThumbs();
-                self.raise('filebatchuploadcomplete', [self.filestack, self.getExtraData()]);
-                self.clearFileInput();
-            };
-            fnError = function (jqXHR, textStatus, errorThrown) {
-                var outData = self.getOutData(jqXHR), errMsg = self.parseError(jqXHR, errorThrown);
-                self.showUploadError(errMsg, outData, 'filebatchuploaderror');
-                self.uploadFileCount = total - 1;
-                if (!self.showPreview) {
-                    return;
-                }
-                self.getThumbs().each(function () {
-                    var $thumb = $(this), key = $thumb.attr('data-fileindex');
-                    $thumb.removeClass('file-uploading');
-                    if (self.filestack[key] !== undefined) {
-                        self.setThumbStatus($thumb, 'Error');
-                    }
-                });
-                self.getThumbs().removeClass('file-uploading');
-                self.getThumbs(' .kv-file-upload').removeAttr('disabled');
-                self.getThumbs(' .kv-file-delete').removeAttr('disabled');
-            };
-            $.each(files, function (key, data) {
-                if (!isEmpty(files[key])) {
-                    self.formdata.append(self.uploadFileAttr, data);
-                }
-            });
-            self.ajaxSubmit(fnBefore, fnSuccess, fnComplete, fnError);
-        },
-        uploadExtraOnly: function () {
-            var self = this, params = {}, fnBefore, fnSuccess, fnComplete, fnError;
-            self.formdata = new FormData();
-            if (self.abort(params)) {
-                return;
-            }
-            fnBefore = function (jqXHR) {
-                self.lock();
-                var outData = self.getOutData(jqXHR);
-                self.raise('filebatchpreupload', [outData]);
-                self.setProgress(50);
-                params.data = outData;
-                params.xhr = jqXHR;
-                if (self.abort(params)) {
-                    jqXHR.abort();
-                    self.setProgress(100);
-                }
-            };
-            fnSuccess = function (data, textStatus, jqXHR) {
-                var outData = self.getOutData(jqXHR, data);
-                if (isEmpty(data) || isEmpty(data.error)) {
-                    self.raise('filebatchuploadsuccess', [outData]);
-                    self.clearFileInput();
-                    self.initUploadSuccess(data);
-                } else {
-                    self.showUploadError(data.error, outData, 'filebatchuploaderror');
-                }
-            };
-            fnComplete = function () {
-                self.setProgress(100);
-                self.unlock();
-                self.raise('filebatchuploadcomplete', [self.filestack, self.getExtraData()]);
-                self.clearFileInput();
-            };
-            fnError = function (jqXHR, textStatus, errorThrown) {
-                var outData = self.getOutData(jqXHR), errMsg = self.parseError(jqXHR, errorThrown);
-                params.data = outData;
-                self.showUploadError(errMsg, outData, 'filebatchuploaderror');
-            };
-            self.ajaxSubmit(fnBefore, fnSuccess, fnComplete, fnError);
-        },
-        hideFileIcon: function () {
-            if (this.overwriteInitial) {
-                this.$captionContainer.find('.kv-caption-icon').hide();
-            }
-        },
-        showFileIcon: function () {
-            this.$captionContainer.find('.kv-caption-icon').show();
-        },
-        resetErrors: function (fade) {
-            var self = this, $error = self.$errorContainer;
-            self.isError = false;
-            self.$container.removeClass('has-error');
-            $error.html('');
-            if (fade) {
-                $error.fadeOut('slow');
-            } else {
-                $error.hide();
-            }
-        },
-        showFolderError: function (folders) {
-            var self = this, $error = self.$errorContainer;
-            if (!folders) {
-                return;
-            }
-            $error.html(self.msgFoldersNotAllowed.repl('{n}', folders));
-            $error.fadeIn(800);
-            addCss(self.$container, 'has-error');
-            self.raise('filefoldererror', [folders]);
-        },
-        showUploadError: function (msg, params, event) {
-            var self = this, $error = self.$errorContainer, ev = event || 'fileuploaderror';
-            if ($error.find('ul').length === 0) {
-                $error.html('<ul><li>' + msg + '</li></ul>');
-            } else {
-                $error.find('ul').append('<li>' + msg + '</li>');
-            }
-            $error.fadeIn(800);
-            self.raise(ev, [params]);
-            self.$container.removeClass('file-input-new');
-            addCss(self.$container, 'has-error');
-            return true;
-        },
-        showError: function (msg, params, event) {
-            var self = this, $error = self.$errorContainer, ev = event || 'fileerror';
-            params = params || {};
-            params.reader = self.reader;
-            $error.html(msg);
-            $error.fadeIn(800);
-            self.raise(ev, [params]);
-            if (!self.isUploadable) {
-                self.clearFileInput();
-            }
-            self.$container.removeClass('file-input-new');
-            addCss(self.$container, 'has-error');
-            self.$btnUpload.attr('disabled', true);
-            return true;
-        },
-        errorHandler: function (evt, caption) {
-            var self = this, err = evt.target.error;
-            switch (err.code) {
-                case err.NOT_FOUND_ERR:
-                    self.showError(self.msgFileNotFound.replace('{name}', caption));
-                    break;
-                case err.SECURITY_ERR:
-                    self.showError(self.msgFileSecured.replace('{name}', caption));
-                    break;
-                case err.NOT_READABLE_ERR:
-                    self.showError(self.msgFileNotReadable.replace('{name}', caption));
-                    break;
-                case err.ABORT_ERR:
-                    self.showError(self.msgFilePreviewAborted.replace('{name}', caption));
-                    break;
-                default:
-                    self.showError(self.msgFilePreviewError.replace('{name}', caption));
-            }
-        },
-        parseFileType: function (file) {
-            var self = this, isValid, vType, cat, i;
-            for (i = 0; i < defaultPreviewTypes.length; i += 1) {
-                cat = defaultPreviewTypes[i];
-                isValid = isSet(cat, self.fileTypeSettings) ? self.fileTypeSettings[cat] : defaultFileTypeSettings[cat];
-                vType = isValid(file.type, file.name) ? cat : '';
-                if (!isEmpty(vType)) {
-                    return vType;
-                }
-            }
-            return 'other';
-        },
-        previewDefault: function (file, previewId, isDisabled) {
-            if (!this.showPreview) {
-                return;
-            }
-            var self = this, data = objUrl.createObjectURL(file), $obj = $('#' + previewId),
-                config = self.previewSettings.other || defaultPreviewSettings.other,
-                footer = self.renderFileFooter(file.name, config.width),
-                previewOtherTemplate = self.getPreviewTemplate('other'),
-                ind = previewId.slice(previewId.lastIndexOf('-') + 1),
-                frameClass = '';
-            if (isDisabled === true) {
-                frameClass = ' btn disabled';
-                footer += '<div class="file-other-error text-danger"><i class="glyphicon glyphicon-exclamation-sign"></i></div>';
-            }
-            self.$preview.append("\n" + previewOtherTemplate
-                .repl('{previewId}', previewId)
-                .repl('{frameClass}', frameClass)
-                .repl('{fileindex}', ind)
-                .repl('{caption}', self.slug(file.name))
-                .repl('{width}', config.width)
-                .repl('{height}', config.height)
-                .repl('{type}', file.type)
-                .repl('{data}', data)
-                .repl('{footer}', footer));
-        },
-        previewFile: function (i, file, theFile, previewId, data) {
-            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),
-                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),
-                footer = self.renderFileFooter(caption, config.width), modal = '',
-                ind = previewId.slice(previewId.lastIndexOf('-') + 1);
-            if (chkTypes && chkMimes) {
-                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;
-                } else {
-                    content = tmplt.repl('{previewId}', previewId).repl('{caption}', caption)
-                        .repl('{frameClass}', '')
-                        .repl('{type}', file.type).repl('{data}', data)
-                        .repl('{width}', config.width).repl('{height}', config.height)
-                        .repl('{footer}', footer).repl('{fileindex}', ind);
-                }
-                self.$preview.append("\n" + content);
-                self.validateImage(i, previewId);
-            } else {
-                self.previewDefault(file, previewId);
-            }
-        },
-        slugDefault: function (text) {
-            return isEmpty(text) ? '' : text.split(/(\\|\/)/g).pop().replace(/[^\w\u00C0-\u017F\-.\\\/ ]+/g, '');
-        },
-        getFileStack: function (skipNull) {
-            var self = this, status;
-            return self.filestack.filter(function (n) {
-                return (skipNull ? n !== undefined : n !== undefined && n !== null);
-            });
-        },
-        readFiles: function (files) {
-            this.reader = new FileReader();
-            var self = this, $el = self.$element, $preview = self.$preview, reader = self.reader,
-                $container = self.$previewContainer, $status = self.$previewStatus, msgLoading = self.msgLoading,
-                msgProgress = self.msgProgress, previewInitId = self.previewInitId, numFiles = files.length,
-                settings = self.fileTypeSettings, ctr = self.filestack.length,
-                throwError = function (msg, file, previewId, index) {
-                    var p1 = $.extend(self.getOutData({}, {}, files), {id: previewId, index: index}),
-                        p2 = {id: previewId, index: index, file: file, files: files};
-                    self.previewDefault(file, previewId, true);
-                    return self.isUploadable ? self.showUploadError(msg, p1) : self.showError(msg, p2);
-                };
-
-            function readFile(i) {
-                if (isEmpty($el.attr('multiple'))) {
-                    numFiles = 1;
-                }
-                if (i >= numFiles) {
-                    if (self.isUploadable && self.filestack.length > 0) {
-                        self.raise('filebatchselected', [self.getFileStack()]);
-                    } else {
-                        self.raise('filebatchselected', [files]);
-                    }
-                    $container.removeClass('loading');
-                    $status.html('');
-                    return;
-                }
-                var node = ctr + i, previewId = previewInitId + "-" + node, isText, file = files[i],
-                    caption = self.slug(file.name), fileSize = (file.size || 0) / 1000, checkFile, fileExtExpr = '',
-                    previewData = objUrl.createObjectURL(file), fileCount = 0, j, msg, typ, chk,
-                    fileTypes = self.allowedFileTypes, strTypes = isEmpty(fileTypes) ? '' : fileTypes.join(', '),
-                    fileExt = self.allowedFileExtensions, strExt = isEmpty(fileExt) ? '' : fileExt.join(', ');
-                if (!isEmpty(fileExt)) {
-                    fileExtExpr = new RegExp('\\.(' + fileExt.join('|') + ')$', 'i');
-                }
-                fileSize = fileSize.toFixed(2);
-                if (self.maxFileSize > 0 && fileSize > self.maxFileSize) {
-                    msg = self.msgSizeTooLarge.replace('{name}', caption)
-                        .replace('{size}', fileSize)
-                        .replace('{maxSize}', self.maxFileSize);
-                    self.isError = throwError(msg, file, previewId, i);
-                    return;
-                }
-                if (!isEmpty(fileTypes) && isArray(fileTypes)) {
-                    for (j = 0; j < fileTypes.length; j += 1) {
-                        typ = fileTypes[j];
-                        checkFile = settings[typ];
-                        chk = (checkFile !== undefined && checkFile(file.type, caption));
-                        fileCount += isEmpty(chk) ? 0 : chk.length;
-                    }
-                    if (fileCount === 0) {
-                        msg = self.msgInvalidFileType.replace('{name}', caption).replace('{types}', strTypes);
-                        self.isError = throwError(msg, file, previewId, i);
-                        return;
-                    }
-                }
-                if (fileCount === 0 && !isEmpty(fileExt) && isArray(fileExt) && !isEmpty(fileExtExpr)) {
-                    chk = caption.match(fileExtExpr);
-                    fileCount += isEmpty(chk) ? 0 : chk.length;
-                    if (fileCount === 0) {
-                        msg = self.msgInvalidFileExtension.replace('{name}', caption).replace('{extensions}',
-                            strExt);
-                        self.isError = throwError(msg, file, previewId, i);
-                        return;
-                    }
-                }
-                if (!self.showPreview) {
-                    self.filestack.push(file);
-                    setTimeout(readFile(i + 1), 100);
-                    self.raise('fileloaded', [file, previewId, i, reader]);
-                    return;
-                }
-                if ($preview.length > 0 && FileReader !== undefined) {
-                    $status.html(msgLoading.replace('{index}', i + 1).replace('{files}', numFiles));
-                    $container.addClass('loading');
-                    reader.onerror = function (evt) {
-                        self.errorHandler(evt, caption);
-                    };
-                    reader.onload = function (theFile) {
-                        self.previewFile(i, file, theFile, previewId, previewData);
-                        self.initFileActions();
-                    };
-                    reader.onloadend = function () {
-                        msg = msgProgress
-                            .replace('{index}', i + 1).replace('{files}', numFiles)
-                            .replace('{percent}', 50).replace('{name}', caption);
-                        setTimeout(function () {
-                            $status.html(msg);
-                            self.updateFileDetails(numFiles);
-                            readFile(i + 1);
-                        }, 100);
-                        self.raise('fileloaded', [file, previewId, i, reader]);
-                    };
-                    reader.onprogress = function (data) {
-                        if (data.lengthComputable) {
-                            var fact = (data.loaded / data.total) * 100, progress = Math.ceil(fact);
-                            msg = msgProgress.replace('{index}', i + 1).replace('{files}', numFiles)
-                                .replace('{percent}', progress).replace('{name}', caption);
-                            setTimeout(function () {
-                                $status.html(msg);
-                            }, 100);
-                        }
-                    };
-                    isText = isSet('text', settings) ? settings.text : defaultFileTypeSettings.text;
-                    if (isText(file.type, caption)) {
-                        reader.readAsText(file, self.textEncoding);
-                    } else {
-                        reader.readAsArrayBuffer(file);
-                    }
-                } else {
-                    self.previewDefault(file, previewId);
-                    setTimeout(function () {
-                        readFile(i + 1);
-                        self.updateFileDetails(numFiles);
-                    }, 100);
-                    self.raise('fileloaded', [file, previewId, i, reader]);
-                }
-                self.filestack.push(file);
-            }
-
-            readFile(0);
-            self.updateFileDetails(numFiles, false);
-        },
-        updateFileDetails: function (numFiles) {
-            var self = this, $el = self.$element, fileStack = self.getFileStack(),
-                name = $el.val() || (fileStack.length && fileStack[0].name) || '', label = self.slug(name),
-                n = self.isUploadable ? fileStack.length : numFiles,
-                nFiles = previewCache.count(self.id) + n,
-                log = n > 1 ? self.getMsgSelected(nFiles) : label;
-            if (self.isError) {
-                self.$previewContainer.removeClass('loading');
-                self.$previewStatus.html('');
-                self.$captionContainer.find('.kv-caption-icon').hide();
-            } else {
-                self.showFileIcon();
-            }
-            self.setCaption(log, self.isError);
-            self.$container.removeClass('file-input-new file-input-ajax-new');
-            if (arguments.length === 1) {
-                self.raise('fileselect', [numFiles, label]);
-            }
-            if (previewCache.count(self.id)) {
-                self.initPreviewDeletes();
-            }
-        },
-        change: function (e) {
-            var self = this, $el = self.$element;
-            if (!self.isUploadable && isEmpty($el.val()) && self.fileInputCleared) { // IE 11 fix
-                self.fileInputCleared = false;
-                return;
-            }
-            self.fileInputCleared = false;
-            var tfiles, msg, total, $preview = self.$preview, 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,
-                flagSingle = (isSingleUpload && ctr > 0),
-                throwError = function (mesg, file, previewId, index) {
-                    var p1 = $.extend(self.getOutData({}, {}, files), {id: previewId, index: index}),
-                        p2 = {id: previewId, index: index, file: file, files: files};
-                    return self.isUploadable ? self.showUploadError(mesg, p1) : self.showError(mesg, p2);
-                };
-            self.reader = null;
-            self.resetUpload();
-            self.hideFileIcon();
-            if (self.isUploadable) {
-                self.$container.find('.file-drop-zone .' + self.dropZoneTitleClass).remove();
-            }
-            if (isDragDrop) {
-                tfiles = [];
-                while (files[i]) {
-                    f = files[i];
-                    if (!f.type && f.size % 4096 === 0) {
-                        folders++;
-                    } else {
-                        tfiles.push(f);
-                    }
-                    i++;
-                }
-            } else {
-                if (e.target.files === undefined) {
-                    tfiles = e.target && e.target.value ? [
-                        {name: e.target.value.replace(/^.+\\/, '')}
-                    ] : [];
-                } else {
-                    tfiles = e.target.files;
-                }
-            }
-            if (isEmpty(tfiles) || tfiles.length === 0) {
-                if (!isAjaxUpload) {
-                    self.clear();
-                }
-                self.showFolderError(folders);
-                self.raise('fileselectnone');
-                return;
-            }
-            self.resetErrors();
-            len = tfiles.length;
-            total = self.isUploadable ? self.getFileStack().length + len : len;
-            if (self.maxFileCount > 0 && total > self.maxFileCount) {
-                if (!self.autoReplace || len > self.maxFileCount) {
-                    n = (self.autoReplace && len > self.maxFileCount) ? len : total;
-                    msg = self.msgFilesTooMany.replace('{m}', self.maxFileCount).replace('{n}', n);
-                    self.isError = throwError(msg, null, null, null);
-                    self.$captionContainer.find('.kv-caption-icon').hide();
-                    self.setCaption('', true);
-                    self.setEllipsis();
-                    self.$container.removeClass('file-input-new file-input-ajax-new');
-                    return;
-                }
-                if (total > self.maxFileCount) {
-                    self.resetPreviewThumbs(isAjaxUpload);
-                }
-            } else {
-                 if (!isAjaxUpload || flagSingle) {
-                    self.resetPreviewThumbs(false);
-                    if (flagSingle) {
-                        self.filestack = [];
-                    }
-                } else {
-                    if (isAjaxUpload && ctr === 0 && (!previewCache.count(self.id) || self.overwriteInitial)) {
-                        self.resetPreviewThumbs(true);
-                    }
-                }
-            }
-            if (self.isPreviewable) {
-                self.readFiles(tfiles);
-            } else {
-                self.updateFileDetails(1);
-            }
-            self.showFolderError(folders);
-        },
-        validateImage: function (i, previewId) {
-            var self = this, $preview = self.$preview, params, w1, w2, $cap,
-                $thumb = $preview.find("#" + previewId), fname = 'Untitled',
-                $img = $thumb.find('img');
-            if (!$img.length) {
-                return;
-            }
-            handler($img, 'load', function () {
-                w1 = $thumb.width();
-                w2 = $preview.width();
-                if (w1 > w2) {
-                    $img.css('width', '100%');
-                    $thumb.css('width', '97%');
-                }
-                $cap = $img.closest('.file-preview-frame').find('.file-caption-name');
-                if ($cap.length) {
-                    $cap.width($img.width());
-                    fname = $cap.text();
-                    $cap.attr('title', fname);
-                }
-                params = {ind: i, id: previewId};
-                self.checkDimensions(i, 'Small', $img, $thumb, fname, 'Width', params);
-                self.checkDimensions(i, 'Small', $img, $thumb, fname, 'Height', params);
-                self.checkDimensions(i, 'Large', $img, $thumb, fname, 'Width', params);
-                self.checkDimensions(i, 'Large', $img, $thumb, fname, 'Height', params);
-                self.raise('fileimageloaded', [previewId]);
-                objUrl.revokeObjectURL($img.attr('src'));
-            });
-        },
-        checkDimensions: function (i, chk, $img, $thumb, fname, type, params) {
-            var self = this, msg, dim, tag = chk === 'Small' ? 'min' : 'max',
-                limit = self[tag + 'Image' + type], $imgEl, isValid;
-            if (isEmpty(limit) || !$img.length) {
-                return;
-            }
-            $imgEl = $img[0];
-            dim = (type === 'Width') ? $imgEl.naturalWidth || $imgEl.width : $imgEl.naturalHeight || $imgEl.height;
-            isValid = chk === 'Small' ? dim >= limit : dim <= limit;
-            if (isValid) {
-                return;
-            }
-            msg = self['msgImage' + type + chk].replace('{name}', fname).replace('{size}', limit);
-            self.showUploadError(msg, params);
-            self.setThumbStatus($thumb, 'Error');
-            self.filestack[i] = null;
-        },
-        initCaption: function () {
-            var self = this, cap = self.initialCaption || '';
-            if (self.overwriteInitial || isEmpty(cap)) {
-                self.$caption.html('');
-                return false;
-            }
-            self.setCaption(cap);
-            return true;
-        },
-        setCaption: function (content, isError) {
-            var self = this, title, out;
-            if (isError) {
-                title = $('<div>' + self.msgValidationError + '</div>').text();
-                out = '<span class="' + self.msgValidationErrorClass + '">' +
-                self.msgValidationErrorIcon + title + '</span>';
-            } else {
-                if (isEmpty(content) || self.$caption.length === 0) {
-                    return;
-                }
-                title = $('<div>' + content + '</div>').text();
-                out = self.getLayoutTemplate('icon') + title;
-            }
-            self.$caption.html(out);
-            self.$caption.attr('title', title);
-            self.$captionContainer.find('.file-caption-ellipsis').attr('title', title);
-            self.setEllipsis();
-        },
-        initBrowse: function ($container) {
-            var self = this;
-            self.$btnFile = $container.find('.btn-file');
-            self.$btnFile.append(self.$element);
-        },
-        createContainer: function () {
-            var self = this,
-                $container = $(document.createElement("div"))
-                    .attr({"class": 'file-input file-input-new'})
-                    .html(self.renderMain());
-            self.$element.before($container);
-            self.initBrowse($container);
-            return $container;
-        },
-        refreshContainer: function () {
-            var self = this, $container = self.$container;
-            $container.before(self.$element);
-            $container.html(self.renderMain());
-            self.initBrowse($container);
-        },
-        renderMain: function () {
-            var self = this, dropCss = (self.isUploadable && self.dropZoneEnabled) ? ' file-drop-zone' : '',
-                preview = self.showPreview ? self.getLayoutTemplate('preview').repl('{class}', self.previewClass)
-                    .repl('{dropClass}', dropCss) : '',
-                css = self.isDisabled ? self.captionClass + ' file-caption-disabled' : self.captionClass,
-                caption = self.captionTemplate.repl('{class}', css + ' kv-fileinput-caption');
-            return self.mainTemplate.repl('{class}', self.mainClass)
-                .repl('{preview}', preview)
-                .repl('{caption}', caption)
-                .repl('{upload}', self.renderUpload())
-                .repl('{remove}', self.renderRemove())
-                .repl('{cancel}', self.renderCancel())
-                .repl('{browse}', self.renderBrowse());
-        },
-        renderBrowse: function () {
-            var self = this, css = self.browseClass + ' btn-file', status = '';
-            if (self.isDisabled) {
-                status = ' disabled ';
-            }
-            return '<div class="' + css + '"' + status + '> ' + self.browseIcon + self.browseLabel + ' </div>';
-        },
-        renderRemove: function () {
-            var self = this, css = self.removeClass + ' fileinput-remove fileinput-remove-button', status = '';
-            if (!self.showRemove) {
-                return '';
-            }
-            if (self.isDisabled) {
-                status = ' disabled ';
-            }
-            return '<button type="button" title="' + self.removeTitle + '" class="' + css + '"' + status + '>' + self.removeIcon + self.removeLabel + '</button>';
-        },
-        renderCancel: function () {
-            var self = this, css = self.cancelClass + ' fileinput-cancel fileinput-cancel-button';
-            if (!self.showCancel) {
-                return '';
-            }
-            return '<button type="button" title="' + self.cancelTitle + '" class="hide ' + css + '">' + self.cancelIcon + self.cancelLabel + '</button>';
-        },
-        renderUpload: function () {
-            var self = this, css = self.uploadClass + ' kv-fileinput-upload fileinput-upload-button', content = '', status = '';
-            if (!self.showUpload) {
-                return '';
-            }
-            if (self.isDisabled) {
-                status = ' disabled ';
-            }
-            if (!self.isUploadable || self.isDisabled) {
-                content = '<button type="submit" title="' + self.uploadTitle + '"class="' + css + '"' + status + '>' + self.uploadIcon + self.uploadLabel + '</button>';
-            } else {
-                content = '<a href="' + self.uploadUrl + '" title="' + self.uploadTitle + '" class="' + css + '"' + status + '>' + self.uploadIcon + self.uploadLabel + '</a>';
-            }
-            return content;
-        }
-    };
-
-    //FileInput plugin definition
-    $.fn.fileinput = function (option) {
-        if (!hasFileAPISupport() && !isIE(9)) {
-            return;
-        }
-
-        var args = Array.apply(null, arguments);
-        args.shift();
-        return this.each(function () {
-            var $this = $(this), data = $this.data('fileinput'), defaults,
-                options = typeof option === 'object' && option,
-                lang = options.language || $this.data('language') || 'en';
-
-            if (!data) {
-                defaults = $.extend({}, $.fn.fileinput.defaults);
-                if (lang !== 'en' && !isEmpty($.fn.fileinputLocales[lang])) {
-                    defaults = $.extend(defaults, $.fn.fileinputLocales[lang]);
-                }
-                data = new FileInput(this, $.extend(defaults, options, $this.data()));
-                $this.data('fileinput', data);
-            }
-
-            if (typeof option === 'string') {
-                data[option].apply(data, args);
-            }
-        });
-    };
-
-    $.fn.fileinput.defaults = {
-        language: 'en',
-        showCaption: true,
-        showPreview: true,
-        showRemove: true,
-        showUpload: true,
-        showCancel: true,
-        showUploadedThumbs: true,
-        autoReplace: false,
-        mainClass: '',
-        previewClass: '',
-        captionClass: '',
-        mainTemplate: null,
-        initialCaption: '',
-        initialPreview: [],
-        initialPreviewDelimiter: '*$$*',
-        initialPreviewConfig: [],
-        initialPreviewThumbTags: [],
-        previewThumbTags: {},
-        initialPreviewShowDelete: true,
-        deleteUrl: '',
-        deleteExtraData: {},
-        overwriteInitial: true,
-        layoutTemplates: defaultLayoutTemplates,
-        previewTemplates: defaultPreviewTemplates,
-        allowedPreviewTypes: defaultPreviewTypes,
-        allowedPreviewMimeTypes: null,
-        allowedFileTypes: null,
-        allowedFileExtensions: null,
-        customLayoutTags: {},
-        customPreviewTags: {},
-        previewSettings: defaultPreviewSettings,
-        fileTypeSettings: defaultFileTypeSettings,
-        previewFileIcon: '<i class="glyphicon glyphicon-file"></i>',
-        browseIcon: '<i class="glyphicon glyphicon-folder-open"></i> &nbsp;',
-        browseClass: 'btn btn-primary',
-        removeIcon: '<i class="glyphicon glyphicon-trash"></i> ',
-        removeClass: 'btn btn-default',
-        cancelIcon: '<i class="glyphicon glyphicon-ban-circle"></i> ',
-        cancelClass: 'btn btn-default',
-        uploadIcon: '<i class="glyphicon glyphicon-upload"></i> ',
-        uploadClass: 'btn btn-default',
-        uploadUrl: null,
-        uploadAsync: true,
-        uploadExtraData: {},
-        minImageWidth: null,
-        minImageHeight: null,
-        maxImageWidth: null,
-        maxImageHeight: null,
-        maxFileSize: 0,
-        minFileCount: 0,
-        maxFileCount: 0,
-        msgValidationErrorClass: 'text-danger',
-        msgValidationErrorIcon: '<i class="glyphicon glyphicon-exclamation-sign"></i> ',
-        msgErrorClass: 'file-error-message',
-        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>',
-        elCaptionContainer: null,
-        elCaptionText: null,
-        elPreviewContainer: null,
-        elPreviewImage: null,
-        elPreviewStatus: null,
-        elErrorContainer: null,
-        slugCallback: null,
-        dropZoneEnabled: true,
-        dropZoneTitleClass: 'file-drop-zone-title',
-        fileActionSettings: {},
-        otherActionButtons: '',
-        textEncoding: 'UTF-8',
-        ajaxSettings: {},
-        ajaxDeleteSettings: {},
-        showAjaxErrorDetails: true
-    };
-
-    $.fn.fileinputLocales.en = {
-        fileSingle: 'file',
-        filePlural: 'files',
-        browseLabel: 'Browse &hellip;',
-        removeLabel: 'Remove',
-        removeTitle: 'Clear selected files',
-        cancelLabel: 'Cancel',
-        cancelTitle: 'Abort ongoing upload',
-        uploadLabel: 'Upload',
-        uploadTitle: 'Upload selected files',
-        msgSizeTooLarge: 'File "{name}" (<b>{size} KB</b>) exceeds maximum allowed upload size of <b>{maxSize} KB</b>. Please retry your upload!',
-        msgFilesTooLess: 'You must select at least <b>{n}</b> {files} to upload. Please retry your upload!',
-        msgFilesTooMany: 'Number of files selected for upload <b>({n})</b> exceeds maximum allowed limit of <b>{m}</b>. Please retry your upload!',
-        msgFileNotFound: 'File "{name}" not found!',
-        msgFileSecured: 'Security restrictions prevent reading the file "{name}".',
-        msgFileNotReadable: 'File "{name}" is not readable.',
-        msgFilePreviewAborted: 'File preview aborted for "{name}".',
-        msgFilePreviewError: 'An error occurred while reading the file "{name}".',
-        msgInvalidFileType: 'Invalid type for file "{name}". Only "{types}" files are supported.',
-        msgInvalidFileExtension: 'Invalid extension for file "{name}". Only "{extensions}" files are supported.',
-        msgValidationError: 'File Upload Error',
-        msgLoading: 'Loading file {index} of {files} &hellip;',
-        msgProgress: 'Loading file {index} of {files} - {name} - {percent}% completed.',
-        msgSelected: '{n} {files} selected',
-        msgFoldersNotAllowed: 'Drag & drop files only! {n} folder(s) dropped were skipped.',
-        msgImageWidthSmall: 'Width of image file "{name}" must be at least {size} px.',
-        msgImageHeightSmall: 'Height of image file "{name}" must be at least {size} px.',
-        msgImageWidthLarge: 'Width of image file "{name}" cannot exceed {size} px.',
-        msgImageHeightLarge: 'Height of image file "{name}" cannot exceed {size} px.',
-        dropZoneTitle: 'Drag & drop files here &hellip;'
-    };
-
-    $.extend($.fn.fileinput.defaults, $.fn.fileinputLocales.en);
-
-    $.fn.fileinput.Constructor = FileInput;
-
-    /**
-     * Convert automatically file inputs with class 'file'
-     * into a bootstrap fileinput control.
-     */
-    $(document).ready(function () {
-        var $input = $('input.file[type=file]');
-        if ($input.length) {
-            $input.fileinput();
-        }
-    });
+/*!
+ * @copyright Copyright &copy; Kartik Visweswaran, Krajee.com, 2014 - 2015
+ * @version 4.2.6
+ *
+ * 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. It also offers the ability to upload and delete files using AJAX, and add 
+ * files in batches (i.e. preview, append, or remove before upload).
+ * 
+ * Author: Kartik Visweswaran
+ * Copyright: 2015, Kartik Visweswaran, Krajee.com
+ * For more JQuery plugins visit http://plugins.krajee.com
+ * For more Yii related demos visit http://demos.krajee.com
+ */
+(function ($) {
+    "use strict";
+
+    $.fn.fileinputLocales = {};
+
+    String.prototype.repl = function (from, to) {
+        return this.split(from).join(to);
+    };
+    var isIE = function (ver) {
+            var div = document.createElement("div"), status;
+            div.innerHTML = "<!--[if IE " + ver + "]><i></i><![endif]-->";
+            status = (div.getElementsByTagName("i").length === 1);
+            document.body.appendChild(div);
+            div.parentNode.removeChild(div);
+            return status;
+        },
+        handler = function ($el, event, callback, skipNS) {
+            var ev = skipNS ? event : event + '.fileinput';
+            $el.off(ev).on(ev, callback);
+        },
+        previewCache = {
+            data: {},
+            init: function (obj) {
+                var content = obj.initialPreview, id = obj.id;
+                if (content.length > 0 && !isArray(content)) {
+                    content = content.split(obj.initialPreviewDelimiter);
+                }
+                previewCache.data[id] = {
+                    content: content,
+                    config: obj.initialPreviewConfig,
+                    tags: obj.initialPreviewThumbTags,
+                    delimiter: obj.initialPreviewDelimiter,
+                    template: obj.previewGenericTemplate,
+                    msg: function (n) {
+                        return obj.getMsgSelected(n);
+                    },
+                    initId: obj.previewInitId,
+                    footer: obj.getLayoutTemplate('footer'),
+                    isDelete: obj.initialPreviewShowDelete,
+                    caption: obj.initialCaption,
+                    actions: function (showUpload, showDelete, disabled, url, key) {
+                        return obj.renderFileActions(showUpload, showDelete, disabled, url, key);
+                    }
+                };
+            },
+            fetch: function (id) {
+                return previewCache.data[id].content.filter(function (n) {
+                    return n !== null;
+                });
+            },
+            count: function (id, all) {
+                return !!previewCache.data[id] && !!previewCache.data[id].content ?
+                    (all ? previewCache.data[id].content.length : previewCache.fetch(id).length) : 0;
+            },
+            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';
+                isDisabled = isDisabled === undefined ? true : isDisabled;
+                if (data.content[i] === null) {
+                    return '';
+                }
+                if (!isEmpty(config) && !isEmpty(config.frameClass)) {
+                    frameClass += ' ' + config.frameClass;
+                }
+                out = data.template
+                    .repl('{previewId}', previewId)
+                    .repl('{frameClass}', frameClass)
+                    .repl('{fileindex}', ind)
+                    .repl('{content}', data.content[i])
+                    .repl('{footer}', previewCache.footer(id, i, isDisabled));
+                if (data.tags.length && data.tags[i]) {
+                    out = replaceTags(out, data.tags[i]);
+                }
+                if (!isEmpty(config) && !isEmpty(config.frameAttr)) {
+                    $tmp = $(document.createElement('div')).html(out);
+                    $tmp.find('.file-preview-initial').attr(config.frameAttr);
+                    out = $tmp.html();
+                    $tmp.remove();
+                }
+                return out;
+            },
+            add: function (id, content, config, tags, append) {
+                var data = $.extend(true, {}, previewCache.data[id]), index;
+                if (!isArray(content)) {
+                    content = content.split(data.delimiter);
+                }
+                if (append) {
+                    index = data.content.push(content) - 1;
+                    data.config[index] = config;
+                    data.tags[index] = tags;
+                } else {
+                    index = content.length;
+                    data.content = content;
+                    data.config = config;
+                    data.tags = tags;
+                }
+                previewCache.data[id] = data;
+                return index;
+            },
+            set: function (id, content, config, tags, append) {
+                var data = $.extend(true, {}, previewCache.data[id]), i;
+                if (!isArray(content)) {
+                    content = content.split(data.delimiter);
+                }
+                if (append) {
+                    for (i = 0; i < content.length; i++) {
+                        data.content.push(content[i]);
+                    }
+                    for (i = 0; i < config.length; i++) {
+                        data.config.push(config[i]);
+                    }
+                    for (i = 0; i < tags.length; i++) {
+                        data.tags.push(tags[i]);
+                    }
+                } else {
+                    data.content = content;
+                    data.config = config;
+                    data.tags = tags;
+                }
+                previewCache.data[id] = data;
+            },
+            unset: function (id, index) {
+                var chk = previewCache.count(id);
+                if (!chk) {
+                    return;
+                }
+                if (chk === 1) {
+                    previewCache.data[id].content = [];
+                    previewCache.data[id].config = [];
+                    return;
+                }
+                previewCache.data[id].content[index] = null;
+                previewCache.data[id].config[index] = null;
+            },
+            out: function (id) {
+                var html = '', data = previewCache.data[id], caption, len = previewCache.count(id, true);
+                if (len === 0) {
+                    return {content: '', caption: ''};
+                }
+                for (var i = 0; i < len; i++) {
+                    html += previewCache.get(id, i);
+                }
+                caption = data.msg(previewCache.count(id));
+                return {content: html, caption: caption};
+            },
+            footer: function (id, i, isDisabled) {
+                var data = previewCache.data[id];
+                isDisabled = isDisabled === undefined ? true : isDisabled;
+                if (data.config.length === 0 || isEmpty(data.config[i])) {
+                    return '';
+                }
+                var config = data.config[i],
+                    caption = isSet('caption', config) ? config.caption : '',
+                    width = isSet('width', config) ? config.width : 'auto',
+                    url = isSet('url', config) ? config.url : false,
+                    key = isSet('key', config) ? config.key : null,
+                    disabled = (url === false) && isDisabled,
+                    actions = data.isDelete ? data.actions(false, true, disabled, url, key) : '',
+                    footer = data.footer.repl('{actions}', actions);
+                return footer
+                    .repl('{caption}', caption)
+                    .repl('{width}', width)
+                    .repl('{indicator}', '')
+                    .repl('{indicatorTitle}', '');
+            }
+        },
+        getNum = function (num, def) {
+            def = def || 0;
+            if (typeof num === "number") {
+                return num;
+            }
+            if (typeof num === "string") {
+                num = parseFloat(num);
+            }
+            return isNaN(num) ? def : num;
+        },
+        hasFileAPISupport = function () {
+            return window.File && window.FileReader;
+        },
+        hasDragDropSupport = function () {
+            var $div = document.createElement('div');
+            return !isIE(9) && ($div.draggable !== undefined || ($div.ondragstart !== undefined && $div.ondrop !== undefined));
+        },
+        hasFileUploadSupport = function () {
+            return hasFileAPISupport() && window.FormData;
+        },
+        addCss = function ($el, css) {
+            $el.removeClass(css).addClass(css);
+        },
+        STYLE_SETTING = 'style="width:{width};height:{height};"',
+        OBJECT_PARAMS = '      <param name="controller" value="true" />\n' +
+            '      <param name="allowFullScreen" value="true" />\n' +
+            '      <param name="allowScriptAccess" value="always" />\n' +
+            '      <param name="autoPlay" value="false" />\n' +
+            '      <param name="autoStart" value="false" />\n' +
+            '      <param name="quality" value="high" />\n',
+        DEFAULT_PREVIEW = '<div class="file-preview-other">\n' +
+            '       {previewFileIcon}\n' +
+            '   </div>',
+        defaultFileActionSettings = {
+            removeIcon: '<i class="glyphicon glyphicon-trash text-danger"></i>',
+            removeClass: 'btn btn-xs btn-default',
+            removeTitle: 'Remove file',
+            uploadIcon: '<i class="glyphicon glyphicon-upload text-info"></i>',
+            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>',
+            indicatorError: '<i class="glyphicon glyphicon-exclamation-sign text-danger"></i>',
+            indicatorLoading: '<i class="glyphicon glyphicon-hand-up text-muted"></i>',
+            indicatorNewTitle: 'Not uploaded yet',
+            indicatorSuccessTitle: 'Uploaded',
+            indicatorErrorTitle: 'Upload Error',
+            indicatorLoadingTitle: 'Uploading ...'
+        },
+        tMain1 = '{preview}\n' +
+            '<div class="kv-upload-progress hide"></div>\n' +
+            '<div class="input-group {class}">\n' +
+            '   {caption}\n' +
+            '   <div class="input-group-btn">\n' +
+            '       {remove}\n' +
+            '       {cancel}\n' +
+            '       {upload}\n' +
+            '       {browse}\n' +
+            '   </div>\n' +
+            '</div>',
+        tMain2 = '{preview}\n<div class="kv-upload-progress hide"></div>\n{remove}\n{cancel}\n{upload}\n{browse}\n',
+        tPreview = '<div class="file-preview {class}">\n' +
+            '    <div class="close fileinput-remove">&times;</div>\n' +
+            '    <div class="{dropClass}">\n' +
+            '    <div class="file-preview-thumbnails">\n' +
+            '    </div>\n' +
+            '    <div class="clearfix"></div>' +
+            '    <div class="file-preview-status text-center text-success"></div>\n' +
+            '    <div class="kv-fileinput-error"></div>\n' +
+            '    </div>\n' +
+            '</div>',
+        tIcon = '<span class="glyphicon glyphicon-file kv-caption-icon"></span>',
+        tCaption = '<div tabindex="-1" class="form-control file-caption {class}">\n' +
+            '   <span class="file-caption-ellipsis">&hellip;</span>\n' +
+            '   <div class="file-caption-name"></div>\n' +
+            '</div>',
+        tModal = '<div id="{id}" class="modal fade">\n' +
+            '  <div class="modal-dialog modal-lg">\n' +
+            '    <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' +
+            '      </div>\n' +
+            '      <div class="modal-body">\n' +
+            '        <textarea class="form-control" style="font-family:Monaco,Consolas,monospace; height: {height}px;" readonly>{body}</textarea>\n' +
+            '      </div>\n' +
+            '    </div>\n' +
+            '  </div>\n' +
+            '</div>',
+        tProgress = '<div class="progress">\n' +
+            '    <div class="{class}" role="progressbar"' +
+            ' aria-valuenow="{percent}" aria-valuemin="0" aria-valuemax="100" style="width:{percent}%;">\n' +
+            '        {percent}%\n' +
+            '     </div>\n' +
+            '</div>',
+        tFooter = '<div class="file-thumbnail-footer">\n' +
+            '    <div class="file-caption-name">{caption}</div>\n' +
+            '    {actions}\n' +
+            '</div>',
+        tActions = '<div class="file-actions">\n' +
+            '    <div class="file-footer-buttons">\n' +
+            '        {upload}{delete}{other}' +
+            '    </div>\n' +
+            '    <div class="file-upload-indicator" tabindex="-1" title="{indicatorTitle}">{indicator}</div>\n' +
+            '    <div class="clearfix"></div>\n' +
+            '</div>',
+        tActionDelete = '<button type="button" class="kv-file-remove {removeClass}" ' +
+            'title="{removeTitle}"{dataUrl}{dataKey}>{removeIcon}</button>\n',
+        tActionUpload = '<button type="button" class="kv-file-upload {uploadClass}" title="{uploadTitle}">' +
+            '   {uploadIcon}\n</button>\n',
+        tGeneric = '<div class="file-preview-frame{frameClass}" id="{previewId}" data-fileindex="{fileindex}">\n' +
+            '   {content}\n' +
+            '   {footer}\n' +
+            '</div>\n',
+        tHtml = '<div class="file-preview-frame{frameClass}" id="{previewId}" data-fileindex="{fileindex}">\n' +
+            '    <object data="{data}" type="{type}" width="{width}" height="{height}">\n' +
+            '       ' + DEFAULT_PREVIEW + '\n' +
+            '    </object>\n' +
+            '   {footer}\n' +
+            '</div>',
+        tImage = '<div class="file-preview-frame{frameClass}" id="{previewId}" data-fileindex="{fileindex}">\n' +
+            '   <img src="{data}" class="file-preview-image" title="{caption}" alt="{caption}" ' + STYLE_SETTING + '>\n' +
+            '   {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' +
+            '   {footer}\n' +
+            '</div>',
+        tVideo = '<div class="file-preview-frame{frameClass}" id="{previewId}" data-fileindex="{fileindex}"' +
+            ' title="{caption}" ' + STYLE_SETTING + '>\n' +
+            '   <video width="{width}" height="{height}" controls>\n' +
+            '       <source src="{data}" type="{type}">\n' +
+            '       ' + DEFAULT_PREVIEW + '\n' +
+            '   </video>\n' +
+            '   {footer}\n' +
+            '</div>\n',
+        tAudio = '<div class="file-preview-frame{frameClass}" id="{previewId}" data-fileindex="{fileindex}"' +
+            ' title="{caption}" ' + STYLE_SETTING + '>\n' +
+            '   <audio controls>\n' +
+            '       <source src="' + '{data}' + '" type="{type}">\n' +
+            '       ' + DEFAULT_PREVIEW + '\n' +
+            '   </audio>\n' +
+            '   {footer}\n' +
+            '</div>',
+        tFlash = '<div class="file-preview-frame{frameClass}" id="{previewId}" data-fileindex="{fileindex}"' +
+            ' title="{caption}" ' + STYLE_SETTING + '>\n' +
+            '   <object type="application/x-shockwave-flash" width="{width}" height="{height}" data="{data}">\n' +
+            OBJECT_PARAMS + '       ' + DEFAULT_PREVIEW + '\n' +
+            '   </object>\n' +
+            '   {footer}\n' +
+            '</div>\n',
+        tObject = '<div class="file-preview-frame{frameClass}" id="{previewId}" data-fileindex="{fileindex}"' +
+            ' title="{caption}" ' + STYLE_SETTING + '>\n' +
+            '   <object data="{data}" type="{type}" width="{width}" height="{height}">\n' +
+            '       <param name="movie" value="{caption}" />\n' +
+            OBJECT_PARAMS + '         ' + DEFAULT_PREVIEW + '\n' +
+            '   </object>\n' +
+            '   {footer}\n' +
+            '</div>',
+        tOther = '<div class="file-preview-frame{frameClass}" id="{previewId}" data-fileindex="{fileindex}"' +
+            ' title="{caption}" ' + STYLE_SETTING + '>\n' +
+            '   ' + DEFAULT_PREVIEW + '\n' +
+            '   {footer}\n' +
+            '</div>',
+        defaultLayoutTemplates = {
+            main1: tMain1,
+            main2: tMain2,
+            preview: tPreview,
+            icon: tIcon,
+            caption: tCaption,
+            modal: tModal,
+            progress: tProgress,
+            footer: tFooter,
+            actions: tActions,
+            actionDelete: tActionDelete,
+            actionUpload: tActionUpload
+        },
+        defaultPreviewTemplates = {
+            generic: tGeneric,
+            html: tHtml,
+            image: tImage,
+            text: tText,
+            video: tVideo,
+            audio: tAudio,
+            flash: tFlash,
+            object: tObject,
+            other: tOther
+        },
+        defaultPreviewTypes = ['image', 'html', 'text', 'video', 'audio', 'flash', 'object'],
+        defaultPreviewSettings = {
+            image: {width: "auto", height: "160px"},
+            html: {width: "213px", height: "160px"},
+            text: {width: "160px", height: "160px"},
+            video: {width: "213px", height: "160px"},
+            audio: {width: "213px", height: "80px"},
+            flash: {width: "213px", height: "160px"},
+            object: {width: "160px", height: "160px"},
+            other: {width: "160px", height: "160px"}
+        },
+        defaultFileTypeSettings = {
+            image: function (vType, vName) {
+                return (vType !== undefined) ? vType.match('image.*') : vName.match(/\.(gif|png|jpe?g)$/i);
+            },
+            html: function (vType, vName) {
+                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);
+            },
+            video: function (vType, vName) {
+                return (vType !== undefined && vType.match(/\.video\/(ogg|mp4|webm)$/i)) || vName.match(/\.(og?|mp4|webm)$/i);
+            },
+            audio: function (vType, vName) {
+                return (vType !== undefined && vType.match(/\.audio\/(ogg|mp3|wav)$/i)) || vName.match(/\.(ogg|mp3|wav)$/i);
+            },
+            flash: function (vType, vName) {
+                return (vType !== undefined && vType === 'application/x-shockwave-flash') || vName.match(/\.(swf)$/i);
+            },
+            object: function () {
+                return true;
+            },
+            other: function () {
+                return true;
+            }
+        },
+        isEmpty = function (value, trim) {
+            return value === null || value === undefined || value.length === 0 || (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);
+        },
+        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));
+        },
+        htmlEncode = function (str) {
+            return String(str).repl('&', '&amp;')
+                .repl('"', '&quot;')
+                .repl("'", '&#39;')
+                .repl('<', '&lt;')
+                .repl('>', '&gt;');
+        },
+        replaceTags = function (str, tags) {
+            var out = str;
+            tags = tags || {};
+            $.each(tags, function (key, value) {
+                if (typeof value === "function") {
+                    value = value();
+                }
+                out = out.repl(key, value);
+            });
+            return out;
+        },
+        objUrl = window.URL || window.webkitURL,
+        FileInput = function (element, options) {
+            var self = this;
+            self.$element = $(element);
+            if (!self.validate()) {
+                return;
+            }
+            self.isPreviewable = hasFileAPISupport();
+            self.isIE9 = isIE(9);
+            self.isIE10 = isIE(10);
+            if (self.isPreviewable || self.isIE9) {
+                self.init(options);
+                self.listen();
+            } else {
+                self.$element.removeClass('file-loading');
+            }
+        };
+
+    FileInput.prototype = {
+        constructor: FileInput,
+        validate: function () {
+            var self = this, $exception;
+            if (self.$element.attr('type') === 'file') {
+                return true;
+            }
+            $exception = '<div class="help-block alert alert-warning">' +
+            '<h4>Invalid Input Type</h4>' +
+            'You must set an input <code>type = file</code> for <b>bootstrap-fileinput</b> plugin to initialize.' +
+            '</div>';
+            self.$element.after($exception);
+            return false;
+        },
+        init: function (options) {
+            var self = this, $el = self.$element, t;
+            $.each(options, function (key, value) {
+                self[key] = (key === 'maxFileCount' || key === 'maxFileSize') ? getNum(value) : value;
+            });
+            self.fileInputCleared = false;
+            self.fileBatchCompleted = true;
+            if (isEmpty(self.allowedPreviewTypes)) {
+                self.allowedPreviewTypes = defaultPreviewTypes;
+            }
+            if (!self.isPreviewable) {
+                self.showPreview = false;
+            }
+            self.uploadFileAttr = !isEmpty($el.attr('name')) ? $el.attr('name') : 'file_data';
+            self.reader = null;
+            self.formdata = {};
+            self.filestack = [];
+            self.ajaxRequests = [];
+            self.isError = false;
+            self.ajaxAborted = false;
+            self.dropZoneEnabled = hasDragDropSupport() && self.dropZoneEnabled;
+            self.isDisabled = self.$element.attr('disabled') || self.$element.attr('readonly');
+            self.isUploadable = hasFileUploadSupport() && !isEmpty(self.uploadUrl);
+            self.slug = typeof options.slugCallback === "function" ? options.slugCallback : self.slugDefault;
+            self.mainTemplate = self.showCaption ? self.getLayoutTemplate('main1') : self.getLayoutTemplate('main2');
+            self.captionTemplate = self.getLayoutTemplate('caption');
+            self.previewGenericTemplate = self.getPreviewTemplate('generic');
+            if (isEmpty(self.$element.attr('id'))) {
+                self.$element.attr('id', uniqId());
+            }
+            if (self.$container === undefined) {
+                self.$container = self.createContainer();
+            } else {
+                self.refreshContainer();
+            }
+            self.$progress = self.$container.find('.kv-upload-progress');
+            self.$btnUpload = self.$container.find('.kv-fileinput-upload');
+            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'));
+            if (!isEmpty(self.msgErrorClass)) {
+                addCss(self.$errorContainer, self.msgErrorClass);
+            }
+            self.$errorContainer.hide();
+            self.fileActionSettings = $.extend(defaultFileActionSettings, options.fileActionSettings);
+            self.previewInitId = "preview-" + uniqId();
+            self.id = self.$element.attr('id');
+            previewCache.init(self);
+            self.initPreview(true);
+            self.initPreviewDeletes();
+            self.options = options;
+            self.setFileDropZoneTitle();
+            self.uploadCount = 0;
+            self.uploadPercent = 0;
+            self.$element.removeClass('file-loading');
+            t = self.getLayoutTemplate('progress');
+            self.progressTemplate = t.replace('{class}', self.progressClass);
+            self.progressCompleteTemplate = t.replace('{class}', self.progressCompleteClass);
+            self.setEllipsis();
+        },
+        parseError: function (jqXHR, errorThrown, fileName) {
+            var self = this, errMsg = $.trim(errorThrown + ''),
+                dot = errMsg.slice(-1) === '.' ? '' : '.',
+                text = jqXHR.responseJSON !== undefined && jqXHR.responseJSON.error !== undefined ?
+                    jqXHR.responseJSON.error : jqXHR.responseText;
+            if (self.showAjaxErrorDetails) {
+                text = $.trim(text.replace(/\n\s*\n/g, '\n'));
+                text = text.length > 0 ? '<pre>' + text + '</pre>' : '';
+                errMsg += dot + text;
+            } else {
+                errMsg += dot;
+            }
+            return fileName ? '<b>' + fileName + ': </b>' + jqXHR : errMsg;
+        },
+        raise: function (event, params) {
+            var self = this, e = $.Event(event);
+            if (params !== undefined) {
+                self.$element.trigger(e, params);
+            } else {
+                self.$element.trigger(e);
+            }
+            if (!e.result) {
+                return e.result;
+            }
+            switch (event) {
+                // ignore these events
+                case 'filebatchuploadcomplete':
+                case 'filebatchuploadsuccess':
+                case 'fileuploaded':
+                case 'fileclear':
+                case 'filecleared':
+                case 'filereset':
+                case 'fileerror':
+                case 'filefoldererror':
+                case 'fileuploaderror':
+                case 'filebatchuploaderror':
+                case 'filedeleteerror':
+                case 'filecustomerror':
+                case 'filesuccessremove':
+                    break;
+                // receive data response via `filecustomerror` event`
+                default:
+                    self.ajaxAborted = e.result;
+                    break;
+            }
+            return true;
+        },
+        getLayoutTemplate: function (t) {
+            var self = this,
+                template = isSet(t, self.layoutTemplates) ? self.layoutTemplates[t] : defaultLayoutTemplates[t];
+            if (isEmpty(self.customLayoutTags)) {
+                return template;
+            }
+            return replaceTags(template, self.customLayoutTags);
+        },
+        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);
+        },
+        getOutData: function (jqXHR, responseData, filesData) {
+            var self = this;
+            jqXHR = jqXHR || {};
+            responseData = responseData || {};
+            filesData = filesData || self.filestack.slice(0) || {};
+            return {
+                form: self.formdata,
+                files: filesData,
+                extra: self.getExtraData(),
+                response: responseData,
+                reader: self.reader,
+                jqXHR: jqXHR
+            };
+        },
+        setEllipsis: function () {
+            var self = this, $capCont = self.$captionContainer, $cap = self.$caption,
+                $div = $cap.clone().css('height', 'auto').hide();
+            $capCont.parent().before($div);
+            $capCont.removeClass('kv-has-ellipsis');
+            if ($div.outerWidth() > $cap.outerWidth()) {
+                $capCont.addClass('kv-has-ellipsis');
+            }
+            $div.remove();
+        },
+        listen: function () {
+            var self = this, $el = self.$element, $cap = self.$captionContainer, $btnFile = self.$btnFile,
+                $form = $el.closest('form'), $cont = self.$container;
+            handler($el, 'change', $.proxy(self.change, self));
+            handler($(window), 'resize', function () {
+                self.setEllipsis();
+            });
+            handler($btnFile, 'click', function () {
+                self.raise('filebrowse');
+                if (self.isError && !self.isUploadable) {
+                    self.clear();
+                }
+                $cap.focus();
+            });
+            handler($form, 'reset', $.proxy(self.reset, self));
+            handler($cont.find('.fileinput-remove:not([disabled])'), 'click', $.proxy(self.clear, self));
+            handler($cont.find('.fileinput-cancel'), 'click', $.proxy(self.cancel, self));
+            if (self.isUploadable && self.dropZoneEnabled && self.showPreview) {
+                self.initDragDrop();
+            }
+            if (!self.isUploadable) {
+                handler($form, 'submit', $.proxy(self.submitForm, self));
+            }
+            handler(self.$container.find('.kv-fileinput-upload'), 'click', function (e) {
+                var $btn = $(this), $form, isEnabled = !$btn.hasClass('disabled') && isEmpty($btn.attr('disabled'));
+                if (!self.isUploadable) {
+                    if (isEnabled && $btn.attr('type') !== 'submit') {
+                        $form = $btn.closest('form');
+                        // downgrade to normal form submit if possible
+                        if ($form.length) {
+                            $form.trigger('submit');
+                        }
+                        e.preventDefault();
+                    }
+                    return;
+                }
+                e.preventDefault();
+                if (isEnabled) {
+                    self.upload();
+                }
+            });
+        },
+        submitForm: function () {
+            var self = this, $el = self.$element, files = $el.get(0).files;
+            if (files && files.length < self.minFileCount && self.minFileCount > 0) {
+                self.noFilesError({});
+                return false;
+            }
+            return !self.abort({});
+        },
+        abort: function (params) {
+            var self = this, data;
+            if (self.ajaxAborted && typeof self.ajaxAborted === "object" && self.ajaxAborted.message !== undefined) {
+                data = $.extend(self.getOutData(), params);
+                data.abortData = self.ajaxAborted.data || {};
+                data.abortMessage = self.ajaxAborted.message;
+                self.showUploadError(self.ajaxAborted.message, data, 'filecustomerror');
+                return true;
+            }
+            return false;
+        },
+        noFilesError: function (params) {
+            var self = this, label = self.minFileCount > 1 ? self.filePlural : self.fileSingle,
+                msg = self.msgFilesTooLess.replace('{n}', self.minFileCount).replace('{files}', label),
+                $error = self.$errorContainer;
+            $error.html(msg);
+            self.isError = true;
+            self.updateFileDetails(0);
+            $error.fadeIn(800);
+            self.raise('fileerror', [params]);
+            self.clearFileInput();
+            addCss(self.$container, 'has-error');
+        },
+        setProgress: function (p) {
+            var self = this, pct = Math.min(p, 100),
+                template = pct < 100 ? self.progressTemplate : self.progressCompleteTemplate;
+            if (!isEmpty(template)) {
+                self.$progress.html(template.repl('{percent}', pct));
+            }
+        },
+        upload: function () {
+            var self = this, totLen = self.getFileStack().length, params = {},
+                i, outData, len, hasExtraData = !$.isEmptyObject(self.getExtraData());
+            if (totLen < self.minFileCount && self.minFileCount > 0) {
+                self.noFilesError(params);
+                return;
+            }
+            if (!self.isUploadable || self.isDisabled || (totLen === 0 && !hasExtraData)) {
+                return;
+            }
+            self.resetUpload();
+            self.$progress.removeClass('hide');
+            self.uploadCount = 0;
+            self.uploadPercent = 0;
+            self.lock();
+            self.setProgress(0);
+            if (totLen === 0 && hasExtraData) {
+                self.uploadExtraOnly();
+                return;
+            }
+            len = self.filestack.length;
+            self.hasInitData = false;
+            if (self.uploadAsync && self.showPreview) {
+                outData = self.getOutData();
+                self.raise('filebatchpreupload', [outData]);
+                self.fileBatchCompleted = false;
+                self.uploadCache = {content: [], config: [], tags: [], append: true};
+                for (i = 0; i < len; i += 1) {
+                    if (self.filestack[i] !== undefined) {
+                        self.uploadSingle(i, self.filestack, true);
+                    }
+                }
+                return;
+            }
+            self.uploadBatch();
+        },
+        lock: function () {
+            var self = this;
+            self.resetErrors();
+            self.disable();
+            if (self.showRemove) {
+                addCss(self.$container.find('.fileinput-remove'), 'hide');
+            }
+            if (self.showCancel) {
+                self.$container.find('.fileinput-cancel').removeClass('hide');
+            }
+            self.raise('filelock', [self.filestack, self.getExtraData()]);
+        },
+        unlock: function (reset) {
+            var self = this;
+            if (reset === undefined) {
+                reset = true;
+            }
+            self.enable();
+            if (self.showCancel) {
+                addCss(self.$container.find('.fileinput-cancel'), 'hide');
+            }
+            if (self.showRemove) {
+                self.$container.find('.fileinput-remove').removeClass('hide');
+            }
+            if (reset) {
+                self.resetFileStack();
+            }
+            self.raise('fileunlock', [self.filestack, self.getExtraData()]);
+        },
+        resetFileStack: function () {
+            var self = this, i = 0, newstack = [];
+            self.getThumbs().each(function () {
+                var $thumb = $(this), ind = $thumb.attr('data-fileindex'),
+                    file = self.filestack[ind];
+                if (ind === -1) {
+                    return;
+                }
+                if (file !== undefined) {
+                    newstack[i] = file;
+                    $thumb.attr({
+                        'id': self.previewInitId + '-' + i,
+                        'data-fileindex': i
+                    });
+                    i += 1;
+                } else {
+                    $thumb.attr({
+                        'id': 'uploaded-' + uniqId(),
+                        'data-fileindex': '-1'
+                    });
+                }
+            });
+            self.filestack = newstack;
+        },
+        destroy: function () {
+            var self = this, $cont = self.$container;
+            $cont.find('.file-drop-zone').off();
+            self.$element.insertBefore($cont).off('.fileinput').removeData();
+            $cont.off().remove();
+        },
+        refresh: function (options) {
+            var self = this, $el = self.$element;
+            options = options ? $.extend(self.options, options) : self.options;
+            self.destroy();
+            $el.fileinput(options);
+            if ($el.val()) {
+                $el.trigger('change.fileinput');
+            }
+        },
+        initDragDrop: function () {
+            var self = this, $zone = self.$container.find('.file-drop-zone'),
+                allEvents = 'dragenter.fileinput dragover.fileinput drop.fileinput';
+            handler($zone, 'dragenter.fileinput dragover.fileinput', function (e) {
+                var hasFiles = $.inArray('Files', e.originalEvent.dataTransfer.types) > -1;
+                e.stopPropagation();
+                e.preventDefault();
+                if (self.isDisabled || !hasFiles) {
+                    e.originalEvent.dataTransfer.effectAllowed = 'none';
+                    e.originalEvent.dataTransfer.dropEffect = 'none';
+                    return;
+                }
+                addCss($(this), 'highlighted');
+            }, true);
+            handler($zone, 'dragleave', function (e) {
+                e.stopPropagation();
+                e.preventDefault();
+                if (self.isDisabled) {
+                    return;
+                }
+                $(this).removeClass('highlighted');
+            });
+            handler($zone, 'drop', function (e) {
+                e.preventDefault();
+                if (self.isDisabled || isEmpty(e.originalEvent.dataTransfer.files)) {
+                    return;
+                }
+                self.change(e, 'dragdrop');
+                $(this).removeClass('highlighted');
+            });
+            handler($(document), allEvents, function (e) {
+                e.stopPropagation();
+                e.preventDefault();
+            }, true);
+        },
+        setFileDropZoneTitle: function () {
+            var self = this, $zone = self.$container.find('.file-drop-zone');
+            $zone.find('.' + self.dropZoneTitleClass).remove();
+            if (!self.isUploadable || !self.showPreview || $zone.length === 0 || self.getFileStack().length > 0 || !self.dropZoneEnabled) {
+                return;
+            }
+            if ($zone.find('.file-preview-frame').length === 0) {
+                $zone.prepend('<div class="' + self.dropZoneTitleClass + '">' + self.dropZoneTitle + '</div>');
+            }
+            self.$container.removeClass('file-input-new');
+            addCss(self.$container, 'file-input-ajax-new');
+        },
+        initFileActions: function () {
+            var self = this;
+            self.$preview.find('.kv-file-remove').each(function () {
+                var $el = $(this), $frame = $el.closest('.file-preview-frame'),
+                    ind = $frame.attr('data-fileindex'), n, cap;
+                handler($el, 'click', function () {
+                    self.cleanMemory($frame);
+                    $frame.fadeOut('slow', function () {
+                        self.filestack[ind] = undefined;
+                        self.clearObjects($frame);
+                        $frame.remove();
+                        var filestack = self.getFileStack(true), len = filestack.length,
+                            chk = previewCache.count(self.id);
+                        self.clearFileInput();
+                        if (len === 0 && chk === 0) {
+                            self.reset();
+                        } else {
+                            n = chk + len;
+                            cap = n > 1 ? self.getMsgSelected(n) : (filestack[0] ? filestack[0].name : '');
+                            self.setCaption(cap);
+                        }
+                    });
+                });
+            });
+            self.$preview.find('.kv-file-upload').each(function () {
+                var $el = $(this);
+                handler($el, 'click', function () {
+                    var $frame = $el.closest('.file-preview-frame'),
+                        ind = $frame.attr('data-fileindex');
+                    self.uploadSingle(ind, self.filestack, false);
+                });
+            });
+        },
+        getMsgSelected: function (n) {
+            var self = this, strFiles = n === 1 ? self.fileSingle : self.filePlural;
+            return self.msgSelected.replace('{n}', n).replace('{files}', strFiles);
+        },
+        renderFileFooter: function (caption, width) {
+            var self = this, config = self.fileActionSettings, footer, out,
+                template = self.getLayoutTemplate('footer');
+            if (self.isUploadable) {
+                footer = template.repl('{actions}', self.renderFileActions(true, true, false, false, false));
+                out = footer.repl('{caption}', caption)
+                    .repl('{width}', width)
+                    .repl('{indicator}', config.indicatorNew)
+                    .repl('{indicatorTitle}', config.indicatorNewTitle);
+            } else {
+                out = template.repl('{actions}', '')
+                    .repl('{caption}', caption)
+                    .repl('{width}', width)
+                    .repl('{indicator}', '')
+                    .repl('{indicatorTitle}', '');
+            }
+            out = replaceTags(out, self.previewThumbTags);
+            return out;
+        },
+        renderFileActions: function (showUpload, showDelete, disabled, url, key) {
+            if (!showUpload && !showDelete) {
+                return '';
+            }
+            var self = this,
+                vUrl = url === false ? '' : ' data-url="' + url + '"',
+                vKey = key === false ? '' : ' data-key="' + key + '"',
+                btnDelete = self.getLayoutTemplate('actionDelete'),
+                btnUpload = '',
+                template = self.getLayoutTemplate('actions'),
+                otherButtons = self.otherActionButtons.repl('{dataKey}', vKey),
+                config = self.fileActionSettings,
+                removeClass = disabled ? config.removeClass + ' disabled' : config.removeClass;
+            btnDelete = btnDelete
+                .repl('{removeClass}', removeClass)
+                .repl('{removeIcon}', config.removeIcon)
+                .repl('{removeTitle}', config.removeTitle)
+                .repl('{dataUrl}', vUrl)
+                .repl('{dataKey}', vKey);
+            if (showUpload) {
+                btnUpload = self.getLayoutTemplate('actionUpload')
+                    .repl('{uploadClass}', config.uploadClass)
+                    .repl('{uploadIcon}', config.uploadIcon)
+                    .repl('{uploadTitle}', config.uploadTitle);
+            }
+            return template
+                .repl('{delete}', btnDelete)
+                .repl('{upload}', btnUpload)
+                .repl('{other}', otherButtons);
+        },
+        setThumbStatus: function ($thumb, status) {
+            var self = this, icon = 'indicator' + status, msg = icon + 'Title',
+                css = 'file-preview-' + status.toLowerCase(),
+                $indicator = $thumb.find('.file-upload-indicator'),
+                config = self.fileActionSettings;
+            $thumb.removeClass('file-preview-success file-preview-error file-preview-loading');
+            $indicator.html(config[icon]);
+            $indicator.attr('title', config[msg]);
+            $thumb.addClass(css);
+        },
+        clearPreview: function () {
+            var self = this, $thumbs = !self.showUploadedThumbs ? self.$preview.find('.file-preview-frame') :
+                self.$preview.find('.file-preview-frame:not(.file-preview-success)');
+            $thumbs.remove();
+            if (!self.$preview.find('.file-preview-frame').length || !self.showPreview) {
+                self.resetUpload();
+            }
+        },
+        initPreview: function (isInit) {
+            var self = this, cap = self.initialCaption || '', out;
+            if (!previewCache.count(self.id)) {
+                self.clearPreview();
+                if (isInit) {
+                    self.setCaption(cap);
+                } else {
+                    self.initCaption();
+                }
+                return;
+            }
+            out = previewCache.out(self.id);
+            cap = isInit && self.initialCaption ? self.initialCaption : out.caption;
+            self.$preview.html(out.content);
+            self.setCaption(cap);
+            if (!isEmpty(out.content)) {
+                self.$container.removeClass('file-input-new');
+            }
+        },
+        initPreviewDeletes: function () {
+            var self = this, deleteExtraData = self.deleteExtraData || {},
+                resetProgress = function () {
+                    if (self.$preview.find('.kv-file-remove').length === 0) {
+                        self.reset();
+                        self.initialCaption = '';
+                    }
+                };
+
+            self.$preview.find('.kv-file-remove').each(function () {
+                var $el = $(this), vUrl = $el.data('url') || self.deleteUrl, vKey = $el.data('key');
+                if (isEmpty(vUrl) || vKey === undefined) {
+                    return;
+                }
+                var $frame = $el.closest('.file-preview-frame'), cache = previewCache.data[self.id],
+                    settings, params, index = $frame.data('fileindex'), config, extraData;
+                index = parseInt(index.replace('init_', ''));
+                config = isEmpty(cache.config) && isEmpty(cache.config[index]) ? null : cache.config[index];
+                extraData = isEmpty(config) || isEmpty(config.extra) ? deleteExtraData : config.extra;
+                if (typeof extraData === "function") {
+                    extraData = extraData();
+                }
+                params = {id: $el.attr('id'), key: vKey, extra: extraData};
+                settings = $.extend({
+                    url: vUrl,
+                    type: 'POST',
+                    dataType: 'json',
+                    data: $.extend({key: vKey}, extraData),
+                    beforeSend: function (jqXHR) {
+                        self.ajaxAborted = false;
+                        self.raise('filepredelete', [vKey, jqXHR, extraData]);
+                        if (self.ajaxAborted) {
+                            jqXHR.abort();
+                        } else {
+                            addCss($frame, 'file-uploading');
+                            addCss($el, 'disabled');
+                        }
+                    },
+                    success: function (data, textStatus, jqXHR) {
+                        var n, cap;
+                        if (isEmpty(data) || isEmpty(data.error)) {
+                            previewCache.unset(self.id, index);
+                            n = previewCache.count(self.id);
+                            cap = n > 0 ? self.getMsgSelected(n) : '';
+                            self.raise('filedeleted', [vKey, jqXHR, extraData]);
+                            self.setCaption(cap);
+                        } else {
+                            params.jqXHR = jqXHR;
+                            params.response = data;
+                            self.showError(data.error, params, 'filedeleteerror');
+                            $frame.removeClass('file-uploading');
+                            $el.removeClass('disabled');
+                            resetProgress();
+                            return;
+                        }
+                        $frame.removeClass('file-uploading').addClass('file-deleted');
+                        $frame.fadeOut('slow', function () {
+                            self.clearObjects($frame);
+                            $frame.remove();
+                            resetProgress();
+                            if (!n && self.getFileStack().length === 0) {
+                                self.setCaption('');
+                                self.reset();
+                            }
+                        });
+                    },
+                    error: function (jqXHR, textStatus, errorThrown) {
+                        var errMsg = self.parseError(jqXHR, errorThrown);
+                        params.jqXHR = jqXHR;
+                        params.response = {};
+                        self.showError(errMsg, params, 'filedeleteerror');
+                        $frame.removeClass('file-uploading');
+                        resetProgress();
+                    }
+                }, self.ajaxDeleteSettings);
+                handler($el, 'click', function () {
+                    $.ajax(settings);
+                });
+            });
+        },
+        clearObjects: function ($el) {
+            $el.find('video audio').each(function () {
+                this.pause();
+                $(this).remove();
+            });
+            $el.find('img object div').each(function () {
+                $(this).remove();
+            });
+        },
+        clearFileInput: function () {
+            var self = this, $el = self.$element, $srcFrm, $tmpFrm, $tmpEl;
+            if (isEmpty($el.val())) {
+                return;
+            }
+            // Fix for IE ver < 11, that does not clear file inputs
+            // Requires a sequence of steps to prevent IE crashing but
+            // still allow clearing of the file input.
+            if (self.isIE9 || self.isIE10) {
+                $srcFrm = $el.closest('form');
+                $tmpFrm = $(document.createElement('form'));
+                $tmpEl = $(document.createElement('div'));
+                $el.before($tmpEl);
+                if ($srcFrm.length) {
+                    $srcFrm.after($tmpFrm);
+                } else {
+                    $tmpEl.after($tmpFrm);
+                }
+                $tmpFrm.append($el).trigger('reset');
+                $tmpEl.before($el).remove();
+                $tmpFrm.remove();
+            } else { // normal input clear behavior for other sane browsers
+                $el.val('');
+            }
+            self.fileInputCleared = true;
+        },
+        resetUpload: function () {
+            var self = this;
+            self.uploadCache = {content: [], config: [], tags: [], append: true};
+            self.uploadCount = 0;
+            self.uploadPercent = 0;
+            self.$btnUpload.removeAttr('disabled');
+            self.setProgress(0);
+            addCss(self.$progress, 'hide');
+            self.resetErrors(false);
+            self.ajaxAborted = false;
+            self.ajaxRequests = [];
+        },
+        cancel: function () {
+            var self = this, xhr = self.ajaxRequests, len = xhr.length, i;
+            if (len > 0) {
+                for (i = 0; i < len; i += 1) {
+                    xhr[i].abort();
+                }
+            }
+            self.getThumbs().each(function () {
+                var $thumb = $(this), ind = $thumb.attr('data-fileindex');
+                $thumb.removeClass('file-uploading');
+                if (self.filestack[ind] !== undefined) {
+                    $thumb.find('.kv-file-upload').removeClass('disabled').removeAttr('disabled');
+                    $thumb.find('.kv-file-remove').removeClass('disabled').removeAttr('disabled');
+                }
+                self.unlock();
+            });
+        },
+        cleanMemory: function ($thumb) {
+            var data = $thumb.is('img') ? $thumb.attr('src') : $thumb.find('source').attr('src');
+            objUrl.revokeObjectURL(data);
+        },
+        hasInitialPreview: function () {
+            var self = this;
+            return !self.overwriteInitial && previewCache.count(self.id);
+        },
+        clear: function () {
+            var self = this, cap;
+            self.$btnUpload.removeAttr('disabled');
+            self.getThumbs().find('video,audio,img').each(function () {
+                self.cleanMemory($(this));
+            });
+            self.resetUpload();
+            self.filestack = [];
+            self.clearFileInput();
+            self.resetErrors(true);
+            self.raise('fileclear');
+            if (self.hasInitialPreview()) {
+                self.showFileIcon();
+                self.resetPreview();
+                self.setEllipsis();
+                self.initPreviewDeletes();
+                self.$container.removeClass('file-input-new');
+            } else {
+                self.getThumbs().each(function () {
+                    self.clearObjects($(this));
+                });
+                if (self.isUploadable) {
+                    previewCache.data[self.id] = {};
+                }
+                self.$preview.html('');
+                cap = (!self.overwriteInitial && self.initialCaption.length > 0) ? self.initialCaption : '';
+                self.setCaption(cap);
+                self.setEllipsis();
+                self.$caption.attr('title', '');
+                addCss(self.$container, 'file-input-new');
+            }
+            if (self.$container.find('.file-preview-frame').length === 0) {
+                if (!self.initCaption()) {
+                    self.$captionContainer.find('.kv-caption-icon').hide();
+                }
+                self.setEllipsis();
+            }
+            self.hideFileIcon();
+            self.raise('filecleared');
+            self.$captionContainer.focus();
+            self.setFileDropZoneTitle();
+        },
+        resetPreview: function () {
+            var self = this, out;
+            if (previewCache.count(self.id)) {
+                out = previewCache.out(self.id);
+                self.$preview.html(out.content);
+                self.setCaption(out.caption);
+            } else {
+                self.clearPreview();
+                self.initCaption();
+            }
+        },
+        resetPreviewThumbs: function (isAjax) {
+            var self = this, out;
+            if (isAjax) {
+                self.clearPreview();
+                self.filestack = [];
+                return;
+            }
+            if (self.hasInitialPreview()) {
+                out = previewCache.out(self.id);
+                self.$preview.html(out.content);
+                self.setCaption(out.caption);
+                self.initPreviewDeletes();
+            } else {
+                self.clearPreview();
+            }
+        },
+        reset: function () {
+            var self = this;
+            self.resetPreview();
+            self.setEllipsis();
+            self.$container.find('.fileinput-filename').text('');
+            self.raise('filereset');
+            addCss(self.$container, 'file-input-new');
+            if (self.$preview.find('.file-preview-frame').length || self.isUploadable && self.dropZoneEnabled) {
+                self.$container.removeClass('file-input-new');
+            }
+            self.setFileDropZoneTitle();
+            self.filestack = [];
+            self.formdata = {};
+        },
+        disable: function () {
+            var self = this;
+            self.isDisabled = true;
+            self.raise('filedisabled');
+            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, .file-preview-frame button").attr("disabled",
+                true);
+            self.initDragDrop();
+        },
+        enable: function () {
+            var self = this;
+            self.isDisabled = false;
+            self.raise('fileenabled');
+            self.$element.removeAttr('disabled');
+            self.$container.find(".kv-fileinput-caption").removeClass("file-caption-disabled");
+            self.$container.find(".btn-file, .fileinput-remove, .kv-fileinput-upload, .file-preview-frame button").removeAttr("disabled");
+            self.initDragDrop();
+        },
+        getThumbs: function (css) {
+            css = css || '';
+            return this.$preview.find('.file-preview-frame:not(.file-preview-initial)' + css);
+        },
+        getExtraData: function (previewId, index) {
+            var self = this, data = self.uploadExtraData;
+            if (typeof self.uploadExtraData === "function") {
+                data = self.uploadExtraData(previewId, index);
+            }
+            return data;
+        },
+        uploadExtra: function (previewId, index) {
+            var self = this, data = self.getExtraData(previewId, index);
+            if (data.length === 0) {
+                return;
+            }
+            $.each(data, function (key, value) {
+                self.formdata.append(key, value);
+            });
+        },
+        initXhr: function (xhrobj, factor) {
+            var self = this;
+            if (xhrobj.upload) {
+                xhrobj.upload.addEventListener('progress', function (event) {
+                    var pct = 0, position = event.loaded || event.position, total = event.total;
+                    if (event.lengthComputable) {
+                        pct = Math.ceil(position / total * factor);
+                    }
+                    self.uploadPercent = Math.max(pct, self.uploadPercent);
+                    self.setProgress(self.uploadPercent);
+                }, false);
+            }
+            return xhrobj;
+        },
+        ajaxSubmit: function (fnBefore, fnSuccess, fnComplete, fnError, previewId, index) {
+            var self = this, settings;
+            self.raise('filepreajax', [previewId, index]);
+            self.uploadExtra(previewId, index);
+            settings = $.extend({
+                xhr: function () {
+                    var xhrobj = $.ajaxSettings.xhr();
+                    return self.initXhr(xhrobj, 98);
+                },
+                url: self.uploadUrl,
+                type: 'POST',
+                dataType: 'json',
+                data: self.formdata,
+                cache: false,
+                processData: false,
+                contentType: false,
+                beforeSend: fnBefore,
+                success: fnSuccess,
+                complete: fnComplete,
+                error: fnError
+            }, self.ajaxSettings);
+            self.ajaxRequests.push($.ajax(settings));
+        },
+        initUploadSuccess: function (out, $thumb, allFiles) {
+            var self = this, append, data, index, $newThumb, content, config, tags;
+            if (typeof out !== 'object' || $.isEmptyObject(out)) {
+                return;
+            }
+            if (out.initialPreview !== undefined && out.initialPreview.length > 0) {
+                self.hasInitData = true;
+                content = out.initialPreview || [];
+                config = out.initialPreviewConfig || [];
+                tags = out.initialPreviewThumbTags || [];
+                append = out.append === undefined || out.append ? true : false;
+                self.overwriteInitial = false;
+                if ($thumb !== undefined && !allFiles) {
+                    index = previewCache.add(self.id, content, config[0], tags[0], append);
+                    data = previewCache.get(self.id, index, false);
+                    $newThumb = $(data).hide();
+                    $thumb.after($newThumb).fadeOut('slow', function () {
+                        $newThumb.fadeIn('slow').css('display:inline-block');
+                        self.initPreviewDeletes();
+                        self.clearFileInput();
+                        $thumb.remove();
+                    });
+                } else {
+                    if (allFiles) {
+                        self.uploadCache.content.push(content[0]);
+                        self.uploadCache.config.push(config[0]);
+                        self.uploadCache.tags.push(tags[0]);
+                        self.uploadCache.append = append;
+                    } else {
+                        previewCache.set(self.id, content, config, tags, append);
+                        self.initPreview();
+                        self.initPreviewDeletes();
+                    }
+                }
+            }
+        },
+        initSuccessThumbs: function () {
+            var self = this;
+            self.getThumbs('.file-preview-success').each(function () {
+                var $thumb = $(this), $remove = $thumb.find('.kv-file-remove');
+                $remove.removeAttr('disabled');
+                handler($remove, 'click', function () {
+                    var out = self.raise('filesuccessremove', [$thumb.attr('id'), $thumb.data('fileindex')]);
+                    self.cleanMemory($thumb);
+                    if (out === false) {
+                        return;
+                    }
+                    $thumb.fadeOut('slow', function () {
+                        $thumb.remove();
+                        if (!self.$preview.find('.file-preview-frame').length) {
+                            self.reset();
+                        }
+                    });
+                });
+            });
+        },
+        uploadSingle: function (i, files, allFiles) {
+            var self = this, total = self.getFileStack().length, formdata = new FormData(), outData,
+                previewId = self.previewInitId + "-" + i, $thumb = $('#' + previewId + ':not(.file-preview-initial)'),
+                pct, chkComplete, $btnUpload = $thumb.find('.kv-file-upload'), $btnDelete = $thumb.find('.kv-file-remove'),
+                updateProgress, hasPostData = self.filestack.length > 0 || !$.isEmptyObject(self.uploadExtraData),
+                resetActions, fnBefore, fnSuccess, fnComplete, fnError, params = {id: previewId, index: i};
+            self.formdata = formdata;
+            if (total === 0 || !hasPostData || $btnUpload.hasClass('disabled') || self.abort(params)) {
+                return;
+            }
+            chkComplete = function () {
+                var $thumbs = self.getThumbs('.file-uploading');
+                if ($thumbs.length > 0 || self.fileBatchCompleted) {
+                    return;
+                }
+                self.fileBatchCompleted = true;
+                setTimeout(function () {
+                    previewCache.set(self.id, self.uploadCache.content, self.uploadCache.config, self.uploadCache.tags,
+                        self.uploadCache.append);
+                    if (self.hasInitData) {
+                        self.initPreview();
+                        self.initPreviewDeletes();
+                    }
+                    self.setProgress(100);
+                    self.unlock();
+                    self.clearFileInput();
+                    self.raise('filebatchuploadcomplete', [self.filestack, self.getExtraData()]);
+                }, 100);
+            };
+            updateProgress = function () {
+                if (!allFiles || total === 0 || self.uploadPercent >= 100) {
+                    return;
+                }
+                self.uploadCount += 1;
+                pct = 80 + Math.ceil(self.uploadCount * 20 / total);
+                self.uploadPercent = Math.max(pct, self.uploadPercent);
+                self.setProgress(self.uploadPercent);
+                self.initPreviewDeletes();
+            };
+            resetActions = function () {
+                $btnUpload.removeAttr('disabled');
+                $btnDelete.removeAttr('disabled');
+                $thumb.removeClass('file-uploading');
+            };
+            fnBefore = function (jqXHR) {
+                outData = self.getOutData(jqXHR);
+                if (!$thumb.hasClass('file-preview-success')) {
+                    self.setThumbStatus($thumb, 'Loading');
+                    addCss($thumb, 'file-uploading');
+                }
+                $btnUpload.attr('disabled', true);
+                $btnDelete.attr('disabled', true);
+                if (!allFiles) {
+                    self.lock();
+                }
+                self.raise('filepreupload', [outData, previewId, i]);
+                params = $.extend(params, outData);
+                if (self.abort(params)) {
+                    jqXHR.abort();
+                    self.setProgress(100);
+                }
+            };
+            fnSuccess = function (data, textStatus, jqXHR) {
+                outData = self.getOutData(jqXHR, data);
+                params = $.extend(params, outData);
+                setTimeout(function () {
+                    if (isEmpty(data) || isEmpty(data.error)) {
+                        self.setThumbStatus($thumb, 'Success');
+                        $btnUpload.hide();
+                        self.filestack[i] = undefined;
+                        self.raise('fileuploaded', [outData, previewId, i]);
+                        self.initUploadSuccess(data, $thumb, allFiles);
+                        if (!allFiles) {
+                            self.resetFileStack();
+                        }
+                    } else {
+                        self.setThumbStatus($thumb, 'Error');
+                        self.showUploadError(data.error, params);
+                    }
+                }, 100);
+            };
+            fnComplete = function () {
+                setTimeout(function () {
+                    updateProgress();
+                    resetActions();
+                    if (!allFiles) {
+                        self.unlock(false);
+                    } else {
+                        chkComplete();
+                    }
+                    self.initSuccessThumbs();
+                }, 100);
+            };
+            fnError = function (jqXHR, textStatus, errorThrown) {
+                var errMsg = self.parseError(jqXHR, errorThrown, (allFiles ? files[i].name : null));
+                self.setThumbStatus($thumb, 'Error');
+                params = $.extend(params, self.getOutData(jqXHR));
+                self.showUploadError(errMsg, params);
+            };
+            formdata.append(self.uploadFileAttr, files[i]);
+            formdata.append('file_id', i);
+            self.ajaxSubmit(fnBefore, fnSuccess, fnComplete, fnError, previewId, i);
+        },
+        uploadBatch: function () {
+            var self = this, files = self.filestack, total = files.length, config,
+                hasPostData = self.filestack.length > 0 || !$.isEmptyObject(self.uploadExtraData),
+                setAllUploaded, enableActions, fnBefore, fnSuccess, fnComplete, fnError,
+                params = {};
+            self.formdata = new FormData();
+            if (total === 0 || !hasPostData || self.abort(params)) {
+                return;
+            }
+            setAllUploaded = function () {
+                $.each(files, function (key) {
+                    self.filestack[key] = undefined;
+                });
+                self.clearFileInput();
+            };
+            fnBefore = function (jqXHR) {
+                self.lock();
+                var outData = self.getOutData(jqXHR);
+                if (self.showPreview) {
+                    self.getThumbs().each(function () {
+                        var $thumb = $(this), $btnUpload = $thumb.find('.kv-file-upload'),
+                            $btnDelete = $thumb.find('.kv-file-remove');
+                        if (!$thumb.hasClass('file-preview-success')) {
+                            self.setThumbStatus($thumb, 'Loading');
+                            addCss($thumb, 'file-uploading');
+                        }
+                        $btnUpload.attr('disabled', true);
+                        $btnDelete.attr('disabled', true);
+                    });
+                }
+                self.raise('filebatchpreupload', [outData]);
+                if (self.abort(outData)) {
+                    jqXHR.abort();
+                }
+            };
+            fnSuccess = function (data, textStatus, jqXHR) {
+                var outData = self.getOutData(jqXHR, data), $thumbs = self.getThumbs(),
+                    keys = isEmpty(data.errorkeys) ? [] : data.errorkeys, key = 0;
+                if (isEmpty(data) || isEmpty(data.error)) {
+                    self.raise('filebatchuploadsuccess', [outData]);
+                    setAllUploaded();
+                    if (self.showPreview) {
+                        $thumbs.each(function () {
+                            var $thumb = $(this), $btnUpload = $thumb.find('.kv-file-upload');
+                            $thumb.find('.kv-file-upload').hide();
+                            self.setThumbStatus($thumb, 'Success');
+                            $thumb.removeClass('file-uploading');
+                            $btnUpload.removeAttr('disabled');
+                        });
+                        self.initUploadSuccess(data);
+                    } else {
+                        self.reset();
+                    }
+                } else {
+                    if (self.showPreview) {
+                        $thumbs.each(function () {
+                            var $thumb = $(this), $btnDelete = $thumb.find('.kv-file-remove'),
+                                $btnUpload = $thumb.find('.kv-file-upload');
+                            $thumb.removeClass('file-uploading');
+                            $btnUpload.removeAttr('disabled');
+                            $btnDelete.removeAttr('disabled');
+                            if (keys.length === 0) {
+                                self.setThumbStatus($thumb, 'Error');
+                                return;
+                            }
+                            if ($.inArray(key, keys) !== -1) {
+                                self.setThumbStatus($thumb, 'Error');
+                            } else {
+                                $thumb.find('.kv-file-upload').hide();
+                                self.setThumbStatus($thumb, 'Success');
+                                self.filestack[key] = undefined;
+                            }
+                            key++;
+                        });
+                        self.initUploadSuccess(data);
+                    }
+                    self.showUploadError(data.error, outData, 'filebatchuploaderror');
+                }
+            };
+            fnComplete = function () {
+                self.setProgress(100);
+                self.unlock();
+                self.initSuccessThumbs();
+                self.raise('filebatchuploadcomplete', [self.filestack, self.getExtraData()]);
+                self.clearFileInput();
+            };
+            fnError = function (jqXHR, textStatus, errorThrown) {
+                var outData = self.getOutData(jqXHR), errMsg = self.parseError(jqXHR, errorThrown);
+                self.showUploadError(errMsg, outData, 'filebatchuploaderror');
+                self.uploadFileCount = total - 1;
+                if (!self.showPreview) {
+                    return;
+                }
+                self.getThumbs().each(function () {
+                    var $thumb = $(this), key = $thumb.attr('data-fileindex');
+                    $thumb.removeClass('file-uploading');
+                    if (self.filestack[key] !== undefined) {
+                        self.setThumbStatus($thumb, 'Error');
+                    }
+                });
+                self.getThumbs().removeClass('file-uploading');
+                self.getThumbs(' .kv-file-upload').removeAttr('disabled');
+                self.getThumbs(' .kv-file-delete').removeAttr('disabled');
+            };
+            $.each(files, function (key, data) {
+                if (!isEmpty(files[key])) {
+                    self.formdata.append(self.uploadFileAttr, data);
+                }
+            });
+            self.ajaxSubmit(fnBefore, fnSuccess, fnComplete, fnError);
+        },
+        uploadExtraOnly: function () {
+            var self = this, params = {}, fnBefore, fnSuccess, fnComplete, fnError;
+            self.formdata = new FormData();
+            if (self.abort(params)) {
+                return;
+            }
+            fnBefore = function (jqXHR) {
+                self.lock();
+                var outData = self.getOutData(jqXHR);
+                self.raise('filebatchpreupload', [outData]);
+                self.setProgress(50);
+                params.data = outData;
+                params.xhr = jqXHR;
+                if (self.abort(params)) {
+                    jqXHR.abort();
+                    self.setProgress(100);
+                }
+            };
+            fnSuccess = function (data, textStatus, jqXHR) {
+                var outData = self.getOutData(jqXHR, data);
+                if (isEmpty(data) || isEmpty(data.error)) {
+                    self.raise('filebatchuploadsuccess', [outData]);
+                    self.clearFileInput();
+                    self.initUploadSuccess(data);
+                } else {
+                    self.showUploadError(data.error, outData, 'filebatchuploaderror');
+                }
+            };
+            fnComplete = function () {
+                self.setProgress(100);
+                self.unlock();
+                self.raise('filebatchuploadcomplete', [self.filestack, self.getExtraData()]);
+                self.clearFileInput();
+            };
+            fnError = function (jqXHR, textStatus, errorThrown) {
+                var outData = self.getOutData(jqXHR), errMsg = self.parseError(jqXHR, errorThrown);
+                params.data = outData;
+                self.showUploadError(errMsg, outData, 'filebatchuploaderror');
+            };
+            self.ajaxSubmit(fnBefore, fnSuccess, fnComplete, fnError);
+        },
+        hideFileIcon: function () {
+            if (this.overwriteInitial) {
+                this.$captionContainer.find('.kv-caption-icon').hide();
+            }
+        },
+        showFileIcon: function () {
+            this.$captionContainer.find('.kv-caption-icon').show();
+        },
+        resetErrors: function (fade) {
+            var self = this, $error = self.$errorContainer;
+            self.isError = false;
+            self.$container.removeClass('has-error');
+            $error.html('');
+            if (fade) {
+                $error.fadeOut('slow');
+            } else {
+                $error.hide();
+            }
+        },
+        showFolderError: function (folders) {
+            var self = this, $error = self.$errorContainer;
+            if (!folders) {
+                return;
+            }
+            $error.html(self.msgFoldersNotAllowed.repl('{n}', folders));
+            $error.fadeIn(800);
+            addCss(self.$container, 'has-error');
+            self.raise('filefoldererror', [folders]);
+        },
+        showUploadError: function (msg, params, event) {
+            var self = this, $error = self.$errorContainer, ev = event || 'fileuploaderror';
+            if ($error.find('ul').length === 0) {
+                $error.html('<ul><li>' + msg + '</li></ul>');
+            } else {
+                $error.find('ul').append('<li>' + msg + '</li>');
+            }
+            $error.fadeIn(800);
+            self.raise(ev, [params]);
+            self.$container.removeClass('file-input-new');
+            addCss(self.$container, 'has-error');
+            return true;
+        },
+        showError: function (msg, params, event) {
+            var self = this, $error = self.$errorContainer, ev = event || 'fileerror';
+            params = params || {};
+            params.reader = self.reader;
+            $error.html(msg);
+            $error.fadeIn(800);
+            self.raise(ev, [params]);
+            if (!self.isUploadable) {
+                self.clearFileInput();
+            }
+            self.$container.removeClass('file-input-new');
+            addCss(self.$container, 'has-error');
+            self.$btnUpload.attr('disabled', true);
+            return true;
+        },
+        errorHandler: function (evt, caption) {
+            var self = this, err = evt.target.error;
+            switch (err.code) {
+                case err.NOT_FOUND_ERR:
+                    self.showError(self.msgFileNotFound.replace('{name}', caption));
+                    break;
+                case err.SECURITY_ERR:
+                    self.showError(self.msgFileSecured.replace('{name}', caption));
+                    break;
+                case err.NOT_READABLE_ERR:
+                    self.showError(self.msgFileNotReadable.replace('{name}', caption));
+                    break;
+                case err.ABORT_ERR:
+                    self.showError(self.msgFilePreviewAborted.replace('{name}', caption));
+                    break;
+                default:
+                    self.showError(self.msgFilePreviewError.replace('{name}', caption));
+            }
+        },
+        parseFileType: function (file) {
+            var self = this, isValid, vType, cat, i;
+            for (i = 0; i < defaultPreviewTypes.length; i += 1) {
+                cat = defaultPreviewTypes[i];
+                isValid = isSet(cat, self.fileTypeSettings) ? self.fileTypeSettings[cat] : defaultFileTypeSettings[cat];
+                vType = isValid(file.type, file.name) ? cat : '';
+                if (!isEmpty(vType)) {
+                    return vType;
+                }
+            }
+            return 'other';
+        },
+        previewDefault: function (file, previewId, isDisabled) {
+            if (!this.showPreview) {
+                return;
+            }
+            var self = this, data = objUrl.createObjectURL(file), $obj = $('#' + previewId),
+                config = self.previewSettings.other || defaultPreviewSettings.other,
+                footer = self.renderFileFooter(file.name, config.width),
+                previewOtherTemplate = self.getPreviewTemplate('other'),
+                ind = previewId.slice(previewId.lastIndexOf('-') + 1),
+                frameClass = '';
+            if (isDisabled === true) {
+                frameClass = ' btn disabled';
+                footer += '<div class="file-other-error text-danger"><i class="glyphicon glyphicon-exclamation-sign"></i></div>';
+            }
+            self.$preview.append("\n" + previewOtherTemplate
+                .repl('{previewId}', previewId)
+                .repl('{frameClass}', frameClass)
+                .repl('{fileindex}', ind)
+                .repl('{caption}', self.slug(file.name))
+                .repl('{width}', config.width)
+                .repl('{height}', config.height)
+                .repl('{type}', file.type)
+                .repl('{data}', data)
+                .repl('{footer}', footer));
+        },
+        previewFile: function (i, file, theFile, previewId, data) {
+            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),
+                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),
+                footer = self.renderFileFooter(caption, config.width), modal = '',
+                ind = previewId.slice(previewId.lastIndexOf('-') + 1);
+            if (chkTypes && chkMimes) {
+                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;
+                } else {
+                    content = tmplt.repl('{previewId}', previewId).repl('{caption}', caption)
+                        .repl('{frameClass}', '')
+                        .repl('{type}', file.type).repl('{data}', data)
+                        .repl('{width}', config.width).repl('{height}', config.height)
+                        .repl('{footer}', footer).repl('{fileindex}', ind);
+                }
+                self.$preview.append("\n" + content);
+                self.validateImage(i, previewId);
+            } else {
+                self.previewDefault(file, previewId);
+            }
+        },
+        slugDefault: function (text) {
+            return isEmpty(text) ? '' : text.split(/(\\|\/)/g).pop().replace(/[^\w\u00C0-\u017F\-.\\\/ ]+/g, '');
+        },
+        getFileStack: function (skipNull) {
+            var self = this, status;
+            return self.filestack.filter(function (n) {
+                return (skipNull ? n !== undefined : n !== undefined && n !== null);
+            });
+        },
+        readFiles: function (files) {
+            this.reader = new FileReader();
+            var self = this, $el = self.$element, $preview = self.$preview, reader = self.reader,
+                $container = self.$previewContainer, $status = self.$previewStatus, msgLoading = self.msgLoading,
+                msgProgress = self.msgProgress, previewInitId = self.previewInitId, numFiles = files.length,
+                settings = self.fileTypeSettings, ctr = self.filestack.length,
+                throwError = function (msg, file, previewId, index) {
+                    var p1 = $.extend(self.getOutData({}, {}, files), {id: previewId, index: index}),
+                        p2 = {id: previewId, index: index, file: file, files: files};
+                    self.previewDefault(file, previewId, true);
+                    return self.isUploadable ? self.showUploadError(msg, p1) : self.showError(msg, p2);
+                };
+
+            function readFile(i) {
+                if (isEmpty($el.attr('multiple'))) {
+                    numFiles = 1;
+                }
+                if (i >= numFiles) {
+                    if (self.isUploadable && self.filestack.length > 0) {
+                        self.raise('filebatchselected', [self.getFileStack()]);
+                    } else {
+                        self.raise('filebatchselected', [files]);
+                    }
+                    $container.removeClass('loading');
+                    $status.html('');
+                    return;
+                }
+                var node = ctr + i, previewId = previewInitId + "-" + node, isText, file = files[i],
+                    caption = self.slug(file.name), fileSize = (file.size || 0) / 1000, checkFile, fileExtExpr = '',
+                    previewData = objUrl.createObjectURL(file), fileCount = 0, j, msg, typ, chk,
+                    fileTypes = self.allowedFileTypes, strTypes = isEmpty(fileTypes) ? '' : fileTypes.join(', '),
+                    fileExt = self.allowedFileExtensions, strExt = isEmpty(fileExt) ? '' : fileExt.join(', ');
+                if (!isEmpty(fileExt)) {
+                    fileExtExpr = new RegExp('\\.(' + fileExt.join('|') + ')$', 'i');
+                }
+                fileSize = fileSize.toFixed(2);
+                if (self.maxFileSize > 0 && fileSize > self.maxFileSize) {
+                    msg = self.msgSizeTooLarge.replace('{name}', caption)
+                        .replace('{size}', fileSize)
+                        .replace('{maxSize}', self.maxFileSize);
+                    self.isError = throwError(msg, file, previewId, i);
+                    return;
+                }
+                if (!isEmpty(fileTypes) && isArray(fileTypes)) {
+                    for (j = 0; j < fileTypes.length; j += 1) {
+                        typ = fileTypes[j];
+                        checkFile = settings[typ];
+                        chk = (checkFile !== undefined && checkFile(file.type, caption));
+                        fileCount += isEmpty(chk) ? 0 : chk.length;
+                    }
+                    if (fileCount === 0) {
+                        msg = self.msgInvalidFileType.replace('{name}', caption).replace('{types}', strTypes);
+                        self.isError = throwError(msg, file, previewId, i);
+                        return;
+                    }
+                }
+                if (fileCount === 0 && !isEmpty(fileExt) && isArray(fileExt) && !isEmpty(fileExtExpr)) {
+                    chk = caption.match(fileExtExpr);
+                    fileCount += isEmpty(chk) ? 0 : chk.length;
+                    if (fileCount === 0) {
+                        msg = self.msgInvalidFileExtension.replace('{name}', caption).replace('{extensions}',
+                            strExt);
+                        self.isError = throwError(msg, file, previewId, i);
+                        return;
+                    }
+                }
+                if (!self.showPreview) {
+                    self.filestack.push(file);
+                    setTimeout(readFile(i + 1), 100);
+                    self.raise('fileloaded', [file, previewId, i, reader]);
+                    return;
+                }
+                if ($preview.length > 0 && FileReader !== undefined) {
+                    $status.html(msgLoading.replace('{index}', i + 1).replace('{files}', numFiles));
+                    $container.addClass('loading');
+                    reader.onerror = function (evt) {
+                        self.errorHandler(evt, caption);
+                    };
+                    reader.onload = function (theFile) {
+                        self.previewFile(i, file, theFile, previewId, previewData);
+                        self.initFileActions();
+                    };
+                    reader.onloadend = function () {
+                        msg = msgProgress
+                            .replace('{index}', i + 1).replace('{files}', numFiles)
+                            .replace('{percent}', 50).replace('{name}', caption);
+                        setTimeout(function () {
+                            $status.html(msg);
+                            self.updateFileDetails(numFiles);
+                            readFile(i + 1);
+                        }, 100);
+                        self.raise('fileloaded', [file, previewId, i, reader]);
+                    };
+                    reader.onprogress = function (data) {
+                        if (data.lengthComputable) {
+                            var fact = (data.loaded / data.total) * 100, progress = Math.ceil(fact);
+                            msg = msgProgress.replace('{index}', i + 1).replace('{files}', numFiles)
+                                .replace('{percent}', progress).replace('{name}', caption);
+                            setTimeout(function () {
+                                $status.html(msg);
+                            }, 100);
+                        }
+                    };
+                    isText = isSet('text', settings) ? settings.text : defaultFileTypeSettings.text;
+                    if (isText(file.type, caption)) {
+                        reader.readAsText(file, self.textEncoding);
+                    } else {
+                        reader.readAsArrayBuffer(file);
+                    }
+                } else {
+                    self.previewDefault(file, previewId);
+                    setTimeout(function () {
+                        readFile(i + 1);
+                        self.updateFileDetails(numFiles);
+                    }, 100);
+                    self.raise('fileloaded', [file, previewId, i, reader]);
+                }
+                self.filestack.push(file);
+            }
+
+            readFile(0);
+            self.updateFileDetails(numFiles, false);
+        },
+        updateFileDetails: function (numFiles) {
+            var self = this, $el = self.$element, fileStack = self.getFileStack(),
+                name = $el.val() || (fileStack.length && fileStack[0].name) || '', label = self.slug(name),
+                n = self.isUploadable ? fileStack.length : numFiles,
+                nFiles = previewCache.count(self.id) + n,
+                log = n > 1 ? self.getMsgSelected(nFiles) : label;
+            if (self.isError) {
+                self.$previewContainer.removeClass('loading');
+                self.$previewStatus.html('');
+                self.$captionContainer.find('.kv-caption-icon').hide();
+            } else {
+                self.showFileIcon();
+            }
+            self.setCaption(log, self.isError);
+            self.$container.removeClass('file-input-new file-input-ajax-new');
+            if (arguments.length === 1) {
+                self.raise('fileselect', [numFiles, label]);
+            }
+            if (previewCache.count(self.id)) {
+                self.initPreviewDeletes();
+            }
+        },
+        change: function (e) {
+            var self = this, $el = self.$element;
+            if (!self.isUploadable && isEmpty($el.val()) && self.fileInputCleared) { // IE 11 fix
+                self.fileInputCleared = false;
+                return;
+            }
+            self.fileInputCleared = false;
+            var tfiles, msg, total, $preview = self.$preview, 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,
+                flagSingle = (isSingleUpload && ctr > 0),
+                throwError = function (mesg, file, previewId, index) {
+                    var p1 = $.extend(self.getOutData({}, {}, files), {id: previewId, index: index}),
+                        p2 = {id: previewId, index: index, file: file, files: files};
+                    return self.isUploadable ? self.showUploadError(mesg, p1) : self.showError(mesg, p2);
+                };
+            self.reader = null;
+            self.resetUpload();
+            self.hideFileIcon();
+            if (self.isUploadable) {
+                self.$container.find('.file-drop-zone .' + self.dropZoneTitleClass).remove();
+            }
+            if (isDragDrop) {
+                tfiles = [];
+                while (files[i]) {
+                    f = files[i];
+                    if (!f.type && f.size % 4096 === 0) {
+                        folders++;
+                    } else {
+                        tfiles.push(f);
+                    }
+                    i++;
+                }
+            } else {
+                if (e.target.files === undefined) {
+                    tfiles = e.target && e.target.value ? [
+                        {name: e.target.value.replace(/^.+\\/, '')}
+                    ] : [];
+                } else {
+                    tfiles = e.target.files;
+                }
+            }
+            if (isEmpty(tfiles) || tfiles.length === 0) {
+                if (!isAjaxUpload) {
+                    self.clear();
+                }
+                self.showFolderError(folders);
+                self.raise('fileselectnone');
+                return;
+            }
+            self.resetErrors();
+            len = tfiles.length;
+            total = self.isUploadable ? self.getFileStack().length + len : len;
+            if (self.maxFileCount > 0 && total > self.maxFileCount) {
+                if (!self.autoReplace || len > self.maxFileCount) {
+                    n = (self.autoReplace && len > self.maxFileCount) ? len : total;
+                    msg = self.msgFilesTooMany.replace('{m}', self.maxFileCount).replace('{n}', n);
+                    self.isError = throwError(msg, null, null, null);
+                    self.$captionContainer.find('.kv-caption-icon').hide();
+                    self.setCaption('', true);
+                    self.setEllipsis();
+                    self.$container.removeClass('file-input-new file-input-ajax-new');
+                    return;
+                }
+                if (total > self.maxFileCount) {
+                    self.resetPreviewThumbs(isAjaxUpload);
+                }
+            } else {
+                 if (!isAjaxUpload || flagSingle) {
+                    self.resetPreviewThumbs(false);
+                    if (flagSingle) {
+                        self.filestack = [];
+                    }
+                } else {
+                    if (isAjaxUpload && ctr === 0 && (!previewCache.count(self.id) || self.overwriteInitial)) {
+                        self.resetPreviewThumbs(true);
+                    }
+                }
+            }
+            if (self.isPreviewable) {
+                self.readFiles(tfiles);
+            } else {
+                self.updateFileDetails(1);
+            }
+            self.showFolderError(folders);
+        },
+        validateImage: function (i, previewId) {
+            var self = this, $preview = self.$preview, params, w1, w2, $cap,
+                $thumb = $preview.find("#" + previewId), fname = 'Untitled',
+                $img = $thumb.find('img');
+            if (!$img.length) {
+                return;
+            }
+            handler($img, 'load', function () {
+                w1 = $thumb.width();
+                w2 = $preview.width();
+                if (w1 > w2) {
+                    $img.css('width', '100%');
+                    $thumb.css('width', '97%');
+                }
+                $cap = $img.closest('.file-preview-frame').find('.file-caption-name');
+                if ($cap.length) {
+                    $cap.width($img.width());
+                    fname = $cap.text();
+                    $cap.attr('title', fname);
+                }
+                params = {ind: i, id: previewId};
+                self.checkDimensions(i, 'Small', $img, $thumb, fname, 'Width', params);
+                self.checkDimensions(i, 'Small', $img, $thumb, fname, 'Height', params);
+                self.checkDimensions(i, 'Large', $img, $thumb, fname, 'Width', params);
+                self.checkDimensions(i, 'Large', $img, $thumb, fname, 'Height', params);
+                self.raise('fileimageloaded', [previewId]);
+                objUrl.revokeObjectURL($img.attr('src'));
+            });
+        },
+        checkDimensions: function (i, chk, $img, $thumb, fname, type, params) {
+            var self = this, msg, dim, tag = chk === 'Small' ? 'min' : 'max',
+                limit = self[tag + 'Image' + type], $imgEl, isValid;
+            if (isEmpty(limit) || !$img.length) {
+                return;
+            }
+            $imgEl = $img[0];
+            dim = (type === 'Width') ? $imgEl.naturalWidth || $imgEl.width : $imgEl.naturalHeight || $imgEl.height;
+            isValid = chk === 'Small' ? dim >= limit : dim <= limit;
+            if (isValid) {
+                return;
+            }
+            msg = self['msgImage' + type + chk].replace('{name}', fname).replace('{size}', limit);
+            self.showUploadError(msg, params);
+            self.setThumbStatus($thumb, 'Error');
+            self.filestack[i] = null;
+        },
+        initCaption: function () {
+            var self = this, cap = self.initialCaption || '';
+            if (self.overwriteInitial || isEmpty(cap)) {
+                self.$caption.html('');
+                return false;
+            }
+            self.setCaption(cap);
+            return true;
+        },
+        setCaption: function (content, isError) {
+            var self = this, title, out;
+            if (isError) {
+                title = $('<div>' + self.msgValidationError + '</div>').text();
+                out = '<span class="' + self.msgValidationErrorClass + '">' +
+                self.msgValidationErrorIcon + title + '</span>';
+            } else {
+                if (isEmpty(content) || self.$caption.length === 0) {
+                    return;
+                }
+                title = $('<div>' + content + '</div>').text();
+                out = self.getLayoutTemplate('icon') + title;
+            }
+            self.$caption.html(out);
+            self.$caption.attr('title', title);
+            self.$captionContainer.find('.file-caption-ellipsis').attr('title', title);
+            self.setEllipsis();
+        },
+        initBrowse: function ($container) {
+            var self = this;
+            self.$btnFile = $container.find('.btn-file');
+            self.$btnFile.append(self.$element);
+        },
+        createContainer: function () {
+            var self = this,
+                $container = $(document.createElement("div"))
+                    .attr({"class": 'file-input file-input-new'})
+                    .html(self.renderMain());
+            self.$element.before($container);
+            self.initBrowse($container);
+            return $container;
+        },
+        refreshContainer: function () {
+            var self = this, $container = self.$container;
+            $container.before(self.$element);
+            $container.html(self.renderMain());
+            self.initBrowse($container);
+        },
+        renderMain: function () {
+            var self = this, dropCss = (self.isUploadable && self.dropZoneEnabled) ? ' file-drop-zone' : '',
+                preview = self.showPreview ? self.getLayoutTemplate('preview').repl('{class}', self.previewClass)
+                    .repl('{dropClass}', dropCss) : '',
+                css = self.isDisabled ? self.captionClass + ' file-caption-disabled' : self.captionClass,
+                caption = self.captionTemplate.repl('{class}', css + ' kv-fileinput-caption');
+            return self.mainTemplate.repl('{class}', self.mainClass)
+                .repl('{preview}', preview)
+                .repl('{caption}', caption)
+                .repl('{upload}', self.renderUpload())
+                .repl('{remove}', self.renderRemove())
+                .repl('{cancel}', self.renderCancel())
+                .repl('{browse}', self.renderBrowse());
+        },
+        renderBrowse: function () {
+            var self = this, css = self.browseClass + ' btn-file', status = '';
+            if (self.isDisabled) {
+                status = ' disabled ';
+            }
+            return '<div class="' + css + '"' + status + '> ' + self.browseIcon + self.browseLabel + ' </div>';
+        },
+        renderRemove: function () {
+            var self = this, css = self.removeClass + ' fileinput-remove fileinput-remove-button', status = '';
+            if (!self.showRemove) {
+                return '';
+            }
+            if (self.isDisabled) {
+                status = ' disabled ';
+            }
+            return '<button type="button" title="' + self.removeTitle + '" class="' + css + '"' + status + '>' + self.removeIcon + self.removeLabel + '</button>';
+        },
+        renderCancel: function () {
+            var self = this, css = self.cancelClass + ' fileinput-cancel fileinput-cancel-button';
+            if (!self.showCancel) {
+                return '';
+            }
+            return '<button type="button" title="' + self.cancelTitle + '" class="hide ' + css + '">' + self.cancelIcon + self.cancelLabel + '</button>';
+        },
+        renderUpload: function () {
+            var self = this, css = self.uploadClass + ' kv-fileinput-upload fileinput-upload-button', content = '', status = '';
+            if (!self.showUpload) {
+                return '';
+            }
+            if (self.isDisabled) {
+                status = ' disabled ';
+            }
+            if (!self.isUploadable || self.isDisabled) {
+                content = '<button type="submit" title="' + self.uploadTitle + '"class="' + css + '"' + status + '>' + self.uploadIcon + self.uploadLabel + '</button>';
+            } else {
+                content = '<a href="' + self.uploadUrl + '" title="' + self.uploadTitle + '" class="' + css + '"' + status + '>' + self.uploadIcon + self.uploadLabel + '</a>';
+            }
+            return content;
+        }
+    };
+
+    //FileInput plugin definition
+    $.fn.fileinput = function (option) {
+        if (!hasFileAPISupport() && !isIE(9)) {
+            return;
+        }
+
+        var args = Array.apply(null, arguments);
+        args.shift();
+        return this.each(function () {
+            var $this = $(this), data = $this.data('fileinput'), defaults,
+                options = typeof option === 'object' && option,
+                lang = options.language || $this.data('language') || 'en';
+
+            if (!data) {
+                defaults = $.extend({}, $.fn.fileinput.defaults);
+                if (lang !== 'en' && !isEmpty($.fn.fileinputLocales[lang])) {
+                    defaults = $.extend(defaults, $.fn.fileinputLocales[lang]);
+                }
+                data = new FileInput(this, $.extend(defaults, options, $this.data()));
+                $this.data('fileinput', data);
+            }
+
+            if (typeof option === 'string') {
+                data[option].apply(data, args);
+            }
+        });
+    };
+
+    $.fn.fileinput.defaults = {
+        language: 'en',
+        showCaption: true,
+        showPreview: true,
+        showRemove: true,
+        showUpload: true,
+        showCancel: true,
+        showUploadedThumbs: true,
+        autoReplace: false,
+        mainClass: '',
+        previewClass: '',
+        captionClass: '',
+        mainTemplate: null,
+        initialCaption: '',
+        initialPreview: [],
+        initialPreviewDelimiter: '*$$*',
+        initialPreviewConfig: [],
+        initialPreviewThumbTags: [],
+        previewThumbTags: {},
+        initialPreviewShowDelete: true,
+        deleteUrl: '',
+        deleteExtraData: {},
+        overwriteInitial: true,
+        layoutTemplates: defaultLayoutTemplates,
+        previewTemplates: defaultPreviewTemplates,
+        allowedPreviewTypes: defaultPreviewTypes,
+        allowedPreviewMimeTypes: null,
+        allowedFileTypes: null,
+        allowedFileExtensions: null,
+        customLayoutTags: {},
+        customPreviewTags: {},
+        previewSettings: defaultPreviewSettings,
+        fileTypeSettings: defaultFileTypeSettings,
+        previewFileIcon: '<i class="glyphicon glyphicon-file"></i>',
+        browseIcon: '<i class="glyphicon glyphicon-folder-open"></i> &nbsp;',
+        browseClass: 'btn btn-primary',
+        removeIcon: '<i class="glyphicon glyphicon-trash"></i> ',
+        removeClass: 'btn btn-default',
+        cancelIcon: '<i class="glyphicon glyphicon-ban-circle"></i> ',
+        cancelClass: 'btn btn-default',
+        uploadIcon: '<i class="glyphicon glyphicon-upload"></i> ',
+        uploadClass: 'btn btn-default',
+        uploadUrl: null,
+        uploadAsync: true,
+        uploadExtraData: {},
+        minImageWidth: null,
+        minImageHeight: null,
+        maxImageWidth: null,
+        maxImageHeight: null,
+        maxFileSize: 0,
+        minFileCount: 0,
+        maxFileCount: 0,
+        msgValidationErrorClass: 'text-danger',
+        msgValidationErrorIcon: '<i class="glyphicon glyphicon-exclamation-sign"></i> ',
+        msgErrorClass: 'file-error-message',
+        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>',
+        elCaptionContainer: null,
+        elCaptionText: null,
+        elPreviewContainer: null,
+        elPreviewImage: null,
+        elPreviewStatus: null,
+        elErrorContainer: null,
+        slugCallback: null,
+        dropZoneEnabled: true,
+        dropZoneTitleClass: 'file-drop-zone-title',
+        fileActionSettings: {},
+        otherActionButtons: '',
+        textEncoding: 'UTF-8',
+        ajaxSettings: {},
+        ajaxDeleteSettings: {},
+        showAjaxErrorDetails: true
+    };
+
+    $.fn.fileinputLocales.en = {
+        fileSingle: 'file',
+        filePlural: 'files',
+        browseLabel: 'Browse &hellip;',
+        removeLabel: 'Remove',
+        removeTitle: 'Clear selected files',
+        cancelLabel: 'Cancel',
+        cancelTitle: 'Abort ongoing upload',
+        uploadLabel: 'Upload',
+        uploadTitle: 'Upload selected files',
+        msgSizeTooLarge: 'File "{name}" (<b>{size} KB</b>) exceeds maximum allowed upload size of <b>{maxSize} KB</b>. Please retry your upload!',
+        msgFilesTooLess: 'You must select at least <b>{n}</b> {files} to upload. Please retry your upload!',
+        msgFilesTooMany: 'Number of files selected for upload <b>({n})</b> exceeds maximum allowed limit of <b>{m}</b>. Please retry your upload!',
+        msgFileNotFound: 'File "{name}" not found!',
+        msgFileSecured: 'Security restrictions prevent reading the file "{name}".',
+        msgFileNotReadable: 'File "{name}" is not readable.',
+        msgFilePreviewAborted: 'File preview aborted for "{name}".',
+        msgFilePreviewError: 'An error occurred while reading the file "{name}".',
+        msgInvalidFileType: 'Invalid type for file "{name}". Only "{types}" files are supported.',
+        msgInvalidFileExtension: 'Invalid extension for file "{name}". Only "{extensions}" files are supported.',
+        msgValidationError: 'File Upload Error',
+        msgLoading: 'Loading file {index} of {files} &hellip;',
+        msgProgress: 'Loading file {index} of {files} - {name} - {percent}% completed.',
+        msgSelected: '{n} {files} selected',
+        msgFoldersNotAllowed: 'Drag & drop files only! {n} folder(s) dropped were skipped.',
+        msgImageWidthSmall: 'Width of image file "{name}" must be at least {size} px.',
+        msgImageHeightSmall: 'Height of image file "{name}" must be at least {size} px.',
+        msgImageWidthLarge: 'Width of image file "{name}" cannot exceed {size} px.',
+        msgImageHeightLarge: 'Height of image file "{name}" cannot exceed {size} px.',
+        dropZoneTitle: 'Drag & drop files here &hellip;'
+    };
+
+    $.extend($.fn.fileinput.defaults, $.fn.fileinputLocales.en);
+
+    $.fn.fileinput.Constructor = FileInput;
+
+    /**
+     * Convert automatically file inputs with class 'file'
+     * into a bootstrap fileinput control.
+     */
+    $(document).ready(function () {
+        var $input = $('input.file[type=file]');
+        if ($input.length) {
+            $input.fileinput();
+        }
+    });
 })(window.jQuery);
 })(window.jQuery);

ファイルの差分が大きいため隠しています
+ 0 - 16
js/fileinput.min.js


+ 44 - 44
js/fileinput_locale_LANG.js

@@ -1,45 +1,45 @@
-/*!
- * FileInput <_LANG_> Translations
- *
- * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or
- * any HTML markup tags in the messages must not be converted or translated.
- *
- * @see http://github.com/kartik-v/bootstrap-fileinput
- *
- * NOTE: this file must be saved in UTF-8 encoding.
- */
-(function ($) {
-    "use strict";
-
-    $.fn.fileinputLocales['_LANG_'] = {
-        fileSingle: 'file',
-        filePlural: 'files',
-        browseLabel: 'Browse &hellip;',
-        removeLabel: 'Remove',
-        removeTitle: 'Clear selected files',
-        cancelLabel: 'Cancel',
-        cancelTitle: 'Abort ongoing upload',
-        uploadLabel: 'Upload',
-        uploadTitle: 'Upload selected files',
-        msgSizeTooLarge: 'File "{name}" (<b>{size} KB</b>) exceeds maximum allowed upload size of <b>{maxSize} KB</b>. Please retry your upload!',
-        msgFilesTooLess: 'You must select at least <b>{n}</b> {files} to upload. Please retry your upload!',
-        msgFilesTooMany: 'Number of files selected for upload <b>({n})</b> exceeds maximum allowed limit of <b>{m}</b>. Please retry your upload!',
-        msgFileNotFound: 'File "{name}" not found!',
-        msgFileSecured: 'Security restrictions prevent reading the file "{name}".',
-        msgFileNotReadable: 'File "{name}" is not readable.',
-        msgFilePreviewAborted: 'File preview aborted for "{name}".',
-        msgFilePreviewError: 'An error occurred while reading the file "{name}".',
-        msgInvalidFileType: 'Invalid type for file "{name}". Only "{types}" files are supported.',
-        msgInvalidFileExtension: 'Invalid extension for file "{name}". Only "{extensions}" files are supported.',
-        msgValidationError: 'File Upload Error',
-        msgLoading: 'Loading file {index} of {files} &hellip;',
-        msgProgress: 'Loading file {index} of {files} - {name} - {percent}% completed.',
-        msgSelected: '{n} {files} selected',
-        msgFoldersNotAllowed: 'Drag & drop files only! Skipped {n} dropped folder(s).',
-        msgImageWidthSmall: 'Width of image file "{name}" must be at least {size} px.',
-        msgImageHeightSmall: 'Height of image file "{name}" must be at least {size} px.',
-        msgImageWidthLarge: 'Width of image file "{name}" cannot exceed {size} px.',
-        msgImageHeightLarge: 'Height of image file "{name}" cannot exceed {size} px.',
-        dropZoneTitle: 'Drag & drop files here &hellip;'
-    };
+/*!
+ * FileInput <_LANG_> Translations
+ *
+ * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or
+ * any HTML markup tags in the messages must not be converted or translated.
+ *
+ * @see http://github.com/kartik-v/bootstrap-fileinput
+ *
+ * NOTE: this file must be saved in UTF-8 encoding.
+ */
+(function ($) {
+    "use strict";
+
+    $.fn.fileinputLocales['_LANG_'] = {
+        fileSingle: 'file',
+        filePlural: 'files',
+        browseLabel: 'Browse &hellip;',
+        removeLabel: 'Remove',
+        removeTitle: 'Clear selected files',
+        cancelLabel: 'Cancel',
+        cancelTitle: 'Abort ongoing upload',
+        uploadLabel: 'Upload',
+        uploadTitle: 'Upload selected files',
+        msgSizeTooLarge: 'File "{name}" (<b>{size} KB</b>) exceeds maximum allowed upload size of <b>{maxSize} KB</b>. Please retry your upload!',
+        msgFilesTooLess: 'You must select at least <b>{n}</b> {files} to upload. Please retry your upload!',
+        msgFilesTooMany: 'Number of files selected for upload <b>({n})</b> exceeds maximum allowed limit of <b>{m}</b>. Please retry your upload!',
+        msgFileNotFound: 'File "{name}" not found!',
+        msgFileSecured: 'Security restrictions prevent reading the file "{name}".',
+        msgFileNotReadable: 'File "{name}" is not readable.',
+        msgFilePreviewAborted: 'File preview aborted for "{name}".',
+        msgFilePreviewError: 'An error occurred while reading the file "{name}".',
+        msgInvalidFileType: 'Invalid type for file "{name}". Only "{types}" files are supported.',
+        msgInvalidFileExtension: 'Invalid extension for file "{name}". Only "{extensions}" files are supported.',
+        msgValidationError: 'File Upload Error',
+        msgLoading: 'Loading file {index} of {files} &hellip;',
+        msgProgress: 'Loading file {index} of {files} - {name} - {percent}% completed.',
+        msgSelected: '{n} {files} selected',
+        msgFoldersNotAllowed: 'Drag & drop files only! Skipped {n} dropped folder(s).',
+        msgImageWidthSmall: 'Width of image file "{name}" must be at least {size} px.',
+        msgImageHeightSmall: 'Height of image file "{name}" must be at least {size} px.',
+        msgImageWidthLarge: 'Width of image file "{name}" cannot exceed {size} px.',
+        msgImageHeightLarge: 'Height of image file "{name}" cannot exceed {size} px.',
+        dropZoneTitle: 'Drag & drop files here &hellip;'
+    };
 })(window.jQuery);
 })(window.jQuery);

+ 45 - 45
js/fileinput_locale_bg.js

@@ -1,45 +1,45 @@
-/*!
- * FileInput Bulgarian Translations
- *
- * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or
- * any HTML markup tags in the messages must not be converted or translated.
- *
- * @see http://github.com/kartik-v/bootstrap-fileinput
- *
- * NOTE: this file must be saved in UTF-8 encoding.
- */
-(function ($) {
-    "use strict";
-
-    $.fn.fileinputLocales['bg'] = {
-        fileSingle: 'файл',
-        filePlural: 'файла',
-        browseLabel: 'Избери &hellip;',
-        removeLabel: 'Премахни',
-        removeTitle: 'Изчисти избраните',
-        cancelLabel: 'Откажи',
-        cancelTitle: 'Откажи качването',
-        uploadLabel: 'Качи',
-        uploadTitle: 'Качи избраните файлове',
-        msgSizeTooLarge: 'Файла "{name}" (<b>{size} KB</b>) надвишава максималните разрешени <b>{maxSize} KB</b>. Моля опитайте отново!',
-        msgFilesTooLess: 'Трябва да изберете поне <b>{n}</b> {files} файла. Моля опитайте отново!',
-        msgFilesTooMany: 'Броя файлове избрани за качване <b>({n})</b> надвишава ограниченито от максимум <b>{m}</b>. Моля опитайте отново!',
-        msgFileNotFound: 'Файлът "{name}" не може да бъде намерен!',
-        msgFileSecured: 'От съображения за сигурност не може да прочетем файла "{name}".',
-        msgFileNotReadable: 'Файлът "{name}" не е четим.',
-        msgFilePreviewAborted: 'Прегледа на файла е прекратен за "{name}".',
-        msgFilePreviewError: 'Грешка при опит за четене на файла "{name}".',
-        msgInvalidFileType: 'Невалиден тип на файла "{name}". Разрешени са само "{types}".',
-        msgInvalidFileExtension: 'Невалидно разрешение на "{name}". Разрешени са само "{extensions}".',
-        msgValidationError: 'Грешка при качване на файл.',
-        msgLoading: 'Зареждане на файл {index} от общо {files} &hellip;',
-        msgProgress: 'Зареждане на файл {index} от общо {files} - {name} - {percent}% завършени.',
-        msgSelected: '{n} {files} избрани',
-        msgFoldersNotAllowed: 'Само пуснати файлове! Пропуснати {n} пуснати папки.',
-        msgImageWidthSmall: 'Широчината на изображението "{name}" трябва да е поне {size} px.',
-        msgImageHeightSmall: 'Височината на изображението "{name}" трябва да е поне {size} px.',
-        msgImageWidthLarge: 'Широчината на изображението "{name}" не може да е по-голяма от {size} px.',
-        msgImageHeightLarge: 'Височината на изображението "{name}" нее може да е по-голяма от {size} px.',
-        dropZoneTitle: 'Пуснете файловете тук &hellip;'
-    };
-})(window.jQuery);
+/*!
+ * FileInput Bulgarian Translations
+ *
+ * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or
+ * any HTML markup tags in the messages must not be converted or translated.
+ *
+ * @see http://github.com/kartik-v/bootstrap-fileinput
+ *
+ * NOTE: this file must be saved in UTF-8 encoding.
+ */
+(function ($) {
+    "use strict";
+
+    $.fn.fileinputLocales['bg'] = {
+        fileSingle: 'файл',
+        filePlural: 'файла',
+        browseLabel: 'Избери &hellip;',
+        removeLabel: 'Премахни',
+        removeTitle: 'Изчисти избраните',
+        cancelLabel: 'Откажи',
+        cancelTitle: 'Откажи качването',
+        uploadLabel: 'Качи',
+        uploadTitle: 'Качи избраните файлове',
+        msgSizeTooLarge: 'Файла "{name}" (<b>{size} KB</b>) надвишава максималните разрешени <b>{maxSize} KB</b>. Моля опитайте отново!',
+        msgFilesTooLess: 'Трябва да изберете поне <b>{n}</b> {files} файла. Моля опитайте отново!',
+        msgFilesTooMany: 'Броя файлове избрани за качване <b>({n})</b> надвишава ограниченито от максимум <b>{m}</b>. Моля опитайте отново!',
+        msgFileNotFound: 'Файлът "{name}" не може да бъде намерен!',
+        msgFileSecured: 'От съображения за сигурност не може да прочетем файла "{name}".',
+        msgFileNotReadable: 'Файлът "{name}" не е четим.',
+        msgFilePreviewAborted: 'Прегледа на файла е прекратен за "{name}".',
+        msgFilePreviewError: 'Грешка при опит за четене на файла "{name}".',
+        msgInvalidFileType: 'Невалиден тип на файла "{name}". Разрешени са само "{types}".',
+        msgInvalidFileExtension: 'Невалидно разрешение на "{name}". Разрешени са само "{extensions}".',
+        msgValidationError: 'Грешка при качване на файл.',
+        msgLoading: 'Зареждане на файл {index} от общо {files} &hellip;',
+        msgProgress: 'Зареждане на файл {index} от общо {files} - {name} - {percent}% завършени.',
+        msgSelected: '{n} {files} избрани',
+        msgFoldersNotAllowed: 'Само пуснати файлове! Пропуснати {n} пуснати папки.',
+        msgImageWidthSmall: 'Широчината на изображението "{name}" трябва да е поне {size} px.',
+        msgImageHeightSmall: 'Височината на изображението "{name}" трябва да е поне {size} px.',
+        msgImageWidthLarge: 'Широчината на изображението "{name}" не може да е по-голяма от {size} px.',
+        msgImageHeightLarge: 'Височината на изображението "{name}" нее може да е по-голяма от {size} px.',
+        dropZoneTitle: 'Пуснете файловете тук &hellip;'
+    };
+})(window.jQuery);

+ 44 - 44
js/fileinput_locale_cz.js

@@ -1,45 +1,45 @@
-/*!
- * FileInput Czech Translations
- *
- * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or
- * any HTML markup tags in the messages must not be converted or translated.
- *
- * @see http://github.com/kartik-v/bootstrap-fileinput
- *
- * NOTE: this file must be saved in UTF-8 encoding.
- */
-(function ($) {
-    "use strict";
-
-    $.fn.fileinputLocales['cz'] = {
-        fileSingle: 'soubor',
-        filePlural: 'soubory',
-        browseLabel: 'Vybrat &hellip;',
-        removeLabel: 'Odstranit',
-        removeTitle: 'Vyčistit vybrané soubory',
-        cancelLabel: 'Storno',
-        cancelTitle: 'Přerušit  nahrávání',
-        uploadLabel: 'Nahrát',
-        uploadTitle: 'Nahrát vybrané soubory',
-        msgSizeTooLarge: 'Soubor "{name}" (<b>{size} KB</b>): překročení - maximální povolená velikost <b>{maxSize} KB</b>. Zkuste nahrát znova, prosím!',
-        msgFilesTooLess: 'Musíte vybrat nejméně <b>{n}</b> {files} pro nahrání. Zkuste nahrát znova, prosím!',
-        msgFilesTooMany: 'Počet vybraných souborů pro nahrání <b>({n})</b>: překročení - maximální povolený limit <b>{m}</b>. Zkuste nahrát znova, prosím!',
-        msgFileNotFound: 'Soubor "{name}" nebyl nalezen!',
-        msgFileSecured: 'Zabezpečení souboru znemožnilo číst soubor "{name}".',
-        msgFileNotReadable: 'Soubor "{name}" není čitelný.',
-        msgFilePreviewAborted: 'Náhled souboru byl přerušen pro "{name}".',
-        msgFilePreviewError: 'Nastala chyba při načtení souboru "{name}".',
-        msgInvalidFileType: 'Neplatný typ souboru "{name}". Pouze "{types}" souborů jsou podporovány.',
-        msgInvalidFileExtension: 'Neplatná extenze souboru "{name}". Pouze "{extensions}" souborů jsou podporovány.',
-        msgValidationError: 'Chyba nahrání souboru.',
-        msgLoading: 'Nahrávání souboru {index} z {files} &hellip;',
-        msgProgress: 'Nahrávání souboru {index} z {files} - {name} - {percent}% dokončeno.',
-        msgSelected: '{n} {files} vybrano',
-        msgFoldersNotAllowed: 'Táhni a pusť pouze soubory! Vynechané {n} pustěné složk(y).',
-        msgImageWidthSmall: 'Šířka image soubor "{name}", musí být alespoň {size} px.',
-        msgImageHeightSmall: 'Výška image soubor "{name}", musí být alespoň {size} px.',
-        msgImageWidthLarge: 'Šířka obrazového souboru "{name}" nelze překročit {size} px.',
-        msgImageHeightLarge: 'Výška obrazového souboru "{name}" nelze překročit {size} px.',
-        dropZoneTitle: 'Táhni a pusť soubory sem &hellip;'
-    };
+/*!
+ * FileInput Czech Translations
+ *
+ * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or
+ * any HTML markup tags in the messages must not be converted or translated.
+ *
+ * @see http://github.com/kartik-v/bootstrap-fileinput
+ *
+ * NOTE: this file must be saved in UTF-8 encoding.
+ */
+(function ($) {
+    "use strict";
+
+    $.fn.fileinputLocales['cz'] = {
+        fileSingle: 'soubor',
+        filePlural: 'soubory',
+        browseLabel: 'Vybrat &hellip;',
+        removeLabel: 'Odstranit',
+        removeTitle: 'Vyčistit vybrané soubory',
+        cancelLabel: 'Storno',
+        cancelTitle: 'Přerušit  nahrávání',
+        uploadLabel: 'Nahrát',
+        uploadTitle: 'Nahrát vybrané soubory',
+        msgSizeTooLarge: 'Soubor "{name}" (<b>{size} KB</b>): překročení - maximální povolená velikost <b>{maxSize} KB</b>. Zkuste nahrát znova, prosím!',
+        msgFilesTooLess: 'Musíte vybrat nejméně <b>{n}</b> {files} pro nahrání. Zkuste nahrát znova, prosím!',
+        msgFilesTooMany: 'Počet vybraných souborů pro nahrání <b>({n})</b>: překročení - maximální povolený limit <b>{m}</b>. Zkuste nahrát znova, prosím!',
+        msgFileNotFound: 'Soubor "{name}" nebyl nalezen!',
+        msgFileSecured: 'Zabezpečení souboru znemožnilo číst soubor "{name}".',
+        msgFileNotReadable: 'Soubor "{name}" není čitelný.',
+        msgFilePreviewAborted: 'Náhled souboru byl přerušen pro "{name}".',
+        msgFilePreviewError: 'Nastala chyba při načtení souboru "{name}".',
+        msgInvalidFileType: 'Neplatný typ souboru "{name}". Pouze "{types}" souborů jsou podporovány.',
+        msgInvalidFileExtension: 'Neplatná extenze souboru "{name}". Pouze "{extensions}" souborů jsou podporovány.',
+        msgValidationError: 'Chyba nahrání souboru.',
+        msgLoading: 'Nahrávání souboru {index} z {files} &hellip;',
+        msgProgress: 'Nahrávání souboru {index} z {files} - {name} - {percent}% dokončeno.',
+        msgSelected: '{n} {files} vybrano',
+        msgFoldersNotAllowed: 'Táhni a pusť pouze soubory! Vynechané {n} pustěné složk(y).',
+        msgImageWidthSmall: 'Šířka image soubor "{name}", musí být alespoň {size} px.',
+        msgImageHeightSmall: 'Výška image soubor "{name}", musí být alespoň {size} px.',
+        msgImageWidthLarge: 'Šířka obrazového souboru "{name}" nelze překročit {size} px.',
+        msgImageHeightLarge: 'Výška obrazového souboru "{name}" nelze překročit {size} px.',
+        dropZoneTitle: 'Táhni a pusť soubory sem &hellip;'
+    };
 })(window.jQuery);
 })(window.jQuery);

+ 42 - 42
js/fileinput_locale_de.js

@@ -1,43 +1,43 @@
-/*!
- * FileInput German Translations
- *
- * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or
- * any HTML markup tags in the messages must not be converted or translated.
- *
- * @see http://github.com/kartik-v/bootstrap-fileinput
- */
-(function ($) {
-    "use strict";
-
-    $.fn.fileinputLocales['de'] = {
-        fileSingle: 'Datei',
-        filePlural: 'Dateien',
-        browseLabel: 'Auswählen &hellip;',
-        removeLabel: 'Löschen',
-        removeTitle: 'Ausgewählte löschen',
-        cancelLabel: 'Laden',
-        cancelTitle: 'Hochladen abbrechen',
-        uploadLabel: 'Hochladen',
-        uploadTitle: 'Hochladen der ausgewählten Dateien',
-        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. Bitte versuchen es erneut!',
-        msgFilesTooMany: 'Anzahl der Dateien für den Upload ausgewählt <b>({n})</b> überschreitet maximal zulässige Grenze von <b>{m}</b> Stück.',
-        msgFileNotFound: 'Datei "{name}" wurde nicht gefunden!',
-        msgFileSecured: 'Sicherheitseinstellungen verhindern das Lesen der Datei "{name}".',
-        msgFileNotReadable: 'Die Datei "{name}" ist nicht lesbar.',
-        msgFilePreviewAborted: 'Dateivorschau abgebrochen für "{name}".',
-        msgFilePreviewError: 'Beim Lesen der Datei "{name}" ein Fehler aufgetreten.',
-        msgInvalidFileType: 'Ungültiger Typ für Datei "{name}". Nur Dateien der Typen "{types}" werden unterstützt.',
-        msgInvalidFileExtension: 'Ungültige Erweiterung für Datei "{name}". Nur Dateien mit der Endung "{extensions}" werden unterstützt.',
-        msgValidationError: 'Fehler beim Hochladen',
-        msgLoading: 'Lade Datei {index} von {files} hoch&hellip;',
-        msgProgress: 'Datei {index} von {files} - {name} - zu {percent}% fertiggestellt.',
-        msgSelected: '{n} {files} ausgewählt',
-        msgFoldersNotAllowed: 'Drag & Drop funktioniert nur bei Dateien! {n} Ordner übersprungen.',
-        msgImageWidthSmall: 'Breite der Bilddatei "{name}" muss mindestens {size} px betragen.',
-        msgImageHeightSmall: 'Höhe der Bilddatei "{name}" muss mindestens {size} px betragen.',
-        msgImageWidthLarge: 'Breite der Bilddatei "{name}" nicht überschreiten {size} px.',
-        msgImageHeightLarge: 'Höhe der Bilddatei "{name}" nicht überschreiten {size} px.',
-        dropZoneTitle: 'Dateien hierher ziehen &hellip;'
-    };
+/*!
+ * FileInput German Translations
+ *
+ * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or
+ * any HTML markup tags in the messages must not be converted or translated.
+ *
+ * @see http://github.com/kartik-v/bootstrap-fileinput
+ */
+(function ($) {
+    "use strict";
+
+    $.fn.fileinputLocales['de'] = {
+        fileSingle: 'Datei',
+        filePlural: 'Dateien',
+        browseLabel: 'Auswählen &hellip;',
+        removeLabel: 'Löschen',
+        removeTitle: 'Ausgewählte löschen',
+        cancelLabel: 'Laden',
+        cancelTitle: 'Hochladen abbrechen',
+        uploadLabel: 'Hochladen',
+        uploadTitle: 'Hochladen der ausgewählten Dateien',
+        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. Bitte versuchen es erneut!',
+        msgFilesTooMany: 'Anzahl der Dateien für den Upload ausgewählt <b>({n})</b> überschreitet maximal zulässige Grenze von <b>{m}</b> Stück.',
+        msgFileNotFound: 'Datei "{name}" wurde nicht gefunden!',
+        msgFileSecured: 'Sicherheitseinstellungen verhindern das Lesen der Datei "{name}".',
+        msgFileNotReadable: 'Die Datei "{name}" ist nicht lesbar.',
+        msgFilePreviewAborted: 'Dateivorschau abgebrochen für "{name}".',
+        msgFilePreviewError: 'Beim Lesen der Datei "{name}" ein Fehler aufgetreten.',
+        msgInvalidFileType: 'Ungültiger Typ für Datei "{name}". Nur Dateien der Typen "{types}" werden unterstützt.',
+        msgInvalidFileExtension: 'Ungültige Erweiterung für Datei "{name}". Nur Dateien mit der Endung "{extensions}" werden unterstützt.',
+        msgValidationError: 'Fehler beim Hochladen',
+        msgLoading: 'Lade Datei {index} von {files} hoch&hellip;',
+        msgProgress: 'Datei {index} von {files} - {name} - zu {percent}% fertiggestellt.',
+        msgSelected: '{n} {files} ausgewählt',
+        msgFoldersNotAllowed: 'Drag & Drop funktioniert nur bei Dateien! {n} Ordner übersprungen.',
+        msgImageWidthSmall: 'Breite der Bilddatei "{name}" muss mindestens {size} px betragen.',
+        msgImageHeightSmall: 'Höhe der Bilddatei "{name}" muss mindestens {size} px betragen.',
+        msgImageWidthLarge: 'Breite der Bilddatei "{name}" nicht überschreiten {size} px.',
+        msgImageHeightLarge: 'Höhe der Bilddatei "{name}" nicht überschreiten {size} px.',
+        dropZoneTitle: 'Dateien hierher ziehen &hellip;'
+    };
 })(window.jQuery);
 })(window.jQuery);

+ 44 - 44
js/fileinput_locale_el.js

@@ -1,45 +1,45 @@
-/*!
- * FileInput Greek Translations
- *
- * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or
- * any HTML markup tags in the messages must not be converted or translated.
- *
- * @see http://github.com/kartik-v/bootstrap-fileinput
- *
- * NOTE: this file must be saved in UTF-8 encoding.
- */
-(function ($) {
-    "use strict";
-
-    $.fn.fileinputLocales['el'] = {
-        fileSingle: 'Αρχείο',
-        filePlural: 'Αρχεία',
-        browseLabel: 'Αναζήτηση &hellip;',
-        removeLabel: 'Ακύρωση',
-        removeTitle: 'Εκκαθάριση αρχείων',
-        cancelLabel: 'Ακύρωση',
-        cancelTitle: 'Ακύρωση μεταφόρτωσης',
-        uploadLabel: 'Μεταφόρτωση',
-        uploadTitle: 'Μεταφόρτωση επιλεγμένων αρχείων',
-        msgSizeTooLarge: 'Το αρχείο "{name}" (<b>{size} KB</b>) υπερβαίνει το μέγιστο επιτρεπόμενο μέγεθος μεταφόρτωσης <b>{maxSize} KB</b>. Παρακαλώ ξαναπροσπαθήστε!',
-        msgFilesTooLess: 'Πρέπει να επιλέξετε τουλάχιστον <b>{n}</b> {files} για να ξεκινήσει η μεταφόρτωση. Παρακαλώ ξαναπροσπαθήστε!',
-        msgFilesTooMany: 'Ο αριθμός των αρχείων που έχουν επιλεγεί για μεταφόρτωση <b>({n})</b> υπερβαίνει το μέγιστο επιτρεπόμενο αριθμό <b>{m}</b>. Παρακαλώ ξαναπροσπαθήστε!',
-        msgFileNotFound: 'Το αρχείο με όνομα "{name}" δεν βρέθηκε!',
-        msgFileSecured: 'Περιορισμοί ασφαλείας εμπόδισαν την ανάγνωση του αρχείου"{name}".',
-        msgFileNotReadable: 'Το αρχείο με όνομα "{name}" δεν είναι αναγνώσιμο.',
-        msgFilePreviewAborted: 'Η προεπισκόπηση του αρχείου ακυρώθηκε για "{name}".',
-        msgFilePreviewError: 'Παρουσιάστηκε σφάλμα κατά την ανάγνωση του αρχείου "{name}".',
-        msgInvalidFileType: 'Μη έγκυρος τύπος αρχείου "{name}". Οι τύποι αρχείων που υποστηρίζονται είναι : "{types}".',
-        msgInvalidFileExtension: 'Μη έγκυρη επέκταση αρχείου "{name}". Οι επεκτάσεις που υποστηρίζονται είναι:  "{extensions}" .',
-        msgValidationError: 'Σφάλμα κατά την μεταφόρτωση',
-        msgLoading: 'Φόρτωση αρχείου {index} από {files} &hellip;',
-        msgProgress: 'Φόρτωση αρχείου {index} απο {files} - {name} - {percent}% ολοκληρώθηκε.',
-        msgSelected: '{n} {files} επιλέχθηκαν',
-        msgFoldersNotAllowed: 'Μπορείτε να σύρετε μόνο αρχεία! Παραβλέφθηκαν {n} φάκελος(οι).',
-        msgImageWidthSmall: 'Πλάτος του αρχείου εικόνας "{name}" πρέπει να είναι τουλάχιστον {size} px.',
-        msgImageHeightSmall: 'Ύψος του αρχείου εικόνας "{name}" πρέπει να είναι τουλάχιστον {size} px.',
-        msgImageWidthLarge: 'Πλάτος του αρχείου εικόνας "{name}" δεν μπορεί να υπερβαίνει το {size} px.',
-        msgImageHeightLarge: 'Ύψος του αρχείου εικόνας "{name}" δεν μπορεί να υπερβαίνει το {size} px.',
-        dropZoneTitle: 'Σύρετε τα αρχεία εδώ &hellip;'
-    };
+/*!
+ * FileInput Greek Translations
+ *
+ * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or
+ * any HTML markup tags in the messages must not be converted or translated.
+ *
+ * @see http://github.com/kartik-v/bootstrap-fileinput
+ *
+ * NOTE: this file must be saved in UTF-8 encoding.
+ */
+(function ($) {
+    "use strict";
+
+    $.fn.fileinputLocales['el'] = {
+        fileSingle: 'Αρχείο',
+        filePlural: 'Αρχεία',
+        browseLabel: 'Αναζήτηση &hellip;',
+        removeLabel: 'Ακύρωση',
+        removeTitle: 'Εκκαθάριση αρχείων',
+        cancelLabel: 'Ακύρωση',
+        cancelTitle: 'Ακύρωση μεταφόρτωσης',
+        uploadLabel: 'Μεταφόρτωση',
+        uploadTitle: 'Μεταφόρτωση επιλεγμένων αρχείων',
+        msgSizeTooLarge: 'Το αρχείο "{name}" (<b>{size} KB</b>) υπερβαίνει το μέγιστο επιτρεπόμενο μέγεθος μεταφόρτωσης <b>{maxSize} KB</b>. Παρακαλώ ξαναπροσπαθήστε!',
+        msgFilesTooLess: 'Πρέπει να επιλέξετε τουλάχιστον <b>{n}</b> {files} για να ξεκινήσει η μεταφόρτωση. Παρακαλώ ξαναπροσπαθήστε!',
+        msgFilesTooMany: 'Ο αριθμός των αρχείων που έχουν επιλεγεί για μεταφόρτωση <b>({n})</b> υπερβαίνει το μέγιστο επιτρεπόμενο αριθμό <b>{m}</b>. Παρακαλώ ξαναπροσπαθήστε!',
+        msgFileNotFound: 'Το αρχείο με όνομα "{name}" δεν βρέθηκε!',
+        msgFileSecured: 'Περιορισμοί ασφαλείας εμπόδισαν την ανάγνωση του αρχείου"{name}".',
+        msgFileNotReadable: 'Το αρχείο με όνομα "{name}" δεν είναι αναγνώσιμο.',
+        msgFilePreviewAborted: 'Η προεπισκόπηση του αρχείου ακυρώθηκε για "{name}".',
+        msgFilePreviewError: 'Παρουσιάστηκε σφάλμα κατά την ανάγνωση του αρχείου "{name}".',
+        msgInvalidFileType: 'Μη έγκυρος τύπος αρχείου "{name}". Οι τύποι αρχείων που υποστηρίζονται είναι : "{types}".',
+        msgInvalidFileExtension: 'Μη έγκυρη επέκταση αρχείου "{name}". Οι επεκτάσεις που υποστηρίζονται είναι:  "{extensions}" .',
+        msgValidationError: 'Σφάλμα κατά την μεταφόρτωση',
+        msgLoading: 'Φόρτωση αρχείου {index} από {files} &hellip;',
+        msgProgress: 'Φόρτωση αρχείου {index} απο {files} - {name} - {percent}% ολοκληρώθηκε.',
+        msgSelected: '{n} {files} επιλέχθηκαν',
+        msgFoldersNotAllowed: 'Μπορείτε να σύρετε μόνο αρχεία! Παραβλέφθηκαν {n} φάκελος(οι).',
+        msgImageWidthSmall: 'Πλάτος του αρχείου εικόνας "{name}" πρέπει να είναι τουλάχιστον {size} px.',
+        msgImageHeightSmall: 'Ύψος του αρχείου εικόνας "{name}" πρέπει να είναι τουλάχιστον {size} px.',
+        msgImageWidthLarge: 'Πλάτος του αρχείου εικόνας "{name}" δεν μπορεί να υπερβαίνει το {size} px.',
+        msgImageHeightLarge: 'Ύψος του αρχείου εικόνας "{name}" δεν μπορεί να υπερβαίνει το {size} px.',
+        dropZoneTitle: 'Σύρετε τα αρχεία εδώ &hellip;'
+    };
 })(window.jQuery);
 })(window.jQuery);

+ 45 - 45
js/fileinput_locale_es.js

@@ -1,45 +1,45 @@
-/*!
- * FileInput Spanish Translations
- *
- * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or
- * any HTML markup tags in the messages must not be converted or translated.
- *
- * @see http://github.com/kartik-v/bootstrap-fileinput
- *
- * NOTE: this file must be saved in UTF-8 encoding.
- */
-(function ($) {
-    "use strict";
-
-    $.fn.fileinputLocales['es'] = {
-        fileSingle: 'archivo',
-        filePlural: 'archivos',
-        browseLabel: 'Examinar &hellip;',
-        removeLabel: 'Quitar',
-        removeTitle: 'Quitar archivos seleccionados',
-        cancelLabel: 'Cancelar',
-        cancelTitle: 'Abortar la subida en curso',
-        uploadLabel: 'Subir archivo',
-        uploadTitle: 'Subir archivos seleccionados',
-        msgSizeTooLarge: 'Archivo "{name}" (<b>{size} KB</b>) excede el tamaño máximo permitido de <b>{maxSize} KB</b>. Por favor, inténtelo de nuevo con archivos mas pequeños.',
-        msgFilesTooLess: 'Debe seleccionar al menos <b>{n}</b> {files} a cargar. Por favor, inténtelo de nuevo.',
-        msgFilesTooMany: 'El número de archivos seleccionados a cargar <b>({n})</b> excede el límite máximo permitido de <b>{m}</b>. Por favor, inténtelo de nuevo.',
-        msgFileNotFound: 'Archivo "{name}" no encontrado.',
-        msgFileSecured: 'No es posible acceder al archivo "{name}" porque estará siendo usado por otra aplicación o no tengamos permisos de lectura.',
-        msgFileNotReadable: 'No es posible acceder al archivo "{name}".',
-        msgFilePreviewAborted: 'Previsualización del archivo "{name}" cancelada.',
-        msgFilePreviewError: 'Ocurrió un error mientras se leía el archivo "{name}".',
-        msgInvalidFileType: 'Tipo de archivo no válido para "{name}". Sólo archivos "{types}" son permitidos.',
-        msgInvalidFileExtension: 'Extensión de archivo no válido para "{name}". Sólo archivos "{extensions}" son permitidos.',
-        msgValidationError: 'Error al subir archivo',
-        msgLoading: 'Subiendo archivo {index} de {files} &hellip;',
-        msgProgress: 'Subiendo archivo {index} de {files} - {name} - {percent}% completado.',
-        msgSelected: '{n} {files} seleccionado(s)',
-        msgFoldersNotAllowed: 'Arrastre y suelte únicamente archivos. Omitida(s) {n} carpeta(s).',
-        msgImageWidthSmall: 'El ancho de la imagen "{name}" debe ser al menos {size} px.',
-        msgImageHeightSmall: 'La altura de la imagen "{name}" debe ser al menos {size} px.',
-        msgImageWidthLarge: 'El ancho de la imagen "{name}" no puede exceder de {size} px.',
-        msgImageHeightLarge: 'La altura de la imagen "{name}" no puede exceder de {size} px.',
-        dropZoneTitle: 'Arrastre y suelte aquí los archivos &hellip;'
-    };
-})(window.jQuery);
+/*!
+ * FileInput Spanish Translations
+ *
+ * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or
+ * any HTML markup tags in the messages must not be converted or translated.
+ *
+ * @see http://github.com/kartik-v/bootstrap-fileinput
+ *
+ * NOTE: this file must be saved in UTF-8 encoding.
+ */
+(function ($) {
+    "use strict";
+
+    $.fn.fileinputLocales['es'] = {
+        fileSingle: 'archivo',
+        filePlural: 'archivos',
+        browseLabel: 'Examinar &hellip;',
+        removeLabel: 'Quitar',
+        removeTitle: 'Quitar archivos seleccionados',
+        cancelLabel: 'Cancelar',
+        cancelTitle: 'Abortar la subida en curso',
+        uploadLabel: 'Subir archivo',
+        uploadTitle: 'Subir archivos seleccionados',
+        msgSizeTooLarge: 'Archivo "{name}" (<b>{size} KB</b>) excede el tamaño máximo permitido de <b>{maxSize} KB</b>. Por favor, inténtelo de nuevo con archivos mas pequeños.',
+        msgFilesTooLess: 'Debe seleccionar al menos <b>{n}</b> {files} a cargar. Por favor, inténtelo de nuevo.',
+        msgFilesTooMany: 'El número de archivos seleccionados a cargar <b>({n})</b> excede el límite máximo permitido de <b>{m}</b>. Por favor, inténtelo de nuevo.',
+        msgFileNotFound: 'Archivo "{name}" no encontrado.',
+        msgFileSecured: 'No es posible acceder al archivo "{name}" porque estará siendo usado por otra aplicación o no tengamos permisos de lectura.',
+        msgFileNotReadable: 'No es posible acceder al archivo "{name}".',
+        msgFilePreviewAborted: 'Previsualización del archivo "{name}" cancelada.',
+        msgFilePreviewError: 'Ocurrió un error mientras se leía el archivo "{name}".',
+        msgInvalidFileType: 'Tipo de archivo no válido para "{name}". Sólo archivos "{types}" son permitidos.',
+        msgInvalidFileExtension: 'Extensión de archivo no válido para "{name}". Sólo archivos "{extensions}" son permitidos.',
+        msgValidationError: 'Error al subir archivo',
+        msgLoading: 'Subiendo archivo {index} de {files} &hellip;',
+        msgProgress: 'Subiendo archivo {index} de {files} - {name} - {percent}% completado.',
+        msgSelected: '{n} {files} seleccionado(s)',
+        msgFoldersNotAllowed: 'Arrastre y suelte únicamente archivos. Omitida(s) {n} carpeta(s).',
+        msgImageWidthSmall: 'El ancho de la imagen "{name}" debe ser al menos {size} px.',
+        msgImageHeightSmall: 'La altura de la imagen "{name}" debe ser al menos {size} px.',
+        msgImageWidthLarge: 'El ancho de la imagen "{name}" no puede exceder de {size} px.',
+        msgImageHeightLarge: 'La altura de la imagen "{name}" no puede exceder de {size} px.',
+        dropZoneTitle: 'Arrastre y suelte aquí los archivos &hellip;'
+    };
+})(window.jQuery);

+ 46 - 46
js/fileinput_locale_fa.js

@@ -1,46 +1,46 @@
-/*!
- * FileInput Persian Translations
- *
- * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or
- * any HTML markup tags in the messages must not be converted or translated.
- *
- * @see http://github.com/kartik-v/bootstrap-fileinput
- * @author Milad Nekofar <[email protected]>
- *
- * NOTE: this file must be saved in UTF-8 encoding.
- */
-(function ($) {
-    "use strict";
-
-    $.fn.fileinputLocales['fa'] = {
-        fileSingle: 'فایل',
-        filePlural: 'فایل',
-        browseLabel: 'مرور &hellip;',
-        removeLabel: 'حذف',
-        removeTitle: 'پاکسازی فایل‌های انتخاب شده',
-        cancelLabel: 'لغو',
-        cancelTitle: 'لغو بارگزاری جاری',
-        uploadLabel: 'بارگذاری',
-        uploadTitle: 'بارگذاری فایل‌های انتخاب شده',
-        msgSizeTooLarge: 'فایل "{name}" (<b>{size} کیلوبایت</b>) از حداکثر مجاز <b>{maxSize} کیلوبایت</b> عبور کرده است. لطفا مجددا برای بارگذاری سعی کنید!',
-        msgFilesTooLess: 'شما باید حداقل <b>{n}</b> {files} فایل برای بارگذاری انتخاب کنید. لطفا مجددا برای بارگذاری سعی کنید!',
-        msgFilesTooMany: 'تعداد فایل‌های انتخاب شده برای بارگذاری <b>({n})</b> از حداکثر مجاز عبور کرده است <b>{m}</b>. لطفا مجددا برای بارگذاری سعی کنید!',
-        msgFileNotFound: 'فایل "{name}" یافت نشد!',
-        msgFileSecured: 'محدودیت های امنیتی مانع خواندن فایل "{name}" است.',
-        msgFileNotReadable: 'فایل "{name}" قابل نوشتن نیست.',
-        msgFilePreviewAborted: 'پیشنمایش فایل "{name}". شکست خورد',
-        msgFilePreviewError: 'در هنگام خواندن فایل "{name}" خطایی رخ داد.',
-        msgInvalidFileType: 'نوع فایل "{name}" معتبر نیست. فقط "{types}" پشیبانی می‌شود.',
-        msgInvalidFileExtension: 'پسوند فایل "{name}" معتبر نیست. فقط "{extensions}" پشتیبانی می‌شود.',
-        msgValidationError: 'خطا در بارگزاری فایل',
-        msgLoading: 'بارگیری فایل {index} از {files} &hellip;',
-        msgProgress: 'بارگیری فایل {index} از {files} - {name} - {percent}% تمام شد.',
-        msgSelected: '{n} {files} انتخاب شده',
-        msgFoldersNotAllowed: 'فقط فایل‌ها را بکشید و رها کنید! {n} پوشه نادیده گرفته شد.',
-        msgImageWidthSmall: 'عرض فایل تصویر "{name}" باید حداقل {size} پیکسل باشد.',
-        msgImageHeightSmall: 'ارتفاع فایل تصویر "{name}" باید حداقل {size} پیکسل باشد.',
-        msgImageWidthLarge: 'عرض فایل تصویر "{name}" نمیتواند از {size} پیکسل بیشتر باشد.',
-        msgImageHeightLarge: 'ارتفاع فایل تصویر "{name}" نمی‌تواند از {size} پیکسل بیشتر باشد.',
-        dropZoneTitle: 'فایل‌ها را بکشید و در اینجا رها کنید &hellip;'
-    };
-})(window.jQuery);
+/*!
+ * FileInput Persian Translations
+ *
+ * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or
+ * any HTML markup tags in the messages must not be converted or translated.
+ *
+ * @see http://github.com/kartik-v/bootstrap-fileinput
+ * @author Milad Nekofar <[email protected]>
+ *
+ * NOTE: this file must be saved in UTF-8 encoding.
+ */
+(function ($) {
+    "use strict";
+
+    $.fn.fileinputLocales['fa'] = {
+        fileSingle: 'فایل',
+        filePlural: 'فایل',
+        browseLabel: 'مرور &hellip;',
+        removeLabel: 'حذف',
+        removeTitle: 'پاکسازی فایل‌های انتخاب شده',
+        cancelLabel: 'لغو',
+        cancelTitle: 'لغو بارگزاری جاری',
+        uploadLabel: 'بارگذاری',
+        uploadTitle: 'بارگذاری فایل‌های انتخاب شده',
+        msgSizeTooLarge: 'فایل "{name}" (<b>{size} کیلوبایت</b>) از حداکثر مجاز <b>{maxSize} کیلوبایت</b> عبور کرده است. لطفا مجددا برای بارگذاری سعی کنید!',
+        msgFilesTooLess: 'شما باید حداقل <b>{n}</b> {files} فایل برای بارگذاری انتخاب کنید. لطفا مجددا برای بارگذاری سعی کنید!',
+        msgFilesTooMany: 'تعداد فایل‌های انتخاب شده برای بارگذاری <b>({n})</b> از حداکثر مجاز عبور کرده است <b>{m}</b>. لطفا مجددا برای بارگذاری سعی کنید!',
+        msgFileNotFound: 'فایل "{name}" یافت نشد!',
+        msgFileSecured: 'محدودیت های امنیتی مانع خواندن فایل "{name}" است.',
+        msgFileNotReadable: 'فایل "{name}" قابل نوشتن نیست.',
+        msgFilePreviewAborted: 'پیشنمایش فایل "{name}". شکست خورد',
+        msgFilePreviewError: 'در هنگام خواندن فایل "{name}" خطایی رخ داد.',
+        msgInvalidFileType: 'نوع فایل "{name}" معتبر نیست. فقط "{types}" پشیبانی می‌شود.',
+        msgInvalidFileExtension: 'پسوند فایل "{name}" معتبر نیست. فقط "{extensions}" پشتیبانی می‌شود.',
+        msgValidationError: 'خطا در بارگزاری فایل',
+        msgLoading: 'بارگیری فایل {index} از {files} &hellip;',
+        msgProgress: 'بارگیری فایل {index} از {files} - {name} - {percent}% تمام شد.',
+        msgSelected: '{n} {files} انتخاب شده',
+        msgFoldersNotAllowed: 'فقط فایل‌ها را بکشید و رها کنید! {n} پوشه نادیده گرفته شد.',
+        msgImageWidthSmall: 'عرض فایل تصویر "{name}" باید حداقل {size} پیکسل باشد.',
+        msgImageHeightSmall: 'ارتفاع فایل تصویر "{name}" باید حداقل {size} پیکسل باشد.',
+        msgImageWidthLarge: 'عرض فایل تصویر "{name}" نمیتواند از {size} پیکسل بیشتر باشد.',
+        msgImageHeightLarge: 'ارتفاع فایل تصویر "{name}" نمی‌تواند از {size} پیکسل بیشتر باشد.',
+        dropZoneTitle: 'فایل‌ها را بکشید و در اینجا رها کنید &hellip;'
+    };
+})(window.jQuery);

+ 44 - 44
js/fileinput_locale_fr.js

@@ -1,45 +1,45 @@
-/*!
- * FileInput French Translations
- *
- * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or
- * any HTML markup tags in the messages must not be converted or translated.
- *
- * @see http://github.com/kartik-v/bootstrap-fileinput
- *
- * NOTE: this file must be saved in UTF-8 encoding.
- */
-(function ($) {
-    "use strict";
-
-    $.fn.fileinputLocales['fr'] = {
-        fileSingle: 'fichier',
-        filePlural: 'fichiers',
-        browseLabel: 'Parcourir&hellip;',
-        removeLabel: 'Retirer',
-        removeTitle: 'Retirer les fichiers sélectionnés',
-        cancelLabel: 'Annuler',
-        cancelTitle: "Annuler l'envoi en cours",
-        uploadLabel: 'Transférer',
-        uploadTitle: 'Transférer les fichiers sélectionnés',
-        msgSizeTooLarge: 'Le fichier "{name}" (<b>{size} KB</b>) dépasse la taille maximale autorisée qui est de <b>{maxSize} KB</b>. Merci de recommencer !',
-        msgFilesTooLess: 'Vous devez sélectionner au moins <b>{n}</b> {files} à transmetter. Merci de recommencer !',
-        msgFilesTooMany: 'Le nombre de fichier sélectionné <b>({n})</b> dépasse la quantité maximale autorisée qui est de <b>{m}</b>. Merci de recommencer !',
-        msgFileNotFound: 'Le fichier "{name}" est introuvable !',
-        msgFileSecured: "Des restrictions de sécurité vous empêchent d'accéder au fichier \"{name}\".",
-        msgFileNotReadable: 'Le fichier "{name}" est illisble.',
-        msgFilePreviewAborted: 'Prévisualisation du fichier "{name}" annulée.',
-        msgFilePreviewError: 'Une erreur est survenue lors de la lecture du fichier "{name}".',
-        msgInvalidFileType: 'Type de document invalide pour "{name}". Seulement les documents de type "{types}" sont autorisés.',
-        msgInvalidFileExtension: 'Extension invalide pour le fichier "{name}". Seules les extensions "{extensions}" sont autorisées.',
-        msgValidationError: 'Erreur lors de la transmission du fichier',
-        msgLoading: 'Transmission du fichier {index} sur {files}&hellip;',
-        msgProgress: 'Transmission du fichier {index} sur {files} - {name} - {percent}% faits.',
-        msgSelected: '{n} {files} sélectionné(s)',
-        msgFoldersNotAllowed: 'Glissez et déposez uniquement des fichiers ! {n} répertoire(s) exclu(s).',
-        msgImageWidthSmall: 'Largeur de fichier image "{name}" doit être d\'au moins {size} px.',
-        msgImageHeightSmall: 'Hauteur de fichier image "{name}" doit être d\'au moins {size} px.',
-        msgImageWidthLarge: 'Largeur de fichier image "{name}" ne peut pas dépasser {size} px.',
-        msgImageHeightLarge: 'Hauteur de fichier image "{name}" ne peut pas dépasser {size} px.',
-        dropZoneTitle: 'Glissez et déposez les fichiers ici&hellip;'
-    };
+/*!
+ * FileInput French Translations
+ *
+ * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or
+ * any HTML markup tags in the messages must not be converted or translated.
+ *
+ * @see http://github.com/kartik-v/bootstrap-fileinput
+ *
+ * NOTE: this file must be saved in UTF-8 encoding.
+ */
+(function ($) {
+    "use strict";
+
+    $.fn.fileinputLocales['fr'] = {
+        fileSingle: 'fichier',
+        filePlural: 'fichiers',
+        browseLabel: 'Parcourir&hellip;',
+        removeLabel: 'Retirer',
+        removeTitle: 'Retirer les fichiers sélectionnés',
+        cancelLabel: 'Annuler',
+        cancelTitle: "Annuler l'envoi en cours",
+        uploadLabel: 'Transférer',
+        uploadTitle: 'Transférer les fichiers sélectionnés',
+        msgSizeTooLarge: 'Le fichier "{name}" (<b>{size} KB</b>) dépasse la taille maximale autorisée qui est de <b>{maxSize} KB</b>. Merci de recommencer !',
+        msgFilesTooLess: 'Vous devez sélectionner au moins <b>{n}</b> {files} à transmetter. Merci de recommencer !',
+        msgFilesTooMany: 'Le nombre de fichier sélectionné <b>({n})</b> dépasse la quantité maximale autorisée qui est de <b>{m}</b>. Merci de recommencer !',
+        msgFileNotFound: 'Le fichier "{name}" est introuvable !',
+        msgFileSecured: "Des restrictions de sécurité vous empêchent d'accéder au fichier \"{name}\".",
+        msgFileNotReadable: 'Le fichier "{name}" est illisble.',
+        msgFilePreviewAborted: 'Prévisualisation du fichier "{name}" annulée.',
+        msgFilePreviewError: 'Une erreur est survenue lors de la lecture du fichier "{name}".',
+        msgInvalidFileType: 'Type de document invalide pour "{name}". Seulement les documents de type "{types}" sont autorisés.',
+        msgInvalidFileExtension: 'Extension invalide pour le fichier "{name}". Seules les extensions "{extensions}" sont autorisées.',
+        msgValidationError: 'Erreur lors de la transmission du fichier',
+        msgLoading: 'Transmission du fichier {index} sur {files}&hellip;',
+        msgProgress: 'Transmission du fichier {index} sur {files} - {name} - {percent}% faits.',
+        msgSelected: '{n} {files} sélectionné(s)',
+        msgFoldersNotAllowed: 'Glissez et déposez uniquement des fichiers ! {n} répertoire(s) exclu(s).',
+        msgImageWidthSmall: 'Largeur de fichier image "{name}" doit être d\'au moins {size} px.',
+        msgImageHeightSmall: 'Hauteur de fichier image "{name}" doit être d\'au moins {size} px.',
+        msgImageWidthLarge: 'Largeur de fichier image "{name}" ne peut pas dépasser {size} px.',
+        msgImageHeightLarge: 'Hauteur de fichier image "{name}" ne peut pas dépasser {size} px.',
+        dropZoneTitle: 'Glissez et déposez les fichiers ici&hellip;'
+    };
 })(window.jQuery);
 })(window.jQuery);

+ 45 - 45
js/fileinput_locale_hu.js

@@ -1,45 +1,45 @@
-/*!
- * FileInput Hungarian Translations
- *
- * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or
- * any HTML markup tags in the messages must not be converted or translated.
- *
- * @see http://github.com/kartik-v/bootstrap-fileinput
- *
- * NOTE: this file must be saved in UTF-8 encoding.
- */
-(function ($) {
-    "use strict";
-
-    $.fn.fileinputLocales['hu'] = {
-        fileSingle: 'fájl',
-        filePlural: 'fájl',
-        browseLabel: 'Böngész &hellip;',
-        removeLabel: 'Eltávolít',
-        removeTitle: 'Kijelölt fájlok törlése',
-        cancelLabel: 'Mégse',
-        cancelTitle: 'Feltöltés megszakítása',
-        uploadLabel: 'Feltöltés',
-        uploadTitle: 'Kijelölt fájlok feltöltése',
-        msgSizeTooLarge: '"{name}" fájl (<b>{size} KB</b>) mérete nagyobb a megengedettnél <b>{maxSize} KB</b>. Kérjük próbálja újra!',
-        msgFilesTooLess: 'Legalább <b>{n}</b> {files} ki kell választania a feltöltéshez. Kérjük próbálja újra!',
-        msgFilesTooMany: 'A feltölteni kívánt fájlok száma <b>({n})</b> elérte a megengedett maximumot <b>{m}</b>. Kérjük próbálja újra!',
-        msgFileNotFound: '"{name}" fájl nem található!',
-        msgFileSecured: 'Biztonsági beállítások nem engedik olvasni a fájlt "{name}".',
-        msgFileNotReadable: '"{name}" fájl nem olvasható',
-        msgFilePreviewAborted: '"{name}" fájl feltöltése megszakítva.',
-        msgFilePreviewError: 'Hiba lépett fel a "{name}" fájl olvasása közben.',
-        msgInvalidFileType: 'Nem megengedett fájl "{name}". Csak a "{types}" fájl típusok támogatottak.',
-        msgInvalidFileExtension: 'Nem megengedett kiterjesztés / fájltípus "{name}". Csak a "{extensions}" kiterjesztés(ek) / fájltípus(ok) támogatottak.',
-        msgValidationError: 'Fájl ellenörzési hiba.',
-        msgLoading: '{index} / {files} töltése &hellip;',
-        msgProgress: 'Feltöltés: {index} / {files} - {name} - {percent}% kész.',
-        msgSelected: '{n} {files} kiválasztva.',
-        msgFoldersNotAllowed: 'Csak fájlokat húzzon ide! Kihagyva {n} könyvtár.',
-        msgImageWidthSmall: 'Szélessége image file "{name}" legalább {size} px.',
-        msgImageHeightSmall: 'Magassága image file "{name}" legalább {size} px.',
-        msgImageWidthLarge: 'Szélessége image file "{name}" nem haladhatja meg a {size} px.',
-        msgImageHeightLarge: 'Magassága image file "{name}" nem haladhatja meg a {size} px.',
-        dropZoneTitle: 'Fájlok húzása ide &hellip;'
-    };
-})(window.jQuery);
+/*!
+ * FileInput Hungarian Translations
+ *
+ * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or
+ * any HTML markup tags in the messages must not be converted or translated.
+ *
+ * @see http://github.com/kartik-v/bootstrap-fileinput
+ *
+ * NOTE: this file must be saved in UTF-8 encoding.
+ */
+(function ($) {
+    "use strict";
+
+    $.fn.fileinputLocales['hu'] = {
+        fileSingle: 'fájl',
+        filePlural: 'fájl',
+        browseLabel: 'Böngész &hellip;',
+        removeLabel: 'Eltávolít',
+        removeTitle: 'Kijelölt fájlok törlése',
+        cancelLabel: 'Mégse',
+        cancelTitle: 'Feltöltés megszakítása',
+        uploadLabel: 'Feltöltés',
+        uploadTitle: 'Kijelölt fájlok feltöltése',
+        msgSizeTooLarge: '"{name}" fájl (<b>{size} KB</b>) mérete nagyobb a megengedettnél <b>{maxSize} KB</b>. Kérjük próbálja újra!',
+        msgFilesTooLess: 'Legalább <b>{n}</b> {files} ki kell választania a feltöltéshez. Kérjük próbálja újra!',
+        msgFilesTooMany: 'A feltölteni kívánt fájlok száma <b>({n})</b> elérte a megengedett maximumot <b>{m}</b>. Kérjük próbálja újra!',
+        msgFileNotFound: '"{name}" fájl nem található!',
+        msgFileSecured: 'Biztonsági beállítások nem engedik olvasni a fájlt "{name}".',
+        msgFileNotReadable: '"{name}" fájl nem olvasható',
+        msgFilePreviewAborted: '"{name}" fájl feltöltése megszakítva.',
+        msgFilePreviewError: 'Hiba lépett fel a "{name}" fájl olvasása közben.',
+        msgInvalidFileType: 'Nem megengedett fájl "{name}". Csak a "{types}" fájl típusok támogatottak.',
+        msgInvalidFileExtension: 'Nem megengedett kiterjesztés / fájltípus "{name}". Csak a "{extensions}" kiterjesztés(ek) / fájltípus(ok) támogatottak.',
+        msgValidationError: 'Fájl ellenörzési hiba.',
+        msgLoading: '{index} / {files} töltése &hellip;',
+        msgProgress: 'Feltöltés: {index} / {files} - {name} - {percent}% kész.',
+        msgSelected: '{n} {files} kiválasztva.',
+        msgFoldersNotAllowed: 'Csak fájlokat húzzon ide! Kihagyva {n} könyvtár.',
+        msgImageWidthSmall: 'Szélessége image file "{name}" legalább {size} px.',
+        msgImageHeightSmall: 'Magassága image file "{name}" legalább {size} px.',
+        msgImageWidthLarge: 'Szélessége image file "{name}" nem haladhatja meg a {size} px.',
+        msgImageHeightLarge: 'Magassága image file "{name}" nem haladhatja meg a {size} px.',
+        dropZoneTitle: 'Fájlok húzása ide &hellip;'
+    };
+})(window.jQuery);

+ 46 - 46
js/fileinput_locale_it.js

@@ -1,47 +1,47 @@
-/*!
- * FileInput Italian Translation
- * 
- * Author: Lorenzo Milesi <[email protected]>
- *
- * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or
- * any HTML markup tags in the messages must not be converted or translated.
- *
- * @see http://github.com/kartik-v/bootstrap-fileinput
- *
- * NOTE: this file must be saved in UTF-8 encoding.
- */
-(function ($) {
-    "use strict";
-
-    $.fn.fileinputLocales['it'] = {
-        fileSingle: 'file',
-        filePlural: 'file',
-        browseLabel: 'Sfoglia&hellip;',
-        removeLabel: 'Rimuovi',
-        removeTitle: 'Rimuovi i file selezionati',
-        cancelLabel: 'Annulla',
-        cancelTitle: 'Annulla i caricamenti in corso',
-        uploadLabel: 'Carica',
-        uploadTitle: 'Carica i file selezionati',
-        msgSizeTooLarge: 'Il file "{name}" (<b>{size} KB</b>) eccede la dimensione massima di caricamento di <b>{maxSize} KB</b>. Per favore correggi il file e riprova!',
-        msgFilesTooLess: 'Devi selezionare almeno <b>{n}</b> {files} da caricare. Per favore correggi e riprova!',
-        msgFilesTooMany: 'Il numero di file selezionati per il caricamento <b>({n})</b> eccede il numero massimo di file accettati <b>{m}</b>. Per favore correggi e riprova!',
-        msgFileNotFound: 'File "{name}" non trovato!',
-        msgFileSecured: 'Restrizioni di sicurezza impediscono la lettura del file "{name}".',
-        msgFileNotReadable: 'Il file "{name}" non \xE8 leggibile.',
-        msgFilePreviewAborted: 'Generazione anteprima per "{name}" annullata.',
-        msgFilePreviewError: 'Errore durante la lettura del file "{name}".',
-        msgInvalidFileType: 'Tipo non valido per il file "{name}". Sono ammessi solo file di tipo "{types}".',
-        msgInvalidFileExtension: 'Estensione non valida per il file "{name}". Sono ammessi solo file con estensione "{extensions}".',
-        msgValidationError: 'Errore caricamento file',
-        msgLoading: 'Caricamento file {index} di {files}&hellip;',
-        msgProgress: 'Caricamento file {index} di {files} - {name} - {percent}% completato.',
-        msgSelected: '{n} {files} selezionati',
-        msgFoldersNotAllowed: 'Trascina solo file! Ignorata/e {n} cartella/e.',
-        msgImageWidthSmall: 'Larghezza di file immagine "{name}" deve essere di almeno {size} px.',
-        msgImageHeightSmall: 'Altezza di file immagine "{name}" deve essere di almeno {size} px.',
-        msgImageWidthLarge: 'Larghezza di file immagine "{name}" non può superare {size} px.',
-        msgImageHeightLarge: 'Altezza di file immagine "{name}" non può superare {size} px.',
-        dropZoneTitle: 'Trascina i file qui&hellip;'
-    };
+/*!
+ * FileInput Italian Translation
+ * 
+ * Author: Lorenzo Milesi <[email protected]>
+ *
+ * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or
+ * any HTML markup tags in the messages must not be converted or translated.
+ *
+ * @see http://github.com/kartik-v/bootstrap-fileinput
+ *
+ * NOTE: this file must be saved in UTF-8 encoding.
+ */
+(function ($) {
+    "use strict";
+
+    $.fn.fileinputLocales['it'] = {
+        fileSingle: 'file',
+        filePlural: 'file',
+        browseLabel: 'Sfoglia&hellip;',
+        removeLabel: 'Rimuovi',
+        removeTitle: 'Rimuovi i file selezionati',
+        cancelLabel: 'Annulla',
+        cancelTitle: 'Annulla i caricamenti in corso',
+        uploadLabel: 'Carica',
+        uploadTitle: 'Carica i file selezionati',
+        msgSizeTooLarge: 'Il file "{name}" (<b>{size} KB</b>) eccede la dimensione massima di caricamento di <b>{maxSize} KB</b>. Per favore correggi il file e riprova!',
+        msgFilesTooLess: 'Devi selezionare almeno <b>{n}</b> {files} da caricare. Per favore correggi e riprova!',
+        msgFilesTooMany: 'Il numero di file selezionati per il caricamento <b>({n})</b> eccede il numero massimo di file accettati <b>{m}</b>. Per favore correggi e riprova!',
+        msgFileNotFound: 'File "{name}" non trovato!',
+        msgFileSecured: 'Restrizioni di sicurezza impediscono la lettura del file "{name}".',
+        msgFileNotReadable: 'Il file "{name}" non \xE8 leggibile.',
+        msgFilePreviewAborted: 'Generazione anteprima per "{name}" annullata.',
+        msgFilePreviewError: 'Errore durante la lettura del file "{name}".',
+        msgInvalidFileType: 'Tipo non valido per il file "{name}". Sono ammessi solo file di tipo "{types}".',
+        msgInvalidFileExtension: 'Estensione non valida per il file "{name}". Sono ammessi solo file con estensione "{extensions}".',
+        msgValidationError: 'Errore caricamento file',
+        msgLoading: 'Caricamento file {index} di {files}&hellip;',
+        msgProgress: 'Caricamento file {index} di {files} - {name} - {percent}% completato.',
+        msgSelected: '{n} {files} selezionati',
+        msgFoldersNotAllowed: 'Trascina solo file! Ignorata/e {n} cartella/e.',
+        msgImageWidthSmall: 'Larghezza di file immagine "{name}" deve essere di almeno {size} px.',
+        msgImageHeightSmall: 'Altezza di file immagine "{name}" deve essere di almeno {size} px.',
+        msgImageWidthLarge: 'Larghezza di file immagine "{name}" non può superare {size} px.',
+        msgImageHeightLarge: 'Altezza di file immagine "{name}" non può superare {size} px.',
+        dropZoneTitle: 'Trascina i file qui&hellip;'
+    };
 })(window.jQuery);
 })(window.jQuery);

+ 45 - 45
js/fileinput_locale_nl.js

@@ -1,45 +1,45 @@
-/*!
- * FileInput Dutch Translations
- *
- * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or
- * any HTML markup tags in the messages must not be converted or translated.
- *
- * @see http://github.com/kartik-v/bootstrap-fileinput
- *
- * NOTE: this file must be saved in UTF-8 encoding.
- */
-(function ($) {
-    "use strict";
-
-    $.fn.fileinputLocales['nl'] = {
-        fileSingle: 'bestand',
-        filePlural: 'bestanden',
-        browseLabel: 'Zoek &hellip;',
-        removeLabel: 'Verwijder',
-        removeTitle: 'Verwijder geselecteerde bestanden',
-        cancelLabel: 'Annuleren',
-        cancelTitle: 'Annuleer gaande upload',
-        uploadLabel: 'Upload',
-        uploadTitle: 'Upload geselecteerde bestanden',
-        msgSizeTooLarge: 'Bestand "{name}" (<b>{size} KB</b>) is groter dan de toegestaande <b>{maxSize} KB</b>. Probeer opnieuw!',
-        msgFilesTooLess: 'U moet minstens <b>{n}</b> {files} selecteren om te uploaden. Probeer opnieuw!',
-        msgFilesTooMany: 'Aantal geselecteerde bestanden <b>({n})</b> is meer dan de toegestaande <b>{m}</b>. Probeer opnieuw!',
-        msgFileNotFound: 'Bestand "{name}" niet gevonden!',
-        msgFileSecured: 'Bestand kan niet gelezen worden in verband met beveiligings redenen "{name}".',
-        msgFileNotReadable: 'Bestand "{name}" is niet leesbaar.',
-        msgFilePreviewAborted: 'Bestand weergaven geannuleerd voor "{name}".',
-        msgFilePreviewError: 'Er is een fout opgetreden met lezen van "{name}".',
-        msgInvalidFileType: 'Geen geldig bestand "{name}". Alleen "{types}" zijn toegestaan.',
-        msgInvalidFileExtension: 'Geen geldige extensie "{name}". Alleen "{extensions}" zijn toegestaan.',
-        msgValidationError: 'Bestand upload fout',
-        msgLoading: 'Bestanden laden {index} van de {files} &hellip;',
-        msgProgress: 'Bestanden laden {index} van de {files} - {name} - {percent}% compleet.',
-        msgSelected: '{n} {files} geselecteerd',
-        msgFoldersNotAllowed: 'Drag & drop bestanden alleen! overgeslagen {n} mappen(s).',
-        msgImageWidthSmall: 'Breedte van de image-bestand "{name}" moet minstens {size} px zijn.',
-        msgImageHeightSmall: 'Hoogte van de beeld bestand "{name}" moet minstens {size} px zijn.',
-        msgImageWidthLarge: 'Breedte van de image-bestand "{name}" kan niet hoger zijn dan {size} px.',
-        msgImageHeightLarge: 'Hoogte van het beeld bestand "{name}" kan niet hoger zijn dan {size} px.',
-        dropZoneTitle: 'Drag & drop bestanden hier &hellip;'
-    };
-})(window.jQuery);
+/*!
+ * FileInput Dutch Translations
+ *
+ * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or
+ * any HTML markup tags in the messages must not be converted or translated.
+ *
+ * @see http://github.com/kartik-v/bootstrap-fileinput
+ *
+ * NOTE: this file must be saved in UTF-8 encoding.
+ */
+(function ($) {
+    "use strict";
+
+    $.fn.fileinputLocales['nl'] = {
+        fileSingle: 'bestand',
+        filePlural: 'bestanden',
+        browseLabel: 'Zoek &hellip;',
+        removeLabel: 'Verwijder',
+        removeTitle: 'Verwijder geselecteerde bestanden',
+        cancelLabel: 'Annuleren',
+        cancelTitle: 'Annuleer gaande upload',
+        uploadLabel: 'Upload',
+        uploadTitle: 'Upload geselecteerde bestanden',
+        msgSizeTooLarge: 'Bestand "{name}" (<b>{size} KB</b>) is groter dan de toegestaande <b>{maxSize} KB</b>. Probeer opnieuw!',
+        msgFilesTooLess: 'U moet minstens <b>{n}</b> {files} selecteren om te uploaden. Probeer opnieuw!',
+        msgFilesTooMany: 'Aantal geselecteerde bestanden <b>({n})</b> is meer dan de toegestaande <b>{m}</b>. Probeer opnieuw!',
+        msgFileNotFound: 'Bestand "{name}" niet gevonden!',
+        msgFileSecured: 'Bestand kan niet gelezen worden in verband met beveiligings redenen "{name}".',
+        msgFileNotReadable: 'Bestand "{name}" is niet leesbaar.',
+        msgFilePreviewAborted: 'Bestand weergaven geannuleerd voor "{name}".',
+        msgFilePreviewError: 'Er is een fout opgetreden met lezen van "{name}".',
+        msgInvalidFileType: 'Geen geldig bestand "{name}". Alleen "{types}" zijn toegestaan.',
+        msgInvalidFileExtension: 'Geen geldige extensie "{name}". Alleen "{extensions}" zijn toegestaan.',
+        msgValidationError: 'Bestand upload fout',
+        msgLoading: 'Bestanden laden {index} van de {files} &hellip;',
+        msgProgress: 'Bestanden laden {index} van de {files} - {name} - {percent}% compleet.',
+        msgSelected: '{n} {files} geselecteerd',
+        msgFoldersNotAllowed: 'Drag & drop bestanden alleen! overgeslagen {n} mappen(s).',
+        msgImageWidthSmall: 'Breedte van de image-bestand "{name}" moet minstens {size} px zijn.',
+        msgImageHeightSmall: 'Hoogte van de beeld bestand "{name}" moet minstens {size} px zijn.',
+        msgImageWidthLarge: 'Breedte van de image-bestand "{name}" kan niet hoger zijn dan {size} px.',
+        msgImageHeightLarge: 'Hoogte van het beeld bestand "{name}" kan niet hoger zijn dan {size} px.',
+        dropZoneTitle: 'Drag & drop bestanden hier &hellip;'
+    };
+})(window.jQuery);

+ 44 - 44
js/fileinput_locale_pl.js

@@ -1,45 +1,45 @@
-/*!
- * FileInput Polish Translations
- *
- * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or
- * any HTML markup tags in the messages must not be converted or translated.
- *
- * @see http://github.com/kartik-v/bootstrap-fileinput
- *
- * NOTE: this file must be saved in UTF-8 encoding.
- */
-(function ($) {
-    "use strict";
-
-    $.fn.fileinputLocales['pl'] = {
-        fileSingle: 'plik',
-        filePlural: 'pliki',
-        browseLabel: 'Przeglądaj &hellip;',
-        removeLabel: 'Usuń',
-        removeTitle: 'Usuń zaznaczone pliki',
-        cancelLabel: 'Przerwij',
-        cancelTitle: 'Anuluj wysyłanie',
-        uploadLabel: 'Wgraj',
-        uploadTitle: 'Wgraj zaznaczone pliki',
-        msgSizeTooLarge: 'Plik o nazwie "{name}" (<b>{size} KB</b>) przekroczył maksymalną dopuszczalną wielkość pliku wynoszącą <b>{maxSize} KB</b>. Proszę ponowić próbę wysłania pliku!',
-        msgFilesTooLess: 'Musisz wybrać przynajmniej <b>{n}</b> {files} do wgrania. Proszę spróbować jeszcze raz wgrać pliki!',
-        msgFilesTooMany: 'Liczba plików wybranych do wgrania w liczbie <b>({n})</b>, przekracza maksymalny dozwolony limit wynoszący <b>{m}</b>. Proszę spróbować ponownie!',
-        msgFileNotFound: 'Plik "{name}" nie istnieje!',
-        msgFileSecured: 'Ustawienia zabezpieczeń uniemożliwiają odczyt pliku "{name}".',
-        msgFileNotReadable: 'Plik "{name}" nie jest plikiem do odczytu.',
-        msgFilePreviewAborted: 'Podgląd pliku "{name}" został przerwany.',
-        msgFilePreviewError: 'Wystąpił błąd w czasie odczytu pliku "{name}".',
-        msgInvalidFileType: 'Nieznny typ pliku "{name}". Tylko następujące rodzaje plików "{types}", są obsługiwane.',
-        msgInvalidFileExtension: 'Złe rozszerzenie dla pliku "{name}". Tylko następujące rozszerzenia plików "{extensions}", są obsługiwane.',
-        msgValidationError: 'Błąd podczas przesyłania pliku.',
-        msgLoading: 'Wczytywanie pliku {index} z {files} &hellip;',
-        msgProgress: 'Wczytywanie pliku {index} z {files} - {name} - {percent}% zakończone.',
-        msgSelected: '{n} {files} zaznaczonych',
-        msgFoldersNotAllowed: 'Metodą przeciągnij i upuść, można przenosić tylko pliki. Pominięto {n} katalogów.',
-        msgImageWidthSmall: 'Szerokość pliku obrazu "{name}" musi być co najmniej {size} px.',
-        msgImageHeightSmall: 'Wysokość pliku obrazu "{name}" musi być co najmniej {size} px.',
-        msgImageWidthLarge: 'Szerokość pliku obrazu "{name}" nie może przekraczać {size} px.',
-        msgImageHeightLarge: 'Wysokość pliku obrazu "{name}" nie może przekraczać {size} px.',
-        dropZoneTitle: 'Przeciągnij i upuść pliki tu &hellip;'
-    };
+/*!
+ * FileInput Polish Translations
+ *
+ * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or
+ * any HTML markup tags in the messages must not be converted or translated.
+ *
+ * @see http://github.com/kartik-v/bootstrap-fileinput
+ *
+ * NOTE: this file must be saved in UTF-8 encoding.
+ */
+(function ($) {
+    "use strict";
+
+    $.fn.fileinputLocales['pl'] = {
+        fileSingle: 'plik',
+        filePlural: 'pliki',
+        browseLabel: 'Przeglądaj &hellip;',
+        removeLabel: 'Usuń',
+        removeTitle: 'Usuń zaznaczone pliki',
+        cancelLabel: 'Przerwij',
+        cancelTitle: 'Anuluj wysyłanie',
+        uploadLabel: 'Wgraj',
+        uploadTitle: 'Wgraj zaznaczone pliki',
+        msgSizeTooLarge: 'Plik o nazwie "{name}" (<b>{size} KB</b>) przekroczył maksymalną dopuszczalną wielkość pliku wynoszącą <b>{maxSize} KB</b>. Proszę ponowić próbę wysłania pliku!',
+        msgFilesTooLess: 'Musisz wybrać przynajmniej <b>{n}</b> {files} do wgrania. Proszę spróbować jeszcze raz wgrać pliki!',
+        msgFilesTooMany: 'Liczba plików wybranych do wgrania w liczbie <b>({n})</b>, przekracza maksymalny dozwolony limit wynoszący <b>{m}</b>. Proszę spróbować ponownie!',
+        msgFileNotFound: 'Plik "{name}" nie istnieje!',
+        msgFileSecured: 'Ustawienia zabezpieczeń uniemożliwiają odczyt pliku "{name}".',
+        msgFileNotReadable: 'Plik "{name}" nie jest plikiem do odczytu.',
+        msgFilePreviewAborted: 'Podgląd pliku "{name}" został przerwany.',
+        msgFilePreviewError: 'Wystąpił błąd w czasie odczytu pliku "{name}".',
+        msgInvalidFileType: 'Nieznny typ pliku "{name}". Tylko następujące rodzaje plików "{types}", są obsługiwane.',
+        msgInvalidFileExtension: 'Złe rozszerzenie dla pliku "{name}". Tylko następujące rozszerzenia plików "{extensions}", są obsługiwane.',
+        msgValidationError: 'Błąd podczas przesyłania pliku.',
+        msgLoading: 'Wczytywanie pliku {index} z {files} &hellip;',
+        msgProgress: 'Wczytywanie pliku {index} z {files} - {name} - {percent}% zakończone.',
+        msgSelected: '{n} {files} zaznaczonych',
+        msgFoldersNotAllowed: 'Metodą przeciągnij i upuść, można przenosić tylko pliki. Pominięto {n} katalogów.',
+        msgImageWidthSmall: 'Szerokość pliku obrazu "{name}" musi być co najmniej {size} px.',
+        msgImageHeightSmall: 'Wysokość pliku obrazu "{name}" musi być co najmniej {size} px.',
+        msgImageWidthLarge: 'Szerokość pliku obrazu "{name}" nie może przekraczać {size} px.',
+        msgImageHeightLarge: 'Wysokość pliku obrazu "{name}" nie może przekraczać {size} px.',
+        dropZoneTitle: 'Przeciągnij i upuść pliki tu &hellip;'
+    };
 })(window.jQuery);
 })(window.jQuery);

+ 44 - 44
js/fileinput_locale_pt-BR.js

@@ -1,45 +1,45 @@
-/*!
- * FileInput Brazillian Portuguese Translations
- *
- * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or
- * any HTML markup tags in the messages must not be converted or translated.
- *
- * @see http://github.com/kartik-v/bootstrap-fileinput
- *
- * NOTE: this file must be saved in UTF-8 encoding.
- */
-(function ($) {
-    "use strict";
-
-    $.fn.fileinputLocales['pt-BR'] = {
-        fileSingle: 'arquivo',
-        filePlural: 'arquivos',
-        browseLabel: 'Procurar&hellip;',
-        removeLabel: 'Remover',
-        removeTitle: 'Remover arquivos selecionados',
-        cancelLabel: 'Cancelar',
-        cancelTitle: 'Interromper envio em andamento',
-        uploadLabel: 'Enviar',
-        uploadTitle: 'Enviar arquivos selecionados',
-        msgSizeTooLarge: 'O arquivo "{name}" (<b>{size} KB</b>) excede o tamanho máximo permitido de <b>{maxSize} KB</b>. Por favor, tente enviar novamente!',
-        msgFilesTooLess: 'Você deve selecionar pelo menos <b>{n}</b> {files} para enviar. Por favor, tente enviar novamente!',
-        msgFilesTooMany: 'O número de arquivos selecionados para o envio <b>({n})</b> excede o limite máximo permitido de <b>{m}</b>. Por favor, tente enviar novamente!',
-        msgFileNotFound: 'O arquivo "{name}" não foi encontrado!',
-        msgFileSecured: 'Restrições de segurança impedem a leitura do arquivo "{name}".',
-        msgFileNotReadable: 'O arquivo "{name}" não pode ser lido.',
-        msgFilePreviewAborted: 'A pré-visualização do arquivo "{name}" foi interrompida.',
-        msgFilePreviewError: 'Ocorreu um erro ao ler o arquivo "{name}".',
-        msgInvalidFileType: 'Tipo inválido para o arquivo "{name}". Apenas arquivos "{types}" são permitidos.',
-        msgInvalidFileExtension: 'Extensão inválida para o arquivo "{name}". Apenas arquivos "{extensions}" são permitidos.',
-        msgValidationError: 'Erro de envio de arquivo',
-        msgLoading: 'Enviando arquivo {index} de {files}&hellip;',
-        msgProgress: 'Enviando arquivo {index} de {files} - {name} - {percent}% completo.',
-        msgSelected: '{n} {files} selecionado(s)',
-        msgFoldersNotAllowed: 'Arraste e solte apenas arquivos! {n} soltar pasta(s) ignoradas.',
-        msgImageWidthSmall: 'Largura do arquivo de imagem "{name}" deve ser pelo menos {size} px.',
-        msgImageHeightSmall: 'Altura do arquivo de imagem "{name}" deve ser pelo menos {size} px.',
-        msgImageWidthLarge: 'Largura do arquivo de imagem "{name}" não pode exceder {size} px.',
-        msgImageHeightLarge: 'Altura do arquivo de imagem "{name}" não pode exceder {size} px.',
-        dropZoneTitle: 'Arraste e solte os arquivos aqui&hellip;'
-    };
+/*!
+ * FileInput Brazillian Portuguese Translations
+ *
+ * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or
+ * any HTML markup tags in the messages must not be converted or translated.
+ *
+ * @see http://github.com/kartik-v/bootstrap-fileinput
+ *
+ * NOTE: this file must be saved in UTF-8 encoding.
+ */
+(function ($) {
+    "use strict";
+
+    $.fn.fileinputLocales['pt-BR'] = {
+        fileSingle: 'arquivo',
+        filePlural: 'arquivos',
+        browseLabel: 'Procurar&hellip;',
+        removeLabel: 'Remover',
+        removeTitle: 'Remover arquivos selecionados',
+        cancelLabel: 'Cancelar',
+        cancelTitle: 'Interromper envio em andamento',
+        uploadLabel: 'Enviar',
+        uploadTitle: 'Enviar arquivos selecionados',
+        msgSizeTooLarge: 'O arquivo "{name}" (<b>{size} KB</b>) excede o tamanho máximo permitido de <b>{maxSize} KB</b>. Por favor, tente enviar novamente!',
+        msgFilesTooLess: 'Você deve selecionar pelo menos <b>{n}</b> {files} para enviar. Por favor, tente enviar novamente!',
+        msgFilesTooMany: 'O número de arquivos selecionados para o envio <b>({n})</b> excede o limite máximo permitido de <b>{m}</b>. Por favor, tente enviar novamente!',
+        msgFileNotFound: 'O arquivo "{name}" não foi encontrado!',
+        msgFileSecured: 'Restrições de segurança impedem a leitura do arquivo "{name}".',
+        msgFileNotReadable: 'O arquivo "{name}" não pode ser lido.',
+        msgFilePreviewAborted: 'A pré-visualização do arquivo "{name}" foi interrompida.',
+        msgFilePreviewError: 'Ocorreu um erro ao ler o arquivo "{name}".',
+        msgInvalidFileType: 'Tipo inválido para o arquivo "{name}". Apenas arquivos "{types}" são permitidos.',
+        msgInvalidFileExtension: 'Extensão inválida para o arquivo "{name}". Apenas arquivos "{extensions}" são permitidos.',
+        msgValidationError: 'Erro de envio de arquivo',
+        msgLoading: 'Enviando arquivo {index} de {files}&hellip;',
+        msgProgress: 'Enviando arquivo {index} de {files} - {name} - {percent}% completo.',
+        msgSelected: '{n} {files} selecionado(s)',
+        msgFoldersNotAllowed: 'Arraste e solte apenas arquivos! {n} soltar pasta(s) ignoradas.',
+        msgImageWidthSmall: 'Largura do arquivo de imagem "{name}" deve ser pelo menos {size} px.',
+        msgImageHeightSmall: 'Altura do arquivo de imagem "{name}" deve ser pelo menos {size} px.',
+        msgImageWidthLarge: 'Largura do arquivo de imagem "{name}" não pode exceder {size} px.',
+        msgImageHeightLarge: 'Altura do arquivo de imagem "{name}" não pode exceder {size} px.',
+        dropZoneTitle: 'Arraste e solte os arquivos aqui&hellip;'
+    };
 })(window.jQuery);
 })(window.jQuery);

+ 44 - 44
js/fileinput_locale_pt.js

@@ -1,45 +1,45 @@
-/*!
- * FileInput Portuguese Translations
- *
- * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or
- * any HTML markup tags in the messages must not be converted or translated.
- *
- * @see http://github.com/kartik-v/bootstrap-fileinput
- *
- * NOTE: this file must be saved in UTF-8 encoding.
- */
-(function ($) {
-    "use strict";
-
-    $.fn.fileinputLocales['pt'] = {
-        fileSingle: 'ficheiro',
-        filePlural: 'ficheiros',
-        browseLabel: 'Procurar &hellip;',
-        removeLabel: 'Remover',
-        removeTitle: 'Remover ficheiros seleccionados',
-        cancelLabel: 'Cancelar',
-        cancelTitle: 'Abortar carregamento ',
-        uploadLabel: 'Carregar',
-        uploadTitle: 'Carregar ficheiros seleccionados',
-        msgSizeTooLarge: 'Ficheiro "{name}" (<b>{size} KB</b>) excede o tamanho máximo permido de <b>{maxSize} KB</b>. Por favor carregue de novo!',
-        msgFilesTooLess: 'Deve seleccionar pelo menos <b>{n}</b> {files} para fazer upload. Por favor carregue de novo!',
-        msgFilesTooMany: 'Número máximo de ficheiros seleccionados <b>({n})</b> excede o limite máximo de <b>{m}</b>. Por favor carregue de novo!',
-        msgFileNotFound: 'Ficheiro "{name}" não encontrado!',
-        msgFileSecured: 'Restrições de segurança preventem a leitura do ficheiro "{name}".',
-        msgFileNotReadable: 'Ficheiro "{name}" não pode ser lido.',
-        msgFilePreviewAborted: 'Pré-visualização abortado para o ficheiro "{name}".',
-        msgFilePreviewError: 'Ocorreu um erro ao ler o ficheiro "{name}".',
-        msgInvalidFileType: 'Tipo inválido para o ficheiro "{name}". Apenas ficheiros "{types}" são suportados.',
-        msgInvalidFileExtension: 'Extensão inválida para o ficheiro "{name}". Apenas ficheiros "{extensions}" são suportados.',
-        msgValidationError: 'Erro de carregamento de ficheiro',
-        msgLoading: 'A carregar ficheiro {index} de {files} &hellip;',
-        msgProgress: 'A carregar ficheiro {index} de {files} - {name} - {percent}% completo.',
-        msgSelected: '{n} {files} seleccionados',
-        msgFoldersNotAllowed: 'Arrastar e largar ficheiros apenas! {n} pasta(s) ignoradas.',
-        msgImageWidthSmall: 'Largura do arquivo de imagem "{name}" deve ser pelo menos {size} px.',
-        msgImageHeightSmall: 'Altura do arquivo de imagem "{name}" deve ser pelo menos {size} px.',
-        msgImageWidthLarge: 'Largura do arquivo de imagem "{name}" não pode exceder {size} px.',
-        msgImageHeightLarge: 'Altura do arquivo de imagem "{name}" não pode exceder {size} px.',
-        dropZoneTitle: 'Arrastar e largar ficheiros aqui &hellip;'
-    };
+/*!
+ * FileInput Portuguese Translations
+ *
+ * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or
+ * any HTML markup tags in the messages must not be converted or translated.
+ *
+ * @see http://github.com/kartik-v/bootstrap-fileinput
+ *
+ * NOTE: this file must be saved in UTF-8 encoding.
+ */
+(function ($) {
+    "use strict";
+
+    $.fn.fileinputLocales['pt'] = {
+        fileSingle: 'ficheiro',
+        filePlural: 'ficheiros',
+        browseLabel: 'Procurar &hellip;',
+        removeLabel: 'Remover',
+        removeTitle: 'Remover ficheiros seleccionados',
+        cancelLabel: 'Cancelar',
+        cancelTitle: 'Abortar carregamento ',
+        uploadLabel: 'Carregar',
+        uploadTitle: 'Carregar ficheiros seleccionados',
+        msgSizeTooLarge: 'Ficheiro "{name}" (<b>{size} KB</b>) excede o tamanho máximo permido de <b>{maxSize} KB</b>. Por favor carregue de novo!',
+        msgFilesTooLess: 'Deve seleccionar pelo menos <b>{n}</b> {files} para fazer upload. Por favor carregue de novo!',
+        msgFilesTooMany: 'Número máximo de ficheiros seleccionados <b>({n})</b> excede o limite máximo de <b>{m}</b>. Por favor carregue de novo!',
+        msgFileNotFound: 'Ficheiro "{name}" não encontrado!',
+        msgFileSecured: 'Restrições de segurança preventem a leitura do ficheiro "{name}".',
+        msgFileNotReadable: 'Ficheiro "{name}" não pode ser lido.',
+        msgFilePreviewAborted: 'Pré-visualização abortado para o ficheiro "{name}".',
+        msgFilePreviewError: 'Ocorreu um erro ao ler o ficheiro "{name}".',
+        msgInvalidFileType: 'Tipo inválido para o ficheiro "{name}". Apenas ficheiros "{types}" são suportados.',
+        msgInvalidFileExtension: 'Extensão inválida para o ficheiro "{name}". Apenas ficheiros "{extensions}" são suportados.',
+        msgValidationError: 'Erro de carregamento de ficheiro',
+        msgLoading: 'A carregar ficheiro {index} de {files} &hellip;',
+        msgProgress: 'A carregar ficheiro {index} de {files} - {name} - {percent}% completo.',
+        msgSelected: '{n} {files} seleccionados',
+        msgFoldersNotAllowed: 'Arrastar e largar ficheiros apenas! {n} pasta(s) ignoradas.',
+        msgImageWidthSmall: 'Largura do arquivo de imagem "{name}" deve ser pelo menos {size} px.',
+        msgImageHeightSmall: 'Altura do arquivo de imagem "{name}" deve ser pelo menos {size} px.',
+        msgImageWidthLarge: 'Largura do arquivo de imagem "{name}" não pode exceder {size} px.',
+        msgImageHeightLarge: 'Altura do arquivo de imagem "{name}" não pode exceder {size} px.',
+        dropZoneTitle: 'Arrastar e largar ficheiros aqui &hellip;'
+    };
 })(window.jQuery);
 })(window.jQuery);

+ 46 - 46
js/fileinput_locale_ro.js

@@ -1,46 +1,46 @@
-/*!
- * FileInput Romanian Translations
- *
- * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or
- * any HTML markup tags in the messages must not be converted or translated.
- *
- * @see http://github.com/kartik-v/bootstrap-fileinput
- * @author Ciprian Voicu <[email protected]>
- *
- * NOTE: this file must be saved in UTF-8 encoding.
- */
-(function ($) {
-    "use strict";
-
-    $.fn.fileinputLocales['ro'] = {
-        fileSingle: 'fișier',
-        filePlural: 'fișiere',
-        browseLabel: 'Răsfoiește &hellip;',
-        removeLabel: 'Șterge',
-        removeTitle: 'Curăță fișierele selectate',
-        cancelLabel: 'Renunță',
-        cancelTitle: 'Anulează încărcarea curentă',
-        uploadLabel: 'Încarcă',
-        uploadTitle: 'Încarcă fișierele selectate',
-        msgSizeTooLarge: 'Fișierul "{name}" (<b>{size} KB</b>) depășește limita maximă de încărcare de <b>{maxSize} KB</b>. Te rugăm reîncearcă!',
-        msgFilesTooLess: 'Trebuie să selectezi cel puțin <b>{n}</b> {files} pentru a încărca. Te rugăm reîncearcă!',
-        msgFilesTooMany: 'Numărul fișierelor pentru încărcare <b>({n})</b> depășește limita maximă de <b>{m}</b>. Te rugăm reîncearcă!',
-        msgFileNotFound: 'Fișierul "{name}" nu a fost găsit!',
-        msgFileSecured: 'Restricții de securitate previn citirea fișierului "{name}".',
-        msgFileNotReadable: 'Fișierul "{name}" nu se poate citi.',
-        msgFilePreviewAborted: 'Fișierului "{name}" nu poate fi previzualizat.',
-        msgFilePreviewError: 'A intervenit o eroare în încercarea de citire a fișierului "{name}".',
-        msgInvalidFileType: 'Tip de fișier incorect pentru "{name}". Sunt suportate doar fișiere de tipurile "{types}".',
-        msgInvalidFileExtension: 'Extensie incorectă pentru "{name}". Sunt suportate doar extensiile "{extensions}".',
-        msgValidationError: 'Eroare de încărcare',
-        msgLoading: 'Se încarcă fișierul {index} din {files} &hellip;',
-        msgProgress: 'Se încarcă fișierul {index} din {files} - {name} - {percent}% încărcat.',
-        msgSelected: '{n} {files} încărcate',
-        msgFoldersNotAllowed: 'Se poate doar trăgând fișierele! Se renunță la {n} dosar(e).',
-        msgImageWidthSmall: 'Lățimea de fișier de imagine "{name}" trebuie să fie de cel puțin {size px.',
-        msgImageHeightSmall: 'Înălțimea fișier imagine "{name}" trebuie să fie de cel puțin {size} px.',
-        msgImageWidthLarge: 'Lățimea de fișier de imagine "{name}" nu poate depăși {size} px.',
-        msgImageHeightLarge: 'Înălțimea fișier imagine "{name}" nu poate depăși {size} px.',
-        dropZoneTitle: 'Trage fișierele aici &hellip;'
-    };
-})(window.jQuery);
+/*!
+ * FileInput Romanian Translations
+ *
+ * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or
+ * any HTML markup tags in the messages must not be converted or translated.
+ *
+ * @see http://github.com/kartik-v/bootstrap-fileinput
+ * @author Ciprian Voicu <[email protected]>
+ *
+ * NOTE: this file must be saved in UTF-8 encoding.
+ */
+(function ($) {
+    "use strict";
+
+    $.fn.fileinputLocales['ro'] = {
+        fileSingle: 'fișier',
+        filePlural: 'fișiere',
+        browseLabel: 'Răsfoiește &hellip;',
+        removeLabel: 'Șterge',
+        removeTitle: 'Curăță fișierele selectate',
+        cancelLabel: 'Renunță',
+        cancelTitle: 'Anulează încărcarea curentă',
+        uploadLabel: 'Încarcă',
+        uploadTitle: 'Încarcă fișierele selectate',
+        msgSizeTooLarge: 'Fișierul "{name}" (<b>{size} KB</b>) depășește limita maximă de încărcare de <b>{maxSize} KB</b>. Te rugăm reîncearcă!',
+        msgFilesTooLess: 'Trebuie să selectezi cel puțin <b>{n}</b> {files} pentru a încărca. Te rugăm reîncearcă!',
+        msgFilesTooMany: 'Numărul fișierelor pentru încărcare <b>({n})</b> depășește limita maximă de <b>{m}</b>. Te rugăm reîncearcă!',
+        msgFileNotFound: 'Fișierul "{name}" nu a fost găsit!',
+        msgFileSecured: 'Restricții de securitate previn citirea fișierului "{name}".',
+        msgFileNotReadable: 'Fișierul "{name}" nu se poate citi.',
+        msgFilePreviewAborted: 'Fișierului "{name}" nu poate fi previzualizat.',
+        msgFilePreviewError: 'A intervenit o eroare în încercarea de citire a fișierului "{name}".',
+        msgInvalidFileType: 'Tip de fișier incorect pentru "{name}". Sunt suportate doar fișiere de tipurile "{types}".',
+        msgInvalidFileExtension: 'Extensie incorectă pentru "{name}". Sunt suportate doar extensiile "{extensions}".',
+        msgValidationError: 'Eroare de încărcare',
+        msgLoading: 'Se încarcă fișierul {index} din {files} &hellip;',
+        msgProgress: 'Se încarcă fișierul {index} din {files} - {name} - {percent}% încărcat.',
+        msgSelected: '{n} {files} încărcate',
+        msgFoldersNotAllowed: 'Se poate doar trăgând fișierele! Se renunță la {n} dosar(e).',
+        msgImageWidthSmall: 'Lățimea de fișier de imagine "{name}" trebuie să fie de cel puțin {size px.',
+        msgImageHeightSmall: 'Înălțimea fișier imagine "{name}" trebuie să fie de cel puțin {size} px.',
+        msgImageWidthLarge: 'Lățimea de fișier de imagine "{name}" nu poate depăși {size} px.',
+        msgImageHeightLarge: 'Înălțimea fișier imagine "{name}" nu poate depăși {size} px.',
+        dropZoneTitle: 'Trage fișierele aici &hellip;'
+    };
+})(window.jQuery);

+ 46 - 46
js/fileinput_locale_ru.js

@@ -1,46 +1,46 @@
-/*!
- * FileInput Russian Translations
- *
- * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or
- * any HTML markup tags in the messages must not be converted or translated.
- *
- * @see http://github.com/kartik-v/bootstrap-fileinput
- * @author CyanoFresh <[email protected]>
- *
- * NOTE: this file must be saved in UTF-8 encoding.
- */
-(function ($) {
-    "use strict";
-
-    $.fn.fileinputLocales['ru'] = {
-        fileSingle: 'файл',
-        filePlural: 'файлы',
-        browseLabel: 'Выбрать &hellip;',
-        removeLabel: 'Удалить',
-        removeTitle: 'Очистить выбранные файлы',
-        cancelLabel: 'Отмена',
-        cancelTitle: 'Отменить текущую загрузку',
-        uploadLabel: 'Загрузить',
-        uploadTitle: 'Загрузить выбранные файлы',
-        msgSizeTooLarge: 'Файл "{name}" (<b>{size} KB</b>) превышает максимальный размер <b>{maxSize} KB</b>',
-        msgFilesTooLess: 'Вы должны выбрать как минимум <b>{n}</b> {files} для загрузки',
-        msgFilesTooMany: 'Количество выбранных файлов <b>({n})</b> превышает максимально допустимое количество <b>{m}</b>',
-        msgFileNotFound: 'Файл "{name}" не найден!',
-        msgFileSecured: 'Ограничения безопасности запрещают читать файл "{name}".',
-        msgFileNotReadable: 'Файл "{name}" невозможно прочитать.',
-        msgFilePreviewAborted: 'Предпросмотр отменен для файла "{name}".',
-        msgFilePreviewError: 'Произошла ошибка при чтении файла "{name}".',
-        msgInvalidFileType: 'Запрещенный тип файла для "{name}". Только "{types}" разрешены.',
-        msgInvalidFileExtension: 'Запрещенное расширение для файла "{name}". Только "{extensions}" разрешены.',
-        msgValidationError: 'Ошибка при загрузке файла',
-        msgLoading: 'Загрузка файла {index} из {files} &hellip;',
-        msgProgress: 'Загрузка файла {index} из {files} - {name} - {percent}% завершено.',
-        msgSelected: 'Выбрано файлов: {n}',
-        msgFoldersNotAllowed: 'Разрешено перетаскивание только файлов! Пропущено {n} папок.',
-        msgImageWidthSmall: 'Ширина изображения {name} должна быть не меньше {size} px.',
-        msgImageHeightSmall: 'Высота изображения {name} должна быть не меньше {size} px.',
-        msgImageWidthLarge: 'Ширина изображения "{name}" не может превышать {size} px.',
-        msgImageHeightLarge: 'Высота изображения "{name}" не может превышать {size} px.',
-        dropZoneTitle: 'Перетащите файлы сюда &hellip;'
-    };
-})(window.jQuery);
+/*!
+ * FileInput Russian Translations
+ *
+ * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or
+ * any HTML markup tags in the messages must not be converted or translated.
+ *
+ * @see http://github.com/kartik-v/bootstrap-fileinput
+ * @author CyanoFresh <[email protected]>
+ *
+ * NOTE: this file must be saved in UTF-8 encoding.
+ */
+(function ($) {
+    "use strict";
+
+    $.fn.fileinputLocales['ru'] = {
+        fileSingle: 'файл',
+        filePlural: 'файлы',
+        browseLabel: 'Выбрать &hellip;',
+        removeLabel: 'Удалить',
+        removeTitle: 'Очистить выбранные файлы',
+        cancelLabel: 'Отмена',
+        cancelTitle: 'Отменить текущую загрузку',
+        uploadLabel: 'Загрузить',
+        uploadTitle: 'Загрузить выбранные файлы',
+        msgSizeTooLarge: 'Файл "{name}" (<b>{size} KB</b>) превышает максимальный размер <b>{maxSize} KB</b>',
+        msgFilesTooLess: 'Вы должны выбрать как минимум <b>{n}</b> {files} для загрузки',
+        msgFilesTooMany: 'Количество выбранных файлов <b>({n})</b> превышает максимально допустимое количество <b>{m}</b>',
+        msgFileNotFound: 'Файл "{name}" не найден!',
+        msgFileSecured: 'Ограничения безопасности запрещают читать файл "{name}".',
+        msgFileNotReadable: 'Файл "{name}" невозможно прочитать.',
+        msgFilePreviewAborted: 'Предпросмотр отменен для файла "{name}".',
+        msgFilePreviewError: 'Произошла ошибка при чтении файла "{name}".',
+        msgInvalidFileType: 'Запрещенный тип файла для "{name}". Только "{types}" разрешены.',
+        msgInvalidFileExtension: 'Запрещенное расширение для файла "{name}". Только "{extensions}" разрешены.',
+        msgValidationError: 'Ошибка при загрузке файла',
+        msgLoading: 'Загрузка файла {index} из {files} &hellip;',
+        msgProgress: 'Загрузка файла {index} из {files} - {name} - {percent}% завершено.',
+        msgSelected: 'Выбрано файлов: {n}',
+        msgFoldersNotAllowed: 'Разрешено перетаскивание только файлов! Пропущено {n} папок.',
+        msgImageWidthSmall: 'Ширина изображения {name} должна быть не меньше {size} px.',
+        msgImageHeightSmall: 'Высота изображения {name} должна быть не меньше {size} px.',
+        msgImageWidthLarge: 'Ширина изображения "{name}" не может превышать {size} px.',
+        msgImageHeightLarge: 'Высота изображения "{name}" не может превышать {size} px.',
+        dropZoneTitle: 'Перетащите файлы сюда &hellip;'
+    };
+})(window.jQuery);

+ 44 - 44
js/fileinput_locale_sk.js

@@ -1,45 +1,45 @@
-/*!
- * FileInput Slovakian Translations
- *
- * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or
- * any HTML markup tags in the messages must not be converted or translated.
- *
- * @see http://github.com/kartik-v/bootstrap-fileinput
- *
- * NOTE: this file must be saved in UTF-8 encoding.
- */
-(function ($) {
-    "use strict";
-
-    $.fn.fileinputLocales['sk'] = {
-        fileSingle: 'súbor',
-        filePlural: 'súbory',
-        browseLabel: 'Vybrať &hellip;',
-        removeLabel: 'Odstrániť',
-        removeTitle: 'Vyčistiť vybraté súbory',
-        cancelLabel: 'Storno',
-        cancelTitle: 'Prerušiť  nahrávanie',
-        uploadLabel: 'Nahrať',
-        uploadTitle: 'Nahrať vybraté súbory',
-        msgSizeTooLarge: 'Súbor "{name}" (<b>{size} KB</b>): prekročenie - maximálna povolená veľkosť <b>{maxSize} KB</b>. Skúste nahrať opäť, prosím!',
-        msgFilesTooLess: 'Musíte vybrať najmenej <b>{n}</b> {files} pre nahranie. Skúste nahrať opäť, prosím!',
-        msgFilesTooMany: 'Počet vybratých súborov pre nahranie <b>({n})</b>: prekročenie - maximálny povolený limit <b>{m}</b>. Skúste nahrať opäť, prosím!',
-        msgFileNotFound: 'Súbor "{name}" nebol nájdený!',
-        msgFileSecured: 'Zabezpečenie súboru znemožnilo čítať súbor "{name}".',
-        msgFileNotReadable: 'Súbor "{name}" nie je čitateľný.',
-        msgFilePreviewAborted: 'Náhľad súboru bol prerušený pre "{name}".',
-        msgFilePreviewError: 'Nastala chyba pri načítaní súboru "{name}".',
-        msgInvalidFileType: 'Neplatný typ súboru "{name}". Iba "{types}" súborov sú podporované.',
-        msgInvalidFileExtension: 'Neplatná extenzia súboru "{name}". Iba "{extensions}" súborov sú podporované.',
-        msgValidationError: 'Chyba nahratia súboru.',
-        msgLoading: 'Nahrávanie súboru {index} z {files} &hellip;',
-        msgProgress: 'Nahrávanie súboru {index} z {files} - {name} - {percent}% dokončené.',
-        msgSelected: '{n} {files} vybraté',
-        msgFoldersNotAllowed: 'Tiahni a pusť iba súbory! Vynechané {n} pustené prečinok(y).',
-        msgImageWidthSmall: 'Šírka image súboru "{name}", musí byť minimálne {size} px.',
-        msgImageHeightSmall: 'Výška image súboru "{name}", musí byť minimálne {size} px.',
-        msgImageWidthLarge: 'Šírka image súboru "{name}" nemôže presiahnuť {size} px.',
-        msgImageHeightLarge: 'Výška súboru obrazu "{name}" nesmie presiahnuť {size} px.',
-        dropZoneTitle: 'Tiahni a pusť súbory tu &hellip;'
-    };
+/*!
+ * FileInput Slovakian Translations
+ *
+ * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or
+ * any HTML markup tags in the messages must not be converted or translated.
+ *
+ * @see http://github.com/kartik-v/bootstrap-fileinput
+ *
+ * NOTE: this file must be saved in UTF-8 encoding.
+ */
+(function ($) {
+    "use strict";
+
+    $.fn.fileinputLocales['sk'] = {
+        fileSingle: 'súbor',
+        filePlural: 'súbory',
+        browseLabel: 'Vybrať &hellip;',
+        removeLabel: 'Odstrániť',
+        removeTitle: 'Vyčistiť vybraté súbory',
+        cancelLabel: 'Storno',
+        cancelTitle: 'Prerušiť  nahrávanie',
+        uploadLabel: 'Nahrať',
+        uploadTitle: 'Nahrať vybraté súbory',
+        msgSizeTooLarge: 'Súbor "{name}" (<b>{size} KB</b>): prekročenie - maximálna povolená veľkosť <b>{maxSize} KB</b>. Skúste nahrať opäť, prosím!',
+        msgFilesTooLess: 'Musíte vybrať najmenej <b>{n}</b> {files} pre nahranie. Skúste nahrať opäť, prosím!',
+        msgFilesTooMany: 'Počet vybratých súborov pre nahranie <b>({n})</b>: prekročenie - maximálny povolený limit <b>{m}</b>. Skúste nahrať opäť, prosím!',
+        msgFileNotFound: 'Súbor "{name}" nebol nájdený!',
+        msgFileSecured: 'Zabezpečenie súboru znemožnilo čítať súbor "{name}".',
+        msgFileNotReadable: 'Súbor "{name}" nie je čitateľný.',
+        msgFilePreviewAborted: 'Náhľad súboru bol prerušený pre "{name}".',
+        msgFilePreviewError: 'Nastala chyba pri načítaní súboru "{name}".',
+        msgInvalidFileType: 'Neplatný typ súboru "{name}". Iba "{types}" súborov sú podporované.',
+        msgInvalidFileExtension: 'Neplatná extenzia súboru "{name}". Iba "{extensions}" súborov sú podporované.',
+        msgValidationError: 'Chyba nahratia súboru.',
+        msgLoading: 'Nahrávanie súboru {index} z {files} &hellip;',
+        msgProgress: 'Nahrávanie súboru {index} z {files} - {name} - {percent}% dokončené.',
+        msgSelected: '{n} {files} vybraté',
+        msgFoldersNotAllowed: 'Tiahni a pusť iba súbory! Vynechané {n} pustené prečinok(y).',
+        msgImageWidthSmall: 'Šírka image súboru "{name}", musí byť minimálne {size} px.',
+        msgImageHeightSmall: 'Výška image súboru "{name}", musí byť minimálne {size} px.',
+        msgImageWidthLarge: 'Šírka image súboru "{name}" nemôže presiahnuť {size} px.',
+        msgImageHeightLarge: 'Výška súboru obrazu "{name}" nesmie presiahnuť {size} px.',
+        dropZoneTitle: 'Tiahni a pusť súbory tu &hellip;'
+    };
 })(window.jQuery);
 })(window.jQuery);

+ 46 - 46
js/fileinput_locale_sr.js

@@ -1,46 +1,46 @@
-/*!
- * FileInput Serbian Translations
- *
- * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or
- * any HTML markup tags in the messages must not be converted or translated.
- *
- * @see http://github.com/kartik-v/bootstrap-fileinput
- * @author Milos Stojanovic <[email protected]>
- *
- * NOTE: this file must be saved in UTF-8 encoding.
- */
-(function ($) {
-    "use strict";
-
-    $.fn.fileinputLocales['sr'] = {
-        fileSingle: 'datoteka',
-        filePlural: 'datoteke',
-        browseLabel: 'Izaberi &hellip;',
-        removeLabel: 'Ukloni',
-        removeTitle: 'Ukloni označene datoteke',
-        cancelLabel: 'Odustani',
-        cancelTitle: 'Prekini trenutno otpremanje',
-        uploadLabel: 'Otpremi',
-        uploadTitle: 'Otpremi označene datoteke',
-        msgSizeTooLarge: 'Datoteka "{name}" (<b>{size} KB</b>) prekoračuje maksimalnu dozvoljenu veličinu datoteke od <b>{maxSize} KB</b>. Molimo pokušajte ponovo!',
-        msgFilesTooLess: 'Morate odabrati najmanje <b>{n}</b> {files} za otpremanje. Molimo pokušajte ponovo!',
-        msgFilesTooMany: 'Broj datoteka označenih za otpremanje <b>({n})</b> prekoračuje maksimalni dozvoljeni limit od <b>{m}</b>. Molimo pokušajte ponovo!',
-        msgFileNotFound: 'Datoteka "{name}" nije pronađena!',
-        msgFileSecured: 'Datoteku "{name}" nije moguće pročitati zbog bezbednosnih ograničenja.',
-        msgFileNotReadable: 'Datoteku "{name}" nije moguće pročitati.',
-        msgFilePreviewAborted: 'Generisanje prikaza nije moguće za "{name}".',
-        msgFilePreviewError: 'Došlo je do greške prilikom čitanja datoteke "{name}".',
-        msgInvalidFileType: 'Datoteka "{name}" je pogrešnog formata. Dozvoljeni formati su "{types}".',
-        msgInvalidFileExtension: 'Ekstenzija datoteke "{name}" nije dozvoljena. Dozvoljene ekstenzije su "{extensions}".',
-        msgValidationError: 'Greška prilikom otpremanja fajla',
-        msgLoading: 'Učitavanje datoteke {index} od {files} &hellip;',
-        msgProgress: 'Učitavanje datoteke {index} od {files} - {name} - {percent}% završeno.',
-        msgSelected: '{n} {files} je označeno',
-        msgFoldersNotAllowed: 'Moguće je prevlačiti samo datoteke! Preskočeno je {n} fascikla.',
-        msgImageWidthSmall: 'Ширина Имаге Филе "{name}" мора бити најмање {size} пк.',
-        msgImageHeightSmall: 'Висина Имаге Филе "{name}" мора бити најмање {size} пк.',
-        msgImageWidthLarge: 'Ширина Имаге Филе "{name}" не може бити већи од {size} пк.',
-        msgImageHeightLarge: 'Висина Имаге Филе "{name}" не може бити већи од {size} пк.',
-        dropZoneTitle: 'Prevucite datoteke ovde &hellip;'
-    };
-})(window.jQuery);
+/*!
+ * FileInput Serbian Translations
+ *
+ * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or
+ * any HTML markup tags in the messages must not be converted or translated.
+ *
+ * @see http://github.com/kartik-v/bootstrap-fileinput
+ * @author Milos Stojanovic <[email protected]>
+ *
+ * NOTE: this file must be saved in UTF-8 encoding.
+ */
+(function ($) {
+    "use strict";
+
+    $.fn.fileinputLocales['sr'] = {
+        fileSingle: 'datoteka',
+        filePlural: 'datoteke',
+        browseLabel: 'Izaberi &hellip;',
+        removeLabel: 'Ukloni',
+        removeTitle: 'Ukloni označene datoteke',
+        cancelLabel: 'Odustani',
+        cancelTitle: 'Prekini trenutno otpremanje',
+        uploadLabel: 'Otpremi',
+        uploadTitle: 'Otpremi označene datoteke',
+        msgSizeTooLarge: 'Datoteka "{name}" (<b>{size} KB</b>) prekoračuje maksimalnu dozvoljenu veličinu datoteke od <b>{maxSize} KB</b>. Molimo pokušajte ponovo!',
+        msgFilesTooLess: 'Morate odabrati najmanje <b>{n}</b> {files} za otpremanje. Molimo pokušajte ponovo!',
+        msgFilesTooMany: 'Broj datoteka označenih za otpremanje <b>({n})</b> prekoračuje maksimalni dozvoljeni limit od <b>{m}</b>. Molimo pokušajte ponovo!',
+        msgFileNotFound: 'Datoteka "{name}" nije pronađena!',
+        msgFileSecured: 'Datoteku "{name}" nije moguće pročitati zbog bezbednosnih ograničenja.',
+        msgFileNotReadable: 'Datoteku "{name}" nije moguće pročitati.',
+        msgFilePreviewAborted: 'Generisanje prikaza nije moguće za "{name}".',
+        msgFilePreviewError: 'Došlo je do greške prilikom čitanja datoteke "{name}".',
+        msgInvalidFileType: 'Datoteka "{name}" je pogrešnog formata. Dozvoljeni formati su "{types}".',
+        msgInvalidFileExtension: 'Ekstenzija datoteke "{name}" nije dozvoljena. Dozvoljene ekstenzije su "{extensions}".',
+        msgValidationError: 'Greška prilikom otpremanja fajla',
+        msgLoading: 'Učitavanje datoteke {index} od {files} &hellip;',
+        msgProgress: 'Učitavanje datoteke {index} od {files} - {name} - {percent}% završeno.',
+        msgSelected: '{n} {files} je označeno',
+        msgFoldersNotAllowed: 'Moguće je prevlačiti samo datoteke! Preskočeno je {n} fascikla.',
+        msgImageWidthSmall: 'Ширина Имаге Филе "{name}" мора бити најмање {size} пк.',
+        msgImageHeightSmall: 'Висина Имаге Филе "{name}" мора бити најмање {size} пк.',
+        msgImageWidthLarge: 'Ширина Имаге Филе "{name}" не може бити већи од {size} пк.',
+        msgImageHeightLarge: 'Висина Имаге Филе "{name}" не може бити већи од {size} пк.',
+        dropZoneTitle: 'Prevucite datoteke ovde &hellip;'
+    };
+})(window.jQuery);

+ 44 - 44
js/fileinput_locale_th.js

@@ -1,45 +1,45 @@
-/*!
- * FileInput Thai Translations
- *
- * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or
- * any HTML markup tags in the messages must not be converted or translated.
- *
- * @see http://github.com/kartik-v/bootstrap-fileinput
- *
- * NOTE: this file must be saved in UTF-8 encoding.
- */
-(function ($) {
-    "use strict";
-
-    $.fn.fileinputLocales['th'] = {
-        fileSingle: 'ไฟล์',
-        filePlural: 'ไฟล์',
-        browseLabel: 'เลือกดู &hellip;',
-        removeLabel: 'ลบทิ้ง',
-        removeTitle: 'ลบไฟล์ที่เลือกทิ้ง',
-        cancelLabel: 'ยกเลิก',
-        cancelTitle: 'ยกเลิกการอัพโหลด',
-        uploadLabel: 'อัพโหลด',
-        uploadTitle: 'อัพโหลดไฟล์ที่เลือก',
-        msgSizeTooLarge: 'ไฟล์ "{name}" (<b>{size} KB</b>) มีขนาดเกินที่ระบบอนุญาตที่ <b>{maxSize} KB</b>, กรุณาลองใหม่อีกครั้ง!',
-        msgFilesTooLess: 'คุณต้องเลือกไฟล์จำนวนอย่างน้อย <b>{n}</b> {files} เพื่ออัพโหลด, กรุณาลองใหม่อีกครั้ง!',
-        msgFilesTooMany: 'ไฟล์ที่คุณเลือกมีจำนวน <b>({n})</b> ซึ่งเกินกว่าที่ระบบอนุญาตที่ <b>{m}</b>, กรุณาลองใหม่อีกครั้ง!',
-        msgFileNotFound: 'ไม่พบไฟล์ "{name}" !',
-        msgFileSecured: 'ระบบความปลอดภัยไม่อนุญาตให้อ่านไฟล์ "{name}".',
-        msgFileNotReadable: 'ไม่สามารถอ่านไฟล์ "{name}" ได้',
-        msgFilePreviewAborted: 'ไฟล์ "{name}" ไม่อนุญาตให้ดูตัวอย่าง',
-        msgFilePreviewError: 'พบปัญหาในการดูตัวอย่างไฟล์ "{name}".',
-        msgInvalidFileType: 'ไฟล์ "{name}" เป็นประเภทไฟล์ที่ไม่ถูกต้อง, อนุญาตเฉพาะไฟล์ประเภท "{types}"',
-        msgInvalidFileExtension: 'ไฟล์ "{name}" เป็น extension ที่ไมถูกต้อง, อนุญาตเฉพาะไฟล์ extension "{extensions}"',
-        msgValidationError: 'อัพโหลดไฟล์มีปัญหา',
-        msgLoading: 'กำลังโหลดไฟล์ {index} จาก {files} &hellip;',
-        msgProgress: 'กำลังโหลดไฟล์ {index} จาก {files} - {name} - {percent}%',
-        msgSelected: '{n} {files} ถูกเลือก',
-        msgFoldersNotAllowed: 'Drag & drop เฉพาะไฟล์เท่านั้น! ข้าม dropped folder จำนวน {n}',
-        msgImageWidthSmall: 'ความกว้างของภาพไฟล์ "{name}" ต้องมีอย่างน้อย {size} px.',
-        msgImageHeightSmall: 'ความสูงของภาพไฟล์ "{name}" ต้องมีอย่างน้อย {size} px.',
-        msgImageWidthLarge: 'ความกว้างของภาพไฟล์ "{name}" ไม่เกิน {size} พิกเซล.',
-        msgImageHeightLarge: 'ความสูงของไฟล์ภาพ "{name}" ไม่เกิน {size} พิกเซล.',
-        dropZoneTitle: 'Drag & drop ไฟล์ตรงนี้ &hellip;'
-    };
+/*!
+ * FileInput Thai Translations
+ *
+ * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or
+ * any HTML markup tags in the messages must not be converted or translated.
+ *
+ * @see http://github.com/kartik-v/bootstrap-fileinput
+ *
+ * NOTE: this file must be saved in UTF-8 encoding.
+ */
+(function ($) {
+    "use strict";
+
+    $.fn.fileinputLocales['th'] = {
+        fileSingle: 'ไฟล์',
+        filePlural: 'ไฟล์',
+        browseLabel: 'เลือกดู &hellip;',
+        removeLabel: 'ลบทิ้ง',
+        removeTitle: 'ลบไฟล์ที่เลือกทิ้ง',
+        cancelLabel: 'ยกเลิก',
+        cancelTitle: 'ยกเลิกการอัพโหลด',
+        uploadLabel: 'อัพโหลด',
+        uploadTitle: 'อัพโหลดไฟล์ที่เลือก',
+        msgSizeTooLarge: 'ไฟล์ "{name}" (<b>{size} KB</b>) มีขนาดเกินที่ระบบอนุญาตที่ <b>{maxSize} KB</b>, กรุณาลองใหม่อีกครั้ง!',
+        msgFilesTooLess: 'คุณต้องเลือกไฟล์จำนวนอย่างน้อย <b>{n}</b> {files} เพื่ออัพโหลด, กรุณาลองใหม่อีกครั้ง!',
+        msgFilesTooMany: 'ไฟล์ที่คุณเลือกมีจำนวน <b>({n})</b> ซึ่งเกินกว่าที่ระบบอนุญาตที่ <b>{m}</b>, กรุณาลองใหม่อีกครั้ง!',
+        msgFileNotFound: 'ไม่พบไฟล์ "{name}" !',
+        msgFileSecured: 'ระบบความปลอดภัยไม่อนุญาตให้อ่านไฟล์ "{name}".',
+        msgFileNotReadable: 'ไม่สามารถอ่านไฟล์ "{name}" ได้',
+        msgFilePreviewAborted: 'ไฟล์ "{name}" ไม่อนุญาตให้ดูตัวอย่าง',
+        msgFilePreviewError: 'พบปัญหาในการดูตัวอย่างไฟล์ "{name}".',
+        msgInvalidFileType: 'ไฟล์ "{name}" เป็นประเภทไฟล์ที่ไม่ถูกต้อง, อนุญาตเฉพาะไฟล์ประเภท "{types}"',
+        msgInvalidFileExtension: 'ไฟล์ "{name}" เป็น extension ที่ไมถูกต้อง, อนุญาตเฉพาะไฟล์ extension "{extensions}"',
+        msgValidationError: 'อัพโหลดไฟล์มีปัญหา',
+        msgLoading: 'กำลังโหลดไฟล์ {index} จาก {files} &hellip;',
+        msgProgress: 'กำลังโหลดไฟล์ {index} จาก {files} - {name} - {percent}%',
+        msgSelected: '{n} {files} ถูกเลือก',
+        msgFoldersNotAllowed: 'Drag & drop เฉพาะไฟล์เท่านั้น! ข้าม dropped folder จำนวน {n}',
+        msgImageWidthSmall: 'ความกว้างของภาพไฟล์ "{name}" ต้องมีอย่างน้อย {size} px.',
+        msgImageHeightSmall: 'ความสูงของภาพไฟล์ "{name}" ต้องมีอย่างน้อย {size} px.',
+        msgImageWidthLarge: 'ความกว้างของภาพไฟล์ "{name}" ไม่เกิน {size} พิกเซล.',
+        msgImageHeightLarge: 'ความสูงของไฟล์ภาพ "{name}" ไม่เกิน {size} พิกเซล.',
+        dropZoneTitle: 'Drag & drop ไฟล์ตรงนี้ &hellip;'
+    };
 })(window.jQuery);
 })(window.jQuery);

+ 45 - 45
js/fileinput_locale_tr.js

@@ -1,45 +1,45 @@
-/*!
- * FileInput Turkish Translations
- *
- * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or
- * any HTML markup tags in the messages must not be converted or translated.
- *
- * @see http://github.com/kartik-v/bootstrap-fileinput
- *
- * NOTE: this file must be saved in UTF-8 encoding.
- */
-(function ($) {
-    "use strict";
-
-    $.fn.fileinputLocales['tr'] = {
-        fileSingle: 'dosya',
-        filePlural: 'dosyalar',
-        browseLabel: 'Gözat &hellip;',
-        removeLabel: 'Sil',
-        removeTitle: 'Seçilen dosyaları sil',
-        cancelLabel: 'İptal',
-        cancelTitle: 'Devam eden yüklemeyi iptal et',
-        uploadLabel: 'Yükle',
-        uploadTitle: 'Seçilen dosyaları yükle',
-        msgSizeTooLarge: '"{name}" dosyasının boyutu (<b>{size} KB</b>) izin verilen azami dosya boyutu olan <b>{maxSize} KB</b>\'tan büyük. Lütfen tekrar deneyin!',
-        msgFilesTooLess: 'Yüklemek için en az <b>{n}</b> {files} dosya seçmelisiniz. Lütfen tekrar deneyin!',
-        msgFilesTooMany: 'Yüklemek için seçtiğiniz dosya sayısı <b>({n})</b> azami limitin <b>{m}</b> altında olmalıdır. Lütfen tekrar deneyin!',
-        msgFileNotFound: '"{name}" dosyası bulunamadı!',
-        msgFileSecured: 'Güvenlik kısıtlamaları "{name}" dosyasının okunmasını engelliyor.',
-        msgFileNotReadable: '"{name}" dosyası okunabilir değil.',
-        msgFilePreviewAborted: '"{name}" dosyası için önizleme iptal edildi.',
-        msgFilePreviewError: '"{name}" dosyası okunurken bir hata oluştu.',
-        msgInvalidFileType: '"{name}" dosyasının türü geçerli değil. Yalnızca "{types}" türünde dosyalara izin veriliyor.',
-        msgInvalidFileExtension: '"{name}" dosyasının uzantısı geçersiz. Yalnızca "{extensions}" uzantılı dosyalara izin veriliyor.',
-        msgValidationError: 'Dosya Yükleme Hatası',
-        msgLoading: 'Dosyalar yükleniyor {index} / {files} &hellip;',
-        msgProgress: 'Dosya yükleniyor {index} / {files} - {name} - %{percent} tamamlandı.',
-        msgSelected: '{n} {files} seçildi',
-        msgFoldersNotAllowed: 'Yalnızca dosyaları sürükleyip bırakabilirsiniz! {n} dizin(ler) göz ardı edildi.',
-        msgImageWidthSmall: 'Görüntü dosyası "{name}" genişliği en az {size} piksel olmalıdır.',
-        msgImageHeightSmall: 'Görüntü dosyası "{name}" yüksekliği en az {size} piksel olmalıdır.',
-        msgImageWidthLarge: 'Görüntü dosyası "{name}" genişliği {size} px geçemez.',
-        msgImageHeightLarge: 'Resim dosyası "{name}" Yükseklik {size} px geçemez.',
-        dropZoneTitle: 'Dosyaları buraya sürükleyip bırakın &hellip;'
-    };
-})(window.jQuery);
+/*!
+ * FileInput Turkish Translations
+ *
+ * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or
+ * any HTML markup tags in the messages must not be converted or translated.
+ *
+ * @see http://github.com/kartik-v/bootstrap-fileinput
+ *
+ * NOTE: this file must be saved in UTF-8 encoding.
+ */
+(function ($) {
+    "use strict";
+
+    $.fn.fileinputLocales['tr'] = {
+        fileSingle: 'dosya',
+        filePlural: 'dosyalar',
+        browseLabel: 'Gözat &hellip;',
+        removeLabel: 'Sil',
+        removeTitle: 'Seçilen dosyaları sil',
+        cancelLabel: 'İptal',
+        cancelTitle: 'Devam eden yüklemeyi iptal et',
+        uploadLabel: 'Yükle',
+        uploadTitle: 'Seçilen dosyaları yükle',
+        msgSizeTooLarge: '"{name}" dosyasının boyutu (<b>{size} KB</b>) izin verilen azami dosya boyutu olan <b>{maxSize} KB</b>\'tan büyük. Lütfen tekrar deneyin!',
+        msgFilesTooLess: 'Yüklemek için en az <b>{n}</b> {files} dosya seçmelisiniz. Lütfen tekrar deneyin!',
+        msgFilesTooMany: 'Yüklemek için seçtiğiniz dosya sayısı <b>({n})</b> azami limitin <b>{m}</b> altında olmalıdır. Lütfen tekrar deneyin!',
+        msgFileNotFound: '"{name}" dosyası bulunamadı!',
+        msgFileSecured: 'Güvenlik kısıtlamaları "{name}" dosyasının okunmasını engelliyor.',
+        msgFileNotReadable: '"{name}" dosyası okunabilir değil.',
+        msgFilePreviewAborted: '"{name}" dosyası için önizleme iptal edildi.',
+        msgFilePreviewError: '"{name}" dosyası okunurken bir hata oluştu.',
+        msgInvalidFileType: '"{name}" dosyasının türü geçerli değil. Yalnızca "{types}" türünde dosyalara izin veriliyor.',
+        msgInvalidFileExtension: '"{name}" dosyasının uzantısı geçersiz. Yalnızca "{extensions}" uzantılı dosyalara izin veriliyor.',
+        msgValidationError: 'Dosya Yükleme Hatası',
+        msgLoading: 'Dosyalar yükleniyor {index} / {files} &hellip;',
+        msgProgress: 'Dosya yükleniyor {index} / {files} - {name} - %{percent} tamamlandı.',
+        msgSelected: '{n} {files} seçildi',
+        msgFoldersNotAllowed: 'Yalnızca dosyaları sürükleyip bırakabilirsiniz! {n} dizin(ler) göz ardı edildi.',
+        msgImageWidthSmall: 'Görüntü dosyası "{name}" genişliği en az {size} piksel olmalıdır.',
+        msgImageHeightSmall: 'Görüntü dosyası "{name}" yüksekliği en az {size} piksel olmalıdır.',
+        msgImageWidthLarge: 'Görüntü dosyası "{name}" genişliği {size} px geçemez.',
+        msgImageHeightLarge: 'Resim dosyası "{name}" Yükseklik {size} px geçemez.',
+        dropZoneTitle: 'Dosyaları buraya sürükleyip bırakın &hellip;'
+    };
+})(window.jQuery);

+ 46 - 46
js/fileinput_locale_uk.js

@@ -1,46 +1,46 @@
-/*!
- * FileInput Ukrainian Translations
- *
- * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or
- * any HTML markup tags in the messages must not be converted or translated.
- *
- * @see http://github.com/kartik-v/bootstrap-fileinput
- * @author CyanoFresh <[email protected]>
- *
- * NOTE: this file must be saved in UTF-8 encoding.
- */
-(function ($) {
-    "use strict";
-
-    $.fn.fileinputLocales['uk'] = {
-        fileSingle: 'файл',
-        filePlural: 'файли',
-        browseLabel: 'Вибрати &hellip;',
-        removeLabel: 'Видалити',
-        removeTitle: 'Видалити вибрані файли',
-        cancelLabel: 'Скасувати',
-        cancelTitle: 'Скасувати поточну загрузку',
-        uploadLabel: 'Загрузити',
-        uploadTitle: 'Загрузити вибрані файли',
-        msgSizeTooLarge: 'Файл "{name}" (<b>{size} KB</b>) перевищує максимальний розмір <b>{maxSize} KB</b>',
-        msgFilesTooLess: 'Ви повинні вибрати як мінімум <b>{n}</b> {files} для загрузки',
-        msgFilesTooMany: 'Кількість вибраних файлів <b>({n})</b> перевищує максимально допустиму кількість <b>{m}</b>',
-        msgFileNotFound: 'Файл "{name}" не знайдено!',
-        msgFileSecured: 'Обмеження безпеки перешкоджають читанню файла "{name}".',
-        msgFileNotReadable: 'Файл "{name}" неможливо прочитати.',
-        msgFilePreviewAborted: 'Перегляд скасований для файла "{name}".',
-        msgFilePreviewError: 'Сталася помилка під час читання файла "{name}".',
-        msgInvalidFileType: 'Заборонений тип файла для "{name}". Тільки "{types}" дозволені.',
-        msgInvalidFileExtension: 'Заборонене розширення для файла "{name}". Тільки "{extensions}" дозволені.',
-        msgValidationError: 'Помилка під час загрузки файла',
-        msgLoading: 'Загрузка файла {index} із {files} &hellip;',
-        msgProgress: 'Загрузка файла {index} із {files} - {name} - {percent}% завершено.',
-        msgSelected: '{n} {files} вибрано',
-        msgFoldersNotAllowed: 'Дозволено перетягувати тільки файли! Пропущено {n} папок.',
-        msgImageWidthSmall: 'Ширина зображення "{name}" повинна бути не менше {size} px.',
-        msgImageHeightSmall: 'Висота зображення "{name}" повинна бути не менше {size} px.',
-        msgImageWidthLarge: 'Ширина зображення "{name}" не може перевищувати {size} px.',
-        msgImageHeightLarge: 'Висота зображення "{name}" не може перевищувати {size} px.',
-        dropZoneTitle: 'Перетягніть файли сюди &hellip;'
-    };
-})(window.jQuery);
+/*!
+ * FileInput Ukrainian Translations
+ *
+ * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or
+ * any HTML markup tags in the messages must not be converted or translated.
+ *
+ * @see http://github.com/kartik-v/bootstrap-fileinput
+ * @author CyanoFresh <[email protected]>
+ *
+ * NOTE: this file must be saved in UTF-8 encoding.
+ */
+(function ($) {
+    "use strict";
+
+    $.fn.fileinputLocales['uk'] = {
+        fileSingle: 'файл',
+        filePlural: 'файли',
+        browseLabel: 'Вибрати &hellip;',
+        removeLabel: 'Видалити',
+        removeTitle: 'Видалити вибрані файли',
+        cancelLabel: 'Скасувати',
+        cancelTitle: 'Скасувати поточну загрузку',
+        uploadLabel: 'Загрузити',
+        uploadTitle: 'Загрузити вибрані файли',
+        msgSizeTooLarge: 'Файл "{name}" (<b>{size} KB</b>) перевищує максимальний розмір <b>{maxSize} KB</b>',
+        msgFilesTooLess: 'Ви повинні вибрати як мінімум <b>{n}</b> {files} для загрузки',
+        msgFilesTooMany: 'Кількість вибраних файлів <b>({n})</b> перевищує максимально допустиму кількість <b>{m}</b>',
+        msgFileNotFound: 'Файл "{name}" не знайдено!',
+        msgFileSecured: 'Обмеження безпеки перешкоджають читанню файла "{name}".',
+        msgFileNotReadable: 'Файл "{name}" неможливо прочитати.',
+        msgFilePreviewAborted: 'Перегляд скасований для файла "{name}".',
+        msgFilePreviewError: 'Сталася помилка під час читання файла "{name}".',
+        msgInvalidFileType: 'Заборонений тип файла для "{name}". Тільки "{types}" дозволені.',
+        msgInvalidFileExtension: 'Заборонене розширення для файла "{name}". Тільки "{extensions}" дозволені.',
+        msgValidationError: 'Помилка під час загрузки файла',
+        msgLoading: 'Загрузка файла {index} із {files} &hellip;',
+        msgProgress: 'Загрузка файла {index} із {files} - {name} - {percent}% завершено.',
+        msgSelected: '{n} {files} вибрано',
+        msgFoldersNotAllowed: 'Дозволено перетягувати тільки файли! Пропущено {n} папок.',
+        msgImageWidthSmall: 'Ширина зображення "{name}" повинна бути не менше {size} px.',
+        msgImageHeightSmall: 'Висота зображення "{name}" повинна бути не менше {size} px.',
+        msgImageWidthLarge: 'Ширина зображення "{name}" не може перевищувати {size} px.',
+        msgImageHeightLarge: 'Висота зображення "{name}" не може перевищувати {size} px.',
+        dropZoneTitle: 'Перетягніть файли сюди &hellip;'
+    };
+})(window.jQuery);

+ 48 - 48
js/fileinput_locale_zh.js

@@ -1,49 +1,49 @@
-/*!
- * FileInput Chinese Translations
- *
- * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or
- * any HTML markup tags in the messages must not be converted or translated.
- *
- * @see http://github.com/kartik-v/bootstrap-fileinput
- * @author kangqf <[email protected]>
- *
- * NOTE: this file must be saved in UTF-8 encoding.
- */
-(function ($) {
-    "use strict";
-
-    $.fn.fileinputLocales['zh'] = {
-        fileSingle: '文件',
-        filePlural: '多个文件',
-        browseLabel: '选择 &hellip;',
-        removeLabel: '移除',
-        removeTitle: '清除选中文件',
-        cancelLabel: '取消',
-        cancelTitle: '取消进行中的上传',
-        uploadLabel: '上传',
-        uploadTitle: '上传选中文件',
-        msgSizeTooLarge: '文件 "{name}" (<b>{size} KB</b>) 超过了允许大小 <b>{maxSize} KB</b>. 请重新上传!',
-        msgFilesTooLess: '你必须选择最少 <b>{n}</b> {files} 来上传. 请重新上传!',
-        msgFilesTooMany: '选择的上传文件个数 <b>({n})</b> 超出最大文件的限制个数 <b>{m}</b>. 请重新上传!',
-        msgFileNotFound: '文件 "{name}" 未找到!',
-        msgFileSecured: '安全限制,为了防止读取文件 "{name}".',
-        msgFileNotReadable: '文件 "{name}" 不可读.',
-        msgFilePreviewAborted: '取消 "{name}" 的预览.',
-        msgFilePreviewError: '读取 "{name}" 时出现了一个错误.',
-        msgInvalidFileType: '不正确的类型 "{name}". 只支持 "{types}" 类型的文件.',
-        msgInvalidFileExtension: '不正确的文件扩展名 "{name}". 只支持 "{extensions}" 的文件扩展名.',
-        msgValidationError: '文件上传错误',
-        msgLoading: '加载第 {index} 文件 共 {files} &hellip;',
-        msgProgress: '加载第 {index} 文件 共 {files} - {name} - {percent}% 完成.',
-        msgSelected: '{n} {files} 选中',
-        msgFoldersNotAllowed: '只支持拖拽文件! 跳过 {n} 拖拽的文件夹.',
-        msgImageWidthSmall: '宽度的图像文件的"{name}"的必须是至少{size}像素.',
-        msgImageHeightSmall: '图像文件的"{name}"的高度必须至少为{size}像素.',
-        msgImageWidthLarge: '宽度的图像文件"{name}"不能超过{size}像素.',
-        msgImageHeightLarge: '图像文件"{name}"的高度不能超过{size}像素.',
-        dropZoneTitle: '拖拽文件到这里 &hellip;',
-        slugCallback: function(text) {
-            return text ? text.split(/(\\|\/)/g).pop().replace(/[^\w\u4e00-\u9fa5\-.\\\/ ]+/g, '') : '';
-        }
-    };
+/*!
+ * FileInput Chinese Translations
+ *
+ * This file must be loaded after 'fileinput.js'. Patterns in braces '{}', or
+ * any HTML markup tags in the messages must not be converted or translated.
+ *
+ * @see http://github.com/kartik-v/bootstrap-fileinput
+ * @author kangqf <[email protected]>
+ *
+ * NOTE: this file must be saved in UTF-8 encoding.
+ */
+(function ($) {
+    "use strict";
+
+    $.fn.fileinputLocales['zh'] = {
+        fileSingle: '文件',
+        filePlural: '多个文件',
+        browseLabel: '选择 &hellip;',
+        removeLabel: '移除',
+        removeTitle: '清除选中文件',
+        cancelLabel: '取消',
+        cancelTitle: '取消进行中的上传',
+        uploadLabel: '上传',
+        uploadTitle: '上传选中文件',
+        msgSizeTooLarge: '文件 "{name}" (<b>{size} KB</b>) 超过了允许大小 <b>{maxSize} KB</b>. 请重新上传!',
+        msgFilesTooLess: '你必须选择最少 <b>{n}</b> {files} 来上传. 请重新上传!',
+        msgFilesTooMany: '选择的上传文件个数 <b>({n})</b> 超出最大文件的限制个数 <b>{m}</b>. 请重新上传!',
+        msgFileNotFound: '文件 "{name}" 未找到!',
+        msgFileSecured: '安全限制,为了防止读取文件 "{name}".',
+        msgFileNotReadable: '文件 "{name}" 不可读.',
+        msgFilePreviewAborted: '取消 "{name}" 的预览.',
+        msgFilePreviewError: '读取 "{name}" 时出现了一个错误.',
+        msgInvalidFileType: '不正确的类型 "{name}". 只支持 "{types}" 类型的文件.',
+        msgInvalidFileExtension: '不正确的文件扩展名 "{name}". 只支持 "{extensions}" 的文件扩展名.',
+        msgValidationError: '文件上传错误',
+        msgLoading: '加载第 {index} 文件 共 {files} &hellip;',
+        msgProgress: '加载第 {index} 文件 共 {files} - {name} - {percent}% 完成.',
+        msgSelected: '{n} {files} 选中',
+        msgFoldersNotAllowed: '只支持拖拽文件! 跳过 {n} 拖拽的文件夹.',
+        msgImageWidthSmall: '宽度的图像文件的"{name}"的必须是至少{size}像素.',
+        msgImageHeightSmall: '图像文件的"{name}"的高度必须至少为{size}像素.',
+        msgImageWidthLarge: '宽度的图像文件"{name}"不能超过{size}像素.',
+        msgImageHeightLarge: '图像文件"{name}"的高度不能超过{size}像素.',
+        dropZoneTitle: '拖拽文件到这里 &hellip;',
+        slugCallback: function(text) {
+            return text ? text.split(/(\\|\/)/g).pop().replace(/[^\w\u4e00-\u9fa5\-.\\\/ ]+/g, '') : '';
+        }
+    };
 })(window.jQuery);
 })(window.jQuery);

+ 20 - 20
nuget/Package.nuspec

@@ -1,21 +1,21 @@
-<?xml version="1.0"?>
-<package >
-  <metadata>
-    <id>bootstrap-fileinput</id>
-	<title>bootstrap-fileinput</title>
-    <version>4.2.5</version>
-    <authors>Kartik Visweswaran, Robert Kiss (nuget package)</authors>
-    <owners>Kartik Visweswaran</owners>
-    <licenseUrl>https://github.com/kartik-v/bootstrap-fileinput/blob/master/LICENSE.md</licenseUrl>
-    <projectUrl>https://github.com/kartik-v/bootstrap-fileinput</projectUrl>
-    <iconUrl>http://getbootstrap.com/favicon.ico</iconUrl>
-    <requireLicenseAcceptance>false</requireLicenseAcceptance>
-    <description>An enhanced HTML 5 file input for Bootstrap 3.x with file preview for various files, offers multiple selection, and more.</description>
-    <releaseNotes>https://github.com/kartik-v/bootstrap-fileinput/blob/master/CHANGE.md</releaseNotes>
-    <copyright>Copyright 2015</copyright>
-    <tags>bootstrap bootstrap-fileinput</tags>
-    <dependencies>
-      <dependency id="bootstrap" version="3.0.0" />
-    </dependencies>
-  </metadata>
+<?xml version="1.0"?>
+<package >
+  <metadata>
+    <id>bootstrap-fileinput</id>
+	<title>bootstrap-fileinput</title>
+    <version>4.2.6</version>
+    <authors>Kartik Visweswaran, Robert Kiss (nuget package)</authors>
+    <owners>Kartik Visweswaran</owners>
+    <licenseUrl>https://github.com/kartik-v/bootstrap-fileinput/blob/master/LICENSE.md</licenseUrl>
+    <projectUrl>https://github.com/kartik-v/bootstrap-fileinput</projectUrl>
+    <iconUrl>http://getbootstrap.com/favicon.ico</iconUrl>
+    <requireLicenseAcceptance>false</requireLicenseAcceptance>
+    <description>An enhanced HTML 5 file input for Bootstrap 3.x with file preview for various files, offers multiple selection, and more.</description>
+    <releaseNotes>https://github.com/kartik-v/bootstrap-fileinput/blob/master/CHANGE.md</releaseNotes>
+    <copyright>Copyright 2015</copyright>
+    <tags>bootstrap bootstrap-fileinput</tags>
+    <dependencies>
+      <dependency id="bootstrap" version="3.0.0" />
+    </dependencies>
+  </metadata>
 </package>
 </package>

+ 35 - 35
nuget/build.bat

@@ -1,35 +1,35 @@
-@echo off
-
-NuGet Update -self
-REM remove package content folder
-rmdir /s /q content
-
-REM create new package content folder
-mkdir content
-
-REM create sub folder for js files
-mkdir content\Scripts
-
-REM create sub folders for css and img files
-mkdir content\Content
-mkdir content\Content\bootstrap-fileinput
-mkdir content\Content\bootstrap-fileinput\css
-mkdir content\Content\bootstrap-fileinput\img
-
-REM delete the previous package versions
-del bootstrap-fileinput.*
-
-REM copy the content to the destination folders
-copy ..\js\*.js content\Scripts
-copy ..\css\*.css content\Content\bootstrap-fileinput\css
-copy ..\img\*.* content\Content\bootstrap-fileinput\img
-
-REM create a new package
-NuGet Pack Package.nuspec -Exclude NuGet.exe;build.bat
-
-REM Upload the new package
-REM for %%f in (bootstrap-fileinput.*) do (
-REM	NuGet Push %%f
-REM	rmdir /s /q content
-REM	del %%f
-REM )
+@echo off
+
+NuGet Update -self
+REM remove package content folder
+rmdir /s /q content
+
+REM create new package content folder
+mkdir content
+
+REM create sub folder for js files
+mkdir content\Scripts
+
+REM create sub folders for css and img files
+mkdir content\Content
+mkdir content\Content\bootstrap-fileinput
+mkdir content\Content\bootstrap-fileinput\css
+mkdir content\Content\bootstrap-fileinput\img
+
+REM delete the previous package versions
+del bootstrap-fileinput.*
+
+REM copy the content to the destination folders
+copy ..\js\*.js content\Scripts
+copy ..\css\*.css content\Content\bootstrap-fileinput\css
+copy ..\img\*.* content\Content\bootstrap-fileinput\img
+
+REM create a new package
+NuGet Pack Package.nuspec -Exclude NuGet.exe;build.bat
+
+REM Upload the new package
+REM for %%f in (bootstrap-fileinput.*) do (
+REM	NuGet Push %%f
+REM	rmdir /s /q content
+REM	del %%f
+REM )

この差分においてかなりの量のファイルが変更されているため、一部のファイルを表示していません