bootstrap-fileselect.js 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. /*!
  2. * Bootstrap Fileselect v3.1.2
  3. * (c) 2016-2020 Jonathan Nessier, Neoflow
  4. * Licensed under MIT (https://github.com/Neoflow/Bootstrap-Fileselect/blob/master/LICENSE)
  5. */
  6. (function (window, $) {
  7. const Fileselect = function (fileInput, options) {
  8. this.$fileInput = $(fileInput);
  9. this.options = options;
  10. this.userLanguage = 'en';
  11. this.$fileselect = $(this);
  12. this.metadata = this.$fileInput.data();
  13. this.$inputGroup = $('<div>').addClass('custom-file');
  14. this.$labelInput = $('<label>').addClass('custom-file-label');
  15. this.translations = {
  16. 'en': {
  17. 'chooseFile': 'Choose file...',
  18. 'chooseFiles': 'Choose files...',
  19. 'browse': 'Browse',
  20. 'rules': {
  21. 'numberOfFiles': 'The number of uploadable files is limited to [num] file(s)',
  22. 'fileExtensions': 'The files are restricted to the following file extensions: [ext]',
  23. 'fileSize': 'The file size is limited to [size]',
  24. }
  25. },
  26. };
  27. this.init();
  28. };
  29. Fileselect.prototype = {
  30. defaults: {
  31. restyling: true,
  32. allowedFileSize: false,
  33. allowedFileExtensions: false,
  34. allowedNumberOfFiles: false,
  35. language: false,
  36. translations: {},
  37. validationCallback: function (message, instance) {
  38. alert(message);
  39. }
  40. },
  41. init: function () {
  42. this.config = this.loadConfig();
  43. this.translations = this.loadTranslation();
  44. if (this.config.restyling) {
  45. this.$fileInput
  46. .addClass('custom-file-input')
  47. .before(this.$inputGroup);
  48. this.$inputGroup
  49. .append(this.$fileInput, this.$labelInput);
  50. this.$labelInput.attr('data-browse', this.translations.browse);
  51. this.$labelInput.css({
  52. 'overflow': 'hidden'
  53. });
  54. if (this.$fileInput[0].hasAttribute("multiple")) {
  55. this.$labelInput.text(this.translations.chooseFiles);
  56. } else {
  57. this.$labelInput.text(this.translations.chooseFile);
  58. }
  59. }
  60. this.$fileInput.on('change', $.proxy(this.changeEvent, this));
  61. return $(this);
  62. },
  63. changeEvent: function (e) {
  64. this.$fileInput.trigger('bs.fs.change', [this]);
  65. const files = this.$fileInput[0].files,
  66. label = $.map(files, function (file) {
  67. return file.name;
  68. }).join(', ');
  69. let result = false;
  70. if (this.validateNumberOfFiles(files) && this.validateFileExtensions(files) && this.validateFileSize(files)) {
  71. this.$labelInput.text(label);
  72. result = true;
  73. } else {
  74. this.$fileInput.val(null);
  75. }
  76. this.$fileInput.trigger('bs.fs.changed', [this]);
  77. return result;
  78. },
  79. loadConfig: function () {
  80. let config = $.extend({}, this.defaults, this.options, this.metadata);
  81. if (typeof config.allowedFileExtensions === 'string') {
  82. config.allowedFileExtensions = config.allowedFileExtensions.split(',');
  83. }
  84. return config;
  85. },
  86. loadTranslation: function () {
  87. $.each(this.config.translations, $.proxy(function (language, translations) {
  88. this.translations[language] = translations
  89. }, this));
  90. let userLanguage = (this.config.language || navigator.language || navigator.userLanguage).substring(0, 2).toLowerCase(),
  91. translatedLanguages = $.map(this.translations, function (translations, key) {
  92. return key;
  93. });
  94. if ($.inArray(userLanguage, translatedLanguages) >= 0) {
  95. this.userLanguage = userLanguage;
  96. } else {
  97. // console.info('User language (' + userLanguage + ') has no translation. Switched to default language (' + this.userLanguage + ').')
  98. }
  99. return this.translations[this.userLanguage];
  100. },
  101. validateNumberOfFiles: function (files) {
  102. this.$fileInput
  103. .trigger('bs.fs.validate', [this])
  104. .trigger('bs.fs.number-of-files-validate', [this]);
  105. let result = true;
  106. if (this.config.allowedNumberOfFiles && files.length > parseInt(this.config.allowedNumberOfFiles)) {
  107. this.config.validationCallback(this.translations.rules.numberOfFiles.replace('[num]', this.config.allowedNumberOfFiles), 'allowedNumberOfFiles', this);
  108. result = false;
  109. }
  110. this.$fileInput
  111. .trigger('bs.fs.validated', [this])
  112. .trigger('bs.fs.number-of-files-validated', [this]);
  113. return result;
  114. },
  115. validateFileExtensions: function (files) {
  116. this.$fileInput
  117. .trigger('bs.fs.validate', [this])
  118. .trigger('bs.fs.file-extensions-validate', [this]);
  119. let result = true;
  120. if (this.config.allowedFileExtensions) {
  121. $.each(files, $.proxy(function (i, file) {
  122. var fileExtension = file.name.replace(/^.*\./, '').toLowerCase();
  123. if ($.inArray(fileExtension, this.config.allowedFileExtensions) === -1) {
  124. this.config.validationCallback(this.translations.rules.fileExtensions.replace('[ext]', this.config.allowedFileExtensions.join(', ')), 'allowedFileExtensions', this);
  125. result = false;
  126. return;
  127. }
  128. }, this));
  129. }
  130. this.$fileInput
  131. .trigger('bs.fs.validated', [this])
  132. .trigger('bs.fs.file-extensions-validated', [this]);
  133. return result;
  134. },
  135. validateFileSize: function (files) {
  136. this.$fileInput
  137. .trigger('bs.fs.validate', [this])
  138. .trigger('bs.fs.file-size-validate', [this]);
  139. let result = true;
  140. if (this.config.allowedFileSize) {
  141. $.each(files, $.proxy(function (i, file) {
  142. if (file.size > this.config.allowedFileSize) {
  143. this.config.validationCallback(this.translations.rules.fileSize.replace('[size]', Math.round(this.config.allowedFileSize / 1024 / 1024) + 'MB'), 'allowedFileSize', this);
  144. result = false;
  145. return;
  146. }
  147. }, this));
  148. }
  149. this.$fileInput
  150. .trigger('bs.fs.validated', [this])
  151. .trigger('bs.fs.file-size-validated', [this]);
  152. return result;
  153. },
  154. };
  155. Fileselect.defaults = Fileselect.prototype.defaults;
  156. $.fn.fileselect = function (options) {
  157. this.each(function () {
  158. new Fileselect(this, options);
  159. });
  160. return this;
  161. };
  162. window.Fileselect = Fileselect;
  163. })(window, jQuery);