dyjh před 6 roky
rodič
revize
de07c9cf3c
82 změnil soubory, kde provedl 15964 přidání a 4 odebrání
  1. 101 0
      public/base/plugins/bootstrap-fileinput/css/fileinput-rtl.css
  2. 12 0
      public/base/plugins/bootstrap-fileinput/css/fileinput-rtl.min.css
  3. 525 0
      public/base/plugins/bootstrap-fileinput/css/fileinput.css
  4. 11 0
      public/base/plugins/bootstrap-fileinput/css/fileinput.min.css
  5. 224 0
      public/base/plugins/bootstrap-fileinput/examples/index.html
  6. binární
      public/base/plugins/bootstrap-fileinput/img/loading-sm.gif
  7. binární
      public/base/plugins/bootstrap-fileinput/img/loading.gif
  8. 4503 0
      public/base/plugins/bootstrap-fileinput/js/fileinput.js
  9. 10 0
      public/base/plugins/bootstrap-fileinput/js/fileinput.min.js
  10. 100 0
      public/base/plugins/bootstrap-fileinput/js/locales/LANG.js
  11. 101 0
      public/base/plugins/bootstrap-fileinput/js/locales/ar.js
  12. 101 0
      public/base/plugins/bootstrap-fileinput/js/locales/az.js
  13. 100 0
      public/base/plugins/bootstrap-fileinput/js/locales/bg.js
  14. 100 0
      public/base/plugins/bootstrap-fileinput/js/locales/ca.js
  15. 101 0
      public/base/plugins/bootstrap-fileinput/js/locales/cr.js
  16. 100 0
      public/base/plugins/bootstrap-fileinput/js/locales/cs.js
  17. 100 0
      public/base/plugins/bootstrap-fileinput/js/locales/da.js
  18. 98 0
      public/base/plugins/bootstrap-fileinput/js/locales/de.js
  19. 100 0
      public/base/plugins/bootstrap-fileinput/js/locales/el.js
  20. 100 0
      public/base/plugins/bootstrap-fileinput/js/locales/es.js
  21. 99 0
      public/base/plugins/bootstrap-fileinput/js/locales/et.js
  22. 101 0
      public/base/plugins/bootstrap-fileinput/js/locales/fa.js
  23. 91 0
      public/base/plugins/bootstrap-fileinput/js/locales/fi.js
  24. 99 0
      public/base/plugins/bootstrap-fileinput/js/locales/fr.js
  25. 100 0
      public/base/plugins/bootstrap-fileinput/js/locales/gl.js
  26. 96 0
      public/base/plugins/bootstrap-fileinput/js/locales/he.js
  27. 100 0
      public/base/plugins/bootstrap-fileinput/js/locales/hu.js
  28. 101 0
      public/base/plugins/bootstrap-fileinput/js/locales/id.js
  29. 102 0
      public/base/plugins/bootstrap-fileinput/js/locales/it.js
  30. 109 0
      public/base/plugins/bootstrap-fileinput/js/locales/ja.js
  31. 101 0
      public/base/plugins/bootstrap-fileinput/js/locales/ka.js
  32. 100 0
      public/base/plugins/bootstrap-fileinput/js/locales/kr.js
  33. 88 0
      public/base/plugins/bootstrap-fileinput/js/locales/kz.js
  34. 100 0
      public/base/plugins/bootstrap-fileinput/js/locales/lt.js
  35. 100 0
      public/base/plugins/bootstrap-fileinput/js/locales/nl.js
  36. 99 0
      public/base/plugins/bootstrap-fileinput/js/locales/no.js
  37. 90 0
      public/base/plugins/bootstrap-fileinput/js/locales/pl.js
  38. 100 0
      public/base/plugins/bootstrap-fileinput/js/locales/pt-BR.js
  39. 100 0
      public/base/plugins/bootstrap-fileinput/js/locales/pt.js
  40. 101 0
      public/base/plugins/bootstrap-fileinput/js/locales/ro.js
  41. 101 0
      public/base/plugins/bootstrap-fileinput/js/locales/ru.js
  42. 100 0
      public/base/plugins/bootstrap-fileinput/js/locales/sk.js
  43. 98 0
      public/base/plugins/bootstrap-fileinput/js/locales/sl.js
  44. 99 0
      public/base/plugins/bootstrap-fileinput/js/locales/sv.js
  45. 100 0
      public/base/plugins/bootstrap-fileinput/js/locales/th.js
  46. 99 0
      public/base/plugins/bootstrap-fileinput/js/locales/tr.js
  47. 101 0
      public/base/plugins/bootstrap-fileinput/js/locales/uk.js
  48. 101 0
      public/base/plugins/bootstrap-fileinput/js/locales/vi.js
  49. 102 0
      public/base/plugins/bootstrap-fileinput/js/locales/zh-TW.js
  50. 100 0
      public/base/plugins/bootstrap-fileinput/js/locales/zh.js
  51. 2471 0
      public/base/plugins/bootstrap-fileinput/js/plugins/piexif.js
  52. 0 0
      public/base/plugins/bootstrap-fileinput/js/plugins/piexif.min.js
  53. 19 0
      public/base/plugins/bootstrap-fileinput/js/plugins/purify.js
  54. 0 0
      public/base/plugins/bootstrap-fileinput/js/plugins/purify.min.js
  55. 1590 0
      public/base/plugins/bootstrap-fileinput/js/plugins/sortable.js
  56. 0 0
      public/base/plugins/bootstrap-fileinput/js/plugins/sortable.min.js
  57. 21 0
      public/base/plugins/bootstrap-fileinput/nuget/Package.nuspec
  58. 35 0
      public/base/plugins/bootstrap-fileinput/nuget/build.bat
  59. 136 0
      public/base/plugins/bootstrap-fileinput/scss/fileinput-rtl.scss
  60. 671 0
      public/base/plugins/bootstrap-fileinput/scss/fileinput.scss
  61. 201 0
      public/base/plugins/bootstrap-fileinput/scss/themes/explorer-fa/theme.scss
  62. 201 0
      public/base/plugins/bootstrap-fileinput/scss/themes/explorer-fas/theme.scss
  63. 201 0
      public/base/plugins/bootstrap-fileinput/scss/themes/explorer/theme.scss
  64. 157 0
      public/base/plugins/bootstrap-fileinput/themes/explorer-fa/theme.css
  65. 87 0
      public/base/plugins/bootstrap-fileinput/themes/explorer-fa/theme.js
  66. 12 0
      public/base/plugins/bootstrap-fileinput/themes/explorer-fa/theme.min.css
  67. 13 0
      public/base/plugins/bootstrap-fileinput/themes/explorer-fa/theme.min.js
  68. 157 0
      public/base/plugins/bootstrap-fileinput/themes/explorer-fas/theme.css
  69. 87 0
      public/base/plugins/bootstrap-fileinput/themes/explorer-fas/theme.js
  70. 12 0
      public/base/plugins/bootstrap-fileinput/themes/explorer-fas/theme.min.css
  71. 13 0
      public/base/plugins/bootstrap-fileinput/themes/explorer-fas/theme.min.js
  72. 156 0
      public/base/plugins/bootstrap-fileinput/themes/explorer/theme.css
  73. 58 0
      public/base/plugins/bootstrap-fileinput/themes/explorer/theme.js
  74. 11 0
      public/base/plugins/bootstrap-fileinput/themes/explorer/theme.min.css
  75. 12 0
      public/base/plugins/bootstrap-fileinput/themes/explorer/theme.min.js
  76. 47 0
      public/base/plugins/bootstrap-fileinput/themes/fa/theme.js
  77. 12 0
      public/base/plugins/bootstrap-fileinput/themes/fa/theme.min.js
  78. 47 0
      public/base/plugins/bootstrap-fileinput/themes/fas/theme.js
  79. 12 0
      public/base/plugins/bootstrap-fileinput/themes/fas/theme.min.js
  80. 45 0
      public/base/plugins/bootstrap-fileinput/themes/gly/theme.js
  81. 12 0
      public/base/plugins/bootstrap-fileinput/themes/gly/theme.min.js
  82. 3 4
      resources/views/admin/album/product/edit.blade.php

+ 101 - 0
public/base/plugins/bootstrap-fileinput/css/fileinput-rtl.css

xqd
@@ -0,0 +1,101 @@
+/*!
+ * bootstrap-fileinput v4.5.2
+ * http://plugins.krajee.com/file-input
+ *
+ * Krajee RTL (Right To Left) default styling for bootstrap-fileinput.
+ *
+ * Author: Kartik Visweswaran
+ * Copyright: 2014 - 2018, Kartik Visweswaran, Krajee.com
+ *
+ * Licensed under the BSD 3-Clause
+ * https://github.com/kartik-v/bootstrap-fileinput/blob/master/LICENSE.md
+ */
+.kv-rtl .close, .kv-rtl .krajee-default .file-actions, .kv-rtl .krajee-default .file-other-error {
+    float: left;
+}
+
+.kv-rtl .krajee-default.file-preview-frame, .kv-rtl .krajee-default .file-drag-handle, .kv-rtl .krajee-default .file-upload-indicator {
+    float: right;
+}
+
+.kv-rtl .file-zoom-dialog, .kv-rtl .file-error-message pre, .kv-rtl .file-error-message ul {
+    text-align: right;
+}
+
+.kv-rtl {
+    direction: rtl;
+}
+
+.kv-rtl .floating-buttons {
+    left: 10px;
+    right: auto;
+}
+
+.kv-rtl .floating-buttons .btn-kv {
+    margin-left: 0;
+    margin-right: 3px;
+}
+
+.kv-rtl .file-caption-icon {
+    left: auto;
+    right: 8px;
+}
+
+.kv-rtl .file-drop-zone {
+    margin: 12px 12px 12px 15px;
+}
+
+.kv-rtl .btn-prev {
+    right: 1px;
+    left: auto;
+}
+
+.kv-rtl .btn-next {
+    left: 1px;
+    right: auto;
+}
+
+.kv-rtl .pull-right, .kv-rtl .float-right {
+    float: left !important;
+}
+
+.kv-rtl .pull-left, .kv-rtl .float-left {
+    float: right !important;
+}
+
+.kv-rtl .kv-zoom-title {
+    direction: ltr;
+}
+
+.kv-rtl .krajee-default.file-preview-frame {
+    box-shadow: -1px 1px 5px 0 #a2958a;
+}
+
+.kv-rtl .krajee-default.file-preview-frame:not(.file-preview-error):hover {
+    box-shadow: -3px 3px 5px 0 #333;
+}
+
+.kv-rtl .kv-zoom-actions .btn-kv {
+    margin-left: 0;
+    margin-right: 3px;
+}
+
+.kv-rtl .file-caption.icon-visible .file-caption-name {
+    padding-left: 0;
+    padding-right: 15px;
+}
+
+.kv-rtl .input-group-btn > .btn:last-child {
+    border-radius: 4px 0 0 4px;
+}
+
+.kv-rtl .input-group .form-control:first-child {
+    border-radius: 0 4px 4px 0;
+}
+
+.kv-rtl .btn-file input[type=file] {
+    left: auto;
+    right: 0;
+    text-align: left;
+    background: none repeat scroll 100% 0 transparent;
+}

+ 12 - 0
public/base/plugins/bootstrap-fileinput/css/fileinput-rtl.min.css

xqd
@@ -0,0 +1,12 @@
+/*!
+ * bootstrap-fileinput v4.5.2
+ * http://plugins.krajee.com/file-input
+ *
+ * Krajee RTL (Right To Left) default styling for bootstrap-fileinput.
+ *
+ * Author: Kartik Visweswaran
+ * Copyright: 2014 - 2018, Kartik Visweswaran, Krajee.com
+ *
+ * Licensed under the BSD 3-Clause
+ * https://github.com/kartik-v/bootstrap-fileinput/blob/master/LICENSE.md
+ */.kv-rtl .close,.kv-rtl .krajee-default .file-actions,.kv-rtl .krajee-default .file-other-error{float:left}.kv-rtl .krajee-default .file-drag-handle,.kv-rtl .krajee-default .file-upload-indicator,.kv-rtl .krajee-default.file-preview-frame{float:right}.kv-rtl .file-error-message pre,.kv-rtl .file-error-message ul,.kv-rtl .file-zoom-dialog{text-align:right}.kv-rtl{direction:rtl}.kv-rtl .floating-buttons{left:10px;right:auto}.kv-rtl .floating-buttons .btn-kv{margin-left:0;margin-right:3px}.kv-rtl .file-caption-icon{left:auto;right:8px}.kv-rtl .file-drop-zone{margin:12px 12px 12px 15px}.kv-rtl .btn-prev{right:1px;left:auto}.kv-rtl .btn-next{left:1px;right:auto}.kv-rtl .float-right,.kv-rtl .pull-right{float:left!important}.kv-rtl .float-left,.kv-rtl .pull-left{float:right!important}.kv-rtl .kv-zoom-title{direction:ltr}.kv-rtl .krajee-default.file-preview-frame{box-shadow:-1px 1px 5px 0 #a2958a}.kv-rtl .krajee-default.file-preview-frame:not(.file-preview-error):hover{box-shadow:-3px 3px 5px 0 #333}.kv-rtl .kv-zoom-actions .btn-kv{margin-left:0;margin-right:3px}.kv-rtl .file-caption.icon-visible .file-caption-name{padding-left:0;padding-right:15px}.kv-rtl .input-group-btn>.btn:last-child{border-radius:4px 0 0 4px}.kv-rtl .input-group .form-control:first-child{border-radius:0 4px 4px 0}.kv-rtl .btn-file input[type=file]{left:auto;right:0;text-align:left;background:100% 0 none}

+ 525 - 0
public/base/plugins/bootstrap-fileinput/css/fileinput.css

xqd
@@ -0,0 +1,525 @@
+/*!
+ * bootstrap-fileinput v4.5.2
+ * http://plugins.krajee.com/file-input
+ *
+ * Krajee default styling for bootstrap-fileinput.
+ *
+ * Author: Kartik Visweswaran
+ * Copyright: 2014 - 2018, Kartik Visweswaran, Krajee.com
+ *
+ * Licensed under the BSD 3-Clause
+ * https://github.com/kartik-v/bootstrap-fileinput/blob/master/LICENSE.md
+ */
+.file-loading input[type=file], input[type=file].file-loading {
+    width: 0;
+    height: 0;
+}
+
+.file-no-browse {
+    position: absolute;
+    left: 50%;
+    bottom: 20%;
+    width: 1px;
+    height: 1px;
+    font-size: 0;
+    opacity: 0;
+    border: none;
+    background: none;
+    outline: none;
+    box-shadow: none;
+}
+
+.kv-hidden, .file-caption-icon, .file-zoom-dialog .modal-header:before, .file-zoom-dialog .modal-header:after, .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-new .no-browse .input-group-btn, .file-input-ajax-new .fileinput-remove-button, .file-input-ajax-new .fileinput-upload-button, .file-input-ajax-new .no-browse .input-group-btn, .hide-content .kv-file-content {
+    display: none;
+}
+
+.btn-file input[type=file], .file-caption-icon, .file-preview .fileinput-remove, .krajee-default .file-thumb-progress, .file-zoom-dialog .btn-navigate, .file-zoom-dialog .floating-buttons {
+    position: absolute;
+}
+
+.file-input, .file-loading:before, .btn-file, .file-caption, .file-preview, .krajee-default.file-preview-frame, .krajee-default .file-thumbnail-footer, .file-zoom-dialog .modal-dialog {
+    position: relative;
+}
+
+.file-error-message pre, .file-error-message ul, .krajee-default .file-actions, .krajee-default .file-other-error {
+    text-align: left;
+}
+
+.file-error-message pre, .file-error-message ul {
+    margin: 0;
+}
+
+.krajee-default .file-drag-handle, .krajee-default .file-upload-indicator {
+    float: left;
+    margin: 5px 0 -5px;
+    width: 16px;
+    height: 16px;
+}
+
+.krajee-default .file-thumb-progress .progress, .krajee-default .file-thumb-progress .progress-bar {
+    height: 11px;
+    font-family: Verdana, Helvetica, sans-serif;
+    font-size: 9px;
+}
+
+.krajee-default .file-caption-info, .krajee-default .file-size-info {
+    display: block;
+    white-space: nowrap;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    width: 160px;
+    height: 15px;
+    margin: auto;
+}
+
+.file-zoom-content > .file-object.type-video, .file-zoom-content > .file-object.type-flash, .file-zoom-content > .file-object.type-image {
+    max-width: 100%;
+    max-height: 100%;
+    width: auto;
+}
+
+.file-zoom-content > .file-object.type-video, .file-zoom-content > .file-object.type-flash {
+    height: 100%;
+}
+
+.file-zoom-content > .file-object.type-pdf, .file-zoom-content > .file-object.type-html, .file-zoom-content > .file-object.type-text, .file-zoom-content > .file-object.type-default {
+    width: 100%;
+}
+
+.file-loading:before {
+    content: " Loading...";
+    display: inline-block;
+    padding-left: 20px;
+    line-height: 16px;
+    font-size: 13px;
+    font-variant: small-caps;
+    color: #999;
+    background: transparent url(../img/loading.gif) top left no-repeat;
+}
+
+.file-object {
+    margin: 0 0 -5px 0;
+    padding: 0;
+}
+
+.btn-file {
+    overflow: hidden;
+}
+
+.btn-file input[type=file] {
+    top: 0;
+    left: 0;
+    min-width: 100%;
+    min-height: 100%;
+    text-align: right;
+    opacity: 0;
+    background: none repeat scroll 0 0 transparent;
+    cursor: inherit;
+    display: block;
+}
+
+.btn-file ::-ms-browse {
+    font-size: 10000px;
+    width: 100%;
+    height: 100%;
+}
+
+.file-caption .file-caption-name {
+    width: 100%;
+    margin: 0;
+    padding: 0;
+    box-shadow: none;
+    border: none;
+    background: none;
+    outline: none;
+}
+
+.file-caption.icon-visible .file-caption-icon {
+    display: inline-block;
+}
+
+.file-caption.icon-visible .file-caption-name {
+    padding-left: 15px;
+}
+
+.file-caption-icon {
+    left: 8px;
+}
+
+.file-error-message {
+    color: #a94442;
+    background-color: #f2dede;
+    margin: 5px;
+    border: 1px solid #ebccd1;
+    border-radius: 4px;
+    padding: 15px;
+}
+
+.file-error-message pre {
+    margin: 5px 0;
+}
+
+.file-caption-disabled {
+    background-color: #eee;
+    cursor: not-allowed;
+    opacity: 1;
+}
+
+.file-preview {
+    border-radius: 5px;
+    border: 1px solid #ddd;
+    padding: 8px;
+    width: 100%;
+    margin-bottom: 5px;
+}
+
+.file-preview .btn-xs {
+    padding: 1px 5px;
+    font-size: 12px;
+    line-height: 1.5;
+    border-radius: 3px;
+}
+
+.file-preview .fileinput-remove {
+    top: 1px;
+    right: 1px;
+    line-height: 10px;
+}
+
+.file-preview .clickable {
+    cursor: pointer;
+}
+
+.file-preview-image {
+    font: 40px Impact, Charcoal, sans-serif;
+    color: #008000;
+}
+
+.krajee-default.file-preview-frame {
+    margin: 8px;
+    border: 1px solid rgba(0,0,0,0.2);
+    box-shadow: 0 0 10px 0 rgba(0,0,0,0.2);
+    padding: 6px;
+    float: left;
+    text-align: center;
+}
+
+.krajee-default.file-preview-frame .kv-file-content {
+    width: 213px;
+    height: 160px;
+}
+
+.krajee-default.file-preview-frame .kv-file-content.kv-pdf-rendered {
+    width: 400px;
+}
+
+.krajee-default.file-preview-frame[data-template="audio"] .kv-file-content {
+    width: 240px;
+    height: 55px;
+}
+
+.krajee-default.file-preview-frame .file-thumbnail-footer {
+    height: 70px;
+}
+
+.krajee-default.file-preview-frame:not(.file-preview-error):hover {
+    border: 1px solid rgba(0,0,0,0.3);
+    box-shadow: 0 0 10px 0 rgba(0,0,0,0.4);
+}
+
+.krajee-default .file-preview-text {
+    display: block;
+    color: #428bca;
+    border: 1px solid #ddd;
+    font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
+    outline: none;
+    padding: 8px;
+    resize: none;
+}
+
+.krajee-default .file-preview-html {
+    border: 1px solid #ddd;
+    padding: 8px;
+    overflow: auto;
+}
+
+.krajee-default .file-other-icon {
+    font-size: 6em;
+}
+
+.krajee-default .file-footer-buttons {
+    float: right;
+}
+
+.krajee-default .file-footer-caption {
+    display: block;
+    text-align: center;
+    padding-top: 4px;
+    font-size: 11px;
+    color: #777;
+    margin-bottom: 15px;
+}
+
+.krajee-default .file-preview-error {
+    opacity: 0.65;
+    box-shadow: none;
+}
+
+.krajee-default .file-thumb-progress {
+    height: 11px;
+    top: 37px;
+    left: 0;
+    right: 0;
+}
+
+.krajee-default.kvsortable-ghost {
+    background: #e1edf7;
+    border: 2px solid #a1abff;
+}
+
+.krajee-default .file-preview-other:hover {
+    opacity: 0.8;
+}
+
+.krajee-default .file-preview-frame:not(.file-preview-error) .file-footer-caption:hover {
+    color: #000;
+}
+
+.kv-upload-progress .progress {
+    height: 20px;
+    margin: 10px 0;
+    overflow: hidden;
+}
+
+.kv-upload-progress .progress-bar {
+    height: 20px;
+    font-family: Verdana, Helvetica, sans-serif;
+}
+
+/*noinspection CssOverwrittenProperties*/
+.file-zoom-dialog .file-other-icon {
+    font-size: 22em;
+    font-size: 50vmin;
+}
+
+.file-zoom-dialog .modal-dialog {
+    width: auto;
+}
+
+.file-zoom-dialog .modal-header {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+}
+
+.file-zoom-dialog .btn-navigate {
+    padding: 0;
+    margin: 0;
+    background: transparent;
+    text-decoration: none;
+    outline: none;
+    opacity: 0.7;
+    top: 45%;
+    font-size: 4em;
+    color: #1c94c4;
+}
+
+.file-zoom-dialog .btn-navigate:not([disabled]):hover {
+    outline: none;
+    box-shadow: none;
+    opacity: 0.6;
+}
+
+.file-zoom-dialog .floating-buttons {
+    top: 5px;
+    right: 10px;
+}
+
+.file-zoom-dialog .btn-navigate[disabled] {
+    opacity: 0.3;
+}
+
+.file-zoom-dialog .btn-prev {
+    left: 1px;
+}
+
+.file-zoom-dialog .btn-next {
+    right: 1px;
+}
+
+.file-zoom-dialog .kv-zoom-title {
+    font-weight: 300;
+    color: #999;
+    max-width: 50%;
+    overflow: hidden;
+    white-space: nowrap;
+    text-overflow: ellipsis;
+}
+
+.file-input-new .no-browse .form-control {
+    border-top-right-radius: 4px;
+    border-bottom-right-radius: 4px;
+}
+
+.file-input-ajax-new .no-browse .form-control {
+    border-top-right-radius: 4px;
+    border-bottom-right-radius: 4px;
+}
+
+.file-caption-main {
+    width: 100%;
+}
+
+.file-thumb-loading {
+    background: transparent url(../img/loading.gif) no-repeat scroll center center content-box !important;
+}
+
+.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.clickable:hover {
+    border: 2px dashed #999;
+}
+
+.file-drop-zone.clickable:focus {
+    border: 2px solid #5acde2;
+}
+
+.file-drop-zone .file-preview-thumbnails {
+    cursor: default;
+}
+
+.file-drop-zone-title {
+    color: #aaa;
+    font-size: 1.6em;
+    padding: 85px 10px;
+    cursor: default;
+}
+
+.file-highlighted {
+    border: 2px dashed #999 !important;
+    background-color: #eee;
+}
+
+.file-uploading {
+    background: url(../img/loading-sm.gif) no-repeat center bottom 10px;
+    opacity: 0.65;
+}
+
+.file-zoom-fullscreen .modal-dialog {
+    min-width: 100%;
+    margin: 0;
+}
+
+.file-zoom-fullscreen .modal-content {
+    border-radius: 0;
+    box-shadow: none;
+    min-height: 100vh;
+}
+
+.file-zoom-fullscreen .modal-body {
+    overflow-y: auto;
+}
+
+.floating-buttons {
+    z-index: 3000;
+}
+
+.floating-buttons .btn-kv {
+    margin-left: 3px;
+    z-index: 3000;
+}
+
+.file-zoom-content {
+    height: 480px;
+    text-align: center;
+}
+
+.file-zoom-content .file-preview-image {
+    max-height: 100%;
+}
+
+.file-zoom-content .file-preview-video {
+    max-height: 100%;
+}
+
+.file-zoom-content > .file-object.type-image {
+    height: auto;
+    min-height: inherit;
+}
+
+.file-zoom-content > .file-object.type-audio {
+    width: auto;
+    height: 30px;
+}
+
+@media (min-width: 576px) {
+    .file-zoom-dialog .modal-dialog {
+        max-width: 500px;
+    }
+}
+
+@media (min-width: 992px) {
+    .file-zoom-dialog .modal-lg {
+        max-width: 800px;
+    }
+}
+
+@media (max-width: 767px) {
+    .file-preview-thumbnails {
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        flex-direction: column;
+    }
+
+    .file-zoom-dialog .modal-header {
+        flex-direction: column;
+    }
+}
+
+@media (max-width: 350px) {
+    .krajee-default.file-preview-frame:not([data-template="audio"]) .kv-file-content {
+        width: 160px;
+    }
+}
+
+@media (max-width: 420px) {
+    .krajee-default.file-preview-frame .kv-file-content.kv-pdf-rendered {
+        width: 100%;
+    }
+}
+
+.file-loading[dir=rtl]:before {
+    background: transparent url(../img/loading.gif) top right no-repeat;
+    padding-left: 0;
+    padding-right: 20px;
+}
+
+.file-sortable .file-drag-handle {
+    cursor: move;
+    opacity: 1;
+}
+
+.file-sortable .file-drag-handle:hover {
+    opacity: 0.7;
+}
+
+.clickable .file-drop-zone-title {
+    cursor: pointer;
+}
+
+.kv-zoom-actions .btn-kv {
+    margin-left: 3px;
+}
+
+.file-preview-initial.sortable-chosen {
+    background-color: #d9edf7;
+}

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 11 - 0
public/base/plugins/bootstrap-fileinput/css/fileinput.min.css


+ 224 - 0
public/base/plugins/bootstrap-fileinput/examples/index.html

xqd
@@ -0,0 +1,224 @@
+<!DOCTYPE html>
+<!-- release v4.5.2, copyright 2014 - 2018 Kartik Visweswaran -->
+<!--suppress JSUnresolvedLibraryURL -->
+<html lang="en">
+<head>
+    <meta charset="UTF-8"/>
+    <title>Krajee JQuery Plugins - &copy; Kartik</title>
+    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" rel="stylesheet">
+    <link href="../css/fileinput.css" media="all" rel="stylesheet" type="text/css"/>
+    <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" media="all" rel="stylesheet" type="text/css"/>
+    <link href="../themes/explorer-fa/theme.css" media="all" rel="stylesheet" type="text/css"/>
+
+    <script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
+    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.11.0/umd/popper.min.js" type="text/javascript"></script>
+    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/js/bootstrap.min.js" type="text/javascript"></script>
+    <script src="../js/plugins/sortable.js" type="text/javascript"></script>
+    <script src="../js/fileinput.js" type="text/javascript"></script>
+    <script src="../js/locales/zh.js" type="text/javascript"></script>
+    <script src="../themes/explorer-fa/theme.js" type="text/javascript"></script>
+    <script src="../themes/fa/theme.js" type="text/javascript"></script>
+</head>
+<body>
+<div class="container kv-main">
+    <div class="page-header">
+        <h1>Bootstrap File Input Example
+            <small><a href="https://github.com/kartik-v/bootstrap-fileinput-samples"><i
+                    class="glyphicon glyphicon-download"></i> Download Sample Files</a></small>
+        </h1>
+    </div>
+    <form enctype="multipart/form-data">
+        <div class="file-loading">
+            <input id="kv-explorer" type="file" multiple>
+        </div>
+        <br>
+        <div class="file-loading">
+            <input id="file-0a" class="file" type="file" multiple data-min-file-count="1">
+        </div>
+        <br>
+        <button type="submit" class="btn btn-primary">Submit</button>
+        <button type="reset" class="btn btn-default">Reset</button>
+    </form>
+    <hr>
+    <form enctype="multipart/form-data">
+        <label for="file-0b">Test invalid input type</label>
+        <div class="file-loading">
+            <input id="file-0b" name="file-0b" class="file" type="text" multiple data-min-file-count="1">
+        </div>
+        <script>
+            $(document).on('ready', function () {
+                $("#file-0b").fileinput();
+            });
+        </script>
+    </form>
+    <hr>
+    <form enctype="multipart/form-data">
+        <div class="file-loading">
+            <input id="file-0c" class="file" type="file" multiple data-min-file-count="3">
+        </div>
+        <hr>
+        <div class="form-group">
+            <div class="file-loading">
+                <input id="file-0d" class="file" type="file">
+            </div>
+        </div>
+        <hr>
+        <div class="form-group">
+            <div class="file-loading">
+                <input id="file-1" type="file" multiple class="file" data-overwrite-initial="false" data-min-file-count="2">
+            </div>
+        </div>
+        <hr>
+        <div class="form-group">
+            <div class="file-loading">
+                <input id="file-2" type="file" class="file" readonly data-show-upload="false">
+            </div>
+        </div>
+        <hr>
+        <div class="form-group">
+            <div class="file-loading">
+                <label>Preview File Icon</label>
+                <input id="file-3" type="file" multiple>
+            </div>
+        </div>
+        <hr>
+        <div class="form-group">
+            <div class="file-loading">
+                <input id="file-4" type="file" class="file" data-upload-url="#">
+            </div>
+        </div>
+        <hr>
+        <div class="form-group">
+            <button class="btn btn-warning" type="button">Disable Test</button>
+            <button class="btn btn-info" type="reset">Refresh Test</button>
+            <button class="btn btn-primary">Submit</button>
+            <button class="btn btn-default" type="reset">Reset</button>
+        </div>
+        <hr>
+        <div class="form-group">
+            <div class="file-loading">
+                <input type="file" class="file" id="test-upload" multiple>
+            </div>
+            <div id="errorBlock" class="help-block"></div>
+        </div>
+        <hr>
+        <div class="form-group">
+            <div class="file-loading">
+                <input id="file-5" class="file" type="file" multiple data-preview-file-type="any" data-upload-url="#">
+            </div>
+        </div>
+    </form>
+
+
+    <hr>
+    <h4>Multi Language Inputs</h4>
+    <form enctype="multipart/form-data">
+        <label>French Input</label>
+        <div class="file-loading">
+            <input id="file-fr" name="file-fr[]" type="file" multiple>
+        </div>
+        <hr style="border: 2px dotted">
+        <label>Spanish Input</label>
+            <div class="file-loading">
+                <input id="file-es" name="file-es[]" type="file" multiple>
+            </div>
+    </form>
+    <hr>
+    <br>
+</div>
+</body>
+<script>
+    $('#file-fr').fileinput({
+        theme: 'fa',
+        language: 'zh',
+        uploadUrl: '#',
+        allowedFileExtensions: ['jpg', 'png', 'gif']
+    });
+
+
+    // $('#file-es').fileinput({
+    //     theme: 'fa',
+    //     language: 'es',
+    //     uploadUrl: '#',
+    //     allowedFileExtensions: ['jpg', 'png', 'gif']
+    // });
+    // $("#file-0").fileinput({
+    //     theme: 'fa',
+    //     'allowedFileExtensions': ['jpg', 'png', 'gif']
+    // });
+    // $("#file-1").fileinput({
+    //     theme: 'fa',
+    //     uploadUrl: '#', // you must set a valid URL here else you will get an error
+    //     allowedFileExtensions: ['jpg', 'png', 'gif'],
+    //     overwriteInitial: false,
+    //     maxFileSize: 1000,
+    //     maxFilesNum: 10,
+    //     //allowedFileTypes: ['image', 'video', 'flash'],
+    //     slugCallback: function (filename) {
+    //         return filename.replace('(', '_').replace(']', '_');
+    //     }
+    // });
+    //
+    // $("#file-3").fileinput({
+    //     theme: 'fa',
+    //     showUpload: false,
+    //     showCaption: false,
+    //     browseClass: "btn btn-primary btn-lg",
+    //     fileType: "any",
+    //     previewFileIcon: "<i class='glyphicon glyphicon-king'></i>",
+    //     overwriteInitial: false,
+    //     initialPreviewAsData: true,
+    //     initialPreview: [
+    //         "http://lorempixel.com/1920/1080/transport/1",
+    //         "http://lorempixel.com/1920/1080/transport/2",
+    //         "http://lorempixel.com/1920/1080/transport/3"
+    //     ],
+    //     initialPreviewConfig: [
+    //         {caption: "transport-1.jpg", size: 329892, width: "120px", url: "{$url}", key: 1},
+    //         {caption: "transport-2.jpg", size: 872378, width: "120px", url: "{$url}", key: 2},
+    //         {caption: "transport-3.jpg", size: 632762, width: "120px", url: "{$url}", key: 3}
+    //     ]
+    // });
+    // $("#file-4").fileinput({
+    //     theme: 'fa',
+    //     uploadExtraData: {kvId: '10'}
+    // });
+    $(".btn-warning").on('click', function () {
+        var $el = $("#file-4");
+        if ($el.attr('disabled')) {
+            $el.fileinput('enable');
+        } else {
+            $el.fileinput('disable');
+        }
+    });
+    $(".btn-info").on('click', function () {
+        $("#file-4").fileinput('refresh', {previewClass: 'bg-info'});
+    });
+
+    $(document).ready(function () {
+        $("#test-upload").fileinput({
+            'theme': 'fa',
+            'showPreview': false,
+            'allowedFileExtensions': ['jpg', 'png', 'gif'],
+            'elErrorContainer': '#errorBlock'
+        });
+        $("#kv-explorer").fileinput({
+            'theme': 'explorer-fa',
+            'uploadUrl': '#',
+            overwriteInitial: false,
+            initialPreviewAsData: true,
+            initialPreview: [
+                "http://lorempixel.com/1920/1080/nature/1",
+                "http://lorempixel.com/1920/1080/nature/2",
+                "http://lorempixel.com/1920/1080/nature/3"
+            ],
+            initialPreviewConfig: [
+                {caption: "nature-1.jpg", size: 329892, width: "120px", url: "{$url}", key: 1},
+                {caption: "nature-2.jpg", size: 872378, width: "120px", url: "{$url}", key: 2},
+                {caption: "nature-3.jpg", size: 632762, width: "120px", url: "{$url}", key: 3}
+            ]
+        });
+
+    });
+</script>
+</html>

binární
public/base/plugins/bootstrap-fileinput/img/loading-sm.gif


binární
public/base/plugins/bootstrap-fileinput/img/loading.gif


+ 4503 - 0
public/base/plugins/bootstrap-fileinput/js/fileinput.js

xqd
@@ -0,0 +1,4503 @@
+/*!
+ * bootstrap-fileinput v4.5.2
+ * http://plugins.krajee.com/file-input
+ *
+ * Author: Kartik Visweswaran
+ * Copyright: 2014 - 2018, Kartik Visweswaran, Krajee.com
+ *
+ * Licensed under the BSD 3-Clause
+ * https://github.com/kartik-v/bootstrap-fileinput/blob/master/LICENSE.md
+ */
+(function (factory) {
+    "use strict";
+    //noinspection JSUnresolvedVariable
+    if (typeof define === 'function' && define.amd) { // jshint ignore:line
+        // AMD. Register as an anonymous module.
+        define(['jquery'], factory); // jshint ignore:line
+    } else { // noinspection JSUnresolvedVariable
+        if (typeof module === 'object' && module.exports) { // jshint ignore:line
+            // Node/CommonJS
+            // noinspection JSUnresolvedVariable
+            module.exports = factory(require('jquery')); // jshint ignore:line
+        } else {
+            // Browser globals
+            factory(window.jQuery);
+        }
+    }
+}(function ($) {
+    "use strict";
+
+    $.fn.fileinputLocales = {};
+    $.fn.fileinputThemes = {};
+
+    String.prototype.setTokens = function (replacePairs) {
+        var str = this.toString(), key, re;
+        for (key in replacePairs) {
+            if (replacePairs.hasOwnProperty(key)) {
+                re = new RegExp("\{" + key + "\}", "g");
+                str = str.replace(re, replacePairs[key]);
+            }
+        }
+        return str;
+    };
+
+    var $h, FileInput;
+
+    // fileinput helper object for all global variables and internal helper methods
+    //noinspection JSUnresolvedVariable
+    $h = {
+        FRAMES: '.kv-preview-thumb',
+        SORT_CSS: 'file-sortable',
+        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' +
+        '<span class="{previewFileIconClass}">{previewFileIcon}</span>\n' +
+        '</div>',
+        MODAL_ID: 'kvFileinputModal',
+        MODAL_EVENTS: ['show', 'shown', 'hide', 'hidden', 'loaded'],
+        objUrl: window.URL || window.webkitURL,
+        compare: function (input, str, exact) {
+            return input !== undefined && (exact ? input === str : input.match(str));
+        },
+        isIE: function (ver) {
+            // check for IE versions < 11
+            if (navigator.appName !== 'Microsoft Internet Explorer') {
+                return false;
+            }
+            if (ver === 10) {
+                return new RegExp('msie\\s' + ver, 'i').test(navigator.userAgent);
+            }
+            var div = document.createElement("div"), status;
+            div.innerHTML = "<!--[if IE " + ver + "]> <i></i> <![endif]-->";
+            status = div.getElementsByTagName("i").length;
+            document.body.appendChild(div);
+            div.parentNode.removeChild(div);
+            return status;
+        },
+        canAssignFilesToInput: function () {
+            var input = document.createElement('input');
+            try {
+                input.type = "file";
+                input.files = null;
+                return true;
+            } catch (err) {
+                return false;
+            }
+        },
+        getDragDropFolders: function (items) {
+            var i, item, len = items.length, folders = 0;
+            if (len > 0 && items[0].webkitGetAsEntry()) {
+                for (i = 0; i < len; i++) {
+                    item = items[i].webkitGetAsEntry();
+                    if (item && item.isDirectory) {
+                        folders++;
+                    }
+                }
+            }
+            return folders;
+        },
+        initModal: function ($modal) {
+            var $body = $('body');
+            if ($body.length) {
+                $modal.appendTo($body);
+            }
+        },
+        isEmpty: function (value, trim) {
+            return value === undefined || value === null || value.length === 0 || (trim && $.trim(value) === '');
+        },
+        isArray: function (a) {
+            return Array.isArray(a) || Object.prototype.toString.call(a) === '[object Array]';
+        },
+        ifSet: function (needle, haystack, def) {
+            def = def || '';
+            return (haystack && typeof haystack === 'object' && needle in haystack) ? haystack[needle] : def;
+        },
+        cleanArray: function (arr) {
+            if (!(arr instanceof Array)) {
+                arr = [];
+            }
+            return arr.filter(function (e) {
+                return (e !== undefined && e !== null);
+            });
+        },
+        spliceArray: function (arr, index, reverseOrder) {
+            var i, j = 0, out = [], newArr;
+            if (!(arr instanceof Array)) {
+                return [];
+            }
+            newArr = $.extend(true, [], arr);
+            if (reverseOrder) {
+                newArr.reverse();
+            }
+            for (i = 0; i < newArr.length; i++) {
+                if (i !== index) {
+                    out[j] = newArr[i];
+                    j++;
+                }
+            }
+            if (reverseOrder) {
+                out.reverse();
+            }
+            return out;
+        },
+        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');
+            /** @namespace div.draggable */
+            /** @namespace div.ondragstart */
+            /** @namespace div.ondrop */
+            return !$h.isIE(9) &&
+                (div.draggable !== undefined || (div.ondragstart !== undefined && div.ondrop !== undefined));
+        },
+        hasFileUploadSupport: function () {
+            return $h.hasFileAPISupport() && window.FormData;
+        },
+        hasBlobSupport: function () {
+            try {
+                return !!window.Blob && Boolean(new Blob());
+            } catch (e) {
+                return false;
+            }
+        },
+        hasArrayBufferViewSupport: function () {
+            try {
+                return new Blob([new Uint8Array(100)]).size === 100;
+            } catch (e) {
+                return false;
+            }
+        },
+        dataURI2Blob: function (dataURI) {
+            //noinspection JSUnresolvedVariable
+            var BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder ||
+                window.MSBlobBuilder, canBlob = $h.hasBlobSupport(), byteStr, arrayBuffer, intArray, i, mimeStr, bb,
+                canProceed = (canBlob || BlobBuilder) && window.atob && window.ArrayBuffer && window.Uint8Array;
+            if (!canProceed) {
+                return null;
+            }
+            if (dataURI.split(',')[0].indexOf('base64') >= 0) {
+                byteStr = atob(dataURI.split(',')[1]);
+            } else {
+                byteStr = decodeURIComponent(dataURI.split(',')[1]);
+            }
+            arrayBuffer = new ArrayBuffer(byteStr.length);
+            intArray = new Uint8Array(arrayBuffer);
+            for (i = 0; i < byteStr.length; i += 1) {
+                intArray[i] = byteStr.charCodeAt(i);
+            }
+            mimeStr = dataURI.split(',')[0].split(':')[1].split(';')[0];
+            if (canBlob) {
+                return new Blob([$h.hasArrayBufferViewSupport() ? intArray : arrayBuffer], {type: mimeStr});
+            }
+            bb = new BlobBuilder();
+            bb.append(arrayBuffer);
+            return bb.getBlob(mimeStr);
+        },
+        arrayBuffer2String: function (buffer) {
+            //noinspection JSUnresolvedVariable
+            if (window.TextDecoder) {
+                // noinspection JSUnresolvedFunction
+                return new TextDecoder("utf-8").decode(buffer);
+            }
+            var array = Array.prototype.slice.apply(new Uint8Array(buffer)), out = '', i = 0, len, c, char2, char3;
+            len = array.length;
+            while (i < len) {
+                c = array[i++];
+                switch (c >> 4) { // jshint ignore:line
+                    case 0:
+                    case 1:
+                    case 2:
+                    case 3:
+                    case 4:
+                    case 5:
+                    case 6:
+                    case 7:
+                        // 0xxxxxxx
+                        out += String.fromCharCode(c);
+                        break;
+                    case 12:
+                    case 13:
+                        // 110x xxxx   10xx xxxx
+                        char2 = array[i++];
+                        out += String.fromCharCode(((c & 0x1F) << 6) | (char2 & 0x3F)); // jshint ignore:line
+                        break;
+                    case 14:
+                        // 1110 xxxx  10xx xxxx  10xx xxxx
+                        char2 = array[i++];
+                        char3 = array[i++];
+                        out += String.fromCharCode(((c & 0x0F) << 12) | // jshint ignore:line
+                            ((char2 & 0x3F) << 6) |  // jshint ignore:line
+                            ((char3 & 0x3F) << 0)); // jshint ignore:line
+                        break;
+                }
+            }
+            return out;
+        },
+        isHtml: function (str) {
+            var a = document.createElement('div');
+            a.innerHTML = str;
+            for (var c = a.childNodes, i = c.length; i--;) {
+                if (c[i].nodeType === 1) {
+                    return true;
+                }
+            }
+            return false;
+        },
+        isSvg: function (str) {
+            return str.match(/^\s*<\?xml/i) && (str.match(/<!DOCTYPE svg/i) || str.match(/<svg/i));
+        },
+        getMimeType: function (signature, contents, type) {
+            switch (signature) {
+                case "ffd8ffe0":
+                case "ffd8ffe1":
+                case "ffd8ffe2":
+                    return 'image/jpeg';
+                case '89504E47':
+                    return 'image/png';
+                case '47494638':
+                    return 'image/gif';
+                case '49492a00':
+                    return 'image/tiff';
+                case '52494646':
+                    return 'image/webp';
+                case '66747970':
+                    return 'video/3gp';
+                case '4f676753':
+                    return 'video/ogg';
+                case '1a45dfa3':
+                    return 'video/mkv';
+                case '000001ba':
+                case '000001b3':
+                    return 'video/mpeg';
+                case '3026b275':
+                    return 'video/wmv';
+                case '25504446':
+                    return 'application/pdf';
+                case '25215053':
+                    return 'application/ps';
+                case '504b0304':
+                case '504b0506':
+                case '504b0508':
+                    return 'application/zip';
+                case '377abcaf':
+                    return 'application/7z';
+                case '75737461':
+                    return 'application/tar';
+                case '7801730d':
+                    return 'application/dmg';
+                default:
+                    switch (signature.substring(0, 6)) {
+                        case '435753':
+                            return 'application/x-shockwave-flash';
+                        case '494433':
+                            return 'audio/mp3';
+                        case '425a68':
+                            return 'application/bzip';
+                        default:
+                            switch (signature.substring(0, 4)) {
+                                case '424d':
+                                    return 'image/bmp';
+                                case 'fffb':
+                                    return 'audio/mp3';
+                                case '4d5a':
+                                    return 'application/exe';
+                                case '1f9d':
+                                case '1fa0':
+                                    return 'application/zip';
+                                case '1f8b':
+                                    return 'application/gzip';
+                                default:
+                                    return contents && !contents.match(/[^\u0000-\u007f]/) ? 'application/text-plain' : type;
+                            }
+                    }
+            }
+        },
+        addCss: function ($el, css) {
+            $el.removeClass(css).addClass(css);
+        },
+        getElement: function (options, param, value) {
+            return ($h.isEmpty(options) || $h.isEmpty(options[param])) ? value : $(options[param]);
+        },
+        uniqId: function () {
+            return Math.round(new Date().getTime()) + '_' + Math.round(Math.random() * 100);
+        },
+        htmlEncode: function (str, undefVal) {
+            if (str === undefined) {
+                return undefVal || null;
+            }
+            return str.replace(/&/g, '&amp;')
+                .replace(/</g, '&lt;')
+                .replace(/>/g, '&gt;')
+                .replace(/"/g, '&quot;')
+                .replace(/'/g, '&apos;');
+        },
+        replaceTags: function (str, tags) {
+            var out = str;
+            if (!tags) {
+                return out;
+            }
+            $.each(tags, function (key, value) {
+                if (typeof value === "function") {
+                    value = value();
+                }
+                out = out.split(key).join(value);
+            });
+            return out;
+        },
+        cleanMemory: function ($thumb) {
+            var data = $thumb.is('img') ? $thumb.attr('src') : $thumb.find('source').attr('src');
+            /** @namespace $h.objUrl.revokeObjectURL */
+            $h.objUrl.revokeObjectURL(data);
+        },
+        findFileName: function (filePath) {
+            var sepIndex = filePath.lastIndexOf('/');
+            if (sepIndex === -1) {
+                sepIndex = filePath.lastIndexOf('\\');
+            }
+            return filePath.split(filePath.substring(sepIndex, sepIndex + 1)).pop();
+        },
+        checkFullScreen: function () {
+            //noinspection JSUnresolvedVariable
+            return document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement ||
+                document.msFullscreenElement;
+        },
+        toggleFullScreen: function (maximize) {
+            var doc = document, de = doc.documentElement;
+            if (de && maximize && !$h.checkFullScreen()) {
+                /** @namespace document.requestFullscreen */
+                /** @namespace document.msRequestFullscreen */
+                /** @namespace document.mozRequestFullScreen */
+                /** @namespace document.webkitRequestFullscreen */
+                /** @namespace Element.ALLOW_KEYBOARD_INPUT */
+                if (de.requestFullscreen) {
+                    de.requestFullscreen();
+                } else if (de.msRequestFullscreen) {
+                    de.msRequestFullscreen();
+                } else if (de.mozRequestFullScreen) {
+                    de.mozRequestFullScreen();
+                } else if (de.webkitRequestFullscreen) {
+                    de.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT);
+                }
+            } else {
+                /** @namespace document.exitFullscreen */
+                /** @namespace document.msExitFullscreen */
+                /** @namespace document.mozCancelFullScreen */
+                /** @namespace document.webkitExitFullscreen */
+                if (doc.exitFullscreen) {
+                    doc.exitFullscreen();
+                } else if (doc.msExitFullscreen) {
+                    doc.msExitFullscreen();
+                } else if (doc.mozCancelFullScreen) {
+                    doc.mozCancelFullScreen();
+                } else if (doc.webkitExitFullscreen) {
+                    doc.webkitExitFullscreen();
+                }
+            }
+        },
+        moveArray: function (arr, oldIndex, newIndex, reverseOrder) {
+            var newArr = $.extend(true, [], arr);
+            if (reverseOrder) {
+                newArr.reverse();
+            }
+            if (newIndex >= newArr.length) {
+                var k = newIndex - newArr.length;
+                while ((k--) + 1) {
+                    newArr.push(undefined);
+                }
+            }
+            newArr.splice(newIndex, 0, newArr.splice(oldIndex, 1)[0]);
+            if (reverseOrder) {
+                newArr.reverse();
+            }
+            return newArr;
+        },
+        cleanZoomCache: function ($el) {
+            var $cache = $el.closest('.kv-zoom-cache-theme');
+            if (!$cache.length) {
+                $cache = $el.closest('.kv-zoom-cache');
+            }
+            $cache.remove();
+        },
+        closeButton: function (css) {
+            css = css ? 'close ' + css : 'close';
+            return '<button type="button" class="' + css + '" aria-label="Close">\n' +
+                '  <span aria-hidden="true">&times;</span>\n' +
+                '</button>';
+        },
+        getRotation: function (value) {
+            switch (value) {
+                case 2:
+                    return 'rotateY(180deg)';
+                case 3:
+                    return 'rotate(180deg)';
+                case 4:
+                    return 'rotate(180deg) rotateY(180deg)';
+                case 5:
+                    return 'rotate(270deg) rotateY(180deg)';
+                case 6:
+                    return 'rotate(90deg)';
+                case 7:
+                    return 'rotate(90deg) rotateY(180deg)';
+                case 8:
+                    return 'rotate(270deg)';
+                default:
+                    return '';
+            }
+        },
+        setTransform: function (el, val) {
+            if (!el) {
+                return;
+            }
+            el.style.transform = val;
+            el.style.webkitTransform = val;
+            el.style['-moz-transform'] = val;
+            el.style['-ms-transform'] = val;
+            el.style['-o-transform'] = val;
+        },
+        setImageOrientation: function ($img, $zoomImg, value) {
+            if (!$img || !$img.length) {
+                return;
+            }
+            var ev = 'load.fileinputimageorient';
+            $img.off(ev).on(ev, function () {
+                var img = $img.get(0), zoomImg = $zoomImg && $zoomImg.length ? $zoomImg.get(0) : null,
+                    h = img.offsetHeight, w = img.offsetWidth, r = $h.getRotation(value);
+                $img.data('orientation', value);
+                if (zoomImg) {
+                    $zoomImg.data('orientation', value);
+                }
+                if (value < 5) {
+                    $h.setTransform(img, r);
+                    $h.setTransform(zoomImg, r);
+                    return;
+                }
+                var offsetAngle = Math.atan(w / h), origFactor = Math.sqrt(Math.pow(h, 2) + Math.pow(w, 2)),
+                    scale = !origFactor ? 1 : (h / Math.cos(Math.PI / 2 + offsetAngle)) / origFactor,
+                    s = ' scale(' + Math.abs(scale) + ')';
+                $h.setTransform(img, r + s);
+                $h.setTransform(zoomImg, r + s);
+            });
+        }
+    };
+    FileInput = function (element, options) {
+        var self = this;
+        self.$element = $(element);
+        self.$parent = self.$element.parent();
+        if (!self._validate()) {
+            return;
+        }
+        self.isPreviewable = $h.hasFileAPISupport();
+        self.isIE9 = $h.isIE(9);
+        self.isIE10 = $h.isIE(10);
+        if (self.isPreviewable || self.isIE9) {
+            self._init(options);
+            self._listen();
+        }
+        self.$element.removeClass('file-loading');
+    };
+    //noinspection JSUnusedGlobalSymbols
+    FileInput.prototype = {
+        constructor: FileInput,
+        _cleanup: function () {
+            var self = this;
+            self.reader = null;
+            self.formdata = {};
+            self.uploadCount = 0;
+            self.uploadStatus = {};
+            self.uploadLog = [];
+            self.uploadAsyncCount = 0;
+            self.loadedImages = [];
+            self.totalImagesCount = 0;
+            self.ajaxRequests = [];
+            self.clearStack();
+            self.fileBatchCompleted = true;
+            if (!self.isPreviewable) {
+                self.showPreview = false;
+            }
+            self.isError = false;
+            self.ajaxAborted = false;
+            self.cancelling = false;
+        },
+        _init: function (options, refreshMode) {
+            var self = this, f, $el = self.$element, $cont, t, tmp;
+            self.options = options;
+            $.each(options, function (key, value) {
+                switch (key) {
+                    case 'minFileCount':
+                    case 'maxFileCount':
+                    case 'minFileSize':
+                    case 'maxFileSize':
+                    case 'maxFilePreviewSize':
+                    case 'resizeImageQuality':
+                    case 'resizeIfSizeMoreThan':
+                    case 'progressUploadThreshold':
+                    case 'initialPreviewCount':
+                    case 'zoomModalHeight':
+                    case 'minImageHeight':
+                    case 'maxImageHeight':
+                    case 'minImageWidth':
+                    case 'maxImageWidth':
+                        self[key] = $h.getNum(value);
+                        break;
+                    default:
+                        self[key] = value;
+                        break;
+                }
+            });
+            if (self.rtl) { // swap buttons for rtl
+                tmp = self.previewZoomButtonIcons.prev;
+                self.previewZoomButtonIcons.prev = self.previewZoomButtonIcons.next;
+                self.previewZoomButtonIcons.next = tmp;
+            }
+            if (!refreshMode) {
+                self._cleanup();
+            }
+            self.$form = $el.closest('form');
+            self._initTemplateDefaults();
+            self.uploadFileAttr = !$h.isEmpty($el.attr('name')) ? $el.attr('name') : 'file_data';
+            t = self._getLayoutTemplate('progress');
+            self.progressTemplate = t.replace('{class}', self.progressClass);
+            self.progressCompleteTemplate = t.replace('{class}', self.progressCompleteClass);
+            self.progressErrorTemplate = t.replace('{class}', self.progressErrorClass);
+            self.isDisabled = $el.attr('disabled') || $el.attr('readonly');
+            if (self.isDisabled) {
+                $el.attr('disabled', true);
+            }
+            self.isClickable = self.browseOnZoneClick && self.showPreview &&
+                (self.dropZoneEnabled || !$h.isEmpty(self.defaultPreviewContent));
+            self.isAjaxUpload = $h.hasFileUploadSupport() && !$h.isEmpty(self.uploadUrl);
+            self.dropZoneEnabled = $h.hasDragDropSupport() && self.dropZoneEnabled;
+            if (!self.isAjaxUpload) {
+                self.dropZoneEnabled = self.dropZoneEnabled && $h.canAssignFilesToInput();
+            }
+            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 (!self.imageCanvas && self.resizeImage && (self.maxImageWidth || self.maxImageHeight)) {
+                self.imageCanvas = document.createElement('canvas');
+                self.imageCanvasContext = self.imageCanvas.getContext('2d');
+            }
+            if ($h.isEmpty($el.attr('id'))) {
+                $el.attr('id', $h.uniqId());
+            }
+            self.namespace = '.fileinput_' + $el.attr('id').replace(/-/g, '_');
+            if (self.$container === undefined) {
+                self.$container = self._createContainer();
+            } else {
+                self._refreshContainer();
+            }
+            $cont = self.$container;
+            self.$dropZone = $cont.find('.file-drop-zone');
+            self.$progress = $cont.find('.kv-upload-progress');
+            self.$btnUpload = $cont.find('.fileinput-upload');
+            self.$captionContainer = $h.getElement(options, 'elCaptionContainer', $cont.find('.file-caption'));
+            self.$caption = $h.getElement(options, 'elCaptionText', $cont.find('.file-caption-name'));
+            if (!$h.isEmpty(self.msgPlaceholder)) {
+                f = $el.attr('multiple') ? self.filePlural : self.fileSingle;
+                self.$caption.attr('placeholder', self.msgPlaceholder.replace('{files}', f));
+            }
+            self.$captionIcon = self.$captionContainer.find('.file-caption-icon');
+            self.$previewContainer = $h.getElement(options, 'elPreviewContainer', $cont.find('.file-preview'));
+            self.$preview = $h.getElement(options, 'elPreviewImage', $cont.find('.file-preview-thumbnails'));
+            self.$previewStatus = $h.getElement(options, 'elPreviewStatus', $cont.find('.file-preview-status'));
+            self.$errorContainer = $h.getElement(options, 'elErrorContainer', self.$previewContainer.find('.kv-fileinput-error'));
+            self._validateDisabled();
+            if (!$h.isEmpty(self.msgErrorClass)) {
+                $h.addCss(self.$errorContainer, self.msgErrorClass);
+            }
+            if (!refreshMode) {
+                self.$errorContainer.hide();
+                self.previewInitId = "preview-" + $h.uniqId();
+                self._initPreviewCache();
+                self._initPreview(true);
+                self._initPreviewActions();
+                if (self.$parent.hasClass('file-loading')) {
+                    self.$container.insertBefore(self.$parent);
+                    self.$parent.remove();
+                }
+            } else {
+                if (!self._errorsExist()) {
+                    self.$errorContainer.hide();
+                }
+            }
+            self._setFileDropZoneTitle();
+            if ($el.attr('disabled')) {
+                self.disable();
+            }
+            self._initZoom();
+            if (self.hideThumbnailContent) {
+                $h.addCss(self.$preview, 'hide-content');
+            }
+        },
+        _initTemplateDefaults: function () {
+            var self = this, tMain1, tMain2, tPreview, tFileIcon, tClose, tCaption, tBtnDefault, tBtnLink, tBtnBrowse,
+                tModalMain, tModal, tProgress, tSize, tFooter, tActions, tActionDelete, tActionUpload, tActionDownload,
+                tActionZoom, tActionDrag, tIndicator, tTagBef, tTagBef1, tTagBef2, tTagAft, tGeneric, tHtml, tImage,
+                tText, tOffice, tGdocs, tVideo, tAudio, tFlash, tObject, tPdf, tOther, tStyle, tZoomCache, vDefaultDim;
+            tMain1 = '{preview}\n' +
+                '<div class="kv-upload-progress kv-hidden"></div><div class="clearfix"></div>\n' +
+                '<div class="input-group {class}">\n' +
+                '  {caption}\n' +
+                '<div class="input-group-btn input-group-append">\n' +
+                '      {remove}\n' +
+                '      {cancel}\n' +
+                '      {upload}\n' +
+                '      {browse}\n' +
+                '    </div>\n' +
+                '</div>';
+            tMain2 = '{preview}\n<div class="kv-upload-progress kv-hidden"></div>\n<div class="clearfix"></div>\n{remove}\n{cancel}\n{upload}\n{browse}\n';
+            tPreview = '<div class="file-preview {class}">\n' +
+                '    {close}' +
+                '    <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>';
+            tClose = $h.closeButton('fileinput-remove');
+            tFileIcon = '<i class="glyphicon glyphicon-file"></i>';
+            // noinspection HtmlUnknownAttribute
+            tCaption = '<div class="file-caption form-control {class}" tabindex="500">\n' +
+                '  <span class="file-caption-icon"></span>\n' +
+                '  <input class="file-caption-name" onkeydown="return false;" onpaste="return false;">\n' +
+                '</div>';
+            //noinspection HtmlUnknownAttribute
+            tBtnDefault = '<button type="{type}" tabindex="500" title="{title}" class="{css}" ' +
+                '{status}>{icon} {label}</button>';
+            //noinspection HtmlUnknownAttribute
+            tBtnLink = '<a href="{href}" tabindex="500" title="{title}" class="{css}" {status}>{icon} {label}</a>';
+            //noinspection HtmlUnknownAttribute
+            tBtnBrowse = '<div tabindex="500" class="{css}" {status}>{icon} {label}</div>';
+            tModalMain = '<div id="' + $h.MODAL_ID + '" class="file-zoom-dialog modal fade" ' +
+                'tabindex="-1" aria-labelledby="' + $h.MODAL_ID + 'Label"></div>';
+            tModal = '<div class="modal-dialog modal-lg{rtl}" role="document">\n' +
+                '  <div class="modal-content">\n' +
+                '    <div class="modal-header">\n' +
+                '      <h5 class="modal-title">{heading}</h5>\n' +
+                '      <span class="kv-zoom-title"></span>\n' +
+                '      <div class="kv-zoom-actions">{toggleheader}{fullscreen}{borderless}{close}</div>\n' +
+                '    </div>\n' +
+                '    <div class="modal-body">\n' +
+                '      <div class="floating-buttons"></div>\n' +
+                '      <div class="kv-zoom-body file-zoom-content {zoomFrameClass}"></div>\n' + '{prev} {next}\n' +
+                '    </div>\n' +
+                '  </div>\n' +
+                '</div>\n';
+            tProgress = '<div class="progress">\n' +
+                '    <div class="{class}" role="progressbar"' +
+                ' aria-valuenow="{percent}" aria-valuemin="0" aria-valuemax="100" style="width:{percent}%;">\n' +
+                '        {status}\n' +
+                '     </div>\n' +
+                '</div>';
+            tSize = ' <samp>({sizeText})</samp>';
+            tFooter = '<div class="file-thumbnail-footer">\n' +
+                '    <div class="file-footer-caption" title="{caption}">\n' +
+                '        <div class="file-caption-info">{caption}</div>\n' +
+                '        <div class="file-size-info">{size}</div>\n' +
+                '    </div>\n' +
+                '    {progress}\n{indicator}\n{actions}\n' +
+                '</div>';
+            tActions = '<div class="file-actions">\n' +
+                '    <div class="file-footer-buttons">\n' +
+                '        {download} {upload} {delete} {zoom} {other}' +
+                '    </div>\n' +
+                '</div>\n' +
+                '{drag}\n' +
+                '<div class="clearfix"></div>';
+            //noinspection HtmlUnknownAttribute
+            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}</button>';
+            tActionDownload = '<a class="kv-file-download {downloadClass}" title="{downloadTitle}" ' +
+                'href="{downloadUrl}" download="{caption}" target="_blank">{downloadIcon}</a>';
+            tActionZoom = '<button type="button" class="kv-file-zoom {zoomClass}" ' +
+                'title="{zoomTitle}">{zoomIcon}</button>';
+            tActionDrag = '<span class="file-drag-handle {dragClass}" title="{dragTitle}">{dragIcon}</span>';
+            tIndicator = '<div class="file-upload-indicator" title="{indicatorTitle}">{indicator}</div>';
+            tTagBef = '<div class="file-preview-frame {frameClass}" id="{previewId}" data-fileindex="{fileindex}"' +
+                ' data-template="{template}"';
+            tTagBef1 = tTagBef + '><div class="kv-file-content">\n';
+            tTagBef2 = tTagBef + ' title="{caption}"><div class="kv-file-content">\n';
+            tTagAft = '</div>{footer}\n</div>\n';
+            tGeneric = '{content}\n';
+            tStyle = ' {style}';
+            tHtml = '<div class="kv-preview-data file-preview-html" title="{caption}"' + tStyle + '>{data}</div>\n';
+            tImage = '<img src="{data}" class="file-preview-image kv-preview-data" title="{caption}" ' +
+                'alt="{caption}"' + tStyle + '>\n';
+            tText = '<textarea class="kv-preview-data file-preview-text" title="{caption}" readonly' + tStyle + '>' +
+                '{data}</textarea>\n';
+            tOffice = '<iframe class="kv-preview-data file-preview-office" ' +
+                'src="https://view.officeapps.live.com/op/embed.aspx?src={data}"' + tStyle + '></iframe>';
+            tGdocs = '<iframe class="kv-preview-data file-preview-gdocs" ' +
+                'src="https://docs.google.com/gview?url={data}&embedded=true"' + tStyle + '></iframe>';
+            tVideo = '<video class="kv-preview-data file-preview-video" controls' + tStyle + '>\n' +
+                '<source src="{data}" type="{type}">\n' + $h.DEFAULT_PREVIEW + '\n</video>\n';
+            tAudio = '<!--suppress ALL --><audio class="kv-preview-data file-preview-audio" controls' + tStyle + '>\n<source src="{data}" ' +
+                'type="{type}">\n' + $h.DEFAULT_PREVIEW + '\n</audio>\n';
+            tFlash = '<embed class="kv-preview-data file-preview-flash" src="{data}" type="application/x-shockwave-flash"' + tStyle + '>\n';
+            tPdf = '<embed class="kv-preview-data file-preview-pdf" src="{data}" type="application/pdf"' + tStyle + '>\n';
+            tObject = '<object class="kv-preview-data file-preview-object file-object {typeCss}" ' +
+                'data="{data}" type="{type}"' + tStyle + '>\n' + '<param name="movie" value="{caption}" />\n' +
+                $h.OBJECT_PARAMS + ' ' + $h.DEFAULT_PREVIEW + '\n</object>\n';
+            tOther = '<div class="kv-preview-data file-preview-other-frame"' + tStyle + '>\n' + $h.DEFAULT_PREVIEW + '\n</div>\n';
+            tZoomCache = '<div class="kv-zoom-cache" style="display:none">{zoomContent}</div>';
+            vDefaultDim = {width: "100%", height: "100%", 'min-height': "480px"};
+            if (self._isPdfRendered()) {
+                tPdf = self.pdfRendererTemplate.replace('{renderer}', self._encodeURI(self.pdfRendererUrl));
+            }
+            self.defaults = {
+                layoutTemplates: {
+                    main1: tMain1,
+                    main2: tMain2,
+                    preview: tPreview,
+                    close: tClose,
+                    fileIcon: tFileIcon,
+                    caption: tCaption,
+                    modalMain: tModalMain,
+                    modal: tModal,
+                    progress: tProgress,
+                    size: tSize,
+                    footer: tFooter,
+                    indicator: tIndicator,
+                    actions: tActions,
+                    actionDelete: tActionDelete,
+                    actionUpload: tActionUpload,
+                    actionDownload: tActionDownload,
+                    actionZoom: tActionZoom,
+                    actionDrag: tActionDrag,
+                    btnDefault: tBtnDefault,
+                    btnLink: tBtnLink,
+                    btnBrowse: tBtnBrowse,
+                    zoomCache: tZoomCache
+                },
+                previewMarkupTags: {
+                    tagBefore1: tTagBef1,
+                    tagBefore2: tTagBef2,
+                    tagAfter: tTagAft
+                },
+                previewContentTemplates: {
+                    generic: tGeneric,
+                    html: tHtml,
+                    image: tImage,
+                    text: tText,
+                    office: tOffice,
+                    gdocs: tGdocs,
+                    video: tVideo,
+                    audio: tAudio,
+                    flash: tFlash,
+                    object: tObject,
+                    pdf: tPdf,
+                    other: tOther
+                },
+                allowedPreviewTypes: ['image', 'html', 'text', 'video', 'audio', 'flash', 'pdf', 'object'],
+                previewTemplates: {},
+                previewSettings: {
+                    image: {width: "auto", height: "auto", 'max-width': "100%", 'max-height': "100%"},
+                    html: {width: "213px", height: "160px"},
+                    text: {width: "213px", height: "160px"},
+                    office: {width: "213px", height: "160px"},
+                    gdocs: {width: "213px", height: "160px"},
+                    video: {width: "213px", height: "160px"},
+                    audio: {width: "100%", height: "30px"},
+                    flash: {width: "213px", height: "160px"},
+                    object: {width: "213px", height: "160px"},
+                    pdf: {width: "100%", height: "160px"},
+                    other: {width: "213px", height: "160px"}
+                },
+                previewSettingsSmall: {
+                    image: {width: "auto", height: "auto", 'max-width': "100%", 'max-height': "100%"},
+                    html: {width: "100%", height: "160px"},
+                    text: {width: "100%", height: "160px"},
+                    office: {width: "100%", height: "160px"},
+                    gdocs: {width: "100%", height: "160px"},
+                    video: {width: "100%", height: "auto"},
+                    audio: {width: "100%", height: "30px"},
+                    flash: {width: "100%", height: "auto"},
+                    object: {width: "100%", height: "auto"},
+                    pdf: {width: "100%", height: "160px"},
+                    other: {width: "100%", height: "160px"}
+                },
+                previewZoomSettings: {
+                    image: {width: "auto", height: "auto", 'max-width': "100%", 'max-height': "100%"},
+                    html: vDefaultDim,
+                    text: vDefaultDim,
+                    office: {width: "100%", height: "100%", 'max-width': "100%", 'min-height': "480px"},
+                    gdocs: {width: "100%", height: "100%", 'max-width': "100%", 'min-height': "480px"},
+                    video: {width: "auto", height: "100%", 'max-width': "100%"},
+                    audio: {width: "100%", height: "30px"},
+                    flash: {width: "auto", height: "480px"},
+                    object: {width: "auto", height: "100%", 'max-width': "100%", 'min-height': "480px"},
+                    pdf: vDefaultDim,
+                    other: {width: "auto", height: "100%", 'min-height': "480px"}
+                },
+                fileTypeSettings: {
+                    image: function (vType, vName) {
+                        return ($h.compare(vType, 'image.*') && !$h.compare(vType, /(tiff?|wmf)$/i) ||
+                            $h.compare(vName, /\.(gif|png|jpe?g)$/i));
+                    },
+                    html: function (vType, vName) {
+                        return $h.compare(vType, 'text/html') || $h.compare(vName, /\.(htm|html)$/i);
+                    },
+                    office: function (vType, vName) {
+                        return $h.compare(vType, /(word|excel|powerpoint|office)$/i) ||
+                            $h.compare(vName, /\.(docx?|xlsx?|pptx?|pps|potx?)$/i);
+                    },
+                    gdocs: function (vType, vName) {
+                        return $h.compare(vType, /(word|excel|powerpoint|office|iwork-pages|tiff?)$/i) ||
+                            $h.compare(vName, /\.(docx?|xlsx?|pptx?|pps|potx?|rtf|ods|odt|pages|ai|dxf|ttf|tiff?|wmf|e?ps)$/i);
+                    },
+                    text: function (vType, vName) {
+                        return $h.compare(vType, 'text.*') || $h.compare(vName, /\.(xml|javascript)$/i) ||
+                            $h.compare(vName, /\.(txt|md|csv|nfo|ini|json|php|js|css)$/i);
+                    },
+                    video: function (vType, vName) {
+                        return $h.compare(vType, 'video.*') && ($h.compare(vType, /(ogg|mp4|mp?g|mov|webm|3gp)$/i) ||
+                            $h.compare(vName, /\.(og?|mp4|webm|mp?g|mov|3gp)$/i));
+                    },
+                    audio: function (vType, vName) {
+                        return $h.compare(vType, 'audio.*') && ($h.compare(vName, /(ogg|mp3|mp?g|wav)$/i) ||
+                            $h.compare(vName, /\.(og?|mp3|mp?g|wav)$/i));
+                    },
+                    flash: function (vType, vName) {
+                        return $h.compare(vType, 'application/x-shockwave-flash', true) || $h.compare(vName, /\.(swf)$/i);
+                    },
+                    pdf: function (vType, vName) {
+                        return $h.compare(vType, 'application/pdf', true) || $h.compare(vName, /\.(pdf)$/i);
+                    },
+                    object: function () {
+                        return true;
+                    },
+                    other: function () {
+                        return true;
+                    }
+                },
+                fileActionSettings: {
+                    showRemove: true,
+                    showUpload: true,
+                    showDownload: true,
+                    showZoom: true,
+                    showDrag: true,
+                    removeIcon: '<i class="glyphicon glyphicon-trash"></i>',
+                    removeClass: 'btn btn-sm btn-kv btn-default btn-outline-secondary',
+                    removeErrorClass: 'btn btn-sm btn-kv btn-danger',
+                    removeTitle: 'Remove file',
+                    uploadIcon: '<i class="glyphicon glyphicon-upload"></i>',
+                    uploadClass: 'btn btn-sm btn-kv btn-default btn-outline-secondary',
+                    uploadTitle: 'Upload file',
+                    uploadRetryIcon: '<i class="glyphicon glyphicon-repeat"></i>',
+                    uploadRetryTitle: 'Retry upload',
+                    downloadIcon: '<i class="glyphicon glyphicon-download"></i>',
+                    downloadClass: 'btn btn-sm btn-kv btn-default btn-outline-secondary',
+                    downloadTitle: 'Download file',
+                    zoomIcon: '<i class="glyphicon glyphicon-zoom-in"></i>',
+                    zoomClass: 'btn btn-sm btn-kv btn-default btn-outline-secondary',
+                    zoomTitle: 'View Details',
+                    dragIcon: '<i class="glyphicon glyphicon-move"></i>',
+                    dragClass: 'text-info',
+                    dragTitle: 'Move / Rearrange',
+                    dragSettings: {},
+                    indicatorNew: '<i class="glyphicon glyphicon-plus-sign text-warning"></i>',
+                    indicatorSuccess: '<i class="glyphicon glyphicon-ok-sign text-success"></i>',
+                    indicatorError: '<i class="glyphicon glyphicon-exclamation-sign text-danger"></i>',
+                    indicatorLoading: '<i class="glyphicon glyphicon-hourglass text-muted"></i>',
+                    indicatorNewTitle: 'Not uploaded yet',
+                    indicatorSuccessTitle: 'Uploaded',
+                    indicatorErrorTitle: 'Upload Error',
+                    indicatorLoadingTitle: 'Uploading ...'
+                }
+            };
+            $.each(self.defaults, function (key, setting) {
+                if (key === 'allowedPreviewTypes') {
+                    if (self.allowedPreviewTypes === undefined) {
+                        self.allowedPreviewTypes = setting;
+                    }
+                    return;
+                }
+                self[key] = $.extend(true, {}, setting, self[key]);
+            });
+            self._initPreviewTemplates();
+        },
+        _initPreviewTemplates: function () {
+            var self = this, tags = self.previewMarkupTags, tagBef, tagAft = tags.tagAfter;
+            $.each(self.previewContentTemplates, function (key, value) {
+                if ($h.isEmpty(self.previewTemplates[key])) {
+                    tagBef = tags.tagBefore2;
+                    if (key === 'generic' || key === 'image' || key === 'html' || key === 'text') {
+                        tagBef = tags.tagBefore1;
+                    }
+                    if (self._isPdfRendered() && key === 'pdf') {
+                        tagBef = tagBef.replace('kv-file-content', 'kv-file-content kv-pdf-rendered');
+                    }
+                    self.previewTemplates[key] = tagBef + value + tagAft;
+                }
+            });
+        },
+        _initPreviewCache: function () {
+            var self = this;
+            self.previewCache = {
+                data: {},
+                init: function () {
+                    var content = self.initialPreview;
+                    if (content.length > 0 && !$h.isArray(content)) {
+                        content = content.split(self.initialPreviewDelimiter);
+                    }
+                    self.previewCache.data = {
+                        content: content,
+                        config: self.initialPreviewConfig,
+                        tags: self.initialPreviewThumbTags
+                    };
+                },
+                count: function () {
+                    return !!self.previewCache.data && !!self.previewCache.data.content ?
+                        self.previewCache.data.content.length : 0;
+                },
+                get: function (i, isDisabled) {
+                    var ind = 'init_' + i, data = self.previewCache.data, config = data.config[i],
+                        content = data.content[i], previewId = self.previewInitId + '-' + ind, out, $tmp, cat, ftr,
+                        fname, ftype, frameClass, asData = $h.ifSet('previewAsData', config, self.initialPreviewAsData),
+                        parseTemplate = function (cat, dat, fn, ft, id, ftr, ind, fc, t) {
+                            fc = ' file-preview-initial ' + $h.SORT_CSS + (fc ? ' ' + fc : '');
+                            return self._generatePreviewTemplate(cat, dat, fn, ft, id, false, null, fc, ftr, ind, t);
+                        };
+                    if (!content) {
+                        return '';
+                    }
+                    isDisabled = isDisabled === undefined ? true : isDisabled;
+                    cat = $h.ifSet('type', config, self.initialPreviewFileType || 'generic');
+                    fname = $h.ifSet('filename', config, $h.ifSet('caption', config));
+                    ftype = $h.ifSet('filetype', config, cat);
+                    ftr = self.previewCache.footer(i, isDisabled, (config && config.size || null));
+                    frameClass = $h.ifSet('frameClass', config);
+                    if (asData) {
+                        out = parseTemplate(cat, content, fname, ftype, previewId, ftr, ind, frameClass);
+                    } else {
+                        out = parseTemplate('generic', content, fname, ftype, previewId, ftr, ind, frameClass, cat)
+                            .setTokens({'content': data.content[i]});
+                    }
+                    if (data.tags.length && data.tags[i]) {
+                        out = $h.replaceTags(out, data.tags[i]);
+                    }
+                    /** @namespace config.frameAttr */
+                    if (!$h.isEmpty(config) && !$h.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 (content, config, tags, append) {
+                    var data = self.previewCache.data, index;
+                    if (!$h.isArray(content)) {
+                        content = content.split(self.initialPreviewDelimiter);
+                    }
+                    if (append) {
+                        index = data.content.push(content) - 1;
+                        data.config[index] = config;
+                        data.tags[index] = tags;
+                    } else {
+                        index = content.length - 1;
+                        data.content = content;
+                        data.config = config;
+                        data.tags = tags;
+                    }
+                    self.previewCache.data = data;
+                    return index;
+                },
+                set: function (content, config, tags, append) {
+                    var data = self.previewCache.data, i, chk;
+                    if (!content || !content.length) {
+                        return;
+                    }
+                    if (!$h.isArray(content)) {
+                        content = content.split(self.initialPreviewDelimiter);
+                    }
+                    chk = content.filter(function (n) {
+                        return n !== null;
+                    });
+                    if (!chk.length) {
+                        return;
+                    }
+                    if (data.content === undefined) {
+                        data.content = [];
+                    }
+                    if (data.config === undefined) {
+                        data.config = [];
+                    }
+                    if (data.tags === undefined) {
+                        data.tags = [];
+                    }
+                    if (append) {
+                        for (i = 0; i < content.length; i++) {
+                            if (content[i]) {
+                                data.content.push(content[i]);
+                            }
+                        }
+                        for (i = 0; i < config.length; i++) {
+                            if (config[i]) {
+                                data.config.push(config[i]);
+                            }
+                        }
+                        for (i = 0; i < tags.length; i++) {
+                            if (tags[i]) {
+                                data.tags.push(tags[i]);
+                            }
+                        }
+                    } else {
+                        data.content = content;
+                        data.config = config;
+                        data.tags = tags;
+                    }
+                    self.previewCache.data = data;
+                },
+                unset: function (index) {
+                    var chk = self.previewCache.count(), rev = self.reversePreviewOrder;
+                    if (!chk) {
+                        return;
+                    }
+                    if (chk === 1) {
+                        self.previewCache.data.content = [];
+                        self.previewCache.data.config = [];
+                        self.previewCache.data.tags = [];
+                        self.initialPreview = [];
+                        self.initialPreviewConfig = [];
+                        self.initialPreviewThumbTags = [];
+                        return;
+                    }
+                    self.previewCache.data.content = $h.spliceArray(self.previewCache.data.content, index, rev);
+                    self.previewCache.data.config = $h.spliceArray(self.previewCache.data.config, index, rev);
+                    self.previewCache.data.tags = $h.spliceArray(self.previewCache.data.tags, index, rev);
+                },
+                out: function () {
+                    var html = '', caption, len = self.previewCache.count(), i, content;
+                    if (len === 0) {
+                        return {content: '', caption: ''};
+                    }
+                    for (i = 0; i < len; i++) {
+                        content = self.previewCache.get(i);
+                        html = self.reversePreviewOrder ? (content + html) : (html + content);
+                    }
+                    caption = self._getMsgSelected(len);
+                    return {content: html, caption: caption};
+                },
+                footer: function (i, isDisabled, size) {
+                    var data = self.previewCache.data || {};
+                    if ($h.isEmpty(data.content)) {
+                        return '';
+                    }
+                    if ($h.isEmpty(data.config) || $h.isEmpty(data.config[i])) {
+                        data.config[i] = {};
+                    }
+                    isDisabled = isDisabled === undefined ? true : isDisabled;
+                    var config = data.config[i], caption = $h.ifSet('caption', config), a,
+                        width = $h.ifSet('width', config, 'auto'), url = $h.ifSet('url', config, false),
+                        key = $h.ifSet('key', config, null), fs = self.fileActionSettings,
+                        initPreviewShowDel = self.initialPreviewShowDelete || false,
+                        dUrl = config.downloadUrl || self.initialPreviewDownloadUrl || '',
+                        dFil = config.filename || config.caption || '',
+                        initPreviewShowDwl = !!(dUrl),
+                        sDel = $h.ifSet('showRemove', config, $h.ifSet('showRemove', fs, initPreviewShowDel)),
+                        sDwl = $h.ifSet('showDownload', config, $h.ifSet('showDownload', fs, initPreviewShowDwl)),
+                        sZm = $h.ifSet('showZoom', config, $h.ifSet('showZoom', fs, true)),
+                        sDrg = $h.ifSet('showDrag', config, $h.ifSet('showDrag', fs, true)),
+                        dis = (url === false) && isDisabled;
+                    sDwl = sDwl && config.downloadUrl !== false && !!dUrl;
+                    a = self._renderFileActions(false, sDwl, sDel, sZm, sDrg, dis, url, key, true, dUrl, dFil);
+                    return self._getLayoutTemplate('footer').setTokens({
+                        'progress': self._renderThumbProgress(),
+                        'actions': a,
+                        'caption': caption,
+                        'size': self._getSize(size),
+                        'width': width,
+                        'indicator': ''
+                    });
+                }
+            };
+            self.previewCache.init();
+        },
+        _isPdfRendered: function () {
+            var self = this, useLib = self.usePdfRenderer,
+                flag = typeof useLib === "function" ? useLib() : !!useLib;
+            return flag && self.pdfRendererUrl;
+        },
+        _handler: function ($el, event, callback) {
+            var self = this, ns = self.namespace, ev = event.split(' ').join(ns + ' ') + ns;
+            if (!$el || !$el.length) {
+                return;
+            }
+            $el.off(ev).on(ev, callback);
+        },
+        _encodeURI: function (vUrl) {
+            var self = this;
+            return self.encodeUrl ? encodeURI(vUrl) : vUrl;
+        },
+        _log: function (msg) {
+            var self = this, id = self.$element.attr('id');
+            if (id) {
+                msg = '"' + id + '": ' + msg;
+            }
+            msg = 'bootstrap-fileinput: ' + msg;
+            if (typeof window.console.log !== "undefined") {
+                window.console.log(msg);
+            } else {
+                window.alert(msg);
+            }
+        },
+        _validate: function () {
+            var self = this, status = self.$element.attr('type') === 'file';
+            if (!status) {
+                self._log('The input "type" must be set to "file" for initializing the "bootstrap-fileinput" plugin.');
+            }
+            return status;
+        },
+        _errorsExist: function () {
+            var self = this, $err, $errList = self.$errorContainer.find('li');
+            if ($errList.length) {
+                return true;
+            }
+            $err = $(document.createElement('div')).html(self.$errorContainer.html());
+            $err.find('.kv-error-close').remove();
+            $err.find('ul').remove();
+            return !!$.trim($err.text()).length;
+        },
+        _errorHandler: function (evt, caption) {
+            var self = this, err = evt.target.error, showError = function (msg) {
+                self._showError(msg.replace('{name}', caption));
+            };
+            /** @namespace err.NOT_FOUND_ERR */
+            /** @namespace err.SECURITY_ERR */
+            /** @namespace err.NOT_READABLE_ERR */
+            if (err.code === err.NOT_FOUND_ERR) {
+                showError(self.msgFileNotFound);
+            } else if (err.code === err.SECURITY_ERR) {
+                showError(self.msgFileSecured);
+            } else if (err.code === err.NOT_READABLE_ERR) {
+                showError(self.msgFileNotReadable);
+            } else if (err.code === err.ABORT_ERR) {
+                showError(self.msgFilePreviewAborted);
+            } else {
+                showError(self.msgFilePreviewError);
+            }
+        },
+        _addError: function (msg) {
+            var self = this, $error = self.$errorContainer;
+            if (msg && $error.length) {
+                $error.html(self.errorCloseButton + msg);
+                self._handler($error.find('.kv-error-close'), 'click', function () {
+                    setTimeout(function () {
+                        if (self.showPreview && !self.getFrames().length) {
+                            self.clear();
+                        }
+                        $error.fadeOut('slow');
+                    }, 10);
+                });
+            }
+        },
+        _setValidationError: function (css) {
+            var self = this;
+            css = (css ? css + ' ' : '') + 'has-error';
+            self.$container.removeClass(css).addClass('has-error');
+            $h.addCss(self.$captionContainer, 'is-invalid');
+        },
+        _resetErrors: function (fade) {
+            var self = this, $error = self.$errorContainer;
+            self.isError = false;
+            self.$container.removeClass('has-error');
+            self.$captionContainer.removeClass('is-invalid');
+            $error.html('');
+            if (fade) {
+                $error.fadeOut('slow');
+            } else {
+                $error.hide();
+            }
+        },
+        _showFolderError: function (folders) {
+            var self = this, $error = self.$errorContainer, msg;
+            if (!folders) {
+                return;
+            }
+            if (!self.isAjaxUpload) {
+                self._clearFileInput();
+            }
+            msg = self.msgFoldersNotAllowed.replace('{n}', folders);
+            self._addError(msg);
+            self._setValidationError();
+            $error.fadeIn(800);
+            self._raise('filefoldererror', [folders, msg]);
+        },
+        _showUploadError: function (msg, params, event) {
+            var self = this, $error = self.$errorContainer, ev = event || 'fileuploaderror', e = params && params.id ?
+                '<li data-file-id="' + params.id + '">' + msg + '</li>' : '<li>' + msg + '</li>';
+            if ($error.find('ul').length === 0) {
+                self._addError('<ul>' + e + '</ul>');
+            } else {
+                $error.find('ul').append(e);
+            }
+            $error.fadeIn(800);
+            self._raise(ev, [params, msg]);
+            self._setValidationError('file-input-new');
+            return true;
+        },
+        _showError: function (msg, params, event) {
+            var self = this, $error = self.$errorContainer, ev = event || 'fileerror';
+            params = params || {};
+            params.reader = self.reader;
+            self._addError(msg);
+            $error.fadeIn(800);
+            self._raise(ev, [params, msg]);
+            if (!self.isAjaxUpload) {
+                self._clearFileInput();
+            }
+            self._setValidationError('file-input-new');
+            self.$btnUpload.attr('disabled', true);
+            return true;
+        },
+        _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;
+            self._addError(msg);
+            self.isError = true;
+            self._updateFileDetails(0);
+            $error.fadeIn(800);
+            self._raise('fileerror', [params, msg]);
+            self._clearFileInput();
+            self._setValidationError();
+        },
+        _parseError: function (operation, jqXHR, errorThrown, fileName) {
+            /** @namespace jqXHR.responseJSON */
+            var self = this, errMsg = $.trim(errorThrown + ''), textPre,
+                text = jqXHR.responseJSON !== undefined && jqXHR.responseJSON.error !== undefined ?
+                    jqXHR.responseJSON.error : jqXHR.responseText;
+            if (self.cancelling && self.msgUploadAborted) {
+                errMsg = self.msgUploadAborted;
+            }
+            if (self.showAjaxErrorDetails && text) {
+                text = $.trim(text.replace(/\n\s*\n/g, '\n'));
+                textPre = text.length ? '<pre>' + text + '</pre>' : '';
+                errMsg += errMsg ? textPre : text;
+            }
+            if (!errMsg) {
+                errMsg = self.msgAjaxError.replace('{operation}', operation);
+            }
+            self.cancelling = false;
+            return fileName ? '<b>' + fileName + ': </b>' + errMsg : errMsg;
+        },
+        _parseFileType: function (type, name) {
+            var self = this, isValid, vType, cat, i, types = self.allowedPreviewTypes || [];
+            if (type === 'application/text-plain') {
+                return 'text';
+            }
+            for (i = 0; i < types.length; i++) {
+                cat = types[i];
+                isValid = self.fileTypeSettings[cat];
+                vType = isValid(type, name) ? cat : '';
+                if (!$h.isEmpty(vType)) {
+                    return vType;
+                }
+            }
+            return 'other';
+        },
+        _getPreviewIcon: function (fname) {
+            var self = this, ext, out = null;
+            if (fname && fname.indexOf('.') > -1) {
+                ext = fname.split('.').pop();
+                if (self.previewFileIconSettings) {
+                    out = self.previewFileIconSettings[ext] || self.previewFileIconSettings[ext.toLowerCase()] || null;
+                }
+                if (self.previewFileExtSettings) {
+                    $.each(self.previewFileExtSettings, function (key, func) {
+                        if (self.previewFileIconSettings[key] && func(ext)) {
+                            out = self.previewFileIconSettings[key];
+                            //noinspection UnnecessaryReturnStatementJS
+                            return;
+                        }
+                    });
+                }
+            }
+            return out;
+        },
+        _parseFilePreviewIcon: function (content, fname) {
+            var self = this, icn = self._getPreviewIcon(fname) || self.previewFileIcon, out = content;
+            if (out.indexOf('{previewFileIcon}') > -1) {
+                out = out.setTokens({'previewFileIconClass': self.previewFileIconClass, 'previewFileIcon': icn});
+            }
+            return out;
+        },
+        _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.isDefaultPrevented() || e.result === false) {
+                return false;
+            }
+            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:
+                    if (!self.ajaxAborted) {
+                        self.ajaxAborted = e.result;
+                    }
+                    break;
+            }
+            return true;
+        },
+        _listenFullScreen: function (isFullScreen) {
+            var self = this, $modal = self.$modal, $btnFull, $btnBord;
+            if (!$modal || !$modal.length) {
+                return;
+            }
+            $btnFull = $modal && $modal.find('.btn-fullscreen');
+            $btnBord = $modal && $modal.find('.btn-borderless');
+            if (!$btnFull.length || !$btnBord.length) {
+                return;
+            }
+            $btnFull.removeClass('active').attr('aria-pressed', 'false');
+            $btnBord.removeClass('active').attr('aria-pressed', 'false');
+            if (isFullScreen) {
+                $btnFull.addClass('active').attr('aria-pressed', 'true');
+            } else {
+                $btnBord.addClass('active').attr('aria-pressed', 'true');
+            }
+            if ($modal.hasClass('file-zoom-fullscreen')) {
+                self._maximizeZoomDialog();
+            } else {
+                if (isFullScreen) {
+                    self._maximizeZoomDialog();
+                } else {
+                    $btnBord.removeClass('active').attr('aria-pressed', 'false');
+                }
+            }
+        },
+        _listen: function () {
+            var self = this, $el = self.$element, $form = self.$form, $cont = self.$container, fullScreenEvents;
+            self._handler($el, 'click', function (e) {
+                if ($el.hasClass('file-no-browse')) {
+                    if ($el.data('zoneClicked')) {
+                        $el.data('zoneClicked', false);
+                    } else {
+                        e.preventDefault();
+                    }
+                }
+            });
+            self._handler($el, 'change', $.proxy(self._change, self));
+            if (self.showBrowse) {
+                self._handler(self.$btnFile, 'click', $.proxy(self._browse, self));
+            }
+            self._handler($cont.find('.fileinput-remove:not([disabled])'), 'click', $.proxy(self.clear, self));
+            self._handler($cont.find('.fileinput-cancel'), 'click', $.proxy(self.cancel, self));
+            self._initDragDrop();
+            self._handler($form, 'reset', $.proxy(self.clear, self));
+            if (!self.isAjaxUpload) {
+                self._handler($form, 'submit', $.proxy(self._submitForm, self));
+            }
+            self._handler(self.$container.find('.fileinput-upload'), 'click', $.proxy(self._uploadClick, self));
+            self._handler($(window), 'resize', function () {
+                self._listenFullScreen(screen.width === window.innerWidth && screen.height === window.innerHeight);
+            });
+            fullScreenEvents = 'webkitfullscreenchange mozfullscreenchange fullscreenchange MSFullscreenChange';
+            self._handler($(document), fullScreenEvents, function () {
+                self._listenFullScreen($h.checkFullScreen());
+            });
+            self._autoFitContent();
+            self._initClickable();
+            self._refreshPreview();
+        },
+        _autoFitContent: function () {
+            var width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth,
+                self = this, config = width < 400 ? (self.previewSettingsSmall || self.defaults.previewSettingsSmall) :
+                (self.previewSettings || self.defaults.previewSettings), sel;
+            $.each(config, function (cat, settings) {
+                sel = '.file-preview-frame .file-preview-' + cat;
+                self.$preview.find(sel + '.kv-preview-data,' + sel + ' .kv-preview-data').css(settings);
+            });
+        },
+        _scanDroppedItems: function (item, files, path) {
+            path = path || "";
+            var self = this, i, dirReader, readDir, errorHandler = function (e) {
+                self._log('Error scanning dropped files!');
+                self._log(e);
+            };
+            if (item.isFile) {
+                item.file(function (file) {
+                    files.push(file);
+                }, errorHandler);
+            } else {
+                if (item.isDirectory) {
+                    dirReader = item.createReader();
+                    readDir = function () {
+                        dirReader.readEntries(function (entries) {
+                            if (entries && entries.length > 0) {
+                                for (i = 0; i < entries.length; i++) {
+                                    self._scanDroppedItems(entries[i], files, path + item.name + "/");
+                                }
+                                // recursively call readDir() again, since browser can only handle first 100 entries.
+                                readDir();
+                            }
+                            return null;
+                        }, errorHandler);
+                    };
+                    readDir();
+                }
+            }
+
+        },
+        _initDragDrop: function () {
+            var self = this, $zone = self.$dropZone;
+            if (self.dropZoneEnabled && self.showPreview) {
+                self._handler($zone, 'dragenter dragover', $.proxy(self._zoneDragEnter, self));
+                self._handler($zone, 'dragleave', $.proxy(self._zoneDragLeave, self));
+                self._handler($zone, 'drop', $.proxy(self._zoneDrop, self));
+                self._handler($(document), 'dragenter dragover drop', self._zoneDragDropInit);
+            }
+        },
+        _zoneDragDropInit: function (e) {
+            e.stopPropagation();
+            e.preventDefault();
+        },
+        _zoneDragEnter: function (e) {
+            var self = this, hasFiles = $.inArray('Files', e.originalEvent.dataTransfer.types) > -1;
+            self._zoneDragDropInit(e);
+            if (self.isDisabled || !hasFiles) {
+                e.originalEvent.dataTransfer.effectAllowed = 'none';
+                e.originalEvent.dataTransfer.dropEffect = 'none';
+                return;
+            }
+            $h.addCss(self.$dropZone, 'file-highlighted');
+        },
+        _zoneDragLeave: function (e) {
+            var self = this;
+            self._zoneDragDropInit(e);
+            if (self.isDisabled) {
+                return;
+            }
+            self.$dropZone.removeClass('file-highlighted');
+        },
+        _zoneDrop: function (e) {
+            /** @namespace e.originalEvent.dataTransfer */
+            var self = this, i, $el = self.$element, dataTransfer = e.originalEvent.dataTransfer,
+                files = dataTransfer.files, items = dataTransfer.items, folders = $h.getDragDropFolders(items),
+                processFiles = function () {
+                    if (!self.isAjaxUpload) {
+                        self.changeTriggered = true;
+                        $el.get(0).files = files;
+                        setTimeout(function () {
+                            self.changeTriggered = false;
+                            $el.trigger('change' + self.namespace);
+                        }, 10);
+                    } else {
+                        self._change(e, files);
+                    }
+                    self.$dropZone.removeClass('file-highlighted');
+                };
+            e.preventDefault();
+            if (self.isDisabled || $h.isEmpty(files)) {
+                return;
+            }
+            if (folders > 0) {
+                if (!self.isAjaxUpload) {
+                    self._showFolderError(folders);
+                    return;
+                }
+                files = [];
+                for (i = 0; i < items.length; i++) {
+                    var item = items[i].webkitGetAsEntry();
+                    if (item) {
+                        self._scanDroppedItems(item, files);
+                    }
+                }
+                setTimeout(function () {
+                    processFiles();
+                }, 500);
+            } else {
+                processFiles();
+            }
+        },
+        _uploadClick: function (e) {
+            var self = this, $btn = self.$container.find('.fileinput-upload'), $form,
+                isEnabled = !$btn.hasClass('disabled') && $h.isEmpty($btn.attr('disabled'));
+            if (e && e.isDefaultPrevented()) {
+                return;
+            }
+            if (!self.isAjaxUpload) {
+                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;
+            return self._isFileSelectionValid() && !self._abort({});
+        },
+        _clearPreview: function () {
+            var self = this, $p = self.$preview,
+                $thumbs = self.showUploadedThumbs ? self.getFrames(':not(.file-preview-success)') : self.getFrames();
+            $thumbs.each(function () {
+                var $thumb = $(this);
+                $thumb.remove();
+                $h.cleanZoomCache($p.find('#zoom-' + $thumb.attr('id')));
+            });
+            if (!self.getFrames().length || !self.showPreview) {
+                self._resetUpload();
+            }
+            self._validateDefaultPreview();
+        },
+        _initSortable: function () {
+            var self = this, $el = self.$preview, settings, selector = '.' + $h.SORT_CSS,
+                rev = self.reversePreviewOrder;
+            if (!window.KvSortable || $el.find(selector).length === 0) {
+                return;
+            }
+            //noinspection JSUnusedGlobalSymbols
+            settings = {
+                handle: '.drag-handle-init',
+                dataIdAttr: 'data-preview-id',
+                scroll: false,
+                draggable: selector,
+                onSort: function (e) {
+                    var oldIndex = e.oldIndex, newIndex = e.newIndex, i = 0;
+                    self.initialPreview = $h.moveArray(self.initialPreview, oldIndex, newIndex, rev);
+                    self.initialPreviewConfig = $h.moveArray(self.initialPreviewConfig, oldIndex, newIndex, rev);
+                    self.previewCache.init();
+                    self.getFrames('.file-preview-initial').each(function () {
+                        $(this).attr('data-fileindex', 'init_' + i);
+                        i++;
+                    });
+                    self._raise('filesorted', {
+                        previewId: $(e.item).attr('id'),
+                        'oldIndex': oldIndex,
+                        'newIndex': newIndex,
+                        stack: self.initialPreviewConfig
+                    });
+                }
+            };
+            if ($el.data('kvsortable')) {
+                $el.kvsortable('destroy');
+            }
+            $.extend(true, settings, self.fileActionSettings.dragSettings);
+            $el.kvsortable(settings);
+        },
+        _setPreviewContent: function (content) {
+            var self = this;
+            self.$preview.html(content);
+            self._autoFitContent();
+        },
+        _initPreview: function (isInit) {
+            var self = this, cap = self.initialCaption || '', out;
+            if (!self.previewCache.count()) {
+                self._clearPreview();
+                if (isInit) {
+                    self._setCaption(cap);
+                } else {
+                    self._initCaption();
+                }
+                return;
+            }
+            out = self.previewCache.out();
+            cap = isInit && self.initialCaption ? self.initialCaption : out.caption;
+            self._setPreviewContent(out.content);
+            self._setInitThumbAttr();
+            self._setCaption(cap);
+            self._initSortable();
+            if (!$h.isEmpty(out.content)) {
+                self.$container.removeClass('file-input-new');
+            }
+        },
+        _getZoomButton: function (type) {
+            var self = this, label = self.previewZoomButtonIcons[type], css = self.previewZoomButtonClasses[type],
+                title = ' title="' + (self.previewZoomButtonTitles[type] || '') + '" ',
+                params = title + (type === 'close' ? ' data-dismiss="modal" aria-hidden="true"' : '');
+            if (type === 'fullscreen' || type === 'borderless' || type === 'toggleheader') {
+                params += ' data-toggle="button" aria-pressed="false" autocomplete="off"';
+            }
+            return '<button type="button" class="' + css + ' btn-' + type + '"' + params + '>' + label + '</button>';
+        },
+        _getModalContent: function () {
+            var self = this;
+            return self._getLayoutTemplate('modal').setTokens({
+                'rtl': self.rtl ? ' kv-rtl' : '',
+                'zoomFrameClass': self.frameClass,
+                'heading': self.msgZoomModalHeading,
+                'prev': self._getZoomButton('prev'),
+                'next': self._getZoomButton('next'),
+                'toggleheader': self._getZoomButton('toggleheader'),
+                'fullscreen': self._getZoomButton('fullscreen'),
+                'borderless': self._getZoomButton('borderless'),
+                'close': self._getZoomButton('close')
+            });
+        },
+        _listenModalEvent: function (event) {
+            var self = this, $modal = self.$modal, getParams = function (e) {
+                return {
+                    sourceEvent: e,
+                    previewId: $modal.data('previewId'),
+                    modal: $modal
+                };
+            };
+            $modal.on(event + '.bs.modal', function (e) {
+                var $btnFull = $modal.find('.btn-fullscreen'), $btnBord = $modal.find('.btn-borderless');
+                self._raise('filezoom' + event, getParams(e));
+                if (event === 'shown') {
+                    $btnBord.removeClass('active').attr('aria-pressed', 'false');
+                    $btnFull.removeClass('active').attr('aria-pressed', 'false');
+                    if ($modal.hasClass('file-zoom-fullscreen')) {
+                        self._maximizeZoomDialog();
+                        if ($h.checkFullScreen()) {
+                            $btnFull.addClass('active').attr('aria-pressed', 'true');
+                        } else {
+                            $btnBord.addClass('active').attr('aria-pressed', 'true');
+                        }
+                    }
+                }
+            });
+        },
+        _initZoom: function () {
+            var self = this, $dialog, modalMain = self._getLayoutTemplate('modalMain'), modalId = '#' + $h.MODAL_ID;
+            if (!self.showPreview) {
+                return;
+            }
+            self.$modal = $(modalId);
+            if (!self.$modal || !self.$modal.length) {
+                $dialog = $(document.createElement('div')).html(modalMain).insertAfter(self.$container);
+                self.$modal = $(modalId).insertBefore($dialog);
+                $dialog.remove();
+            }
+            $h.initModal(self.$modal);
+            self.$modal.html(self._getModalContent());
+            $.each($h.MODAL_EVENTS, function (key, event) {
+                self._listenModalEvent(event);
+            });
+        },
+        _initZoomButtons: function () {
+            var self = this, previewId = self.$modal.data('previewId') || '', $first, $last,
+                thumbs = self.getFrames().toArray(), len = thumbs.length, $prev = self.$modal.find('.btn-prev'),
+                $next = self.$modal.find('.btn-next');
+            if (thumbs.length < 2) {
+                $prev.hide();
+                $next.hide();
+                return;
+            } else {
+                $prev.show();
+                $next.show();
+            }
+            if (!len) {
+                return;
+            }
+            $first = $(thumbs[0]);
+            $last = $(thumbs[len - 1]);
+            $prev.removeAttr('disabled');
+            $next.removeAttr('disabled');
+            if ($first.length && $first.attr('id') === previewId) {
+                $prev.attr('disabled', true);
+            }
+            if ($last.length && $last.attr('id') === previewId) {
+                $next.attr('disabled', true);
+            }
+        },
+        _maximizeZoomDialog: function () {
+            var self = this, $modal = self.$modal, $head = $modal.find('.modal-header:visible'),
+                $foot = $modal.find('.modal-footer:visible'), $body = $modal.find('.modal-body'),
+                h = $(window).height(), diff = 0;
+            $modal.addClass('file-zoom-fullscreen');
+            if ($head && $head.length) {
+                h -= $head.outerHeight(true);
+            }
+            if ($foot && $foot.length) {
+                h -= $foot.outerHeight(true);
+            }
+            if ($body && $body.length) {
+                diff = $body.outerHeight(true) - $body.height();
+                h -= diff;
+            }
+            $modal.find('.kv-zoom-body').height(h);
+        },
+        _resizeZoomDialog: function (fullScreen) {
+            var self = this, $modal = self.$modal, $btnFull = $modal.find('.btn-fullscreen'),
+                $btnBord = $modal.find('.btn-borderless');
+            if ($modal.hasClass('file-zoom-fullscreen')) {
+                $h.toggleFullScreen(false);
+                if (!fullScreen) {
+                    if (!$btnFull.hasClass('active')) {
+                        $modal.removeClass('file-zoom-fullscreen');
+                        self.$modal.find('.kv-zoom-body').css('height', self.zoomModalHeight);
+                    } else {
+                        $btnFull.removeClass('active').attr('aria-pressed', 'false');
+                    }
+                } else {
+                    if (!$btnFull.hasClass('active')) {
+                        $modal.removeClass('file-zoom-fullscreen');
+                        self._resizeZoomDialog(true);
+                        if ($btnBord.hasClass('active')) {
+                            $btnBord.removeClass('active').attr('aria-pressed', 'false');
+                        }
+                    }
+                }
+            } else {
+                if (!fullScreen) {
+                    self._maximizeZoomDialog();
+                    return;
+                }
+                $h.toggleFullScreen(true);
+            }
+            $modal.focus();
+        },
+        _setZoomContent: function ($frame, animate) {
+            var self = this, $content, tmplt, body, title, $body, $dataEl, config, previewId = $frame.attr('id'),
+                $zoomPreview = self.$preview.find('#zoom-' + previewId), $modal = self.$modal, $tmp,
+                $btnFull = $modal.find('.btn-fullscreen'), $btnBord = $modal.find('.btn-borderless'), cap, size,
+                $btnTogh = $modal.find('.btn-toggleheader');
+            tmplt = $zoomPreview.attr('data-template') || 'generic';
+            $content = $zoomPreview.find('.kv-file-content');
+            body = $content.length ? $content.html() : '';
+            cap = $frame.data('caption') || '';
+            size = $frame.data('size') || '';
+            title = cap + ' ' + size;
+            $modal.find('.kv-zoom-title').attr('title', $('<div/>').html(title).text()).html(title);
+            $body = $modal.find('.kv-zoom-body');
+            $modal.removeClass('kv-single-content');
+            if (animate) {
+                $tmp = $body.addClass('file-thumb-loading').clone().insertAfter($body);
+                $body.html(body).hide();
+                $tmp.fadeOut('fast', function () {
+                    $body.fadeIn('fast', function () {
+                        $body.removeClass('file-thumb-loading');
+                    });
+                    $tmp.remove();
+                });
+            } else {
+                $body.html(body);
+            }
+            config = self.previewZoomSettings[tmplt];
+            if (config) {
+                $dataEl = $body.find('.kv-preview-data');
+                $h.addCss($dataEl, 'file-zoom-detail');
+                $.each(config, function (key, value) {
+                    $dataEl.css(key, value);
+                    if (($dataEl.attr('width') && key === 'width') || ($dataEl.attr('height') && key === 'height')) {
+                        $dataEl.removeAttr(key);
+                    }
+                });
+            }
+            $modal.data('previewId', previewId);
+            self._handler($modal.find('.btn-prev'), 'click', function () {
+                self._zoomSlideShow('prev', previewId);
+            });
+            self._handler($modal.find('.btn-next'), 'click', function () {
+                self._zoomSlideShow('next', previewId);
+            });
+            self._handler($btnFull, 'click', function () {
+                self._resizeZoomDialog(true);
+            });
+            self._handler($btnBord, 'click', function () {
+                self._resizeZoomDialog(false);
+            });
+            self._handler($btnTogh, 'click', function () {
+                var $header = $modal.find('.modal-header'), $floatBar = $modal.find('.modal-body .floating-buttons'),
+                    ht, $actions = $header.find('.kv-zoom-actions'), resize = function (height) {
+                        var $body = self.$modal.find('.kv-zoom-body'), h = self.zoomModalHeight;
+                        if ($modal.hasClass('file-zoom-fullscreen')) {
+                            h = $body.outerHeight(true);
+                            if (!height) {
+                                h = h - $header.outerHeight(true);
+                            }
+                        }
+                        $body.css('height', height ? h + height : h);
+                    };
+                if ($header.is(':visible')) {
+                    ht = $header.outerHeight(true);
+                    $header.slideUp('slow', function () {
+                        $actions.find('.btn').appendTo($floatBar);
+                        resize(ht);
+                    });
+                } else {
+                    $floatBar.find('.btn').appendTo($actions);
+                    $header.slideDown('slow', function () {
+                        resize();
+                    });
+                }
+                $modal.focus();
+            });
+            self._handler($modal, 'keydown', function (e) {
+                var key = e.which || e.keyCode, $prev = $(this).find('.btn-prev'), $next = $(this).find('.btn-next'),
+                    vId = $(this).data('previewId'), vPrevKey = self.rtl ? 39 : 37, vNextKey = self.rtl ? 37 : 39;
+                if (key === vPrevKey && $prev.length && !$prev.attr('disabled')) {
+                    self._zoomSlideShow('prev', vId);
+                }
+                if (key === vNextKey && $next.length && !$next.attr('disabled')) {
+                    self._zoomSlideShow('next', vId);
+                }
+            });
+        },
+        _zoomPreview: function ($btn) {
+            var self = this, $frame, $modal = self.$modal;
+            if (!$btn.length) {
+                throw 'Cannot zoom to detailed preview!';
+            }
+            $h.initModal($modal);
+            $modal.html(self._getModalContent());
+            $frame = $btn.closest($h.FRAMES);
+            self._setZoomContent($frame);
+            $modal.modal('show');
+            self._initZoomButtons();
+        },
+        _zoomSlideShow: function (dir, previewId) {
+            var self = this, $btn = self.$modal.find('.kv-zoom-actions .btn-' + dir), $targFrame, i,
+                thumbs = self.getFrames().toArray(), len = thumbs.length, out;
+            if ($btn.attr('disabled')) {
+                return;
+            }
+            for (i = 0; i < len; i++) {
+                if ($(thumbs[i]).attr('id') === previewId) {
+                    out = dir === 'prev' ? i - 1 : i + 1;
+                    break;
+                }
+            }
+            if (out < 0 || out >= len || !thumbs[out]) {
+                return;
+            }
+            $targFrame = $(thumbs[out]);
+            if ($targFrame.length) {
+                self._setZoomContent($targFrame, true);
+            }
+            self._initZoomButtons();
+            self._raise('filezoom' + dir, {'previewId': previewId, modal: self.$modal});
+        },
+        _initZoomButton: function () {
+            var self = this;
+            self.$preview.find('.kv-file-zoom').each(function () {
+                var $el = $(this);
+                self._handler($el, 'click', function () {
+                    self._zoomPreview($el);
+                });
+            });
+        },
+        _inputFileCount: function () {
+            return this.$element.get(0).files.length;
+        },
+        _refreshPreview: function () {
+            var self = this, files;
+            if (!self._inputFileCount() || !self.showPreview || !self.isPreviewable) {
+                return;
+            }
+            if (self.isAjaxUpload) {
+                files = self.getFileStack();
+                self.filestack = [];
+                if (files.length) {
+                    self._clearFileInput();
+                } else {
+                    files = self.$element.get(0).files;
+                }
+            } else {
+                files = self.$element.get(0).files;
+            }
+            if (files && files.length) {
+                self.readFiles(files);
+                self._setFileDropZoneTitle();
+            }
+        },
+        _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 (!self._inputFileCount()) {
+                return;
+            }
+            $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();
+        },
+        _resetUpload: function () {
+            var self = this;
+            self.uploadCache = {content: [], config: [], tags: [], append: true};
+            self.uploadCount = 0;
+            self.uploadStatus = {};
+            self.uploadLog = [];
+            self.uploadAsyncCount = 0;
+            self.loadedImages = [];
+            self.totalImagesCount = 0;
+            self.$btnUpload.removeAttr('disabled');
+            self._setProgress(0);
+            self.$progress.hide();
+            self._resetErrors(false);
+            self.ajaxAborted = false;
+            self.ajaxRequests = [];
+            self._resetCanvas();
+            self.cacheInitialPreview = {};
+            if (self.overwriteInitial) {
+                self.initialPreview = [];
+                self.initialPreviewConfig = [];
+                self.initialPreviewThumbTags = [];
+                self.previewCache.data = {
+                    content: [],
+                    config: [],
+                    tags: []
+                };
+            }
+        },
+        _resetCanvas: function () {
+            var self = this;
+            if (self.canvas && self.imageCanvasContext) {
+                self.imageCanvasContext.clearRect(0, 0, self.canvas.width, self.canvas.height);
+            }
+        },
+        _hasInitialPreview: function () {
+            var self = this;
+            return !self.overwriteInitial && self.previewCache.count();
+        },
+        _resetPreview: function () {
+            var self = this, out, cap;
+            if (self.previewCache.count()) {
+                out = self.previewCache.out();
+                self._setPreviewContent(out.content);
+                self._setInitThumbAttr();
+                cap = self.initialCaption ? self.initialCaption : out.caption;
+                self._setCaption(cap);
+            } else {
+                self._clearPreview();
+                self._initCaption();
+            }
+            if (self.showPreview) {
+                self._initZoom();
+                self._initSortable();
+            }
+        },
+        _clearDefaultPreview: function () {
+            var self = this;
+            self.$preview.find('.file-default-preview').remove();
+        },
+        _validateDefaultPreview: function () {
+            var self = this;
+            if (!self.showPreview || $h.isEmpty(self.defaultPreviewContent)) {
+                return;
+            }
+            self._setPreviewContent('<div class="file-default-preview">' + self.defaultPreviewContent + '</div>');
+            self.$container.removeClass('file-input-new');
+            self._initClickable();
+        },
+        _resetPreviewThumbs: function (isAjax) {
+            var self = this, out;
+            if (isAjax) {
+                self._clearPreview();
+                self.clearStack();
+                return;
+            }
+            if (self._hasInitialPreview()) {
+                out = self.previewCache.out();
+                self._setPreviewContent(out.content);
+                self._setInitThumbAttr();
+                self._setCaption(out.caption);
+                self._initPreviewActions();
+            } else {
+                self._clearPreview();
+            }
+        },
+        _getLayoutTemplate: function (t) {
+            var self = this, template = self.layoutTemplates[t];
+            if ($h.isEmpty(self.customLayoutTags)) {
+                return template;
+            }
+            return $h.replaceTags(template, self.customLayoutTags);
+        },
+        _getPreviewTemplate: function (t) {
+            var self = this, template = self.previewTemplates[t];
+            if ($h.isEmpty(self.customPreviewTags)) {
+                return template;
+            }
+            return $h.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,
+                filenames: self.filenames,
+                filescount: self.getFilesCount(),
+                extra: self._getExtraData(),
+                response: responseData,
+                reader: self.reader,
+                jqXHR: jqXHR
+            };
+        },
+        _getMsgSelected: function (n) {
+            var self = this, strFiles = n === 1 ? self.fileSingle : self.filePlural;
+            return n > 0 ? self.msgSelected.replace('{n}', n).replace('{files}', strFiles) : self.msgNoFilesSelected;
+        },
+        _getFrame: function (id) {
+            var self = this, $frame = $('#' + id);
+            if (!$frame.length) {
+                self._log('Invalid thumb frame with id: "' + id + '".');
+                return null;
+            }
+            return $frame;
+        },
+        _getThumbs: function (css) {
+            css = css || '';
+            return this.getFrames(':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;
+        },
+        _initXhr: function (xhrobj, previewId, fileCount) {
+            var self = this;
+            if (xhrobj.upload) {
+                xhrobj.upload.addEventListener('progress', function (event) {
+                    var pct = 0, total = event.total, position = event.loaded || event.position;
+                    /** @namespace event.lengthComputable */
+                    if (event.lengthComputable) {
+                        pct = Math.floor(position / total * 100);
+                    }
+                    if (previewId) {
+                        self._setAsyncUploadStatus(previewId, pct, fileCount);
+                    } else {
+                        self._setProgress(pct);
+                    }
+                }, false);
+            }
+            return xhrobj;
+        },
+        _initAjaxSettings: function () {
+            var self = this;
+            self._ajaxSettings = $.extend(true, {}, self.ajaxSettings);
+            self._ajaxDeleteSettings = $.extend(true, {}, self.ajaxDeleteSettings);
+        },
+        _mergeAjaxCallback: function (funcName, srcFunc, type) {
+            var self = this, settings = self._ajaxSettings, flag = self.mergeAjaxCallbacks, targFunc;
+            if (type === 'delete') {
+                settings = self._ajaxDeleteSettings;
+                flag = self.mergeAjaxDeleteCallbacks;
+            }
+            targFunc = settings[funcName];
+            if (flag && typeof targFunc === "function") {
+                if (flag === 'before') {
+                    settings[funcName] = function () {
+                        targFunc.apply(this, arguments);
+                        srcFunc.apply(this, arguments);
+                    };
+                } else {
+                    settings[funcName] = function () {
+                        srcFunc.apply(this, arguments);
+                        targFunc.apply(this, arguments);
+                    };
+                }
+            } else {
+                settings[funcName] = srcFunc;
+            }
+        },
+        _ajaxSubmit: function (fnBefore, fnSuccess, fnComplete, fnError, previewId, index) {
+            var self = this, settings, vUrl;
+            if (!self._raise('filepreajax', [previewId, index])) {
+                return;
+            }
+            self._uploadExtra(previewId, index);
+            self._initAjaxSettings();
+            self._mergeAjaxCallback('beforeSend', fnBefore);
+            self._mergeAjaxCallback('success', fnSuccess);
+            self._mergeAjaxCallback('complete', fnComplete);
+            self._mergeAjaxCallback('error', fnError);
+            vUrl = index && self.uploadUrlThumb ? self.uploadUrlThumb : self.uploadUrl;
+            settings = $.extend(true, {}, {
+                xhr: function () {
+                    var xhrobj = $.ajaxSettings.xhr();
+                    return self._initXhr(xhrobj, previewId, self.getFileStack().length);
+                },
+                url: self._encodeURI(vUrl),
+                type: 'POST',
+                dataType: 'json',
+                data: self.formdata,
+                cache: false,
+                processData: false,
+                contentType: false
+            }, self._ajaxSettings);
+            self.ajaxRequests.push($.ajax(settings));
+        },
+        _mergeArray: function (prop, content) {
+            var self = this, arr1 = $h.cleanArray(self[prop]), arr2 = $h.cleanArray(content);
+            self[prop] = arr1.concat(arr2);
+        },
+        _initUploadSuccess: function (out, $thumb, allFiles) {
+            var self = this, append, data, index, $div, $newCache, content, config, tags, i;
+            if (!self.showPreview || 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;
+                if (content.length > 0 && !$h.isArray(content)) {
+                    content = content.split(self.initialPreviewDelimiter);
+                }
+                self._mergeArray('initialPreview', content);
+                self._mergeArray('initialPreviewConfig', config);
+                self._mergeArray('initialPreviewThumbTags', tags);
+                if ($thumb !== undefined) {
+                    if (!allFiles) {
+                        index = self.previewCache.add(content, config[0], tags[0], append);
+                        data = self.previewCache.get(index, false);
+                        $div = $(document.createElement('div')).html(data).hide().insertAfter($thumb);
+                        $newCache = $div.find('.kv-zoom-cache');
+                        if ($newCache && $newCache.length) {
+                            $newCache.insertAfter($thumb);
+                        }
+                        $thumb.fadeOut('slow', function () {
+                            var $newThumb = $div.find('.file-preview-frame');
+                            if ($newThumb && $newThumb.length) {
+                                $newThumb.insertBefore($thumb).fadeIn('slow').css('display:inline-block');
+                            }
+                            self._initPreviewActions();
+                            self._clearFileInput();
+                            $h.cleanZoomCache(self.$preview.find('#zoom-' + $thumb.attr('id')));
+                            $thumb.remove();
+                            $div.remove();
+                            self._initSortable();
+                        });
+                    } else {
+                        i = $thumb.attr('data-fileindex');
+                        self.uploadCache.content[i] = content[0];
+                        self.uploadCache.config[i] = config[0] || [];
+                        self.uploadCache.tags[i] = tags[0] || [];
+                        self.uploadCache.append = append;
+                    }
+                } else {
+                    self.previewCache.set(content, config, tags, append);
+                    self._initPreview();
+                    self._initPreviewActions();
+                }
+            }
+        },
+        _initSuccessThumbs: function () {
+            var self = this;
+            if (!self.showPreview) {
+                return;
+            }
+            self._getThumbs($h.FRAMES + '.file-preview-success').each(function () {
+                var $thumb = $(this), $preview = self.$preview, $remove = $thumb.find('.kv-file-remove');
+                $remove.removeAttr('disabled');
+                self._handler($remove, 'click', function () {
+                    var id = $thumb.attr('id'),
+                        out = self._raise('filesuccessremove', [id, $thumb.attr('data-fileindex')]);
+                    $h.cleanMemory($thumb);
+                    if (out === false) {
+                        return;
+                    }
+                    $thumb.fadeOut('slow', function () {
+                        $h.cleanZoomCache($preview.find('#zoom-' + id));
+                        $thumb.remove();
+                        if (!self.getFrames().length) {
+                            self.reset();
+                        }
+                    });
+                });
+            });
+        },
+        _checkAsyncComplete: function () {
+            var self = this, previewId, i;
+            for (i = 0; i < self.filestack.length; i++) {
+                if (self.filestack[i]) {
+                    previewId = self.previewInitId + "-" + i;
+                    if ($.inArray(previewId, self.uploadLog) === -1) {
+                        return false;
+                    }
+                }
+            }
+            return (self.uploadAsyncCount === self.uploadLog.length);
+        },
+        _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);
+            });
+        },
+        _uploadSingle: function (i, isBatch) {
+            var self = this, total = self.getFileStack().length, formdata = new FormData(), outData,
+                previewId = self.previewInitId + "-" + i, $thumb, chkComplete, $btnUpload, $btnDelete,
+                hasPostData = self.filestack.length > 0 || !$.isEmptyObject(self.uploadExtraData), uploadFailed,
+                $prog = $('#' + previewId).find('.file-thumb-progress'), fnBefore, fnSuccess, fnComplete, fnError,
+                updateUploadLog, params = {id: previewId, index: i};
+            self.formdata = formdata;
+            if (self.showPreview) {
+                $thumb = $('#' + previewId + ':not(.file-preview-initial)');
+                $btnUpload = $thumb.find('.kv-file-upload');
+                $btnDelete = $thumb.find('.kv-file-remove');
+                $prog.show();
+            }
+            if (total === 0 || !hasPostData || ($btnUpload && $btnUpload.hasClass('disabled')) || self._abort(params)) {
+                return;
+            }
+            updateUploadLog = function (i, previewId) {
+                if (!uploadFailed) {
+                    self.updateStack(i, undefined);
+                }
+                self.uploadLog.push(previewId);
+                if (self._checkAsyncComplete()) {
+                    self.fileBatchCompleted = true;
+                }
+            };
+            chkComplete = function () {
+                var u = self.uploadCache, $initThumbs, i, j, len = 0, data = self.cacheInitialPreview;
+                if (!self.fileBatchCompleted) {
+                    return;
+                }
+                if (data && data.content) {
+                    len = data.content.length;
+                }
+                setTimeout(function () {
+                    var triggerReset = self.getFileStack(true).length === 0;
+                    if (self.showPreview) {
+                        self.previewCache.set(u.content, u.config, u.tags, u.append);
+                        if (len) {
+                            for (i = 0; i < u.content.length; i++) {
+                                j = i + len;
+                                data.content[j] = u.content[i];
+                                //noinspection JSUnresolvedVariable
+                                if (data.config.length) {
+                                    data.config[j] = u.config[i];
+                                }
+                                if (data.tags.length) {
+                                    data.tags[j] = u.tags[i];
+                                }
+                            }
+                            self.initialPreview = $h.cleanArray(data.content);
+                            self.initialPreviewConfig = $h.cleanArray(data.config);
+                            self.initialPreviewThumbTags = $h.cleanArray(data.tags);
+                        } else {
+                            self.initialPreview = u.content;
+                            self.initialPreviewConfig = u.config;
+                            self.initialPreviewThumbTags = u.tags;
+                        }
+                        self.cacheInitialPreview = {};
+                        if (self.hasInitData) {
+                            self._initPreview();
+                            self._initPreviewActions();
+                        }
+                    }
+                    self.unlock(triggerReset);
+                    if (triggerReset) {
+                        self._clearFileInput();
+                    }
+                    $initThumbs = self.$preview.find('.file-preview-initial');
+                    if (self.uploadAsync && $initThumbs.length) {
+                        $h.addCss($initThumbs, $h.SORT_CSS);
+                        self._initSortable();
+                    }
+                    self._raise('filebatchuploadcomplete', [self.filestack, self._getExtraData()]);
+                    self.uploadCount = 0;
+                    self.uploadStatus = {};
+                    self.uploadLog = [];
+                    self._setProgress(101);
+                    self.ajaxAborted = false;
+                }, 100);
+            };
+            fnBefore = function (jqXHR) {
+                outData = self._getOutData(jqXHR);
+                self.fileBatchCompleted = false;
+                if (!isBatch) {
+                    self.ajaxAborted = false;
+                }
+                if (self.showPreview) {
+                    if (!$thumb.hasClass('file-preview-success')) {
+                        self._setThumbStatus($thumb, 'Loading');
+                        $h.addCss($thumb, 'file-uploading');
+                    }
+                    $btnUpload.attr('disabled', true);
+                    $btnDelete.attr('disabled', true);
+                }
+                if (!isBatch) {
+                    self.lock();
+                }
+                self._raise('filepreupload', [outData, previewId, i]);
+                $.extend(true, params, outData);
+                if (self._abort(params)) {
+                    jqXHR.abort();
+                    if (!isBatch) {
+                        self._setThumbStatus($thumb, 'New');
+                        $thumb.removeClass('file-uploading');
+                        $btnUpload.removeAttr('disabled');
+                        $btnDelete.removeAttr('disabled');
+                        self.unlock();
+                    }
+                    self._setProgressCancelled();
+                }
+            };
+            fnSuccess = function (data, textStatus, jqXHR) {
+                var pid = self.showPreview && $thumb.attr('id') ? $thumb.attr('id') : previewId;
+                outData = self._getOutData(jqXHR, data);
+                $.extend(true, params, outData);
+                setTimeout(function () {
+                    if ($h.isEmpty(data) || $h.isEmpty(data.error)) {
+                        if (self.showPreview) {
+                            self._setThumbStatus($thumb, 'Success');
+                            $btnUpload.hide();
+                            self._initUploadSuccess(data, $thumb, isBatch);
+                            self._setProgress(101, $prog);
+                        }
+                        self._raise('fileuploaded', [outData, pid, i]);
+                        if (!isBatch) {
+                            self.updateStack(i, undefined);
+                        } else {
+                            updateUploadLog(i, pid);
+                        }
+                    } else {
+                        uploadFailed = true;
+                        self._showUploadError(data.error, params);
+                        self._setPreviewError($thumb, i, self.filestack[i], self.retryErrorUploads);
+                        if (!self.retryErrorUploads) {
+                            $btnUpload.hide();
+                        }
+                        if (isBatch) {
+                            updateUploadLog(i, pid);
+                        }
+                        self._setProgress(101, $('#' + pid).find('.file-thumb-progress'), self.msgUploadError);
+                    }
+                }, 100);
+            };
+            fnComplete = function () {
+                setTimeout(function () {
+                    if (self.showPreview) {
+                        $btnUpload.removeAttr('disabled');
+                        $btnDelete.removeAttr('disabled');
+                        $thumb.removeClass('file-uploading');
+                    }
+                    if (!isBatch) {
+                        self.unlock(false);
+                        self._clearFileInput();
+                    } else {
+                        chkComplete();
+                    }
+                    self._initSuccessThumbs();
+                }, 100);
+            };
+            fnError = function (jqXHR, textStatus, errorThrown) {
+                var op = self.ajaxOperations.uploadThumb,
+                    errMsg = self._parseError(op, jqXHR, errorThrown, (isBatch && self.filestack[i].name ? self.filestack[i].name : null));
+                uploadFailed = true;
+                setTimeout(function () {
+                    if (isBatch) {
+                        updateUploadLog(i, previewId);
+                    }
+                    self.uploadStatus[previewId] = 100;
+                    self._setPreviewError($thumb, i, self.filestack[i], self.retryErrorUploads);
+                    if (!self.retryErrorUploads) {
+                        $btnUpload.hide();
+                    }
+                    $.extend(true, params, self._getOutData(jqXHR));
+                    self._setProgress(101, $prog, self.msgAjaxProgressError.replace('{operation}', op));
+                    self._setProgress(101, $('#' + previewId).find('.file-thumb-progress'), self.msgUploadError);
+                    self._showUploadError(errMsg, params);
+                }, 100);
+            };
+            formdata.append(self.uploadFileAttr, self.filestack[i], self.filenames[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, params = {}, fnBefore, fnSuccess, fnError,
+                fnComplete, hasPostData = self.filestack.length > 0 || !$.isEmptyObject(self.uploadExtraData),
+                setAllUploaded;
+            self.formdata = new FormData();
+            if (total === 0 || !hasPostData || self._abort(params)) {
+                return;
+            }
+            setAllUploaded = function () {
+                $.each(files, function (key) {
+                    self.updateStack(key, undefined);
+                });
+                self._clearFileInput();
+            };
+            fnBefore = function (jqXHR) {
+                self.lock();
+                var outData = self._getOutData(jqXHR);
+                self.ajaxAborted = false;
+                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');
+                            $h.addCss($thumb, 'file-uploading');
+                        }
+                        $btnUpload.attr('disabled', true);
+                        $btnDelete.attr('disabled', true);
+                    });
+                }
+                self._raise('filebatchpreupload', [outData]);
+                if (self._abort(outData)) {
+                    jqXHR.abort();
+                    self._getThumbs().each(function () {
+                        var $thumb = $(this), $btnUpload = $thumb.find('.kv-file-upload'),
+                            $btnDelete = $thumb.find('.kv-file-remove');
+                        if ($thumb.hasClass('file-preview-loading')) {
+                            self._setThumbStatus($thumb, 'New');
+                            $thumb.removeClass('file-uploading');
+                        }
+                        $btnUpload.removeAttr('disabled');
+                        $btnDelete.removeAttr('disabled');
+                    });
+                    self._setProgressCancelled();
+                }
+            };
+            fnSuccess = function (data, textStatus, jqXHR) {
+                /** @namespace data.errorkeys */
+                var outData = self._getOutData(jqXHR, data), key = 0,
+                    $thumbs = self._getThumbs(':not(.file-preview-success)'),
+                    keys = $h.isEmpty(data) || $h.isEmpty(data.errorkeys) ? [] : data.errorkeys;
+
+                if ($h.isEmpty(data) || $h.isEmpty(data.error)) {
+                    self._raise('filebatchuploadsuccess', [outData]);
+                    setAllUploaded();
+                    if (self.showPreview) {
+                        $thumbs.each(function () {
+                            var $thumb = $(this);
+                            self._setThumbStatus($thumb, 'Success');
+                            $thumb.removeClass('file-uploading');
+                            $thumb.find('.kv-file-upload').hide().removeAttr('disabled');
+                        });
+                        self._initUploadSuccess(data);
+                    } else {
+                        self.reset();
+                    }
+                    self._setProgress(101);
+                } else {
+                    if (self.showPreview) {
+                        $thumbs.each(function () {
+                            var $thumb = $(this), i = $thumb.attr('data-fileindex');
+                            $thumb.removeClass('file-uploading');
+                            $thumb.find('.kv-file-upload').removeAttr('disabled');
+                            $thumb.find('.kv-file-remove').removeAttr('disabled');
+                            if (keys.length === 0 || $.inArray(key, keys) !== -1) {
+                                self._setPreviewError($thumb, i, self.filestack[i], self.retryErrorUploads);
+                                if (!self.retryErrorUploads) {
+                                    $thumb.find('.kv-file-upload').hide();
+                                    self.updateStack(i, undefined);
+                                }
+                            } else {
+                                $thumb.find('.kv-file-upload').hide();
+                                self._setThumbStatus($thumb, 'Success');
+                                self.updateStack(i, undefined);
+                            }
+                            if (!$thumb.hasClass('file-preview-error') || self.retryErrorUploads) {
+                                key++;
+                            }
+                        });
+                        self._initUploadSuccess(data);
+                    }
+                    self._showUploadError(data.error, outData, 'filebatchuploaderror');
+                    self._setProgress(101, self.$progress, self.msgUploadError);
+                }
+            };
+            fnComplete = function () {
+                self.unlock();
+                self._initSuccessThumbs();
+                self._clearFileInput();
+                self._raise('filebatchuploadcomplete', [self.filestack, self._getExtraData()]);
+            };
+            fnError = function (jqXHR, textStatus, errorThrown) {
+                var outData = self._getOutData(jqXHR), op = self.ajaxOperations.uploadBatch,
+                    errMsg = self._parseError(op, 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._setPreviewError($thumb);
+                    }
+                });
+                self._getThumbs().removeClass('file-uploading');
+                self._getThumbs(' .kv-file-upload').removeAttr('disabled');
+                self._getThumbs(' .kv-file-delete').removeAttr('disabled');
+                self._setProgress(101, self.$progress, self.msgAjaxProgressError.replace('{operation}', op));
+            };
+            $.each(files, function (key, data) {
+                if (!$h.isEmpty(files[key])) {
+                    self.formdata.append(self.uploadFileAttr, data, self.filenames[key]);
+                }
+            });
+            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._setProgressCancelled();
+                }
+            };
+            fnSuccess = function (data, textStatus, jqXHR) {
+                var outData = self._getOutData(jqXHR, data);
+                if ($h.isEmpty(data) || $h.isEmpty(data.error)) {
+                    self._raise('filebatchuploadsuccess', [outData]);
+                    self._clearFileInput();
+                    self._initUploadSuccess(data);
+                    self._setProgress(101);
+                } else {
+                    self._showUploadError(data.error, outData, 'filebatchuploaderror');
+                }
+            };
+            fnComplete = function () {
+                self.unlock();
+                self._clearFileInput();
+                self._raise('filebatchuploadcomplete', [self.filestack, self._getExtraData()]);
+            };
+            fnError = function (jqXHR, textStatus, errorThrown) {
+                var outData = self._getOutData(jqXHR), op = self.ajaxOperations.uploadExtra,
+                    errMsg = self._parseError(op, jqXHR, errorThrown);
+                params.data = outData;
+                self._showUploadError(errMsg, outData, 'filebatchuploaderror');
+                self._setProgress(101, self.$progress, self.msgAjaxProgressError.replace('{operation}', op));
+            };
+            self._ajaxSubmit(fnBefore, fnSuccess, fnComplete, fnError);
+        },
+        _deleteFileIndex: function ($frame) {
+            var self = this, ind = $frame.attr('data-fileindex'), rev = self.reversePreviewOrder;
+            if (ind.substring(0, 5) === 'init_') {
+                ind = parseInt(ind.replace('init_', ''));
+                self.initialPreview = $h.spliceArray(self.initialPreview, ind, rev);
+                self.initialPreviewConfig = $h.spliceArray(self.initialPreviewConfig, ind, rev);
+                self.initialPreviewThumbTags = $h.spliceArray(self.initialPreviewThumbTags, ind, rev);
+                self.getFrames().each(function () {
+                    var $nFrame = $(this), nInd = $nFrame.attr('data-fileindex');
+                    if (nInd.substring(0, 5) === 'init_') {
+                        nInd = parseInt(nInd.replace('init_', ''));
+                        if (nInd > ind) {
+                            nInd--;
+                            $nFrame.attr('data-fileindex', 'init_' + nInd);
+                        }
+                    }
+                });
+                if (self.uploadAsync) {
+                    self.cacheInitialPreview = self.getPreview();
+                }
+            }
+        },
+        _initFileActions: function () {
+            var self = this, $preview = self.$preview;
+            if (!self.showPreview) {
+                return;
+            }
+            self._initZoomButton();
+            self.getFrames(' .kv-file-remove').each(function () {
+                var $el = $(this), $frame = $el.closest($h.FRAMES), hasError, id = $frame.attr('id'),
+                    ind = $frame.attr('data-fileindex'), n, cap, status;
+                self._handler($el, 'click', function () {
+                    status = self._raise('filepreremove', [id, ind]);
+                    if (status === false || !self._validateMinCount()) {
+                        return false;
+                    }
+                    hasError = $frame.hasClass('file-preview-error');
+                    $h.cleanMemory($frame);
+                    $frame.fadeOut('slow', function () {
+                        $h.cleanZoomCache($preview.find('#zoom-' + id));
+                        self.updateStack(ind, undefined);
+                        self._clearObjects($frame);
+                        $frame.remove();
+                        if (id && hasError) {
+                            self.$errorContainer.find('li[data-file-id="' + id + '"]').fadeOut('fast', function () {
+                                $(this).remove();
+                                if (!self._errorsExist()) {
+                                    self._resetErrors();
+                                }
+                            });
+                        }
+                        self._clearFileInput();
+                        var filestack = self.getFileStack(true), chk = self.previewCache.count(),
+                            len = filestack.length, hasThumb = self.showPreview && self.getFrames().length;
+                        if (len === 0 && chk === 0 && !hasThumb) {
+                            self.reset();
+                        } else {
+                            n = chk + len;
+                            cap = n > 1 ? self._getMsgSelected(n) : (filestack[0] ? self._getFileNames()[0] : '');
+                            self._setCaption(cap);
+                        }
+                        self._raise('fileremoved', [id, ind]);
+                    });
+                });
+            });
+            self.getFrames(' .kv-file-upload').each(function () {
+                var $el = $(this);
+                self._handler($el, 'click', function () {
+                    var $frame = $el.closest($h.FRAMES), ind = $frame.attr('data-fileindex');
+                    self.$progress.hide();
+                    if ($frame.hasClass('file-preview-error') && !self.retryErrorUploads) {
+                        return;
+                    }
+                    self._uploadSingle(ind, false);
+                });
+            });
+        },
+        _initPreviewActions: function () {
+            var self = this, $preview = self.$preview, deleteExtraData = self.deleteExtraData || {},
+                btnRemove = $h.FRAMES + ' .kv-file-remove', settings = self.fileActionSettings,
+                origClass = settings.removeClass, errClass = settings.removeErrorClass,
+                resetProgress = function () {
+                    var hasFiles = self.isAjaxUpload ? self.previewCache.count() : self._inputFileCount();
+                    if (!$preview.find($h.FRAMES).length && !hasFiles) {
+                        self._setCaption('');
+                        self.reset();
+                        self.initialCaption = '';
+                    }
+                };
+            self._initZoomButton();
+            $preview.find(btnRemove).each(function () {
+                var $el = $(this), vUrl = $el.data('url') || self.deleteUrl, vKey = $el.data('key'),
+                    fnBefore, fnSuccess, fnError;
+                if ($h.isEmpty(vUrl) || vKey === undefined) {
+                    return;
+                }
+                var $frame = $el.closest($h.FRAMES), cache = self.previewCache.data,
+                    settings, params, index = $frame.attr('data-fileindex'), config, extraData;
+                index = parseInt(index.replace('init_', ''));
+                config = $h.isEmpty(cache.config) && $h.isEmpty(cache.config[index]) ? null : cache.config[index];
+                extraData = $h.isEmpty(config) || $h.isEmpty(config.extra) ? deleteExtraData : config.extra;
+                if (typeof extraData === "function") {
+                    extraData = extraData();
+                }
+                params = {id: $el.attr('id'), key: vKey, extra: extraData};
+                fnBefore = function (jqXHR) {
+                    self.ajaxAborted = false;
+                    self._raise('filepredelete', [vKey, jqXHR, extraData]);
+
+                    if (self._abort()) {
+                        jqXHR.abort();
+                    } else {
+                        $el.removeClass(errClass);
+                        $h.addCss($frame, 'file-uploading');
+                        $h.addCss($el, 'disabled ' + origClass);
+                    }
+                };
+                fnSuccess = function (data, textStatus, jqXHR) {
+                    var n, cap;
+                    if (!$h.isEmpty(data) && !$h.isEmpty(data.error)) {
+                        params.jqXHR = jqXHR;
+                        params.response = data;
+                        self._showError(data.error, params, 'filedeleteerror');
+                        $frame.removeClass('file-uploading');
+                        $el.removeClass('disabled ' + origClass).addClass(errClass);
+                        resetProgress();
+                        return;
+                    }
+                    $frame.removeClass('file-uploading').addClass('file-deleted');
+                    $frame.fadeOut('slow', function () {
+                        index = parseInt(($frame.attr('data-fileindex')).replace('init_', ''));
+                        self.previewCache.unset(index);
+                        self._deleteFileIndex($frame);
+                        n = self.previewCache.count();
+                        cap = n > 0 ? self._getMsgSelected(n) : '';
+                        self._setCaption(cap);
+                        self._raise('filedeleted', [vKey, jqXHR, extraData]);
+                        $h.cleanZoomCache($preview.find('#zoom-' + $frame.attr('id')));
+                        self._clearObjects($frame);
+                        $frame.remove();
+                        resetProgress();
+                    });
+                };
+                fnError = function (jqXHR, textStatus, errorThrown) {
+                    var op = self.ajaxOperations.deleteThumb, errMsg = self._parseError(op, jqXHR, errorThrown);
+                    params.jqXHR = jqXHR;
+                    params.response = {};
+                    self._showError(errMsg, params, 'filedeleteerror');
+                    $frame.removeClass('file-uploading');
+                    $el.removeClass('disabled ' + origClass).addClass(errClass);
+                    resetProgress();
+                };
+                self._initAjaxSettings();
+                self._mergeAjaxCallback('beforeSend', fnBefore, 'delete');
+                self._mergeAjaxCallback('success', fnSuccess, 'delete');
+                self._mergeAjaxCallback('error', fnError, 'delete');
+                settings = $.extend(true, {}, {
+                    url: self._encodeURI(vUrl),
+                    type: 'POST',
+                    dataType: 'json',
+                    data: $.extend(true, {}, {key: vKey}, extraData)
+                }, self._ajaxDeleteSettings);
+                self._handler($el, 'click', function () {
+                    if (!self._validateMinCount()) {
+                        return false;
+                    }
+                    layer.confirm("请问是否确定删除,删除后不可恢复?", {
+                        title: "删除文件" //按钮
+                    },function(index){
+                        self.ajaxAborted = false;
+                        self._raise('filebeforedelete', [vKey, extraData]);
+                        //noinspection JSUnresolvedVariable,JSHint
+                        if (self.ajaxAborted instanceof Promise) {
+                            self.ajaxAborted.then(function (result) {
+                                if (!result) {
+                                    $.ajax(settings);
+                                }
+                            });
+                        } else {
+                            if (!self.ajaxAborted) {
+                                $.ajax(settings);
+                            }
+                        }
+                        layer.close(index)
+                    });
+
+                });
+            });
+        },
+        _hideFileIcon: function () {
+            var self = this;
+            if (self.overwriteInitial) {
+                self.$captionContainer.removeClass('icon-visible');
+            }
+        },
+        _showFileIcon: function () {
+            var self = this;
+            $h.addCss(self.$captionContainer, 'icon-visible');
+        },
+        _getSize: function (bytes) {
+            var self = this, size = parseFloat(bytes), i, func = self.fileSizeGetter, sizes, out;
+            if (!$.isNumeric(bytes) || !$.isNumeric(size)) {
+                return '';
+            }
+            if (typeof func === 'function') {
+                out = func(size);
+            } else {
+                if (size === 0) {
+                    out = '0.00 B';
+                } else {
+                    i = Math.floor(Math.log(size) / Math.log(1024));
+                    sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
+                    out = (size / Math.pow(1024, i)).toFixed(2) * 1 + ' ' + sizes[i];
+                }
+            }
+            return self._getLayoutTemplate('size').replace('{sizeText}', out);
+        },
+        _generatePreviewTemplate: function (cat, data, fname, ftype, previewId, isError, size, frameClass, foot, ind, templ) {
+            var self = this, caption = self.slug(fname), prevContent, zoomContent = '', styleAttribs = '',
+                screenW = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth,
+                config = screenW < 400 ? (self.previewSettingsSmall[cat] || self.defaults.previewSettingsSmall[cat]) :
+                    (self.previewSettings[cat] || self.defaults.previewSettings[cat]),
+                footer = foot || self._renderFileFooter(caption, size, 'auto', isError),
+                hasIconSetting = self._getPreviewIcon(fname), typeCss = 'type-default',
+                forcePrevIcon = hasIconSetting && self.preferIconicPreview,
+                forceZoomIcon = hasIconSetting && self.preferIconicZoomPreview, getContent;
+            if (config) {
+                $.each(config, function (key, val) {
+                    styleAttribs += key + ':' + val + ';';
+                });
+            }
+            getContent = function (c, d, zoom, frameCss) {
+                var id = zoom ? 'zoom-' + previewId : previewId, tmplt = self._getPreviewTemplate(c),
+                    css = (frameClass || '') + ' ' + frameCss;
+                if (self.frameClass) {
+                    css = self.frameClass + ' ' + css;
+                }
+                if (zoom) {
+                    css = css.replace(' ' + $h.SORT_CSS, '');
+                }
+                tmplt = self._parseFilePreviewIcon(tmplt, fname);
+                if (c === 'text') {
+                    d = $h.htmlEncode(d);
+                }
+                if (cat === 'object' && !ftype) {
+                    $.each(self.defaults.fileTypeSettings, function (key, func) {
+                        if (key === 'object' || key === 'other') {
+                            return;
+                        }
+                        if (func(fname, ftype)) {
+                            typeCss = 'type-' + key;
+                        }
+                    });
+                }
+                return tmplt.setTokens({
+                    'previewId': id,
+                    'caption': caption,
+                    'frameClass': css,
+                    'type': ftype,
+                    'fileindex': ind,
+                    'typeCss': typeCss,
+                    'footer': footer,
+                    'data': d,
+                    'template': templ || cat,
+                    'style': styleAttribs ? 'style="' + styleAttribs + '"' : ''
+                });
+            };
+            ind = ind || previewId.slice(previewId.lastIndexOf('-') + 1);
+            if (self.fileActionSettings.showZoom) {
+                zoomContent = getContent((forceZoomIcon ? 'other' : cat), data, true, 'kv-zoom-thumb');
+            }
+            zoomContent = '\n' + self._getLayoutTemplate('zoomCache').replace('{zoomContent}', zoomContent);
+            prevContent = getContent((forcePrevIcon ? 'other' : cat), data, false, 'kv-preview-thumb');
+            return prevContent + zoomContent;
+        },
+        _addToPreview: function ($preview, content) {
+            var self = this;
+            return self.reversePreviewOrder ? $preview.prepend(content) : $preview.append(content);
+        },
+        _previewDefault: function (file, previewId, isDisabled) {
+            var self = this, $preview = self.$preview;
+            if (!self.showPreview) {
+                return;
+            }
+            var fname = file ? file.name : '', ftype = file ? file.type : '', content, size = file.size || 0,
+                caption = self.slug(fname), isError = isDisabled === true && !self.isAjaxUpload,
+                data = $h.objUrl.createObjectURL(file);
+            self._clearDefaultPreview();
+            content = self._generatePreviewTemplate('other', data, fname, ftype, previewId, isError, size);
+            self._addToPreview($preview, content);
+            self._setThumbAttr(previewId, caption, size);
+            if (isDisabled === true && self.isAjaxUpload) {
+                self._setThumbStatus($('#' + previewId), 'Error');
+            }
+        },
+        _previewFile: function (i, file, theFile, previewId, data, fileInfo) {
+            if (!this.showPreview) {
+                return;
+            }
+            var self = this, fname = file ? file.name : '', ftype = fileInfo.type, caption = fileInfo.name,
+                cat = self._parseFileType(ftype, fname), types = self.allowedPreviewTypes, content,
+                mimes = self.allowedPreviewMimeTypes, $preview = self.$preview, fsize = file.size || 0,
+                chkTypes = types && types.indexOf(cat) >= 0, chkMimes = mimes && mimes.indexOf(ftype) !== -1,
+                iData = (cat === 'text' || cat === 'html' || cat === 'image') ? theFile.target.result : data;
+            /** @namespace window.DOMPurify */
+            if (cat === 'html' && self.purifyHtml && window.DOMPurify) {
+                iData = window.DOMPurify.sanitize(iData);
+            }
+            if (chkTypes || chkMimes) {
+                content = self._generatePreviewTemplate(cat, iData, fname, ftype, previewId, false, fsize);
+                self._clearDefaultPreview();
+                self._addToPreview($preview, content);
+                var $img = $preview.find('#' + previewId + ' img');
+                self._validateImageOrientation($img, file, previewId, caption, ftype, fsize, iData);
+            } else {
+                self._previewDefault(file, previewId);
+            }
+            self._setThumbAttr(previewId, caption, fsize);
+            self._initSortable();
+        },
+        _setThumbAttr: function (id, caption, size) {
+            var self = this, $frame = $('#' + id);
+            if ($frame.length) {
+                size = size && size > 0 ? self._getSize(size) : '';
+                $frame.data({'caption': caption, 'size': size});
+            }
+        },
+        _setInitThumbAttr: function () {
+            var self = this, data = self.previewCache.data, len = self.previewCache.count(), config,
+                caption, size, previewId;
+            if (len === 0) {
+                return;
+            }
+            for (var i = 0; i < len; i++) {
+                config = data.config[i];
+                previewId = self.previewInitId + '-' + 'init_' + i;
+                caption = $h.ifSet('caption', config, $h.ifSet('filename', config));
+                size = $h.ifSet('size', config);
+                self._setThumbAttr(previewId, caption, size);
+            }
+        },
+        _slugDefault: function (text) {
+            // noinspection RegExpRedundantEscape
+            return $h.isEmpty(text) ? '' : String(text).replace(/[\[\]\/\{}:;#%=\(\)\*\+\?\\\^\$\|<>&"']/g, '_');
+        },
+        _updateFileDetails: function (numFiles) {
+            var self = this, $el = self.$element, fileStack = self.getFileStack(),
+                name = ($h.isIE(9) && $h.findFileName($el.val())) ||
+                    ($el[0].files[0] && $el[0].files[0].name) || (fileStack.length && fileStack[0].name) || '',
+                label = self.slug(name), n = self.isAjaxUpload ? fileStack.length : numFiles,
+                nFiles = self.previewCache.count() + n, log = n === 1 ? label : self._getMsgSelected(nFiles);
+            if (self.isError) {
+                self.$previewContainer.removeClass('file-thumb-loading');
+                self.$previewStatus.html('');
+                self.$captionContainer.removeClass('icon-visible');
+            } 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 (self.previewCache.count()) {
+                self._initPreviewActions();
+            }
+        },
+        _setThumbStatus: function ($thumb, status) {
+            var self = this;
+            if (!self.showPreview) {
+                return;
+            }
+            var 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');
+            if (status === 'Success') {
+                $thumb.find('.file-drag-handle').remove();
+            }
+            $indicator.html(config[icon]);
+            $indicator.attr('title', config[msg]);
+            $thumb.addClass(css);
+            if (status === 'Error' && !self.retryErrorUploads) {
+                $thumb.find('.kv-file-upload').attr('disabled', true);
+            }
+        },
+        _setProgressCancelled: function () {
+            var self = this;
+            self._setProgress(101, self.$progress, self.msgCancelled);
+        },
+        _setProgress: function (p, $el, error) {
+            var self = this, pct = Math.min(p, 100), out, pctLimit = self.progressUploadThreshold,
+                t = p <= 100 ? self.progressTemplate : self.progressCompleteTemplate,
+                template = pct < 100 ? self.progressTemplate : (error ? self.progressErrorTemplate : t);
+            $el = $el || self.$progress;
+            if (!$h.isEmpty(template)) {
+                if (pctLimit && pct > pctLimit && p <= 100) {
+                    out = template.setTokens({'percent': pctLimit, 'status': self.msgUploadThreshold});
+                } else {
+                    out = template.setTokens({'percent': pct, 'status': (p > 100 ? self.msgUploadEnd : pct + '%')});
+                }
+                $el.html(out);
+                if (error) {
+                    $el.find('[role="progressbar"]').html(error);
+                }
+            }
+        },
+        _setFileDropZoneTitle: function () {
+            var self = this, $zone = self.$container.find('.file-drop-zone'), title = self.dropZoneTitle, strFiles;
+            if (self.isClickable) {
+                strFiles = $h.isEmpty(self.$element.attr('multiple')) ? self.fileSingle : self.filePlural;
+                title += self.dropZoneClickTitle.replace('{files}', strFiles);
+            }
+            $zone.find('.' + self.dropZoneTitleClass).remove();
+            if (!self.showPreview || $zone.length === 0 || self.getFileStack().length > 0 || !self.dropZoneEnabled ||
+                (!self.isAjaxUpload && self.$element.files)) {
+                return;
+            }
+            if ($zone.find($h.FRAMES).length === 0 && $h.isEmpty(self.defaultPreviewContent)) {
+                $zone.prepend('<div class="' + self.dropZoneTitleClass + '">' + title + '</div>');
+            }
+            self.$container.removeClass('file-input-new');
+            $h.addCss(self.$container, 'file-input-ajax-new');
+        },
+        _setAsyncUploadStatus: function (previewId, pct, total) {
+            var self = this, sum = 0;
+            self._setProgress(pct, $('#' + previewId).find('.file-thumb-progress'));
+            self.uploadStatus[previewId] = pct;
+            $.each(self.uploadStatus, function (key, value) {
+                sum += value;
+            });
+            self._setProgress(Math.floor(sum / total));
+        },
+        _validateMinCount: function () {
+            var self = this, len = self.isAjaxUpload ? self.getFileStack().length : self._inputFileCount();
+            if (self.validateInitialCount && self.minFileCount > 0 && self._getFileCount(len - 1) < self.minFileCount) {
+                self._noFilesError({});
+                return false;
+            }
+            return true;
+        },
+        _getFileCount: function (fileCount) {
+            var self = this, addCount = 0;
+            if (self.validateInitialCount && !self.overwriteInitial) {
+                addCount = self.previewCache.count();
+                fileCount += addCount;
+            }
+            return fileCount;
+        },
+        _getFileId: function (file) {
+            var self = this, custom = self.generateFileId, relativePath;
+            if (typeof custom === 'function') {
+                return custom(file, event);
+            }
+            if (!file) {
+                return null;
+            }
+            /** @namespace file.webkitRelativePath */
+            /** @namespace file.fileName */
+            relativePath = String(file.webkitRelativePath || file.fileName || file.name || null);
+            if (!relativePath) {
+                return null;
+            }
+            return (file.size + '-' + relativePath.replace(/[^0-9a-zA-Z_-]/img, ''));
+        },
+        _getFileName: function (file) {
+            return file && file.name ? this.slug(file.name) : undefined;
+        },
+        _getFileIds: function (skipNull) {
+            var self = this;
+            return self.fileids.filter(function (n) {
+                return (skipNull ? n !== undefined : n !== undefined && n !== null);
+            });
+        },
+        _getFileNames: function (skipNull) {
+            var self = this;
+            return self.filenames.filter(function (n) {
+                return (skipNull ? n !== undefined : n !== undefined && n !== null);
+            });
+        },
+        _setPreviewError: function ($thumb, i, val, repeat) {
+            var self = this;
+            if (i !== undefined) {
+                self.updateStack(i, val);
+            }
+            if (!self.showPreview) {
+                return;
+            }
+            if (self.removeFromPreviewOnError && !repeat) {
+                $thumb.remove();
+                return;
+            } else {
+                self._setThumbStatus($thumb, 'Error');
+            }
+            self._refreshUploadButton($thumb, repeat);
+        },
+        _refreshUploadButton: function ($thumb, repeat) {
+            var self = this, $btn = $thumb.find('.kv-file-upload'), cfg = self.fileActionSettings,
+                icon = cfg.uploadIcon, title = cfg.uploadTitle;
+            if (!$btn.length) {
+                return;
+            }
+            if (repeat) {
+                icon = cfg.uploadRetryIcon;
+                title = cfg.uploadRetryTitle;
+            }
+            $btn.attr('title', title).html(icon);
+        },
+        _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 ($h.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].setTokens({'name': fname, 'size': limit});
+            self._showUploadError(msg, params);
+            self._setPreviewError($thumb, i, null);
+        },
+        _getExifObj: function (iData) {
+            var self = this, exifObj = null;
+            try {
+                exifObj = window.piexif ? window.piexif.load(iData) : null;
+            } catch (err) {
+                exifObj = null;
+            }
+            if (!exifObj) {
+                self._log('Error loading the piexif.js library.');
+            }
+            return exifObj;
+        },
+        _validateImageOrientation: function ($img, file, previewId, caption, ftype, fsize, iData) {
+            var self = this, exifObj, value;
+            exifObj = $img.length && self.autoOrientImage ? self._getExifObj(iData) : null;
+            value = exifObj ? exifObj["0th"][piexif.ImageIFD.Orientation] : null; // jshint ignore:line
+            if (!value) {
+                self._validateImage(previewId, caption, ftype, fsize, iData, exifObj);
+                return;
+            }
+            $h.setImageOrientation($img, self.$preview.find('#zoom-' + previewId + ' img'), value);
+            self._raise('fileimageoriented', {'$img': $img, 'file': file});
+            self._validateImage(previewId, caption, ftype, fsize, iData, exifObj);
+        },
+        _validateImage: function (previewId, fname, ftype, fsize, iData, exifObj) {
+            var self = this, $preview = self.$preview, params, w1, w2, $thumb = $preview.find("#" + previewId),
+                i = $thumb.attr('data-fileindex'), $img = $thumb.find('img');
+            fname = fname || 'Untitled';
+            $img.one('load', function () {
+                w1 = $thumb.width();
+                w2 = $preview.width();
+                if (w1 > w2) {
+                    $img.css('width', '100%');
+                }
+                params = {ind: i, id: previewId};
+                self._checkDimensions(i, 'Small', $img, $thumb, fname, 'Width', params);
+                self._checkDimensions(i, 'Small', $img, $thumb, fname, 'Height', params);
+                if (!self.resizeImage) {
+                    self._checkDimensions(i, 'Large', $img, $thumb, fname, 'Width', params);
+                    self._checkDimensions(i, 'Large', $img, $thumb, fname, 'Height', params);
+                }
+                self._raise('fileimageloaded', [previewId]);
+                self.loadedImages.push({
+                    ind: i,
+                    img: $img,
+                    thumb: $thumb,
+                    pid: previewId,
+                    typ: ftype,
+                    siz: fsize,
+                    validated: false,
+                    imgData: iData,
+                    exifObj: exifObj
+                });
+                $thumb.data('exif', exifObj);
+                self._validateAllImages();
+            }).one('error', function () {
+                self._raise('fileimageloaderror', [previewId]);
+            }).each(function () {
+                if (this.complete) {
+                    $(this).trigger('load');
+                } else {
+                    if (this.error) {
+                        $(this).trigger('error');
+                    }
+                }
+            });
+        },
+        _validateAllImages: function () {
+            var self = this, i, counter = {val: 0}, numImgs = self.loadedImages.length, config,
+                fsize, minSize = self.resizeIfSizeMoreThan;
+            if (numImgs !== self.totalImagesCount) {
+                return;
+            }
+            self._raise('fileimagesloaded');
+            if (!self.resizeImage) {
+                return;
+            }
+            for (i = 0; i < self.loadedImages.length; i++) {
+                config = self.loadedImages[i];
+                if (config.validated) {
+                    continue;
+                }
+                fsize = config.siz;
+                if (fsize && fsize > minSize * 1000) {
+                    self._getResizedImage(config, counter, numImgs);
+                }
+                self.loadedImages[i].validated = true;
+            }
+        },
+        _getResizedImage: function (config, counter, numImgs) {
+            var self = this, img = $(config.img)[0], width = img.naturalWidth, height = img.naturalHeight, blob,
+                ratio = 1, maxWidth = self.maxImageWidth || width, maxHeight = self.maxImageHeight || height,
+                isValidImage = !!(width && height), chkWidth, chkHeight, canvas = self.imageCanvas, dataURI,
+                context = self.imageCanvasContext, type = config.typ, pid = config.pid, ind = config.ind,
+                $thumb = config.thumb, throwError, msg, exifObj = config.exifObj, exifStr;
+            throwError = function (msg, params, ev) {
+                if (self.isAjaxUpload) {
+                    self._showUploadError(msg, params, ev);
+                } else {
+                    self._showError(msg, params, ev);
+                }
+                self._setPreviewError($thumb, ind);
+            };
+            if (!self.filestack[ind] || !isValidImage || (width <= maxWidth && height <= maxHeight)) {
+                if (isValidImage && self.filestack[ind]) {
+                    self._raise('fileimageresized', [pid, ind]);
+                }
+                counter.val++;
+                if (counter.val === numImgs) {
+                    self._raise('fileimagesresized');
+                }
+                if (!isValidImage) {
+                    throwError(self.msgImageResizeError, {id: pid, 'index': ind}, 'fileimageresizeerror');
+                    return;
+                }
+            }
+            type = type || self.resizeDefaultImageType;
+            chkWidth = width > maxWidth;
+            chkHeight = height > maxHeight;
+            if (self.resizePreference === 'width') {
+                ratio = chkWidth ? maxWidth / width : (chkHeight ? maxHeight / height : 1);
+            } else {
+                ratio = chkHeight ? maxHeight / height : (chkWidth ? maxWidth / width : 1);
+            }
+            self._resetCanvas();
+            width *= ratio;
+            height *= ratio;
+            canvas.width = width;
+            canvas.height = height;
+            try {
+                context.drawImage(img, 0, 0, width, height);
+                dataURI = canvas.toDataURL(type, self.resizeQuality);
+                if (exifObj) {
+                    exifStr = window.piexif.dump(exifObj);
+                    dataURI = window.piexif.insert(exifStr, dataURI);
+                }
+                blob = $h.dataURI2Blob(dataURI);
+                self.filestack[ind] = blob;
+                self._raise('fileimageresized', [pid, ind]);
+                counter.val++;
+                if (counter.val === numImgs) {
+                    self._raise('fileimagesresized', [undefined, undefined]);
+                }
+                if (!(blob instanceof Blob)) {
+                    throwError(self.msgImageResizeError, {id: pid, 'index': ind}, 'fileimageresizeerror');
+                }
+            }
+            catch (err) {
+                counter.val++;
+                if (counter.val === numImgs) {
+                    self._raise('fileimagesresized', [undefined, undefined]);
+                }
+                msg = self.msgImageResizeException.replace('{errors}', err.message);
+                throwError(msg, {id: pid, 'index': ind}, 'fileimageresizeexception');
+            }
+        },
+        _initBrowse: function ($container) {
+            var self = this, $el = self.$element;
+            if (self.showBrowse) {
+                self.$btnFile = $container.find('.btn-file').append($el);
+            } else {
+                $el.appendTo($container).attr('tabindex', -1);
+                $h.addCss($el, 'file-no-browse');
+            }
+        },
+        _initClickable: function () {
+            var self = this, $zone, $tmpZone;
+            if (!self.isClickable) {
+                return;
+            }
+            $zone = self.$dropZone;
+            if (!self.isAjaxUpload) {
+                $tmpZone = self.$preview.find('.file-default-preview');
+                if ($tmpZone.length) {
+                    $zone = $tmpZone;
+                }
+            }
+
+            $h.addCss($zone, 'clickable');
+            $zone.attr('tabindex', -1);
+            self._handler($zone, 'click', function (e) {
+                var $tar = $(e.target);
+                if (!$(self.elErrorContainer + ':visible').length &&
+                    (!$tar.parents('.file-preview-thumbnails').length || $tar.parents('.file-default-preview').length)) {
+                    self.$element.data('zoneClicked', true).trigger('click');
+                    $zone.blur();
+                }
+            });
+        },
+        _initCaption: function () {
+            var self = this, cap = self.initialCaption || '';
+            if (self.overwriteInitial || $h.isEmpty(cap)) {
+                self.$caption.val('');
+                return false;
+            }
+            self._setCaption(cap);
+            return true;
+        },
+        _setCaption: function (content, isError) {
+            var self = this, title, out, icon, n, cap, stack = self.getFileStack();
+            if (!self.$caption.length) {
+                return;
+            }
+            self.$captionContainer.removeClass('icon-visible');
+            if (isError) {
+                title = $('<div>' + self.msgValidationError + '</div>').text();
+                n = stack.length;
+                if (n) {
+                    cap = n === 1 && stack[0] ? self._getFileNames()[0] : self._getMsgSelected(n);
+                } else {
+                    cap = self._getMsgSelected(self.msgNo);
+                }
+                out = $h.isEmpty(content) ? cap : content;
+                icon = '<span class="' + self.msgValidationErrorClass + '">' + self.msgValidationErrorIcon + '</span>';
+            } else {
+                if ($h.isEmpty(content)) {
+                    return;
+                }
+                title = $('<div>' + content + '</div>').text();
+                out = title;
+                icon = self._getLayoutTemplate('fileIcon');
+            }
+            self.$captionContainer.addClass('icon-visible');
+            self.$caption.attr('title', title).val(out);
+            self.$captionIcon.html(icon);
+        },
+        _createContainer: function () {
+            var self = this, attribs = {"class": 'file-input file-input-new' + (self.rtl ? ' kv-rtl' : '')},
+                $container = $(document.createElement("div")).attr(attribs).html(self._renderMain());
+            $container.insertBefore(self.$element);
+            self._initBrowse($container);
+            if (self.theme) {
+                $container.addClass('theme-' + self.theme);
+            }
+            return $container;
+        },
+        _refreshContainer: function () {
+            var self = this, $container = self.$container, $el = self.$element;
+            $el.insertAfter($container);
+            $container.html(self._renderMain());
+            self._initBrowse($container);
+            self._validateDisabled();
+        },
+        _validateDisabled: function () {
+            var self = this;
+            self.$caption.attr({readonly: self.isDisabled});
+        },
+        _renderMain: function () {
+            var self = this,
+                dropCss = self.dropZoneEnabled ? ' file-drop-zone' : 'file-drop-disabled',
+                close = !self.showClose ? '' : self._getLayoutTemplate('close'),
+                preview = !self.showPreview ? '' : self._getLayoutTemplate('preview')
+                    .setTokens({'class': self.previewClass, 'dropClass': dropCss}),
+                css = self.isDisabled ? self.captionClass + ' file-caption-disabled' : self.captionClass,
+                caption = self.captionTemplate.setTokens({'class': css + ' kv-fileinput-caption'});
+            return self.mainTemplate.setTokens({
+                'class': self.mainClass + (!self.showBrowse && self.showCaption ? ' no-browse' : ''),
+                'preview': preview,
+                'close': close,
+                'caption': caption,
+                'upload': self._renderButton('upload'),
+                'remove': self._renderButton('remove'),
+                'cancel': self._renderButton('cancel'),
+                'browse': self._renderButton('browse')
+            });
+
+        },
+        _renderButton: function (type) {
+            var self = this, tmplt = self._getLayoutTemplate('btnDefault'), css = self[type + 'Class'],
+                title = self[type + 'Title'], icon = self[type + 'Icon'], label = self[type + 'Label'],
+                status = self.isDisabled ? ' disabled' : '', btnType = 'button';
+            switch (type) {
+                case 'remove':
+                    if (!self.showRemove) {
+                        return '';
+                    }
+                    break;
+                case 'cancel':
+                    if (!self.showCancel) {
+                        return '';
+                    }
+                    css += ' kv-hidden';
+                    break;
+                case 'upload':
+                    if (!self.showUpload) {
+                        return '';
+                    }
+                    if (self.isAjaxUpload && !self.isDisabled) {
+                        tmplt = self._getLayoutTemplate('btnLink').replace('{href}', self.uploadUrl);
+                    } else {
+                        btnType = 'submit';
+                    }
+                    break;
+                case 'browse':
+                    if (!self.showBrowse) {
+                        return '';
+                    }
+                    tmplt = self._getLayoutTemplate('btnBrowse');
+                    break;
+                default:
+                    return '';
+            }
+
+            css += type === 'browse' ? ' btn-file' : ' fileinput-' + type + ' fileinput-' + type + '-button';
+            if (!$h.isEmpty(label)) {
+                label = ' <span class="' + self.buttonLabelClass + '">' + label + '</span>';
+            }
+            return tmplt.setTokens({
+                'type': btnType, 'css': css, 'title': title, 'status': status, 'icon': icon, 'label': label
+            });
+        },
+        _renderThumbProgress: function () {
+            var self = this;
+            return '<div class="file-thumb-progress kv-hidden">' +
+                self.progressTemplate.setTokens({'percent': '0', 'status': self.msgUploadBegin}) +
+                '</div>';
+        },
+        _renderFileFooter: function (caption, size, width, isError) {
+            var self = this, config = self.fileActionSettings, rem = config.showRemove, drg = config.showDrag,
+                upl = config.showUpload, zoom = config.showZoom, out,
+                template = self._getLayoutTemplate('footer'), tInd = self._getLayoutTemplate('indicator'),
+                ind = isError ? config.indicatorError : config.indicatorNew,
+                title = isError ? config.indicatorErrorTitle : config.indicatorNewTitle,
+                indicator = tInd.setTokens({'indicator': ind, 'indicatorTitle': title});
+            size = self._getSize(size);
+            if (self.isAjaxUpload) {
+                out = template.setTokens({
+                    'actions': self._renderFileActions(upl, false, rem, zoom, drg, false, false, false),
+                    'caption': caption,
+                    'size': size,
+                    'width': width,
+                    'progress': self._renderThumbProgress(),
+                    'indicator': indicator
+                });
+            } else {
+                out = template.setTokens({
+                    'actions': self._renderFileActions(false, false, false, zoom, drg, false, false, false),
+                    'caption': caption,
+                    'size': size,
+                    'width': width,
+                    'progress': '',
+                    'indicator': indicator
+                });
+            }
+            out = $h.replaceTags(out, self.previewThumbTags);
+            return out;
+        },
+        _renderFileActions: function (showUpl, showDwn, showDel, showZoom, showDrag, disabled, url, key, isInit, dUrl, dFile) {
+            if (!showUpl && !showDwn && !showDel && !showZoom && !showDrag) {
+                return '';
+            }
+            var self = this, vUrl = url === false ? '' : ' data-url="' + url + '"',
+                vKey = key === false ? '' : ' data-key="' + key + '"', btnDelete = '', btnUpload = '', btnDownload = '',
+                btnZoom = '', btnDrag = '', css, template = self._getLayoutTemplate('actions'),
+                config = self.fileActionSettings,
+                otherButtons = self.otherActionButtons.setTokens({'dataKey': vKey, 'key': key}),
+                removeClass = disabled ? config.removeClass + ' disabled' : config.removeClass;
+            if (showDel) {
+                btnDelete = self._getLayoutTemplate('actionDelete').setTokens({
+                    'removeClass': removeClass,
+                    'removeIcon': config.removeIcon,
+                    'removeTitle': config.removeTitle,
+                    'dataUrl': vUrl,
+                    'dataKey': vKey,
+                    'key': key
+                });
+            }
+            if (showUpl) {
+                btnUpload = self._getLayoutTemplate('actionUpload').setTokens({
+                    'uploadClass': config.uploadClass,
+                    'uploadIcon': config.uploadIcon,
+                    'uploadTitle': config.uploadTitle
+                });
+            }
+            if (showDwn) {
+                btnDownload = self._getLayoutTemplate('actionDownload').setTokens({
+                    'downloadClass': config.downloadClass,
+                    'downloadIcon': config.downloadIcon,
+                    'downloadTitle': config.downloadTitle,
+                    'downloadUrl': dUrl || self.initialPreviewDownloadUrl
+                });
+                btnDownload = btnDownload.setTokens({'filename': dFile, 'key': key});
+            }
+            if (showZoom) {
+                btnZoom = self._getLayoutTemplate('actionZoom').setTokens({
+                    'zoomClass': config.zoomClass,
+                    'zoomIcon': config.zoomIcon,
+                    'zoomTitle': config.zoomTitle
+                });
+            }
+            if (showDrag && isInit) {
+                css = 'drag-handle-init ' + config.dragClass;
+                btnDrag = self._getLayoutTemplate('actionDrag').setTokens({
+                    'dragClass': css,
+                    'dragTitle': config.dragTitle,
+                    'dragIcon': config.dragIcon
+                });
+            }
+            return template.setTokens({
+                'delete': btnDelete,
+                'upload': btnUpload,
+                'download': btnDownload,
+                'zoom': btnZoom,
+                'drag': btnDrag,
+                'other': otherButtons
+            });
+        },
+        _browse: function (e) {
+            var self = this;
+            if (e && e.isDefaultPrevented() || !self._raise('filebrowse')) {
+                return;
+            }
+            if (self.isError && !self.isAjaxUpload) {
+                self.clear();
+            }
+            self.$captionContainer.focus();
+        },
+        _filterDuplicate: function (file, files, fileIds) {
+            var self = this, fileId = self._getFileId(file);
+
+            if (fileId && fileIds && fileIds.indexOf(fileId) > -1) {
+                return;
+            }
+            if (!fileIds) {
+                fileIds = [];
+            }
+            files.push(file);
+            fileIds.push(fileId);
+        },
+        _change: function (e) {
+            var self = this;
+            if (self.changeTriggered) {
+                return;
+            }
+            var $el = self.$element, isDragDrop = arguments.length > 1, isAjaxUpload = self.isAjaxUpload,
+                tfiles = [], files = isDragDrop ? arguments[1] : $el.get(0).files, total,
+                maxCount = !isAjaxUpload && $h.isEmpty($el.attr('multiple')) ? 1 : self.maxFileCount,
+                len, ctr = self.filestack.length, isSingleUpload = $h.isEmpty($el.attr('multiple')),
+                flagSingle = (isSingleUpload && ctr > 0), fileIds = self._getFileIds(),
+                throwError = function (mesg, file, previewId, index) {
+                    var p1 = $.extend(true, {}, self._getOutData({}, {}, files), {id: previewId, index: index}),
+                        p2 = {id: previewId, index: index, file: file, files: files};
+                    return isAjaxUpload ? self._showUploadError(mesg, p1) : self._showError(mesg, p2);
+                },
+                maxCountCheck = function (n, m) {
+                    var msg = self.msgFilesTooMany.replace('{m}', m).replace('{n}', n);
+                    self.isError = throwError(msg, null, null, null);
+                    self.$captionContainer.removeClass('icon-visible');
+                    self._setCaption('', true);
+                    self.$container.removeClass('file-input-new file-input-ajax-new');
+                };
+            self.reader = null;
+            self._resetUpload();
+            self._hideFileIcon();
+            if (self.dropZoneEnabled) {
+                self.$container.find('.file-drop-zone .' + self.dropZoneTitleClass).remove();
+            }
+            if (isAjaxUpload) {
+                $.each(files, function (vKey, vFile) {
+                    self._filterDuplicate(vFile, tfiles, fileIds);
+                });
+            } else {
+                if (e.target && e.target.files === undefined) {
+                    files = e.target.value ? [{name: e.target.value.replace(/^.+\\/, '')}] : [];
+                } else {
+                    files = e.target.files || {};
+                }
+                tfiles = files;
+            }
+            if ($h.isEmpty(tfiles) || tfiles.length === 0) {
+                if (!isAjaxUpload) {
+                    self.clear();
+                }
+                self._raise('fileselectnone');
+                return;
+            }
+            self._resetErrors();
+            len = tfiles.length;
+            total = self._getFileCount(isAjaxUpload ? (self.getFileStack().length + len) : len);
+            if (maxCount > 0 && total > maxCount) {
+                if (!self.autoReplace || len > maxCount) {
+                    maxCountCheck((self.autoReplace && len > maxCount ? len : total), maxCount);
+                    return;
+                }
+                if (total > maxCount) {
+                    self._resetPreviewThumbs(isAjaxUpload);
+                }
+            } else {
+                if (!isAjaxUpload || flagSingle) {
+                    self._resetPreviewThumbs(false);
+                    if (flagSingle) {
+                        self.clearStack();
+                    }
+                } else {
+                    if (isAjaxUpload && ctr === 0 && (!self.previewCache.count() || self.overwriteInitial)) {
+                        self._resetPreviewThumbs(true);
+                    }
+                }
+            }
+            if (self.isPreviewable) {
+                self.readFiles(tfiles);
+            } else {
+                self._updateFileDetails(1);
+            }
+        },
+        _abort: function (params) {
+            var self = this, data;
+            if (self.ajaxAborted && typeof self.ajaxAborted === "object" && self.ajaxAborted.message !== undefined) {
+                data = $.extend(true, {}, self._getOutData(), params);
+                data.abortData = self.ajaxAborted.data || {};
+                data.abortMessage = self.ajaxAborted.message;
+                self._setProgress(101, self.$progress, self.msgCancelled);
+                self._showUploadError(self.ajaxAborted.message, data, 'filecustomerror');
+                self.cancel();
+                return true;
+            }
+            return !!self.ajaxAborted;
+        },
+        _resetFileStack: function () {
+            var self = this, i = 0, newstack = [], newnames = [], newids = [];
+            self._getThumbs().each(function () {
+                var $thumb = $(this), ind = $thumb.attr('data-fileindex'), file = self.filestack[ind],
+                    pid = $thumb.attr('id');
+                if (ind === '-1' || ind === -1) {
+                    return;
+                }
+                if (file !== undefined) {
+                    newstack[i] = file;
+                    newnames[i] = self._getFileName(file);
+                    newids[i] = self._getFileId(file);
+                    $thumb.attr({'id': self.previewInitId + '-' + i, 'data-fileindex': i});
+                    i++;
+                } else {
+                    $thumb.attr({'id': 'uploaded-' + $h.uniqId(), 'data-fileindex': '-1'});
+                }
+                self.$preview.find('#zoom-' + pid).attr({
+                    'id': 'zoom-' + $thumb.attr('id'),
+                    'data-fileindex': $thumb.attr('data-fileindex')
+                });
+            });
+            self.filestack = newstack;
+            self.filenames = newnames;
+            self.fileids = newids;
+        },
+        _isFileSelectionValid: function (cnt) {
+            var self = this;
+            cnt = cnt || 0;
+            if (self.required && !self.getFilesCount()) {
+                self.$errorContainer.html('');
+                self._showUploadError(self.msgFileRequired);
+                return false;
+            }
+            if (self.minFileCount > 0 && self._getFileCount(cnt) < self.minFileCount) {
+                self._noFilesError({});
+                return false;
+            }
+            return true;
+        },
+        clearStack: function () {
+            var self = this;
+            self.filestack = [];
+            self.filenames = [];
+            self.fileids = [];
+            return self.$element;
+        },
+        updateStack: function (i, file) {
+            var self = this;
+            self.filestack[i] = file;
+            self.filenames[i] = self._getFileName(file);
+            self.fileids[i] = file && self._getFileId(file) || null;
+            return self.$element;
+        },
+        addToStack: function (file) {
+            var self = this;
+            self.filestack.push(file);
+            self.filenames.push(self._getFileName(file));
+            self.fileids.push(self._getFileId(file));
+            return self.$element;
+        },
+        getFileStack: function (skipNull) {
+            var self = this;
+            return self.filestack.filter(function (n) {
+                return (skipNull ? n !== undefined : n !== undefined && n !== null);
+            });
+        },
+        getFilesCount: function () {
+            var self = this, len = self.isAjaxUpload ? self.getFileStack().length : self._inputFileCount();
+            return self._getFileCount(len);
+        },
+        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, readFile,
+                fileTypes = self.allowedFileTypes, typLen = fileTypes ? fileTypes.length : 0,
+                fileExt = self.allowedFileExtensions, strExt = $h.isEmpty(fileExt) ? '' : fileExt.join(', '),
+                maxPreviewSize = self.maxFilePreviewSize && parseFloat(self.maxFilePreviewSize),
+                canPreview = $preview.length && (!maxPreviewSize || isNaN(maxPreviewSize)),
+                throwError = function (msg, file, previewId, index) {
+                    var p1 = $.extend(true, {}, self._getOutData({}, {}, files), {id: previewId, index: index}),
+                        p2 = {id: previewId, index: index, file: file, files: files}, $thumb;
+                    self._previewDefault(file, previewId, true);
+                    if (self.isAjaxUpload) {
+                        self.addToStack(undefined);
+                        setTimeout(function () {
+                            readFile(index + 1);
+                        }, 100);
+                    } else {
+                        numFiles = 0;
+                    }
+                    self._initFileActions();
+                    $thumb = $('#' + previewId);
+                    $thumb.find('.kv-file-upload').hide();
+                    if (self.removeFromPreviewOnError) {
+                        $thumb.remove();
+                    }
+                    self.isError = self.isAjaxUpload ? self._showUploadError(msg, p1) : self._showError(msg, p2);
+                    self._updateFileDetails(numFiles);
+                };
+
+            self.loadedImages = [];
+            self.totalImagesCount = 0;
+
+            $.each(files, function (key, file) {
+                var func = self.fileTypeSettings.image;
+                if (func && func(file.type)) {
+                    self.totalImagesCount++;
+                }
+            });
+            readFile = function (i) {
+                if ($h.isEmpty($el.attr('multiple'))) {
+                    numFiles = 1;
+                }
+                if (i >= numFiles) {
+                    if (self.isAjaxUpload && self.filestack.length > 0) {
+                        self._raise('filebatchselected', [self.getFileStack()]);
+                    } else {
+                        self._raise('filebatchselected', [files]);
+                    }
+                    $container.removeClass('file-thumb-loading');
+                    $status.html('');
+                    return;
+                }
+                var node = ctr + i, previewId = previewInitId + "-" + node, file = files[i], fSizeKB, j, msg,
+                    fnText = settings.text, fnImage = settings.image, fnHtml = settings.html, typ, chk, typ1, typ2,
+                    caption = file && file.name ? self.slug(file.name) : '', fileSize = (file && file.size || 0) / 1000,
+                    fileExtExpr = '', previewData = file ? $h.objUrl.createObjectURL(file) : null, fileCount = 0,
+                    strTypes = '',
+                    func, knownTypes = 0, isText, isHtml, isImage, txtFlag, processFileLoaded = function () {
+                        var msg = msgProgress.setTokens({
+                            'index': i + 1,
+                            'files': numFiles,
+                            'percent': 50,
+                            'name': caption
+                        });
+                        setTimeout(function () {
+                            $status.html(msg);
+                            self._updateFileDetails(numFiles);
+                            readFile(i + 1);
+                        }, 100);
+                        self._raise('fileloaded', [file, previewId, i, reader]);
+                    };
+                if (!file) {
+                    return;
+                }
+                if (typLen > 0) {
+                    for (j = 0; j < typLen; j++) {
+                        typ1 = fileTypes[j];
+                        typ2 = self.msgFileTypes[typ1] || typ1;
+                        strTypes += j === 0 ? typ2 : ', ' + typ2;
+                    }
+                }
+                if (caption === false) {
+                    readFile(i + 1);
+                    return;
+                }
+                if (caption.length === 0) {
+                    msg = self.msgInvalidFileName.replace('{name}', $h.htmlEncode(file.name, '[unknown]'));
+                    throwError(msg, file, previewId, i);
+                    return;
+                }
+                if (!$h.isEmpty(fileExt)) {
+                    fileExtExpr = new RegExp('\\.(' + fileExt.join('|') + ')$', 'i');
+                }
+                fSizeKB = fileSize.toFixed(2);
+                if (self.maxFileSize > 0 && fileSize > self.maxFileSize) {
+                    msg = self.msgSizeTooLarge.setTokens({
+                        'name': caption,
+                        'size': fSizeKB,
+                        'maxSize': self.maxFileSize
+                    });
+                    throwError(msg, file, previewId, i);
+                    return;
+                }
+                if (self.minFileSize !== null && fileSize <= $h.getNum(self.minFileSize)) {
+                    msg = self.msgSizeTooSmall.setTokens({
+                        'name': caption,
+                        'size': fSizeKB,
+                        'minSize': self.minFileSize
+                    });
+                    throwError(msg, file, previewId, i);
+                    return;
+                }
+                if (!$h.isEmpty(fileTypes) && $h.isArray(fileTypes)) {
+                    for (j = 0; j < fileTypes.length; j += 1) {
+                        typ = fileTypes[j];
+                        func = settings[typ];
+                        fileCount += !func || (typeof func !== 'function') ? 0 : (func(file.type, file.name) ? 1 : 0);
+                    }
+                    if (fileCount === 0) {
+                        msg = self.msgInvalidFileType.setTokens({'name': caption, 'types': strTypes});
+                        throwError(msg, file, previewId, i);
+                        return;
+                    }
+                }
+                if (fileCount === 0 && !$h.isEmpty(fileExt) && $h.isArray(fileExt) && !$h.isEmpty(fileExtExpr)) {
+                    chk = $h.compare(caption, fileExtExpr);
+                    fileCount += $h.isEmpty(chk) ? 0 : chk.length;
+                    if (fileCount === 0) {
+                        msg = self.msgInvalidFileExtension.setTokens({'name': caption, 'extensions': strExt});
+                        throwError(msg, file, previewId, i);
+                        return;
+                    }
+                }
+                if (!self.showPreview) {
+                    if (self.isAjaxUpload) {
+                        self.addToStack(file);
+                    }
+                    setTimeout(function () {
+                        readFile(i + 1);
+                        self._updateFileDetails(numFiles);
+                    }, 100);
+                    self._raise('fileloaded', [file, previewId, i, reader]);
+                    return;
+                }
+                if (!canPreview && fileSize > maxPreviewSize) {
+                    self.addToStack(file);
+                    $container.addClass('file-thumb-loading');
+                    self._previewDefault(file, previewId);
+                    self._initFileActions();
+                    self._updateFileDetails(numFiles);
+                    readFile(i + 1);
+                    return;
+                }
+                if ($preview.length && FileReader !== undefined) {
+                    isText = fnText(file.type, caption);
+                    isHtml = fnHtml(file.type, caption);
+                    isImage = fnImage(file.type, caption);
+                    $status.html(msgLoading.replace('{index}', i + 1).replace('{files}', numFiles));
+                    $container.addClass('file-thumb-loading');
+                    reader.onerror = function (evt) {
+                        self._errorHandler(evt, caption);
+                    };
+                    reader.onload = function (theFile) {
+                        var hex, fileInfo, uint, byte, bytes = [], contents, mime, readTextImage = function (textFlag) {
+                            var newReader = new FileReader();
+                            newReader.onerror = function (theFileNew) {
+                                self._errorHandler(theFileNew, caption);
+                            };
+                            newReader.onload = function (theFileNew) {
+                                self._previewFile(i, file, theFileNew, previewId, previewData, fileInfo);
+                                self._initFileActions();
+                                processFileLoaded();
+                            };
+                            if (textFlag) {
+                                newReader.readAsText(file, self.textEncoding);
+                            } else {
+                                newReader.readAsDataURL(file);
+                            }
+                        };
+                        fileInfo = {'name': caption, 'type': file.type};
+                        $.each(settings, function (key, func) {
+                            if (key !== 'object' && key !== 'other' && func(file.type, caption)) {
+                                knownTypes++;
+                            }
+                        });
+                        if (knownTypes === 0) {// auto detect mime types from content if no known file types detected
+                            uint = new Uint8Array(theFile.target.result);
+                            for (j = 0; j < uint.length; j++) {
+                                byte = uint[j].toString(16);
+                                bytes.push(byte);
+                            }
+                            hex = bytes.join('').toLowerCase().substring(0, 8);
+                            mime = $h.getMimeType(hex, '', '');
+                            if ($h.isEmpty(mime)) { // look for ascii text content
+                                contents = $h.arrayBuffer2String(reader.result);
+                                mime = $h.isSvg(contents) ? 'image/svg+xml' : $h.getMimeType(hex, contents, file.type);
+                            }
+                            fileInfo = {'name': caption, 'type': mime};
+                            isText = fnText(mime, '');
+                            isHtml = fnHtml(mime, '');
+                            isImage = fnImage(mime, '');
+                            txtFlag = isText || isHtml;
+                            if (txtFlag || isImage) {
+                                readTextImage(txtFlag);
+                                return;
+                            }
+                        }
+                        self._previewFile(i, file, theFile, previewId, previewData, fileInfo);
+                        self._initFileActions();
+                        processFileLoaded();
+                    };
+                    reader.onprogress = function (data) {
+                        if (data.lengthComputable) {
+                            var fact = (data.loaded / data.total) * 100, progress = Math.ceil(fact);
+                            msg = msgProgress.setTokens({
+                                'index': i + 1,
+                                'files': numFiles,
+                                'percent': progress,
+                                'name': caption
+                            });
+                            setTimeout(function () {
+                                $status.html(msg);
+                            }, 100);
+                        }
+                    };
+
+                    if (isText || isHtml) {
+                        reader.readAsText(file, self.textEncoding);
+                    } else {
+                        if (isImage) {
+                            reader.readAsDataURL(file);
+                        } 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.addToStack(file);
+            };
+
+            readFile(0);
+            self._updateFileDetails(numFiles, false);
+        },
+        lock: function () {
+            var self = this;
+            self._resetErrors();
+            self.disable();
+            if (self.showRemove) {
+                self.$container.find('.fileinput-remove').hide();
+            }
+            if (self.showCancel) {
+                self.$container.find('.fileinput-cancel').show();
+            }
+            self._raise('filelock', [self.filestack, self._getExtraData()]);
+            return self.$element;
+        },
+        unlock: function (reset) {
+            var self = this;
+            if (reset === undefined) {
+                reset = true;
+            }
+            self.enable();
+            if (self.showCancel) {
+                self.$container.find('.fileinput-cancel').hide();
+            }
+            if (self.showRemove) {
+                self.$container.find('.fileinput-remove').show();
+            }
+            if (reset) {
+                self._resetFileStack();
+            }
+            self._raise('fileunlock', [self.filestack, self._getExtraData()]);
+            return self.$element;
+        },
+        cancel: function () {
+            var self = this, xhr = self.ajaxRequests, len = xhr.length, i;
+            if (len > 0) {
+                for (i = 0; i < len; i += 1) {
+                    self.cancelling = true;
+                    xhr[i].abort();
+                }
+            }
+            self._setProgressCancelled();
+            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();
+            });
+            return self.$element;
+        },
+        clear: function () {
+            var self = this, cap;
+            if (!self._raise('fileclear')) {
+                return;
+            }
+            self.$btnUpload.removeAttr('disabled');
+            self._getThumbs().find('video,audio,img').each(function () {
+                $h.cleanMemory($(this));
+            });
+            self._clearFileInput();
+            self._resetUpload();
+            self.clearStack();
+            self._resetErrors(true);
+            if (self._hasInitialPreview()) {
+                self._showFileIcon();
+                self._resetPreview();
+                self._initPreviewActions();
+                self.$container.removeClass('file-input-new');
+            } else {
+                self._getThumbs().each(function () {
+                    self._clearObjects($(this));
+                });
+                if (self.isAjaxUpload) {
+                    self.previewCache.data = {};
+                }
+                self.$preview.html('');
+                cap = (!self.overwriteInitial && self.initialCaption.length > 0) ? self.initialCaption : '';
+                self.$caption.attr('title', '').val(cap);
+                $h.addCss(self.$container, 'file-input-new');
+                self._validateDefaultPreview();
+            }
+            if (self.$container.find($h.FRAMES).length === 0) {
+                if (!self._initCaption()) {
+                    self.$captionContainer.removeClass('icon-visible');
+                }
+            }
+            self._hideFileIcon();
+            self._raise('filecleared');
+            self.$captionContainer.focus();
+            self._setFileDropZoneTitle();
+            return self.$element;
+        },
+        reset: function () {
+            var self = this;
+            if (!self._raise('filereset')) {
+                return;
+            }
+            self._resetPreview();
+            self.$container.find('.fileinput-filename').text('');
+            $h.addCss(self.$container, 'file-input-new');
+            if (self.getFrames().length || self.dropZoneEnabled) {
+                self.$container.removeClass('file-input-new');
+            }
+            self.clearStack();
+            self.formdata = {};
+            self._setFileDropZoneTitle();
+            return self.$element;
+        },
+        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(".fileinput-remove, .fileinput-upload, .file-preview-frame button")
+                .attr("disabled", true);
+            $h.addCss(self.$container.find('.btn-file'), 'disabled');
+            self._initDragDrop();
+            return self.$element;
+        },
+        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(".fileinput-remove, .fileinput-upload, .file-preview-frame button")
+                .removeAttr("disabled");
+            self.$container.find('.btn-file').removeClass('disabled');
+            self._initDragDrop();
+            return self.$element;
+        },
+        upload: function () {
+            var self = this, totLen = self.getFileStack().length, i, outData, len,
+                hasExtraData = !$.isEmptyObject(self._getExtraData());
+            if (!self.isAjaxUpload || self.isDisabled || !self._isFileSelectionValid(totLen)) {
+                return;
+            }
+            self._resetUpload();
+            if (totLen === 0 && !hasExtraData) {
+                self._showUploadError(self.msgUploadEmpty);
+                return;
+            }
+            self.$progress.show();
+            self.uploadCount = 0;
+            self.uploadStatus = {};
+            self.uploadLog = [];
+            self.lock();
+            self._setProgress(2);
+            if (totLen === 0 && hasExtraData) {
+                self._uploadExtraOnly();
+                return;
+            }
+            len = self.filestack.length;
+            self.hasInitData = false;
+            if (self.uploadAsync) {
+                outData = self._getOutData();
+                self._raise('filebatchpreupload', [outData]);
+                self.fileBatchCompleted = false;
+                self.uploadCache = {content: [], config: [], tags: [], append: true};
+                self.uploadAsyncCount = self.getFileStack().length;
+                for (i = 0; i < len; i++) {
+                    self.uploadCache.content[i] = null;
+                    self.uploadCache.config[i] = null;
+                    self.uploadCache.tags[i] = null;
+                }
+                self.$preview.find('.file-preview-initial').removeClass($h.SORT_CSS);
+                self._initSortable();
+                self.cacheInitialPreview = self.getPreview();
+
+                for (i = 0; i < len; i++) {
+                    if (self.filestack[i]) {
+                        self._uploadSingle(i, true);
+                    }
+                }
+                return;
+            }
+            self._uploadBatch();
+            return self.$element;
+        },
+        destroy: function () {
+            var self = this, $form = self.$form, $cont = self.$container, $el = self.$element, ns = self.namespace;
+            $(document).off(ns);
+            $(window).off(ns);
+            if ($form && $form.length) {
+                $form.off(ns);
+            }
+            if (self.isAjaxUpload) {
+                self._clearFileInput();
+            }
+            self._cleanup();
+            self._initPreviewCache();
+            $el.insertBefore($cont).off(ns).removeData();
+            $cont.off().remove();
+            return $el;
+        },
+        refresh: function (options) {
+            var self = this, $el = self.$element;
+            if (typeof options !== 'object' || $h.isEmpty(options)) {
+                options = self.options;
+            } else {
+                options = $.extend(true, {}, self.options, options);
+            }
+            self._init(options, true);
+            self._listen();
+            return $el;
+        },
+        zoom: function (frameId) {
+            var self = this, $frame = self._getFrame(frameId), $modal = self.$modal;
+            if (!$frame) {
+                return;
+            }
+            $h.initModal($modal);
+            $modal.html(self._getModalContent());
+            self._setZoomContent($frame);
+            $modal.modal('show');
+            self._initZoomButtons();
+        },
+        getExif: function (frameId) {
+            var self = this, $frame = self._getFrame(frameId);
+            return $frame && $frame.data('exif') || null;
+        },
+        getFrames: function (cssFilter) {
+            var self = this, $frames;
+            cssFilter = cssFilter || '';
+            $frames = self.$preview.find($h.FRAMES + cssFilter);
+            if (self.reversePreviewOrder) {
+                $frames = $($frames.get().reverse());
+            }
+            return $frames;
+        },
+        getPreview: function () {
+            var self = this;
+            return {
+                content: self.initialPreview,
+                config: self.initialPreviewConfig,
+                tags: self.initialPreviewThumbTags
+            };
+        }
+    };
+
+    $.fn.fileinput = function (option) {
+        if (!$h.hasFileAPISupport() && !$h.isIE(9)) {
+            return;
+        }
+        var args = Array.apply(null, arguments), retvals = [];
+        args.shift();
+        this.each(function () {
+            var self = $(this), data = self.data('fileinput'), options = typeof option === 'object' && option,
+                theme = options.theme || self.data('theme'), l = {}, t = {},
+                lang = options.language || self.data('language') || $.fn.fileinput.defaults.language || 'en', opt;
+            if (!data) {
+                if (theme) {
+                    t = $.fn.fileinputThemes[theme] || {};
+                }
+                if (lang !== 'en' && !$h.isEmpty($.fn.fileinputLocales[lang])) {
+                    l = $.fn.fileinputLocales[lang] || {};
+                }
+                opt = $.extend(true, {}, $.fn.fileinput.defaults, t, $.fn.fileinputLocales.en, l, options, self.data());
+                data = new FileInput(this, opt);
+                self.data('fileinput', data);
+            }
+
+            if (typeof option === 'string') {
+                retvals.push(data[option].apply(data, args));
+            }
+        });
+        switch (retvals.length) {
+            case 0:
+                return this;
+            case 1:
+                return retvals[0];
+            default:
+                return retvals;
+        }
+    };
+
+    $.fn.fileinput.defaults = {
+        language: 'en',
+        showCaption: true,
+        showBrowse: true,
+        showPreview: true,
+        showRemove: true,
+        showUpload: true,
+        showCancel: true,
+        showClose: true,
+        showUploadedThumbs: true,
+        browseOnZoneClick: false,
+        autoReplace: false,
+        autoOrientImage: false, // if `true` applicable for JPEG images only
+        required: false,
+        rtl: false,
+        hideThumbnailContent: false,
+        encodeUrl: true,
+        generateFileId: null,
+        previewClass: '',
+        captionClass: '',
+        frameClass: 'krajee-default',
+        mainClass: 'file-caption-main',
+        mainTemplate: null,
+        purifyHtml: true,
+        fileSizeGetter: null,
+        initialCaption: '',
+        initialPreview: [],
+        initialPreviewDelimiter: '*$$*',
+        initialPreviewAsData: false,
+        initialPreviewFileType: 'image',
+        initialPreviewConfig: [],
+        initialPreviewThumbTags: [],
+        previewThumbTags: {},
+        initialPreviewShowDelete: true,
+        initialPreviewDownloadUrl: '',
+        removeFromPreviewOnError: false,
+        deleteUrl: '',
+        deleteExtraData: {},
+        overwriteInitial: true,
+        previewZoomButtonIcons: {
+            prev: '<i class="glyphicon glyphicon-triangle-left"></i>',
+            next: '<i class="glyphicon glyphicon-triangle-right"></i>',
+            toggleheader: '<i class="glyphicon glyphicon-resize-vertical"></i>',
+            fullscreen: '<i class="glyphicon glyphicon-fullscreen"></i>',
+            borderless: '<i class="glyphicon glyphicon-resize-full"></i>',
+            close: '<i class="glyphicon glyphicon-remove"></i>'
+        },
+        previewZoomButtonClasses: {
+            prev: 'btn btn-navigate',
+            next: 'btn btn-navigate',
+            toggleheader: 'btn btn-sm btn-kv btn-default btn-outline-secondary',
+            fullscreen: 'btn btn-sm btn-kv btn-default btn-outline-secondary',
+            borderless: 'btn btn-sm btn-kv btn-default btn-outline-secondary',
+            close: 'btn btn-sm btn-kv btn-default btn-outline-secondary'
+        },
+        previewTemplates: {},
+        previewContentTemplates: {},
+        preferIconicPreview: false,
+        preferIconicZoomPreview: false,
+        allowedPreviewTypes: undefined,
+        allowedPreviewMimeTypes: null,
+        allowedFileTypes: null,
+        allowedFileExtensions: null,
+        defaultPreviewContent: null,
+        customLayoutTags: {},
+        customPreviewTags: {},
+        previewFileIcon: '<i class="glyphicon glyphicon-file"></i>',
+        previewFileIconClass: 'file-other-icon',
+        previewFileIconSettings: {},
+        previewFileExtSettings: {},
+        buttonLabelClass: 'hidden-xs',
+        browseIcon: '<i class="glyphicon glyphicon-folder-open"></i>&nbsp;',
+        browseClass: 'btn btn-primary',
+        removeIcon: '<i class="glyphicon glyphicon-trash"></i>',
+        removeClass: 'btn btn-default btn-secondary',
+        cancelIcon: '<i class="glyphicon glyphicon-ban-circle"></i>',
+        cancelClass: 'btn btn-default btn-secondary',
+        uploadIcon: '<i class="glyphicon glyphicon-upload"></i>',
+        uploadClass: 'btn btn-default btn-secondary',
+        uploadUrl: null,
+        uploadUrlThumb: null,
+        uploadAsync: true,
+        uploadExtraData: {},
+        zoomModalHeight: 480,
+        minImageWidth: null,
+        minImageHeight: null,
+        maxImageWidth: null,
+        maxImageHeight: null,
+        resizeImage: false,
+        resizePreference: 'width',
+        resizeQuality: 0.92,
+        resizeDefaultImageType: 'image/jpeg',
+        resizeIfSizeMoreThan: 0, // in KB
+        minFileSize: 0,
+        maxFileSize: 0,
+        maxFilePreviewSize: 25600, // 25 MB
+        minFileCount: 0,
+        maxFileCount: 0,
+        validateInitialCount: false,
+        msgValidationErrorClass: 'text-danger',
+        msgValidationErrorIcon: '<i class="glyphicon glyphicon-exclamation-sign"></i> ',
+        msgErrorClass: 'file-error-message',
+        progressThumbClass: "progress-bar bg-success progress-bar-success progress-bar-striped active",
+        progressClass: "progress-bar bg-success progress-bar-success progress-bar-striped active",
+        progressCompleteClass: "progress-bar bg-success progress-bar-success",
+        progressErrorClass: "progress-bar bg-danger progress-bar-danger",
+        progressUploadThreshold: 99,
+        previewFileType: 'image',
+        elCaptionContainer: null,
+        elCaptionText: null,
+        elPreviewContainer: null,
+        elPreviewImage: null,
+        elPreviewStatus: null,
+        elErrorContainer: null,
+        errorCloseButton: $h.closeButton('kv-error-close'),
+        slugCallback: null,
+        dropZoneEnabled: true,
+        dropZoneTitleClass: 'file-drop-zone-title',
+        fileActionSettings: {},
+        otherActionButtons: '',
+        textEncoding: 'UTF-8',
+        ajaxSettings: {},
+        ajaxDeleteSettings: {},
+        showAjaxErrorDetails: true,
+        mergeAjaxCallbacks: false,
+        mergeAjaxDeleteCallbacks: false,
+        retryErrorUploads: true,
+        reversePreviewOrder: false
+    };
+
+    // noinspection HtmlUnknownAttribute
+    $.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',
+        msgNo: 'No',
+        msgNoFilesSelected: 'No files selected',
+        msgCancelled: 'Cancelled',
+        msgPlaceholder: 'Select {files}...',
+        msgZoomModalHeading: 'Detailed Preview',
+        msgFileRequired: 'You must select a file to upload.',
+        msgSizeTooSmall: 'File "{name}" (<b>{size} KB</b>) is too small and must be larger than <b>{minSize} KB</b>.',
+        msgSizeTooLarge: 'File "{name}" (<b>{size} KB</b>) exceeds maximum allowed upload size of <b>{maxSize} KB</b>.',
+        msgFilesTooLess: 'You must select at least <b>{n}</b> {files} to upload.',
+        msgFilesTooMany: 'Number of files selected for upload <b>({n})</b> exceeds maximum allowed limit of <b>{m}</b>.',
+        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}".',
+        msgInvalidFileName: 'Invalid or unsupported characters in file name "{name}".',
+        msgInvalidFileType: 'Invalid type for file "{name}". Only "{types}" files are supported.',
+        msgInvalidFileExtension: 'Invalid extension for file "{name}". Only "{extensions}" files are supported.',
+        msgFileTypes: {
+            'image': 'image',
+            'html': 'HTML',
+            'text': 'text',
+            'video': 'video',
+            'audio': 'audio',
+            'flash': 'flash',
+            'pdf': 'PDF',
+            'object': 'object'
+        },
+        msgUploadAborted: 'The file upload was aborted',
+        msgUploadThreshold: 'Processing...',
+        msgUploadBegin: 'Initializing...',
+        msgUploadEnd: 'Done',
+        msgUploadEmpty: 'No valid data available for upload.',
+        msgUploadError: 'Error',
+        msgValidationError: 'Validation 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.',
+        msgImageResizeError: 'Could not get the image dimensions to resize.',
+        msgImageResizeException: 'Error while resizing the image.<pre>{errors}</pre>',
+        msgAjaxError: 'Something went wrong with the {operation} operation. Please try again later!',
+        msgAjaxProgressError: '{operation} failed',
+        ajaxOperations: {
+            deleteThumb: 'file delete',
+            uploadThumb: 'file upload',
+            uploadBatch: 'batch file upload',
+            uploadExtra: 'form data upload'
+        },
+        dropZoneTitle: 'Drag & drop files here &hellip;',
+        dropZoneClickTitle: '<br>(or click to select {files})',
+        previewZoomButtonTitles: {
+            prev: 'View previous file',
+            next: 'View next file',
+            toggleheader: 'Toggle header',
+            fullscreen: 'Toggle full screen',
+            borderless: 'Toggle borderless mode',
+            close: 'Close detailed preview'
+        },
+        usePdfRenderer: function () {
+            return !!navigator.userAgent.match(/(iPod|iPhone|iPad|Android)/i);
+        },
+        pdfRendererUrl: '',
+        pdfRendererTemplate: '<iframe class="kv-preview-data file-preview-pdf" src="{renderer}?file={data}" {style}></iframe>'
+    };
+
+    $.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();
+        }
+    });
+}));

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 10 - 0
public/base/plugins/bootstrap-fileinput/js/fileinput.min.js


+ 100 - 0
public/base/plugins/bootstrap-fileinput/js/locales/LANG.js

xqd
@@ -0,0 +1,100 @@
+/*!
+ * 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',
+        msgNo: 'No',
+        msgNoFilesSelected: 'No files selected',
+        msgCancelled: 'Cancelled',
+        msgPlaceholder: 'Select {files}...',
+        msgZoomModalHeading: 'Detailed Preview',
+        msgFileRequired: 'You must select a file to upload.',
+        msgSizeTooSmall: 'File "{name}" (<b>{size} KB</b>) is too small and must be larger than <b>{minSize} KB</b>.',
+        msgSizeTooLarge: 'File "{name}" (<b>{size} KB</b>) exceeds maximum allowed upload size of <b>{maxSize} KB</b>.',
+        msgFilesTooLess: 'You must select at least <b>{n}</b> {files} to upload.',
+        msgFilesTooMany: 'Number of files selected for upload <b>({n})</b> exceeds maximum allowed limit of <b>{m}</b>.',
+        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}".',
+        msgInvalidFileName: 'Invalid or unsupported characters in file name "{name}".',
+        msgInvalidFileType: 'Invalid type for file "{name}". Only "{types}" files are supported.',
+        msgInvalidFileExtension: 'Invalid extension for file "{name}". Only "{extensions}" files are supported.',
+        msgFileTypes: {
+            'image': 'image',
+            'html': 'HTML',
+            'text': 'text',
+            'video': 'video',
+            'audio': 'audio',
+            'flash': 'flash',
+            'pdf': 'PDF',
+            'object': 'object'
+        },
+        msgUploadAborted: 'The file upload was aborted',
+        msgUploadThreshold: 'Processing...',
+        msgUploadBegin: 'Initializing...',
+        msgUploadEnd: 'Done',
+        msgUploadEmpty: 'No valid data available for upload.',
+        msgUploadError: 'Error',
+        msgValidationError: 'Validation 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.',
+        msgImageResizeError: 'Could not get the image dimensions to resize.',
+        msgImageResizeException: 'Error while resizing the image.<pre>{errors}</pre>',
+        msgAjaxError: 'Something went wrong with the {operation} operation. Please try again later!',
+        msgAjaxProgressError: '{operation} failed',
+        ajaxOperations: {
+            deleteThumb: 'file delete',
+            uploadThumb: 'file upload',
+            uploadBatch: 'batch file upload',
+            uploadExtra: 'form data upload'
+        },
+        dropZoneTitle: 'Drag & drop files here &hellip;',
+        dropZoneClickTitle: '<br>(or click to select {files})',
+        fileActionSettings: {
+            removeTitle: 'Remove file',
+            uploadTitle: 'Upload file',
+            uploadRetryTitle: 'Retry upload',
+            downloadTitle: 'Download file',
+            zoomTitle: 'View details',
+            dragTitle: 'Move / Rearrange',
+            indicatorNewTitle: 'Not uploaded yet',
+            indicatorSuccessTitle: 'Uploaded',
+            indicatorErrorTitle: 'Upload Error',
+            indicatorLoadingTitle: 'Uploading ...'
+        },
+        previewZoomButtonTitles: {
+            prev: 'View previous file',
+            next: 'View next file',
+            toggleheader: 'Toggle header',
+            fullscreen: 'Toggle full screen',
+            borderless: 'Toggle borderless mode',
+            close: 'Close detailed preview'
+        }
+    };
+})(window.jQuery);

+ 101 - 0
public/base/plugins/bootstrap-fileinput/js/locales/ar.js

xqd
@@ -0,0 +1,101 @@
+/*!
+ * FileInput Arabic 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 Yasser Lotfy <y_l@live.com>
+ *
+ * NOTE: this file must be saved in UTF-8 encoding.
+ */
+(function ($) {
+    "use strict";
+
+    $.fn.fileinputLocales['ar'] = {
+        fileSingle: 'ملف',
+        filePlural: 'ملفات',
+        browseLabel: 'تصفح &hellip;',
+        removeLabel: 'إزالة',
+        removeTitle: 'إزالة الملفات المختارة',
+        cancelLabel: 'إلغاء',
+        cancelTitle: 'إنهاء الرفع الحالي',
+        uploadLabel: 'رفع',
+        uploadTitle: 'رفع الملفات المختارة',
+        msgNo: 'لا',
+        msgNoFilesSelected: '',
+        msgCancelled: 'ألغيت',
+        msgPlaceholder: 'Select {files}...',
+        msgZoomModalHeading: 'معاينة تفصيلية',
+        msgFileRequired: 'You must select a file to upload.',
+        msgSizeTooSmall: 'File "{name}" (<b>{size} KB</b>) is too small and must be larger than <b>{minSize} KB</b>.',
+        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}".',
+        msgInvalidFileName: 'Invalid or unsupported characters in file name "{name}".',
+        msgInvalidFileType: 'نوعية غير صالحة للملف "{name}". فقط هذه النوعيات مدعومة "{types}".',
+        msgInvalidFileExtension: 'امتداد غير صالح للملف "{name}". فقط هذه الملفات مدعومة "{extensions}".',
+        msgFileTypes: {
+            'image': 'image',
+            'html': 'HTML',
+            'text': 'text',
+            'video': 'video',
+            'audio': 'audio',
+            'flash': 'flash',
+            'pdf': 'PDF',
+            'object': 'object'
+        },
+        msgUploadAborted: 'تم إلغاء رفع الملف',
+        msgUploadThreshold: 'Processing...',
+        msgUploadBegin: 'Initializing...',
+        msgUploadEnd: 'Done',
+        msgUploadEmpty: 'No valid data available for upload.',
+        msgUploadError: 'Error',
+        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.',
+        msgImageResizeError: 'لم يتمكن من معرفة أبعاد الصورة لتغييرها.',
+        msgImageResizeException: 'حدث خطأ أثناء تغيير أبعاد الصورة.<pre>{errors}</pre>',
+        msgAjaxError: 'Something went wrong with the {operation} operation. Please try again later!',
+        msgAjaxProgressError: '{operation} failed',
+        ajaxOperations: {
+            deleteThumb: 'file delete',
+            uploadThumb: 'file upload',
+            uploadBatch: 'batch file upload',
+            uploadExtra: 'form data upload'
+        },
+        dropZoneTitle: 'اسحب وأفلت الملفات هنا &hellip;',
+        dropZoneClickTitle: '<br>(or click to select {files})',
+        fileActionSettings: {
+            removeTitle: 'إزالة الملف',
+            uploadTitle: 'رفع الملف',
+            uploadRetryTitle: 'Retry upload',
+            downloadTitle: 'Download file',
+            zoomTitle: 'مشاهدة التفاصيل',
+            dragTitle: 'Move / Rearrange',
+            indicatorNewTitle: 'لم يتم الرفع بعد',
+            indicatorSuccessTitle: 'تم الرفع',
+            indicatorErrorTitle: 'خطأ بالرفع',
+            indicatorLoadingTitle: 'جارٍ الرفع ...'
+        },
+        previewZoomButtonTitles: {
+            prev: 'View previous file',
+            next: 'View next file',
+            toggleheader: 'Toggle header',
+            fullscreen: 'Toggle full screen',
+            borderless: 'Toggle borderless mode',
+            close: 'Close detailed preview'
+        }
+    };
+})(window.jQuery);

+ 101 - 0
public/base/plugins/bootstrap-fileinput/js/locales/az.js

xqd
@@ -0,0 +1,101 @@
+/*!
+ * FileInput Azerbaijan 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 Elbrus <elbrusnt@gmail.com>
+ *
+ * NOTE: this file must be saved in UTF-8 encoding.
+ */
+(function ($) {
+    "use strict";
+
+    $.fn.fileinputLocales['az'] = {
+        fileSingle: 'fayl',
+        filePlural: 'fayl',
+        browseLabel: 'Seç &hellip;',
+        removeLabel: 'Sil',
+        removeTitle: 'Seçilmiş faylları təmizlə',
+        cancelLabel: 'İmtina et',
+        cancelTitle: 'Cari yükləməni dayandır',
+        uploadLabel: 'Yüklə',
+        uploadTitle: 'Seçilmiş faylları yüklə',
+        msgNo: 'xeyir',
+        msgNoFilesSelected: 'Heç bir fayl seçilməmişdir',
+        msgCancelled: 'İmtina edildi',
+        msgPlaceholder: 'Select {files}...',
+        msgZoomModalHeading: 'İlkin baxış',
+        msgFileRequired: 'Yükləmə üçün fayl seçməlisiniz.',
+        msgSizeTooSmall: 'Seçdiyiniz "{name}" faylının həcmi (<b>{size} KB</b>)-dır,  minimum <b>{minSize} KB</b> olmalıdır.',
+        msgSizeTooLarge: 'Seçdiyiniz "{name}" faylının həcmi (<b>{size} KB</b>)-dır,  maksimum <b>{maxSize} KB</b> olmalıdır.',
+        msgFilesTooLess: 'Yükləmə üçün minimum <b>{n}</b> {files} seçməlisiniz.',
+        msgFilesTooMany: 'Seçilmiş fayl sayı <b>({n})</b>. Maksimum <b>{m}</b> fayl seçmək mümkündür.',
+        msgFileNotFound: 'Fayl "{name}" tapılmadı!',
+        msgFileSecured: '"{name}" faylının istifadəsinə yetginiz yoxdur.',
+        msgFileNotReadable: '"{name}" faylının istifadəsi mümkün deyil.',
+        msgFilePreviewAborted: '"{name}" faylı üçün ilkin baxış ləğv olunub.',
+        msgFilePreviewError: '"{name}" faylının oxunması mümkün olmadı.',
+        msgInvalidFileName: '"{name}" faylının adında qadağan olunmuş simvollardan istifadə olunmuşdur.',
+        msgInvalidFileType: '"{name}" faylının tipi dəstəklənmir. Yalnız "{types}" tipli faylları yükləmək mümkündür.',
+        msgInvalidFileExtension: '"{name}" faylının genişlənməsi yanlışdır. Yalnız "{extensions}" fayl genişlənmə(si / ləri) qəbul olunur.',
+        msgFileTypes: {
+            'image': 'image',
+            'html': 'HTML',
+            'text': 'text',
+            'video': 'video',
+            'audio': 'audio',
+            'flash': 'flash',
+            'pdf': 'PDF',
+            'object': 'object'
+        },
+        msgUploadAborted: 'Yükləmə dayandırılmışdır',
+        msgUploadThreshold: 'Yükləmə...',
+        msgUploadBegin: 'Yoxlama...',
+        msgUploadEnd: 'Fayl(lar) yükləndi',
+        msgUploadEmpty: 'Yükləmə üçün verilmiş məlumatlar yanlışdır',
+        msgUploadError: 'Error',
+        msgValidationError: 'Yoxlama nəticəsi səhvir',
+        msgLoading: '{files} fayldan {index} yüklənir &hellip;',
+        msgProgress: '{files} fayldan {index} - {name} - {percent}% yükləndi.',
+        msgSelected: 'Faylların sayı: {n}',
+        msgFoldersNotAllowed: 'Ancaq faylların daşınmasına icazə verilir! {n} qovluq yüklənmədi.',
+        msgImageWidthSmall: '{name} faylının eni {size} px -dən kiçik olmamalıdır.',
+        msgImageHeightSmall: '{name} faylının hündürlüyü {size} px -dən kiçik olmamalıdır.',
+        msgImageWidthLarge: '"{name}" faylının eni {size} px -dən böyük olmamalıdır.',
+        msgImageHeightLarge: '"{name}" faylının hündürlüyü {size} px -dən böyük olmamalıdır.',
+        msgImageResizeError: 'Faylın ölçülərini dəyişmək üçün ölçüləri hesablamaq mümkün olmadı.',
+        msgImageResizeException: 'Faylın ölçülərini dəyişmək mümkün olmadı.<pre>{errors}</pre>',
+        msgAjaxError: '{operation} əməliyyatı zamanı səhv baş verdi. Təkrar yoxlayın!',
+        msgAjaxProgressError: '{operation} əməliyyatı yerinə yetirmək mümkün olmadı.',
+        ajaxOperations: {
+            deleteThumb: 'faylı sil',
+            uploadThumb: 'faylı yüklə',
+            uploadBatch: 'bir neçə faylı yüklə',
+            uploadExtra: 'məlumatların yüklənməsi'
+        },
+        dropZoneTitle: 'Faylları bura daşıyın &hellip;',
+        dropZoneClickTitle: '<br>(Və ya seçin {files})',
+        fileActionSettings: {
+            removeTitle: 'Faylı sil',
+            uploadTitle: 'Faylı yüklə',
+            uploadRetryTitle: 'Retry upload',
+            downloadTitle: 'Download file',
+            zoomTitle: 'məlumatlara bax',
+            dragTitle: 'Yerini dəyiş və ya sırala',
+            indicatorNewTitle: 'Davam edir',
+            indicatorSuccessTitle: 'Tamamlandı',
+            indicatorErrorTitle: 'Yükləmə xətası',
+            indicatorLoadingTitle: 'Yükləmə ...'
+        },
+        previewZoomButtonTitles: {
+            prev: 'Əvvəlki fayla bax',
+            next: 'Növbəti fayla bax',
+            toggleheader: 'Başlığı dəyiş',
+            fullscreen: 'Tam ekranı dəyiş',
+            borderless: 'Bölmələrsiz rejimi dəyiş',
+            close: 'Ətraflı baxışı bağla'
+        }
+    };
+})(window.jQuery);

+ 100 - 0
public/base/plugins/bootstrap-fileinput/js/locales/bg.js

xqd
@@ -0,0 +1,100 @@
+/*!
+ * 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: 'Качи избраните файлове',
+        msgNo: 'Не',
+        msgNoFilesSelected: '',
+        msgCancelled: 'Отменен',
+        msgPlaceholder: 'Select {files}...',
+        msgZoomModalHeading: 'Детайлен преглед',
+        msgFileRequired: 'You must select a file to upload.',
+        msgSizeTooSmall: 'File "{name}" (<b>{size} KB</b>) is too small and must be larger than <b>{minSize} KB</b>.',
+        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}".',
+        msgInvalidFileName: 'Invalid or unsupported characters in file name "{name}".',
+        msgInvalidFileType: 'Невалиден тип на файла "{name}". Разрешени са само "{types}".',
+        msgInvalidFileExtension: 'Невалидно разрешение на "{name}". Разрешени са само "{extensions}".',
+        msgFileTypes: {
+            'image': 'image',
+            'html': 'HTML',
+            'text': 'text',
+            'video': 'video',
+            'audio': 'audio',
+            'flash': 'flash',
+            'pdf': 'PDF',
+            'object': 'object'
+        },
+        msgUploadAborted: 'Качите файла, бе прекратена',
+        msgUploadThreshold: 'Processing...',
+        msgUploadBegin: 'Initializing...',
+        msgUploadEnd: 'Done',
+        msgUploadEmpty: 'No valid data available for upload.',
+        msgUploadError: 'Error',
+        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.',
+        msgImageResizeError: 'Не може да размерите на изображението, за да промените размера.',
+        msgImageResizeException: 'Грешка при промяна на размера на изображението.<pre>{errors}</pre>',
+        msgAjaxError: 'Something went wrong with the {operation} operation. Please try again later!',
+        msgAjaxProgressError: '{operation} failed',
+        ajaxOperations: {
+            deleteThumb: 'file delete',
+            uploadThumb: 'file upload',
+            uploadBatch: 'batch file upload',
+            uploadExtra: 'form data upload'
+        },
+        dropZoneTitle: 'Пуснете файловете тук &hellip;',
+        dropZoneClickTitle: '<br>(or click to select {files})',
+        fileActionSettings: {
+            removeTitle: 'Махни файл',
+            uploadTitle: 'Качване на файл',
+            uploadRetryTitle: 'Retry upload',
+            downloadTitle: 'Download file',
+            zoomTitle: 'Вижте детайли',
+            dragTitle: 'Move / Rearrange',
+            indicatorNewTitle: 'Все още не е качил',
+            indicatorSuccessTitle: 'Качено',
+            indicatorErrorTitle: 'Качи Error',
+            indicatorLoadingTitle: 'Качва се ...'
+        },
+        previewZoomButtonTitles: {
+            prev: 'View previous file',
+            next: 'View next file',
+            toggleheader: 'Toggle header',
+            fullscreen: 'Toggle full screen',
+            borderless: 'Toggle borderless mode',
+            close: 'Close detailed preview'
+        }
+    };
+})(window.jQuery);

+ 100 - 0
public/base/plugins/bootstrap-fileinput/js/locales/ca.js

xqd
@@ -0,0 +1,100 @@
+/*!
+ * FileInput Català 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['ca'] = {
+        fileSingle: 'arxiu',
+        filePlural: 'arxius',
+        browseLabel: 'Examinar &hellip;',
+        removeLabel: 'Treure',
+        removeTitle: 'Treure arxius seleccionats',
+        cancelLabel: 'Cancel',
+        cancelTitle: 'Avortar la pujada en curs',
+        uploadLabel: 'Pujar arxiu',
+        uploadTitle: 'Pujar arxius seleccionats',
+        msgNo: 'No',
+        msgNoFilesSelected: '',
+        msgCancelled: 'cancel·lat',
+        msgPlaceholder: 'Select {files}...',
+        msgZoomModalHeading: 'Vista prèvia detallada',
+        msgFileRequired: 'You must select a file to upload.',
+        msgSizeTooSmall: 'File "{name}" (<b>{size} KB</b>) is too small and must be larger than <b>{minSize} KB</b>.',
+        msgSizeTooLarge: 'Arxiu "{name}" (<b>{size} KB</b>) excedeix la mida màxima permès de <b>{maxSize} KB</b>.',
+        msgFilesTooLess: 'Heu de seleccionar almenys <b>{n}</b> {files} a carregar.',
+        msgFilesTooMany: 'El nombre d\'arxius seleccionats a carregar <b>({n})</b> excedeix el límit màxim permès de <b>{m}</b>.',
+        msgFileNotFound: 'Arxiu "{name}" no trobat.',
+        msgFileSecured: 'No es pot accedir a l\'arxiu "{name}" perquè estarà sent usat per una altra aplicació o no tinguem permisos de lectura.',
+        msgFileNotReadable: 'No es pot accedir a l\'arxiu "{name}".',
+        msgFilePreviewAborted: 'Previsualització de l\'arxiu "{name}" cancel·lada.',
+        msgFilePreviewError: 'S\'ha produït un error mentre es llegia el fitxer "{name}".',
+        msgInvalidFileName: 'Invalid or unsupported characters in file name "{name}".',
+        msgInvalidFileType: 'Tipus de fitxer no vàlid per a "{name}". Només arxius "{types}" són permesos.',
+        msgInvalidFileExtension: 'Extensió de fitxer no vàlid per a "{name}". Només arxius "{extensions}" són permesos.',
+        msgFileTypes: {
+            'image': 'image',
+            'html': 'HTML',
+            'text': 'text',
+            'video': 'video',
+            'audio': 'audio',
+            'flash': 'flash',
+            'pdf': 'PDF',
+            'object': 'object'
+        },
+        msgUploadAborted: 'La càrrega d\'arxius s\'ha cancel·lat',
+        msgUploadThreshold: 'Processing...',
+        msgUploadBegin: 'Initializing...',
+        msgUploadEnd: 'Done',
+        msgUploadEmpty: 'No valid data available for upload.',
+        msgUploadError: 'Error',
+        msgValidationError: 'Error de validació',
+        msgLoading: 'Pujant fitxer {index} de {files} &hellip;',
+        msgProgress: 'Pujant fitxer {index} de {files} - {name} - {percent}% completat.',
+        msgSelected: '{n} {files} seleccionat(s)',
+        msgFoldersNotAllowed: 'Arrossegueu i deixeu anar únicament arxius. Omesa(es) {n} carpeta(es).',
+        msgImageWidthSmall: 'L\'ample de la imatge "{name}" ha de ser almenys {size} px.',
+        msgImageHeightSmall: 'L\'alçada de la imatge "{name}" ha de ser almenys {size} px.',
+        msgImageWidthLarge: 'L\'ample de la imatge "{name}" no pot excedir de {size} px.',
+        msgImageHeightLarge: 'L\'alçada de la imatge "{name}" no pot excedir de {size} px.',
+        msgImageResizeError: 'No s\'ha pogut obtenir les dimensions d\'imatge per canviar la mida.',
+        msgImageResizeException: 'Error en canviar la mida de la imatge.<pre>{errors}</pre>',
+        msgAjaxError: 'Something went wrong with the {operation} operation. Please try again later!',
+        msgAjaxProgressError: '{operation} failed',
+        ajaxOperations: {
+            deleteThumb: 'file delete',
+            uploadThumb: 'file upload',
+            uploadBatch: 'batch file upload',
+            uploadExtra: 'form data upload'
+        },
+        dropZoneTitle: 'Arrossegueu i deixeu anar aquí els arxius &hellip;',
+        dropZoneClickTitle: '<br>(or click to select {files})',
+        fileActionSettings: {
+            removeTitle: 'Eliminar arxiu',
+            uploadTitle: 'Pujar arxiu',
+            uploadRetryTitle: 'Retry upload',
+            downloadTitle: 'Download file',
+            zoomTitle: 'Veure detalls',
+            dragTitle: 'Move / Rearrange',
+            indicatorNewTitle: 'No pujat encara',
+            indicatorSuccessTitle: 'Subido',
+            indicatorErrorTitle: 'Pujar Error',
+            indicatorLoadingTitle: 'Pujant ...'
+        },
+        previewZoomButtonTitles: {
+            prev: 'View previous file',
+            next: 'View next file',
+            toggleheader: 'Toggle header',
+            fullscreen: 'Toggle full screen',
+            borderless: 'Toggle borderless mode',
+            close: 'Close detailed preview'
+        }
+    };
+})(window.jQuery);

+ 101 - 0
public/base/plugins/bootstrap-fileinput/js/locales/cr.js

xqd
@@ -0,0 +1,101 @@
+/*!
+ * FileInput Croatian 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 <stojanovic.loshmi@gmail.com>
+ *
+ * NOTE: this file must be saved in UTF-8 encoding.
+ */
+(function ($) {
+    "use strict";
+
+    $.fn.fileinputLocales['cr'] = {
+        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',
+        msgNo: 'Ne',
+        msgNoFilesSelected: '',
+        msgCancelled: 'Otkazan',
+        msgPlaceholder: 'Select {files}...',
+        msgZoomModalHeading: 'Detaljni pregled',
+        msgFileRequired: 'You must select a file to upload.',
+        msgSizeTooSmall: 'File "{name}" (<b>{size} KB</b>) is too small and must be larger than <b>{minSize} KB</b>.',
+        msgSizeTooLarge: 'Datoteka "{name}" (<b>{size} KB</b>) prekoračuje maksimalnu dozvoljenu veličinu datoteke od <b>{maxSize} KB</b>.',
+        msgFilesTooLess: 'Morate odabrati najmanje <b>{n}</b> {files} za otpremanje.',
+        msgFilesTooMany: 'Broj datoteka označenih za otpremanje <b>({n})</b> prekoračuje maksimalni dozvoljeni limit od <b>{m}</b>.',
+        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}".',
+        msgInvalidFileName: 'Invalid or unsupported characters in file name "{name}".',
+        msgInvalidFileType: 'Datoteka "{name}" je pogrešnog formata. Dozvoljeni formati su "{types}".',
+        msgInvalidFileExtension: 'Ekstenzija datoteke "{name}" nije dozvoljena. Dozvoljene ekstenzije su "{extensions}".',
+        msgFileTypes: {
+            'image': 'image',
+            'html': 'HTML',
+            'text': 'text',
+            'video': 'video',
+            'audio': 'audio',
+            'flash': 'flash',
+            'pdf': 'PDF',
+            'object': 'object'
+        },
+        msgUploadAborted: 'Prijenos datoteka je prekinut',
+        msgUploadThreshold: 'Processing...',
+        msgUploadBegin: 'Initializing...',
+        msgUploadEnd: 'Done',
+        msgUploadEmpty: 'No valid data available for upload.',
+        msgUploadError: 'Error',
+        msgValidationError: 'Provjera pogrešaka',
+        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: 'Širina slikovnu datoteku "{name}" moraju biti najmanje {size} px.',
+        msgImageHeightSmall: 'Visina slikovnu datoteku "{name}" moraju biti najmanje {size} px.',
+        msgImageWidthLarge: 'Širina slikovnu datoteku "{name}" ne može prelaziti {size} px.',
+        msgImageHeightLarge: 'Visina slikovnu datoteku "{name}" ne može prelaziti {size} px.',
+        msgImageResizeError: 'Nije mogao dobiti dimenzije slike na veličinu.',
+        msgImageResizeException: 'Greška prilikom promjene veličine slike.<pre>{errors}</pre>',
+        msgAjaxError: 'Something went wrong with the {operation} operation. Please try again later!',
+        msgAjaxProgressError: '{operation} failed',
+        ajaxOperations: {
+            deleteThumb: 'file delete',
+            uploadThumb: 'file upload',
+            uploadBatch: 'batch file upload',
+            uploadExtra: 'form data upload'
+        },
+        dropZoneTitle: 'Prevucite datoteke ovde &hellip;',
+        dropZoneClickTitle: '<br>(or click to select {files})',
+        fileActionSettings: {
+            removeTitle: 'Uklonite datoteku',
+            uploadTitle: 'Postavi datoteku',
+            uploadRetryTitle: 'Retry upload',
+            downloadTitle: 'Download file',
+            zoomTitle: 'Pregledavati pojedinosti',
+            dragTitle: 'Move / Rearrange',
+            indicatorNewTitle: 'Još nije učitao',
+            indicatorSuccessTitle: 'Preneseno',
+            indicatorErrorTitle: 'Postavi Greška',
+            indicatorLoadingTitle: 'Prijenos ...'
+        },
+        previewZoomButtonTitles: {
+            prev: 'View previous file',
+            next: 'View next file',
+            toggleheader: 'Toggle header',
+            fullscreen: 'Toggle full screen',
+            borderless: 'Toggle borderless mode',
+            close: 'Close detailed preview'
+        }
+    };
+})(window.jQuery);

+ 100 - 0
public/base/plugins/bootstrap-fileinput/js/locales/cs.js

xqd
@@ -0,0 +1,100 @@
+/*!
+ * 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['cs'] = {
+        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',
+        msgNo: 'Ne',
+        msgNoFilesSelected: 'Nevybrány žádné soubory',
+        msgCancelled: 'Zrušeno',
+        msgPlaceholder: 'Vybrat {files}...',
+        msgZoomModalHeading: 'Detailní náhled',
+        msgFileRequired: 'Musíte vybrat soubor, který chcete nahrát.',
+        msgSizeTooSmall: 'Soubor "{name}" (<b>{size} KB</b>) je příliš malý, musí mít velikost nejméně <b>{minSize} KB</b>.',
+        msgSizeTooLarge: 'Soubor "{name}" (<b>{size} KB</b>) je příliš velký, maximální povolená velikost <b>{maxSize} KB</b>.',
+        msgFilesTooLess: 'Musíte vybrat nejméně <b>{n}</b> {files} souborů.',
+        msgFilesTooMany: 'Počet vybraných souborů <b>({n})</b> překročil maximální povolený limit <b>{m}</b>.',
+        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}".',
+        msgInvalidFileName: 'Neplatné nebo nepovolené znaky ve jménu souboru "{name}".',
+        msgInvalidFileType: 'Neplatný typ souboru "{name}". Pouze "{types}" souborů jsou podporovány.',
+        msgInvalidFileExtension: 'Neplatná extenze souboru "{name}". Pouze "{extensions}" souborů jsou podporovány.',
+        msgFileTypes: {
+            'image': 'obrázek',
+            'html': 'HTML',
+            'text': 'text',
+            'video': 'video',
+            'audio': 'audio',
+            'flash': 'flash',
+            'pdf': 'PDF',
+            'object': 'object'
+        },
+        msgUploadAborted: 'Nahrávání souboru bylo přerušeno',
+        msgUploadThreshold: 'Zpracovávám...',
+        msgUploadBegin: 'Inicializujem...',
+        msgUploadEnd: 'Hotovo',
+        msgUploadEmpty: 'Pro nahrávání nejsou k dispozici žádné platné údaje.',
+        msgUploadError: 'Chyba',
+        msgValidationError: 'Chyba ověření',
+        msgLoading: 'Nahrávání souboru {index} z {files} &hellip;',
+        msgProgress: 'Nahrávání souboru {index} z {files} - {name} - {percent}% dokončeno.',
+        msgSelected: '{n} {files} vybráno',
+        msgFoldersNotAllowed: 'Táhni a pusť pouze soubory! Vynechané {n} pustěné složk(y).',
+        msgImageWidthSmall: 'Šířka obrázku "{name}", musí být alespoň {size} px.',
+        msgImageHeightSmall: 'Výška obrázku "{name}", musí být alespoň {size} px.',
+        msgImageWidthLarge: 'Šířka obrázku "{name}" nesmí být větší než {size} px.',
+        msgImageHeightLarge: 'Výška obrázku "{name}" nesmí být větší než {size} px.',
+        msgImageResizeError: 'Nelze získat rozměry obrázku pro změnu velikosti.',
+        msgImageResizeException: 'Chyba při změně velikosti obrázku.<pre>{errors}</pre>',
+        msgAjaxError: 'Došlo k chybě v {operation}. Prosím zkuste to znovu později!',
+        msgAjaxProgressError: '{operation} - neúspěšné',
+        ajaxOperations: {
+            deleteThumb: 'odstranit soubor',
+            uploadThumb: 'nahrát soubor',
+            uploadBatch: 'nahrát várku souborů',
+            uploadExtra: 'odesílání dat formuláře'
+        },
+        dropZoneTitle: 'Přetáhni soubory sem &hellip;',
+        dropZoneClickTitle: '<br>(nebo klikni sem a vyber je)',
+        fileActionSettings: {
+            removeTitle: 'Odstranit soubor',
+            uploadTitle: 'Nahrát soubor',
+            uploadRetryTitle: 'Opakovat nahrávání',
+            downloadTitle: 'Stáhnout soubor',
+            zoomTitle: 'Zobrazit podrobnosti',
+            dragTitle: 'Posunout / Přeskládat',
+            indicatorNewTitle: 'Ještě nenahrál',
+            indicatorSuccessTitle: 'Nahraný',
+            indicatorErrorTitle: 'Chyba nahrávání',
+            indicatorLoadingTitle: 'Nahrávání ...'
+        },
+        previewZoomButtonTitles: {
+            prev: 'Zobrazit předchozí soubor',
+            next: 'Zobrazit následující soubor',
+            toggleheader: 'Přepnout záhlaví',
+            fullscreen: 'Přepnout celoobrazovkové zobrazení',
+            borderless: 'Přepnout bezrámečkové zobrazení',
+            close: 'Zavřít detailní náhled'
+        }
+    };
+})(window.jQuery);

+ 100 - 0
public/base/plugins/bootstrap-fileinput/js/locales/da.js

xqd
@@ -0,0 +1,100 @@
+/*!
+ * FileInput Danish 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['da'] = {
+        fileSingle: 'fil',
+        filePlural: 'filer',
+        browseLabel: 'Browse &hellip;',
+        removeLabel: 'Fjern',
+        removeTitle: 'Fjern valgte filer',
+        cancelLabel: 'Fortryd',
+        cancelTitle: 'Afbryd nuv&aelig;rende upload',
+        uploadLabel: 'Upload',
+        uploadTitle: 'Upload valgte filer',
+        msgNo: 'Ingen',
+        msgNoFilesSelected: '',
+        msgCancelled: 'aflyst',
+        msgPlaceholder: 'V&aelig;lg {files}...',
+        msgZoomModalHeading: 'Detaljeret visning',
+        msgFileRequired: 'Du skal v&aelig;lge en fil at uploade.',
+        msgSizeTooSmall: 'Fil "{name}" (<b>{size} KB</b>) er for lille og skal v&aelig;re st&oslash;rre end <b>{minSize} KB</b>.',
+        msgSizeTooLarge: 'Fil "{name}" (<b>{size} KB</b>) er st&oslash;rre end de tilladte <b>{maxSize} KB</b>.',
+        msgFilesTooLess: 'Du skal mindst v&aelig;lge <b>{n}</b> {files} til upload.',
+        msgFilesTooMany: '<b>({n})</b> filer valgt til upload, men maks. <b>{m}</b> er tilladt.',
+        msgFileNotFound: 'Filen "{name}" blev ikke fundet!',
+        msgFileSecured: 'Sikkerhedsrestriktioner forhindrer l&aelig;sning af "{name}".',
+        msgFileNotReadable: 'Filen "{name}" kan ikke indl&aelig;ses.',
+        msgFilePreviewAborted: 'Filgennemsyn annulleret for "{name}".',
+        msgFilePreviewError: 'Der skete en fejl under l&aelig;sningen af filen "{name}".',
+        msgInvalidFileName: 'Ugyldige eller ikke-underst&oslash;ttede tegn i filnavn "{name}".',
+        msgInvalidFileType: 'Ukendt type for filen "{name}". Kun "{types}" kan bruges.',
+        msgInvalidFileExtension: 'Ukendt filtype for filen "{name}". Kun "{extensions}" filer kan bruges.',
+        msgFileTypes: {
+            'image': 'image',
+            'html': 'HTML',
+            'text': 'text',
+            'video': 'video',
+            'audio': 'audio',
+            'flash': 'flash',
+            'pdf': 'PDF',
+            'object': 'object'
+        },
+        msgUploadAborted: 'Filupload annulleret',
+        msgUploadThreshold: 'Arbejder...',
+        msgUploadBegin: 'Initialiserer...',
+        msgUploadEnd: 'Udf&oslash;rt',
+        msgUploadEmpty: 'Ingen gyldig data tilg&aelig;ngelig til upload.',
+        msgUploadError: 'Fejl',
+        msgValidationError: 'Valideringsfejl',
+        msgLoading: 'Henter fil {index} af {files} &hellip;',
+        msgProgress: 'Henter fil {index} af {files} - {name} - {percent}% f&aelig;rdiggjort.',
+        msgSelected: '{n} {files} valgt',
+        msgFoldersNotAllowed: 'Drag & drop kun filer! {n} mappe(r) sprunget over.',
+        msgImageWidthSmall: 'Bredden af billedet "{name}" skal v&aelig;re p&aring; mindst {size} px.',
+        msgImageHeightSmall: 'H&oslash;jden af billedet "{name}" skal v&aelig;re p&aring; mindst {size} px.',
+        msgImageWidthLarge: 'Bredden af billedet "{name}" m&aring; ikke v&aelig;re over {size} px.',
+        msgImageHeightLarge: 'H&oslash;jden af billedet "{name}" m&aring; ikke v&aelig;re over {size} px.',
+        msgImageResizeError: 'Kunne ikke f&aring; billedets dimensioner for at &aelig;ndre st&oslash;rrelsen.',
+        msgImageResizeException: 'Fejl ved at &aelig;ndre st&oslash;rrelsen p&aring; billedet.<pre>{errors}</pre>',
+        msgAjaxError: 'Noget gik galt med {operation} operationen. Fors&oslash;g venligst senere!',
+        msgAjaxProgressError: '{operation} fejlede',
+        ajaxOperations: {
+            deleteThumb: 'fil slet',
+            uploadThumb: 'fil upload',
+            uploadBatch: 'batchfil upload',
+            uploadExtra: 'form data upload'
+        },
+        dropZoneTitle: 'Drag & drop filer her &hellip;',
+        dropZoneClickTitle: '<br>(eller klik for at v&aelig;lge {files})',
+        fileActionSettings: {
+            removeTitle: 'Fjern fil',
+            uploadTitle: 'Upload fil',
+            uploadRetryTitle: 'Fors&aring;g upload igen',
+            downloadTitle: 'Download fil',
+            zoomTitle: 'Se detaljer',
+            dragTitle: 'Flyt / Omarranger',
+            indicatorNewTitle: 'Ikke uploadet endnu',
+            indicatorSuccessTitle: 'Uploadet',
+            indicatorErrorTitle: 'Upload fejl',
+            indicatorLoadingTitle: 'Uploader ...'
+        },
+        previewZoomButtonTitles: {
+            prev: 'Se forrige fil',
+            next: 'Se n&aelig;ste fil',
+            toggleheader: 'Skift header',
+            fullscreen: 'Skift fuld sk&aelig;rm',
+            borderless: 'Skift gr&aelig;nsel&oslash;s mode',
+            close: 'Luk detaljeret visning'
+        }
+    };
+})(window.jQuery);

+ 98 - 0
public/base/plugins/bootstrap-fileinput/js/locales/de.js

xqd
@@ -0,0 +1,98 @@
+/*!
+ * 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: 'Abbrechen',
+        cancelTitle: 'Hochladen abbrechen',
+        uploadLabel: 'Hochladen',
+        uploadTitle: 'Hochladen der ausgewählten Dateien',
+        msgNo: 'Keine',
+        msgNoFilesSelected: 'Keine Dateien ausgewählt',
+        msgCancelled: 'Abgebrochen',
+        msgPlaceholder: '{files} auswählen...',
+        msgZoomModalHeading: 'ausführliche Vorschau',
+        msgFileRequired: 'Sie müssen eine Datei zum Hochladen auswählen.',
+        msgSizeTooSmall: 'Datei "{name}" (<b>{size} KB</b>) unterschreitet mindestens notwendige Upload-Größe von <b>{minSize} KB</b>.',
+        msgSizeTooLarge: 'Datei "{name}" (<b>{size} KB</b>) überschreitet maximal zulässige Upload-Größe von <b>{maxSize} KB</b>.',
+        msgFilesTooLess: 'Sie müssen mindestens <b>{n}</b> {files} zum Hochladen auswählen.',
+        msgFilesTooMany: 'Anzahl der zum Hochladen ausgewählten Dateien <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.',
+        msgInvalidFileName: 'Ungültige oder nicht unterstützte Zeichen im Dateinamen "{name}".',
+        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.',
+        msgFileTypes: {
+            'image': 'image',
+            'html': 'HTML',
+            'text': 'text',
+            'video': 'video',
+            'audio': 'audio',
+            'flash': 'flash',
+            'pdf': 'PDF',
+            'object': 'object'
+        },
+        msgUploadAborted: 'Der Datei-Upload wurde abgebrochen',
+        msgUploadThreshold: 'Wird bearbeitet ...',
+        msgUploadBegin: 'Wird initialisiert ...',
+        msgUploadEnd: 'Erledigt',
+        msgUploadEmpty: 'Keine gültigen Daten zum Hochladen verfügbar.',
+        msgUploadError: 'Fehler',
+        msgValidationError: 'Validierungsfehler',
+        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.',
+        msgImageResizeError: 'Konnte nicht die Bildabmessungen zu ändern.',
+        msgImageResizeException: 'Fehler beim Ändern der Größe des Bildes.<pre>{errors}</pre>',
+        msgAjaxError: 'Bei der Aktion {operation} ist ein Fehler aufgetreten. Bitte versuche es später noch einmal!',
+        msgAjaxProgressError: '{operation} fehlgeschlagen',
+        ajaxOperations: {
+            deleteThumb: 'Datei löschen',
+            uploadThumb: 'Datei hochladen',
+            uploadBatch: 'Batch-Datei-Upload',
+            uploadExtra: 'Formular-Datei-Upload'
+        },
+        dropZoneTitle: 'Dateien hierher ziehen &hellip;',
+        dropZoneClickTitle: '<br>(oder klicken um {files} auszuwählen)',
+        fileActionSettings: {
+            removeTitle: 'Datei entfernen',
+            uploadTitle: 'Datei hochladen',
+            uploadRetryTitle: 'Upload erneut versuchen',
+            downloadTitle: 'Datei herunterladen',
+            zoomTitle: 'Details anzeigen',
+            dragTitle: 'Verschieben / Neuordnen',
+            indicatorNewTitle: 'Noch nicht hochgeladen',
+            indicatorSuccessTitle: 'Hochgeladen',
+            indicatorErrorTitle: 'Upload Fehler',
+            indicatorLoadingTitle: 'Hochladen ...'
+        },
+        previewZoomButtonTitles: {
+            prev: 'Vorherige Datei anzeigen',
+            next: 'Nächste Datei anzeigen',
+            toggleheader: 'Header umschalten',
+            fullscreen: 'Vollbildmodus umschalten',
+            borderless: 'Randlosen Modus umschalten',
+            close: 'Detailansicht schließen'
+        }
+    };
+})(window.jQuery);

+ 100 - 0
public/base/plugins/bootstrap-fileinput/js/locales/el.js

xqd
@@ -0,0 +1,100 @@
+/*!
+ * 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: 'Μεταφόρτωση επιλεγμένων αρχείων',
+        msgNo: 'Όχι',
+        msgNoFilesSelected: 'Δεν επιλέχθηκαν αρχεία',
+        msgCancelled: 'Ακυρώθηκε',
+        msgPlaceholder: 'Select {files}...',
+        msgZoomModalHeading: 'Λεπτομερής Προεπισκόπηση',
+        msgFileRequired: 'You must select a file to upload.',
+        msgSizeTooSmall: 'Το "{name}" (<b>{size} KB</b>) είναι πολύ μικρό, πρέπει να είναι μεγαλύτερο από <b>{minSize} KB</b>.',
+        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}".',
+        msgInvalidFileName: 'Μη έγκυροι χαρακτήρες στο όνομα του αρχείου "{name}".',
+        msgInvalidFileType: 'Μη έγκυρος ο τύπος του αρχείου "{name}". Οι τύποι αρχείων που υποστηρίζονται είναι : "{types}".',
+        msgInvalidFileExtension: 'Μη έγκυρη η επέκταση του αρχείου "{name}". Οι επεκτάσεις που υποστηρίζονται είναι : "{extensions}".',
+        msgFileTypes: {
+            'image': 'image',
+            'html': 'HTML',
+            'text': 'text',
+            'video': 'video',
+            'audio': 'audio',
+            'flash': 'flash',
+            'pdf': 'PDF',
+            'object': 'object'
+        },
+        msgUploadAborted: 'Η μεταφόρτωση του αρχείου ματαιώθηκε',
+        msgUploadThreshold: 'Μεταφόρτωση ...',
+        msgUploadBegin: 'Initializing...',
+        msgUploadEnd: 'Done',
+        msgUploadEmpty: 'No valid data available for upload.',
+        msgUploadError: 'Error',
+        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.',
+        msgImageResizeError: 'Δεν μπορούν να βρεθούν οι διαστάσεις της εικόνας για να αλλάγή μεγέθους.',
+        msgImageResizeException: 'Σφάλμα κατά την αλλαγή μεγέθους της εικόνας. <pre>{errors}</pre>',
+        msgAjaxError: 'Something went wrong with the {operation} operation. Please try again later!',
+        msgAjaxProgressError: '{operation} failed',
+        ajaxOperations: {
+            deleteThumb: 'file delete',
+            uploadThumb: 'file upload',
+            uploadBatch: 'batch file upload',
+            uploadExtra: 'form data upload'
+        },
+        dropZoneTitle: 'Σύρετε τα αρχεία εδώ &hellip;',
+        dropZoneClickTitle: '<br>(ή πατήστε για επιλογή {files})',
+        fileActionSettings: {
+            removeTitle: 'Αφαιρέστε το αρχείο',
+            uploadTitle: 'Μεταφορτώστε το αρχείο',
+            uploadRetryTitle: 'Retry upload',
+            downloadTitle: 'Download file',
+            zoomTitle: 'Δείτε λεπτομέρειες',
+            dragTitle: 'Μετακίνηση/Προσπαρμογή',
+            indicatorNewTitle: 'Δεν μεταφορτώθηκε ακόμα',
+            indicatorSuccessTitle: 'Μεταφορτώθηκε',
+            indicatorErrorTitle: 'Σφάλμα Μεταφόρτωσης',
+            indicatorLoadingTitle: 'Μεταφόρτωση ...'
+        },
+        previewZoomButtonTitles: {
+            prev: 'Προηγούμενο αρχείο',
+            next: 'Επόμενο αρχείο',
+            toggleheader: 'Εμφάνιση/Απόκρυψη τίτλου',
+            fullscreen: 'Εναλλαγή πλήρους οθόνης',
+            borderless: 'Με ή χωρίς πλαίσιο',
+            close: 'Κλείσιμο προβολής'
+        }
+    };
+})(window.jQuery);

+ 100 - 0
public/base/plugins/bootstrap-fileinput/js/locales/es.js

xqd
@@ -0,0 +1,100 @@
+/*!
+ * 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',
+        msgNo: 'No',
+        msgNoFilesSelected: 'No hay archivos seleccionados',
+        msgCancelled: 'Cancelado',
+        msgPlaceholder: 'Seleccionar {files}...',
+        msgZoomModalHeading: 'Vista previa detallada',
+        msgFileRequired: 'Debes seleccionar un archivo para subir.',
+        msgSizeTooSmall: 'El archivo "{name}" (<b>{size} KB</b>) es demasiado pequeño y debe ser mayor de <b>{minSize} KB</b>.',
+        msgSizeTooLarge: 'El archivo "{name}" (<b>{size} KB</b>) excede el tamaño máximo permitido de <b>{maxSize} KB</b>.',
+        msgFilesTooLess: 'Debe seleccionar al menos <b>{n}</b> {files} a cargar.',
+        msgFilesTooMany: 'El número de archivos seleccionados a cargar <b>({n})</b> excede el límite máximo permitido de <b>{m}</b>.',
+        msgFileNotFound: 'Archivo "{name}" no encontrado.',
+        msgFileSecured: 'No es posible acceder al archivo "{name}" porque está siendo usado por otra aplicación o no tiene 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}".',
+        msgInvalidFileName: 'Caracteres no válidos o no soportados en el nombre del archivo "{name}".',
+        msgInvalidFileType: 'Tipo de archivo no válido para "{name}". Sólo se permiten archivos de tipo "{types}".',
+        msgInvalidFileExtension: 'Extensión de archivo no válida para "{name}". Sólo se permiten archivos "{extensions}".',
+        msgFileTypes: {
+            'image': 'image',
+            'html': 'HTML',
+            'text': 'text',
+            'video': 'video',
+            'audio': 'audio',
+            'flash': 'flash',
+            'pdf': 'PDF',
+            'object': 'object'
+        },
+        msgUploadAborted: 'La carga de archivos se ha cancelado',
+        msgUploadThreshold: 'Procesando...',
+        msgUploadBegin: 'Inicializando...',
+        msgUploadEnd: 'Hecho',
+        msgUploadEmpty: 'No existen datos válidos para el envío.',
+        msgUploadError: 'Error',
+        msgValidationError: 'Error de validación',
+        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 de al menos {size} px.',
+        msgImageHeightSmall: 'La altura de la imagen "{name}" debe ser de 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.',
+        msgImageResizeError: 'No se pudieron obtener las dimensiones de la imagen para cambiar el tamaño.',
+        msgImageResizeException: 'Error al cambiar el tamaño de la imagen.<pre>{errors}</pre>',
+        msgAjaxError: 'Algo ha ido mal con la operación {operation}. Por favor, inténtelo de nuevo mas tarde.',
+        msgAjaxProgressError: 'La operación {operation} ha fallado',
+        ajaxOperations: {
+            deleteThumb: 'Archivo borrado',
+            uploadThumb: 'Archivo subido',
+            uploadBatch: 'Datos subidos en lote',
+            uploadExtra: 'Datos del formulario subidos '
+        },
+        dropZoneTitle: 'Arrastre y suelte aquí los archivos &hellip;',
+        dropZoneClickTitle: '<br>(o haga clic para seleccionar {files})',
+        fileActionSettings: {
+            removeTitle: 'Eliminar archivo',
+            uploadTitle: 'Subir archivo',
+            uploadRetryTitle: 'Reintentar subir',
+            downloadTitle: 'Descargar archivo',
+            zoomTitle: 'Ver detalles',
+            dragTitle: 'Mover / Reordenar',
+            indicatorNewTitle: 'No subido todavía',
+            indicatorSuccessTitle: 'Subido',
+            indicatorErrorTitle: 'Error al subir',
+            indicatorLoadingTitle: 'Subiendo...'
+        },
+        previewZoomButtonTitles: {
+            prev: 'Anterior',
+            next: 'Siguiente',
+            toggleheader: 'Mostrar encabezado',
+            fullscreen: 'Pantalla completa',
+            borderless: 'Modo sin bordes',
+            close: 'Cerrar vista detallada'
+        }
+    };
+})(window.jQuery);

+ 99 - 0
public/base/plugins/bootstrap-fileinput/js/locales/et.js

xqd
@@ -0,0 +1,99 @@
+/*!
+ * FileInput Estonian 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['et'] = {
+        fileSingle: 'fail',
+        filePlural: 'failid',
+        browseLabel: 'Sirvi &hellip;',
+        removeLabel: 'Eemalda',
+        removeTitle: 'Clear selected files',
+        cancelLabel: 'Tühista',
+        cancelTitle: 'Abort ongoing upload',
+        uploadLabel: 'Salvesta',
+        uploadTitle: 'Salvesta valitud failid',
+        msgNo: 'No',
+        msgNoFilesSelected: 'No files selected',
+        msgCancelled: 'Cancelled',
+        msgPlaceholder: 'Select {files}...',
+        msgZoomModalHeading: 'Detailed Preview',
+        msgFileRequired: 'You must select a file to upload.',
+        msgSizeTooSmall: 'File "{name}" (<b>{size} KB</b>) is too small and must be larger than <b>{minSize} KB</b>.',
+        msgSizeTooLarge: 'Fail "{name}" (<b>{size} KB</b>) ületab lubatu suuruse <b>{maxSize} KB</b>.',
+        msgFilesTooLess: 'You must select at least <b>{n}</b> {files} to upload.',
+        msgFilesTooMany: 'Number of files selected for upload <b>({n})</b> exceeds maximum allowed limit of <b>{m}</b>.',
+        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}".',
+        msgInvalidFileName: 'Invalid or unsupported characters in file name "{name}".',
+        msgInvalidFileType: '"{name}" on vale tüüpi. Ainult "{types}" on lubatud.',
+        msgInvalidFileExtension: 'Invalid extension for file "{name}". Only "{extensions}" files are supported.',
+        msgFileTypes: {
+            'image': 'image',
+            'html': 'HTML',
+            'text': 'text',
+            'video': 'video',
+            'audio': 'audio',
+            'flash': 'flash',
+            'pdf': 'PDF',
+            'object': 'object'
+        },
+        msgUploadAborted: 'The file upload was aborted',
+        msgUploadThreshold: 'Processing...',
+        msgUploadBegin: 'Initializing...',
+        msgUploadEnd: 'Done',
+        msgUploadEmpty: 'No valid data available for upload.',
+        msgUploadError: 'Error',
+        msgValidationError: 'Validation 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: 'Pildi laius peab olema vähemalt {size} px.',
+        msgImageHeightSmall: 'Pildi kõrgus peab olema vähemalt {size} px.',
+        msgImageWidthLarge: 'Width of image file "{name}" cannot exceed {size} px.',
+        msgImageHeightLarge: 'Height of image file "{name}" cannot exceed {size} px.',
+        msgImageResizeError: 'Could not get the image dimensions to resize.',
+        msgImageResizeException: 'Error while resizing the image.<pre>{errors}</pre>',
+        msgAjaxError: 'Something went wrong with the {operation} operation. Please try again later!',
+        msgAjaxProgressError: '{operation} failed',
+        ajaxOperations: {
+            deleteThumb: 'file delete',
+            uploadThumb: 'file upload',
+            uploadBatch: 'batch file upload',
+            uploadExtra: 'form data upload'
+        },
+        dropZoneTitle: 'Lohista failid siia &hellip;',
+        dropZoneClickTitle: '<br>(or click to select {files})',
+        fileActionSettings: {
+            removeTitle: 'Eemalda fail',
+            uploadTitle: 'Salvesta fail',
+            uploadRetryTitle: 'Retry upload',
+            zoomTitle: 'Vaata detaile',
+            dragTitle: 'Liiguta / Korralda',
+            indicatorNewTitle: 'Pole veel salvestatud',
+            indicatorSuccessTitle: 'Uploaded',
+            indicatorErrorTitle: 'Salvestamise viga',
+            indicatorLoadingTitle: 'Salvestan ...'
+        },
+        previewZoomButtonTitles: {
+            prev: 'View previous file',
+            next: 'View next file',
+            toggleheader: 'Toggle header',
+            fullscreen: 'Toggle full screen',
+            borderless: 'Toggle borderless mode',
+            close: 'Close detailed preview'
+        }
+    };
+})(window.jQuery);

+ 101 - 0
public/base/plugins/bootstrap-fileinput/js/locales/fa.js

xqd
@@ -0,0 +1,101 @@
+/*!
+ * 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 <milad@nekofar.com>
+ *
+ * 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: 'بارگذاری فایل‌های انتخاب شده',
+        msgNo: 'نه',
+        msgNoFilesSelected: 'هیچ فایلی انتخاب نشده است',
+        msgCancelled: 'لغو شد',
+        msgPlaceholder: 'انتخاب {files}...',
+        msgZoomModalHeading: 'نمایش با جزییات',
+        msgFileRequired: 'شما باید یک فایل برای بارگذاری انتخاب نمایید.',
+        msgSizeTooSmall: 'فایل "{name}" (<b>{size} کیلوبایت</b>) خیلی کوچک است و باید از <b>{minSize} کیلوبایت بزرگتر باشد</b>.',
+        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}" خطایی رخ داد.',
+        msgInvalidFileName: 'کاراکترهای غیرمجاز و یا ناشناخته در نام فایل "{name}".',
+        msgInvalidFileType: 'نوع فایل "{name}" معتبر نیست. فقط "{types}" پشیبانی می‌شوند.',
+        msgInvalidFileExtension: 'پسوند فایل "{name}" معتبر نیست. فقط "{extensions}" پشتیبانی می‌شوند.',
+        msgFileTypes: {
+            'image': 'عکس',
+            'html': 'اچ تا ام ال',
+            'text': 'متن',
+            'video': 'ویدئو',
+            'audio': 'صدا',
+            'flash': 'فلش',
+            'pdf': 'پی دی اف',
+            'object': 'دیگر'
+        },
+        msgUploadAborted: 'بارگذاری فایل به مشکل خورد.',
+        msgUploadThreshold: 'در حال پردازش...',
+        msgUploadBegin: 'در حال شروع...',
+        msgUploadEnd: 'انجام شد',
+        msgUploadEmpty: 'هیچ داده معتبری برای بارگذاری موجود نیست.',
+        msgUploadError: 'Error',
+        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} پیکسل بیشتر باشد.',
+        msgImageResizeError: 'یافت نشد ابعاد تصویر را برای تغییر اندازه.',
+        msgImageResizeException: 'خطا در هنگام تغییر اندازه تصویر.<pre>{errors}</pre>',
+        msgAjaxError: 'به نظر مشکلی در حین {operation} روی داده است. لطفا دوباره تلاش کنید!',
+        msgAjaxProgressError: '{operation} لغو شد',
+        ajaxOperations: {
+            deleteThumb: 'حذف فایل',
+            uploadThumb: 'بارگذاری فایل',
+            uploadBatch: 'بارگذاری جمعی فایلها',
+            uploadExtra: 'بارگذاری با کمک فُرم'
+        },
+        dropZoneTitle: 'فایل‌ها را بکشید و در اینجا رها کنید &hellip;',
+        dropZoneClickTitle: '<br>(یا برای انتخاب {files} کلیک کنید)',
+        fileActionSettings: {
+            removeTitle: 'حذف فایل',
+            uploadTitle: 'آپلود فایل',
+            uploadRetryTitle: 'بارگیری مجدد',
+            downloadTitle: 'دریافت فایل',
+            zoomTitle: 'دیدن جزئیات',
+            dragTitle: 'جابجایی / چیدمان',
+            indicatorNewTitle: 'آپلود نشده است',
+            indicatorSuccessTitle: 'آپلود شده',
+            indicatorErrorTitle: 'بارگذاری خطا',
+            indicatorLoadingTitle: 'آپلود ...'
+        },
+        previewZoomButtonTitles: {
+            prev: 'مشاهده فایل قبلی',
+            next: 'مشاهده فایل بعدی',
+            toggleheader: 'نمایش عنوان',
+            fullscreen: 'نمایش تمام صفحه',
+            borderless: 'نمایش حاشیه',
+            close: 'بستن نمایش با جزییات'
+        }
+    };
+})(window.jQuery);

+ 91 - 0
public/base/plugins/bootstrap-fileinput/js/locales/fi.js

xqd
@@ -0,0 +1,91 @@
+/*!
+ * FileInput Finnish 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.fi = {
+        fileSingle: 'tiedosto',
+        filePlural: 'tiedostot',
+        browseLabel: 'Selaa &hellip;',
+        removeLabel: 'Poista',
+        removeTitle: 'Tyhj&auml;nn&auml; valitut tiedostot',
+        cancelLabel: 'Peruuta',
+        cancelTitle: 'Peruuta lataus',
+        uploadLabel: 'Lataa',
+        uploadTitle: 'Lataa valitut tiedostot',
+        msgNoFilesSelected: '',
+        msgFileRequired: 'You must select a file to upload.',
+        msgSizeTooSmall: 'File "{name}" (<b>{size} KB</b>) is too small and must be larger than <b>{minSize} KB</b>.',
+        msgSizeTooLarge: 'Tiedosto "{name}" (<b>{size} Kt</b>) ylitt&auml;&auml; suurimman sallitun tiedoston koon, joka on <b>{maxSize} Kt</b>. Yrit&auml; uudelleen!',
+        msgFilesTooLess: 'V&auml;hint&auml;&auml;n <b>{n}</b> {files} tiedostoa on valittava ladattavaksi. Ole hyv&auml; ja yrit&auml; uudelleen!',
+        msgFilesTooMany: 'Valittujen tiedostojen lukum&auml;&auml;r&auml; <b>({n})</b> ylitt&auml;&auml; suurimman sallitun m&auml;&auml;r&auml;n <b>{m}</b>. Ole hyv&auml; ja yrit&auml; uudelleen!',
+        msgFileNotFound: 'Tiedostoa "{name}" ei l&ouml;ydy!',
+        msgFileSecured: 'Tietoturvarajoitukset est&auml;v&auml;t tiedoston "{name}" lukemisen.',
+        msgFileNotReadable: 'Tiedosto "{name}" ei ole luettavissa.',
+        msgFilePreviewAborted: 'Tiedoston "{name}" esikatselu keskeytetty.',
+        msgFilePreviewError: 'Virhe on tapahtunut luettaessa tiedostoa "{name}".',
+        msgInvalidFileName: 'Invalid or unsupported characters in file name "{name}".',
+        msgInvalidFileType: 'Tiedosto "{name}" on v&auml;&auml;r&auml;n tyyppinen. Ainoastaan tiedostot tyyppi&auml; "{types}" ovat tuettuja.',
+        msgInvalidFileExtension: 'Tiedoston "{name}" tarkenne on ep&auml;kelpo. Ainoastaan tarkenteet "{extensions}" ovat tuettuja.',
+        msgFileTypes: {
+            'image': 'Kuva',
+            'html': 'HTML',
+            'text': 'Teksti',
+            'video': 'Video',
+            'audio': 'Ääni',
+            'flash': 'Flash',
+            'pdf': 'PDF',
+            'object': 'Olio'
+        },
+        msgUploadThreshold: 'Käsitellään...',
+        msgUploadBegin: 'Initializing...',
+        msgUploadEnd: 'Done',
+        msgUploadEmpty: 'Ei ladattavaa dataa.',
+        msgUploadError: 'Error',
+        msgValidationError: 'Tiedoston latausvirhe',
+        msgLoading: 'Ladataan tiedostoa {index} / {files} &hellip;',
+        msgProgress: 'Ladataan tiedostoa {index} / {files} - {name} - {percent}% valmistunut.',
+        msgSelected: '{n} tiedostoa valittu',
+        msgFoldersNotAllowed: 'Raahaa ja pudota ainoastaan tiedostoja! Ohitettu {n} raahattua kansiota.',
+        msgAjaxError: 'Something went wrong with the {operation} operation. Please try again later!',
+        msgAjaxProgressError: '{operation} failed',
+        ajaxOperations: {
+            deleteThumb: 'file delete',
+            uploadThumb: 'file upload',
+            uploadBatch: 'batch file upload',
+            uploadExtra: 'form data upload'
+        },
+        dropZoneTitle: 'Raahaa ja pudota tiedostot t&auml;h&auml;n &hellip;',
+        dropZoneClickTitle: '<br>(tai valitse hiirellä {files})',
+        fileActionSettings: {
+            removeTitle: 'Poista tiedosto',
+            uploadTitle: 'Upload file',
+            uploadRetryTitle: 'Retry upload',
+            downloadTitle: 'Download file',
+            zoomTitle: 'Yksityiskohdat',
+            dragTitle: 'Siirrä / Järjestele',
+            indicatorNewTitle: 'Ei ladattu',
+            indicatorSuccessTitle: 'Ladattu',
+            indicatorErrorTitle: 'Lataus epäonnistui',
+            indicatorLoadingTitle: 'Ladataan ...'
+        },
+        previewZoomButtonTitles: {
+            prev: 'Seuraava tiedosto',
+            next: 'Edellinen tiedosto',
+            toggleheader: 'Näytä otsikko',
+            fullscreen: 'Kokonäytön tila',
+            borderless: 'Rajaton tila',
+            close: 'Sulje esikatselu'
+        }
+    };
+
+    $.extend($.fn.fileinput.defaults, $.fn.fileinputLocales.fi);
+})(window.jQuery);

+ 99 - 0
public/base/plugins/bootstrap-fileinput/js/locales/fr.js

xqd
@@ -0,0 +1,99 @@
+/*!
+ * 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',
+        msgNo: 'Non',
+        msgNoFilesSelected: '',
+        msgCancelled: 'Annulé',
+        msgPlaceholder: 'Sélectionner le(s) {files}...',
+        msgZoomModalHeading: 'Aperçu détaillé',
+        msgFileRequired: 'Vous devez sélectionner un fichier à uploader.',
+        msgSizeTooSmall: 'Le fichier "{name}" (<b>{size} KB</b>) est inférieur à la taille minimale de <b>{minSize} KB</b>.',
+        msgSizeTooLarge: 'Le fichier "{name}" (<b>{size} Ko</b>) dépasse la taille maximale autorisée qui est de <b>{maxSize} Ko</b>.',
+        msgFilesTooLess: 'Vous devez sélectionner au moins <b>{n}</b> {files} à transmettre.',
+        msgFilesTooMany: 'Le nombre de fichier sélectionné <b>({n})</b> dépasse la quantité maximale autorisée qui est de <b>{m}</b>.',
+        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 illisible.',
+        msgFilePreviewAborted: 'Prévisualisation du fichier "{name}" annulée.',
+        msgFilePreviewError: 'Une erreur est survenue lors de la lecture du fichier "{name}".',
+        msgInvalidFileName: 'Caractères invalides ou non supportés dans le nom de 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.',
+        msgFileTypes: {
+            'image': 'image',
+            'html': 'HTML',
+            'text': 'text',
+            'video': 'video',
+            'audio': 'audio',
+            'flash': 'flash',
+            'pdf': 'PDF',
+            'object': 'object'
+        },
+        msgUploadAborted: 'Le transfert du fichier a été interrompu',
+        msgUploadThreshold: 'En cours...',
+        msgUploadBegin: 'Initialisation...',
+        msgUploadEnd: 'Terminé',
+        msgUploadEmpty: 'Aucune donnée valide disponible pour transmission.',
+        msgUploadError: 'Erreur',
+        msgValidationError: 'Erreur de validation',
+        msgLoading: 'Transmission du fichier {index} sur {files}&hellip;',
+        msgProgress: 'Transmission du fichier {index} sur {files} - {name} - {percent}%.',
+        msgSelected: '{n} {files} sélectionné(s)',
+        msgFoldersNotAllowed: 'Glissez et déposez uniquement des fichiers ! {n} répertoire(s) exclu(s).',
+        msgImageWidthSmall: 'La largeur de l\'image "{name}" doit être d\'au moins {size} px.',
+        msgImageHeightSmall: 'La hauteur de l\'image "{name}" doit être d\'au moins {size} px.',
+        msgImageWidthLarge: 'La largeur de l\'image "{name}" ne peut pas dépasser {size} px.',
+        msgImageHeightLarge: 'La hauteur de l\'image "{name}" ne peut pas dépasser {size} px.',
+        msgImageResizeError: "Impossible d'obtenir les dimensions de l'image à redimensionner.",
+        msgImageResizeException: "Erreur lors du redimensionnement de l'image.<pre>{errors}</pre>",
+        msgAjaxError: "Une erreur s'est produite pendant l'opération de {operation}. Veuillez réessayer plus tard.",
+        msgAjaxProgressError: 'L\'opération "{operation}" a échoué',
+        ajaxOperations: {
+            deleteThumb: 'suppression du fichier',
+            uploadThumb: 'transfert du fichier',
+            uploadBatch: 'transfert des fichiers',
+            uploadExtra: 'soumission des données de formulaire'
+        },
+        dropZoneTitle: 'Glissez et déposez les fichiers ici&hellip;',
+        dropZoneClickTitle: '<br>(ou cliquez pour sélectionner manuellement)',
+        fileActionSettings: {
+            removeTitle: 'Supprimer le fichier',
+            uploadTitle: 'Transférer le fichier',
+            uploadRetryTitle: 'Relancer le transfert',
+            zoomTitle: 'Voir les détails',
+            dragTitle: 'Déplacer / Réarranger',
+            indicatorNewTitle: 'Pas encore transféré',
+            indicatorSuccessTitle: 'Posté',
+            indicatorErrorTitle: 'Ajouter erreur',
+            indicatorLoadingTitle: 'En cours...'
+        },
+        previewZoomButtonTitles: {
+            prev: 'Voir le fichier précédent',
+            next: 'Voir le fichier suivant',
+            toggleheader: 'Masquer le titre',
+            fullscreen: 'Mode plein écran',
+            borderless: 'Mode cinéma',
+            close: "Fermer l'aperçu"
+        }
+    };
+})(window.jQuery);

+ 100 - 0
public/base/plugins/bootstrap-fileinput/js/locales/gl.js

xqd
@@ -0,0 +1,100 @@
+/*!
+ * FileInput Galician 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['gl'] = {
+        fileSingle: 'arquivo',
+        filePlural: 'arquivos',
+        browseLabel: 'Examinar &hellip;',
+        removeLabel: 'Quitar',
+        removeTitle: 'Quitar aquivos seleccionados',
+        cancelLabel: 'Cancelar',
+        cancelTitle: 'Abortar a subida en curso',
+        uploadLabel: 'Subir arquivo',
+        uploadTitle: 'Subir arquivos seleccionados',
+        msgNo: 'Non',
+        msgNoFilesSelected: 'Non hay arquivos seleccionados',
+        msgCancelled: 'Cancelado',
+        msgPlaceholder: 'Select {files}...',
+        msgZoomModalHeading: 'Vista previa detallada',
+        msgFileRequired: 'You must select a file to upload.',
+        msgSizeTooSmall: 'O arquivo "{name}" (<b>{size} KB</b>) é demasiado pequeño e debe ser maior de <b>{minSize} KB</b>.',
+        msgSizeTooLarge: 'El arquivo "{name}" (<b>{size} KB</b>) excede o tamaño máximo permitido de <b>{maxSize} KB</b>.',
+        msgFilesTooLess: 'Debe seleccionar al menos <b>{n}</b> {files} a cargar.',
+        msgFilesTooMany: 'O número de arquivos seleccionados a cargar <b>({n})</b> excede do límite máximo permitido de <b>{m}</b>.',
+        msgFileNotFound: 'Arquivo "{name}" non encontrado.',
+        msgFileSecured: 'Non é posible acceder o arquivo "{name}" porque estará sendo usado por outra aplicación ou non teñamos permisos de lectura.',
+        msgFileNotReadable: 'Non é posible acceder o archivo "{name}".',
+        msgFilePreviewAborted: 'Previsualización do arquivo "{name}" cancelada.',
+        msgFilePreviewError: 'Ocurriu un erro mentras se lía o arquivo "{name}".',
+        msgInvalidFileName: 'Caracteres non válidos o no soportados no nome do arquivos "{name}".',
+        msgInvalidFileType: 'Tipo de archivo no válido para "{name}". Sólo se permiten arquivos do tipo "{types}".',
+        msgInvalidFileExtension: 'Extensión de arquivo non válido para "{name}". Só se permiten arquivos "{extensions}".',
+        msgFileTypes: {
+            'image': 'imaxe',
+            'html': 'HTML',
+            'text': 'text',
+            'video': 'video',
+            'audio': 'audio',
+            'flash': 'flash',
+            'pdf': 'PDF',
+            'object': 'object'
+        },
+        msgUploadAborted: 'A carga de arquivos cancelouse',
+        msgUploadThreshold: 'Procesando...',
+        msgUploadBegin: 'Inicialicando...',
+        msgUploadEnd: 'Feito',
+        msgUploadEmpty: 'Non existen datos válidos para o envío.',
+        msgUploadError: 'Error',
+        msgValidationError: 'Erro de validación',
+        msgLoading: 'Subindo arquivo {index} de {files} &hellip;',
+        msgProgress: 'Subiendo arquivo {index} de {files} - {name} - {percent}% completado.',
+        msgSelected: '{n} {files} seleccionado(s)',
+        msgFoldersNotAllowed: 'Arrastra e solta únicamente arquivoa. Omitida(s) {n} carpeta(s).',
+        msgImageWidthSmall: 'O ancho da imaxe "{name}" debe ser de al menos {size} px.',
+        msgImageHeightSmall: 'A altura de la imaxe "{name}" debe ser de al menos {size} px.',
+        msgImageWidthLarge: 'El ancho de la imaxe "{name}" no puede exceder de {size} px.',
+        msgImageHeightLarge: 'La altura de la imaxe "{name}" no puede exceder de {size} px.',
+        msgImageResizeError: 'No se pudieron obtener las dimensiones de la imaxe para cambiar el tamaño.',
+        msgImageResizeException: 'Erro o cambiar o tamaño da imaxe.<pre>{errors}</pre>',
+        msgAjaxError: 'Algo foi mal ca operación {operation}. Por favor, intentao de novo mais tarde.',
+        msgAjaxProgressError: 'A operación {operation} fallou',
+        ajaxOperations: {
+            deleteThumb: 'Arquivo borrado',
+            uploadThumb: 'Arquivo subido',
+            uploadBatch: 'Datos subidos en lote',
+            uploadExtra: 'Datos do formulario subidos'
+        },
+        dropZoneTitle: 'Arrasta e solte aquí os arquivos &hellip;',
+        dropZoneClickTitle: '<br>(ou fai clic para seleccionar {files})',
+        fileActionSettings: {
+            removeTitle: 'Eliminar arquivo',
+            uploadTitle: 'Subir arquivo',
+            uploadRetryTitle: 'Retry upload',
+            downloadTitle: 'Download file',
+            zoomTitle: 'Ver detalles',
+            dragTitle: 'Mover / Reordenar',
+            indicatorNewTitle: 'Non subido todavía',
+            indicatorSuccessTitle: 'Subido',
+            indicatorErrorTitle: 'Erro o subir',
+            indicatorLoadingTitle: 'Subiendo...'
+        },
+        previewZoomButtonTitles: {
+            prev: 'Ver arquivo anterior',
+            next: 'Ver arquivo siguinte',
+            toggleheader: 'Mostrar encabezado',
+            fullscreen: 'Mostrar a pantalla completa',
+            borderless: 'Activar o modo sen bordes',
+            close: 'Cerrar vista detallada'
+        }
+    };
+})(window.jQuery);

+ 96 - 0
public/base/plugins/bootstrap-fileinput/js/locales/he.js

xqd
@@ -0,0 +1,96 @@
+/*!
+ * FileInput Hebrew 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 Daniel Coryat <awq8002@gmail.com>
+ *
+ * NOTE: this file must be saved in UTF-8 encoding.
+ */
+(function ($) {
+    "use strict";
+
+    $.fn.fileinputLocales['he'] = {
+        fileSingle: 'קובץ',
+        filePlural: 'קבצים',
+        browseLabel: 'העלאה &hellip;',
+        removeLabel: 'הסרה',
+        removeTitle: 'נקה קבצים נבחרים',
+        cancelLabel: 'ביטול',
+        cancelTitle: 'ביטול העלאה מתמשכת',
+        uploadLabel: 'טעינה',
+        uploadTitle: 'טעינת קבצים נבחרים',
+        msgNo: 'לא',
+        msgNoFilesSelected: 'לא נבחרו קבצים',
+        msgCancelled: 'מבוטל',
+        msgZoomModalHeading: 'תצוגה מקדימה מפורטת',
+        msgSizeTooSmall: 'קובץ "{name}" (<b>{size} KB</b>) קטן מדי וחייב להיות גדול מ <b>{minSize} KB</b>.',
+        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}".',
+        msgInvalidFileName: 'תווים לא חוקיים או לא נתמכים בשם הקובץ "{name}".',
+        msgInvalidFileType: 'סוג קובץ לא חוקי "{name}". רק "{types}" קבצים נתמכים.',
+        msgInvalidFileExtension: 'תוסף לא חוקי עבור הקובץ "{name}". רק "{extensions}" קבצים נתמכים.',
+        msgFileTypes: {
+            'image': 'תמונה',
+            'html': 'HTML',
+            'text': 'טקסט',
+            'video': 'וידאו',
+            'audio': 'שמע',
+            'flash': 'פלאש',
+            'pdf': 'PDF',
+            'object': 'אובייקט'
+        },
+        msgUploadAborted: 'העלאת הקובץ בוטלה',
+        msgUploadThreshold: 'מעבד...',
+        msgUploadBegin: 'מאתחל ...',
+        msgUploadEnd: 'בוצע',
+        msgUploadEmpty: 'אין נתונים זמינים להעלאה.',
+        msgValidationError: 'שגיאת אימות',
+        msgLoading: 'טוען קובץ {index} של {files} &hellip;',
+        msgProgress: 'טוען קובץ {index} של {files} - {name} - {percent}% הושלמה.',
+        msgSelected: '{n} {files} נבחרו',
+        msgFoldersNotAllowed: 'גרירת קבצים ושחרורם בלבד! דילוג {n} גרירת תיקיה(s).',
+        msgImageWidthSmall: 'רוחב קובץ התמונה "{name}" חייב להיות לפחות {size} px.',
+        msgImageHeightSmall: 'גובה קובץ התמונה "{name}" חייב להיות לפחות {size} px.',
+        msgImageWidthLarge: 'רוחב קובץ התמונה "{name}" לא יעלה על {size} px.',
+        msgImageHeightLarge: 'גובה קובץ התמונה "{name}" לא יעלה על {size} px.',
+        msgImageResizeError: 'לא ניתן לשנות את גודל מידות התמונה.',
+        msgImageResizeException: 'שגיאה בעת שינוי גודל התמונה.<pre>{errors}</pre>',
+        msgAjaxError: 'משהו השתבש עם {operation} המערכת. יש לנסות מאוחר יותר!',
+        msgAjaxProgressError: '{operation} נכשל',
+        ajaxOperations: {
+            deleteThumb: 'קובץ נמחק',
+            uploadThumb: 'קובץ הועלה',
+            uploadBatch: 'קובץ אצווה הועלה',
+            uploadExtra: 'העלאת נתונים בטופס'
+        },
+        dropZoneTitle: 'גרירת קבצים ושחרורם כאן &hellip;',
+        dropZoneClickTitle: '<br>(או לחץ /י כדי לבחור {files})',
+        fileActionSettings: {
+            removeTitle: 'הסרת קובץ',
+            uploadTitle: 'טעינת קובץ',
+            zoomTitle: 'הצגת פרטים',
+            dragTitle: 'העברה / סידור מחדש',
+            indicatorNewTitle: 'עדיין לא הועלה',
+            indicatorSuccessTitle: 'הועלה',
+            indicatorErrorTitle: 'שגיאת העלאה',
+            indicatorLoadingTitle: 'מעלה...'
+        },
+        previewZoomButtonTitles: {
+            prev: 'הצגת את הקובץ הקודם',
+            next: 'הצגת את הקובץ הבא',
+            toggleheader: 'שינוי כותרת',
+            fullscreen: 'מעבר למסך מלא',
+            borderless: 'שינוי המודל ללא שוליים',
+            close: 'סגירת תצוגה מקדימה מפורטת'
+        }
+    };
+})(window.jQuery);

+ 100 - 0
public/base/plugins/bootstrap-fileinput/js/locales/hu.js

xqd
@@ -0,0 +1,100 @@
+/*!
+ * 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ájlok',
+        browseLabel: 'Tallóz &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',
+        msgNo: 'Nem',
+        msgNoFilesSelected: 'Nincs fájl kiválasztva',
+        msgCancelled: 'Megszakítva',
+        msgPlaceholder: 'Válasz {files}...',
+        msgZoomModalHeading: 'Részletes Előnézet',
+        msgFileRequired: 'Kötelező fájlt kiválasztani a feltöltéshez.',
+        msgSizeTooSmall: 'A fájl: "{name}" (<b>{size} KB</b>) mérete túl kicsi, nagyobbnak kell lennie, mint <b>{minSize} KB</b>.',
+        msgSizeTooLarge: '"{name}" fájl (<b>{size} KB</b>) mérete nagyobb a megengedettnél <b>{maxSize} KB</b>.',
+        msgFilesTooLess: 'Legalább <b>{n}</b> {files} ki kell választania a feltöltéshez.',
+        msgFilesTooMany: 'A feltölteni kívánt fájlok száma <b>({n})</b> elérte a megengedett maximumot <b>{m}</b>.',
+        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.',
+        msgInvalidFileName: 'Hibás vagy nem támogatott karakterek a fájl nevében "{name}".',
+        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.',
+        msgFileTypes: {
+            'image': 'image',
+            'html': 'HTML',
+            'text': 'text',
+            'video': 'video',
+            'audio': 'audio',
+            'flash': 'flash',
+            'pdf': 'PDF',
+            'object': 'object'
+        },
+        msgUploadAborted: 'A fájl feltöltés megszakítva',
+        msgUploadThreshold: 'Folyamatban...',
+        msgUploadBegin: 'Inicializálás...',
+        msgUploadEnd: 'Kész',
+        msgUploadEmpty: 'Nincs érvényes adat a feltöltéshez.',
+        msgUploadError: 'Error',
+        msgValidationError: 'Érvényesítés 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: 'A kép szélességének "{name}" legalább {size} pixelnek kell lennie.',
+        msgImageHeightSmall: 'A kép magasságának "{name}" legalább {size} pixelnek kell lennie.',
+        msgImageWidthLarge: 'A kép szélessége "{name}" nem haladhatja meg a {size} pixelt.',
+        msgImageHeightLarge: 'A kép magassága "{name}" nem haladhatja meg a {size} pixelt.',
+        msgImageResizeError: 'Nem lehet megállapítani a kép méreteit az átméretezéshez.',
+        msgImageResizeException: 'Hiba történt a méretezés közben.<pre>{errors}</pre>',
+        msgAjaxError: 'Hiba történt a művelet közben ({operation}). Kérjük, próbálja később!',
+        msgAjaxProgressError: 'Hiba! ({operation})',
+        ajaxOperations: {
+            deleteThumb: 'fájl törlés',
+            uploadThumb: 'fájl feltöltés',
+            uploadBatch: 'csoportos fájl feltöltés',
+            uploadExtra: 'űrlap adat feltöltés'
+        },
+        dropZoneTitle: 'Húzzon ide fájlokat &hellip;',
+        dropZoneClickTitle: '<br>(vagy kattintson ide a {files} tallózásához...)',
+        fileActionSettings: {
+            removeTitle: 'A fájl eltávolítása',
+            uploadTitle: 'fájl feltöltése',
+            uploadRetryTitle: 'Feltöltés újból',
+            downloadTitle: 'Fájl letöltése',
+            zoomTitle: 'Részletek megtekintése',
+            dragTitle: 'Mozgatás / Átrendezés',
+            indicatorNewTitle: 'Nem feltöltött',
+            indicatorSuccessTitle: 'Feltöltött',
+            indicatorErrorTitle: 'Feltöltés hiba',
+            indicatorLoadingTitle: 'Feltöltés ...'
+        },
+        previewZoomButtonTitles: {
+            prev: 'Elöző fájl megnézése',
+            next: 'Következő fájl megnézése',
+            toggleheader: 'Fejléc mutatása',
+            fullscreen: 'Teljes képernyős mód bekapcsolása',
+            borderless: 'Keret nélküli ablak mód bekapcsolása',
+            close: 'Részletes előnézet bezárása'
+        }
+    };
+})(window.jQuery);

+ 101 - 0
public/base/plugins/bootstrap-fileinput/js/locales/id.js

xqd
@@ -0,0 +1,101 @@
+/*!
+ * FileInput Indonesian 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 Bambang Riswanto <bamz3r@gmail.com>
+ *
+ * NOTE: this file must be saved in UTF-8 encoding.
+ */
+(function ($) {
+    "use strict";
+
+    $.fn.fileinputLocales['id'] = {
+        fileSingle: 'berkas',
+        filePlural: 'berkas',
+        browseLabel: 'Pilih berkas &hellip;',
+        removeLabel: 'Hapus',
+        removeTitle: 'Hapus berkas terpilih',
+        cancelLabel: 'Batal',
+        cancelTitle: 'Batalkan proses pengunggahan',
+        uploadLabel: 'Unggah',
+        uploadTitle: 'Unggah berkas terpilih',
+        msgNo: 'Tidak',
+        msgNoFilesSelected: '',
+        msgCancelled: 'Dibatalkan',
+        msgPlaceholder: 'Pilih {files}...',
+        msgZoomModalHeading: 'Pratinjau terperinci',
+        msgFileRequired: 'Anda harus memilih berkas untuk diunggah.',
+        msgSizeTooSmall: 'Berkas "{name}" (<b>{size} KB</b>) terlalu kecil dan harus lebih besar dari <b>{minSize} KB</b>.',
+        msgSizeTooLarge: 'Berkas "{name}" (<b>{size} KB</b>) melebihi ukuran unggah maksimal yaitu <b>{maxSize} KB</b>.',
+        msgFilesTooLess: 'Anda harus memilih setidaknya <b>{n}</b> {files} untuk diunggah.',
+        msgFilesTooMany: '<b>({n})</b> berkas yang dipilih untuk diunggah melebihi ukuran unggah maksimal yaitu <b>{m}</b>.',
+        msgFileNotFound: 'Berkas "{name}" tak ditemukan!',
+        msgFileSecured: 'Sistem keamanan mencegah untuk membaca berkas "{name}".',
+        msgFileNotReadable: 'Berkas "{name}" tak dapat dibaca.',
+        msgFilePreviewAborted: 'Pratinjau untuk berkas "{name}" dibatalkan.',
+        msgFilePreviewError: 'Kesalahan saat membaca berkas "{name}".',
+        msgInvalidFileName: 'Karakter tidak dikenali atau tidak didukung untuk nama berkas "{name}".',
+        msgInvalidFileType: 'Jenis berkas "{name}" tidak sah. Hanya berkas "{types}" yang didukung.',
+        msgInvalidFileExtension: 'Ekstensi berkas "{name}" tidak sah. Hanya ekstensi "{extensions}" yang didukung.',
+        msgFileTypes: {
+            'image': 'image',
+            'html': 'HTML',
+            'text': 'text',
+            'video': 'video',
+            'audio': 'audio',
+            'flash': 'flash',
+            'pdf': 'PDF',
+            'object': 'object'
+        },
+        msgUploadAborted: 'Proses Unggah berkas dibatalkan',
+        msgUploadThreshold: 'Memproses...',
+        msgUploadBegin: 'Menyiapkan...',
+        msgUploadEnd: 'Selesai',
+        msgUploadEmpty: 'Tidak ada data valid yang tersedia untuk diunggah.',
+        msgUploadError: 'Kesalahan',
+        msgValidationError: 'Kesalahan saat memvalidasi',
+        msgLoading: 'Memuat {index} dari {files} berkas &hellip;',
+        msgProgress: 'Memuat {index} dari {files} berkas - {name} - {percent}% selesai.',
+        msgSelected: '{n} {files} dipilih',
+        msgFoldersNotAllowed: 'Hanya tahan dan lepas file saja! {n} folder diabaikan.',
+        msgImageWidthSmall: 'Lebar dari gambar "{name}" harus sekurangnya {size} px.',
+        msgImageHeightSmall: 'Tinggi dari gambar "{name}" harus sekurangnya {size} px.',
+        msgImageWidthLarge: 'Lebar dari gambar "{name}" tak boleh melebihi {size} px.',
+        msgImageHeightLarge: 'Tinggi dari gambar "{name}" tak boleh melebihi {size} px.',
+        msgImageResizeError: 'Tidak dapat menentukan dimensi gambar untuk mengubah ukuran.',
+        msgImageResizeException: 'Kesalahan saat mengubah ukuran gambar.<pre>{errors}</pre>',
+        msgAjaxError: 'Terjadi kesalahan ketika melakukan operasi {operation}. Silahkan coba lagi nanti!',
+        msgAjaxProgressError: '{operation} gagal',
+        ajaxOperations: {
+            deleteThumb: 'Hapus berkas',
+            uploadThumb: 'Unggah berkas',
+            uploadBatch: 'Unggah banyak berkas',
+            uploadExtra: 'Unggah form ekstra'
+        },
+        dropZoneTitle: 'Tarik dan lepaskan berkas disini &hellip;',
+        dropZoneClickTitle: '<br>(atau klik untuk memilih {files})',
+        fileActionSettings: {
+            removeTitle: 'Hapus Berkas',
+            uploadTitle: 'Unggah Berkas',
+            uploadRetryTitle: 'Unggah Ulang',
+            downloadTitle: 'Unduh Berkas',
+            zoomTitle: 'Tampilkan Rincian',
+            dragTitle: 'Pindah atau Atur Ulang',
+            indicatorNewTitle: 'Belum diunggah',
+            indicatorSuccessTitle: 'Sudah diunggah',
+            indicatorErrorTitle: 'Kesalahan dalam mengungah',
+            indicatorLoadingTitle: 'Mengunggah ...'
+        },
+        previewZoomButtonTitles: {
+            prev: 'Lihat berkas sebelumnya',
+            next: 'Lihat berkas selanjutnya',
+            toggleheader: 'Beralih ke tajuk',
+            fullscreen: 'Beralih ke mode penuh',
+            borderless: 'Beralih ke mode tanpa tepi',
+            close: 'Tutup pratinjau terperinci'
+        }
+    };
+})(window.jQuery);

+ 102 - 0
public/base/plugins/bootstrap-fileinput/js/locales/it.js

xqd
@@ -0,0 +1,102 @@
+/*!
+ * FileInput Italian Translation
+ * 
+ * Author: Lorenzo Milesi <maxxer@yetopen.it>
+ *
+ * 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',
+        msgNo: 'No',
+        msgNoFilesSelected: 'Nessun file selezionato',
+        msgCancelled: 'Annullato',
+        msgPlaceholder: 'Seleziona {files}...',
+        msgZoomModalHeading: 'Anteprima dettagliata',
+        msgFileRequired: 'Devi selezionare un file da caricare.',
+        msgSizeTooSmall: 'Il file "{name}" (<b>{size} KB</b>) è troppo piccolo, deve essere almeno di <b>{minSize} KB</b>.',
+        msgSizeTooLarge: 'Il file "{name}" (<b>{size} KB</b>) eccede la dimensione massima di caricamento di <b>{maxSize} KB</b>.',
+        msgFilesTooLess: 'Devi selezionare almeno <b>{n}</b> {files} da caricare.',
+        msgFilesTooMany: 'Il numero di file selezionati per il caricamento <b>({n})</b> eccede il numero massimo di file accettati <b>{m}</b>.',
+        msgFileNotFound: 'File "{name}" non trovato!',
+        msgFileSecured: 'Restrizioni di sicurezza impediscono la lettura del file "{name}".',
+        msgFileNotReadable: 'Il file "{name}" non è leggibile.',
+        msgFilePreviewAborted: 'Generazione anteprima per "{name}" annullata.',
+        msgFilePreviewError: 'Errore durante la lettura del file "{name}".',
+        msgInvalidFileName: 'Carattere non valido o non supportato nel 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}".',
+        msgFileTypes: {
+            'image': 'image',
+            'html': 'HTML',
+            'text': 'text',
+            'video': 'video',
+            'audio': 'audio',
+            'flash': 'flash',
+            'pdf': 'PDF',
+            'object': 'object'
+        },
+        msgUploadAborted: 'Il caricamento del file è stato interrotto',
+        msgUploadThreshold: 'In lavorazione...',
+        msgUploadBegin: 'Inizializzazione...',
+        msgUploadEnd: 'Fatto',
+        msgUploadEmpty: 'Dati non disponibili',
+        msgUploadError: 'Errore',
+        msgValidationError: 'Errore di convalida',
+        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: 'La larghezza dell\'immagine "{name}" deve essere di almeno {size} px.',
+        msgImageHeightSmall: 'L\'altezza dell\'immagine "{name}" deve essere di almeno {size} px.',
+        msgImageWidthLarge: 'La larghezza dell\'immagine "{name}" non può superare {size} px.',
+        msgImageHeightLarge: 'L\'altezza dell\'immagine "{name}" non può superare {size} px.',
+        msgImageResizeError: 'Impossibile ottenere le dimensioni dell\'immagine per ridimensionare.',
+        msgImageResizeException: 'Errore durante il ridimensionamento dell\'immagine.<pre>{errors}</pre>',
+        msgAjaxError: 'Qualcosa non ha funzionato con l\'operazione {operation}. Per favore riprova più tardi!',
+        msgAjaxProgressError: '{operation} failed',
+        ajaxOperations: {
+            deleteThumb: 'eliminazione file',
+            uploadThumb: 'caricamento file',
+            uploadBatch: 'caricamento file in batch',
+            uploadExtra: 'upload dati del form'
+        },
+        dropZoneTitle: 'Trascina i file qui&hellip;',
+        dropZoneClickTitle: '<br>(o clicca per selezionare {files})',
+        fileActionSettings: {
+            removeTitle: 'Rimuovere il file',
+            uploadTitle: 'Caricare un file',
+            uploadRetryTitle: 'Riprova il caricamento',
+            downloadTitle: 'Scarica file',
+            zoomTitle: 'Guarda i dettagli',
+            dragTitle: 'Muovi / Riordina',
+            indicatorNewTitle: 'Non ancora caricato',
+            indicatorSuccessTitle: 'Caricati',
+            indicatorErrorTitle: 'Carica Errore',
+            indicatorLoadingTitle: 'Caricamento ...'
+        },
+        previewZoomButtonTitles: {
+            prev: 'Vedi il file precedente',
+            next: 'Vedi il file seguente',
+            toggleheader: 'Attiva header',
+            fullscreen: 'Attiva full screen',
+            borderless: 'Abilita modalità senza bordi',
+            close: 'Chiudi'
+        }
+    };
+})(window.jQuery);

+ 109 - 0
public/base/plugins/bootstrap-fileinput/js/locales/ja.js

xqd
@@ -0,0 +1,109 @@
+/*!
+ * FileInput Japanese 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 Yuta Hoshina <hoshina@gmail.com>
+ *
+ * NOTE: this file must be saved in UTF-8 encoding.
+ * slugCallback
+ *    \u4e00-\u9fa5 : Kanji (Chinese characters)
+ *    \u3040-\u309f : Hiragana (Japanese syllabary)
+ *    \u30a0-\u30ff\u31f0-\u31ff : Katakana (including phonetic extension)
+ *    \u3200-\u32ff : Enclosed CJK Letters and Months
+ *    \uff00-\uffef : Halfwidth and Fullwidth Forms
+ */
+(function ($) {
+    "use strict";
+
+    $.fn.fileinputLocales['ja'] = {
+        fileSingle: 'ファイル',
+        filePlural: 'ファイル',
+        browseLabel: 'ファイルを選択&hellip;',
+        removeLabel: '削除',
+        removeTitle: '選択したファイルを削除',
+        cancelLabel: 'キャンセル',
+        cancelTitle: 'アップロードをキャンセル',
+        uploadLabel: 'アップロード',
+        uploadTitle: '選択したファイルをアップロード',
+        msgNo: 'いいえ',
+        msgNoFilesSelected: 'ファイルが選択されていません',
+        msgCancelled: 'キャンセル',
+        msgPlaceholder: 'Select {files}...',
+        msgZoomModalHeading: 'プレビュー',
+        msgFileRequired: 'ファイルを選択してください',
+        msgSizeTooSmall: 'ファイル"{name}" (<b>{size} KB</b>)はアップロード可能な下限容量<b>{minSize} KB</b>より小さいです',
+        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}"の読み込み中にエラーが発生しました',
+        msgInvalidFileName: 'ファイル名に無効な文字が含まれています "{name}".',
+        msgInvalidFileType: '"{name}"は無効なファイル形式です。"{types}"形式のファイルのみサポートしています',
+        msgInvalidFileExtension: '"{name}"は無効な拡張子です。拡張子が"{extensions}"のファイルのみサポートしています',
+        msgFileTypes: {
+            'image': 'image',
+            'html': 'HTML',
+            'text': 'text',
+            'video': 'video',
+            'audio': 'audio',
+            'flash': 'flash',
+            'pdf': 'PDF',
+            'object': 'object'
+        },
+        msgUploadAborted: 'ファイルのアップロードが中止されました',
+        msgUploadThreshold: '処理中...',
+        msgUploadBegin: '初期化中...',
+        msgUploadEnd: '完了',
+        msgUploadEmpty: 'アップロードに有効なデータがありません',
+        msgUploadError: 'エラー',
+        msgValidationError: '検証エラー',
+        msgLoading: '{files}個中{index}個目のファイルを読み込み中&hellip;',
+        msgProgress: '{files}個中{index}個のファイルを読み込み中 - {name} - {percent}% 完了',
+        msgSelected: '{n}個の{files}を選択',
+        msgFoldersNotAllowed: 'ドラッグ&ドロップが可能なのはファイルのみです。{n}個のフォルダ-は無視されました',
+        msgImageWidthSmall: '画像ファイル"{name}"の幅が小さすぎます。画像サイズの幅は少なくとも{size}px必要です',
+        msgImageHeightSmall: '画像ファイル"{name}"の高さが小さすぎます。画像サイズの高さは少なくとも{size}px必要です',
+        msgImageWidthLarge: '画像ファイル"{name}"の幅がアップロード可能な画像サイズ({size}px)を超えています',
+        msgImageHeightLarge: '画像ファイル"{name}"の高さがアップロード可能な画像サイズ({size}px)を超えています',
+        msgImageResizeError: 'リサイズ時に画像サイズが取得できませんでした',
+        msgImageResizeException: '画像のリサイズ時にエラーが発生しました。<pre>{errors}</pre>',
+        msgAjaxError: '{operation}実行中にエラーが発生しました。時間をおいてもう一度お試しください。',
+        msgAjaxProgressError: '{operation} failed',
+        ajaxOperations: {
+            deleteThumb: 'ファイル削除',
+            uploadThumb: 'ファイルアップロード',
+            uploadBatch: '一括ファイルアップロード',
+            uploadExtra: 'フォームデータアップロード'
+        },
+        dropZoneTitle: 'ファイルをドラッグ&ドロップ&hellip;',
+        dropZoneClickTitle: '<br>(または クリックして{files}を選択 )',
+        slugCallback: function(text) {
+            return text ? text.split(/(\\|\/)/g).pop().replace(/[^\w\u4e00-\u9fa5\u3040-\u309f\u30a0-\u30ff\u31f0-\u31ff\u3200-\u32ff\uff00-\uffef\-.\\\/ ]+/g, '') : '';
+        },
+        fileActionSettings: {
+            removeTitle: 'ファイルを削除',
+            uploadTitle: 'ファイルをアップロード',
+            uploadRetryTitle: '再アップロード',
+            zoomTitle: 'プレビュー',
+            dragTitle: '移動 / 再配置',
+            indicatorNewTitle: 'まだアップロードされていません',
+            indicatorSuccessTitle: 'アップロード済み',
+            indicatorErrorTitle: 'アップロード失敗',
+            indicatorLoadingTitle: 'アップロード中...'
+        },
+        previewZoomButtonTitles: {
+            prev: '前のファイルを表示',
+            next: '次のファイルを表示',
+            toggleheader: 'ファイル情報の表示/非表示',
+            fullscreen: 'フルスクリーン表示の開始/終了',
+            borderless: 'フルウィンドウ表示の開始/終了',
+            close: 'プレビューを閉じる'
+        }
+    };
+})(window.jQuery);

+ 101 - 0
public/base/plugins/bootstrap-fileinput/js/locales/ka.js

xqd
@@ -0,0 +1,101 @@
+/*!
+ * FileInput Georgian 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 Avtandil Kikabidze aka LONGMAN <akalongman@gmail.com>
+ *
+ * NOTE: this file must be saved in UTF-8 encoding.
+ */
+(function ($) {
+    "use strict";
+
+    $.fn.fileinputLocales['ka'] = {
+        fileSingle: 'ფაილი',
+        filePlural: 'ფაილები',
+        browseLabel: 'არჩევა &hellip;',
+        removeLabel: 'წაშლა',
+        removeTitle: 'არჩეული ფაილების წაშლა',
+        cancelLabel: 'გაუქმება',
+        cancelTitle: 'მიმდინარე ატვირთვის გაუქმება',
+        uploadLabel: 'ატვირთვა',
+        uploadTitle: 'არჩეული ფაილების ატვირთვა',
+        msgNo: 'არა',
+        msgNoFilesSelected: 'ფაილები არ არის არჩეული',
+        msgCancelled: 'გაუქმებულია',
+        msgPlaceholder: 'აირჩიეთ {files}...',
+        msgZoomModalHeading: 'დეტალურად ნახვა',
+        msgFileRequired: 'ატვირთვისთვის აუცილებელია ფაილის არჩევა.',
+        msgSizeTooSmall: 'ფაილი "{name}" (<b>{size} KB</b>) არის ძალიან პატარა. მისი ზომა უნდა იყოს არანაკლებ <b>{minSize} KB</b>.',
+        msgSizeTooLarge: 'ფაილი "{name}" (<b>{size} KB</b>) აჭარბებს მაქსიმალურ დასაშვებ ზომას <b>{maxSize} KB</b>.',
+        msgFilesTooLess: 'უნდა აირჩიოთ მინიმუმ <b>{n}</b> {file} ატვირთვისთვის.',
+        msgFilesTooMany: 'არჩეული ფაილების რაოდენობა <b>({n})</b> აჭარბებს დასაშვებ ლიმიტს <b>{m}</b>.',
+        msgFileNotFound: 'ფაილი "{name}" არ მოიძებნა!',
+        msgFileSecured: 'უსაფრთხოებით გამოწვეული შეზღუდვები კრძალავს ფაილის "{name}" წაკითხვას.',
+        msgFileNotReadable: 'ფაილის "{name}" წაკითხვა შეუძლებელია.',
+        msgFilePreviewAborted: 'პრევიუ გაუქმებულია ფაილისათვის "{name}".',
+        msgFilePreviewError: 'დაფიქსირდა შეცდომა ფაილის "{name}" კითხვისას.',
+        msgInvalidFileName: 'ნაპოვნია დაუშვებელი სიმბოლოები ფაილის "{name}" სახელში.',
+        msgInvalidFileType: 'ფაილს "{name}" გააჩნია დაუშვებელი ტიპი. მხოლოდ "{types}" ტიპის ფაილები არის დაშვებული.',
+        msgInvalidFileExtension: 'ფაილს "{name}" გააჩნია დაუშვებელი გაფართოება. მხოლოდ "{extensions}" გაფართოების ფაილები არის დაშვებული.',
+        msgFileTypes: {
+            'image': 'image',
+            'html': 'HTML',
+            'text': 'text',
+            'video': 'video',
+            'audio': 'audio',
+            'flash': 'flash',
+            'pdf': 'PDF',
+            'object': 'object'
+        },
+        msgUploadAborted: 'ფაილის ატვირთვა შეწყდა',
+        msgUploadThreshold: 'მუშავდება...',
+        msgUploadBegin: 'ინიციალიზაცია...',
+        msgUploadEnd: 'დასრულებულია',
+        msgUploadEmpty: 'ატვირთვისთვის დაუშვებელი მონაცემები.',
+        msgUploadError: 'ატვირთვის შეცდომა',
+        msgValidationError: 'ვალიდაციის შეცდომა',
+        msgLoading: 'ატვირთვა {index} / {files} &hellip;',
+        msgProgress: 'ფაილის ატვირთვა დასრულებულია {index} / {files} - {name} - {percent}%.',
+        msgSelected: 'არჩეულია {n} {file}',
+        msgFoldersNotAllowed: 'დაშვებულია მხოლოდ ფაილების გადმოთრევა! გამოტოვებულია {n} გადმოთრეული ფოლდერი.',
+        msgImageWidthSmall: 'სურათის "{name}" სიგანე უნდა იყოს არანაკლებ {size} px.',
+        msgImageHeightSmall: 'სურათის "{name}" სიმაღლე უნდა იყოს არანაკლებ {size} px.',
+        msgImageWidthLarge: 'სურათის "{name}" სიგანე არ უნდა აღემატებოდეს {size} px-ს.',
+        msgImageHeightLarge: 'სურათის "{name}" სიმაღლე არ უნდა აღემატებოდეს {size} px-ს.',
+        msgImageResizeError: 'ვერ მოხერხდა სურათის ზომის შეცვლისთვის საჭირო მონაცემების გარკვევა.',
+        msgImageResizeException: 'შეცდომა სურათის ზომის შეცვლისას.<pre>{errors}</pre>',
+        msgAjaxError: 'დაფიქსირდა შეცდომა ოპერაციის {operation} შესრულებისას. ცადეთ მოგვიანებით!',
+        msgAjaxProgressError: 'ვერ მოხერხდა ოპერაციის {operation} შესრულება',
+        ajaxOperations: {
+            deleteThumb: 'ფაილის წაშლა',
+            uploadThumb: 'ფაილის ატვირთვა',
+            uploadBatch: 'ფაილების ატვირთვა',
+            uploadExtra: 'მონაცემების გაგზავნა ფორმიდან'
+        },
+        dropZoneTitle: 'გადმოათრიეთ ფაილები აქ &hellip;',
+        dropZoneClickTitle: '<br>(ან დააჭირეთ რათა აირჩიოთ {files})',
+        fileActionSettings: {
+            removeTitle: 'ფაილის წაშლა',
+            uploadTitle: 'ფაილის ატვირთვა',
+            uploadRetryTitle: 'ატვირთვის გამეორება',
+            downloadTitle: 'ფაილის ჩამოტვირთვა',
+            zoomTitle: 'დეტალურად ნახვა',
+            dragTitle: 'გადაადგილება / მიმდევრობის შეცვლა',
+            indicatorNewTitle: 'ჯერ არ ატვირთულა',
+            indicatorSuccessTitle: 'ატვირთულია',
+            indicatorErrorTitle: 'ატვირთვის შეცდომა',
+            indicatorLoadingTitle: 'ატვირთვა ...'
+        },
+        previewZoomButtonTitles: {
+            prev: 'წინა ფაილის ნახვა',
+            next: 'შემდეგი ფაილის ნახვა',
+            toggleheader: 'სათაურის დამალვა',
+            fullscreen: 'მთელ ეკრანზე გაშლა',
+            borderless: 'მთელ გვერდზე გაშლა',
+            close: 'დახურვა'
+        }
+    };
+})(window.jQuery);

+ 100 - 0
public/base/plugins/bootstrap-fileinput/js/locales/kr.js

xqd
@@ -0,0 +1,100 @@
+/*!
+ * FileInput Korean 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['kr'] = {
+        fileSingle: '파일',
+        filePlural: '파일들',
+        browseLabel: '찾아보기 &hellip;',
+        removeLabel: '지우기',
+        removeTitle: '선택한 파일들 지우기',
+        cancelLabel: '취소',
+        cancelTitle: '진행중인 업로드 중단',
+        uploadLabel: '업로드',
+        uploadTitle: '선택한 파일 업로드',
+        msgNo: '아니요',
+        msgNoFilesSelected: '선택한 파일이 없습니다',
+        msgCancelled: '취소되었습니다',
+        msgPlaceholder: '{files} 선택...',
+        msgZoomModalHeading: '세부 정보',
+        msgFileRequired: '업로드를 위해 반드시 파일을 선택해야 합니다.',
+        msgSizeTooSmall: '파일 "{name}" (<b>{size} KB</b>)이 너무 작습니다. <b>{minSize} KB</b>보다 용량이 커야 합니다..',
+        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}"을/를 읽는 도중 에러가 발생했습니다.',
+        msgInvalidFileName: '파일 이름 "{name}" 중 지원 불가능한 문자가 포함되어 있습니다.',
+        msgInvalidFileType: '"{name}"의 타입은 지원하지 않습니다. "{types}" 타입의 파일을 선택해 주십시요.',
+        msgInvalidFileExtension: '"{name}"의 확장자는 지원하지 않습니다. "{extensions}" 확장자를 선택해 주십시요.',
+        msgFileTypes: {
+            'image': 'image',
+            'html': 'HTML',
+            'text': 'text',
+            'video': 'video',
+            'audio': 'audio',
+            'flash': 'flash',
+            'pdf': 'PDF',
+            'object': 'object'
+        },
+        msgUploadAborted: '파일 업로드가 중단되었습니다',
+        msgUploadThreshold: '처리하는 중...',
+        msgUploadBegin: '초기화 중...',
+        msgUploadEnd: '완료',
+        msgUploadEmpty: '업로드 가능한 데이터가 존재하지 않습니다.',
+        msgUploadError: '오류',
+        msgValidationError: '유효성 오류',
+        msgLoading: '{index}/{files}번째 파일을 불러오는 중입니다. &hellip;',
+        msgProgress: '{index}/{files} - {name} - {percent}% 불러오기 완료.',
+        msgSelected: '{n} {files}이 선택 되었습니다.',
+        msgFoldersNotAllowed: '파일만 마우스로 끌어올 수 있습니다! 끌어온 폴더는 건너뜁니다.',
+        msgImageWidthSmall: '"{name}"의 가로는 {size} px 보다 넓어야 합니다.',
+        msgImageHeightSmall: '"{name}"의 세로는 {size} px 보다 높아야 합니다.',
+        msgImageWidthLarge: '"{name}"의 가로는 {size} px를 넘을 수 없습니다.',
+        msgImageHeightLarge: '"{name}"의 세로는 {size} px를 넘을 수 없습니다.',
+        msgImageResizeError: '이미지의 치수를 가져올 수 없습니다',
+        msgImageResizeException: '이미지 사이즈 재조정이 다음 이유로 실패했습니다.<pre>{errors}</pre>',
+        msgAjaxError: '{operation} 실행 도중 실패했습니다. 잠시 후 다시 시도해 주세요!',
+        msgAjaxProgressError: '{operation} failed',
+        ajaxOperations: {
+            deleteThumb: 'file delete',
+            uploadThumb: 'file upload',
+            uploadBatch: 'batch file upload',
+            uploadExtra: 'form data upload'
+        },
+        dropZoneTitle: '마우스로 파일을 끌어오세요 &hellip;',
+        dropZoneClickTitle: '<br>(또는 {files} 선택을 위해 클릭하십시요)',
+        fileActionSettings: {
+            removeTitle: '파일 지우기',
+            uploadTitle: '파일 업로드',
+            uploadRetryTitle: '업로드 재시도',
+            downloadTitle: '파일 다운로드',
+            zoomTitle: '세부 정보 보기',
+            dragTitle: '옮기기 / 재배열하기',
+            indicatorNewTitle: '아직 업로드 되지 않았습니다',
+            indicatorSuccessTitle: '업로드 성공',
+            indicatorErrorTitle: '업로드 중 에러 발생',
+            indicatorLoadingTitle: '업로드 중 ...'
+        },
+        previewZoomButtonTitles: {
+            prev: '이전 파일',
+            next: '다음 파일',
+            toggleheader: '머릿글 토글',
+            fullscreen: '전체화면 토글',
+            borderless: '창 테두리 토글',
+            close: '세부 정보 닫기'
+        }
+    };
+})(window.jQuery);

+ 88 - 0
public/base/plugins/bootstrap-fileinput/js/locales/kz.js

xqd
@@ -0,0 +1,88 @@
+/*!
+ * FileInput Kazakh 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 Kali Toleugazy <almatytol@gmail.com>
+ *
+ * NOTE: this file must be saved in UTF-8 encoding.
+ */
+(function ($) {
+    "use strict";
+
+    $.fn.fileinputLocales['kz'] = {
+        fileSingle: 'файл',
+        filePlural: 'файлдар',
+        browseLabel: 'Таңдау &hellip;',
+        removeLabel: 'Жою',
+        removeTitle: 'Таңдалған файлдарды жою',
+        cancelLabel: 'Күшін жою',
+        cancelTitle: 'Ағымдағы жүктеуді болдырмау',
+        uploadLabel: 'Жүктеу',
+        uploadTitle: 'Таңдалған файлдарды жүктеу',
+        msgNo: 'жоқ',
+        msgNoFilesSelected: 'Файл таңдалмады',
+        msgCancelled: 'Күші жойылған',
+        msgPlaceholder: 'Select {files}...',
+        msgZoomModalHeading: 'Алдын ала толық көру',
+        msgSizeTooLarge: 'Файл "{name}" (<b>{size} KB</b>) ең үлкен <b>{maxSize} KB</b> өлшемінен асады.',
+        msgFilesTooLess: 'Жүктеу үшіy кемінде <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}" рұқсат.',
+        msgUploadAborted: 'Файлды жүктеу доғарылды',
+        msgUploadThreshold: 'Өңдеу...',
+        msgUploadBegin: 'Initializing...',
+        msgUploadEnd: 'Done',
+        msgUploadEmpty: 'No valid data available for upload.',
+        msgUploadError: 'Error',
+        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. аспау керек',
+        msgImageResizeError: 'Суреттің өлшемін өзгерту үшін, мөлшері алынбады',
+        msgImageResizeException: 'Суреттің мөлшерлерін өзгерткен кезде қателік пайда болды.<pre>{errors}</pre>',
+        msgAjaxError: 'Something went wrong with the {operation} operation. Please try again later!',
+        msgAjaxProgressError: '{operation} failed',
+        ajaxOperations: {
+            deleteThumb: 'file delete',
+            uploadThumb: 'file upload',
+            uploadBatch: 'batch file upload',
+            uploadExtra: 'form data upload'
+        },
+        dropZoneTitle: 'Файлдарды осында сүйреу &hellip;',
+        dropZoneClickTitle: '<br>(or click to select {files})',
+        fileActionSettings: {
+            removeTitle: 'Файлды өшіру',
+            uploadTitle: 'Файлды жүктеу',
+            uploadRetryTitle: 'Retry upload',
+            downloadTitle: 'Download file',
+            zoomTitle: 'мәліметтерді көру',
+            dragTitle: 'Орнын ауыстыру',
+            indicatorNewTitle: 'Жүктелген жоқ',
+            indicatorSuccessTitle: 'Жүктелген',
+            indicatorErrorTitle: 'Жүктелу қатесі ',
+            indicatorLoadingTitle: 'Жүктелу ...'
+        },
+        previewZoomButtonTitles: {
+            prev: 'Алдыңғы файлды қарау',
+            next: 'Келесі файлды қарау',
+            toggleheader: 'Тақырыпты ауыстыру',
+            fullscreen: 'Толық экран режимін қосу',
+            borderless: 'Жиексіз режиміне ауысу',
+            close: 'Толық көрінісін жабу'
+        }
+    };
+})(window.jQuery);

+ 100 - 0
public/base/plugins/bootstrap-fileinput/js/locales/lt.js

xqd
@@ -0,0 +1,100 @@
+/*!
+ * 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
+ * @author Mindaugas Varkalys <varkalys.mindaugas@gmail.com>
+ *
+ * NOTE: this file must be saved in UTF-8 encoding.
+ */
+(function ($) {
+    "use strict";
+
+    $.fn.fileinputLocales['lt'] = {
+        fileSingle: 'failas',
+        filePlural: 'failai',
+        browseLabel: 'Naršyti &hellip;',
+        removeLabel: 'Šalinti',
+        removeTitle: 'Pašalinti pasirinktus failus',
+        cancelLabel: 'Atšaukti',
+        cancelTitle: 'Atšaukti vykstantį įkėlimą',
+        uploadLabel: 'Įkelti',
+        uploadTitle: 'Įkelti pasirinktus failus',
+        msgNo: 'Ne',
+        msgNoFilesSelected: 'Nepasirinkta jokių failų',
+        msgCancelled: 'Atšaukta',
+        msgPlaceholder: 'Select {files}...',
+        msgZoomModalHeading: 'Detali Peržiūra',
+        msgFileRequired: 'Pasirinkite failą įkėlimui.',
+        msgSizeTooSmall: 'Failas "{name}" (<b>{size} KB</b>) yra per mažas ir turi būti didesnis nei <b>{minSize} KB</b>.',
+        msgSizeTooLarge: 'Failas "{name}" (<b>{size} KB</b>) viršija maksimalų leidžiamą įkeliamo failo dydį <b>{maxSize} KB</b>.',
+        msgFilesTooLess: 'Turite pasirinkti bent <b>{n}</b> failus įkėlimui.',
+        msgFilesTooMany: 'Įkėlimui pasirinktų failų skaičius <b>({n})</b> viršija maksimalų leidžiamą limitą <b>{m}</b>.',
+        msgFileNotFound: 'Failas "{name}" nerastas!',
+        msgFileSecured: 'Saugumo apribojimai neleidžia perskaityti failo "{name}".',
+        msgFileNotReadable: 'Failas "{name}" neperskaitomas.',
+        msgFilePreviewAborted: 'Failo peržiūra nutraukta "{name}".',
+        msgFilePreviewError: 'Įvyko klaida skaitant failą "{name}".',
+        msgInvalidFileName: 'Klaidingi arba nepalaikomi simboliai failo pavadinime "{name}".',
+        msgInvalidFileType: 'Klaidingas failo "{name}" tipas. Tik "{types}" tipai yra palaikomi.',
+        msgInvalidFileExtension: 'Klaidingas failo "{name}" plėtinys. Tik "{extensions}" plėtiniai yra palaikomi.',
+        msgFileTypes: {
+            'image': 'paveikslėlis',
+            'html': 'HTML',
+            'text': 'tekstas',
+            'video': 'vaizdo įrašas',
+            'audio': 'garso įrašas',
+            'flash': 'flash',
+            'pdf': 'PDF',
+            'object': 'objektas'
+        },
+        msgUploadAborted: 'Failo įkėlimas buvo nutrauktas',
+        msgUploadThreshold: 'Vykdoma...',
+        msgUploadBegin: 'Inicijuojama...',
+        msgUploadEnd: 'Baigta',
+        msgUploadEmpty: 'Nėra teisingų duomenų įkėlimui.',
+        msgUploadError: 'Klaida',
+        msgValidationError: 'Validacijos Klaida',
+        msgLoading: 'Keliamas failas {index} iš {files} &hellip;',
+        msgProgress: 'Keliamas failas {index} iš {files} - {name} - {percent}% baigta.',
+        msgSelected: 'Pasirinkti {n} {files}',
+        msgFoldersNotAllowed: 'Tempkite tik failus! Praleisti {n} nutempti aplankalas(-i).',
+        msgImageWidthSmall: 'Paveikslėlio "{name}" plotis turi būti bent {size} px.',
+        msgImageHeightSmall: 'Paveikslėlio "{name}" aukštis turi būti bent {size} px.',
+        msgImageWidthLarge: 'Paveikslėlio "{name}" plotis negali viršyti {size} px.',
+        msgImageHeightLarge: 'Paveikslėlio "{name}" aukštis negali viršyti {size} px.',
+        msgImageResizeError: 'Nepavyksta gauti paveikslėlio matmetų, kad pakeisti jo matmemis.',
+        msgImageResizeException: 'Klaida keičiant paveikslėlio matmenis.<pre>{errors}</pre>',
+        msgAjaxError: 'Kažkas nutiko vykdant {operation} operaciją. Prašome pabandyti vėliau!',
+        msgAjaxProgressError: '{operation} operacija nesėkminga',
+        ajaxOperations: {
+            deleteThumb: 'failo trynimo',
+            uploadThumb: 'failo įkėlimo',
+            uploadBatch: 'failų rinkinio įkėlimo',
+            uploadExtra: 'formos duomenų įkėlimo'
+        },
+        dropZoneTitle: 'Tempkite failus čia &hellip;',
+        dropZoneClickTitle: '<br>(arba paspauskite, kad pasirinktumėte failus)',
+        fileActionSettings: {
+            removeTitle: 'Šalinti failą',
+            uploadTitle: 'Įkelti failą',
+            uploadRetryTitle: 'Bandyti įkelti vėl',
+            zoomTitle: 'Peržiūrėti detales',
+            dragTitle: 'Perstumti',
+            indicatorNewTitle: 'Dar neįkelta',
+            indicatorSuccessTitle: 'Įkelta',
+            indicatorErrorTitle: 'Įkėlimo Klaida',
+            indicatorLoadingTitle: 'Įkeliama ...'
+        },
+        previewZoomButtonTitles: {
+            prev: 'Peržiūrėti ankstesnį failą',
+            next: 'Peržiūrėti kitą failą',
+            toggleheader: 'Perjungti viršutinę juostą',
+            fullscreen: 'Perjungti pilno ekrano rėžimą',
+            borderless: 'Perjungti berėmį režimą',
+            close: 'Uždaryti detalią peržiūrą'
+        }
+    };
+})(window.jQuery);

+ 100 - 0
public/base/plugins/bootstrap-fileinput/js/locales/nl.js

xqd
@@ -0,0 +1,100 @@
+/*!
+ * 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 upload',
+        uploadLabel: 'Upload',
+        uploadTitle: 'Upload geselecteerde bestanden',
+        msgNo: 'Nee',
+        msgNoFilesSelected: '',
+        msgCancelled: 'Geannuleerd',
+        msgPlaceholder: 'Selecteer {files}...',
+        msgZoomModalHeading: 'Gedetailleerd voorbeeld',
+        msgFileRequired: 'U moet een bestand kiezen om te uploaden.',
+        msgSizeTooSmall: 'Bestand "{name}" (<b>{size} KB</b>) is te klein en moet groter zijn dan <b>{minSize} KB</b>.',
+        msgSizeTooLarge: 'Bestand "{name}" (<b>{size} KB</b>) is groter dan de toegestane <b>{maxSize} KB</b>.',
+        msgFilesTooLess: 'U moet minstens <b>{n}</b> {files} selecteren om te uploaden.',
+        msgFilesTooMany: 'Aantal geselecteerde bestanden <b>({n})</b> is meer dan de toegestane <b>{m}</b>.',
+        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 het lezen van "{name}".',
+        msgInvalidFileName: 'Ongeldige of niet ondersteunde karakters in bestandsnaam "{name}".',
+        msgInvalidFileType: 'Geen geldig bestand "{name}". Alleen "{types}" zijn toegestaan.',
+        msgInvalidFileExtension: 'Geen geldige extensie "{name}". Alleen "{extensions}" zijn toegestaan.',
+        msgFileTypes: {
+            'image': 'afbeelding',
+            'html': 'HTML',
+            'text': 'tekst',
+            'video': 'video',
+            'audio': 'geluid',
+            'flash': 'flash',
+            'pdf': 'PDF',
+            'object': 'object'
+        },
+        msgUploadAborted: 'Het uploaden van bestanden is afgebroken',
+        msgUploadThreshold: 'Verwerken...',
+        msgUploadBegin: 'Initialiseren...',
+        msgUploadEnd: 'Gedaan',
+        msgUploadEmpty: 'Geen geldige data beschikbaar voor upload.',
+        msgUploadError: 'Error',
+        msgValidationError: 'Bevestiging 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 alleen bestanden! {n} overgeslagen map(pen).',
+        msgImageWidthSmall: 'Breedte van het foto-bestand "{name}" moet minstens {size} px zijn.',
+        msgImageHeightSmall: 'Hoogte van het foto-bestand "{name}" moet minstens {size} px zijn.',
+        msgImageWidthLarge: 'Breedte van het foto-bestand "{name}" kan niet hoger zijn dan {size} px.',
+        msgImageHeightLarge: 'Hoogte van het foto bestand "{name}" kan niet hoger zijn dan {size} px.',
+        msgImageResizeError: 'Kon de foto afmetingen niet lezen om te verkleinen.',
+        msgImageResizeException: 'Fout bij het verkleinen van de foto.<pre>{errors}</pre>',
+        msgAjaxError: 'Er ging iets mis met de {operation} actie. Gelieve later opnieuw te proberen!',
+        msgAjaxProgressError: '{operation} mislukt',
+        ajaxOperations: {
+            deleteThumb: 'bestand verwijderen',
+            uploadThumb: 'bestand uploaden',
+            uploadBatch: 'alle bestanden uploaden',
+            uploadExtra: 'form data upload'
+        },
+        dropZoneTitle: 'Drag & drop bestanden hier &hellip;',
+        dropZoneClickTitle: '<br>(of klik hier om {files} te selecteren)',
+        fileActionSettings: {
+            removeTitle: 'Verwijder bestand',
+            uploadTitle: 'bestand uploaden',
+            uploadRetryTitle: 'Opnieuw uploaden',
+            downloadTitle: 'Download file',
+            zoomTitle: 'Bekijk details',
+            dragTitle: 'Verplaatsen / herindelen',
+            indicatorNewTitle: 'Nog niet geupload',
+            indicatorSuccessTitle: 'geupload',
+            indicatorErrorTitle: 'fout uploaden',
+            indicatorLoadingTitle: 'uploaden ...'
+        },
+        previewZoomButtonTitles: {
+            prev: 'Toon vorig bestand',
+            next: 'Toon volgend bestand',
+            toggleheader: 'Toggle header',
+            fullscreen: 'Toggle volledig scherm',
+            borderless: 'Toggle randloze modus',
+            close: 'Sluit gedetailleerde weergave'
+        }
+    };
+})(window.jQuery);

+ 99 - 0
public/base/plugins/bootstrap-fileinput/js/locales/no.js

xqd
@@ -0,0 +1,99 @@
+/*!
+ * FileInput Norwegian 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['no'] = {
+        fileSingle: 'fil',
+        filePlural: 'filer',
+        browseLabel: 'Bla gjennom &hellip;',
+        removeLabel: 'Fjern',
+        removeTitle: 'Fjern valgte filer',
+        cancelLabel: 'Avbryt',
+        cancelTitle: 'Stopp pågående opplastninger',
+        uploadLabel: 'Last opp',
+        uploadTitle: 'Last opp valgte filer',
+        msgNo: 'Nei',
+        msgNoFilesSelected: 'Ingen filer er valgt',
+        msgCancelled: 'Avbrutt',
+        msgPlaceholder: 'Select {files}...',
+        msgZoomModalHeading: 'Detaljert visning',
+        msgFileRequired: 'You must select a file to upload.',
+        msgSizeTooSmall: 'Filen "{name}" (<b>{size} KB</b>) er for liten og må være større enn <b>{minSize} KB</b>.',
+        msgSizeTooLarge: 'Filen "{name}" (<b>{size} KB</b>) er for stor, maksimal filstørrelse er <b>{maxSize} KB</b>.',
+        msgFilesTooLess: 'Du må velge minst <b>{n}</b> {files} for opplastning.',
+        msgFilesTooMany: 'For mange filer til opplastning, <b>({n})</b> overstiger maksantallet som er <b>{m}</b>.',
+        msgFileNotFound: 'Fant ikke filen "{name}"!',
+        msgFileSecured: 'Sikkerhetsrestriksjoner hindrer lesing av filen "{name}".',
+        msgFileNotReadable: 'Filen "{name}" er ikke lesbar.',
+        msgFilePreviewAborted: 'Filvisning avbrutt for "{name}".',
+        msgFilePreviewError: 'En feil oppstod under lesing av filen "{name}".',
+        msgInvalidFileName: 'Ugyldige tegn i filen "{name}".',
+        msgInvalidFileType: 'Ugyldig type for filen "{name}". Kun "{types}" filer er tillatt.',
+        msgInvalidFileExtension: 'Ugyldig endelse for filen "{name}". Kun "{extensions}" filer støttes.',
+        msgFileTypes: {
+            'image': 'image',
+            'html': 'HTML',
+            'text': 'text',
+            'video': 'video',
+            'audio': 'audio',
+            'flash': 'flash',
+            'pdf': 'PDF',
+            'object': 'object'
+        },
+        msgUploadAborted: 'Filopplastningen ble avbrutt',
+        msgUploadThreshold: 'Prosesserer...',
+        msgUploadBegin: 'Initialiserer...',
+        msgUploadEnd: 'Ferdig',
+        msgUploadEmpty: 'Ingen gyldige data tilgjengelig for opplastning.',
+        msgUploadError: 'Error',
+        msgValidationError: 'Valideringsfeil',
+        msgLoading: 'Laster fil {index} av {files} &hellip;',
+        msgProgress: 'Laster fil {index} av {files} - {name} - {percent}% fullført.',
+        msgSelected: '{n} {files} valgt',
+        msgFoldersNotAllowed: 'Kun Dra & slipp filer! Hoppet over {n} mappe(r).',
+        msgImageWidthSmall: 'Bredde på bildefilen "{name}" må være minst {size} px.',
+        msgImageHeightSmall: 'Høyde på bildefilen "{name}" må være minst {size} px.',
+        msgImageWidthLarge: 'Bredde på bildefilen "{name}" kan ikke overstige {size} px.',
+        msgImageHeightLarge: 'Høyde på bildefilen "{name}" kan ikke overstige {size} px.',
+        msgImageResizeError: 'Fant ikke dimensjonene som skulle resizes.',
+        msgImageResizeException: 'En feil oppstod under endring av størrelse .<pre>{errors}</pre>',
+        msgAjaxError: 'Noe gikk galt med {operation} operasjonen. Vennligst prøv igjen senere!',
+        msgAjaxProgressError: '{operation} feilet',
+        ajaxOperations: {
+            deleteThumb: 'file delete',
+            uploadThumb: 'file upload',
+            uploadBatch: 'batch file upload',
+            uploadExtra: 'form data upload'
+        },
+        dropZoneTitle: 'Dra & slipp filer her &hellip;',
+        dropZoneClickTitle: '<br>(eller klikk for å velge {files})',
+        fileActionSettings: {
+            removeTitle: 'Fjern fil',
+            uploadTitle: 'Last opp fil',
+            uploadRetryTitle: 'Retry upload',
+            zoomTitle: 'Vis detaljer',
+            dragTitle: 'Flytt / endre rekkefølge',
+            indicatorNewTitle: 'Opplastning ikke fullført',
+            indicatorSuccessTitle: 'Opplastet',
+            indicatorErrorTitle: 'Opplastningsfeil',
+            indicatorLoadingTitle: 'Laster opp ...'
+        },
+        previewZoomButtonTitles: {
+            prev: 'Vis forrige fil',
+            next: 'Vis neste fil',
+            toggleheader: 'Vis header',
+            fullscreen: 'Åpne fullskjerm',
+            borderless: 'Åpne uten kanter',
+            close: 'Lukk detaljer'
+        }
+    };
+})(window.jQuery);

+ 90 - 0
public/base/plugins/bootstrap-fileinput/js/locales/pl.js

xqd
@@ -0,0 +1,90 @@
+/*!
+ * 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',
+        msgNo: 'Nie',
+        msgNoFilesSelected: 'Brak zaznaczonych plików',
+        msgCancelled: 'Odwołany',
+        msgPlaceholder: 'Wybierz {files}...',
+        msgZoomModalHeading: 'Szczegółowy podgląd',
+        msgFileRequired: 'Musisz wybrać plik do wgrania.',
+        msgSizeTooSmall: 'Plik "{name}" (<b>{size} KB</b>) jest zbyt mały i musi być większy niż <b>{minSize} KB</b>.',
+        msgSizeTooLarge: 'Plik o nazwie "{name}" (<b>{size} KB</b>) przekroczył maksymalną dopuszczalną wielkość pliku wynoszącą <b>{maxSize} KB</b>.',
+        msgFilesTooLess: 'Minimalna liczba plików do wgrania: <b>{n}</b>.',
+        msgFilesTooMany: 'Liczba plików wybranych do wgrania w liczbie <b>({n})</b>, przekracza maksymalny dozwolony limit wynoszący <b>{m}</b>.',
+        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}".',
+        msgInvalidFileName: 'Nieprawidłowe lub nieobsługiwane znaki w nazwie pliku "{name}".',
+        msgInvalidFileType: 'Nieznany typ pliku "{name}". Tylko następujące rodzaje plików są dozwolone: "{types}".',
+        msgInvalidFileExtension: 'Złe rozszerzenie dla pliku "{name}". Tylko następujące rozszerzenia plików są dozwolone: "{extensions}".',
+        msgUploadAborted: 'Przesyłanie pliku zostało przerwane',
+        msgUploadThreshold: 'Przetwarzanie...',
+        msgUploadBegin: 'Rozpoczynanie...',
+        msgUploadEnd: 'Gotowe!',
+        msgUploadEmpty: 'Brak poprawnych danych do przesłania.',
+        msgUploadError: 'Błąd',
+        msgValidationError: 'Błąd walidacji',
+        msgLoading: 'Wczytywanie pliku {index} z {files} &hellip;',
+        msgProgress: 'Wczytywanie pliku {index} z {files} - {name} - {percent}% zakończone.',
+        msgSelected: '{n} Plików 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.',
+        msgImageResizeError: 'Nie udało się uzyskać wymiaru obrazu, aby zmienić rozmiar.',
+        msgImageResizeException: 'Błąd podczas zmiany rozmiaru obrazu.<pre>{errors}</pre>',
+        msgAjaxError: 'Coś poczło nie tak podczas {operation}. Spróbuj ponownie!',
+        msgAjaxProgressError: '{operation} nie powiodło się',
+        ajaxOperations: {
+            deleteThumb: 'usuwanie pliku',
+            uploadThumb: 'przesyłanie pliku',
+            uploadBatch: 'masowe przesyłanie plików',
+            uploadExtra: 'przesyłanie danych formularza'
+        },
+        dropZoneTitle: 'Przeciągnij i upuść pliki tutaj &hellip;',
+        dropZoneClickTitle: '<br>(lub kliknij tutaj i wybierz {files} z komputera)',
+        fileActionSettings: {
+            removeTitle: 'Usuń plik',
+            uploadTitle: 'Przesyłanie pliku',
+            uploadRetryTitle: 'Ponów',
+            downloadTitle: 'Pobierz plik',
+            zoomTitle: 'Pokaż szczegóły',
+            dragTitle: 'Przenies / Ponownie zaaranżuj',
+            indicatorNewTitle: 'Jeszcze nie przesłany',
+            indicatorSuccessTitle: 'Dodane',
+            indicatorErrorTitle: 'Błąd',
+            indicatorLoadingTitle: 'Przesyłanie ...'
+        },
+        previewZoomButtonTitles: {
+            prev: 'Pokaż poprzedni plik',
+            next: 'Pokaż następny plik',
+            toggleheader: 'Włącz / wyłącz nagłówek',
+            fullscreen: 'Włącz / wyłącz pełny ekran',
+            borderless: 'Włącz / wyłącz tryb bez ramek',
+            close: 'Zamknij szczegółowy widok'
+        }
+    };
+})(window.jQuery);

+ 100 - 0
public/base/plugins/bootstrap-fileinput/js/locales/pt-BR.js

xqd
@@ -0,0 +1,100 @@
+/*!
+ * 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',
+        msgNo: 'Não',
+        msgNoFilesSelected: 'Nenhum arquivo selecionado',
+        msgCancelled: 'Cancelado',
+        msgPlaceholder: 'Selecionar {files}...',
+        msgZoomModalHeading: 'Pré-visualização detalhada',
+        msgFileRequired: 'Você deve selecionar um arquivo para enviar.',
+        msgSizeTooSmall: 'O arquivo "{name}" (<b>{size} KB</b>) é muito pequeno e deve ser maior que <b>{minSize} KB</b>.',
+        msgSizeTooLarge: 'O arquivo "{name}" (<b>{size} KB</b>) excede o tamanho máximo permitido de <b>{maxSize} KB</b>.',
+        msgFilesTooLess: 'Você deve selecionar pelo menos <b>{n}</b> {files} para enviar.',
+        msgFilesTooMany: 'O número de arquivos selecionados para o envio <b>({n})</b> excede o limite máximo permitido de <b>{m}</b>.',
+        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}".',
+        msgInvalidFileName: 'Caracteres inválidos ou não suportados no 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.',
+        msgFileTypes: {
+            'image': 'imagem',
+            'html': 'HTML',
+            'text': 'texto',
+            'video': 'vídeo',
+            'audio': 'audio',
+            'flash': 'flash',
+            'pdf': 'PDF',
+            'object': 'objeto'
+        },
+        msgUploadAborted: 'O envio do arquivo foi abortado',
+        msgUploadThreshold: 'Processando...',
+        msgUploadBegin: 'Inicializando...',
+        msgUploadEnd: 'Concluído',
+        msgUploadEmpty: 'Nenhuma informação válida para upload.',
+        msgUploadError: 'Erro de Upload',
+        msgValidationError: 'Erro de validação',
+        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} 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.',
+        msgImageResizeError: 'Não foi possível obter as dimensões da imagem para redimensionar.',
+        msgImageResizeException: 'Erro ao redimensionar a imagem.<pre>{errors}</pre>',
+        msgAjaxError: 'Algo deu errado com a operação {operation}. Por favor tente novamente mais tarde!',
+        msgAjaxProgressError: '{operation} falhou',
+        ajaxOperations: {
+            deleteThumb: 'Exclusão de arquivo',
+            uploadThumb: 'Upload de arquivos',
+            uploadBatch: 'Carregamento de arquivos em lote',
+            uploadExtra: 'Carregamento de dados do formulário'
+        },
+        dropZoneTitle: 'Arraste e solte os arquivos aqui&hellip;',
+        dropZoneClickTitle: '<br>(ou clique para selecionar o(s) arquivo(s))',
+        fileActionSettings: {
+            removeTitle: 'Remover arquivo',
+            uploadTitle: 'Enviar arquivo',
+            uploadRetryTitle: 'Retry upload',
+            downloadTitle: 'Download file',
+            zoomTitle: 'Ver detalhes',
+            dragTitle: 'Mover / Reordenar',
+            indicatorNewTitle: 'Ainda não enviado',
+            indicatorSuccessTitle: 'Enviado',
+            indicatorErrorTitle: 'Erro',
+            indicatorLoadingTitle: 'Enviando...'
+        },
+        previewZoomButtonTitles: {
+            prev: 'Visualizar arquivo anterior',
+            next: 'Visualizar próximo arquivo',
+            toggleheader: 'Mostrar cabeçalho',
+            fullscreen: 'Ativar tela cheia',
+            borderless: 'Ativar modo sem borda',
+            close: 'Fechar pré-visualização detalhada'
+        }
+    };
+})(window.jQuery);

+ 100 - 0
public/base/plugins/bootstrap-fileinput/js/locales/pt.js

xqd
@@ -0,0 +1,100 @@
+/*!
+ * 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',
+        msgNo: 'Não',
+        msgNoFilesSelected: '',
+        msgCancelled: 'Cancelado',
+        msgPlaceholder: 'Select {files}...',
+        msgZoomModalHeading: 'Pré-visualização detalhada',
+        msgFileRequired: 'You must select a file to upload.',
+        msgSizeTooSmall: 'File "{name}" (<b>{size} KB</b>) is too small and must be larger than <b>{minSize} KB</b>.',
+        msgSizeTooLarge: 'Ficheiro "{name}" (<b>{size} KB</b>) excede o tamanho máximo permido de <b>{maxSize} KB</b>.',
+        msgFilesTooLess: 'Deve seleccionar pelo menos <b>{n}</b> {files} para fazer upload.',
+        msgFilesTooMany: 'Número máximo de ficheiros seleccionados <b>({n})</b> excede o limite máximo de <b>{m}</b>.',
+        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}".',
+        msgInvalidFileName: 'Invalid or unsupported characters in file name "{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.',
+        msgFileTypes: {
+            'image': 'image',
+            'html': 'HTML',
+            'text': 'text',
+            'video': 'video',
+            'audio': 'audio',
+            'flash': 'flash',
+            'pdf': 'PDF',
+            'object': 'object'
+        },
+        msgUploadAborted: 'O upload do arquivo foi abortada',
+        msgUploadThreshold: 'Processing...',
+        msgUploadBegin: 'Initializing...',
+        msgUploadEnd: 'Done',
+        msgUploadEmpty: 'No valid data available for upload.',
+        msgUploadError: 'Error',
+        msgValidationError: 'Erro de validação',
+        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.',
+        msgImageResizeError: 'Could not get the image dimensions to resize.',
+        msgImageResizeException: 'Erro ao redimensionar a imagem.<pre>{errors}</pre>',
+        msgAjaxError: 'Something went wrong with the {operation} operation. Please try again later!',
+        msgAjaxProgressError: '{operation} failed',
+        ajaxOperations: {
+            deleteThumb: 'file delete',
+            uploadThumb: 'file upload',
+            uploadBatch: 'batch file upload',
+            uploadExtra: 'form data upload'
+        },
+        dropZoneTitle: 'Arrastar e largar ficheiros aqui &hellip;',
+        dropZoneClickTitle: '<br>(or click to select {files})',
+        fileActionSettings: {
+            removeTitle: 'Remover arquivo',
+            uploadTitle: 'Carregar arquivo',
+            uploadRetryTitle: 'Retry upload',
+            downloadTitle: 'Download file',
+            zoomTitle: 'Ver detalhes',
+            dragTitle: 'Move / Rearrange',
+            indicatorNewTitle: 'Ainda não carregou',
+            indicatorSuccessTitle: 'Carregado',
+            indicatorErrorTitle: 'Carregar Erro',
+            indicatorLoadingTitle: 'A carregar ...'
+        },
+        previewZoomButtonTitles: {
+            prev: 'View previous file',
+            next: 'View next file',
+            toggleheader: 'Toggle header',
+            fullscreen: 'Toggle full screen',
+            borderless: 'Toggle borderless mode',
+            close: 'Close detailed preview'
+        }
+    };
+})(window.jQuery);

+ 101 - 0
public/base/plugins/bootstrap-fileinput/js/locales/ro.js

xqd
@@ -0,0 +1,101 @@
+/*!
+ * 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 <pictoru@autoportret.ro>
+ *
+ * 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',
+        msgNo: 'Nu',
+        msgNoFilesSelected: '',
+        msgCancelled: 'Anulat',
+        msgPlaceholder: 'Select {files}...',
+        msgZoomModalHeading: 'Previzualizare detaliată',
+        msgFileRequired: 'You must select a file to upload.',
+        msgSizeTooSmall: 'File "{name}" (<b>{size} KB</b>) is too small and must be larger than <b>{minSize} KB</b>.',
+        msgSizeTooLarge: 'Fișierul "{name}" (<b>{size} KB</b>) depășește limita maximă de încărcare de <b>{maxSize} KB</b>.',
+        msgFilesTooLess: 'Trebuie să selectezi cel puțin <b>{n}</b> {files} pentru a încărca.',
+        msgFilesTooMany: 'Numărul fișierelor pentru încărcare <b>({n})</b> depășește limita maximă de <b>{m}</b>.',
+        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}".',
+        msgInvalidFileName: 'Invalid or unsupported characters in file name "{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}".',
+        msgFileTypes: {
+            'image': 'image',
+            'html': 'HTML',
+            'text': 'text',
+            'video': 'video',
+            'audio': 'audio',
+            'flash': 'flash',
+            'pdf': 'PDF',
+            'object': 'object'
+        },
+        msgUploadAborted: 'Fișierul Încărcarea a fost întrerupt',
+        msgUploadThreshold: 'Processing...',
+        msgUploadBegin: 'Initializing...',
+        msgUploadEnd: 'Done',
+        msgUploadEmpty: 'No valid data available for upload.',
+        msgUploadError: 'Error',
+        msgValidationError: 'Eroare de validare',
+        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.',
+        msgImageResizeError: 'Nu a putut obține dimensiunile imaginii pentru a redimensiona.',
+        msgImageResizeException: 'Eroare la redimensionarea imaginii.<pre>{errors}</pre>',
+        msgAjaxError: 'Something went wrong with the {operation} operation. Please try again later!',
+        msgAjaxProgressError: '{operation} failed',
+        ajaxOperations: {
+            deleteThumb: 'file delete',
+            uploadThumb: 'file upload',
+            uploadBatch: 'batch file upload',
+            uploadExtra: 'form data upload'
+        },
+        dropZoneTitle: 'Trage fișierele aici &hellip;',
+        dropZoneClickTitle: '<br>(or click to select {files})',
+        fileActionSettings: {
+            removeTitle: 'Scoateți fișier',
+            uploadTitle: 'Incarca fisier',
+            uploadRetryTitle: 'Retry upload',
+            downloadTitle: 'Download file',
+            zoomTitle: 'Vezi detalii',
+            dragTitle: 'Move / Rearrange',
+            indicatorNewTitle: 'Nu a încărcat încă',
+            indicatorSuccessTitle: 'încărcat',
+            indicatorErrorTitle: 'Încărcați eroare',
+            indicatorLoadingTitle: 'Se încarcă ...'
+        },
+        previewZoomButtonTitles: {
+            prev: 'View previous file',
+            next: 'View next file',
+            toggleheader: 'Toggle header',
+            fullscreen: 'Toggle full screen',
+            borderless: 'Toggle borderless mode',
+            close: 'Close detailed preview'
+        }
+    };
+})(window.jQuery);

+ 101 - 0
public/base/plugins/bootstrap-fileinput/js/locales/ru.js

xqd
@@ -0,0 +1,101 @@
+/*!
+ * 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 <cyanofresh@gmail.com>
+ *
+ * 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: 'Загрузить выбранные файлы',
+        msgNo: 'нет',
+        msgNoFilesSelected: '',
+        msgCancelled: 'Отменено',
+        msgPlaceholder: 'Выбрать {files}...',
+        msgZoomModalHeading: 'Подробное превью',
+        msgFileRequired: 'Необходимо выбрать файл для загрузки.',
+        msgSizeTooSmall: 'Файл "{name}" (<b>{size} KB</b>) имеет слишком маленький размер и должен быть больше <b>{minSize} KB</b>.',
+        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}".',
+        msgInvalidFileName: 'Неверные или неподдерживаемые символы в названии файла "{name}".',
+        msgInvalidFileType: 'Запрещенный тип файла для "{name}". Только "{types}" разрешены.',
+        msgInvalidFileExtension: 'Запрещенное расширение для файла "{name}". Только "{extensions}" разрешены.',
+        msgFileTypes: {
+            'image': 'image',
+            'html': 'HTML',
+            'text': 'text',
+            'video': 'video',
+            'audio': 'audio',
+            'flash': 'flash',
+            'pdf': 'PDF',
+            'object': 'object'
+        },
+        msgUploadAborted: 'Выгрузка файла прервана',
+        msgUploadThreshold: 'Обработка...',
+        msgUploadBegin: 'Инициализация...',
+        msgUploadEnd: 'Готово',
+        msgUploadEmpty: 'Недопустимые данные для загрузки',
+        msgUploadError: 'Ошибка загрузки',
+        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.',
+        msgImageResizeError: 'Не удалось получить размеры изображения, чтобы изменить размер.',
+        msgImageResizeException: 'Ошибка при изменении размера изображения.<pre>{errors}</pre>',
+        msgAjaxError: 'Произошла ошибка при выполнении операции {operation}. Повторите попытку позже!',
+        msgAjaxProgressError: 'Не удалось выполнить {operation}',
+        ajaxOperations: {
+            deleteThumb: 'удалить файл',
+            uploadThumb: 'загрузить файл',
+            uploadBatch: 'загрузить пакет файлов',
+            uploadExtra: 'загрузка данных с формы'
+        },
+        dropZoneTitle: 'Перетащите файлы сюда &hellip;',
+        dropZoneClickTitle: '<br>(Или щёлкните, чтобы выбрать {files})',
+        fileActionSettings: {
+            removeTitle: 'Удалить файл',
+            uploadTitle: 'Загрузить файл',
+            uploadRetryTitle: 'Повторить загрузку',
+            downloadTitle: 'Загрузить файл',
+            zoomTitle: 'Посмотреть детали',
+            dragTitle: 'Переместить / Изменить порядок',
+            indicatorNewTitle: 'Еще не загружен',
+            indicatorSuccessTitle: 'Загружен',
+            indicatorErrorTitle: 'Ошибка загрузки',
+            indicatorLoadingTitle: 'Загрузка ...'
+        },
+        previewZoomButtonTitles: {
+            prev: 'Посмотреть предыдущий файл',
+            next: 'Посмотреть следующий файл',
+            toggleheader: 'Переключить заголовок',
+            fullscreen: 'Переключить полноэкранный режим',
+            borderless: 'Переключить режим без полей',
+            close: 'Закрыть подробный предпросмотр'
+        }
+    };
+})(window.jQuery);

+ 100 - 0
public/base/plugins/bootstrap-fileinput/js/locales/sk.js

xqd
@@ -0,0 +1,100 @@
+/*!
+ * 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',
+        msgNo: 'Nie',
+        msgNoFilesSelected: '',
+        msgCancelled: 'Zrušené',
+        msgPlaceholder: 'Vybrať {files}...',
+        msgZoomModalHeading: 'Detailný náhľad',
+        msgFileRequired: 'Musíte vybrať súbor, ktorý chcete nahrať.',
+        msgSizeTooSmall: 'Súbor "{name}" (<b>{size} KB</b>) je príliš malý, musí mať veľkosť najmenej <b>{minSize} KB</b>.',
+        msgSizeTooLarge: 'Súbor "{name}" (<b>{size} KB</b>) je príliš veľký, maximálna povolená veľkosť <b>{maxSize} KB</b>.',
+        msgFilesTooLess: 'Musíte vybrať najmenej <b>{n}</b> {files} pre nahranie.',
+        msgFilesTooMany: 'Počet vybratých súborov <b>({n})</b> prekročil maximálny povolený limit <b>{m}</b>.',
+        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}".',
+        msgInvalidFileName: 'Invalid or unsupported characters in file name "{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é.',
+        msgFileTypes: {
+            'image': 'obrázok',
+            'html': 'HTML',
+            'text': 'text',
+            'video': 'video',
+            'audio': 'audio',
+            'flash': 'flash',
+            'pdf': 'PDF',
+            'object': 'object'
+        },
+        msgUploadAborted: 'Nahrávanie súboru bolo prerušené',
+        msgUploadThreshold: 'Spracovávam...',
+        msgUploadBegin: 'Inicializujem...',
+        msgUploadEnd: 'Hotovo',
+        msgUploadEmpty: 'Na nahrávanie nie sú k dispozícii žiadne platné údaje.',
+        msgUploadError: 'Chyba',
+        msgValidationError: 'Chyba overenia',
+        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 obrázku "{name}", musí byť minimálne {size} px.',
+        msgImageHeightSmall: 'Výška obrázku "{name}", musí byť minimálne {size} px.',
+        msgImageWidthLarge: 'Šírka obrázku "{name}" nemôže presiahnuť {size} px.',
+        msgImageHeightLarge: 'Výška obrázku "{name}" nesmie presiahnuť {size} px.',
+        msgImageResizeError: 'Nepodarilo sa získať veľkosť obrázka pre zmenu veľkosti.',
+        msgImageResizeException: 'Chyba pri zmene veľkosti obrázka.<pre>{errors}</pre>',
+        msgAjaxError: 'Pri operácii {operation} sa vyskytla chyba. Skúste to prosím neskôr!',
+        msgAjaxProgressError: '{operation} - neúspešné',
+        ajaxOperations: {
+            deleteThumb: 'odstrániť súbor',
+            uploadThumb: 'nahrať súbor',
+            uploadBatch: 'nahrať várku súborov',
+            uploadExtra: 'odosielanie údajov z formulára'
+        },
+        dropZoneTitle: 'Tiahni a pusť súbory tu &hellip;',
+        dropZoneClickTitle: '<br>(alebo kliknite sem a vyberte {files})',
+        fileActionSettings: {
+            removeTitle: 'Odstrániť súbor',
+            uploadTitle: 'Nahrať súbor',
+            uploadRetryTitle: 'Znova nahrať',
+            downloadTitle: 'Stiahnuť súbor',
+            zoomTitle: 'Zobraziť podrobnosti',
+            dragTitle: 'Posunúť / Preskládať',
+            indicatorNewTitle: 'Ešte nenahral',
+            indicatorSuccessTitle: 'Nahraný',
+            indicatorErrorTitle: 'Chyba pri nahrávaní',
+            indicatorLoadingTitle: 'Nahrávanie ...'
+        },
+        previewZoomButtonTitles: {
+            prev: 'Zobraziť predchádzajúci súbor',
+            next: 'Zobraziť následujúci súbor',
+            toggleheader: 'Prepnúť záhlavie',
+            fullscreen: 'Prepnúť zobrazenie na celú obrazovku',
+            borderless: 'Prepnúť na bezrámikové zobrazenie',
+            close: 'Zatvoriť detailný náhľad'
+        }
+    };
+})(window.jQuery);

+ 98 - 0
public/base/plugins/bootstrap-fileinput/js/locales/sl.js

xqd
@@ -0,0 +1,98 @@
+/*!
+ * FileInput Slovenian 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 kv1dr <kv1dr.android@gmail.com>
+ *
+ * NOTE: this file must be saved in UTF-8 encoding.
+ */
+(function ($) {
+    "use strict";
+
+    $.fn.fileinputLocales['sl'] = {
+        fileSingle: 'datoteka',
+        filePlural: 'datotek',
+        browseLabel: 'Prebrskaj &hellip;',
+        removeLabel: 'Odstrani',
+        removeTitle: 'Počisti izbrane datoteke',
+        cancelLabel: 'Prekliči',
+        cancelTitle: 'Prekliči nalaganje',
+        uploadLabel: 'Naloži',
+        uploadTitle: 'Naloži izbrane datoteke',
+        msgNo: 'Ne',
+        msgNoFilesSelected: 'Nobena datoteka ni izbrana',
+        msgCancelled: 'Preklicano',
+        msgPlaceholder: 'Select {files}...',
+        msgZoomModalHeading: 'Podroben predogled',
+        msgSizeTooLarge: 'Datoteka "{name}" (<b>{size} KB</b>) presega največjo dovoljeno velikost za nalaganje <b>{maxSize} KB</b>.',
+        msgFilesTooLess: 'Za nalaganje morate izbrati vsaj <b>{n}</b> {files}.',
+        msgFilesTooMany: 'Število datotek, izbranih za nalaganje <b>({n})</b> je prekoračilo največjo dovoljeno število <b>{m}</b>.',
+        msgFileNotFound: 'Datoteka "{name}" ni bila najdena!',
+        msgFileSecured: 'Zaradi varnostnih omejitev nisem mogel prebrati datoteko "{name}".',
+        msgFileNotReadable: 'Datoteka "{name}" ni berljiva.',
+        msgFilePreviewAborted: 'Predogled datoteke "{name}" preklican.',
+        msgFilePreviewError: 'Pri branju datoteke "{name}" je prišlo do napake.',
+        msgInvalidFileType: 'Napačen tip datoteke "{name}". Samo "{types}" datoteke so podprte.',
+        msgInvalidFileExtension: 'Napačna končnica datoteke "{name}". Samo "{extensions}" datoteke so podprte.',
+        msgFileTypes: {
+            'image': 'image',
+            'html': 'HTML',
+            'text': 'text',
+            'video': 'video',
+            'audio': 'audio',
+            'flash': 'flash',
+            'pdf': 'PDF',
+            'object': 'object'
+        },
+        msgUploadAborted: 'Nalaganje datoteke je bilo preklicano',
+        msgUploadThreshold: 'Procesiram...',
+        msgUploadBegin: 'Initializing...',
+        msgUploadEnd: 'Done',
+        msgUploadEmpty: 'No valid data available for upload.',
+        msgUploadError: 'Error',
+        msgValidationError: 'Napaki pri validiranju',
+        msgLoading: 'Nalaganje datoteke {index} od {files} &hellip;',
+        msgProgress: 'Nalaganje datoteke {index} od {files} - {name} - {percent}% dokončano.',
+        msgSelected: '{n} {files} izbrano',
+        msgFoldersNotAllowed: 'Povlecite in spustite samo datoteke! Izpuščenih je bilo {n} map.',
+        msgImageWidthSmall: 'Širina slike "{name}" mora biti vsaj {size} px.',
+        msgImageHeightSmall: 'Višina slike "{name}" mora biti vsaj {size} px.',
+        msgImageWidthLarge: 'Širina slike "{name}" ne sme preseči {size} px.',
+        msgImageHeightLarge: 'Višina slike "{name}" ne sme preseči {size} px.',
+        msgImageResizeError: 'Nisem mogel pridobiti dimenzij slike za spreminjanje velikosti.',
+        msgImageResizeException: 'Napaka pri spreminjanju velikosti slike.<pre>{errors}</pre>',
+        msgAjaxError: 'Something went wrong with the {operation} operation. Please try again later!',
+        msgAjaxProgressError: '{operation} failed',
+        ajaxOperations: {
+            deleteThumb: 'file delete',
+            uploadThumb: 'file upload',
+            uploadBatch: 'batch file upload',
+            uploadExtra: 'form data upload'
+        },
+        dropZoneTitle: 'Povlecite in spustite datoteke sem &hellip;',
+        dropZoneClickTitle: '<br>(ali kliknite sem za izbiro {files})',
+        fileActionSettings: {
+            removeTitle: 'Odstrani datoteko',
+            uploadTitle: 'Naloži datoteko',
+            uploadRetryTitle: 'Retry upload',
+            downloadTitle: 'Download file',
+            zoomTitle: 'Poglej podrobnosti',
+            dragTitle: 'Premaki / Razporedi',
+            indicatorNewTitle: 'Še ni naloženo',
+            indicatorSuccessTitle: 'Naloženo',
+            indicatorErrorTitle: 'Napaka pri nalaganju',
+            indicatorLoadingTitle: 'Nalagam ...'
+        },
+        previewZoomButtonTitles: {
+            prev: 'Poglej prejšno datoteko',
+            next: 'Poglej naslednjo datoteko',
+            toggleheader: 'Preklopi glavo',
+            fullscreen: 'Preklopi celozaslonski način',
+            borderless: 'Preklopi način brez robov',
+            close: 'Zapri predogled podrobnosti'
+        }
+    };
+})(window.jQuery);

+ 99 - 0
public/base/plugins/bootstrap-fileinput/js/locales/sv.js

xqd
@@ -0,0 +1,99 @@
+/*!
+ * 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['sv'] = {
+        fileSingle: 'fil',
+        filePlural: 'filer',
+        browseLabel: 'Bläddra &hellip;',
+        removeLabel: 'Ta bort',
+        removeTitle: 'Rensa valda filer',
+        cancelLabel: 'Avbryt',
+        cancelTitle: 'Avbryt pågående uppladdning',
+        uploadLabel: 'Ladda upp',
+        uploadTitle: 'Ladda upp valda filer',
+        msgNo: 'Nej',
+        msgNoFilesSelected: 'Inga filer valda',
+        msgCancelled: 'Avbruten',
+        msgPlaceholder: 'Select {files}...',
+        msgZoomModalHeading: 'detaljerad förhandsgranskning',
+        msgFileRequired: 'You must select a file to upload.',
+        msgSizeTooSmall: 'Filen "{name}" (<b>{size} KB</b>) är för liten och måste vara större än <b>{minSize} KB</b>.',
+        msgSizeTooLarge: 'File "{name}" (<b>{size} KB</b>) överstiger högsta tillåtna uppladdningsstorlek <b>{maxSize} KB</b>.',
+        msgFilesTooLess: 'Du måste välja minst <b>{n}</b> {files} för att ladda upp.',
+        msgFilesTooMany: 'Antal filer valda för uppladdning <b>({n})</b> överstiger högsta tillåtna gränsen <b>{m}</b>.',
+        msgFileNotFound: 'Filen "{name}" kunde inte hittas!',
+        msgFileSecured: 'Säkerhetsbegränsningar förhindrar att läsa filen "{name}".',
+        msgFileNotReadable: 'Filen "{name}" är inte läsbar.',
+        msgFilePreviewAborted: 'Filförhandsvisning avbröts för "{name}".',
+        msgFilePreviewError: 'Ett fel uppstod vid inläsning av filen "{name}".',
+        msgInvalidFileName: 'Ogiltiga eller tecken som inte stöds i filnamnet "{name}".',
+        msgInvalidFileType: 'Ogiltig typ för filen "{name}". Endast "{types}" filtyper stöds.',
+        msgInvalidFileExtension: 'Ogiltigt filtillägg för filen "{name}". Endast "{extensions}" filer stöds.',
+        msgFileTypes: {
+            'image': 'bild',
+            'html': 'HTML',
+            'text': 'text',
+            'video': 'video',
+            'audio': 'ljud',
+            'flash': 'flash',
+            'pdf': 'PDF',
+            'object': 'objekt'
+        },
+        msgUploadAborted: 'Filöverföringen avbröts',
+        msgUploadThreshold: 'Bearbetar...',
+        msgUploadBegin: 'Påbörjar...',
+        msgUploadEnd: 'Färdig',
+        msgUploadEmpty: 'Ingen giltig data tillgänglig för uppladdning.',
+        msgUploadError: 'Error',
+        msgValidationError: 'Valideringsfel',
+        msgLoading: 'Laddar fil {index} av {files} &hellip;',
+        msgProgress: 'Laddar fil {index} av {files} - {name} - {percent}% färdig.',
+        msgSelected: '{n} {files} valda',
+        msgFoldersNotAllowed: 'Endast drag & släppfiler! Skippade {n} släpta mappar.',
+        msgImageWidthSmall: 'Bredd på bildfilen "{name}" måste minst vara {size} pixlar.',
+        msgImageHeightSmall: 'Höjden på bildfilen "{name}" måste minst vara {size} pixlar.',
+        msgImageWidthLarge: 'Bredd på bildfil "{name}" kan inte överstiga {size} pixlar.',
+        msgImageHeightLarge: 'Höjden på bildfilen "{name}" kan inte överstiga {size} pixlar.',
+        msgImageResizeError: 'Det gick inte att hämta bildens dimensioner för att ändra storlek.',
+        msgImageResizeException: 'Fel vid storleksändring av bilden.<pre>{errors}</pre>',
+        msgAjaxError: 'Något gick fel med {operation} operationen. Försök igen senare!',
+        msgAjaxProgressError: '{operation} misslyckades',
+        ajaxOperations: {
+            deleteThumb: 'file delete',
+            uploadThumb: 'file upload',
+            uploadBatch: 'batch file upload',
+            uploadExtra: 'form data upload'
+        },
+        dropZoneTitle: 'Drag & släpp filer här &hellip;',
+        dropZoneClickTitle: '<br>(eller klicka för att markera {files})',
+        fileActionSettings: {
+            removeTitle: 'Ta bort fil',
+            uploadTitle: 'Ladda upp fil',
+            uploadRetryTitle: 'Retry upload',
+            zoomTitle: 'Visa detaljer',
+            dragTitle: 'Flytta / Ändra ordning',
+            indicatorNewTitle: 'Inte uppladdat ännu',
+            indicatorSuccessTitle: 'Uppladdad',
+            indicatorErrorTitle: 'Uppladdningsfel',
+            indicatorLoadingTitle: 'Laddar upp...'
+        },
+        previewZoomButtonTitles: {
+            prev: 'Visa föregående fil',
+            next: 'Visa nästa fil',
+            toggleheader: 'Rubrik',
+            fullscreen: 'Fullskärm',
+            borderless: 'Gränslös',
+            close: 'Stäng detaljerad förhandsgranskning'
+        }
+    };
+})(window.jQuery);

+ 100 - 0
public/base/plugins/bootstrap-fileinput/js/locales/th.js

xqd
@@ -0,0 +1,100 @@
+/*!
+ * 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: 'อัพโหลดไฟล์ที่เลือก',
+        msgNo: 'ไม่',
+        msgNoFilesSelected: '',
+        msgCancelled: 'ยกเลิก',
+        msgPlaceholder: 'Select {files}...',
+        msgZoomModalHeading: 'ตัวอย่างละเอียด',
+        msgFileRequired: 'You must select a file to upload.',
+        msgSizeTooSmall: 'File "{name}" (<b>{size} KB</b>) is too small and must be larger than <b>{minSize} KB</b>.',
+        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}".',
+        msgInvalidFileName: 'Invalid or unsupported characters in file name "{name}".',
+        msgInvalidFileType: 'ไฟล์ "{name}" เป็นประเภทไฟล์ที่ไม่ถูกต้อง, อนุญาตเฉพาะไฟล์ประเภท "{types}"',
+        msgInvalidFileExtension: 'ไฟล์ "{name}" เป็น extension ที่ไมถูกต้อง, อนุญาตเฉพาะไฟล์ extension "{extensions}"',
+        msgFileTypes: {
+            'image': 'image',
+            'html': 'HTML',
+            'text': 'text',
+            'video': 'video',
+            'audio': 'audio',
+            'flash': 'flash',
+            'pdf': 'PDF',
+            'object': 'object'
+        },
+        msgUploadAborted: 'อัปโหลดไฟล์ถูกยกเลิก',
+        msgUploadThreshold: 'Processing...',
+        msgUploadBegin: 'Initializing...',
+        msgUploadEnd: 'Done',
+        msgUploadEmpty: 'No valid data available for upload.',
+        msgUploadError: 'Error',
+        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} พิกเซล.',
+        msgImageResizeError: 'ไม่สามารถรับขนาดภาพเพื่อปรับขนาด',
+        msgImageResizeException: 'ข้อผิดพลาดขณะปรับขนาดภาพ<pre>{errors}</pre>',
+        msgAjaxError: 'Something went wrong with the {operation} operation. Please try again later!',
+        msgAjaxProgressError: '{operation} failed',
+        ajaxOperations: {
+            deleteThumb: 'file delete',
+            uploadThumb: 'file upload',
+            uploadBatch: 'batch file upload',
+            uploadExtra: 'form data upload'
+        },
+        dropZoneTitle: 'Drag & drop ไฟล์ตรงนี้ &hellip;',
+        dropZoneClickTitle: '<br>(or click to select {files})',
+        fileActionSettings: {
+            removeTitle: 'ลบไฟล์',
+            uploadTitle: 'อัปโหลดไฟล์',
+            uploadRetryTitle: 'Retry upload',
+            downloadTitle: 'Download file',
+            zoomTitle: 'ดูรายละเอียด',
+            dragTitle: 'Move / Rearrange',
+            indicatorNewTitle: 'ยังไม่ได้อัปโหลด',
+            indicatorSuccessTitle: 'อัพโหลด',
+            indicatorErrorTitle: 'อัปโหลดข้อผิดพลาด',
+            indicatorLoadingTitle: 'อัพโหลด ...'
+        },
+        previewZoomButtonTitles: {
+            prev: 'View previous file',
+            next: 'View next file',
+            toggleheader: 'Toggle header',
+            fullscreen: 'Toggle full screen',
+            borderless: 'Toggle borderless mode',
+            close: 'Close detailed preview'
+        }
+    };
+})(window.jQuery);

+ 99 - 0
public/base/plugins/bootstrap-fileinput/js/locales/tr.js

xqd
@@ -0,0 +1,99 @@
+/*!
+ * 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',
+        msgNo: 'Hayır',
+        msgNoFilesSelected: '',
+        msgCancelled: 'İptal edildi',
+        msgPlaceholder: 'Select {files}...',
+        msgZoomModalHeading: 'Detaylı Önizleme',
+        msgFileRequired: 'Yüklemek için bir dosya seçmelisiniz.',
+        msgSizeTooSmall: '"{name}"(<b>{size} KB</b>) dosyası çok küçük  ve <b>{minSize} KB</b> boyutundan büyük olmalıdır.',
+        msgSizeTooLarge: '"{name}" dosyasının boyutu (<b>{size} KB</b>) izin verilen azami dosya boyutu olan <b>{maxSize} KB</b>\'tan büyük.',
+        msgFilesTooLess: 'Yüklemek için en az <b>{n}</b> {files} dosya seçmelisiniz.',
+        msgFilesTooMany: 'Yüklemek için seçtiğiniz dosya sayısı <b>({n})</b> azami limitin <b>({m})</b> altında olmalıdır.',
+        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.',
+        msgInvalidFileName: '"{name}" dosya adında geçersiz veya desteklenmeyen karakterler var.',
+        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.',
+        msgFileTypes: {
+            'image': 'image',
+            'html': 'HTML',
+            'text': 'text',
+            'video': 'video',
+            'audio': 'audio',
+            'flash': 'flash',
+            'pdf': 'PDF',
+            'object': 'object'
+        },
+        msgUploadAborted: 'Dosya yükleme iptal edildi',
+        msgUploadThreshold: 'İşlem yapılıyor...',
+        msgUploadBegin: 'Başlıyor...',
+        msgUploadEnd: 'Başarılı',
+        msgUploadEmpty: 'Yüklemek için geçerli veri mevcut değil.',
+        msgUploadError: 'Error',
+        msgValidationError: 'Doğrulama Hatası',
+        msgLoading: 'Dosya 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: '"{name}" adlı görüntü dosyasının genişliği en az {size} piksel olmalıdır.',
+        msgImageHeightSmall: '"{name}" adlı görüntü dosyasının yüksekliği en az {size} piksel olmalıdır.',
+        msgImageWidthLarge: '"{name}" adlı görüntü dosyasının genişliği {size} pikseli geçemez.',
+        msgImageHeightLarge: '"{name}" adlı görüntü dosyasının yüksekliği {size} pikseli geçemez.',
+        msgImageResizeError: 'Görüntü boyutlarını yeniden boyutlandıramadı.',
+        msgImageResizeException: 'Görüntü boyutlandırma sırasında hata.<pre>{errors}</pre>',
+        msgAjaxError: '{operation} işlemi ile ilgili bir şeyler ters gitti. Lütfen daha sonra tekrar deneyiniz!',
+        msgAjaxProgressError: '{operation} işlemi başarısız oldu.',
+        ajaxOperations: {
+            deleteThumb: 'dosya silme',
+            uploadThumb: 'dosya yükleme',
+            uploadBatch: 'toplu dosya yükleme',
+            uploadExtra: 'form verisi yükleme'
+        },
+        dropZoneTitle: 'Dosyaları buraya sürükleyip bırakın',
+        dropZoneClickTitle: '<br>(ya da {files} seçmek için tıklayınız)',
+        fileActionSettings: {
+            removeTitle: 'Dosyayı kaldır',
+            uploadTitle: 'Dosyayı yükle',
+            uploadRetryTitle: 'Retry upload',
+            zoomTitle: 'Ayrıntıları görüntüle',
+            dragTitle: 'Taşı / Yeniden düzenle',
+            indicatorNewTitle: 'Henüz yüklenmedi',
+            indicatorSuccessTitle: 'Yüklendi',
+            indicatorErrorTitle: 'Yükleme Hatası',
+            indicatorLoadingTitle: 'Yükleniyor ...'
+        },
+        previewZoomButtonTitles: {
+            prev: 'Önceki dosyayı göster',
+            next: 'Sonraki dosyayı göster',
+            toggleheader: 'Üst bilgi geçiş',
+            fullscreen: 'Tam ekran geçiş',
+            borderless: 'Çerçevesiz moda geçiş',
+            close: 'Detaylı önizlemeyi kapat'
+        }
+    };
+})(window.jQuery);

+ 101 - 0
public/base/plugins/bootstrap-fileinput/js/locales/uk.js

xqd
@@ -0,0 +1,101 @@
+/*!
+ * 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 <cyanofresh@gmail.com>
+ *
+ * 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: 'Відвантажити обрані файли',
+        msgNo: 'Немає',
+        msgNoFilesSelected: '',
+        msgCancelled: 'Cкасовано',
+        msgPlaceholder: 'Оберіть {files}...',
+        msgZoomModalHeading: 'Детальний превью',
+        msgFileRequired: 'Ви повинні обрати файл для завантаження.',
+        msgSizeTooSmall: 'Файл "{name}" (<b>{size} KB</b>) занадто малий і повинен бути більший, ніж <b>{minSize} KB</b>.',
+        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}".',
+        msgInvalidFileName: 'Недійсні чи непідтримувані символи в імені файлу "{name}".',
+        msgInvalidFileType: 'Заборонений тип файла для "{name}". Тільки "{types}" дозволені.',
+        msgInvalidFileExtension: 'Заборонене розширення для файла "{name}". Тільки "{extensions}" дозволені.',
+        msgFileTypes: {
+            'image': 'image',
+            'html': 'HTML',
+            'text': 'text',
+            'video': 'video',
+            'audio': 'audio',
+            'flash': 'flash',
+            'pdf': 'PDF',
+            'object': 'object'
+        },
+        msgUploadAborted: 'Вивантаження файлу перервана',
+        msgUploadThreshold: 'Обробка...',
+        msgUploadBegin: 'Ініціалізація...',
+        msgUploadEnd: 'Готово',
+        msgUploadEmpty: 'Немає доступних даних для відвантаження.',
+        msgUploadError: 'Помилка',
+        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.',
+        msgImageResizeError: 'Не вдалося розміри зображення, щоб змінити розмір.',
+        msgImageResizeException: 'Помилка при зміні розміру зображення.<pre>{errors}</pre>',
+        msgAjaxError: 'Щось не так із операцією {operation}. Будь ласка, спробуйте пізніше!',
+        msgAjaxProgressError: 'помилка {operation}',
+        ajaxOperations: {
+            deleteThumb: 'видалити файл',
+            uploadThumb: 'відвантажити файл',
+            uploadBatch: 'batch file upload',
+            uploadExtra: 'form data upload'
+        },
+        dropZoneTitle: 'Перетягніть файли сюди &hellip;',
+        dropZoneClickTitle: '<br>(або клацність та оберіть {files})',
+        fileActionSettings: {
+            removeTitle: 'Видалити файл',
+            uploadTitle: 'Відвантажити файл',
+            uploadRetryTitle: 'Повторити відвантаження',
+            downloadTitle: 'Завантажити файл',
+            zoomTitle: 'Подивитися деталі',
+            dragTitle: 'Перенести / Переставити',
+            indicatorNewTitle: 'Ще не відвантажено',
+            indicatorSuccessTitle: 'Відвантажено',
+            indicatorErrorTitle: 'Помилка при відвантаженні',
+            indicatorLoadingTitle: 'Завантаження ...'
+        },
+        previewZoomButtonTitles: {
+            prev: 'Переглянути попередній файл',
+            next: 'Переглянути наступний файл',
+            toggleheader: 'Перемкнути заголовок',
+            fullscreen: 'Перемкнути повноекранний режим',
+            borderless: 'Перемкнути режим без полів',
+            close: 'Закрити детальний перегляд'
+        }
+    };
+})(window.jQuery);

+ 101 - 0
public/base/plugins/bootstrap-fileinput/js/locales/vi.js

xqd
@@ -0,0 +1,101 @@
+/*!
+ * FileInput Vietnamese 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['vi'] = {
+        fileSingle: 'tập tin',
+        filePlural: 'các tập tin',
+        browseLabel: 'Duyệt &hellip;',
+        removeLabel: 'Gỡ bỏ',
+        removeTitle: 'Bỏ tập tin đã chọn',
+        cancelLabel: 'Hủy',
+        cancelTitle: 'Hủy upload',
+        uploadLabel: 'Upload',
+        uploadTitle: 'Upload tập tin đã chọn',
+        msgNo: 'Không',
+        msgNoFilesSelected: 'Không tập tin nào được chọn',
+        msgCancelled: 'Đã hủy',
+        msgPlaceholder: 'Select {files}...',
+        msgZoomModalHeading: 'Chi tiết xem trước',
+        msgFileRequired: 'You must select a file to upload.',
+        msgSizeTooSmall: 'File "{name}" (<b>{size} KB</b>) is too small and must be larger than <b>{minSize} KB</b>.',
+        msgSizeTooLarge: 'Tập tin "{name}" (<b>{size} KB</b>) vượt quá kích thước giới hạn cho phép <b>{maxSize} KB</b>.',
+        msgFilesTooLess: 'Bạn phải chọn ít nhất <b>{n}</b> {files} để upload.',
+        msgFilesTooMany: 'Số lượng tập tin upload <b>({n})</b> vượt quá giới hạn cho phép là <b>{m}</b>.',
+        msgFileNotFound: 'Không tìm thấy tập tin "{name}"!',
+        msgFileSecured: 'Các hạn chế về bảo mật không cho phép đọc tập tin "{name}".',
+        msgFileNotReadable: 'Không đọc được tập tin "{name}".',
+        msgFilePreviewAborted: 'Đã dừng xem trước tập tin "{name}".',
+        msgFilePreviewError: 'Đã xảy ra lỗi khi đọc tập tin "{name}".',
+        msgInvalidFileName: 'Invalid or unsupported characters in file name "{name}".',
+        msgInvalidFileType: 'Tập tin "{name}" không hợp lệ. Chỉ hỗ trợ loại tập tin "{types}".',
+        msgInvalidFileExtension: 'Phần mở rộng của tập tin "{name}" không hợp lệ. Chỉ hỗ trợ phần mở rộng "{extensions}".',
+        msgFileTypes: {
+            'image': 'image',
+            'html': 'HTML',
+            'text': 'text',
+            'video': 'video',
+            'audio': 'audio',
+            'flash': 'flash',
+            'pdf': 'PDF',
+            'object': 'object'
+        },
+        msgUploadAborted: 'Đã dừng upload',
+        msgUploadThreshold: 'Đang xử lý...',
+        msgUploadBegin: 'Initializing...',
+        msgUploadEnd: 'Done',
+        msgUploadEmpty: 'No valid data available for upload.',
+        msgUploadError: 'Error',
+        msgValidationError: 'Lỗi xác nhận',
+        msgLoading: 'Đang nạp {index} tập tin trong số {files} &hellip;',
+        msgProgress: 'Đang nạp {index} tập tin trong số {files} - {name} - {percent}% hoàn thành.',
+        msgSelected: '{n} {files} được chọn',
+        msgFoldersNotAllowed: 'Chỉ kéo thả tập tin! Đã bỏ qua {n} thư mục.',
+        msgImageWidthSmall: 'Chiều rộng của hình ảnh "{name}" phải tối thiểu là {size} px.',
+        msgImageHeightSmall: 'Chiều cao của hình ảnh "{name}" phải tối thiểu là {size} px.',
+        msgImageWidthLarge: 'Chiều rộng của hình ảnh "{name}" không được quá {size} px.',
+        msgImageHeightLarge: 'Chiều cao của hình ảnh "{name}" không được quá {size} px.',
+        msgImageResizeError: 'Không lấy được kích thước của hình ảnh để resize.',
+        msgImageResizeException: 'Resize hình ảnh bị lỗi.<pre>{errors}</pre>',
+        msgAjaxError: 'Something went wrong with the {operation} operation. Please try again later!',
+        msgAjaxProgressError: '{operation} failed',
+        ajaxOperations: {
+            deleteThumb: 'file delete',
+            uploadThumb: 'file upload',
+            uploadBatch: 'batch file upload',
+            uploadExtra: 'form data upload'
+        },
+        dropZoneTitle: 'Kéo thả tập tin vào đây &hellip;',
+        dropZoneClickTitle: '<br>(hoặc click để chọn {files})',
+        fileActionSettings: {
+            removeTitle: 'Gỡ bỏ',
+            uploadTitle: 'Upload tập tin',
+            uploadRetryTitle: 'Retry upload',
+            downloadTitle: 'Download file',
+            zoomTitle: 'Phóng lớn',
+            dragTitle: 'Di chuyển / Sắp xếp lại',
+            indicatorNewTitle: 'Chưa được upload',
+            indicatorSuccessTitle: 'Đã upload',
+            indicatorErrorTitle: 'Upload bị lỗi',
+            indicatorLoadingTitle: 'Đang upload ...'
+        },
+        previewZoomButtonTitles: {
+            prev: 'Xem tập tin phía trước',
+            next: 'Xem tập tin tiếp theo',
+            toggleheader: 'Ẩn/hiện tiêu đề',
+            fullscreen: 'Bật/tắt toàn màn hình',
+            borderless: 'Bật/tắt chế độ không viền',
+            close: 'Đóng'
+        }
+    };
+})(window.jQuery);

+ 102 - 0
public/base/plugins/bootstrap-fileinput/js/locales/zh-TW.js

xqd
@@ -0,0 +1,102 @@
+/*!
+ * FileInput Chinese Traditional 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 <kangqingfei@gmail.com>
+ *
+ * NOTE: this file must be saved in UTF-8 encoding.
+ */
+(function ($) {
+    "use strict";
+
+    $.fn.fileinputLocales['zh-TW'] = {
+        fileSingle: '單一檔案',
+        filePlural: '複選檔案',
+        browseLabel: '瀏覽 &hellip;',
+        removeLabel: '移除',
+        removeTitle: '清除選取檔案',
+        cancelLabel: '取消',
+        cancelTitle: '取消上傳中檔案',
+        uploadLabel: '上傳',
+        uploadTitle: '上傳選取檔案',
+        msgNo: '沒有',
+        msgNoFilesSelected: '未選擇檔案',
+        msgCancelled: '取消',
+        zoomTitle: '詳細資料',
+        msgPlaceholder: '選擇 {files}...',
+        msgZoomModalHeading: '內容預覽',
+        msgFileRequired: '必須選擇壹個文件上傳.',
+        msgSizeTooSmall: '檔案 "{name}" (<b>{size} KB</b>) 必須大於限定大小 <b>{minSize} KB</b>.',
+        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}" 發生錯誤.',
+        msgInvalidFileName: '附檔名 "{name}" 包含非法字符.',
+        msgInvalidFileType: '檔案類型錯誤 "{name}". 只能使用 "{types}" 類型的檔案.',
+        msgInvalidFileExtension: '附檔名錯誤 "{name}". 只能使用 "{extensions}" 的檔案.',
+        msgFileTypes: {
+            'image': 'image',
+            'html': 'HTML',
+            'text': 'text',
+            'video': 'video',
+            'audio': 'audio',
+            'flash': 'flash',
+            'pdf': 'PDF',
+            'object': 'object'
+        },
+        msgUploadAborted: '該文件上傳被中止',
+        msgUploadThreshold: '處理中...',
+        msgUploadBegin: '正在初始化...',
+        msgUploadEnd: '完成',
+        msgUploadEmpty: '無效的文件上傳.',
+        msgUploadError: '上傳錯誤',
+        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).',
+        msgImageResizeError: '無法獲取的圖像尺寸調整。',
+        msgImageResizeException: '錯誤而調整圖像大小。<pre>{errors}</pre>',
+        msgAjaxError: '{operation} 發生錯誤. 請重試!',
+        msgAjaxProgressError: '{operation} 失敗',
+        ajaxOperations: {
+            deleteThumb: 'file delete',
+            uploadThumb: 'file upload',
+            uploadBatch: 'batch file upload',
+            uploadExtra: 'form data upload'
+        },
+        dropZoneTitle: '拖曳檔案至此 &hellip;',
+        dropZoneClickTitle: '<br>(或點擊{files}按鈕選擇文件)',
+        fileActionSettings: {
+            removeTitle: '刪除檔案',
+            uploadTitle: '上傳檔案',
+            uploadRetryTitle: '重試',
+            downloadTitle: '下載檔案',
+            zoomTitle: '詳細資料',
+            dragTitle: '移動 / 重置',
+            indicatorNewTitle: '尚未上傳',
+            indicatorSuccessTitle: '上傳成功',
+            indicatorErrorTitle: '上傳失敗',
+            indicatorLoadingTitle: '上傳中 ...'
+        },
+        previewZoomButtonTitles: {
+            prev: '預覽上壹個文件',
+            next: '預覽下壹個文件',
+            toggleheader: '縮放',
+            fullscreen: '全屏',
+            borderless: '無邊界模式',
+            close: '關閉當前預覽'
+        }
+    };
+})(window.jQuery);

+ 100 - 0
public/base/plugins/bootstrap-fileinput/js/locales/zh.js

xqd
@@ -0,0 +1,100 @@
+/*!
+ * 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 <kangqingfei@gmail.com>
+ *
+ * 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: '上传选中文件',
+        msgNo: '没有',
+        msgNoFilesSelected: '未选择文件',
+        msgCancelled: '取消',
+        msgPlaceholder: '选择 {files}...',
+        msgZoomModalHeading: '详细预览',
+        msgFileRequired: '必须选择一个文件上传.',
+        msgSizeTooSmall: '文件 "{name}" (<b>{size} KB</b>) 必须大于限定大小 <b>{minSize} KB</b>.',
+        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}" 时出现了一个错误.',
+        msgInvalidFileName: '文件名 "{name}" 包含非法字符.',
+        msgInvalidFileType: '不正确的类型 "{name}". 只支持 "{types}" 类型的文件.',
+        msgInvalidFileExtension: '不正确的文件扩展名 "{name}". 只支持 "{extensions}" 的文件扩展名.',
+        msgFileTypes: {
+            'image': 'image',
+            'html': 'HTML',
+            'text': 'text',
+            'video': 'video',
+            'audio': 'audio',
+            'flash': 'flash',
+            'pdf': 'PDF',
+            'object': 'object'
+        },
+        msgUploadAborted: '该文件上传被中止',
+        msgUploadThreshold: '处理中...',
+        msgUploadBegin: '正在初始化...',
+        msgUploadEnd: '完成',
+        msgUploadEmpty: '无效的文件上传.',
+        msgUploadError: '上传出错',
+        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}像素.',
+        msgImageResizeError: '无法获取的图像尺寸调整。',
+        msgImageResizeException: '调整图像大小时发生错误。<pre>{errors}</pre>',
+        msgAjaxError: '{operation} 发生错误. 请重试!',
+        msgAjaxProgressError: '{operation} 失败',
+        ajaxOperations: {
+            deleteThumb: '删除文件',
+            uploadThumb: '上传文件',
+            uploadBatch: '批量上传',
+            uploadExtra: '表单数据上传'
+        },
+        dropZoneTitle: '拖拽文件到这里 &hellip;<br>支持多文件同时上传',
+        dropZoneClickTitle: '<br>(或点击{files}按钮选择文件)',
+        fileActionSettings: {
+            removeTitle: '删除文件',
+            uploadTitle: '上传文件',
+            uploadRetryTitle: '重试',
+            zoomTitle: '查看详情',
+            dragTitle: '移动 / 重置',
+            indicatorNewTitle: '没有上传',
+            indicatorSuccessTitle: '上传',
+            indicatorErrorTitle: '上传错误',
+            indicatorLoadingTitle: '上传 ...'
+        },
+        previewZoomButtonTitles: {
+            prev: '预览上一个文件',
+            next: '预览下一个文件',
+            toggleheader: '缩放',
+            fullscreen: '全屏',
+            borderless: '无边界模式',
+            close: '关闭当前预览'
+        }
+    };
+})(window.jQuery);

+ 2471 - 0
public/base/plugins/bootstrap-fileinput/js/plugins/piexif.js

xqd
@@ -0,0 +1,2471 @@
+/* piexifjs
+
+The MIT License (MIT)
+
+Copyright (c) 2014, 2015 hMatoba(https://github.com/hMatoba)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+(function () {
+    "use strict";
+    var that = {};
+    that.version = "1.03";
+
+    that.remove = function (jpeg) {
+        var b64 = false;
+        if (jpeg.slice(0, 2) == "\xff\xd8") {
+        } else if (jpeg.slice(0, 23) == "data:image/jpeg;base64," || jpeg.slice(0, 22) == "data:image/jpg;base64,") {
+            jpeg = atob(jpeg.split(",")[1]);
+            b64 = true;
+        } else {
+            throw ("Given data is not jpeg.");
+        }
+        
+        var segments = splitIntoSegments(jpeg);
+        if (segments[1].slice(0, 2) == "\xff\xe1" && 
+               segments[1].slice(4, 10) == "Exif\x00\x00") {
+            segments = [segments[0]].concat(segments.slice(2));
+        } else if (segments[2].slice(0, 2) == "\xff\xe1" &&
+                   segments[2].slice(4, 10) == "Exif\x00\x00") {
+            segments = segments.slice(0, 2).concat(segments.slice(3));
+        } else {
+            throw("Exif not found.");
+        }
+        
+        var new_data = segments.join("");
+        if (b64) {
+            new_data = "data:image/jpeg;base64," + btoa(new_data);
+        }
+
+        return new_data;
+    };
+
+
+    that.insert = function (exif, jpeg) {
+        var b64 = false;
+        if (exif.slice(0, 6) != "\x45\x78\x69\x66\x00\x00") {
+            throw ("Given data is not exif.");
+        }
+        if (jpeg.slice(0, 2) == "\xff\xd8") {
+        } else if (jpeg.slice(0, 23) == "data:image/jpeg;base64," || jpeg.slice(0, 22) == "data:image/jpg;base64,") {
+            jpeg = atob(jpeg.split(",")[1]);
+            b64 = true;
+        } else {
+            throw ("Given data is not jpeg.");
+        }
+
+        var exifStr = "\xff\xe1" + pack(">H", [exif.length + 2]) + exif;
+        var segments = splitIntoSegments(jpeg);
+        var new_data = mergeSegments(segments, exifStr);
+        if (b64) {
+            new_data = "data:image/jpeg;base64," + btoa(new_data);
+        }
+
+        return new_data;
+    };
+
+
+    that.load = function (data) {
+        var input_data;
+        if (typeof (data) == "string") {
+            if (data.slice(0, 2) == "\xff\xd8") {
+                input_data = data;
+            } else if (data.slice(0, 23) == "data:image/jpeg;base64," || data.slice(0, 22) == "data:image/jpg;base64,") {
+                input_data = atob(data.split(",")[1]);
+            } else if (data.slice(0, 4) == "Exif") {
+                input_data = data.slice(6);
+            } else {
+                throw ("'load' gots invalid file data.");
+            }
+        } else {
+            throw ("'load' gots invalid type argument.");
+        }
+
+        var exifDict = {};
+        var exif_dict = {
+            "0th": {},
+            "Exif": {},
+            "GPS": {},
+            "Interop": {},
+            "1st": {},
+            "thumbnail": null
+        };
+        var exifReader = new ExifReader(input_data);
+        if (exifReader.tiftag === null) {
+            return exif_dict;
+        }
+
+        if (exifReader.tiftag.slice(0, 2) == "\x49\x49") {
+            exifReader.endian_mark = "<";
+        } else {
+            exifReader.endian_mark = ">";
+        }
+
+        var pointer = unpack(exifReader.endian_mark + "L",
+            exifReader.tiftag.slice(4, 8))[0];
+        exif_dict["0th"] = exifReader.get_ifd(pointer, "0th");
+
+        var first_ifd_pointer = exif_dict["0th"]["first_ifd_pointer"];
+        delete exif_dict["0th"]["first_ifd_pointer"];
+
+        if (34665 in exif_dict["0th"]) {
+            pointer = exif_dict["0th"][34665];
+            exif_dict["Exif"] = exifReader.get_ifd(pointer, "Exif");
+        }
+        if (34853 in exif_dict["0th"]) {
+            pointer = exif_dict["0th"][34853];
+            exif_dict["GPS"] = exifReader.get_ifd(pointer, "GPS");
+        }
+        if (40965 in exif_dict["Exif"]) {
+            pointer = exif_dict["Exif"][40965];
+            exif_dict["Interop"] = exifReader.get_ifd(pointer, "Interop");
+        }
+        if (first_ifd_pointer != "\x00\x00\x00\x00") {
+            pointer = unpack(exifReader.endian_mark + "L",
+                first_ifd_pointer)[0];
+            exif_dict["1st"] = exifReader.get_ifd(pointer, "1st");
+            if ((513 in exif_dict["1st"]) && (514 in exif_dict["1st"])) {
+                var end = exif_dict["1st"][513] + exif_dict["1st"][514];
+                var thumb = exifReader.tiftag.slice(exif_dict["1st"][513], end);
+                exif_dict["thumbnail"] = thumb;
+            }
+        }
+
+        return exif_dict;
+    };
+
+
+    that.dump = function (exif_dict_original) {
+        var TIFF_HEADER_LENGTH = 8;
+
+        var exif_dict = copy(exif_dict_original);
+        var header = "Exif\x00\x00\x4d\x4d\x00\x2a\x00\x00\x00\x08";
+        var exif_is = false;
+        var gps_is = false;
+        var interop_is = false;
+        var first_is = false;
+
+        var zeroth_ifd,
+            exif_ifd,
+            interop_ifd,
+            gps_ifd,
+            first_ifd;
+        
+        if ("0th" in exif_dict) {
+            zeroth_ifd = exif_dict["0th"];
+        } else {
+            zeroth_ifd = {};
+        }
+        
+        if ((("Exif" in exif_dict) && (Object.keys(exif_dict["Exif"]).length)) ||
+            (("Interop" in exif_dict) && (Object.keys(exif_dict["Interop"]).length))) {
+            zeroth_ifd[34665] = 1;
+            exif_is = true;
+            exif_ifd = exif_dict["Exif"];
+            if (("Interop" in exif_dict) && Object.keys(exif_dict["Interop"]).length) {
+                exif_ifd[40965] = 1;
+                interop_is = true;
+                interop_ifd = exif_dict["Interop"];
+            } else if (Object.keys(exif_ifd).indexOf(that.ExifIFD.InteroperabilityTag.toString()) > -1) {
+                delete exif_ifd[40965];
+            }
+        } else if (Object.keys(zeroth_ifd).indexOf(that.ImageIFD.ExifTag.toString()) > -1) {
+            delete zeroth_ifd[34665];
+        }
+
+        if (("GPS" in exif_dict) && (Object.keys(exif_dict["GPS"]).length)) {
+            zeroth_ifd[that.ImageIFD.GPSTag] = 1;
+            gps_is = true;
+            gps_ifd = exif_dict["GPS"];
+        } else if (Object.keys(zeroth_ifd).indexOf(that.ImageIFD.GPSTag.toString()) > -1) {
+            delete zeroth_ifd[that.ImageIFD.GPSTag];
+        }
+        
+        if (("1st" in exif_dict) &&
+            ("thumbnail" in exif_dict) &&
+            (exif_dict["thumbnail"] != null)) {
+            first_is = true;
+            exif_dict["1st"][513] = 1;
+            exif_dict["1st"][514] = 1;
+            first_ifd = exif_dict["1st"];
+        }
+        
+        var zeroth_set = _dict_to_bytes(zeroth_ifd, "0th", 0);
+        var zeroth_length = (zeroth_set[0].length + exif_is * 12 + gps_is * 12 + 4 +
+            zeroth_set[1].length);
+
+        var exif_set,
+            exif_bytes = "",
+            exif_length = 0,
+            gps_set,
+            gps_bytes = "",
+            gps_length = 0,
+            interop_set,
+            interop_bytes = "",
+            interop_length = 0,
+            first_set,
+            first_bytes = "",
+            thumbnail;
+        if (exif_is) {
+            exif_set = _dict_to_bytes(exif_ifd, "Exif", zeroth_length);
+            exif_length = exif_set[0].length + interop_is * 12 + exif_set[1].length;
+        }
+        if (gps_is) {
+            gps_set = _dict_to_bytes(gps_ifd, "GPS", zeroth_length + exif_length);
+            gps_bytes = gps_set.join("");
+            gps_length = gps_bytes.length;
+        }
+        if (interop_is) {
+            var offset = zeroth_length + exif_length + gps_length;
+            interop_set = _dict_to_bytes(interop_ifd, "Interop", offset);
+            interop_bytes = interop_set.join("");
+            interop_length = interop_bytes.length;
+        }
+        if (first_is) {
+            var offset = zeroth_length + exif_length + gps_length + interop_length;
+            first_set = _dict_to_bytes(first_ifd, "1st", offset);
+            thumbnail = _get_thumbnail(exif_dict["thumbnail"]);
+            if (thumbnail.length > 64000) {
+                throw ("Given thumbnail is too large. max 64kB");
+            }
+        }
+
+        var exif_pointer = "",
+            gps_pointer = "",
+            interop_pointer = "",
+            first_ifd_pointer = "\x00\x00\x00\x00";
+        if (exif_is) {
+            var pointer_value = TIFF_HEADER_LENGTH + zeroth_length;
+            var pointer_str = pack(">L", [pointer_value]);
+            var key = 34665;
+            var key_str = pack(">H", [key]);
+            var type_str = pack(">H", [TYPES["Long"]]);
+            var length_str = pack(">L", [1]);
+            exif_pointer = key_str + type_str + length_str + pointer_str;
+        }
+        if (gps_is) {
+            var pointer_value = TIFF_HEADER_LENGTH + zeroth_length + exif_length;
+            var pointer_str = pack(">L", [pointer_value]);
+            var key = 34853;
+            var key_str = pack(">H", [key]);
+            var type_str = pack(">H", [TYPES["Long"]]);
+            var length_str = pack(">L", [1]);
+            gps_pointer = key_str + type_str + length_str + pointer_str;
+        }
+        if (interop_is) {
+            var pointer_value = (TIFF_HEADER_LENGTH +
+                zeroth_length + exif_length + gps_length);
+            var pointer_str = pack(">L", [pointer_value]);
+            var key = 40965;
+            var key_str = pack(">H", [key]);
+            var type_str = pack(">H", [TYPES["Long"]]);
+            var length_str = pack(">L", [1]);
+            interop_pointer = key_str + type_str + length_str + pointer_str;
+        }
+        if (first_is) {
+            var pointer_value = (TIFF_HEADER_LENGTH + zeroth_length +
+                exif_length + gps_length + interop_length);
+            first_ifd_pointer = pack(">L", [pointer_value]);
+            var thumbnail_pointer = (pointer_value + first_set[0].length + 24 +
+                4 + first_set[1].length);
+            var thumbnail_p_bytes = ("\x02\x01\x00\x04\x00\x00\x00\x01" +
+                pack(">L", [thumbnail_pointer]));
+            var thumbnail_length_bytes = ("\x02\x02\x00\x04\x00\x00\x00\x01" +
+                pack(">L", [thumbnail.length]));
+            first_bytes = (first_set[0] + thumbnail_p_bytes +
+                thumbnail_length_bytes + "\x00\x00\x00\x00" +
+                first_set[1] + thumbnail);
+        }
+
+        var zeroth_bytes = (zeroth_set[0] + exif_pointer + gps_pointer +
+            first_ifd_pointer + zeroth_set[1]);
+        if (exif_is) {
+            exif_bytes = exif_set[0] + interop_pointer + exif_set[1];
+        }
+
+        return (header + zeroth_bytes + exif_bytes + gps_bytes +
+            interop_bytes + first_bytes);
+    };
+
+
+    function copy(obj) {
+        return JSON.parse(JSON.stringify(obj));
+    }
+
+
+    function _get_thumbnail(jpeg) {
+        var segments = splitIntoSegments(jpeg);
+        while (("\xff\xe0" <= segments[1].slice(0, 2)) && (segments[1].slice(0, 2) <= "\xff\xef")) {
+            segments = [segments[0]].concat(segments.slice(2));
+        }
+        return segments.join("");
+    }
+
+
+    function _pack_byte(array) {
+        return pack(">" + nStr("B", array.length), array);
+    }
+
+
+    function _pack_short(array) {
+        return pack(">" + nStr("H", array.length), array);
+    }
+
+
+    function _pack_long(array) {
+        return pack(">" + nStr("L", array.length), array);
+    }
+
+
+    function _value_to_bytes(raw_value, value_type, offset) {
+        var four_bytes_over = "";
+        var value_str = "";
+        var length,
+            new_value,
+            num,
+            den;
+
+        if (value_type == "Byte") {
+            length = raw_value.length;
+            if (length <= 4) {
+                value_str = (_pack_byte(raw_value) +
+                    nStr("\x00", 4 - length));
+            } else {
+                value_str = pack(">L", [offset]);
+                four_bytes_over = _pack_byte(raw_value);
+            }
+        } else if (value_type == "Short") {
+            length = raw_value.length;
+            if (length <= 2) {
+                value_str = (_pack_short(raw_value) +
+                    nStr("\x00\x00", 2 - length));
+            } else {
+                value_str = pack(">L", [offset]);
+                four_bytes_over = _pack_short(raw_value);
+            }
+        } else if (value_type == "Long") {
+            length = raw_value.length;
+            if (length <= 1) {
+                value_str = _pack_long(raw_value);
+            } else {
+                value_str = pack(">L", [offset]);
+                four_bytes_over = _pack_long(raw_value);
+            }
+        } else if (value_type == "Ascii") {
+            new_value = raw_value + "\x00";
+            length = new_value.length;
+            if (length > 4) {
+                value_str = pack(">L", [offset]);
+                four_bytes_over = new_value;
+            } else {
+                value_str = new_value + nStr("\x00", 4 - length);
+            }
+        } else if (value_type == "Rational") {
+            if (typeof (raw_value[0]) == "number") {
+                length = 1;
+                num = raw_value[0];
+                den = raw_value[1];
+                new_value = pack(">L", [num]) + pack(">L", [den]);
+            } else {
+                length = raw_value.length;
+                new_value = "";
+                for (var n = 0; n < length; n++) {
+                    num = raw_value[n][0];
+                    den = raw_value[n][1];
+                    new_value += (pack(">L", [num]) +
+                        pack(">L", [den]));
+                }
+            }
+            value_str = pack(">L", [offset]);
+            four_bytes_over = new_value;
+        } else if (value_type == "SRational") {
+            if (typeof (raw_value[0]) == "number") {
+                length = 1;
+                num = raw_value[0];
+                den = raw_value[1];
+                new_value = pack(">l", [num]) + pack(">l", [den]);
+            } else {
+                length = raw_value.length;
+                new_value = "";
+                for (var n = 0; n < length; n++) {
+                    num = raw_value[n][0];
+                    den = raw_value[n][1];
+                    new_value += (pack(">l", [num]) +
+                        pack(">l", [den]));
+                }
+            }
+            value_str = pack(">L", [offset]);
+            four_bytes_over = new_value;
+        } else if (value_type == "Undefined") {
+            length = raw_value.length;
+            if (length > 4) {
+                value_str = pack(">L", [offset]);
+                four_bytes_over = raw_value;
+            } else {
+                value_str = raw_value + nStr("\x00", 4 - length);
+            }
+        }
+
+        var length_str = pack(">L", [length]);
+
+        return [length_str, value_str, four_bytes_over];
+    }
+
+    function _dict_to_bytes(ifd_dict, ifd, ifd_offset) {
+        var TIFF_HEADER_LENGTH = 8;
+        var tag_count = Object.keys(ifd_dict).length;
+        var entry_header = pack(">H", [tag_count]);
+        var entries_length;
+        if (["0th", "1st"].indexOf(ifd) > -1) {
+            entries_length = 2 + tag_count * 12 + 4;
+        } else {
+            entries_length = 2 + tag_count * 12;
+        }
+        var entries = "";
+        var values = "";
+        var key;
+
+        for (var key in ifd_dict) {
+            if (typeof (key) == "string") {
+                key = parseInt(key);
+            }
+            if ((ifd == "0th") && ([34665, 34853].indexOf(key) > -1)) {
+                continue;
+            } else if ((ifd == "Exif") && (key == 40965)) {
+                continue;
+            } else if ((ifd == "1st") && ([513, 514].indexOf(key) > -1)) {
+                continue;
+            }
+
+            var raw_value = ifd_dict[key];
+            var key_str = pack(">H", [key]);
+            var value_type = TAGS[ifd][key]["type"];
+            var type_str = pack(">H", [TYPES[value_type]]);
+
+            if (typeof (raw_value) == "number") {
+                raw_value = [raw_value];
+            }
+            var offset = TIFF_HEADER_LENGTH + entries_length + ifd_offset + values.length;
+            var b = _value_to_bytes(raw_value, value_type, offset);
+            var length_str = b[0];
+            var value_str = b[1];
+            var four_bytes_over = b[2];
+
+            entries += key_str + type_str + length_str + value_str;
+            values += four_bytes_over;
+        }
+
+        return [entry_header + entries, values];
+    }
+
+
+
+    function ExifReader(data) {
+        var segments,
+            app1;
+        if (data.slice(0, 2) == "\xff\xd8") { // JPEG
+            segments = splitIntoSegments(data);
+            app1 = getExifSeg(segments);
+            if (app1) {
+                this.tiftag = app1.slice(10);
+            } else {
+                this.tiftag = null;
+            }
+        } else if (["\x49\x49", "\x4d\x4d"].indexOf(data.slice(0, 2)) > -1) { // TIFF
+            this.tiftag = data;
+        } else if (data.slice(0, 4) == "Exif") { // Exif
+            this.tiftag = data.slice(6);
+        } else {
+            throw ("Given file is neither JPEG nor TIFF.");
+        }
+    }
+
+    ExifReader.prototype = {
+        get_ifd: function (pointer, ifd_name) {
+            var ifd_dict = {};
+            var tag_count = unpack(this.endian_mark + "H",
+                this.tiftag.slice(pointer, pointer + 2))[0];
+            var offset = pointer + 2;
+            var t;
+            if (["0th", "1st"].indexOf(ifd_name) > -1) {
+                t = "Image";
+            } else {
+                t = ifd_name;
+            }
+
+            for (var x = 0; x < tag_count; x++) {
+                pointer = offset + 12 * x;
+                var tag = unpack(this.endian_mark + "H",
+                    this.tiftag.slice(pointer, pointer + 2))[0];
+                var value_type = unpack(this.endian_mark + "H",
+                    this.tiftag.slice(pointer + 2, pointer + 4))[0];
+                var value_num = unpack(this.endian_mark + "L",
+                    this.tiftag.slice(pointer + 4, pointer + 8))[0];
+                var value = this.tiftag.slice(pointer + 8, pointer + 12);
+
+                var v_set = [value_type, value_num, value];
+                if (tag in TAGS[t]) {
+                    ifd_dict[tag] = this.convert_value(v_set);
+                }
+            }
+
+            if (ifd_name == "0th") {
+                pointer = offset + 12 * tag_count;
+                ifd_dict["first_ifd_pointer"] = this.tiftag.slice(pointer, pointer + 4);
+            }
+
+            return ifd_dict;
+        },
+
+        convert_value: function (val) {
+            var data = null;
+            var t = val[0];
+            var length = val[1];
+            var value = val[2];
+            var pointer;
+
+            if (t == 1) { // BYTE
+                if (length > 4) {
+                    pointer = unpack(this.endian_mark + "L", value)[0];
+                    data = unpack(this.endian_mark + nStr("B", length),
+                        this.tiftag.slice(pointer, pointer + length));
+                } else {
+                    data = unpack(this.endian_mark + nStr("B", length), value.slice(0, length));
+                }
+            } else if (t == 2) { // ASCII
+                if (length > 4) {
+                    pointer = unpack(this.endian_mark + "L", value)[0];
+                    data = this.tiftag.slice(pointer, pointer + length - 1);
+                } else {
+                    data = value.slice(0, length - 1);
+                }
+            } else if (t == 3) { // SHORT
+                if (length > 2) {
+                    pointer = unpack(this.endian_mark + "L", value)[0];
+                    data = unpack(this.endian_mark + nStr("H", length),
+                        this.tiftag.slice(pointer, pointer + length * 2));
+                } else {
+                    data = unpack(this.endian_mark + nStr("H", length),
+                        value.slice(0, length * 2));
+                }
+            } else if (t == 4) { // LONG
+                if (length > 1) {
+                    pointer = unpack(this.endian_mark + "L", value)[0];
+                    data = unpack(this.endian_mark + nStr("L", length),
+                        this.tiftag.slice(pointer, pointer + length * 4));
+                } else {
+                    data = unpack(this.endian_mark + nStr("L", length),
+                        value);
+                }
+            } else if (t == 5) { // RATIONAL
+                pointer = unpack(this.endian_mark + "L", value)[0];
+                if (length > 1) {
+                    data = [];
+                    for (var x = 0; x < length; x++) {
+                        data.push([unpack(this.endian_mark + "L",
+                                this.tiftag.slice(pointer + x * 8, pointer + 4 + x * 8))[0],
+                                   unpack(this.endian_mark + "L",
+                                this.tiftag.slice(pointer + 4 + x * 8, pointer + 8 + x * 8))[0]
+                                   ]);
+                    }
+                } else {
+                    data = [unpack(this.endian_mark + "L",
+                            this.tiftag.slice(pointer, pointer + 4))[0],
+                            unpack(this.endian_mark + "L",
+                            this.tiftag.slice(pointer + 4, pointer + 8))[0]
+                            ];
+                }
+            } else if (t == 7) { // UNDEFINED BYTES
+                if (length > 4) {
+                    pointer = unpack(this.endian_mark + "L", value)[0];
+                    data = this.tiftag.slice(pointer, pointer + length);
+                } else {
+                    data = value.slice(0, length);
+                }
+            } else if (t == 10) { // SRATIONAL
+                pointer = unpack(this.endian_mark + "L", value)[0];
+                if (length > 1) {
+                    data = [];
+                    for (var x = 0; x < length; x++) {
+                        data.push([unpack(this.endian_mark + "l",
+                                this.tiftag.slice(pointer + x * 8, pointer + 4 + x * 8))[0],
+                                   unpack(this.endian_mark + "l",
+                                this.tiftag.slice(pointer + 4 + x * 8, pointer + 8 + x * 8))[0]
+                                  ]);
+                    }
+                } else {
+                    data = [unpack(this.endian_mark + "l",
+                            this.tiftag.slice(pointer, pointer + 4))[0],
+                            unpack(this.endian_mark + "l",
+                            this.tiftag.slice(pointer + 4, pointer + 8))[0]
+                           ];
+                }
+            } else {
+                throw ("Exif might be wrong. Got incorrect value " +
+                    "type to decode. type:" + t);
+            }
+
+            if ((data instanceof Array) && (data.length == 1)) {
+                return data[0];
+            } else {
+                return data;
+            }
+        },
+    };
+
+
+    if (typeof window !== "undefined" && typeof window.btoa === "function") {
+        var btoa = window.btoa;
+    }
+    if (typeof btoa === "undefined") {
+        var btoa = function (input) {        var output = "";
+            var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
+            var i = 0;
+            var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
+
+            while (i < input.length) {
+
+                chr1 = input.charCodeAt(i++);
+                chr2 = input.charCodeAt(i++);
+                chr3 = input.charCodeAt(i++);
+
+                enc1 = chr1 >> 2;
+                enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
+                enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
+                enc4 = chr3 & 63;
+
+                if (isNaN(chr2)) {
+                    enc3 = enc4 = 64;
+                } else if (isNaN(chr3)) {
+                    enc4 = 64;
+                }
+
+                output = output +
+                keyStr.charAt(enc1) + keyStr.charAt(enc2) +
+                keyStr.charAt(enc3) + keyStr.charAt(enc4);
+
+            }
+
+            return output;
+        };
+    }
+    
+    
+    if (typeof window !== "undefined" && typeof window.atob === "function") {
+        var atob = window.atob;
+    }
+    if (typeof atob === "undefined") {
+        var atob = function (input) {
+            var output = "";
+            var chr1, chr2, chr3;
+            var enc1, enc2, enc3, enc4;
+            var i = 0;
+            var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
+
+            input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
+
+            while (i < input.length) {
+
+                enc1 = keyStr.indexOf(input.charAt(i++));
+                enc2 = keyStr.indexOf(input.charAt(i++));
+                enc3 = keyStr.indexOf(input.charAt(i++));
+                enc4 = keyStr.indexOf(input.charAt(i++));
+
+                chr1 = (enc1 << 2) | (enc2 >> 4);
+                chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
+                chr3 = ((enc3 & 3) << 6) | enc4;
+
+                output = output + String.fromCharCode(chr1);
+
+                if (enc3 != 64) {
+                    output = output + String.fromCharCode(chr2);
+                }
+                if (enc4 != 64) {
+                    output = output + String.fromCharCode(chr3);
+                }
+
+            }
+
+            return output;
+        };
+    }
+
+
+    function getImageSize(imageArray) {
+        var segments = slice2Segments(imageArray);
+        var seg,
+            width,
+            height,
+            SOF = [192, 193, 194, 195, 197, 198, 199, 201, 202, 203, 205, 206, 207];
+
+        for (var x = 0; x < segments.length; x++) {
+            seg = segments[x];
+            if (SOF.indexOf(seg[1]) >= 0) {
+                height = seg[5] * 256 + seg[6];
+                width = seg[7] * 256 + seg[8];
+                break;
+            }
+        }
+        return [width, height];
+    }
+
+
+    function pack(mark, array) {
+        if (!(array instanceof Array)) {
+            throw ("'pack' error. Got invalid type argument.");
+        }
+        if ((mark.length - 1) != array.length) {
+            throw ("'pack' error. " + (mark.length - 1) + " marks, " + array.length + " elements.");
+        }
+
+        var littleEndian;
+        if (mark[0] == "<") {
+            littleEndian = true;
+        } else if (mark[0] == ">") {
+            littleEndian = false;
+        } else {
+            throw ("");
+        }
+        var packed = "";
+        var p = 1;
+        var val = null;
+        var c = null;
+        var valStr = null;
+
+        while (c = mark[p]) {
+            if (c.toLowerCase() == "b") {
+                val = array[p - 1];
+                if ((c == "b") && (val < 0)) {
+                    val += 0x100;
+                }
+                if ((val > 0xff) || (val < 0)) {
+                    throw ("'pack' error.");
+                } else {
+                    valStr = String.fromCharCode(val);
+                }
+            } else if (c == "H") {
+                val = array[p - 1];
+                if ((val > 0xffff) || (val < 0)) {
+                    throw ("'pack' error.");
+                } else {
+                    valStr = String.fromCharCode(Math.floor((val % 0x10000) / 0x100)) +
+                        String.fromCharCode(val % 0x100);
+                    if (littleEndian) {
+                        valStr = valStr.split("").reverse().join("");
+                    }
+                }
+            } else if (c.toLowerCase() == "l") {
+                val = array[p - 1];
+                if ((c == "l") && (val < 0)) {
+                    val += 0x100000000;
+                }
+                if ((val > 0xffffffff) || (val < 0)) {
+                    throw ("'pack' error.");
+                } else {
+                    valStr = String.fromCharCode(Math.floor(val / 0x1000000)) +
+                        String.fromCharCode(Math.floor((val % 0x1000000) / 0x10000)) +
+                        String.fromCharCode(Math.floor((val % 0x10000) / 0x100)) +
+                        String.fromCharCode(val % 0x100);
+                    if (littleEndian) {
+                        valStr = valStr.split("").reverse().join("");
+                    }
+                }
+            } else {
+                throw ("'pack' error.");
+            }
+
+            packed += valStr;
+            p += 1;
+        }
+
+        return packed;
+    }
+
+    function unpack(mark, str) {
+        if (typeof (str) != "string") {
+            throw ("'unpack' error. Got invalid type argument.");
+        }
+        var l = 0;
+        for (var markPointer = 1; markPointer < mark.length; markPointer++) {
+            if (mark[markPointer].toLowerCase() == "b") {
+                l += 1;
+            } else if (mark[markPointer].toLowerCase() == "h") {
+                l += 2;
+            } else if (mark[markPointer].toLowerCase() == "l") {
+                l += 4;
+            } else {
+                throw ("'unpack' error. Got invalid mark.");
+            }
+        }
+
+        if (l != str.length) {
+            throw ("'unpack' error. Mismatch between symbol and string length. " + l + ":" + str.length);
+        }
+
+        var littleEndian;
+        if (mark[0] == "<") {
+            littleEndian = true;
+        } else if (mark[0] == ">") {
+            littleEndian = false;
+        } else {
+            throw ("'unpack' error.");
+        }
+        var unpacked = [];
+        var strPointer = 0;
+        var p = 1;
+        var val = null;
+        var c = null;
+        var length = null;
+        var sliced = "";
+
+        while (c = mark[p]) {
+            if (c.toLowerCase() == "b") {
+                length = 1;
+                sliced = str.slice(strPointer, strPointer + length);
+                val = sliced.charCodeAt(0);
+                if ((c == "b") && (val >= 0x80)) {
+                    val -= 0x100;
+                }
+            } else if (c == "H") {
+                length = 2;
+                sliced = str.slice(strPointer, strPointer + length);
+                if (littleEndian) {
+                    sliced = sliced.split("").reverse().join("");
+                }
+                val = sliced.charCodeAt(0) * 0x100 +
+                    sliced.charCodeAt(1);
+            } else if (c.toLowerCase() == "l") {
+                length = 4;
+                sliced = str.slice(strPointer, strPointer + length);
+                if (littleEndian) {
+                    sliced = sliced.split("").reverse().join("");
+                }
+                val = sliced.charCodeAt(0) * 0x1000000 +
+                    sliced.charCodeAt(1) * 0x10000 +
+                    sliced.charCodeAt(2) * 0x100 +
+                    sliced.charCodeAt(3);
+                if ((c == "l") && (val >= 0x80000000)) {
+                    val -= 0x100000000;
+                }
+            } else {
+                throw ("'unpack' error. " + c);
+            }
+
+            unpacked.push(val);
+            strPointer += length;
+            p += 1;
+        }
+
+        return unpacked;
+    }
+
+    function nStr(ch, num) {
+        var str = "";
+        for (var i = 0; i < num; i++) {
+            str += ch;
+        }
+        return str;
+    }
+
+    function splitIntoSegments(data) {
+        if (data.slice(0, 2) != "\xff\xd8") {
+            throw ("Given data isn't JPEG.");
+        }
+
+        var head = 2;
+        var segments = ["\xff\xd8"];
+        while (true) {
+            if (data.slice(head, head + 2) == "\xff\xda") {
+                segments.push(data.slice(head));
+                break;
+            } else {
+                var length = unpack(">H", data.slice(head + 2, head + 4))[0];
+                var endPoint = head + length + 2;
+                segments.push(data.slice(head, endPoint));
+                head = endPoint;
+            }
+
+            if (head >= data.length) {
+                throw ("Wrong JPEG data.");
+            }
+        }
+        return segments;
+    }
+
+
+    function getExifSeg(segments) {
+        var seg;
+        for (var i = 0; i < segments.length; i++) {
+            seg = segments[i];
+            if (seg.slice(0, 2) == "\xff\xe1" &&
+                   seg.slice(4, 10) == "Exif\x00\x00") {
+                return seg;
+            }
+        }
+        return null;
+    }
+
+
+    function mergeSegments(segments, exif) {
+        
+        if (segments[1].slice(0, 2) == "\xff\xe0" &&
+            (segments[2].slice(0, 2) == "\xff\xe1" &&
+             segments[2].slice(4, 10) == "Exif\x00\x00")) {
+            if (exif) {
+                segments[2] = exif;
+                segments = ["\xff\xd8"].concat(segments.slice(2));
+            } else if (exif == null) {
+                segments = segments.slice(0, 2).concat(segments.slice(3));
+            } else {
+                segments = segments.slice(0).concat(segments.slice(2));
+            }
+        } else if (segments[1].slice(0, 2) == "\xff\xe0") {
+            if (exif) {
+                segments[1] = exif;
+            }
+        } else if (segments[1].slice(0, 2) == "\xff\xe1" &&
+                   segments[1].slice(4, 10) == "Exif\x00\x00") {
+            if (exif) {
+                segments[1] = exif;
+            } else if (exif == null) {
+                segments = segments.slice(0).concat(segments.slice(2));
+            }
+        } else {
+            if (exif) {
+                segments = [segments[0], exif].concat(segments.slice(1));
+            }
+        }
+        
+        return segments.join("");
+    }
+
+
+    function toHex(str) {
+        var hexStr = "";
+        for (var i = 0; i < str.length; i++) {
+            var h = str.charCodeAt(i);
+            var hex = ((h < 10) ? "0" : "") + h.toString(16);
+            hexStr += hex + " ";
+        }
+        return hexStr;
+    }
+
+
+    var TYPES = {
+        "Byte": 1,
+        "Ascii": 2,
+        "Short": 3,
+        "Long": 4,
+        "Rational": 5,
+        "Undefined": 7,
+        "SLong": 9,
+        "SRational": 10
+    };
+
+
+    var TAGS = {
+        'Image': {
+            11: {
+                'name': 'ProcessingSoftware',
+                'type': 'Ascii'
+            },
+            254: {
+                'name': 'NewSubfileType',
+                'type': 'Long'
+            },
+            255: {
+                'name': 'SubfileType',
+                'type': 'Short'
+            },
+            256: {
+                'name': 'ImageWidth',
+                'type': 'Long'
+            },
+            257: {
+                'name': 'ImageLength',
+                'type': 'Long'
+            },
+            258: {
+                'name': 'BitsPerSample',
+                'type': 'Short'
+            },
+            259: {
+                'name': 'Compression',
+                'type': 'Short'
+            },
+            262: {
+                'name': 'PhotometricInterpretation',
+                'type': 'Short'
+            },
+            263: {
+                'name': 'Threshholding',
+                'type': 'Short'
+            },
+            264: {
+                'name': 'CellWidth',
+                'type': 'Short'
+            },
+            265: {
+                'name': 'CellLength',
+                'type': 'Short'
+            },
+            266: {
+                'name': 'FillOrder',
+                'type': 'Short'
+            },
+            269: {
+                'name': 'DocumentName',
+                'type': 'Ascii'
+            },
+            270: {
+                'name': 'ImageDescription',
+                'type': 'Ascii'
+            },
+            271: {
+                'name': 'Make',
+                'type': 'Ascii'
+            },
+            272: {
+                'name': 'Model',
+                'type': 'Ascii'
+            },
+            273: {
+                'name': 'StripOffsets',
+                'type': 'Long'
+            },
+            274: {
+                'name': 'Orientation',
+                'type': 'Short'
+            },
+            277: {
+                'name': 'SamplesPerPixel',
+                'type': 'Short'
+            },
+            278: {
+                'name': 'RowsPerStrip',
+                'type': 'Long'
+            },
+            279: {
+                'name': 'StripByteCounts',
+                'type': 'Long'
+            },
+            282: {
+                'name': 'XResolution',
+                'type': 'Rational'
+            },
+            283: {
+                'name': 'YResolution',
+                'type': 'Rational'
+            },
+            284: {
+                'name': 'PlanarConfiguration',
+                'type': 'Short'
+            },
+            290: {
+                'name': 'GrayResponseUnit',
+                'type': 'Short'
+            },
+            291: {
+                'name': 'GrayResponseCurve',
+                'type': 'Short'
+            },
+            292: {
+                'name': 'T4Options',
+                'type': 'Long'
+            },
+            293: {
+                'name': 'T6Options',
+                'type': 'Long'
+            },
+            296: {
+                'name': 'ResolutionUnit',
+                'type': 'Short'
+            },
+            301: {
+                'name': 'TransferFunction',
+                'type': 'Short'
+            },
+            305: {
+                'name': 'Software',
+                'type': 'Ascii'
+            },
+            306: {
+                'name': 'DateTime',
+                'type': 'Ascii'
+            },
+            315: {
+                'name': 'Artist',
+                'type': 'Ascii'
+            },
+            316: {
+                'name': 'HostComputer',
+                'type': 'Ascii'
+            },
+            317: {
+                'name': 'Predictor',
+                'type': 'Short'
+            },
+            318: {
+                'name': 'WhitePoint',
+                'type': 'Rational'
+            },
+            319: {
+                'name': 'PrimaryChromaticities',
+                'type': 'Rational'
+            },
+            320: {
+                'name': 'ColorMap',
+                'type': 'Short'
+            },
+            321: {
+                'name': 'HalftoneHints',
+                'type': 'Short'
+            },
+            322: {
+                'name': 'TileWidth',
+                'type': 'Short'
+            },
+            323: {
+                'name': 'TileLength',
+                'type': 'Short'
+            },
+            324: {
+                'name': 'TileOffsets',
+                'type': 'Short'
+            },
+            325: {
+                'name': 'TileByteCounts',
+                'type': 'Short'
+            },
+            330: {
+                'name': 'SubIFDs',
+                'type': 'Long'
+            },
+            332: {
+                'name': 'InkSet',
+                'type': 'Short'
+            },
+            333: {
+                'name': 'InkNames',
+                'type': 'Ascii'
+            },
+            334: {
+                'name': 'NumberOfInks',
+                'type': 'Short'
+            },
+            336: {
+                'name': 'DotRange',
+                'type': 'Byte'
+            },
+            337: {
+                'name': 'TargetPrinter',
+                'type': 'Ascii'
+            },
+            338: {
+                'name': 'ExtraSamples',
+                'type': 'Short'
+            },
+            339: {
+                'name': 'SampleFormat',
+                'type': 'Short'
+            },
+            340: {
+                'name': 'SMinSampleValue',
+                'type': 'Short'
+            },
+            341: {
+                'name': 'SMaxSampleValue',
+                'type': 'Short'
+            },
+            342: {
+                'name': 'TransferRange',
+                'type': 'Short'
+            },
+            343: {
+                'name': 'ClipPath',
+                'type': 'Byte'
+            },
+            344: {
+                'name': 'XClipPathUnits',
+                'type': 'Long'
+            },
+            345: {
+                'name': 'YClipPathUnits',
+                'type': 'Long'
+            },
+            346: {
+                'name': 'Indexed',
+                'type': 'Short'
+            },
+            347: {
+                'name': 'JPEGTables',
+                'type': 'Undefined'
+            },
+            351: {
+                'name': 'OPIProxy',
+                'type': 'Short'
+            },
+            512: {
+                'name': 'JPEGProc',
+                'type': 'Long'
+            },
+            513: {
+                'name': 'JPEGInterchangeFormat',
+                'type': 'Long'
+            },
+            514: {
+                'name': 'JPEGInterchangeFormatLength',
+                'type': 'Long'
+            },
+            515: {
+                'name': 'JPEGRestartInterval',
+                'type': 'Short'
+            },
+            517: {
+                'name': 'JPEGLosslessPredictors',
+                'type': 'Short'
+            },
+            518: {
+                'name': 'JPEGPointTransforms',
+                'type': 'Short'
+            },
+            519: {
+                'name': 'JPEGQTables',
+                'type': 'Long'
+            },
+            520: {
+                'name': 'JPEGDCTables',
+                'type': 'Long'
+            },
+            521: {
+                'name': 'JPEGACTables',
+                'type': 'Long'
+            },
+            529: {
+                'name': 'YCbCrCoefficients',
+                'type': 'Rational'
+            },
+            530: {
+                'name': 'YCbCrSubSampling',
+                'type': 'Short'
+            },
+            531: {
+                'name': 'YCbCrPositioning',
+                'type': 'Short'
+            },
+            532: {
+                'name': 'ReferenceBlackWhite',
+                'type': 'Rational'
+            },
+            700: {
+                'name': 'XMLPacket',
+                'type': 'Byte'
+            },
+            18246: {
+                'name': 'Rating',
+                'type': 'Short'
+            },
+            18249: {
+                'name': 'RatingPercent',
+                'type': 'Short'
+            },
+            32781: {
+                'name': 'ImageID',
+                'type': 'Ascii'
+            },
+            33421: {
+                'name': 'CFARepeatPatternDim',
+                'type': 'Short'
+            },
+            33422: {
+                'name': 'CFAPattern',
+                'type': 'Byte'
+            },
+            33423: {
+                'name': 'BatteryLevel',
+                'type': 'Rational'
+            },
+            33432: {
+                'name': 'Copyright',
+                'type': 'Ascii'
+            },
+            33434: {
+                'name': 'ExposureTime',
+                'type': 'Rational'
+            },
+            34377: {
+                'name': 'ImageResources',
+                'type': 'Byte'
+            },
+            34665: {
+                'name': 'ExifTag',
+                'type': 'Long'
+            },
+            34675: {
+                'name': 'InterColorProfile',
+                'type': 'Undefined'
+            },
+            34853: {
+                'name': 'GPSTag',
+                'type': 'Long'
+            },
+            34857: {
+                'name': 'Interlace',
+                'type': 'Short'
+            },
+            34858: {
+                'name': 'TimeZoneOffset',
+                'type': 'Long'
+            },
+            34859: {
+                'name': 'SelfTimerMode',
+                'type': 'Short'
+            },
+            37387: {
+                'name': 'FlashEnergy',
+                'type': 'Rational'
+            },
+            37388: {
+                'name': 'SpatialFrequencyResponse',
+                'type': 'Undefined'
+            },
+            37389: {
+                'name': 'Noise',
+                'type': 'Undefined'
+            },
+            37390: {
+                'name': 'FocalPlaneXResolution',
+                'type': 'Rational'
+            },
+            37391: {
+                'name': 'FocalPlaneYResolution',
+                'type': 'Rational'
+            },
+            37392: {
+                'name': 'FocalPlaneResolutionUnit',
+                'type': 'Short'
+            },
+            37393: {
+                'name': 'ImageNumber',
+                'type': 'Long'
+            },
+            37394: {
+                'name': 'SecurityClassification',
+                'type': 'Ascii'
+            },
+            37395: {
+                'name': 'ImageHistory',
+                'type': 'Ascii'
+            },
+            37397: {
+                'name': 'ExposureIndex',
+                'type': 'Rational'
+            },
+            37398: {
+                'name': 'TIFFEPStandardID',
+                'type': 'Byte'
+            },
+            37399: {
+                'name': 'SensingMethod',
+                'type': 'Short'
+            },
+            40091: {
+                'name': 'XPTitle',
+                'type': 'Byte'
+            },
+            40092: {
+                'name': 'XPComment',
+                'type': 'Byte'
+            },
+            40093: {
+                'name': 'XPAuthor',
+                'type': 'Byte'
+            },
+            40094: {
+                'name': 'XPKeywords',
+                'type': 'Byte'
+            },
+            40095: {
+                'name': 'XPSubject',
+                'type': 'Byte'
+            },
+            50341: {
+                'name': 'PrintImageMatching',
+                'type': 'Undefined'
+            },
+            50706: {
+                'name': 'DNGVersion',
+                'type': 'Byte'
+            },
+            50707: {
+                'name': 'DNGBackwardVersion',
+                'type': 'Byte'
+            },
+            50708: {
+                'name': 'UniqueCameraModel',
+                'type': 'Ascii'
+            },
+            50709: {
+                'name': 'LocalizedCameraModel',
+                'type': 'Byte'
+            },
+            50710: {
+                'name': 'CFAPlaneColor',
+                'type': 'Byte'
+            },
+            50711: {
+                'name': 'CFALayout',
+                'type': 'Short'
+            },
+            50712: {
+                'name': 'LinearizationTable',
+                'type': 'Short'
+            },
+            50713: {
+                'name': 'BlackLevelRepeatDim',
+                'type': 'Short'
+            },
+            50714: {
+                'name': 'BlackLevel',
+                'type': 'Rational'
+            },
+            50715: {
+                'name': 'BlackLevelDeltaH',
+                'type': 'SRational'
+            },
+            50716: {
+                'name': 'BlackLevelDeltaV',
+                'type': 'SRational'
+            },
+            50717: {
+                'name': 'WhiteLevel',
+                'type': 'Short'
+            },
+            50718: {
+                'name': 'DefaultScale',
+                'type': 'Rational'
+            },
+            50719: {
+                'name': 'DefaultCropOrigin',
+                'type': 'Short'
+            },
+            50720: {
+                'name': 'DefaultCropSize',
+                'type': 'Short'
+            },
+            50721: {
+                'name': 'ColorMatrix1',
+                'type': 'SRational'
+            },
+            50722: {
+                'name': 'ColorMatrix2',
+                'type': 'SRational'
+            },
+            50723: {
+                'name': 'CameraCalibration1',
+                'type': 'SRational'
+            },
+            50724: {
+                'name': 'CameraCalibration2',
+                'type': 'SRational'
+            },
+            50725: {
+                'name': 'ReductionMatrix1',
+                'type': 'SRational'
+            },
+            50726: {
+                'name': 'ReductionMatrix2',
+                'type': 'SRational'
+            },
+            50727: {
+                'name': 'AnalogBalance',
+                'type': 'Rational'
+            },
+            50728: {
+                'name': 'AsShotNeutral',
+                'type': 'Short'
+            },
+            50729: {
+                'name': 'AsShotWhiteXY',
+                'type': 'Rational'
+            },
+            50730: {
+                'name': 'BaselineExposure',
+                'type': 'SRational'
+            },
+            50731: {
+                'name': 'BaselineNoise',
+                'type': 'Rational'
+            },
+            50732: {
+                'name': 'BaselineSharpness',
+                'type': 'Rational'
+            },
+            50733: {
+                'name': 'BayerGreenSplit',
+                'type': 'Long'
+            },
+            50734: {
+                'name': 'LinearResponseLimit',
+                'type': 'Rational'
+            },
+            50735: {
+                'name': 'CameraSerialNumber',
+                'type': 'Ascii'
+            },
+            50736: {
+                'name': 'LensInfo',
+                'type': 'Rational'
+            },
+            50737: {
+                'name': 'ChromaBlurRadius',
+                'type': 'Rational'
+            },
+            50738: {
+                'name': 'AntiAliasStrength',
+                'type': 'Rational'
+            },
+            50739: {
+                'name': 'ShadowScale',
+                'type': 'SRational'
+            },
+            50740: {
+                'name': 'DNGPrivateData',
+                'type': 'Byte'
+            },
+            50741: {
+                'name': 'MakerNoteSafety',
+                'type': 'Short'
+            },
+            50778: {
+                'name': 'CalibrationIlluminant1',
+                'type': 'Short'
+            },
+            50779: {
+                'name': 'CalibrationIlluminant2',
+                'type': 'Short'
+            },
+            50780: {
+                'name': 'BestQualityScale',
+                'type': 'Rational'
+            },
+            50781: {
+                'name': 'RawDataUniqueID',
+                'type': 'Byte'
+            },
+            50827: {
+                'name': 'OriginalRawFileName',
+                'type': 'Byte'
+            },
+            50828: {
+                'name': 'OriginalRawFileData',
+                'type': 'Undefined'
+            },
+            50829: {
+                'name': 'ActiveArea',
+                'type': 'Short'
+            },
+            50830: {
+                'name': 'MaskedAreas',
+                'type': 'Short'
+            },
+            50831: {
+                'name': 'AsShotICCProfile',
+                'type': 'Undefined'
+            },
+            50832: {
+                'name': 'AsShotPreProfileMatrix',
+                'type': 'SRational'
+            },
+            50833: {
+                'name': 'CurrentICCProfile',
+                'type': 'Undefined'
+            },
+            50834: {
+                'name': 'CurrentPreProfileMatrix',
+                'type': 'SRational'
+            },
+            50879: {
+                'name': 'ColorimetricReference',
+                'type': 'Short'
+            },
+            50931: {
+                'name': 'CameraCalibrationSignature',
+                'type': 'Byte'
+            },
+            50932: {
+                'name': 'ProfileCalibrationSignature',
+                'type': 'Byte'
+            },
+            50934: {
+                'name': 'AsShotProfileName',
+                'type': 'Byte'
+            },
+            50935: {
+                'name': 'NoiseReductionApplied',
+                'type': 'Rational'
+            },
+            50936: {
+                'name': 'ProfileName',
+                'type': 'Byte'
+            },
+            50937: {
+                'name': 'ProfileHueSatMapDims',
+                'type': 'Long'
+            },
+            50938: {
+                'name': 'ProfileHueSatMapData1',
+                'type': 'Float'
+            },
+            50939: {
+                'name': 'ProfileHueSatMapData2',
+                'type': 'Float'
+            },
+            50940: {
+                'name': 'ProfileToneCurve',
+                'type': 'Float'
+            },
+            50941: {
+                'name': 'ProfileEmbedPolicy',
+                'type': 'Long'
+            },
+            50942: {
+                'name': 'ProfileCopyright',
+                'type': 'Byte'
+            },
+            50964: {
+                'name': 'ForwardMatrix1',
+                'type': 'SRational'
+            },
+            50965: {
+                'name': 'ForwardMatrix2',
+                'type': 'SRational'
+            },
+            50966: {
+                'name': 'PreviewApplicationName',
+                'type': 'Byte'
+            },
+            50967: {
+                'name': 'PreviewApplicationVersion',
+                'type': 'Byte'
+            },
+            50968: {
+                'name': 'PreviewSettingsName',
+                'type': 'Byte'
+            },
+            50969: {
+                'name': 'PreviewSettingsDigest',
+                'type': 'Byte'
+            },
+            50970: {
+                'name': 'PreviewColorSpace',
+                'type': 'Long'
+            },
+            50971: {
+                'name': 'PreviewDateTime',
+                'type': 'Ascii'
+            },
+            50972: {
+                'name': 'RawImageDigest',
+                'type': 'Undefined'
+            },
+            50973: {
+                'name': 'OriginalRawFileDigest',
+                'type': 'Undefined'
+            },
+            50974: {
+                'name': 'SubTileBlockSize',
+                'type': 'Long'
+            },
+            50975: {
+                'name': 'RowInterleaveFactor',
+                'type': 'Long'
+            },
+            50981: {
+                'name': 'ProfileLookTableDims',
+                'type': 'Long'
+            },
+            50982: {
+                'name': 'ProfileLookTableData',
+                'type': 'Float'
+            },
+            51008: {
+                'name': 'OpcodeList1',
+                'type': 'Undefined'
+            },
+            51009: {
+                'name': 'OpcodeList2',
+                'type': 'Undefined'
+            },
+            51022: {
+                'name': 'OpcodeList3',
+                'type': 'Undefined'
+            }
+        },
+        'Exif': {
+            33434: {
+                'name': 'ExposureTime',
+                'type': 'Rational'
+            },
+            33437: {
+                'name': 'FNumber',
+                'type': 'Rational'
+            },
+            34850: {
+                'name': 'ExposureProgram',
+                'type': 'Short'
+            },
+            34852: {
+                'name': 'SpectralSensitivity',
+                'type': 'Ascii'
+            },
+            34855: {
+                'name': 'ISOSpeedRatings',
+                'type': 'Short'
+            },
+            34856: {
+                'name': 'OECF',
+                'type': 'Undefined'
+            },
+            34864: {
+                'name': 'SensitivityType',
+                'type': 'Short'
+            },
+            34865: {
+                'name': 'StandardOutputSensitivity',
+                'type': 'Long'
+            },
+            34866: {
+                'name': 'RecommendedExposureIndex',
+                'type': 'Long'
+            },
+            34867: {
+                'name': 'ISOSpeed',
+                'type': 'Long'
+            },
+            34868: {
+                'name': 'ISOSpeedLatitudeyyy',
+                'type': 'Long'
+            },
+            34869: {
+                'name': 'ISOSpeedLatitudezzz',
+                'type': 'Long'
+            },
+            36864: {
+                'name': 'ExifVersion',
+                'type': 'Undefined'
+            },
+            36867: {
+                'name': 'DateTimeOriginal',
+                'type': 'Ascii'
+            },
+            36868: {
+                'name': 'DateTimeDigitized',
+                'type': 'Ascii'
+            },
+            37121: {
+                'name': 'ComponentsConfiguration',
+                'type': 'Undefined'
+            },
+            37122: {
+                'name': 'CompressedBitsPerPixel',
+                'type': 'Rational'
+            },
+            37377: {
+                'name': 'ShutterSpeedValue',
+                'type': 'SRational'
+            },
+            37378: {
+                'name': 'ApertureValue',
+                'type': 'Rational'
+            },
+            37379: {
+                'name': 'BrightnessValue',
+                'type': 'SRational'
+            },
+            37380: {
+                'name': 'ExposureBiasValue',
+                'type': 'SRational'
+            },
+            37381: {
+                'name': 'MaxApertureValue',
+                'type': 'Rational'
+            },
+            37382: {
+                'name': 'SubjectDistance',
+                'type': 'Rational'
+            },
+            37383: {
+                'name': 'MeteringMode',
+                'type': 'Short'
+            },
+            37384: {
+                'name': 'LightSource',
+                'type': 'Short'
+            },
+            37385: {
+                'name': 'Flash',
+                'type': 'Short'
+            },
+            37386: {
+                'name': 'FocalLength',
+                'type': 'Rational'
+            },
+            37396: {
+                'name': 'SubjectArea',
+                'type': 'Short'
+            },
+            37500: {
+                'name': 'MakerNote',
+                'type': 'Undefined'
+            },
+            37510: {
+                'name': 'UserComment',
+                'type': 'Ascii'
+            },
+            37520: {
+                'name': 'SubSecTime',
+                'type': 'Ascii'
+            },
+            37521: {
+                'name': 'SubSecTimeOriginal',
+                'type': 'Ascii'
+            },
+            37522: {
+                'name': 'SubSecTimeDigitized',
+                'type': 'Ascii'
+            },
+            40960: {
+                'name': 'FlashpixVersion',
+                'type': 'Undefined'
+            },
+            40961: {
+                'name': 'ColorSpace',
+                'type': 'Short'
+            },
+            40962: {
+                'name': 'PixelXDimension',
+                'type': 'Long'
+            },
+            40963: {
+                'name': 'PixelYDimension',
+                'type': 'Long'
+            },
+            40964: {
+                'name': 'RelatedSoundFile',
+                'type': 'Ascii'
+            },
+            40965: {
+                'name': 'InteroperabilityTag',
+                'type': 'Long'
+            },
+            41483: {
+                'name': 'FlashEnergy',
+                'type': 'Rational'
+            },
+            41484: {
+                'name': 'SpatialFrequencyResponse',
+                'type': 'Undefined'
+            },
+            41486: {
+                'name': 'FocalPlaneXResolution',
+                'type': 'Rational'
+            },
+            41487: {
+                'name': 'FocalPlaneYResolution',
+                'type': 'Rational'
+            },
+            41488: {
+                'name': 'FocalPlaneResolutionUnit',
+                'type': 'Short'
+            },
+            41492: {
+                'name': 'SubjectLocation',
+                'type': 'Short'
+            },
+            41493: {
+                'name': 'ExposureIndex',
+                'type': 'Rational'
+            },
+            41495: {
+                'name': 'SensingMethod',
+                'type': 'Short'
+            },
+            41728: {
+                'name': 'FileSource',
+                'type': 'Undefined'
+            },
+            41729: {
+                'name': 'SceneType',
+                'type': 'Undefined'
+            },
+            41730: {
+                'name': 'CFAPattern',
+                'type': 'Undefined'
+            },
+            41985: {
+                'name': 'CustomRendered',
+                'type': 'Short'
+            },
+            41986: {
+                'name': 'ExposureMode',
+                'type': 'Short'
+            },
+            41987: {
+                'name': 'WhiteBalance',
+                'type': 'Short'
+            },
+            41988: {
+                'name': 'DigitalZoomRatio',
+                'type': 'Rational'
+            },
+            41989: {
+                'name': 'FocalLengthIn35mmFilm',
+                'type': 'Short'
+            },
+            41990: {
+                'name': 'SceneCaptureType',
+                'type': 'Short'
+            },
+            41991: {
+                'name': 'GainControl',
+                'type': 'Short'
+            },
+            41992: {
+                'name': 'Contrast',
+                'type': 'Short'
+            },
+            41993: {
+                'name': 'Saturation',
+                'type': 'Short'
+            },
+            41994: {
+                'name': 'Sharpness',
+                'type': 'Short'
+            },
+            41995: {
+                'name': 'DeviceSettingDescription',
+                'type': 'Undefined'
+            },
+            41996: {
+                'name': 'SubjectDistanceRange',
+                'type': 'Short'
+            },
+            42016: {
+                'name': 'ImageUniqueID',
+                'type': 'Ascii'
+            },
+            42032: {
+                'name': 'CameraOwnerName',
+                'type': 'Ascii'
+            },
+            42033: {
+                'name': 'BodySerialNumber',
+                'type': 'Ascii'
+            },
+            42034: {
+                'name': 'LensSpecification',
+                'type': 'Rational'
+            },
+            42035: {
+                'name': 'LensMake',
+                'type': 'Ascii'
+            },
+            42036: {
+                'name': 'LensModel',
+                'type': 'Ascii'
+            },
+            42037: {
+                'name': 'LensSerialNumber',
+                'type': 'Ascii'
+            },
+            42240: {
+                'name': 'Gamma',
+                'type': 'Rational'
+            }
+        },
+        'GPS': {
+            0: {
+                'name': 'GPSVersionID',
+                'type': 'Byte'
+            },
+            1: {
+                'name': 'GPSLatitudeRef',
+                'type': 'Ascii'
+            },
+            2: {
+                'name': 'GPSLatitude',
+                'type': 'Rational'
+            },
+            3: {
+                'name': 'GPSLongitudeRef',
+                'type': 'Ascii'
+            },
+            4: {
+                'name': 'GPSLongitude',
+                'type': 'Rational'
+            },
+            5: {
+                'name': 'GPSAltitudeRef',
+                'type': 'Byte'
+            },
+            6: {
+                'name': 'GPSAltitude',
+                'type': 'Rational'
+            },
+            7: {
+                'name': 'GPSTimeStamp',
+                'type': 'Rational'
+            },
+            8: {
+                'name': 'GPSSatellites',
+                'type': 'Ascii'
+            },
+            9: {
+                'name': 'GPSStatus',
+                'type': 'Ascii'
+            },
+            10: {
+                'name': 'GPSMeasureMode',
+                'type': 'Ascii'
+            },
+            11: {
+                'name': 'GPSDOP',
+                'type': 'Rational'
+            },
+            12: {
+                'name': 'GPSSpeedRef',
+                'type': 'Ascii'
+            },
+            13: {
+                'name': 'GPSSpeed',
+                'type': 'Rational'
+            },
+            14: {
+                'name': 'GPSTrackRef',
+                'type': 'Ascii'
+            },
+            15: {
+                'name': 'GPSTrack',
+                'type': 'Rational'
+            },
+            16: {
+                'name': 'GPSImgDirectionRef',
+                'type': 'Ascii'
+            },
+            17: {
+                'name': 'GPSImgDirection',
+                'type': 'Rational'
+            },
+            18: {
+                'name': 'GPSMapDatum',
+                'type': 'Ascii'
+            },
+            19: {
+                'name': 'GPSDestLatitudeRef',
+                'type': 'Ascii'
+            },
+            20: {
+                'name': 'GPSDestLatitude',
+                'type': 'Rational'
+            },
+            21: {
+                'name': 'GPSDestLongitudeRef',
+                'type': 'Ascii'
+            },
+            22: {
+                'name': 'GPSDestLongitude',
+                'type': 'Rational'
+            },
+            23: {
+                'name': 'GPSDestBearingRef',
+                'type': 'Ascii'
+            },
+            24: {
+                'name': 'GPSDestBearing',
+                'type': 'Rational'
+            },
+            25: {
+                'name': 'GPSDestDistanceRef',
+                'type': 'Ascii'
+            },
+            26: {
+                'name': 'GPSDestDistance',
+                'type': 'Rational'
+            },
+            27: {
+                'name': 'GPSProcessingMethod',
+                'type': 'Undefined'
+            },
+            28: {
+                'name': 'GPSAreaInformation',
+                'type': 'Undefined'
+            },
+            29: {
+                'name': 'GPSDateStamp',
+                'type': 'Ascii'
+            },
+            30: {
+                'name': 'GPSDifferential',
+                'type': 'Short'
+            },
+            31: {
+                'name': 'GPSHPositioningError',
+                'type': 'Rational'
+            }
+        },
+        'Interop': {
+            1: {
+                'name': 'InteroperabilityIndex',
+                'type': 'Ascii'
+            }
+        },
+    };
+    TAGS["0th"] = TAGS["Image"];
+    TAGS["1st"] = TAGS["Image"];
+    that.TAGS = TAGS;
+
+    
+    that.ImageIFD = {
+        ProcessingSoftware:11,
+        NewSubfileType:254,
+        SubfileType:255,
+        ImageWidth:256,
+        ImageLength:257,
+        BitsPerSample:258,
+        Compression:259,
+        PhotometricInterpretation:262,
+        Threshholding:263,
+        CellWidth:264,
+        CellLength:265,
+        FillOrder:266,
+        DocumentName:269,
+        ImageDescription:270,
+        Make:271,
+        Model:272,
+        StripOffsets:273,
+        Orientation:274,
+        SamplesPerPixel:277,
+        RowsPerStrip:278,
+        StripByteCounts:279,
+        XResolution:282,
+        YResolution:283,
+        PlanarConfiguration:284,
+        GrayResponseUnit:290,
+        GrayResponseCurve:291,
+        T4Options:292,
+        T6Options:293,
+        ResolutionUnit:296,
+        TransferFunction:301,
+        Software:305,
+        DateTime:306,
+        Artist:315,
+        HostComputer:316,
+        Predictor:317,
+        WhitePoint:318,
+        PrimaryChromaticities:319,
+        ColorMap:320,
+        HalftoneHints:321,
+        TileWidth:322,
+        TileLength:323,
+        TileOffsets:324,
+        TileByteCounts:325,
+        SubIFDs:330,
+        InkSet:332,
+        InkNames:333,
+        NumberOfInks:334,
+        DotRange:336,
+        TargetPrinter:337,
+        ExtraSamples:338,
+        SampleFormat:339,
+        SMinSampleValue:340,
+        SMaxSampleValue:341,
+        TransferRange:342,
+        ClipPath:343,
+        XClipPathUnits:344,
+        YClipPathUnits:345,
+        Indexed:346,
+        JPEGTables:347,
+        OPIProxy:351,
+        JPEGProc:512,
+        JPEGInterchangeFormat:513,
+        JPEGInterchangeFormatLength:514,
+        JPEGRestartInterval:515,
+        JPEGLosslessPredictors:517,
+        JPEGPointTransforms:518,
+        JPEGQTables:519,
+        JPEGDCTables:520,
+        JPEGACTables:521,
+        YCbCrCoefficients:529,
+        YCbCrSubSampling:530,
+        YCbCrPositioning:531,
+        ReferenceBlackWhite:532,
+        XMLPacket:700,
+        Rating:18246,
+        RatingPercent:18249,
+        ImageID:32781,
+        CFARepeatPatternDim:33421,
+        CFAPattern:33422,
+        BatteryLevel:33423,
+        Copyright:33432,
+        ExposureTime:33434,
+        ImageResources:34377,
+        ExifTag:34665,
+        InterColorProfile:34675,
+        GPSTag:34853,
+        Interlace:34857,
+        TimeZoneOffset:34858,
+        SelfTimerMode:34859,
+        FlashEnergy:37387,
+        SpatialFrequencyResponse:37388,
+        Noise:37389,
+        FocalPlaneXResolution:37390,
+        FocalPlaneYResolution:37391,
+        FocalPlaneResolutionUnit:37392,
+        ImageNumber:37393,
+        SecurityClassification:37394,
+        ImageHistory:37395,
+        ExposureIndex:37397,
+        TIFFEPStandardID:37398,
+        SensingMethod:37399,
+        XPTitle:40091,
+        XPComment:40092,
+        XPAuthor:40093,
+        XPKeywords:40094,
+        XPSubject:40095,
+        PrintImageMatching:50341,
+        DNGVersion:50706,
+        DNGBackwardVersion:50707,
+        UniqueCameraModel:50708,
+        LocalizedCameraModel:50709,
+        CFAPlaneColor:50710,
+        CFALayout:50711,
+        LinearizationTable:50712,
+        BlackLevelRepeatDim:50713,
+        BlackLevel:50714,
+        BlackLevelDeltaH:50715,
+        BlackLevelDeltaV:50716,
+        WhiteLevel:50717,
+        DefaultScale:50718,
+        DefaultCropOrigin:50719,
+        DefaultCropSize:50720,
+        ColorMatrix1:50721,
+        ColorMatrix2:50722,
+        CameraCalibration1:50723,
+        CameraCalibration2:50724,
+        ReductionMatrix1:50725,
+        ReductionMatrix2:50726,
+        AnalogBalance:50727,
+        AsShotNeutral:50728,
+        AsShotWhiteXY:50729,
+        BaselineExposure:50730,
+        BaselineNoise:50731,
+        BaselineSharpness:50732,
+        BayerGreenSplit:50733,
+        LinearResponseLimit:50734,
+        CameraSerialNumber:50735,
+        LensInfo:50736,
+        ChromaBlurRadius:50737,
+        AntiAliasStrength:50738,
+        ShadowScale:50739,
+        DNGPrivateData:50740,
+        MakerNoteSafety:50741,
+        CalibrationIlluminant1:50778,
+        CalibrationIlluminant2:50779,
+        BestQualityScale:50780,
+        RawDataUniqueID:50781,
+        OriginalRawFileName:50827,
+        OriginalRawFileData:50828,
+        ActiveArea:50829,
+        MaskedAreas:50830,
+        AsShotICCProfile:50831,
+        AsShotPreProfileMatrix:50832,
+        CurrentICCProfile:50833,
+        CurrentPreProfileMatrix:50834,
+        ColorimetricReference:50879,
+        CameraCalibrationSignature:50931,
+        ProfileCalibrationSignature:50932,
+        AsShotProfileName:50934,
+        NoiseReductionApplied:50935,
+        ProfileName:50936,
+        ProfileHueSatMapDims:50937,
+        ProfileHueSatMapData1:50938,
+        ProfileHueSatMapData2:50939,
+        ProfileToneCurve:50940,
+        ProfileEmbedPolicy:50941,
+        ProfileCopyright:50942,
+        ForwardMatrix1:50964,
+        ForwardMatrix2:50965,
+        PreviewApplicationName:50966,
+        PreviewApplicationVersion:50967,
+        PreviewSettingsName:50968,
+        PreviewSettingsDigest:50969,
+        PreviewColorSpace:50970,
+        PreviewDateTime:50971,
+        RawImageDigest:50972,
+        OriginalRawFileDigest:50973,
+        SubTileBlockSize:50974,
+        RowInterleaveFactor:50975,
+        ProfileLookTableDims:50981,
+        ProfileLookTableData:50982,
+        OpcodeList1:51008,
+        OpcodeList2:51009,
+        OpcodeList3:51022,
+        NoiseProfile:51041,
+    };
+
+    
+    that.ExifIFD = {
+        ExposureTime:33434,
+        FNumber:33437,
+        ExposureProgram:34850,
+        SpectralSensitivity:34852,
+        ISOSpeedRatings:34855,
+        OECF:34856,
+        SensitivityType:34864,
+        StandardOutputSensitivity:34865,
+        RecommendedExposureIndex:34866,
+        ISOSpeed:34867,
+        ISOSpeedLatitudeyyy:34868,
+        ISOSpeedLatitudezzz:34869,
+        ExifVersion:36864,
+        DateTimeOriginal:36867,
+        DateTimeDigitized:36868,
+        ComponentsConfiguration:37121,
+        CompressedBitsPerPixel:37122,
+        ShutterSpeedValue:37377,
+        ApertureValue:37378,
+        BrightnessValue:37379,
+        ExposureBiasValue:37380,
+        MaxApertureValue:37381,
+        SubjectDistance:37382,
+        MeteringMode:37383,
+        LightSource:37384,
+        Flash:37385,
+        FocalLength:37386,
+        SubjectArea:37396,
+        MakerNote:37500,
+        UserComment:37510,
+        SubSecTime:37520,
+        SubSecTimeOriginal:37521,
+        SubSecTimeDigitized:37522,
+        FlashpixVersion:40960,
+        ColorSpace:40961,
+        PixelXDimension:40962,
+        PixelYDimension:40963,
+        RelatedSoundFile:40964,
+        InteroperabilityTag:40965,
+        FlashEnergy:41483,
+        SpatialFrequencyResponse:41484,
+        FocalPlaneXResolution:41486,
+        FocalPlaneYResolution:41487,
+        FocalPlaneResolutionUnit:41488,
+        SubjectLocation:41492,
+        ExposureIndex:41493,
+        SensingMethod:41495,
+        FileSource:41728,
+        SceneType:41729,
+        CFAPattern:41730,
+        CustomRendered:41985,
+        ExposureMode:41986,
+        WhiteBalance:41987,
+        DigitalZoomRatio:41988,
+        FocalLengthIn35mmFilm:41989,
+        SceneCaptureType:41990,
+        GainControl:41991,
+        Contrast:41992,
+        Saturation:41993,
+        Sharpness:41994,
+        DeviceSettingDescription:41995,
+        SubjectDistanceRange:41996,
+        ImageUniqueID:42016,
+        CameraOwnerName:42032,
+        BodySerialNumber:42033,
+        LensSpecification:42034,
+        LensMake:42035,
+        LensModel:42036,
+        LensSerialNumber:42037,
+        Gamma:42240,
+    };
+
+
+    that.GPSIFD = {
+        GPSVersionID:0,
+        GPSLatitudeRef:1,
+        GPSLatitude:2,
+        GPSLongitudeRef:3,
+        GPSLongitude:4,
+        GPSAltitudeRef:5,
+        GPSAltitude:6,
+        GPSTimeStamp:7,
+        GPSSatellites:8,
+        GPSStatus:9,
+        GPSMeasureMode:10,
+        GPSDOP:11,
+        GPSSpeedRef:12,
+        GPSSpeed:13,
+        GPSTrackRef:14,
+        GPSTrack:15,
+        GPSImgDirectionRef:16,
+        GPSImgDirection:17,
+        GPSMapDatum:18,
+        GPSDestLatitudeRef:19,
+        GPSDestLatitude:20,
+        GPSDestLongitudeRef:21,
+        GPSDestLongitude:22,
+        GPSDestBearingRef:23,
+        GPSDestBearing:24,
+        GPSDestDistanceRef:25,
+        GPSDestDistance:26,
+        GPSProcessingMethod:27,
+        GPSAreaInformation:28,
+        GPSDateStamp:29,
+        GPSDifferential:30,
+        GPSHPositioningError:31,
+    };
+
+
+    that.InteropIFD = {
+        InteroperabilityIndex:1,
+    };
+
+    that.GPSHelper = {
+        degToDmsRational:function (degFloat) {
+            var minFloat = degFloat % 1 * 60;
+            var secFloat = minFloat % 1 * 60;
+            var deg = Math.floor(degFloat);
+            var min = Math.floor(minFloat);
+            var sec = Math.round(secFloat * 100);
+
+            return [[deg, 1], [min, 1], [sec, 100]];
+        }
+    };
+    
+    
+    if (typeof exports !== 'undefined') {
+        if (typeof module !== 'undefined' && module.exports) {
+            exports = module.exports = that;
+        }
+        exports.piexif = that;
+    } else {
+        window.piexif = that;
+    }
+
+})();

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 0 - 0
public/base/plugins/bootstrap-fileinput/js/plugins/piexif.min.js


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 19 - 0
public/base/plugins/bootstrap-fileinput/js/plugins/purify.js


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 0 - 0
public/base/plugins/bootstrap-fileinput/js/plugins/purify.min.js


+ 1590 - 0
public/base/plugins/bootstrap-fileinput/js/plugins/sortable.js

xqd
@@ -0,0 +1,1590 @@
+/**!
+ * KvSortable
+ * @author	RubaXa   <trash@rubaxa.org>
+ * @license MIT
+ *
+ * Changed kvsortable plugin naming to prevent conflict with JQuery UI Sortable
+ * @author Kartik Visweswaran
+ */
+
+(function kvsortableModule(factory) {
+	"use strict";
+
+	if (typeof define === "function" && define.amd) {
+		define(factory);
+	}
+	else if (typeof module != "undefined" && typeof module.exports != "undefined") {
+		module.exports = factory();
+	}
+	else {
+		/* jshint sub:true */
+		window["KvSortable"] = factory();
+	}
+})(function kvsortableFactory() {
+	"use strict";
+
+	if (typeof window === "undefined" || !window.document) {
+		return function kvsortableError() {
+			throw new Error("KvSortable.js requires a window with a document");
+		};
+	}
+
+	var dragEl,
+		parentEl,
+		ghostEl,
+		cloneEl,
+		rootEl,
+		nextEl,
+		lastDownEl,
+
+		scrollEl,
+		scrollParentEl,
+		scrollCustomFn,
+
+		lastEl,
+		lastCSS,
+		lastParentCSS,
+
+		oldIndex,
+		newIndex,
+
+		activeGroup,
+		putKvSortable,
+
+		autoScroll = {},
+
+		tapEvt,
+		touchEvt,
+
+		moved,
+
+		/** @const */
+		R_SPACE = /\s+/g,
+		R_FLOAT = /left|right|inline/,
+
+		expando = 'KvSortable' + (new Date).getTime(),
+
+		win = window,
+		document = win.document,
+		parseInt = win.parseInt,
+		setTimeout = win.setTimeout,
+
+		$ = win.jQuery || win.Zepto,
+		Polymer = win.Polymer,
+
+		captureMode = false,
+		passiveMode = false,
+
+		supportDraggable = ('draggable' in document.createElement('div')),
+		supportCssPointerEvents = (function (el) {
+			// false when IE11
+			if (!!navigator.userAgent.match(/(?:Trident.*rv[ :]?11\.|msie)/i)) {
+				return false;
+			}
+			el = document.createElement('x');
+			el.style.cssText = 'pointer-events:auto';
+			return el.style.pointerEvents === 'auto';
+		})(),
+
+		_silent = false,
+
+		abs = Math.abs,
+		min = Math.min,
+
+		savedInputChecked = [],
+		touchDragOverListeners = [],
+
+		_autoScroll = _throttle(function (/**Event*/evt, /**Object*/options, /**HTMLElement*/rootEl) {
+			// Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=505521
+			if (rootEl && options.scroll) {
+				var _this = rootEl[expando],
+					el,
+					rect,
+					sens = options.scrollSensitivity,
+					speed = options.scrollSpeed,
+
+					x = evt.clientX,
+					y = evt.clientY,
+
+					winWidth = window.innerWidth,
+					winHeight = window.innerHeight,
+
+					vx,
+					vy,
+
+					scrollOffsetX,
+					scrollOffsetY
+				;
+
+				// Delect scrollEl
+				if (scrollParentEl !== rootEl) {
+					scrollEl = options.scroll;
+					scrollParentEl = rootEl;
+					scrollCustomFn = options.scrollFn;
+
+					if (scrollEl === true) {
+						scrollEl = rootEl;
+
+						do {
+							if ((scrollEl.offsetWidth < scrollEl.scrollWidth) ||
+								(scrollEl.offsetHeight < scrollEl.scrollHeight)
+							) {
+								break;
+							}
+							/* jshint boss:true */
+						} while (scrollEl = scrollEl.parentNode);
+					}
+				}
+
+				if (scrollEl) {
+					el = scrollEl;
+					rect = scrollEl.getBoundingClientRect();
+					vx = (abs(rect.right - x) <= sens) - (abs(rect.left - x) <= sens);
+					vy = (abs(rect.bottom - y) <= sens) - (abs(rect.top - y) <= sens);
+				}
+
+
+				if (!(vx || vy)) {
+					vx = (winWidth - x <= sens) - (x <= sens);
+					vy = (winHeight - y <= sens) - (y <= sens);
+
+					/* jshint expr:true */
+					(vx || vy) && (el = win);
+				}
+
+
+				if (autoScroll.vx !== vx || autoScroll.vy !== vy || autoScroll.el !== el) {
+					autoScroll.el = el;
+					autoScroll.vx = vx;
+					autoScroll.vy = vy;
+
+					clearInterval(autoScroll.pid);
+
+					if (el) {
+						autoScroll.pid = setInterval(function () {
+							scrollOffsetY = vy ? vy * speed : 0;
+							scrollOffsetX = vx ? vx * speed : 0;
+
+							if ('function' === typeof(scrollCustomFn)) {
+								return scrollCustomFn.call(_this, scrollOffsetX, scrollOffsetY, evt);
+							}
+
+							if (el === win) {
+								win.scrollTo(win.pageXOffset + scrollOffsetX, win.pageYOffset + scrollOffsetY);
+							} else {
+								el.scrollTop += scrollOffsetY;
+								el.scrollLeft += scrollOffsetX;
+							}
+						}, 24);
+					}
+				}
+			}
+		}, 30),
+
+		_prepareGroup = function (options) {
+			function toFn(value, pull) {
+				if (value === void 0 || value === true) {
+					value = group.name;
+				}
+
+				if (typeof value === 'function') {
+					return value;
+				} else {
+					return function (to, from) {
+						var fromGroup = from.options.group.name;
+
+						return pull
+							? value
+							: value && (value.join
+								? value.indexOf(fromGroup) > -1
+								: (fromGroup == value)
+							);
+					};
+				}
+			}
+
+			var group = {};
+			var originalGroup = options.group;
+
+			if (!originalGroup || typeof originalGroup != 'object') {
+				originalGroup = {name: originalGroup};
+			}
+
+			group.name = originalGroup.name;
+			group.checkPull = toFn(originalGroup.pull, true);
+			group.checkPut = toFn(originalGroup.put);
+			group.revertClone = originalGroup.revertClone;
+
+			options.group = group;
+		}
+	;
+
+	// Detect support a passive mode
+	try {
+		window.addEventListener('test', null, Object.defineProperty({}, 'passive', {
+			get: function () {
+				// `false`, because everything starts to work incorrectly and instead of d'n'd,
+				// begins the page has scrolled.
+				passiveMode = false;
+				captureMode = {
+					capture: false,
+					passive: passiveMode
+				};
+			}
+		}));
+	} catch (err) {}
+
+	/**
+	 * @class  KvSortable
+	 * @param  {HTMLElement}  el
+	 * @param  {Object}       [options]
+	 */
+	function KvSortable(el, options) {
+		if (!(el && el.nodeType && el.nodeType === 1)) {
+			throw 'KvSortable: `el` must be HTMLElement, and not ' + {}.toString.call(el);
+		}
+
+		this.el = el; // root element
+		this.options = options = _extend({}, options);
+
+
+		// Export instance
+		el[expando] = this;
+
+		// Default options
+		var defaults = {
+			group: Math.random(),
+			sort: true,
+			disabled: false,
+			store: null,
+			handle: null,
+			scroll: true,
+			scrollSensitivity: 30,
+			scrollSpeed: 10,
+			draggable: /[uo]l/i.test(el.nodeName) ? 'li' : '>*',
+			ghostClass: 'kvsortable-ghost',
+			chosenClass: 'kvsortable-chosen',
+			dragClass: 'kvsortable-drag',
+			ignore: 'a, img',
+			filter: null,
+			preventOnFilter: true,
+			animation: 0,
+			setData: function (dataTransfer, dragEl) {
+				dataTransfer.setData('Text', dragEl.textContent);
+			},
+			dropBubble: false,
+			dragoverBubble: false,
+			dataIdAttr: 'data-id',
+			delay: 0,
+			forceFallback: false,
+			fallbackClass: 'kvsortable-fallback',
+			fallbackOnBody: false,
+			fallbackTolerance: 0,
+			fallbackOffset: {x: 0, y: 0},
+			supportPointer: KvSortable.supportPointer !== false
+		};
+
+
+		// Set default options
+		for (var name in defaults) {
+			!(name in options) && (options[name] = defaults[name]);
+		}
+
+		_prepareGroup(options);
+
+		// Bind all private methods
+		for (var fn in this) {
+			if (fn.charAt(0) === '_' && typeof this[fn] === 'function') {
+				this[fn] = this[fn].bind(this);
+			}
+		}
+
+		// Setup drag mode
+		this.nativeDraggable = options.forceFallback ? false : supportDraggable;
+
+		// Bind events
+		_on(el, 'mousedown', this._onTapStart);
+		_on(el, 'touchstart', this._onTapStart);
+		options.supportPointer && _on(el, 'pointerdown', this._onTapStart);
+
+		if (this.nativeDraggable) {
+			_on(el, 'dragover', this);
+			_on(el, 'dragenter', this);
+		}
+
+		touchDragOverListeners.push(this._onDragOver);
+
+		// Restore sorting
+		options.store && this.sort(options.store.get(this));
+	}
+
+
+	KvSortable.prototype = /** @lends KvSortable.prototype */ {
+		constructor: KvSortable,
+
+		_onTapStart: function (/** Event|TouchEvent */evt) {
+			var _this = this,
+				el = this.el,
+				options = this.options,
+				preventOnFilter = options.preventOnFilter,
+				type = evt.type,
+				touch = evt.touches && evt.touches[0],
+				target = (touch || evt).target,
+				originalTarget = evt.target.shadowRoot && (evt.path && evt.path[0]) || target,
+				filter = options.filter,
+				startIndex;
+
+			_saveInputCheckedState(el);
+
+
+			// Don't trigger start event when an element is been dragged, otherwise the evt.oldindex always wrong when set option.group.
+			if (dragEl) {
+				return;
+			}
+
+			if (/mousedown|pointerdown/.test(type) && evt.button !== 0 || options.disabled) {
+				return; // only left button or enabled
+			}
+
+			// cancel dnd if original target is content editable
+			if (originalTarget.isContentEditable) {
+				return;
+			}
+
+			target = _closest(target, options.draggable, el);
+
+			if (!target) {
+				return;
+			}
+
+			if (lastDownEl === target) {
+				// Ignoring duplicate `down`
+				return;
+			}
+
+			// Get the index of the dragged element within its parent
+			startIndex = _index(target, options.draggable);
+
+			// Check filter
+			if (typeof filter === 'function') {
+				if (filter.call(this, evt, target, this)) {
+					_dispatchEvent(_this, originalTarget, 'filter', target, el, el, startIndex);
+					preventOnFilter && evt.preventDefault();
+					return; // cancel dnd
+				}
+			}
+			else if (filter) {
+				filter = filter.split(',').some(function (criteria) {
+					criteria = _closest(originalTarget, criteria.trim(), el);
+
+					if (criteria) {
+						_dispatchEvent(_this, criteria, 'filter', target, el, el, startIndex);
+						return true;
+					}
+				});
+
+				if (filter) {
+					preventOnFilter && evt.preventDefault();
+					return; // cancel dnd
+				}
+			}
+
+			if (options.handle && !_closest(originalTarget, options.handle, el)) {
+				return;
+			}
+
+			// Prepare `dragstart`
+			this._prepareDragStart(evt, touch, target, startIndex);
+		},
+
+		_prepareDragStart: function (/** Event */evt, /** Touch */touch, /** HTMLElement */target, /** Number */startIndex) {
+			var _this = this,
+				el = _this.el,
+				options = _this.options,
+				ownerDocument = el.ownerDocument,
+				dragStartFn;
+
+			if (target && !dragEl && (target.parentNode === el)) {
+				tapEvt = evt;
+
+				rootEl = el;
+				dragEl = target;
+				parentEl = dragEl.parentNode;
+				nextEl = dragEl.nextSibling;
+				lastDownEl = target;
+				activeGroup = options.group;
+				oldIndex = startIndex;
+
+				this._lastX = (touch || evt).clientX;
+				this._lastY = (touch || evt).clientY;
+
+				dragEl.style['will-change'] = 'all';
+
+				dragStartFn = function () {
+					// Delayed drag has been triggered
+					// we can re-enable the events: touchmove/mousemove
+					_this._disableDelayedDrag();
+
+					// Make the element draggable
+					dragEl.draggable = _this.nativeDraggable;
+
+					// Chosen item
+					_toggleClass(dragEl, options.chosenClass, true);
+
+					// Bind the events: dragstart/dragend
+					_this._triggerDragStart(evt, touch);
+
+					// Drag start event
+					_dispatchEvent(_this, rootEl, 'choose', dragEl, rootEl, rootEl, oldIndex);
+				};
+
+				// Disable "draggable"
+				options.ignore.split(',').forEach(function (criteria) {
+					_find(dragEl, criteria.trim(), _disableDraggable);
+				});
+
+				_on(ownerDocument, 'mouseup', _this._onDrop);
+				_on(ownerDocument, 'touchend', _this._onDrop);
+				_on(ownerDocument, 'touchcancel', _this._onDrop);
+				_on(ownerDocument, 'selectstart', _this);
+				options.supportPointer && _on(ownerDocument, 'pointercancel', _this._onDrop);
+
+				if (options.delay) {
+					// If the user moves the pointer or let go the click or touch
+					// before the delay has been reached:
+					// disable the delayed drag
+					_on(ownerDocument, 'mouseup', _this._disableDelayedDrag);
+					_on(ownerDocument, 'touchend', _this._disableDelayedDrag);
+					_on(ownerDocument, 'touchcancel', _this._disableDelayedDrag);
+					_on(ownerDocument, 'mousemove', _this._disableDelayedDrag);
+					_on(ownerDocument, 'touchmove', _this._disableDelayedDrag);
+					options.supportPointer && _on(ownerDocument, 'pointermove', _this._disableDelayedDrag);
+
+					_this._dragStartTimer = setTimeout(dragStartFn, options.delay);
+				} else {
+					dragStartFn();
+				}
+
+
+			}
+		},
+
+		_disableDelayedDrag: function () {
+			var ownerDocument = this.el.ownerDocument;
+
+			clearTimeout(this._dragStartTimer);
+			_off(ownerDocument, 'mouseup', this._disableDelayedDrag);
+			_off(ownerDocument, 'touchend', this._disableDelayedDrag);
+			_off(ownerDocument, 'touchcancel', this._disableDelayedDrag);
+			_off(ownerDocument, 'mousemove', this._disableDelayedDrag);
+			_off(ownerDocument, 'touchmove', this._disableDelayedDrag);
+			_off(ownerDocument, 'pointermove', this._disableDelayedDrag);
+		},
+
+		_triggerDragStart: function (/** Event */evt, /** Touch */touch) {
+			touch = touch || (evt.pointerType == 'touch' ? evt : null);
+
+			if (touch) {
+				// Touch device support
+				tapEvt = {
+					target: dragEl,
+					clientX: touch.clientX,
+					clientY: touch.clientY
+				};
+
+				this._onDragStart(tapEvt, 'touch');
+			}
+			else if (!this.nativeDraggable) {
+				this._onDragStart(tapEvt, true);
+			}
+			else {
+				_on(dragEl, 'dragend', this);
+				_on(rootEl, 'dragstart', this._onDragStart);
+			}
+
+			try {
+				if (document.selection) {
+					// Timeout neccessary for IE9
+					_nextTick(function () {
+						document.selection.empty();
+					});
+				} else {
+					window.getSelection().removeAllRanges();
+				}
+			} catch (err) {
+			}
+		},
+
+		_dragStarted: function () {
+			if (rootEl && dragEl) {
+				var options = this.options;
+
+				// Apply effect
+				_toggleClass(dragEl, options.ghostClass, true);
+				_toggleClass(dragEl, options.dragClass, false);
+
+				KvSortable.active = this;
+
+				// Drag start event
+				_dispatchEvent(this, rootEl, 'start', dragEl, rootEl, rootEl, oldIndex);
+			} else {
+				this._nulling();
+			}
+		},
+
+		_emulateDragOver: function () {
+			if (touchEvt) {
+				if (this._lastX === touchEvt.clientX && this._lastY === touchEvt.clientY) {
+					return;
+				}
+
+				this._lastX = touchEvt.clientX;
+				this._lastY = touchEvt.clientY;
+
+				if (!supportCssPointerEvents) {
+					_css(ghostEl, 'display', 'none');
+				}
+
+				var target = document.elementFromPoint(touchEvt.clientX, touchEvt.clientY);
+				var parent = target;
+				var i = touchDragOverListeners.length;
+
+				if (target && target.shadowRoot) {
+					target = target.shadowRoot.elementFromPoint(touchEvt.clientX, touchEvt.clientY);
+					parent = target;
+				}
+
+				if (parent) {
+					do {
+						if (parent[expando]) {
+							while (i--) {
+								touchDragOverListeners[i]({
+									clientX: touchEvt.clientX,
+									clientY: touchEvt.clientY,
+									target: target,
+									rootEl: parent
+								});
+							}
+
+							break;
+						}
+
+						target = parent; // store last element
+					}
+					/* jshint boss:true */
+					while (parent = parent.parentNode);
+				}
+
+				if (!supportCssPointerEvents) {
+					_css(ghostEl, 'display', '');
+				}
+			}
+		},
+
+
+		_onTouchMove: function (/**TouchEvent*/evt) {
+			if (tapEvt) {
+				var	options = this.options,
+					fallbackTolerance = options.fallbackTolerance,
+					fallbackOffset = options.fallbackOffset,
+					touch = evt.touches ? evt.touches[0] : evt,
+					dx = (touch.clientX - tapEvt.clientX) + fallbackOffset.x,
+					dy = (touch.clientY - tapEvt.clientY) + fallbackOffset.y,
+					translate3d = evt.touches ? 'translate3d(' + dx + 'px,' + dy + 'px,0)' : 'translate(' + dx + 'px,' + dy + 'px)';
+
+				// only set the status to dragging, when we are actually dragging
+				if (!KvSortable.active) {
+					if (fallbackTolerance &&
+						min(abs(touch.clientX - this._lastX), abs(touch.clientY - this._lastY)) < fallbackTolerance
+					) {
+						return;
+					}
+
+					this._dragStarted();
+				}
+
+				// as well as creating the ghost element on the document body
+				this._appendGhost();
+
+				moved = true;
+				touchEvt = touch;
+
+				_css(ghostEl, 'webkitTransform', translate3d);
+				_css(ghostEl, 'mozTransform', translate3d);
+				_css(ghostEl, 'msTransform', translate3d);
+				_css(ghostEl, 'transform', translate3d);
+
+				evt.preventDefault();
+			}
+		},
+
+		_appendGhost: function () {
+			if (!ghostEl) {
+				var rect = dragEl.getBoundingClientRect(),
+					css = _css(dragEl),
+					options = this.options,
+					ghostRect;
+
+				ghostEl = dragEl.cloneNode(true);
+
+				_toggleClass(ghostEl, options.ghostClass, false);
+				_toggleClass(ghostEl, options.fallbackClass, true);
+				_toggleClass(ghostEl, options.dragClass, true);
+
+				_css(ghostEl, 'top', rect.top - parseInt(css.marginTop, 10));
+				_css(ghostEl, 'left', rect.left - parseInt(css.marginLeft, 10));
+				_css(ghostEl, 'width', rect.width);
+				_css(ghostEl, 'height', rect.height);
+				_css(ghostEl, 'opacity', '0.8');
+				_css(ghostEl, 'position', 'fixed');
+				_css(ghostEl, 'zIndex', '100000');
+				_css(ghostEl, 'pointerEvents', 'none');
+
+				options.fallbackOnBody && document.body.appendChild(ghostEl) || rootEl.appendChild(ghostEl);
+
+				// Fixing dimensions.
+				ghostRect = ghostEl.getBoundingClientRect();
+				_css(ghostEl, 'width', rect.width * 2 - ghostRect.width);
+				_css(ghostEl, 'height', rect.height * 2 - ghostRect.height);
+			}
+		},
+
+		_onDragStart: function (/**Event*/evt, /**boolean*/useFallback) {
+			var _this = this;
+			var dataTransfer = evt.dataTransfer;
+			var options = _this.options;
+
+			_this._offUpEvents();
+
+			if (activeGroup.checkPull(_this, _this, dragEl, evt)) {
+				cloneEl = _clone(dragEl);
+
+				cloneEl.draggable = false;
+				cloneEl.style['will-change'] = '';
+
+				_css(cloneEl, 'display', 'none');
+				_toggleClass(cloneEl, _this.options.chosenClass, false);
+
+				// #1143: IFrame support workaround
+				_this._cloneId = _nextTick(function () {
+					rootEl.insertBefore(cloneEl, dragEl);
+					_dispatchEvent(_this, rootEl, 'clone', dragEl);
+				});
+			}
+
+			_toggleClass(dragEl, options.dragClass, true);
+
+			if (useFallback) {
+				if (useFallback === 'touch') {
+					// Bind touch events
+					_on(document, 'touchmove', _this._onTouchMove);
+					_on(document, 'touchend', _this._onDrop);
+					_on(document, 'touchcancel', _this._onDrop);
+
+					if (options.supportPointer) {
+						_on(document, 'pointermove', _this._onTouchMove);
+						_on(document, 'pointerup', _this._onDrop);
+					}
+				} else {
+					// Old brwoser
+					_on(document, 'mousemove', _this._onTouchMove);
+					_on(document, 'mouseup', _this._onDrop);
+				}
+
+				_this._loopId = setInterval(_this._emulateDragOver, 50);
+			}
+			else {
+				if (dataTransfer) {
+					dataTransfer.effectAllowed = 'move';
+					options.setData && options.setData.call(_this, dataTransfer, dragEl);
+				}
+
+				_on(document, 'drop', _this);
+
+				// #1143: Бывает элемент с IFrame внутри блокирует `drop`,
+				// поэтому если вызвался `mouseover`, значит надо отменять весь d'n'd.
+				// Breaking Chrome 62+
+				// _on(document, 'mouseover', _this);
+
+				_this._dragStartId = _nextTick(_this._dragStarted);
+			}
+		},
+
+		_onDragOver: function (/**Event*/evt) {
+			var el = this.el,
+				target,
+				dragRect,
+				targetRect,
+				revert,
+				options = this.options,
+				group = options.group,
+				activeKvSortable = KvSortable.active,
+				isOwner = (activeGroup === group),
+				isMovingBetweenKvSortable = false,
+				canSort = options.sort;
+
+			if (evt.preventDefault !== void 0) {
+				evt.preventDefault();
+				!options.dragoverBubble && evt.stopPropagation();
+			}
+
+			if (dragEl.animated) {
+				return;
+			}
+
+			moved = true;
+
+			if (activeKvSortable && !options.disabled &&
+				(isOwner
+					? canSort || (revert = !rootEl.contains(dragEl)) // Reverting item into the original list
+					: (
+						putKvSortable === this ||
+						(
+							(activeKvSortable.lastPullMode = activeGroup.checkPull(this, activeKvSortable, dragEl, evt)) &&
+							group.checkPut(this, activeKvSortable, dragEl, evt)
+						)
+					)
+				) &&
+				(evt.rootEl === void 0 || evt.rootEl === this.el) // touch fallback
+			) {
+				// Smart auto-scrolling
+				_autoScroll(evt, options, this.el);
+
+				if (_silent) {
+					return;
+				}
+
+				target = _closest(evt.target, options.draggable, el);
+				dragRect = dragEl.getBoundingClientRect();
+
+				if (putKvSortable !== this) {
+					putKvSortable = this;
+					isMovingBetweenKvSortable = true;
+				}
+
+				if (revert) {
+					_cloneHide(activeKvSortable, true);
+					parentEl = rootEl; // actualization
+
+					if (cloneEl || nextEl) {
+						rootEl.insertBefore(dragEl, cloneEl || nextEl);
+					}
+					else if (!canSort) {
+						rootEl.appendChild(dragEl);
+					}
+
+					return;
+				}
+
+
+				if ((el.children.length === 0) || (el.children[0] === ghostEl) ||
+					(el === evt.target) && (_ghostIsLast(el, evt))
+				) {
+					//assign target only if condition is true
+					if (el.children.length !== 0 && el.children[0] !== ghostEl && el === evt.target) {
+						target = el.lastElementChild;
+					}
+
+					if (target) {
+						if (target.animated) {
+							return;
+						}
+
+						targetRect = target.getBoundingClientRect();
+					}
+
+					_cloneHide(activeKvSortable, isOwner);
+
+					if (_onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt) !== false) {
+						if (!dragEl.contains(el)) {
+							el.appendChild(dragEl);
+							parentEl = el; // actualization
+						}
+
+						this._animate(dragRect, dragEl);
+						target && this._animate(targetRect, target);
+					}
+				}
+				else if (target && !target.animated && target !== dragEl && (target.parentNode[expando] !== void 0)) {
+					if (lastEl !== target) {
+						lastEl = target;
+						lastCSS = _css(target);
+						lastParentCSS = _css(target.parentNode);
+					}
+
+					targetRect = target.getBoundingClientRect();
+
+					var width = targetRect.right - targetRect.left,
+						height = targetRect.bottom - targetRect.top,
+						floating = R_FLOAT.test(lastCSS.cssFloat + lastCSS.display)
+							|| (lastParentCSS.display == 'flex' && lastParentCSS['flex-direction'].indexOf('row') === 0),
+						isWide = (target.offsetWidth > dragEl.offsetWidth),
+						isLong = (target.offsetHeight > dragEl.offsetHeight),
+						halfway = (floating ? (evt.clientX - targetRect.left) / width : (evt.clientY - targetRect.top) / height) > 0.5,
+						nextSibling = target.nextElementSibling,
+						after = false
+					;
+
+					if (floating) {
+						var elTop = dragEl.offsetTop,
+							tgTop = target.offsetTop;
+
+						if (elTop === tgTop) {
+							after = (target.previousElementSibling === dragEl) && !isWide || halfway && isWide;
+						}
+						else if (target.previousElementSibling === dragEl || dragEl.previousElementSibling === target) {
+							after = (evt.clientY - targetRect.top) / height > 0.5;
+						} else {
+							after = tgTop > elTop;
+						}
+						} else if (!isMovingBetweenKvSortable) {
+						after = (nextSibling !== dragEl) && !isLong || halfway && isLong;
+					}
+
+					var moveVector = _onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt, after);
+
+					if (moveVector !== false) {
+						if (moveVector === 1 || moveVector === -1) {
+							after = (moveVector === 1);
+						}
+
+						_silent = true;
+						setTimeout(_unsilent, 30);
+
+						_cloneHide(activeKvSortable, isOwner);
+
+						if (!dragEl.contains(el)) {
+							if (after && !nextSibling) {
+								el.appendChild(dragEl);
+							} else {
+								target.parentNode.insertBefore(dragEl, after ? nextSibling : target);
+							}
+						}
+
+						parentEl = dragEl.parentNode; // actualization
+
+						this._animate(dragRect, dragEl);
+						this._animate(targetRect, target);
+					}
+				}
+			}
+		},
+
+		_animate: function (prevRect, target) {
+			var ms = this.options.animation;
+
+			if (ms) {
+				var currentRect = target.getBoundingClientRect();
+
+				if (prevRect.nodeType === 1) {
+					prevRect = prevRect.getBoundingClientRect();
+				}
+
+				_css(target, 'transition', 'none');
+				_css(target, 'transform', 'translate3d('
+					+ (prevRect.left - currentRect.left) + 'px,'
+					+ (prevRect.top - currentRect.top) + 'px,0)'
+				);
+
+				target.offsetWidth; // repaint
+
+				_css(target, 'transition', 'all ' + ms + 'ms');
+				_css(target, 'transform', 'translate3d(0,0,0)');
+
+				clearTimeout(target.animated);
+				target.animated = setTimeout(function () {
+					_css(target, 'transition', '');
+					_css(target, 'transform', '');
+					target.animated = false;
+				}, ms);
+			}
+		},
+
+		_offUpEvents: function () {
+			var ownerDocument = this.el.ownerDocument;
+
+			_off(document, 'touchmove', this._onTouchMove);
+			_off(document, 'pointermove', this._onTouchMove);
+			_off(ownerDocument, 'mouseup', this._onDrop);
+			_off(ownerDocument, 'touchend', this._onDrop);
+			_off(ownerDocument, 'pointerup', this._onDrop);
+			_off(ownerDocument, 'touchcancel', this._onDrop);
+			_off(ownerDocument, 'pointercancel', this._onDrop);
+			_off(ownerDocument, 'selectstart', this);
+		},
+
+		_onDrop: function (/**Event*/evt) {
+			var el = this.el,
+				options = this.options;
+
+			clearInterval(this._loopId);
+			clearInterval(autoScroll.pid);
+			clearTimeout(this._dragStartTimer);
+
+			_cancelNextTick(this._cloneId);
+			_cancelNextTick(this._dragStartId);
+
+			// Unbind events
+			_off(document, 'mouseover', this);
+			_off(document, 'mousemove', this._onTouchMove);
+
+			if (this.nativeDraggable) {
+				_off(document, 'drop', this);
+				_off(el, 'dragstart', this._onDragStart);
+			}
+
+			this._offUpEvents();
+
+			if (evt) {
+				if (moved) {
+					evt.preventDefault();
+					!options.dropBubble && evt.stopPropagation();
+				}
+
+				ghostEl && ghostEl.parentNode && ghostEl.parentNode.removeChild(ghostEl);
+
+				if (rootEl === parentEl || KvSortable.active.lastPullMode !== 'clone') {
+					// Remove clone
+					cloneEl && cloneEl.parentNode && cloneEl.parentNode.removeChild(cloneEl);
+				}
+
+				if (dragEl) {
+					if (this.nativeDraggable) {
+						_off(dragEl, 'dragend', this);
+					}
+
+					_disableDraggable(dragEl);
+					dragEl.style['will-change'] = '';
+
+					// Remove class's
+					_toggleClass(dragEl, this.options.ghostClass, false);
+					_toggleClass(dragEl, this.options.chosenClass, false);
+
+					// Drag stop event
+					_dispatchEvent(this, rootEl, 'unchoose', dragEl, parentEl, rootEl, oldIndex);
+
+					if (rootEl !== parentEl) {
+						newIndex = _index(dragEl, options.draggable);
+
+						if (newIndex >= 0) {
+							// Add event
+							_dispatchEvent(null, parentEl, 'add', dragEl, parentEl, rootEl, oldIndex, newIndex);
+
+							// Remove event
+							_dispatchEvent(this, rootEl, 'remove', dragEl, parentEl, rootEl, oldIndex, newIndex);
+
+							// drag from one list and drop into another
+							_dispatchEvent(null, parentEl, 'sort', dragEl, parentEl, rootEl, oldIndex, newIndex);
+							_dispatchEvent(this, rootEl, 'sort', dragEl, parentEl, rootEl, oldIndex, newIndex);
+						}
+					}
+					else {
+						if (dragEl.nextSibling !== nextEl) {
+							// Get the index of the dragged element within its parent
+							newIndex = _index(dragEl, options.draggable);
+
+							if (newIndex >= 0) {
+								// drag & drop within the same list
+								_dispatchEvent(this, rootEl, 'update', dragEl, parentEl, rootEl, oldIndex, newIndex);
+								_dispatchEvent(this, rootEl, 'sort', dragEl, parentEl, rootEl, oldIndex, newIndex);
+							}
+						}
+					}
+
+					if (KvSortable.active) {
+						/* jshint eqnull:true */
+						if (newIndex == null || newIndex === -1) {
+							newIndex = oldIndex;
+						}
+
+						_dispatchEvent(this, rootEl, 'end', dragEl, parentEl, rootEl, oldIndex, newIndex);
+
+						// Save sorting
+						this.save();
+					}
+				}
+
+			}
+
+			this._nulling();
+		},
+
+		_nulling: function() {
+			rootEl =
+			dragEl =
+			parentEl =
+			ghostEl =
+			nextEl =
+			cloneEl =
+			lastDownEl =
+
+			scrollEl =
+			scrollParentEl =
+
+			tapEvt =
+			touchEvt =
+
+			moved =
+			newIndex =
+
+			lastEl =
+			lastCSS =
+
+			putKvSortable =
+			activeGroup =
+			KvSortable.active = null;
+
+			savedInputChecked.forEach(function (el) {
+				el.checked = true;
+			});
+			savedInputChecked.length = 0;
+		},
+
+		handleEvent: function (/**Event*/evt) {
+			switch (evt.type) {
+				case 'drop':
+				case 'dragend':
+					this._onDrop(evt);
+					break;
+
+				case 'dragover':
+				case 'dragenter':
+					if (dragEl) {
+						this._onDragOver(evt);
+						_globalDragOver(evt);
+					}
+					break;
+
+				case 'mouseover':
+					this._onDrop(evt);
+					break;
+
+				case 'selectstart':
+					evt.preventDefault();
+					break;
+			}
+		},
+
+
+		/**
+		 * Serializes the item into an array of string.
+		 * @returns {String[]}
+		 */
+		toArray: function () {
+			var order = [],
+				el,
+				children = this.el.children,
+				i = 0,
+				n = children.length,
+				options = this.options;
+
+			for (; i < n; i++) {
+				el = children[i];
+				if (_closest(el, options.draggable, this.el)) {
+					order.push(el.getAttribute(options.dataIdAttr) || _generateId(el));
+				}
+			}
+
+			return order;
+		},
+
+
+		/**
+		 * Sorts the elements according to the array.
+		 * @param  {String[]}  order  order of the items
+		 */
+		sort: function (order) {
+			var items = {}, rootEl = this.el;
+
+			this.toArray().forEach(function (id, i) {
+				var el = rootEl.children[i];
+
+				if (_closest(el, this.options.draggable, rootEl)) {
+					items[id] = el;
+				}
+			}, this);
+
+			order.forEach(function (id) {
+				if (items[id]) {
+					rootEl.removeChild(items[id]);
+					rootEl.appendChild(items[id]);
+				}
+			});
+		},
+
+
+		/**
+		 * Save the current sorting
+		 */
+		save: function () {
+			var store = this.options.store;
+			store && store.set(this);
+		},
+
+
+		/**
+		 * For each element in the set, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree.
+		 * @param   {HTMLElement}  el
+		 * @param   {String}       [selector]  default: `options.draggable`
+		 * @returns {HTMLElement|null}
+		 */
+		closest: function (el, selector) {
+			return _closest(el, selector || this.options.draggable, this.el);
+		},
+
+
+		/**
+		 * Set/get option
+		 * @param   {string} name
+		 * @param   {*}      [value]
+		 * @returns {*}
+		 */
+		option: function (name, value) {
+			var options = this.options;
+
+			if (value === void 0) {
+				return options[name];
+			} else {
+				options[name] = value;
+
+				if (name === 'group') {
+					_prepareGroup(options);
+				}
+			}
+		},
+
+
+		/**
+		 * Destroy
+		 */
+		destroy: function () {
+			var el = this.el;
+
+			el[expando] = null;
+
+			_off(el, 'mousedown', this._onTapStart);
+			_off(el, 'touchstart', this._onTapStart);
+			_off(el, 'pointerdown', this._onTapStart);
+
+			if (this.nativeDraggable) {
+				_off(el, 'dragover', this);
+				_off(el, 'dragenter', this);
+			}
+
+			// Remove draggable attributes
+			Array.prototype.forEach.call(el.querySelectorAll('[draggable]'), function (el) {
+				el.removeAttribute('draggable');
+			});
+
+			touchDragOverListeners.splice(touchDragOverListeners.indexOf(this._onDragOver), 1);
+
+			this._onDrop();
+
+			this.el = el = null;
+		}
+	};
+
+
+	function _cloneHide(kvsortable, state) {
+		if (kvsortable.lastPullMode !== 'clone') {
+			state = true;
+		}
+
+		if (cloneEl && (cloneEl.state !== state)) {
+			_css(cloneEl, 'display', state ? 'none' : '');
+
+			if (!state) {
+				if (cloneEl.state) {
+					if (kvsortable.options.group.revertClone) {
+						rootEl.insertBefore(cloneEl, nextEl);
+						kvsortable._animate(dragEl, cloneEl);
+					} else {
+						rootEl.insertBefore(cloneEl, dragEl);
+					}
+				}
+			}
+
+			cloneEl.state = state;
+		}
+	}
+
+
+	function _closest(/**HTMLElement*/el, /**String*/selector, /**HTMLElement*/ctx) {
+		if (el) {
+			ctx = ctx || document;
+
+			do {
+				if ((selector === '>*' && el.parentNode === ctx) || _matches(el, selector)) {
+					return el;
+				}
+				/* jshint boss:true */
+			} while (el = _getParentOrHost(el));
+		}
+
+		return null;
+	}
+
+
+	function _getParentOrHost(el) {
+		var parent = el.host;
+
+		return (parent && parent.nodeType) ? parent : el.parentNode;
+	}
+
+
+	function _globalDragOver(/**Event*/evt) {
+		if (evt.dataTransfer) {
+			evt.dataTransfer.dropEffect = 'move';
+		}
+		evt.preventDefault();
+	}
+
+
+	function _on(el, event, fn) {
+		el.addEventListener(event, fn, captureMode);
+	}
+
+
+	function _off(el, event, fn) {
+		el.removeEventListener(event, fn, captureMode);
+	}
+
+
+	function _toggleClass(el, name, state) {
+		if (el) {
+			if (el.classList) {
+				el.classList[state ? 'add' : 'remove'](name);
+			}
+			else {
+				var className = (' ' + el.className + ' ').replace(R_SPACE, ' ').replace(' ' + name + ' ', ' ');
+				el.className = (className + (state ? ' ' + name : '')).replace(R_SPACE, ' ');
+			}
+		}
+	}
+
+
+	function _css(el, prop, val) {
+		var style = el && el.style;
+
+		if (style) {
+			if (val === void 0) {
+				if (document.defaultView && document.defaultView.getComputedStyle) {
+					val = document.defaultView.getComputedStyle(el, '');
+				}
+				else if (el.currentStyle) {
+					val = el.currentStyle;
+				}
+
+				return prop === void 0 ? val : val[prop];
+			}
+			else {
+				if (!(prop in style)) {
+					prop = '-webkit-' + prop;
+				}
+
+				style[prop] = val + (typeof val === 'string' ? '' : 'px');
+			}
+		}
+	}
+
+
+	function _find(ctx, tagName, iterator) {
+		if (ctx) {
+			var list = ctx.getElementsByTagName(tagName), i = 0, n = list.length;
+
+			if (iterator) {
+				for (; i < n; i++) {
+					iterator(list[i], i);
+				}
+			}
+
+			return list;
+		}
+
+		return [];
+	}
+
+
+
+	function _dispatchEvent(kvsortable, rootEl, name, targetEl, toEl, fromEl, startIndex, newIndex) {
+		kvsortable = (kvsortable || rootEl[expando]);
+
+		var evt = document.createEvent('Event'),
+			options = kvsortable.options,
+			onName = 'on' + name.charAt(0).toUpperCase() + name.substr(1);
+
+		evt.initEvent(name, true, true);
+
+		evt.to = toEl || rootEl;
+		evt.from = fromEl || rootEl;
+		evt.item = targetEl || rootEl;
+		evt.clone = cloneEl;
+
+		evt.oldIndex = startIndex;
+		evt.newIndex = newIndex;
+
+		rootEl.dispatchEvent(evt);
+
+		if (options[onName]) {
+			options[onName].call(kvsortable, evt);
+		}
+	}
+
+
+	function _onMove(fromEl, toEl, dragEl, dragRect, targetEl, targetRect, originalEvt, willInsertAfter) {
+		var evt,
+			kvsortable = fromEl[expando],
+			onMoveFn = kvsortable.options.onMove,
+			retVal;
+
+		evt = document.createEvent('Event');
+		evt.initEvent('move', true, true);
+
+		evt.to = toEl;
+		evt.from = fromEl;
+		evt.dragged = dragEl;
+		evt.draggedRect = dragRect;
+		evt.related = targetEl || toEl;
+		evt.relatedRect = targetRect || toEl.getBoundingClientRect();
+		evt.willInsertAfter = willInsertAfter;
+
+		fromEl.dispatchEvent(evt);
+
+		if (onMoveFn) {
+			retVal = onMoveFn.call(kvsortable, evt, originalEvt);
+		}
+
+		return retVal;
+	}
+
+
+	function _disableDraggable(el) {
+		el.draggable = false;
+	}
+
+
+	function _unsilent() {
+		_silent = false;
+	}
+
+
+	/** @returns {HTMLElement|false} */
+	function _ghostIsLast(el, evt) {
+		var lastEl = el.lastElementChild,
+			rect = lastEl.getBoundingClientRect();
+
+		// 5 — min delta
+		// abs — нельзя добавлять, а то глюки при наведении сверху
+		return (evt.clientY - (rect.top + rect.height) > 5) ||
+			(evt.clientX - (rect.left + rect.width) > 5);
+	}
+
+
+	/**
+	 * Generate id
+	 * @param   {HTMLElement} el
+	 * @returns {String}
+	 * @private
+	 */
+	function _generateId(el) {
+		var str = el.tagName + el.className + el.src + el.href + el.textContent,
+			i = str.length,
+			sum = 0;
+
+		while (i--) {
+			sum += str.charCodeAt(i);
+		}
+
+		return sum.toString(36);
+	}
+
+	/**
+	 * Returns the index of an element within its parent for a selected set of
+	 * elements
+	 * @param  {HTMLElement} el
+	 * @param  {selector} selector
+	 * @return {number}
+	 */
+	function _index(el, selector) {
+		var index = 0;
+
+		if (!el || !el.parentNode) {
+			return -1;
+		}
+
+		while (el && (el = el.previousElementSibling)) {
+			if ((el.nodeName.toUpperCase() !== 'TEMPLATE') && (selector === '>*' || _matches(el, selector))) {
+				index++;
+			}
+		}
+
+		return index;
+	}
+
+	function _matches(/**HTMLElement*/el, /**String*/selector) {
+		if (el) {
+			selector = selector.split('.');
+
+			var tag = selector.shift().toUpperCase(),
+				re = new RegExp('\\s(' + selector.join('|') + ')(?=\\s)', 'g');
+
+			return (
+				(tag === '' || el.nodeName.toUpperCase() == tag) &&
+				(!selector.length || ((' ' + el.className + ' ').match(re) || []).length == selector.length)
+			);
+		}
+
+		return false;
+	}
+
+	function _throttle(callback, ms) {
+		var args, _this;
+
+		return function () {
+			if (args === void 0) {
+				args = arguments;
+				_this = this;
+
+				setTimeout(function () {
+					if (args.length === 1) {
+						callback.call(_this, args[0]);
+					} else {
+						callback.apply(_this, args);
+					}
+
+					args = void 0;
+				}, ms);
+			}
+		};
+	}
+
+	function _extend(dst, src) {
+		if (dst && src) {
+			for (var key in src) {
+				if (src.hasOwnProperty(key)) {
+					dst[key] = src[key];
+				}
+			}
+		}
+
+		return dst;
+	}
+
+	function _clone(el) {
+		if (Polymer && Polymer.dom) {
+			return Polymer.dom(el).cloneNode(true);
+		}
+		else if ($) {
+			return $(el).clone(true)[0];
+		}
+		else {
+			return el.cloneNode(true);
+		}
+	}
+
+	function _saveInputCheckedState(root) {
+		var inputs = root.getElementsByTagName('input');
+		var idx = inputs.length;
+
+		while (idx--) {
+			var el = inputs[idx];
+			el.checked && savedInputChecked.push(el);
+		}
+	}
+
+	function _nextTick(fn) {
+		return setTimeout(fn, 0);
+	}
+
+	function _cancelNextTick(id) {
+		return clearTimeout(id);
+	}
+
+	// Fixed #973:
+	_on(document, 'touchmove', function (evt) {
+		if (KvSortable.active) {
+			evt.preventDefault();
+		}
+	});
+
+	// Export utils
+	KvSortable.utils = {
+		on: _on,
+		off: _off,
+		css: _css,
+		find: _find,
+		is: function (el, selector) {
+			return !!_closest(el, selector, el);
+		},
+		extend: _extend,
+		throttle: _throttle,
+		closest: _closest,
+		toggleClass: _toggleClass,
+		clone: _clone,
+		index: _index,
+		nextTick: _nextTick,
+		cancelNextTick: _cancelNextTick
+	};
+
+
+	/**
+	 * Create kvsortable instance
+	 * @param {HTMLElement}  el
+	 * @param {Object}      [options]
+	 */
+	KvSortable.create = function (el, options) {
+		return new KvSortable(el, options);
+	};
+
+
+	// Export
+	KvSortable.version = '1.7.0';
+	return KvSortable;
+});
+/**
+ * jQuery plugin for KvSortable
+ */
+(function (factory) {
+    "use strict";
+
+    if (typeof define === "function" && define.amd) {
+        define(["jquery"], factory);
+    }
+    else {
+        /* jshint sub:true */
+        factory(jQuery);
+    }
+})(function ($) {
+    "use strict";
+    $.fn.kvsortable = function (options) {
+        var retVal,
+            args = arguments;
+
+        this.each(function () {
+            var $el = $(this), kvsortable = $el.data('kvsortable');
+
+            if (!kvsortable && (options instanceof Object || !options)) {
+                kvsortable = new KvSortable(this, options);
+                $el.data('kvsortable', kvsortable);
+            }
+
+            if (kvsortable) {
+                if (options === 'widget') {
+                    retVal = kvsortable;
+                }
+                else if (options === 'destroy') {
+                    kvsortable.destroy();
+                    $el.removeData('kvsortable');
+                }
+                else if (typeof kvsortable[options] === 'function') {
+                    retVal = kvsortable[options].apply(kvsortable, [].slice.call(args, 1));
+                }
+                else if (options in kvsortable.options) {
+                    retVal = kvsortable.option.apply(kvsortable, args);
+                }
+            }
+        });
+
+        return (retVal === void 0) ? this : retVal;
+    };
+});

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 0 - 0
public/base/plugins/bootstrap-fileinput/js/plugins/sortable.min.js


+ 21 - 0
public/base/plugins/bootstrap-fileinput/nuget/Package.nuspec

xqd
@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+<package >
+  <metadata>
+    <id>bootstrap-fileinput</id>
+	<title>bootstrap-fileinput</title>
+    <version>4.5.2</version>
+    <authors>Kartik Visweswaran</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 2014 - 2018</copyright>
+    <tags>bootstrap bootstrap-fileinput</tags>
+    <dependencies>
+      <dependency id="bootstrap" version="3.3.0" />
+    </dependencies>
+  </metadata>
+</package>

+ 35 - 0
public/base/plugins/bootstrap-fileinput/nuget/build.bat

xqd
@@ -0,0 +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
+
+REM delete the previous package versions
+REM del bootstrap-fileinput.*
+
+REM copy the content to the destination folders
+xcopy ..\js content\Scripts /D /E /C /R /I /K /Y 
+xcopy ..\css content\Content\bootstrap-fileinput\css /D /E /C /R /I /K /Y 
+xcopy ..\img content\Content\bootstrap-fileinput\img /D /E /C /R /I /K /Y 
+xcopy ..\themes content\Content\bootstrap-fileinput\themes /D /E /C /R /I /K /Y 
+xcopy ..\scss content\Content\bootstrap-fileinput\scss /D /E /C /R /I /K /Y 
+
+REM create a new package
+NuGet Pack Package.nuspec -Exclude NuGet.exe;build.bat
+
+REM Upload the new package
+REM for %%f in (content\Content\bootstrap-fileinput.*) do (
+REM NuGet Push %%f
+REM rmdir /s /q content
+REM del %%f
+REM )

+ 136 - 0
public/base/plugins/bootstrap-fileinput/scss/fileinput-rtl.scss

xqd
@@ -0,0 +1,136 @@
+/*!
+ * bootstrap-fileinput v4.5.2
+ * http://plugins.krajee.com/file-input
+ *
+ * Krajee RTL (Right To Left) default styling for bootstrap-fileinput.
+ *
+ * Author: Kartik Visweswaran
+ * Copyright: 2014 - 2018, Kartik Visweswaran, Krajee.com
+ *
+ * Licensed under the BSD 3-Clause
+ * https://github.com/kartik-v/bootstrap-fileinput/blob/master/LICENSE.md
+ */
+
+//colors
+$zorba: #a2958a !default;
+$mine-shaft: #333 !default;
+
+//standard measures
+$radius: 4px !default;
+$pad: 5px !default;
+$border: 1px !default;
+
+//operations
+@function multiply($pixels, $multiplier) {
+    @return $pixels * $multiplier;
+}
+
+//@extend-elements
+%set_float_left {
+    float: left;
+}
+
+%set_float_right {
+    float: right;
+}
+
+%set_text_right {
+    text-align: right;
+}
+
+.kv-rtl {
+    direction: rtl;
+    .floating-buttons {
+        left: multiply($pad, 2);
+        right: auto;
+        .btn-kv {
+            margin-left: 0;
+            margin-right: multiply($pad, 0.6);
+        }
+    }
+    .file-caption-icon {
+        left: auto;
+        right: multiply($pad, 1.6);
+    }
+    .close {
+        @extend %set_float_left;
+    }
+    .file-zoom-dialog {
+        @extend %set_text_right;
+    }
+    .file-error-message {
+        pre {
+            @extend %set_text_right;
+        }
+        ul {
+            @extend %set_text_right;
+        }
+    }
+    .file-drop-zone {
+        margin: multiply($pad, 2.4) multiply($pad, 2.4) multiply($pad, 2.4) multiply($pad, 3);
+    }
+    .btn-prev {
+        right: multiply($pad, 0.2);
+        left: auto;
+    }
+    .btn-next {
+        left: multiply($pad, 0.2);
+        right: auto;
+    }
+    .pull-right {
+        float: left !important;
+    }
+    .pull-left {
+        float: right !important;
+    }
+    .float-right {
+        @extend .pull-right;
+    }
+    .float-left {
+        @extend .pull-left;
+    }
+    .kv-zoom-title {
+        direction: ltr;
+    }
+    .krajee-default {
+        &.file-preview-frame {
+            @extend %set_float_right;
+            box-shadow: (-$border) $border multiply($border, 5) 0 $zorba;
+            &:not(.file-preview-error):hover {
+                box-shadow: multiply($border, -3) multiply($border, 3) multiply($border, 5) 0 $mine-shaft;
+            }
+        }
+        .file-actions {
+            @extend %set_float_left;
+        }
+        .file-other-error {
+            @extend %set_float_left;
+        }
+        .file-drag-handle {
+            @extend %set_float_right;
+        }
+        .file-upload-indicator {
+            @extend %set_float_right;
+        }
+    }
+    .kv-zoom-actions .btn-kv {
+        margin-left: 0;
+        margin-right: multiply($pad, 0.6);
+    }
+    .file-caption.icon-visible .file-caption-name {
+        padding-left: 0;
+        padding-right: multiply($pad, 3);
+    }
+    .input-group-btn > .btn:last-child {
+        border-radius: $radius 0 0 $radius;
+    }
+    .input-group .form-control:first-child {
+        border-radius: 0 $radius $radius 0;
+    }
+    .btn-file input[type=file] {
+        left: auto;
+        right: 0;
+        text-align: left;
+        background: none repeat scroll 100% 0 transparent;
+    }
+}

+ 671 - 0
public/base/plugins/bootstrap-fileinput/scss/fileinput.scss

xqd
@@ -0,0 +1,671 @@
+/*!
+ * bootstrap-fileinput v4.5.2
+ * http://plugins.krajee.com/file-input
+ *
+ * Krajee default styling for bootstrap-fileinput.
+ *
+ * Author: Kartik Visweswaran
+ * Copyright: 2014 - 2018, Kartik Visweswaran, Krajee.com
+ *
+ * Licensed under the BSD 3-Clause
+ * https://github.com/kartik-v/bootstrap-fileinput/blob/master/LICENSE.md
+ */
+//colors
+$mountain-mist: #999 !default;
+$apple-blossom: #a94442 !default;
+$vanilla-ice: #f2dede !default;
+$oyster-pink: #ebccd1 !default;
+$gallery: #eee !default;
+$alto: #ddd !default;
+$green: #008000 !default;
+$mine-shaft: #333 !default;
+$boston-blue: #428bca !default;
+$tapa: #777 !default;
+$black: #000 !default;
+$black-20: rgba(0, 0, 0, 0.2);
+$black-30: rgba(0, 0, 0, 0.3);
+$black-40: rgba(0, 0, 0, 0.4);
+$mystic: #e1edf7 !default;
+$perano: #a1abff !default;
+$silver-chalice: #aaa !default;
+$viking: #5acde2 !default;
+$curious-blue: #1c94c4 !default;
+$link-water: #d9edf7 !default;
+
+//fonts
+$font-0: Impact !default;
+$font-1: Charcoal !default;
+$font-2: sans-serif !default;
+$font-3: Menlo !default;
+$font-4: Monaco !default;
+$font-5: Consolas !default;
+$font-6: "Courier New" !default;
+$font-7: monospace !default;
+
+//urls
+$url-0: url(../img/loading.gif) !default;
+$url-1: url(../img/loading-sm.gif) !default;
+
+//standard measures
+$radius: 4px !default;
+$pad: 5px !default;
+$border: 1px !default;
+
+//operations
+@function multiply($pixels, $multiplier) {
+    @return $pixels * $multiplier;
+}
+
+//@extend-elements
+%set-invisible {
+    width: 0;
+    height: 0;
+}
+
+%set-hidden {
+    display: none;
+}
+
+%set-absolute {
+    position: absolute;
+}
+
+%set-relative {
+    position: relative;
+}
+
+%set-text-left {
+    text-align: left;
+}
+
+%set-error {
+    @extend %set-text-left;
+    margin: 0;
+}
+
+%set-indicator {
+    margin: $pad 0 (-$pad);
+    width: multiply($pad, 3.2);
+    height: multiply($pad, 3.2);
+}
+
+%set-progress {
+    height: multiply($pad, 2.2);
+    font-size: multiply($pad, 1.8);
+}
+
+%set-caption {
+    display: block;
+    white-space: nowrap;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    width: multiply($pad, 32);
+    height: multiply($pad, 3);
+    margin: auto;
+}
+
+%set-object {
+    max-width: 100%;
+    max-height: 100%;
+    width: auto;
+}
+
+%set-object-video {
+    @extend %set-object;
+    height: 100%;
+}
+
+%set-object-default {
+    width: 100%;
+}
+
+.kv-hidden {
+    @extend %set-hidden;
+}
+
+.hide-content .kv-file-content {
+    @extend %set-hidden;
+}
+
+.file-input {
+    @extend %set-relative;
+}
+
+.file-no-browse {
+    @extend %set-absolute;
+    left: 50%;
+    bottom: 20%;
+    width: 1px;
+    height: 1px;
+    font-size: 0;
+    opacity: 0;
+    border: none;
+    background: none;
+    outline: none;
+    box-shadow: none;
+}
+
+.file-loading {
+    input[type=file] {
+        @extend %set-invisible;
+    }
+    &:before {
+        @extend %set-relative;
+        content: " Loading...";
+        display: inline-block;
+        padding-left: multiply($pad, 4);
+        line-height: multiply($pad, 3.2);
+        font-size: multiply($pad, 2.6);
+        font-variant: small-caps;
+        color: $mountain-mist;
+        background: transparent $url-0 top left no-repeat;
+    }
+}
+
+input[type=file].file-loading {
+    @extend %set-invisible;
+}
+
+.file-object {
+    margin: 0 0 (-$pad) 0;
+    padding: 0;
+}
+
+.btn-file {
+    @extend %set-relative;
+    overflow: hidden;
+    input[type=file] {
+        @extend %set-absolute;
+        top: 0;
+        left: 0;
+        min-width: 100%;
+        min-height: 100%;
+        text-align: right;
+        opacity: 0;
+        background: none repeat scroll 0 0 transparent;
+        cursor: inherit;
+        display: block;
+    }
+    ::-ms-browse {
+        font-size: multiply($pad, 2000);
+        width: 100%;
+        height: 100%;
+    }
+}
+
+.file-caption {
+    @extend %set-relative;
+    .file-caption-name {
+        width: 100%;
+        margin: 0;
+        padding: 0;
+        box-shadow: none;
+        border: none;
+        background: none;
+        outline: none;
+    }
+    &.icon-visible {
+        .file-caption-icon {
+            display: inline-block;
+        }
+        .file-caption-name {
+            padding-left: multiply($pad, 3);
+        }
+    }
+}
+
+.file-caption-icon {
+    @extend %set-hidden;
+    @extend %set-absolute;
+    left: multiply($pad, 1.6);
+}
+
+.file-error-message {
+    color: $apple-blossom;
+    background-color: $vanilla-ice;
+    margin: $pad;
+    border: $border solid $oyster-pink;
+    border-radius: $radius;
+    padding: multiply($pad, 3);
+    pre {
+        @extend %set-error;
+        margin: $pad 0;
+    }
+    ul {
+        @extend %set-error;
+    }
+}
+
+.file-caption-disabled {
+    background-color: $gallery;
+    cursor: not-allowed;
+    opacity: 1;
+}
+
+.file-preview {
+    @extend %set-relative;
+    border-radius: multiply($radius, 1.25);
+    border: $border solid $alto;
+    padding: multiply($pad, 1.6);
+    width: 100%;
+    margin-bottom: $pad;
+    .btn-xs {
+        padding: multiply($pad, 0.2) $pad;
+        font-size: multiply($pad, 2.4);
+        line-height: 1.5;
+        border-radius: multiply($radius, 0.75);
+    }
+    .fileinput-remove {
+        @extend %set-absolute;
+        top: multiply($pad, 0.2);
+        right: multiply($pad, 0.2);
+        line-height: multiply($pad, 2);
+    }
+    .clickable {
+        cursor: pointer;
+    }
+}
+
+.file-preview-image {
+    font: multiply($pad, 8) $font-0, $font-1, $font-2;
+    color: $green;
+}
+
+.krajee-default {
+    &.file-preview-frame {
+        @extend %set-relative;
+        margin: multiply($pad, 1.6);
+        border: $border solid $black-20;
+        box-shadow: 0 0 multiply($pad, 2) 0 $black-20;
+        padding: multiply($pad, 1.2);
+        float: left;
+        text-align: center;
+        .kv-file-content {
+            width: multiply($pad, 42.6);
+            height: multiply($pad, 32);
+            &.kv-pdf-rendered {
+                width: 400px;
+            }
+        }
+        .file-thumbnail-footer {
+            height: multiply($pad, 14);
+        }
+        &:not(.file-preview-error):hover {
+            border: $border solid $black-30;
+            box-shadow: 0 0 multiply($pad, 2) 0 $black-40;
+        }
+        &[data-template="audio"] .kv-file-content {
+            width: 240px;
+            height: 55px;
+        }
+    }
+    .file-preview-text {
+        display: block;
+        color: $boston-blue;
+        border: $border solid $alto;
+        font-family: $font-3, $font-4, $font-5, $font-6, $font-7;
+        outline: none;
+        padding: multiply($pad, 1.6);
+        resize: none;
+    }
+    .file-preview-html {
+        border: $border solid $alto;
+        padding: multiply($pad, 1.6);
+        overflow: auto;
+    }
+    .file-actions {
+        @extend %set-text-left;
+    }
+    .file-other-error {
+        @extend %set-text-left;
+    }
+    .file-other-icon {
+        font-size: 6em;
+    }
+    .file-footer-buttons {
+        float: right;
+    }
+    .file-footer-caption {
+        display: block;
+        text-align: center;
+        padding-top: multiply($pad, 0.8);
+        font-size: multiply($pad, 2.2);
+        color: $tapa;
+        margin-bottom: multiply($pad, 3);
+    }
+    .file-preview-error {
+        opacity: 0.65;
+        box-shadow: none;
+    }
+    .file-drag-handle {
+        @extend %set-indicator;
+    }
+    .file-upload-indicator {
+        @extend %set-indicator;
+    }
+    .file-thumb-progress {
+        @extend %set-absolute;
+        height: multiply($pad, 2.2);
+        top: multiply($pad, 7.4);
+        left: 0;
+        right: 0;
+        .progress {
+            @extend %set-progress;
+        }
+        .progress-bar {
+            @extend %set-progress;
+            font-family: Verdana, Helvetica, sans-serif;
+        }
+    }
+    .file-thumbnail-footer {
+        @extend %set-relative;
+    }
+    .file-caption-info {
+        @extend %set-caption;
+    }
+    .file-size-info {
+        @extend %set-caption;
+    }
+    &.kvsortable-ghost {
+        background: $mystic;
+        border: multiply($border, 2) solid $perano;
+    }
+    .file-preview-other:hover {
+        opacity: 0.8;
+    }
+    .file-preview-frame:not(.file-preview-error) .file-footer-caption:hover {
+        color: $black;
+    }
+}
+
+.kv-upload-progress {
+    .progress {
+        height: multiply($pad, 4);
+        line-height: multiply($pad, 4);
+        margin: multiply($pad, 2) 0;
+        overflow: hidden;
+    }
+    .progress-bar {
+        height: multiply($pad, 4);
+        font-family: Verdana, Helvetica, sans-serif;
+    }
+}
+
+.file-zoom-dialog {
+    .file-other-icon {
+        //noinspection CssOverwrittenProperties
+        font-size: 22em;
+        //noinspection CssOverwrittenProperties
+        font-size: 50vmin;
+    }
+    .modal-dialog {
+        @extend %set-relative;
+        width: auto;
+    }
+    .modal-header {
+        display: flex;
+        align-items: center;
+        justify-content: space-between;
+        &:before {
+            @extend %set-hidden;
+        }
+        &:after {
+            @extend %set-hidden;
+        }
+    }
+    .btn-navigate {
+        @extend %set-absolute;
+        padding: 0;
+        margin: 0;
+        background: transparent;
+        text-decoration: none;
+        outline: none;
+        opacity: 0.7;
+        top: 45%;
+        font-size: 4em;
+        color: $curious-blue;
+        &:not([disabled]):hover {
+            outline: none;
+            box-shadow: none;
+            opacity: 0.6;
+        }
+    }
+    .floating-buttons {
+        @extend %set-absolute;
+        top: $pad;
+        right: multiply($pad, 2);
+    }
+    .btn-navigate[disabled] {
+        opacity: 0.3;
+    }
+    .btn-prev {
+        left: multiply($pad, 0.2);
+    }
+    .btn-next {
+        right: multiply($pad, 0.2);
+    }
+    .kv-zoom-title {
+        font-weight: 300;
+        color: $mountain-mist;
+        max-width: 50%;
+        overflow: hidden;
+        white-space: nowrap;
+        text-overflow: ellipsis;
+    }
+}
+
+.file-input-new {
+    .file-preview {
+        @extend %set-hidden;
+    }
+    .close {
+        @extend %set-hidden;
+    }
+    .glyphicon-file {
+        @extend %set-hidden;
+    }
+    .fileinput-remove-button {
+        @extend %set-hidden;
+    }
+    .fileinput-upload-button {
+        @extend %set-hidden;
+    }
+    .no-browse {
+        .input-group-btn {
+            @extend %set-hidden;
+        }
+        .form-control {
+            border-top-right-radius: $radius;
+            border-bottom-right-radius: $radius;
+        }
+    }
+}
+
+.file-input-ajax-new {
+    .fileinput-remove-button {
+        @extend %set-hidden;
+    }
+    .fileinput-upload-button {
+        @extend %set-hidden;
+    }
+    .no-browse {
+        .input-group-btn {
+            @extend %set-hidden;
+        }
+        .form-control {
+            border-top-right-radius: $radius;
+            border-bottom-right-radius: $radius;
+        }
+    }
+}
+
+.file-caption-main {
+    width: 100%;
+}
+
+.file-thumb-loading {
+    background: transparent $url-0 no-repeat scroll center center content-box !important;
+}
+
+.file-drop-zone {
+    border: $border dashed $silver-chalice;
+    border-radius: $radius;
+    height: 100%;
+    text-align: center;
+    vertical-align: middle;
+    margin: multiply($pad, 2.4) multiply($pad, 3) multiply($pad, 2.4) multiply($pad, 2.4);
+    padding: $pad;
+    &.clickable {
+        &:hover {
+            border: multiply($border, 2) dashed $mountain-mist;
+        }
+        &:focus {
+            border: multiply($border, 2) solid $viking;
+        }
+    }
+    .file-preview-thumbnails {
+        cursor: default;
+    }
+}
+
+.file-drop-zone-title {
+    color: $silver-chalice;
+    font-size: 1.6em;
+    padding: multiply($pad, 17) multiply($pad, 2);
+    cursor: default;
+}
+
+.file-highlighted {
+    border: multiply($border, 2) dashed $mountain-mist !important;
+    background-color: $gallery;
+}
+
+.file-uploading {
+    background: $url-1 no-repeat center bottom multiply($pad, 2);
+    opacity: 0.65;
+}
+
+.file-zoom-fullscreen {
+    .modal-dialog {
+        min-width: 100%;
+        margin: 0;
+    }
+    .modal-content {
+        border-radius: 0;
+        box-shadow: none;
+        min-height: 100vh;
+    }
+    .modal-body {
+        overflow-y: auto;
+    }
+}
+
+.floating-buttons {
+    z-index: 3000;
+    .btn-kv {
+        margin-left: multiply($pad, 0.6);
+        z-index: 3000;
+    }
+}
+
+.file-zoom-content {
+    height: multiply($pad, 96);
+    text-align: center;
+    .file-preview-image {
+        max-height: 100%;
+    }
+    .file-preview-video {
+        max-height: 100%;
+    }
+    > .file-object {
+        &.type-image {
+            @extend %set-object;
+            height: auto;
+            min-height: inherit;
+        }
+        &.type-video {
+            @extend %set-object-video;
+        }
+        &.type-flash {
+            @extend %set-object-video;
+        }
+        &.type-audio {
+            width: auto;
+            height: multiply($pad, 6);
+        }
+        &.type-pdf {
+            @extend %set-object-default;
+        }
+        &.type-html {
+            @extend %set-object-default;
+        }
+        &.type-text {
+            @extend %set-object-default;
+        }
+        &.type-default {
+            @extend %set-object-default;
+        }
+    }
+}
+
+@media(min-width: 576px) {
+    .file-zoom-dialog .modal-dialog {
+        max-width: 500px;
+    }
+}
+
+@media(min-width: 992px) {
+    .file-zoom-dialog .modal-lg {
+        max-width: 800px;
+    }
+}
+
+@media(max-width: 767px) {
+    .file-preview-thumbnails {
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        flex-direction: column;
+    }
+    .file-zoom-dialog .modal-header {
+        flex-direction: column;
+    }
+}
+
+@media(max-width: 350px) {
+    .krajee-default.file-preview-frame:not([data-template="audio"]) .kv-file-content {
+        width: 160px;
+    }
+}
+
+@media(max-width: 420px) {
+    .krajee-default.file-preview-frame .kv-file-content.kv-pdf-rendered {
+        width: 100%;
+    }
+}
+
+.file-loading[dir=rtl]:before {
+    background: transparent $url-0 top right no-repeat;
+    padding-left: 0;
+    padding-right: multiply($pad, 4);
+}
+
+.file-sortable .file-drag-handle {
+    cursor: move;
+    opacity: 1;
+    &:hover {
+        opacity: 0.7;
+    }
+}
+
+.clickable .file-drop-zone-title {
+    cursor: pointer;
+}
+
+.kv-zoom-actions .btn-kv {
+    margin-left: multiply($pad, 0.6);
+}
+
+.file-preview-initial.sortable-chosen {
+    background-color: $link-water;
+}

+ 201 - 0
public/base/plugins/bootstrap-fileinput/scss/themes/explorer-fa/theme.scss

xqd
@@ -0,0 +1,201 @@
+/*!
+ * bootstrap-fileinput v4.5.2
+ * http://plugins.krajee.com/file-input
+ *
+ * Krajee Explorer Font Awesome theme style for bootstrap-fileinput. Load this theme file after loading `fileinput.css`.
+ *
+ * Author: Kartik Visweswaran
+ * Copyright: 2014 - 2018, Kartik Visweswaran, Krajee.com
+ *
+ * Licensed under the BSD 3-Clause
+ * https://github.com/kartik-v/bootstrap-fileinput/blob/master/LICENSE.md
+ */
+//colors
+$boston-blue: #428bca !default;
+$alto: #ddd !default;
+$tapa: #777 !default;
+$mystic: #e1edf7 !default;
+$perano: #a1abff !default;
+
+//fonts
+$font-0: Menlo !default;
+$font-1: Monaco !default;
+$font-2: Consolas !default;
+$font-3: "Courier New" !default;
+$font-4: monospace !default;
+
+//standard measures
+$pad: 5px !default;
+$border: 1px !default;
+$tablet: 767px !default;
+
+//operations
+@function multiply($pixels, $multiplier) {
+    @return $pixels * $multiplier;
+}
+
+//@extend-elements
+%set_text_center {
+    text-align: center;
+}
+
+%set_progress {
+    height: multiply($pad, 2.6);
+    font-size: multiply($pad, 2.2);
+    line-height: multiply($pad, 2.6);
+}
+
+%set_indicator {
+    position: absolute;
+    display: inline-block;
+    top: 0;
+    right: multiply($pad, 0.6);
+    width: multiply($pad, 3.2);
+    height: multiply($pad, 3.2);
+    font-size: multiply($pad, 3.2);
+    @extend %set_text_center;
+}
+
+%set_block {
+    display: block;
+}
+
+.theme-explorer-fa {
+    .explorer-frame {
+        td {
+            vertical-align: middle;
+            text-align: left;
+        }
+        .kv-file-content {
+            width: multiply($pad, 16);
+            height: multiply($pad, 16);
+            padding: $pad;
+            @extend %set_text_center;
+        }
+    }
+    .file-actions-cell {
+        position: relative;
+        width: multiply($pad, 24);
+        padding: 0;
+    }
+    .file-thumb-progress {
+        .progress {
+            @extend %set_block;
+            @extend %set_progress;
+            margin-top: $pad;
+        }
+        .progress-bar {
+            @extend %set_progress;
+        }
+    }
+    .file-upload-indicator {
+        @extend %set_indicator;
+    }
+    .file-drag-handle {
+        @extend %set_indicator;
+    }
+    .explorer-caption {
+        @extend %set_block;
+        color: $tapa;
+    }
+    .file-actions {
+        @extend %set_text_center;
+    }
+    .kvsortable-ghost {
+        opacity: 0.6;
+        background: $mystic;
+        border: multiply($border, 2) solid $perano;
+    }
+    .file-preview .table {
+        margin: 0;
+    }
+    .file-error-message ul {
+        padding: $pad 0 0 multiply($pad, 4);
+    }
+}
+
+.explorer-frame {
+    .file-preview-text {
+        display: inline-block;
+        color: $boston-blue;
+        border: $border solid $alto;
+        font-family: $font-0, $font-1, $font-2, $font-3, $font-4;
+        outline: none;
+        padding: multiply($pad, 1.6);
+        resize: none;
+    }
+    .file-preview-html {
+        display: inline-block;
+        border: $border solid $alto;
+        padding: multiply($pad, 1.6);
+        overflow: auto;
+    }
+    .file-preview-other {
+        @extend %set_text_center;
+    }
+    .file-other-icon {
+        font-size: 2.6em;
+    }
+}
+
+@media only screen and(max-width: $tablet) {
+    //@extend-elements
+    %set_block_full {
+        display: block;
+        width: 100% !important;
+    }
+    .theme-explorer-fa {
+        .table {
+            @extend %set_block_full;
+            border: none;
+            tbody {
+                @extend %set_block_full;
+            }
+            tr {
+                @extend %set_block_full;
+                margin-top: $pad;
+                &:first-child {
+                    margin-top: 0;
+                }
+            }
+            td {
+                @extend %set_block_full;
+                text-align: center;
+            }
+            .kv-file-content {
+                border-bottom: none;
+                padding: multiply($pad, 0.8);
+                margin: 0;
+                .file-preview-image {
+                    max-width: 100%;
+                    font-size: multiply($pad, 4);
+                }
+            }
+        }
+        .file-details-cell {
+            border-top: none;
+            border-bottom: none;
+            padding-top: 0;
+            margin: 0;
+        }
+        .file-actions-cell {
+            border-top: none;
+            padding-bottom: multiply($pad, 0.8);
+        }
+        .explorer-frame .explorer-caption {
+            white-space: nowrap;
+            text-overflow: ellipsis;
+            overflow: hidden;
+            left: 0;
+            right: 0;
+            margin: auto;
+        }
+    }
+}
+
+.file-zoom-dialog .explorer-frame .file-other-icon {
+    //noinspection CssOverwrittenProperties
+    font-size: 22em;
+    //noinspection CssOverwrittenProperties
+    font-size: 50vmin;
+}

+ 201 - 0
public/base/plugins/bootstrap-fileinput/scss/themes/explorer-fas/theme.scss

xqd
@@ -0,0 +1,201 @@
+/*!
+ * bootstrap-fileinput v4.5.2
+ * http://plugins.krajee.com/file-input
+ *
+ * Krajee Explorer Font Awesome theme style for bootstrap-fileinput. Load this theme file after loading `fileinput.css`.
+ *
+ * Author: Kartik Visweswaran
+ * Copyright: 2014 - 2018, Kartik Visweswaran, Krajee.com
+ *
+ * Licensed under the BSD 3-Clause
+ * https://github.com/kartik-v/bootstrap-fileinput/blob/master/LICENSE.md
+ */
+//colors
+$boston-blue: #428bca !default;
+$alto: #ddd !default;
+$tapa: #777 !default;
+$mystic: #e1edf7 !default;
+$perano: #a1abff !default;
+
+//fonts
+$font-0: Menlo !default;
+$font-1: Monaco !default;
+$font-2: Consolas !default;
+$font-3: "Courier New" !default;
+$font-4: monospace !default;
+
+//standard measures
+$pad: 5px !default;
+$border: 1px !default;
+$tablet: 767px !default;
+
+//operations
+@function multiply($pixels, $multiplier) {
+    @return $pixels * $multiplier;
+}
+
+//@extend-elements
+%set_text_center {
+    text-align: center;
+}
+
+%set_progress {
+    height: multiply($pad, 2.6);
+    font-size: multiply($pad, 2.2);
+    line-height: multiply($pad, 2.6);
+}
+
+%set_indicator {
+    position: absolute;
+    display: inline-block;
+    top: 0;
+    right: multiply($pad, 0.6);
+    width: multiply($pad, 3.2);
+    height: multiply($pad, 3.2);
+    font-size: multiply($pad, 3.2);
+    @extend %set_text_center;
+}
+
+%set_block {
+    display: block;
+}
+
+.theme-explorer-fa {
+    .explorer-frame {
+        td {
+            vertical-align: middle;
+            text-align: left;
+        }
+        .kv-file-content {
+            width: multiply($pad, 16);
+            height: multiply($pad, 16);
+            padding: $pad;
+            @extend %set_text_center;
+        }
+    }
+    .file-actions-cell {
+        position: relative;
+        width: multiply($pad, 24);
+        padding: 0;
+    }
+    .file-thumb-progress {
+        .progress {
+            @extend %set_block;
+            @extend %set_progress;
+            margin-top: $pad;
+        }
+        .progress-bar {
+            @extend %set_progress;
+        }
+    }
+    .file-upload-indicator {
+        @extend %set_indicator;
+    }
+    .file-drag-handle {
+        @extend %set_indicator;
+    }
+    .explorer-caption {
+        @extend %set_block;
+        color: $tapa;
+    }
+    .file-actions {
+        @extend %set_text_center;
+    }
+    .kvsortable-ghost {
+        opacity: 0.6;
+        background: $mystic;
+        border: multiply($border, 2) solid $perano;
+    }
+    .file-preview .table {
+        margin: 0;
+    }
+    .file-error-message ul {
+        padding: $pad 0 0 multiply($pad, 4);
+    }
+}
+
+.explorer-frame {
+    .file-preview-text {
+        display: inline-block;
+        color: $boston-blue;
+        border: $border solid $alto;
+        font-family: $font-0, $font-1, $font-2, $font-3, $font-4;
+        outline: none;
+        padding: multiply($pad, 1.6);
+        resize: none;
+    }
+    .file-preview-html {
+        display: inline-block;
+        border: $border solid $alto;
+        padding: multiply($pad, 1.6);
+        overflow: auto;
+    }
+    .file-preview-other {
+        @extend %set_text_center;
+    }
+    .file-other-icon {
+        font-size: 2.6em;
+    }
+}
+
+@media only screen and(max-width: $tablet) {
+    //@extend-elements
+    %set_block_full {
+        display: block;
+        width: 100% !important;
+    }
+    .theme-explorer-fa {
+        .table {
+            @extend %set_block_full;
+            border: none;
+            tbody {
+                @extend %set_block_full;
+            }
+            tr {
+                @extend %set_block_full;
+                margin-top: $pad;
+                &:first-child {
+                    margin-top: 0;
+                }
+            }
+            td {
+                @extend %set_block_full;
+                text-align: center;
+            }
+            .kv-file-content {
+                border-bottom: none;
+                padding: multiply($pad, 0.8);
+                margin: 0;
+                .file-preview-image {
+                    max-width: 100%;
+                    font-size: multiply($pad, 4);
+                }
+            }
+        }
+        .file-details-cell {
+            border-top: none;
+            border-bottom: none;
+            padding-top: 0;
+            margin: 0;
+        }
+        .file-actions-cell {
+            border-top: none;
+            padding-bottom: multiply($pad, 0.8);
+        }
+        .explorer-frame .explorer-caption {
+            white-space: nowrap;
+            text-overflow: ellipsis;
+            overflow: hidden;
+            left: 0;
+            right: 0;
+            margin: auto;
+        }
+    }
+}
+
+.file-zoom-dialog .explorer-frame .file-other-icon {
+    //noinspection CssOverwrittenProperties
+    font-size: 22em;
+    //noinspection CssOverwrittenProperties
+    font-size: 50vmin;
+}

+ 201 - 0
public/base/plugins/bootstrap-fileinput/scss/themes/explorer/theme.scss

xqd
@@ -0,0 +1,201 @@
+/*!
+ * bootstrap-fileinput v4.5.2
+ * http://plugins.krajee.com/file-input
+ *
+ * Krajee Explorer theme style for bootstrap-fileinput. Load this theme file after loading `fileinput.css`.
+ *
+ * Author: Kartik Visweswaran
+ * Copyright: 2014 - 2018, Kartik Visweswaran, Krajee.com
+ *
+ * Licensed under the BSD 3-Clause
+ * https://github.com/kartik-v/bootstrap-fileinput/blob/master/LICENSE.md
+ */
+//colors
+$boston-blue: #428bca !default;
+$alto: #ddd !default;
+$tapa: #777 !default;
+$mystic: #e1edf7 !default;
+$perano: #a1abff !default;
+
+//fonts
+$font-0: Menlo !default;
+$font-1: Monaco !default;
+$font-2: Consolas !default;
+$font-3: "Courier New" !default;
+$font-4: monospace !default;
+
+//standard measures
+$pad: 5px !default;
+$border: 1px !default;
+$tablet: 767px !default;
+
+//operations
+@function multiply($pixels, $multiplier) {
+    @return $pixels * $multiplier;
+}
+
+//@extend-elements
+%set_text_center {
+    text-align: center;
+}
+
+%set_progress {
+    height: multiply($pad, 2.6);
+    font-size: multiply($pad, 2.2);
+    line-height: multiply($pad, 2.6);
+}
+
+%set_indicator {
+    position: absolute;
+    display: inline-block;
+    top: 0;
+    right: multiply($pad, 0.6);
+    width: multiply($pad, 3.2);
+    height: multiply($pad, 3.2);
+    font-size: multiply($pad, 3.2);
+    @extend %set_text_center;
+}
+
+%set_block {
+    display: block;
+}
+
+.theme-explorer {
+    .explorer-frame {
+        td {
+            vertical-align: middle;
+            text-align: left;
+        }
+        .kv-file-content {
+            width: multiply($pad, 16);
+            height: multiply($pad, 16);
+            padding: $pad;
+            @extend %set_text_center;
+        }
+    }
+    .file-actions-cell {
+        position: relative;
+        width: multiply($pad, 24);
+        padding: 0;
+    }
+    .file-thumb-progress {
+        .progress {
+            @extend %set_block;
+            @extend %set_progress;
+            margin-top: $pad;
+        }
+        .progress-bar {
+            @extend %set_progress;
+        }
+    }
+    .file-upload-indicator {
+        @extend %set_indicator;
+    }
+    .file-drag-handle {
+        @extend %set_indicator;
+    }
+    .explorer-caption {
+        @extend %set_block;
+        color: $tapa;
+    }
+    .file-actions {
+        @extend %set_text_center;
+    }
+    .kvsortable-ghost {
+        opacity: 0.6;
+        background: $mystic;
+        border: multiply($border, 2) solid $perano;
+    }
+    .file-preview .table {
+        margin: 0;
+    }
+    .file-error-message ul {
+        padding: $pad 0 0 multiply($pad, 4);
+    }
+}
+
+.explorer-frame {
+    .file-preview-text {
+        display: inline-block;
+        color: $boston-blue;
+        border: $border solid $alto;
+        font-family: $font-0, $font-1, $font-2, $font-3, $font-4;
+        outline: none;
+        padding: multiply($pad, 1.6);
+        resize: none;
+    }
+    .file-preview-html {
+        display: inline-block;
+        border: $border solid $alto;
+        padding: multiply($pad, 1.6);
+        overflow: auto;
+    }
+    .file-preview-other {
+        @extend %set_text_center;
+    }
+    .file-other-icon {
+        font-size: 2.6em;
+    }
+}
+
+@media only screen and(max-width: $tablet) {
+    //@extend-elements
+    %set_block_full {
+        display: block;
+        width: 100% !important;
+    }
+    .theme-explorer {
+        .table {
+            @extend %set_block_full;
+            border: none;
+            tbody {
+                @extend %set_block_full;
+            }
+            tr {
+                @extend %set_block_full;
+                margin-top: $pad;
+                &:first-child {
+                    margin-top: 0;
+                }
+            }
+            td {
+                @extend %set_block_full;
+                text-align: center;
+            }
+            .kv-file-content {
+                border-bottom: none;
+                padding: multiply($pad, 0.8);
+                margin: 0;
+                .file-preview-image {
+                    max-width: 100%;
+                    font-size: multiply($pad, 4);
+                }
+            }
+        }
+        .file-details-cell {
+            border-top: none;
+            border-bottom: none;
+            padding-top: 0;
+            margin: 0;
+        }
+        .file-actions-cell {
+            border-top: none;
+            padding-bottom: multiply($pad, 0.8);
+        }
+        .explorer-frame .explorer-caption {
+            white-space: nowrap;
+            text-overflow: ellipsis;
+            overflow: hidden;
+            left: 0;
+            right: 0;
+            margin: auto;
+        }
+    }
+}
+
+.file-zoom-dialog .explorer-frame .file-other-icon {
+    //noinspection CssOverwrittenProperties
+    font-size: 22em;
+    //noinspection CssOverwrittenProperties
+    font-size: 50vmin;
+}

+ 157 - 0
public/base/plugins/bootstrap-fileinput/themes/explorer-fa/theme.css

xqd
@@ -0,0 +1,157 @@
+/*!
+ * bootstrap-fileinput v4.5.2
+ * http://plugins.krajee.com/file-input
+ *
+ * Krajee Explorer Font Awesome 4.x theme style for bootstrap-fileinput. Load this theme file after loading
+ * font awesome 4.x CSS and `fileinput.css`.
+ *
+ * Author: Kartik Visweswaran
+ * Copyright: 2014 - 2018, Kartik Visweswaran, Krajee.com
+ *
+ * Licensed under the BSD 3-Clause
+ * https://github.com/kartik-v/bootstrap-fileinput/blob/master/LICENSE.md
+ */
+.theme-explorer-fa .file-upload-indicator, .theme-explorer-fa .file-drag-handle, .theme-explorer-fa .explorer-frame .kv-file-content, .theme-explorer-fa .file-actions, .explorer-frame .file-preview-other {
+    text-align: center;
+}
+
+.theme-explorer-fa .file-thumb-progress .progress, .theme-explorer-fa .file-thumb-progress .progress-bar {
+    height: 13px;
+    font-size: 11px;
+    line-height: 13px;
+}
+
+.theme-explorer-fa .file-upload-indicator, .theme-explorer-fa .file-drag-handle {
+    position: absolute;
+    display: inline-block;
+    top: 0;
+    right: 3px;
+    width: 16px;
+    height: 16px;
+    font-size: 16px;
+}
+
+.theme-explorer-fa .file-thumb-progress .progress, .theme-explorer-fa .explorer-caption {
+    display: block;
+}
+
+.theme-explorer-fa .explorer-frame td {
+    vertical-align: middle;
+    text-align: left;
+}
+
+.theme-explorer-fa .explorer-frame .kv-file-content {
+    width: 80px;
+    height: 80px;
+    padding: 5px;
+}
+
+.theme-explorer-fa .file-actions-cell {
+    position: relative;
+    width: 120px;
+    padding: 0;
+}
+
+.theme-explorer-fa .file-thumb-progress .progress {
+    margin-top: 5px;
+}
+
+.theme-explorer-fa .explorer-caption {
+    color: #777;
+}
+
+.theme-explorer-fa .kvsortable-ghost {
+    opacity: 0.6;
+    background: #e1edf7;
+    border: 2px solid #a1abff;
+}
+
+.theme-explorer-fa .file-preview .table {
+    margin: 0;
+}
+
+.theme-explorer-fa .file-error-message ul {
+    padding: 5px 0 0 20px;
+}
+
+.explorer-frame .file-preview-text {
+    display: inline-block;
+    color: #428bca;
+    border: 1px solid #ddd;
+    font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
+    outline: none;
+    padding: 8px;
+    resize: none;
+}
+
+.explorer-frame .file-preview-html {
+    display: inline-block;
+    border: 1px solid #ddd;
+    padding: 8px;
+    overflow: auto;
+}
+
+.explorer-frame .file-other-icon {
+    font-size: 2.6em;
+}
+
+@media only screen and (max-width: 767px) {
+    .theme-explorer-fa .table, .theme-explorer-fa .table tbody, .theme-explorer-fa .table tr, .theme-explorer-fa .table td {
+        display: block;
+        width: 100% !important;
+    }
+
+    .theme-explorer-fa .table {
+        border: none;
+    }
+
+    .theme-explorer-fa .table tr {
+        margin-top: 5px;
+    }
+
+    .theme-explorer-fa .table tr:first-child {
+        margin-top: 0;
+    }
+
+    .theme-explorer-fa .table td {
+        text-align: center;
+    }
+
+    .theme-explorer-fa .table .kv-file-content {
+        border-bottom: none;
+        padding: 4px;
+        margin: 0;
+    }
+
+    .theme-explorer-fa .table .kv-file-content .file-preview-image {
+        max-width: 100%;
+        font-size: 20px;
+    }
+
+    .theme-explorer-fa .file-details-cell {
+        border-top: none;
+        border-bottom: none;
+        padding-top: 0;
+        margin: 0;
+    }
+
+    .theme-explorer-fa .file-actions-cell {
+        border-top: none;
+        padding-bottom: 4px;
+    }
+
+    .theme-explorer-fa .explorer-frame .explorer-caption {
+        white-space: nowrap;
+        text-overflow: ellipsis;
+        overflow: hidden;
+        left: 0;
+        right: 0;
+        margin: auto;
+    }
+}
+
+/*noinspection CssOverwrittenProperties*/
+.file-zoom-dialog .explorer-frame .file-other-icon {
+    font-size: 22em;
+    font-size: 50vmin;
+}

+ 87 - 0
public/base/plugins/bootstrap-fileinput/themes/explorer-fa/theme.js

xqd
@@ -0,0 +1,87 @@
+/*!
+ * bootstrap-fileinput v4.5.2
+ * http://plugins.krajee.com/file-input
+ *
+ * Krajee Explorer Font Awesome theme configuration for bootstrap-fileinput. 
+ * Load this theme file after loading `fileinput.js`. Ensure that
+ * font awesome assets and CSS are loaded on the page as well.
+ *
+ * Author: Kartik Visweswaran
+ * Copyright: 2014 - 2018, Kartik Visweswaran, Krajee.com
+ *
+ * Licensed under the BSD 3-Clause
+ * https://github.com/kartik-v/bootstrap-fileinput/blob/master/LICENSE.md
+ */
+(function ($) {
+    "use strict";
+    var teTagBef = '<tr class="file-preview-frame {frameClass}" id="{previewId}" data-fileindex="{fileindex}"' +
+        ' data-template="{template}"', teContent = '<td class="kv-file-content">\n';
+    $.fn.fileinputThemes['explorer-fa'] = {
+        layoutTemplates: {
+            preview: '<div class="file-preview {class}">\n' +
+            '    {close}' +
+            '    <div class="{dropClass}">\n' +
+            '    <table class="table table-bordered table-hover"><tbody class="file-preview-thumbnails">\n' +
+            '    </tbody></table>\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>',
+            footer: '<td class="file-details-cell"><div class="explorer-caption" title="{caption}">{caption}</div> ' +
+            '{size}{progress}</td><td class="file-actions-cell">{indicator} {actions}</td>',
+            actions: '{drag}\n' +
+            '<div class="file-actions">\n' +
+            '    <div class="file-footer-buttons">\n' +
+            '        {upload} {download} {delete} {zoom} {other} ' +
+            '    </div>\n' +
+            '</div>',
+            zoomCache: '<tr style="display:none" class="kv-zoom-cache-theme"><td>' +
+            '<table class="kv-zoom-cache">{zoomContent}</table></td></tr>',
+            fileIcon: '<i class="fa fa-file kv-caption-icon"></i> '
+        },
+        previewMarkupTags: {
+            tagBefore1: teTagBef + '>' + teContent,
+            tagBefore2: teTagBef + ' title="{caption}">' + teContent,
+            tagAfter: '</td>\n{footer}</tr>\n'
+        },
+        previewSettings: {
+            image: {height: "60px"},
+            html: {width: "100px", height: "60px"},
+            text: {width: "100px", height: "60px"},
+            video: {width: "auto", height: "60px"},
+            audio: {width: "auto", height: "60px"},
+            flash: {width: "100%", height: "60px"},
+            object: {width: "100%", height: "60px"},
+            pdf: {width: "100px", height: "60px"},
+            other: {width: "100%", height: "60px"}
+        },
+        frameClass: 'explorer-frame',
+        fileActionSettings: {
+            removeIcon: '<i class="fa fa-trash"></i>',
+            uploadIcon: '<i class="fa fa-upload"></i>',
+            uploadRetryIcon: '<i class="fa fa-repeat"></i>',
+            downloadIcon: '<i class="fa fa-download"></i>',
+            zoomIcon: '<i class="fa fa-search-plus"></i>',
+            dragIcon: '<i class="fa fa-arrows"></i>',
+            indicatorNew: '<i class="fa fa-plus-circle text-warning"></i>',
+            indicatorSuccess: '<i class="fa fa-check-circle text-success"></i>',
+            indicatorError: '<i class="fa fa-exclamation-circle text-danger"></i>',
+            indicatorLoading: '<i class="fa fa-hourglass text-muted"></i>'
+        },
+        previewZoomButtonIcons: {
+            prev: '<i class="fa fa-caret-left fa-lg"></i>',
+            next: '<i class="fa fa-caret-right fa-lg"></i>',
+            toggleheader: '<i class="fa fa-fw fa-arrows-v"></i>',
+            fullscreen: '<i class="fa fa-fw fa-arrows-alt"></i>',
+            borderless: '<i class="fa fa-fw fa-external-link"></i>',
+            close: '<i class="fa fa-fw fa-remove"></i>'
+        },
+        previewFileIcon: '<i class="fa fa-file"></i>',
+        browseIcon: '<i class="fa fa-folder-open"></i>',
+        removeIcon: '<i class="fa fa-trash"></i>',
+        cancelIcon: '<i class="fa fa-ban"></i>',
+        uploadIcon: '<i class="fa fa-upload"></i>',
+        msgValidationErrorIcon: '<i class="fa fa-exclamation-circle"></i> '
+    };
+})(window.jQuery);

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 12 - 0
public/base/plugins/bootstrap-fileinput/themes/explorer-fa/theme.min.css


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 13 - 0
public/base/plugins/bootstrap-fileinput/themes/explorer-fa/theme.min.js


+ 157 - 0
public/base/plugins/bootstrap-fileinput/themes/explorer-fas/theme.css

xqd
@@ -0,0 +1,157 @@
+/*!
+ * bootstrap-fileinput v4.5.2
+ * http://plugins.krajee.com/file-input
+ *
+ * Krajee Explorer Font Awesome 5.x theme style for bootstrap-fileinput. Load this theme file after loading
+ * font awesome 5.x CSS and `fileinput.css`.
+ *
+ * Author: Kartik Visweswaran
+ * Copyright: 2014 - 2018, Kartik Visweswaran, Krajee.com
+ *
+ * Licensed under the BSD 3-Clause
+ * https://github.com/kartik-v/bootstrap-fileinput/blob/master/LICENSE.md
+ */
+.theme-explorer-fas .file-upload-indicator, .theme-explorer-fas .file-drag-handle, .theme-explorer-fas .explorer-frame .kv-file-content, .theme-explorer-fas .file-actions, .explorer-frame .file-preview-other {
+    text-align: center;
+}
+
+.theme-explorer-fas .file-thumb-progress .progress, .theme-explorer-fas .file-thumb-progress .progress-bar {
+    height: 13px;
+    font-size: 11px;
+    line-height: 13px;
+}
+
+.theme-explorer-fas .file-upload-indicator, .theme-explorer-fas .file-drag-handle {
+    position: absolute;
+    display: inline-block;
+    top: 0;
+    right: 3px;
+    width: 16px;
+    height: 16px;
+    font-size: 16px;
+}
+
+.theme-explorer-fas .file-thumb-progress .progress, .theme-explorer-fas .explorer-caption {
+    display: block;
+}
+
+.theme-explorer-fas .explorer-frame td {
+    vertical-align: middle;
+    text-align: left;
+}
+
+.theme-explorer-fas .explorer-frame .kv-file-content {
+    width: 80px;
+    height: 80px;
+    padding: 5px;
+}
+
+.theme-explorer-fas .file-actions-cell {
+    position: relative;
+    width: 120px;
+    padding: 0;
+}
+
+.theme-explorer-fas .file-thumb-progress .progress {
+    margin-top: 5px;
+}
+
+.theme-explorer-fas .explorer-caption {
+    color: #777;
+}
+
+.theme-explorer-fas .kvsortable-ghost {
+    opacity: 0.6;
+    background: #e1edf7;
+    border: 2px solid #a1abff;
+}
+
+.theme-explorer-fas .file-preview .table {
+    margin: 0;
+}
+
+.theme-explorer-fas .file-error-message ul {
+    padding: 5px 0 0 20px;
+}
+
+.explorer-frame .file-preview-text {
+    display: inline-block;
+    color: #428bca;
+    border: 1px solid #ddd;
+    font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
+    outline: none;
+    padding: 8px;
+    resize: none;
+}
+
+.explorer-frame .file-preview-html {
+    display: inline-block;
+    border: 1px solid #ddd;
+    padding: 8px;
+    overflow: auto;
+}
+
+.explorer-frame .file-other-icon {
+    font-size: 2.6em;
+}
+
+@media only screen and (max-width: 767px) {
+    .theme-explorer-fas .table, .theme-explorer-fas .table tbody, .theme-explorer-fas .table tr, .theme-explorer-fas .table td {
+        display: block;
+        width: 100% !important;
+    }
+
+    .theme-explorer-fas .table {
+        border: none;
+    }
+
+    .theme-explorer-fas .table tr {
+        margin-top: 5px;
+    }
+
+    .theme-explorer-fas .table tr:first-child {
+        margin-top: 0;
+    }
+
+    .theme-explorer-fas .table td {
+        text-align: center;
+    }
+
+    .theme-explorer-fas .table .kv-file-content {
+        border-bottom: none;
+        padding: 4px;
+        margin: 0;
+    }
+
+    .theme-explorer-fas .table .kv-file-content .file-preview-image {
+        max-width: 100%;
+        font-size: 20px;
+    }
+
+    .theme-explorer-fas .file-details-cell {
+        border-top: none;
+        border-bottom: none;
+        padding-top: 0;
+        margin: 0;
+    }
+
+    .theme-explorer-fas .file-actions-cell {
+        border-top: none;
+        padding-bottom: 4px;
+    }
+
+    .theme-explorer-fas .explorer-frame .explorer-caption {
+        white-space: nowrap;
+        text-overflow: ellipsis;
+        overflow: hidden;
+        left: 0;
+        right: 0;
+        margin: auto;
+    }
+}
+
+/*noinspection CssOverwrittenProperties*/
+.file-zoom-dialog .explorer-frame .file-other-icon {
+    font-size: 22em;
+    font-size: 50vmin;
+}

+ 87 - 0
public/base/plugins/bootstrap-fileinput/themes/explorer-fas/theme.js

xqd
@@ -0,0 +1,87 @@
+/*!
+ * bootstrap-fileinput v4.5.2
+ * http://plugins.krajee.com/file-input
+ *
+ * Krajee Explorer Font Awesome theme configuration for bootstrap-fileinput. 
+ * Load this theme file after loading `fileinput.js`. Ensure that
+ * font awesome assets and CSS are loaded on the page as well.
+ *
+ * Author: Kartik Visweswaran
+ * Copyright: 2014 - 2018, Kartik Visweswaran, Krajee.com
+ *
+ * Licensed under the BSD 3-Clause
+ * https://github.com/kartik-v/bootstrap-fileinput/blob/master/LICENSE.md
+ */
+(function ($) {
+    "use strict";
+    var teTagBef = '<tr class="file-preview-frame {frameClass}" id="{previewId}" data-fileindex="{fileindex}"' +
+        ' data-template="{template}"', teContent = '<td class="kv-file-content">\n';
+    $.fn.fileinputThemes['explorer-fas'] = {
+        layoutTemplates: {
+            preview: '<div class="file-preview {class}">\n' +
+            '    {close}' +
+            '    <div class="{dropClass}">\n' +
+            '    <table class="table table-bordered table-hover"><tbody class="file-preview-thumbnails">\n' +
+            '    </tbody></table>\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>',
+            footer: '<td class="file-details-cell"><div class="explorer-caption" title="{caption}">{caption}</div> ' +
+            '{size}{progress}</td><td class="file-actions-cell">{indicator} {actions}</td>',
+            actions: '{drag}\n' +
+            '<div class="file-actions">\n' +
+            '    <div class="file-footer-buttons">\n' +
+            '        {upload} {download} {delete} {zoom} {other} ' +
+            '    </div>\n' +
+            '</div>',
+            zoomCache: '<tr style="display:none" class="kv-zoom-cache-theme"><td>' +
+            '<table class="kv-zoom-cache">{zoomContent}</table></td></tr>',
+            fileIcon: '<i class="fas fa-file kv-caption-icon"></i> '
+        },
+        previewMarkupTags: {
+            tagBefore1: teTagBef + '>' + teContent,
+            tagBefore2: teTagBef + ' title="{caption}">' + teContent,
+            tagAfter: '</td>\n{footer}</tr>\n'
+        },
+        previewSettings: {
+            image: {height: "60px"},
+            html: {width: "100px", height: "60px"},
+            text: {width: "100px", height: "60px"},
+            video: {width: "auto", height: "60px"},
+            audio: {width: "auto", height: "60px"},
+            flash: {width: "100%", height: "60px"},
+            object: {width: "100%", height: "60px"},
+            pdf: {width: "100px", height: "60px"},
+            other: {width: "100%", height: "60px"}
+        },
+        frameClass: 'explorer-frame',
+        fileActionSettings: {
+            removeIcon: '<i class="fas fa-trash-alt"></i>',
+            uploadIcon: '<i class="fas fa-upload"></i>',
+            uploadRetryIcon: '<i class="fas fa-redo-alt"></i>',
+            downloadIcon: '<i class="fas fa-download"></i>',
+            zoomIcon: '<i class="fas fa-search-plus"></i>',
+            dragIcon: '<i class="fas fa-arrows-alt"></i>',
+            indicatorNew: '<i class="fas fa-plus-circle text-warning"></i>',
+            indicatorSuccess: '<i class="fas fa-check-circle text-success"></i>',
+            indicatorError: '<i class="fas fa-exclamation-circle text-danger"></i>',
+            indicatorLoading: '<i class="fas fa-hourglass text-muted"></i>'
+        },
+        previewZoomButtonIcons: {
+            prev: '<i class="fas fa-caret-left fa-lg"></i>',
+            next: '<i class="fas fa-caret-right fa-lg"></i>',
+            toggleheader: '<i class="fas fa-fw fa-arrows-alt-v"></i>',
+            fullscreen: '<i class="fas fa-fw fa-arrows-alt"></i>',
+            borderless: '<i class="fas fa-fw fa-external-link-alt"></i>',
+            close: '<i class="fas fa-fw fa-times"></i>'
+        },
+        previewFileIcon: '<i class="fas fa-file"></i>',
+        browseIcon: '<i class="fas fa-folder-open"></i>',
+        removeIcon: '<i class="fas fa-trash-alt"></i>',
+        cancelIcon: '<i class="fas fa-ban"></i>',
+        uploadIcon: '<i class="fas fa-upload"></i>',
+        msgValidationErrorIcon: '<i class="fas fa-exclamation-circle"></i> '
+    };
+})(window.jQuery);

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 12 - 0
public/base/plugins/bootstrap-fileinput/themes/explorer-fas/theme.min.css


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 13 - 0
public/base/plugins/bootstrap-fileinput/themes/explorer-fas/theme.min.js


+ 156 - 0
public/base/plugins/bootstrap-fileinput/themes/explorer/theme.css

xqd
@@ -0,0 +1,156 @@
+/*!
+ * bootstrap-fileinput v4.5.2
+ * http://plugins.krajee.com/file-input
+ *
+ * Krajee Explorer theme style for bootstrap-fileinput. Load this theme file after loading `fileinput.css`.
+ *
+ * Author: Kartik Visweswaran
+ * Copyright: 2014 - 2018, Kartik Visweswaran, Krajee.com
+ *
+ * Licensed under the BSD 3-Clause
+ * https://github.com/kartik-v/bootstrap-fileinput/blob/master/LICENSE.md
+ */
+.theme-explorer .file-upload-indicator, .theme-explorer .file-drag-handle, .theme-explorer .explorer-frame .kv-file-content, .theme-explorer .file-actions, .explorer-frame .file-preview-other {
+    text-align: center;
+}
+
+.theme-explorer .file-thumb-progress .progress, .theme-explorer .file-thumb-progress .progress-bar {
+    height: 13px;
+    font-size: 11px;
+    line-height: 13px;
+}
+
+.theme-explorer .file-upload-indicator, .theme-explorer .file-drag-handle {
+    position: absolute;
+    display: inline-block;
+    top: 0;
+    right: 3px;
+    width: 16px;
+    height: 16px;
+    font-size: 16px;
+}
+
+.theme-explorer .file-thumb-progress .progress, .theme-explorer .explorer-caption {
+    display: block;
+}
+
+.theme-explorer .explorer-frame td {
+    vertical-align: middle;
+    text-align: left;
+}
+
+.theme-explorer .explorer-frame .kv-file-content {
+    width: 80px;
+    height: 80px;
+    padding: 5px;
+}
+
+.theme-explorer .file-actions-cell {
+    position: relative;
+    width: 120px;
+    padding: 0;
+}
+
+.theme-explorer .file-thumb-progress .progress {
+    margin-top: 5px;
+}
+
+.theme-explorer .explorer-caption {
+    color: #777;
+}
+
+.theme-explorer .kvsortable-ghost {
+    opacity: 0.6;
+    background: #e1edf7;
+    border: 2px solid #a1abff;
+}
+
+.theme-explorer .file-preview .table {
+    margin: 0;
+}
+
+.theme-explorer .file-error-message ul {
+    padding: 5px 0 0 20px;
+}
+
+.explorer-frame .file-preview-text {
+    display: inline-block;
+    color: #428bca;
+    border: 1px solid #ddd;
+    font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
+    outline: none;
+    padding: 8px;
+    resize: none;
+}
+
+.explorer-frame .file-preview-html {
+    display: inline-block;
+    border: 1px solid #ddd;
+    padding: 8px;
+    overflow: auto;
+}
+
+.explorer-frame .file-other-icon {
+    font-size: 2.6em;
+}
+
+@media only screen and (max-width: 767px) {
+    .theme-explorer .table, .theme-explorer .table tbody, .theme-explorer .table tr, .theme-explorer .table td {
+        display: block;
+        width: 100% !important;
+    }
+
+    .theme-explorer .table {
+        border: none;
+    }
+
+    .theme-explorer .table tr {
+        margin-top: 5px;
+    }
+
+    .theme-explorer .table tr:first-child {
+        margin-top: 0;
+    }
+
+    .theme-explorer .table td {
+        text-align: center;
+    }
+
+    .theme-explorer .table .kv-file-content {
+        border-bottom: none;
+        padding: 4px;
+        margin: 0;
+    }
+
+    .theme-explorer .table .kv-file-content .file-preview-image {
+        max-width: 100%;
+        font-size: 20px;
+    }
+
+    .theme-explorer .file-details-cell {
+        border-top: none;
+        border-bottom: none;
+        padding-top: 0;
+        margin: 0;
+    }
+
+    .theme-explorer .file-actions-cell {
+        border-top: none;
+        padding-bottom: 4px;
+    }
+
+    .theme-explorer .explorer-frame .explorer-caption {
+        white-space: nowrap;
+        text-overflow: ellipsis;
+        overflow: hidden;
+        left: 0;
+        right: 0;
+        margin: auto;
+    }
+}
+
+/*noinspection CssOverwrittenProperties*/
+.file-zoom-dialog .explorer-frame .file-other-icon {
+    font-size: 22em;
+    font-size: 50vmin;
+}

+ 58 - 0
public/base/plugins/bootstrap-fileinput/themes/explorer/theme.js

xqd
@@ -0,0 +1,58 @@
+/*!
+ * bootstrap-fileinput v4.5.2
+ * http://plugins.krajee.com/file-input
+ *
+ * Krajee Explorer theme configuration for bootstrap-fileinput. Load this theme file after loading `fileinput.js`.
+ *
+ * Author: Kartik Visweswaran
+ * Copyright: 2014 - 2018, Kartik Visweswaran, Krajee.com
+ *
+ * Licensed under the BSD 3-Clause
+ * https://github.com/kartik-v/bootstrap-fileinput/blob/master/LICENSE.md
+ */
+(function ($) {
+    "use strict";
+    var teTagBef = '<tr class="file-preview-frame {frameClass}" id="{previewId}" data-fileindex="{fileindex}"' +
+        ' data-template="{template}"', teContent = '<td class="kv-file-content">\n';
+    $.fn.fileinputThemes.explorer = {
+        layoutTemplates: {
+            preview: '<div class="file-preview {class}">\n' +
+            '    {close}' +
+            '    <div class="{dropClass}">\n' +
+            '    <table class="table table-bordered table-hover"><tbody class="file-preview-thumbnails">\n' +
+            '    </tbody></table>\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>',
+            footer: '<td class="file-details-cell"><div class="explorer-caption" title="{caption}">{caption}</div> ' +
+            '{size}{progress}</td><td class="file-actions-cell">{indicator} {actions}</td>',
+            actions: '{drag}\n' +
+            '<div class="file-actions">\n' +
+            '    <div class="file-footer-buttons">\n' +
+            '        {upload} {download} {delete} {zoom} {other} ' +
+            '    </div>\n' +
+            '</div>',
+            zoomCache: '<tr style="display:none" class="kv-zoom-cache-theme"><td>' +
+            '<table class="kv-zoom-cache">{zoomContent}</table></td></tr>'
+        },
+        previewMarkupTags: {
+            tagBefore1: teTagBef + '>' + teContent,
+            tagBefore2: teTagBef + ' title="{caption}">' + teContent,
+            tagAfter: '</td>\n{footer}</tr>\n'
+        },
+        previewSettings: {
+            image: {height: "60px"},
+            html: {width: "100px", height: "60px"},
+            text: {width: "100px", height: "60px"},
+            video: {width: "auto", height: "60px"},
+            audio: {width: "auto", height: "60px"},
+            flash: {width: "100%", height: "60px"},
+            object: {width: "100%", height: "60px"},
+            pdf: {width: "100px", height: "60px"},
+            other: {width: "100%", height: "60px"}
+        },
+        frameClass: 'explorer-frame'
+    };
+})(window.jQuery);

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 11 - 0
public/base/plugins/bootstrap-fileinput/themes/explorer/theme.min.css


+ 12 - 0
public/base/plugins/bootstrap-fileinput/themes/explorer/theme.min.js

xqd
@@ -0,0 +1,12 @@
+/*!
+ * bootstrap-fileinput v4.5.2
+ * http://plugins.krajee.com/file-input
+ *
+ * Krajee Explorer theme configuration for bootstrap-fileinput. Load this theme file after loading `fileinput.js`.
+ *
+ * Author: Kartik Visweswaran
+ * Copyright: 2014 - 2018, Kartik Visweswaran, Krajee.com
+ *
+ * Licensed under the BSD 3-Clause
+ * https://github.com/kartik-v/bootstrap-fileinput/blob/master/LICENSE.md
+ */!function(e){"use strict";var t='<tr class="file-preview-frame {frameClass}" id="{previewId}" data-fileindex="{fileindex}" data-template="{template}"',i='<td class="kv-file-content">\n';e.fn.fileinputThemes.explorer={layoutTemplates:{preview:'<div class="file-preview {class}">\n    {close}    <div class="{dropClass}">\n    <table class="table table-bordered table-hover"><tbody class="file-preview-thumbnails">\n    </tbody></table>\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>',footer:'<td class="file-details-cell"><div class="explorer-caption" title="{caption}">{caption}</div> {size}{progress}</td><td class="file-actions-cell">{indicator} {actions}</td>',actions:'{drag}\n<div class="file-actions">\n    <div class="file-footer-buttons">\n        {upload} {download} {delete} {zoom} {other}     </div>\n</div>',zoomCache:'<tr style="display:none" class="kv-zoom-cache-theme"><td><table class="kv-zoom-cache">{zoomContent}</table></td></tr>'},previewMarkupTags:{tagBefore1:t+">"+i,tagBefore2:t+' title="{caption}">'+i,tagAfter:"</td>\n{footer}</tr>\n"},previewSettings:{image:{height:"60px"},html:{width:"100px",height:"60px"},text:{width:"100px",height:"60px"},video:{width:"auto",height:"60px"},audio:{width:"auto",height:"60px"},flash:{width:"100%",height:"60px"},object:{width:"100%",height:"60px"},pdf:{width:"100px",height:"60px"},other:{width:"100%",height:"60px"}},frameClass:"explorer-frame"}}(window.jQuery);

+ 47 - 0
public/base/plugins/bootstrap-fileinput/themes/fa/theme.js

xqd
@@ -0,0 +1,47 @@
+/*!
+ * bootstrap-fileinput v4.5.2
+ * http://plugins.krajee.com/file-input
+ *
+ * Font Awesome icon theme configuration for bootstrap-fileinput. Requires font awesome assets to be loaded.
+ *
+ * Author: Kartik Visweswaran
+ * Copyright: 2014 - 2018, Kartik Visweswaran, Krajee.com
+ *
+ * Licensed under the BSD 3-Clause
+ * https://github.com/kartik-v/bootstrap-fileinput/blob/master/LICENSE.md
+ */
+(function ($) {
+    "use strict";
+
+    $.fn.fileinputThemes.fa = {
+        fileActionSettings: {
+            removeIcon: '<i class="fa fa-trash"></i>',
+            uploadIcon: '<i class="fa fa-upload"></i>',
+            uploadRetryIcon: '<i class="fa fa-repeat"></i>',
+            downloadIcon: '<i class="fa fa-download"></i>',
+            zoomIcon: '<i class="fa fa-search-plus"></i>',
+            dragIcon: '<i class="fa fa-arrows"></i>',
+            indicatorNew: '<i class="fa fa-plus-circle text-warning"></i>',
+            indicatorSuccess: '<i class="fa fa-check-circle text-success"></i>',
+            indicatorError: '<i class="fa fa-exclamation-circle text-danger"></i>',
+            indicatorLoading: '<i class="fa fa-hourglass text-muted"></i>'
+        },
+        layoutTemplates: {
+            fileIcon: '<i class="fa fa-file kv-caption-icon"></i> '
+        },
+        previewZoomButtonIcons: {
+            prev: '<i class="fa fa-caret-left fa-lg"></i>',
+            next: '<i class="fa fa-caret-right fa-lg"></i>',
+            toggleheader: '<i class="fa fa-fw fa-arrows-v"></i>',
+            fullscreen: '<i class="fa fa-fw fa-arrows-alt"></i>',
+            borderless: '<i class="fa fa-fw fa-external-link"></i>',
+            close: '<i class="fa fa-fw fa-remove"></i>'
+        },
+        previewFileIcon: '<i class="fa fa-file"></i>',
+        browseIcon: '<i class="fa fa-folder-open"></i>',
+        removeIcon: '<i class="fa fa-trash"></i>',
+        cancelIcon: '<i class="fa fa-ban"></i>',
+        uploadIcon: '<i class="fa fa-upload"></i>',
+        msgValidationErrorIcon: '<i class="fa fa-exclamation-circle"></i> '
+    };
+})(window.jQuery);

+ 12 - 0
public/base/plugins/bootstrap-fileinput/themes/fa/theme.min.js

xqd
@@ -0,0 +1,12 @@
+/*!
+ * bootstrap-fileinput v4.5.2
+ * http://plugins.krajee.com/file-input
+ *
+ * Font Awesome icon theme configuration for bootstrap-fileinput. Requires font awesome assets to be loaded.
+ *
+ * Author: Kartik Visweswaran
+ * Copyright: 2014 - 2018, Kartik Visweswaran, Krajee.com
+ *
+ * Licensed under the BSD 3-Clause
+ * https://github.com/kartik-v/bootstrap-fileinput/blob/master/LICENSE.md
+ */!function(a){"use strict";a.fn.fileinputThemes.fa={fileActionSettings:{removeIcon:'<i class="fa fa-trash"></i>',uploadIcon:'<i class="fa fa-upload"></i>',uploadRetryIcon:'<i class="fa fa-repeat"></i>',downloadIcon:'<i class="fa fa-download"></i>',zoomIcon:'<i class="fa fa-search-plus"></i>',dragIcon:'<i class="fa fa-arrows"></i>',indicatorNew:'<i class="fa fa-plus-circle text-warning"></i>',indicatorSuccess:'<i class="fa fa-check-circle text-success"></i>',indicatorError:'<i class="fa fa-exclamation-circle text-danger"></i>',indicatorLoading:'<i class="fa fa-hourglass text-muted"></i>'},layoutTemplates:{fileIcon:'<i class="fa fa-file kv-caption-icon"></i> '},previewZoomButtonIcons:{prev:'<i class="fa fa-caret-left fa-lg"></i>',next:'<i class="fa fa-caret-right fa-lg"></i>',toggleheader:'<i class="fa fa-fw fa-arrows-v"></i>',fullscreen:'<i class="fa fa-fw fa-arrows-alt"></i>',borderless:'<i class="fa fa-fw fa-external-link"></i>',close:'<i class="fa fa-fw fa-remove"></i>'},previewFileIcon:'<i class="fa fa-file"></i>',browseIcon:'<i class="fa fa-folder-open"></i>',removeIcon:'<i class="fa fa-trash"></i>',cancelIcon:'<i class="fa fa-ban"></i>',uploadIcon:'<i class="fa fa-upload"></i>',msgValidationErrorIcon:'<i class="fa fa-exclamation-circle"></i> '}}(window.jQuery);

+ 47 - 0
public/base/plugins/bootstrap-fileinput/themes/fas/theme.js

xqd
@@ -0,0 +1,47 @@
+/*!
+ * bootstrap-fileinput v4.5.2
+ * http://plugins.krajee.com/file-input
+ *
+ * Font Awesome 5 icon theme configuration for bootstrap-fileinput. Requires font awesome 5 assets to be loaded.
+ *
+ * Author: Kartik Visweswaran
+ * Copyright: 2014 - 2018, Kartik Visweswaran, Krajee.com
+ *
+ * Licensed under the BSD 3-Clause
+ * https://github.com/kartik-v/bootstrap-fileinput/blob/master/LICENSE.md
+ */
+(function ($) {
+    "use strict";
+
+    $.fn.fileinputThemes.fas = {
+        fileActionSettings: {
+            removeIcon: '<i class="fas fa-trash-alt"></i>',
+            uploadIcon: '<i class="fas fa-upload"></i>',
+            uploadRetryIcon: '<i class="fas fa-redo-alt"></i>',
+            downloadIcon: '<i class="fas fa-download"></i>',
+            zoomIcon: '<i class="fas fa-search-plus"></i>',
+            dragIcon: '<i class="fas fa-arrows-alt"></i>',
+            indicatorNew: '<i class="fas fa-plus-circle text-warning"></i>',
+            indicatorSuccess: '<i class="fas fa-check-circle text-success"></i>',
+            indicatorError: '<i class="fas fa-exclamation-circle text-danger"></i>',
+            indicatorLoading: '<i class="fas fa-hourglass text-muted"></i>'
+        },
+        layoutTemplates: {
+            fileIcon: '<i class="fas fa-file kv-caption-icon"></i> '
+        },
+        previewZoomButtonIcons: {
+            prev: '<i class="fas fa-caret-left fa-lg"></i>',
+            next: '<i class="fas fa-caret-right fa-lg"></i>',
+            toggleheader: '<i class="fas fa-fw fa-arrows-alt-v"></i>',
+            fullscreen: '<i class="fas fa-fw fa-arrows-alt"></i>',
+            borderless: '<i class="fas fa-fw fa-external-link-alt"></i>',
+            close: '<i class="fas fa-fw fa-times"></i>'
+        },
+        previewFileIcon: '<i class="fas fa-file"></i>',
+        browseIcon: '<i class="fas fa-folder-open"></i>',
+        removeIcon: '<i class="fas fa-trash-alt"></i>',
+        cancelIcon: '<i class="fas fa-ban"></i>',
+        uploadIcon: '<i class="fas fa-upload"></i>',
+        msgValidationErrorIcon: '<i class="fas fa-exclamation-circle"></i> '
+    };
+})(window.jQuery);

+ 12 - 0
public/base/plugins/bootstrap-fileinput/themes/fas/theme.min.js

xqd
@@ -0,0 +1,12 @@
+/*!
+ * bootstrap-fileinput v4.5.2
+ * http://plugins.krajee.com/file-input
+ *
+ * Font Awesome 5 icon theme configuration for bootstrap-fileinput. Requires font awesome 5 assets to be loaded.
+ *
+ * Author: Kartik Visweswaran
+ * Copyright: 2014 - 2018, Kartik Visweswaran, Krajee.com
+ *
+ * Licensed under the BSD 3-Clause
+ * https://github.com/kartik-v/bootstrap-fileinput/blob/master/LICENSE.md
+ */!function(a){"use strict";a.fn.fileinputThemes.fas={fileActionSettings:{removeIcon:'<i class="fas fa-trash-alt"></i>',uploadIcon:'<i class="fas fa-upload"></i>',uploadRetryIcon:'<i class="fas fa-redo-alt"></i>',downloadIcon:'<i class="fas fa-download"></i>',zoomIcon:'<i class="fas fa-search-plus"></i>',dragIcon:'<i class="fas fa-arrows-alt"></i>',indicatorNew:'<i class="fas fa-plus-circle text-warning"></i>',indicatorSuccess:'<i class="fas fa-check-circle text-success"></i>',indicatorError:'<i class="fas fa-exclamation-circle text-danger"></i>',indicatorLoading:'<i class="fas fa-hourglass text-muted"></i>'},layoutTemplates:{fileIcon:'<i class="fas fa-file kv-caption-icon"></i> '},previewZoomButtonIcons:{prev:'<i class="fas fa-caret-left fa-lg"></i>',next:'<i class="fas fa-caret-right fa-lg"></i>',toggleheader:'<i class="fas fa-fw fa-arrows-alt-v"></i>',fullscreen:'<i class="fas fa-fw fa-arrows-alt"></i>',borderless:'<i class="fas fa-fw fa-external-link-alt"></i>',close:'<i class="fas fa-fw fa-times"></i>'},previewFileIcon:'<i class="fas fa-file"></i>',browseIcon:'<i class="fas fa-folder-open"></i>',removeIcon:'<i class="fas fa-trash-alt"></i>',cancelIcon:'<i class="fas fa-ban"></i>',uploadIcon:'<i class="fas fa-upload"></i>',msgValidationErrorIcon:'<i class="fas fa-exclamation-circle"></i> '}}(window.jQuery);

+ 45 - 0
public/base/plugins/bootstrap-fileinput/themes/gly/theme.js

xqd
@@ -0,0 +1,45 @@
+/*!
+ * bootstrap-fileinput v4.5.2
+ * http://plugins.krajee.com/file-input
+ *
+ * Glyphicon (default) theme configuration for bootstrap-fileinput.
+ *
+ * Author: Kartik Visweswaran
+ * Copyright: 2014 - 2018, Kartik Visweswaran, Krajee.com
+ *
+ * Licensed under the BSD 3-Clause
+ * https://github.com/kartik-v/bootstrap-fileinput/blob/master/LICENSE.md
+ */
+(function ($) {
+    "use strict";
+
+    $.fn.fileinputThemes.gly = {
+        fileActionSettings: {
+            removeIcon: '<i class="glyphicon glyphicon-trash"></i>',
+            uploadIcon: '<i class="glyphicon glyphicon-upload"></i>',
+            zoomIcon: '<i class="glyphicon glyphicon-zoom-in"></i>',
+            dragIcon: '<i class="glyphicon glyphicon-move"></i>',
+            indicatorNew: '<i class="glyphicon glyphicon-plus-sign text-warning"></i>',
+            indicatorSuccess: '<i class="glyphicon glyphicon-ok-sign text-success"></i>',
+            indicatorError: '<i class="glyphicon glyphicon-exclamation-sign text-danger"></i>',
+            indicatorLoading: '<i class="glyphicon glyphicon-hourglass text-muted"></i>'
+        },
+        layoutTemplates: {
+            fileIcon: '<i class="glyphicon glyphicon-file kv-caption-icon"></i>'
+        },
+        previewZoomButtonIcons: {
+            prev: '<i class="glyphicon glyphicon-triangle-left"></i>',
+            next: '<i class="glyphicon glyphicon-triangle-right"></i>',
+            toggleheader: '<i class="glyphicon glyphicon-resize-vertical"></i>',
+            fullscreen: '<i class="glyphicon glyphicon-fullscreen"></i>',
+            borderless: '<i class="glyphicon glyphicon-resize-full"></i>',
+            close: '<i class="glyphicon glyphicon-remove"></i>'
+        },
+        previewFileIcon: '<i class="glyphicon glyphicon-file"></i>',
+        browseIcon: '<i class="glyphicon glyphicon-folder-open"></i>&nbsp;',
+        removeIcon: '<i class="glyphicon glyphicon-trash"></i>',
+        cancelIcon: '<i class="glyphicon glyphicon-ban-circle"></i>',
+        uploadIcon: '<i class="glyphicon glyphicon-upload"></i>',
+        msgValidationErrorIcon: '<i class="glyphicon glyphicon-exclamation-sign"></i> '
+    };
+})(window.jQuery);

+ 12 - 0
public/base/plugins/bootstrap-fileinput/themes/gly/theme.min.js

xqd
@@ -0,0 +1,12 @@
+/*!
+ * bootstrap-fileinput v4.5.2
+ * http://plugins.krajee.com/file-input
+ *
+ * Glyphicon (default) theme configuration for bootstrap-fileinput.
+ *
+ * Author: Kartik Visweswaran
+ * Copyright: 2014 - 2018, Kartik Visweswaran, Krajee.com
+ *
+ * Licensed under the BSD 3-Clause
+ * https://github.com/kartik-v/bootstrap-fileinput/blob/master/LICENSE.md
+ */!function(i){"use strict";i.fn.fileinputThemes.gly={fileActionSettings:{removeIcon:'<i class="glyphicon glyphicon-trash"></i>',uploadIcon:'<i class="glyphicon glyphicon-upload"></i>',zoomIcon:'<i class="glyphicon glyphicon-zoom-in"></i>',dragIcon:'<i class="glyphicon glyphicon-move"></i>',indicatorNew:'<i class="glyphicon glyphicon-plus-sign text-warning"></i>',indicatorSuccess:'<i class="glyphicon glyphicon-ok-sign text-success"></i>',indicatorError:'<i class="glyphicon glyphicon-exclamation-sign text-danger"></i>',indicatorLoading:'<i class="glyphicon glyphicon-hourglass text-muted"></i>'},layoutTemplates:{fileIcon:'<i class="glyphicon glyphicon-file kv-caption-icon"></i>'},previewZoomButtonIcons:{prev:'<i class="glyphicon glyphicon-triangle-left"></i>',next:'<i class="glyphicon glyphicon-triangle-right"></i>',toggleheader:'<i class="glyphicon glyphicon-resize-vertical"></i>',fullscreen:'<i class="glyphicon glyphicon-fullscreen"></i>',borderless:'<i class="glyphicon glyphicon-resize-full"></i>',close:'<i class="glyphicon glyphicon-remove"></i>'},previewFileIcon:'<i class="glyphicon glyphicon-file"></i>',browseIcon:'<i class="glyphicon glyphicon-folder-open"></i>&nbsp;',removeIcon:'<i class="glyphicon glyphicon-trash"></i>',cancelIcon:'<i class="glyphicon glyphicon-ban-circle"></i>',uploadIcon:'<i class="glyphicon glyphicon-upload"></i>',msgValidationErrorIcon:'<i class="glyphicon glyphicon-exclamation-sign"></i> '}}(window.jQuery);

+ 3 - 4
resources/views/admin/album/product/edit.blade.php

xqd
@@ -1,11 +1,10 @@
 @extends('admin.layout')
 @section('header')
 
-    <link href="/base/css/fileinput.css" media="all" rel="stylesheet" type="text/css" />
-
-    <script src="/base/js/fileinput.js" type="text/javascript"></script>
-    <script src="/base/js/fileinput_locale_zh.js" type="text/javascript"></script>
 
+    <link href="/base/plugins/bootstrap-fileinput/css/fileinput.css" media="all" rel="stylesheet" type="text/css"/>
+    <script src="/base/plugins/bootstrap-fileinput/js/fileinput.js" type="text/javascript"></script>
+    <script src="/base/plugins/bootstrap-fileinput/js/locales/zh.js" type="text/javascript"></script>
 @endsection
 @section('content')
 

Některé soubory nejsou zobrazeny, neboť je v těchto rozdílových datech změněno mnoho souborů