filepond-plugin-file-validate-type.esm.js 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. /*!
  2. * FilePondPluginFileValidateType 1.2.8
  3. * Licensed under MIT, https://opensource.org/licenses/MIT/
  4. * Please visit https://pqina.nl/filepond/ for details.
  5. */
  6. /* eslint-disable */
  7. const plugin = ({ addFilter, utils }) => {
  8. // get quick reference to Type utils
  9. const {
  10. Type,
  11. isString,
  12. replaceInString,
  13. guesstimateMimeType,
  14. getExtensionFromFilename,
  15. getFilenameFromURL
  16. } = utils;
  17. const mimeTypeMatchesWildCard = (mimeType, wildcard) => {
  18. const mimeTypeGroup = (/^[^/]+/.exec(mimeType) || []).pop(); // image/png -> image
  19. const wildcardGroup = wildcard.slice(0, -2); // image/* -> image
  20. return mimeTypeGroup === wildcardGroup;
  21. };
  22. const isValidMimeType = (acceptedTypes, userInputType) =>
  23. acceptedTypes.some(acceptedType => {
  24. // accepted is wildcard mime type
  25. if (/\*$/.test(acceptedType)) {
  26. return mimeTypeMatchesWildCard(userInputType, acceptedType);
  27. }
  28. // is normal mime type
  29. return acceptedType === userInputType;
  30. });
  31. const getItemType = item => {
  32. // if the item is a url we guess the mime type by the extension
  33. let type = '';
  34. if (isString(item)) {
  35. const filename = getFilenameFromURL(item);
  36. const extension = getExtensionFromFilename(filename);
  37. if (extension) {
  38. type = guesstimateMimeType(extension);
  39. }
  40. } else {
  41. type = item.type;
  42. }
  43. return type;
  44. };
  45. const validateFile = (item, acceptedFileTypes, typeDetector) => {
  46. // no types defined, everything is allowed \o/
  47. if (acceptedFileTypes.length === 0) {
  48. return true;
  49. }
  50. // gets the item type
  51. const type = getItemType(item);
  52. // no type detector, test now
  53. if (!typeDetector) {
  54. return isValidMimeType(acceptedFileTypes, type);
  55. }
  56. // use type detector
  57. return new Promise((resolve, reject) => {
  58. typeDetector(item, type)
  59. .then(detectedType => {
  60. if (isValidMimeType(acceptedFileTypes, detectedType)) {
  61. resolve();
  62. } else {
  63. reject();
  64. }
  65. })
  66. .catch(reject);
  67. });
  68. };
  69. const applyMimeTypeMap = map => acceptedFileType =>
  70. map[acceptedFileType] === null
  71. ? false
  72. : map[acceptedFileType] || acceptedFileType;
  73. // setup attribute mapping for accept
  74. addFilter('SET_ATTRIBUTE_TO_OPTION_MAP', map =>
  75. Object.assign(map, {
  76. accept: 'acceptedFileTypes'
  77. })
  78. );
  79. // filtering if an item is allowed in hopper
  80. addFilter('ALLOW_HOPPER_ITEM', (file, { query }) => {
  81. // if we are not doing file type validation exit
  82. if (!query('GET_ALLOW_FILE_TYPE_VALIDATION')) {
  83. return true;
  84. }
  85. // we validate the file against the accepted file types
  86. return validateFile(file, query('GET_ACCEPTED_FILE_TYPES'));
  87. });
  88. // called for each file that is loaded
  89. // right before it is set to the item state
  90. // should return a promise
  91. addFilter(
  92. 'LOAD_FILE',
  93. (file, { query }) =>
  94. new Promise((resolve, reject) => {
  95. if (!query('GET_ALLOW_FILE_TYPE_VALIDATION')) {
  96. resolve(file);
  97. return;
  98. }
  99. const acceptedFileTypes = query('GET_ACCEPTED_FILE_TYPES');
  100. // custom type detector method
  101. const typeDetector = query('GET_FILE_VALIDATE_TYPE_DETECT_TYPE');
  102. // if invalid, exit here
  103. const validationResult = validateFile(
  104. file,
  105. acceptedFileTypes,
  106. typeDetector
  107. );
  108. const handleRejection = () => {
  109. const acceptedFileTypesMapped = acceptedFileTypes
  110. .map(
  111. applyMimeTypeMap(
  112. query('GET_FILE_VALIDATE_TYPE_LABEL_EXPECTED_TYPES_MAP')
  113. )
  114. )
  115. .filter(label => label !== false);
  116. const acceptedFileTypesMapped_unique = acceptedFileTypesMapped.filter(
  117. function(item, index) {
  118. return acceptedFileTypesMapped.indexOf(item) === index;
  119. }
  120. );
  121. reject({
  122. status: {
  123. main: query('GET_LABEL_FILE_TYPE_NOT_ALLOWED'),
  124. sub: replaceInString(
  125. query('GET_FILE_VALIDATE_TYPE_LABEL_EXPECTED_TYPES'),
  126. {
  127. allTypes: acceptedFileTypesMapped_unique.join(', '),
  128. allButLastType: acceptedFileTypesMapped_unique
  129. .slice(0, -1)
  130. .join(', '),
  131. lastType:
  132. acceptedFileTypesMapped_unique[
  133. acceptedFileTypesMapped.length - 1
  134. ]
  135. }
  136. )
  137. }
  138. });
  139. };
  140. // has returned new filename immidiately
  141. if (typeof validationResult === 'boolean') {
  142. if (!validationResult) {
  143. return handleRejection();
  144. }
  145. return resolve(file);
  146. }
  147. // is promise
  148. validationResult
  149. .then(() => {
  150. resolve(file);
  151. })
  152. .catch(handleRejection);
  153. })
  154. );
  155. // expose plugin
  156. return {
  157. // default options
  158. options: {
  159. // Enable or disable file type validation
  160. allowFileTypeValidation: [true, Type.BOOLEAN],
  161. // What file types to accept
  162. acceptedFileTypes: [[], Type.ARRAY],
  163. // - must be comma separated
  164. // - mime types: image/png, image/jpeg, image/gif
  165. // - extensions: .png, .jpg, .jpeg ( not enabled yet )
  166. // - wildcards: image/*
  167. // label to show when a type is not allowed
  168. labelFileTypeNotAllowed: ['File is of invalid type', Type.STRING],
  169. // nicer label
  170. fileValidateTypeLabelExpectedTypes: [
  171. 'Expects {allButLastType} or {lastType}',
  172. Type.STRING
  173. ],
  174. // map mime types to extensions
  175. fileValidateTypeLabelExpectedTypesMap: [{}, Type.OBJECT],
  176. // Custom function to detect type of file
  177. fileValidateTypeDetectType: [null, Type.FUNCTION]
  178. }
  179. };
  180. };
  181. // fire pluginloaded event if running in browser, this allows registering the plugin when using async script tags
  182. const isBrowser =
  183. typeof window !== 'undefined' && typeof window.document !== 'undefined';
  184. if (isBrowser) {
  185. document.dispatchEvent(
  186. new CustomEvent('FilePond:pluginloaded', { detail: plugin })
  187. );
  188. }
  189. export default plugin;