From 5c3bb7a4491eda9de5f144a7ef27ad6e7e97b76a Mon Sep 17 00:00:00 2001 From: Will Vincent Date: Tue, 21 Nov 2023 15:27:14 -0600 Subject: [PATCH 1/2] Add min/max file size limits by mime type. --- .../filepond-plugin-file-validate-size.esm.js | 55 +++++++++++++ ...epond-plugin-file-validate-size.esm.min.js | 2 +- dist/filepond-plugin-file-validate-size.js | 56 +++++++++++++ .../filepond-plugin-file-validate-size.min.js | 2 +- src/js/index.js | 80 ++++++++++++++++++- types/index.d.ts | 4 + 6 files changed, 196 insertions(+), 3 deletions(-) diff --git a/dist/filepond-plugin-file-validate-size.esm.js b/dist/filepond-plugin-file-validate-size.esm.js index 0d345d4..85e658f 100644 --- a/dist/filepond-plugin-file-validate-size.esm.js +++ b/dist/filepond-plugin-file-validate-size.esm.js @@ -47,6 +47,58 @@ const plugin = ({ addFilter, utils }) => { return resolve(file); } + // reject or resolve base on file size by mime type + const mimeSizes = query('GET_MIME_FILE_SIZE'); + if (mimeSizes !== null) { + // It's unclear how the query('GET_MAX_FILE_SIZE') is converting strings + // like '5mb' to ints like 5000000, so hacking behavior in here for + // mime-based limits. Ideally should use the same logic the other + // max file size limit uses, but api documentation is virtually + // non existent. :( + + const _strToBytes = str => { + const multiplier = { + b: 1, + kb: 1000, + mb: 1000 ** 2, + gb: 1000 ** 3, + tb: 1000 ** 4, + pb: 1000 ** 5, + }; + const num = Number(str.match(/\d/).toString()); + const type = str + .match(/[a-zA-Z]+/) + .toString() + .toLowerCase(); + return num * multiplier[type]; + }; + + Object.keys(mimeSizes).forEach(mime => { + if ( + file.type === mime || + (mime.substring(2, -2) === '/*' && + file.type.split('/')[0] === mime.slice(0, -2)) + ) { + if (file.size > _strToBytes(mimeSizes[mime])) { + reject({ + status: { + main: query('GET_LABEL_MAX_FILE_SIZE_EXCEEDED'), + sub: replaceInString(query('GET_LABEL_MAX_FILE_SIZE'), { + filesize: toNaturalFileSize( + _strToBytes(mimeSizes[mime]), + '.', + query('GET_FILE_SIZE_BASE'), + query('GET_FILE_SIZE_LABELS', query) + ), + }), + }, + }); + return; + } + } + }); + } + // reject or resolve based on file size const sizeMax = query('GET_MAX_FILE_SIZE'); if (sizeMax !== null && file.size > sizeMax) { @@ -122,6 +174,9 @@ const plugin = ({ addFilter, utils }) => { // Enable or disable file type validation allowFileSizeValidation: [true, Type.BOOLEAN], + // Max individual file size in bytes by mime type + mimeSizes: [null, Type.OBJECT], + // Max individual file size in bytes maxFileSize: [null, Type.INT], diff --git a/dist/filepond-plugin-file-validate-size.esm.min.js b/dist/filepond-plugin-file-validate-size.esm.min.js index 7e09ebe..1681a7d 100644 --- a/dist/filepond-plugin-file-validate-size.esm.min.js +++ b/dist/filepond-plugin-file-validate-size.esm.min.js @@ -6,4 +6,4 @@ /* eslint-disable */ -const e=({addFilter:e,utils:E})=>{const{Type:i,replaceInString:_,toNaturalFileSize:l}=E;return e("ALLOW_HOPPER_ITEM",(e,{query:E})=>{if(!E("GET_ALLOW_FILE_SIZE_VALIDATION"))return!0;const i=E("GET_MAX_FILE_SIZE");if(null!==i&&e.size>i)return!1;const _=E("GET_MIN_FILE_SIZE");return!(null!==_&&e.size<_)}),e("LOAD_FILE",(e,{query:E})=>new Promise((i,I)=>{if(!E("GET_ALLOW_FILE_SIZE_VALIDATION"))return i(e);const L=E("GET_FILE_VALIDATE_SIZE_FILTER");if(L&&!L(e))return i(e);const t=E("GET_MAX_FILE_SIZE");if(null!==t&&e.size>t)return void I({status:{main:E("GET_LABEL_MAX_FILE_SIZE_EXCEEDED"),sub:_(E("GET_LABEL_MAX_FILE_SIZE"),{filesize:l(t,".",E("GET_FILE_SIZE_BASE"),E("GET_FILE_SIZE_LABELS",E))})}});const n=E("GET_MIN_FILE_SIZE");if(null!==n&&e.sizee+E.fileSize,0)>T)return void I({status:{main:E("GET_LABEL_MAX_TOTAL_FILE_SIZE_EXCEEDED"),sub:_(E("GET_LABEL_MAX_TOTAL_FILE_SIZE"),{filesize:l(T,".",E("GET_FILE_SIZE_BASE"),E("GET_FILE_SIZE_LABELS",E))})}})}i(e)})),{options:{allowFileSizeValidation:[!0,i.BOOLEAN],maxFileSize:[null,i.INT],minFileSize:[null,i.INT],maxTotalFileSize:[null,i.INT],fileValidateSizeFilter:[null,i.FUNCTION],labelMinFileSizeExceeded:["File is too small",i.STRING],labelMinFileSize:["Minimum file size is {filesize}",i.STRING],labelMaxFileSizeExceeded:["File is too large",i.STRING],labelMaxFileSize:["Maximum file size is {filesize}",i.STRING],labelMaxTotalFileSizeExceeded:["Maximum total size exceeded",i.STRING],labelMaxTotalFileSize:["Maximum total file size is {filesize}",i.STRING]}}};"undefined"!=typeof window&&void 0!==window.document&&document.dispatchEvent(new CustomEvent("FilePond:pluginloaded",{detail:e}));export default e; +const e=({addFilter:e,utils:E})=>{const{Type:i,replaceInString:_,toNaturalFileSize:l}=E;return e("ALLOW_HOPPER_ITEM",(e,{query:E})=>{if(!E("GET_ALLOW_FILE_SIZE_VALIDATION"))return!0;const i=E("GET_MAX_FILE_SIZE");if(null!==i&&e.size>i)return!1;const _=E("GET_MIN_FILE_SIZE");return!(null!==_&&e.size<_)}),e("LOAD_FILE",(e,{query:E})=>new Promise((i,I)=>{if(!E("GET_ALLOW_FILE_SIZE_VALIDATION"))return i(e);const t=E("GET_FILE_VALIDATE_SIZE_FILTER");if(t&&!t(e))return i(e);const L=E("GET_MIME_FILE_SIZE");if(null!==L){const i=e=>{return Number(e.match(/\d/).toString())*{b:1,kb:1e3,mb:1e6,gb:1e9,tb:1e12,pb:1e15}[e.match(/[a-zA-Z]+/).toString().toLowerCase()]};Object.keys(L).forEach(t=>{(e.type===t||"/*"===t.substring(2,-2)&&e.type.split("/")[0]===t.slice(0,-2))&&e.size>i(L[t])&&I({status:{main:E("GET_LABEL_MAX_FILE_SIZE_EXCEEDED"),sub:_(E("GET_LABEL_MAX_FILE_SIZE"),{filesize:l(i(L[t]),".",E("GET_FILE_SIZE_BASE"),E("GET_FILE_SIZE_LABELS",E))})}})})}const n=E("GET_MAX_FILE_SIZE");if(null!==n&&e.size>n)return void I({status:{main:E("GET_LABEL_MAX_FILE_SIZE_EXCEEDED"),sub:_(E("GET_LABEL_MAX_FILE_SIZE"),{filesize:l(n,".",E("GET_FILE_SIZE_BASE"),E("GET_FILE_SIZE_LABELS",E))})}});const S=E("GET_MIN_FILE_SIZE");if(null!==S&&e.sizee+E.fileSize,0)>s)return void I({status:{main:E("GET_LABEL_MAX_TOTAL_FILE_SIZE_EXCEEDED"),sub:_(E("GET_LABEL_MAX_TOTAL_FILE_SIZE"),{filesize:l(s,".",E("GET_FILE_SIZE_BASE"),E("GET_FILE_SIZE_LABELS",E))})}})}i(e)})),{options:{allowFileSizeValidation:[!0,i.BOOLEAN],mimeSizes:[null,i.OBJECT],maxFileSize:[null,i.INT],minFileSize:[null,i.INT],maxTotalFileSize:[null,i.INT],fileValidateSizeFilter:[null,i.FUNCTION],labelMinFileSizeExceeded:["File is too small",i.STRING],labelMinFileSize:["Minimum file size is {filesize}",i.STRING],labelMaxFileSizeExceeded:["File is too large",i.STRING],labelMaxFileSize:["Maximum file size is {filesize}",i.STRING],labelMaxTotalFileSizeExceeded:["Maximum total size exceeded",i.STRING],labelMaxTotalFileSize:["Maximum total file size is {filesize}",i.STRING]}}};"undefined"!=typeof window&&void 0!==window.document&&document.dispatchEvent(new CustomEvent("FilePond:pluginloaded",{detail:e}));export default e; diff --git a/dist/filepond-plugin-file-validate-size.js b/dist/filepond-plugin-file-validate-size.js index fffab66..aa5396e 100644 --- a/dist/filepond-plugin-file-validate-size.js +++ b/dist/filepond-plugin-file-validate-size.js @@ -60,6 +60,59 @@ return resolve(file); } + // reject or resolve base on file size by mime type + var mimeSizes = query('GET_MIME_FILE_SIZE'); + if (mimeSizes !== null) { + // It's unclear how the query('GET_MAX_FILE_SIZE') is converting strings + // like '5mb' to ints like 5000000, so hacking behavior in here for + // mime-based limits. Ideally should use the same logic the other + // max file size limit uses, but api documentation is virtually + // non existent. :( + + var _strToBytes = function _strToBytes(str) { + var multiplier = { + b: 1, + kb: 1000, + mb: Math.pow(1000, 2), + gb: Math.pow(1000, 3), + tb: Math.pow(1000, 4), + pb: Math.pow(1000, 5), + }; + var num = Number(str.match(/\d/).toString()); + var type = str + .match(/[a-zA-Z]+/) + .toString() + .toLowerCase(); + return num * multiplier[type]; + }; + + Object.keys(mimeSizes).forEach(function(mime) { + if ( + file.type === mime || + (mime.substring(2, -2) === '/*' && + file.type.split('/')[0] === mime.slice(0, -2)) + ) { + if (file.size > _strToBytes(mimeSizes[mime])) { + reject({ + status: { + main: query('GET_LABEL_MAX_FILE_SIZE_EXCEEDED'), + sub: replaceInString(query('GET_LABEL_MAX_FILE_SIZE'), { + filesize: toNaturalFileSize( + _strToBytes(mimeSizes[mime]), + '.', + query('GET_FILE_SIZE_BASE'), + query('GET_FILE_SIZE_LABELS', query) + ), + }), + }, + }); + + return; + } + } + }); + } + // reject or resolve based on file size var sizeMax = query('GET_MAX_FILE_SIZE'); if (sizeMax !== null && file.size > sizeMax) { @@ -138,6 +191,9 @@ // Enable or disable file type validation allowFileSizeValidation: [true, Type.BOOLEAN], + // Max individual file size in bytes by mime type + mimeSizes: [null, Type.OBJECT], + // Max individual file size in bytes maxFileSize: [null, Type.INT], diff --git a/dist/filepond-plugin-file-validate-size.min.js b/dist/filepond-plugin-file-validate-size.min.js index 17fcb9d..82682c1 100644 --- a/dist/filepond-plugin-file-validate-size.min.js +++ b/dist/filepond-plugin-file-validate-size.min.js @@ -6,4 +6,4 @@ /* eslint-disable */ -!function(e,i){"object"==typeof exports&&"undefined"!=typeof module?module.exports=i():"function"==typeof define&&define.amd?define(i):(e=e||self).FilePondPluginFileValidateSize=i()}(this,function(){"use strict";var e=function(e){var i=e.addFilter,E=e.utils,l=E.Type,_=E.replaceInString,n=E.toNaturalFileSize;return i("ALLOW_HOPPER_ITEM",function(e,i){var E=i.query;if(!E("GET_ALLOW_FILE_SIZE_VALIDATION"))return!0;var l=E("GET_MAX_FILE_SIZE");if(null!==l&&e.size>l)return!1;var _=E("GET_MIN_FILE_SIZE");return!(null!==_&&e.size<_)}),i("LOAD_FILE",function(e,i){var E=i.query;return new Promise(function(i,l){if(!E("GET_ALLOW_FILE_SIZE_VALIDATION"))return i(e);var I=E("GET_FILE_VALIDATE_SIZE_FILTER");if(I&&!I(e))return i(e);var t=E("GET_MAX_FILE_SIZE");if(null!==t&&e.size>t)l({status:{main:E("GET_LABEL_MAX_FILE_SIZE_EXCEEDED"),sub:_(E("GET_LABEL_MAX_FILE_SIZE"),{filesize:n(t,".",E("GET_FILE_SIZE_BASE"),E("GET_FILE_SIZE_LABELS",E))})}});else{var L=E("GET_MIN_FILE_SIZE");if(null!==L&&e.sizea)return void l({status:{main:E("GET_LABEL_MAX_TOTAL_FILE_SIZE_EXCEEDED"),sub:_(E("GET_LABEL_MAX_TOTAL_FILE_SIZE"),{filesize:n(a,".",E("GET_FILE_SIZE_BASE"),E("GET_FILE_SIZE_LABELS",E))})}});i(e)}}})}),{options:{allowFileSizeValidation:[!0,l.BOOLEAN],maxFileSize:[null,l.INT],minFileSize:[null,l.INT],maxTotalFileSize:[null,l.INT],fileValidateSizeFilter:[null,l.FUNCTION],labelMinFileSizeExceeded:["File is too small",l.STRING],labelMinFileSize:["Minimum file size is {filesize}",l.STRING],labelMaxFileSizeExceeded:["File is too large",l.STRING],labelMaxFileSize:["Maximum file size is {filesize}",l.STRING],labelMaxTotalFileSizeExceeded:["Maximum total size exceeded",l.STRING],labelMaxTotalFileSize:["Maximum total file size is {filesize}",l.STRING]}}};return"undefined"!=typeof window&&void 0!==window.document&&document.dispatchEvent(new CustomEvent("FilePond:pluginloaded",{detail:e})),e}); +!function(e,i){"object"==typeof exports&&"undefined"!=typeof module?module.exports=i():"function"==typeof define&&define.amd?define(i):(e=e||self).FilePondPluginFileValidateSize=i()}(this,function(){"use strict";var e=function(e){var i=e.addFilter,E=e.utils,_=E.Type,l=E.replaceInString,t=E.toNaturalFileSize;return i("ALLOW_HOPPER_ITEM",function(e,i){var E=i.query;if(!E("GET_ALLOW_FILE_SIZE_VALIDATION"))return!0;var _=E("GET_MAX_FILE_SIZE");if(null!==_&&e.size>_)return!1;var l=E("GET_MIN_FILE_SIZE");return!(null!==l&&e.sizea(I[i])&&_({status:{main:E("GET_LABEL_MAX_FILE_SIZE_EXCEEDED"),sub:l(E("GET_LABEL_MAX_FILE_SIZE"),{filesize:t(a(I[i]),".",E("GET_FILE_SIZE_BASE"),E("GET_FILE_SIZE_LABELS",E))})}})})}var L=E("GET_MAX_FILE_SIZE");if(null!==L&&e.size>L)_({status:{main:E("GET_LABEL_MAX_FILE_SIZE_EXCEEDED"),sub:l(E("GET_LABEL_MAX_FILE_SIZE"),{filesize:t(L,".",E("GET_FILE_SIZE_BASE"),E("GET_FILE_SIZE_LABELS",E))})}});else{var u=E("GET_MIN_FILE_SIZE");if(null!==u&&e.sizeS)return void _({status:{main:E("GET_LABEL_MAX_TOTAL_FILE_SIZE_EXCEEDED"),sub:l(E("GET_LABEL_MAX_TOTAL_FILE_SIZE"),{filesize:t(S,".",E("GET_FILE_SIZE_BASE"),E("GET_FILE_SIZE_LABELS",E))})}});i(e)}}})}),{options:{allowFileSizeValidation:[!0,_.BOOLEAN],mimeSizes:[null,_.OBJECT],maxFileSize:[null,_.INT],minFileSize:[null,_.INT],maxTotalFileSize:[null,_.INT],fileValidateSizeFilter:[null,_.FUNCTION],labelMinFileSizeExceeded:["File is too small",_.STRING],labelMinFileSize:["Minimum file size is {filesize}",_.STRING],labelMaxFileSizeExceeded:["File is too large",_.STRING],labelMaxFileSize:["Maximum file size is {filesize}",_.STRING],labelMaxTotalFileSizeExceeded:["Maximum total size exceeded",_.STRING],labelMaxTotalFileSize:["Maximum total file size is {filesize}",_.STRING]}}};return"undefined"!=typeof window&&void 0!==window.document&&document.dispatchEvent(new CustomEvent("FilePond:pluginloaded",{detail:e})),e}); diff --git a/src/js/index.js b/src/js/index.js index e0203d3..30d8bb8 100644 --- a/src/js/index.js +++ b/src/js/index.js @@ -2,6 +2,22 @@ const plugin = ({ addFilter, utils }) => { // get quick reference to Type utils const { Type, replaceInString, toNaturalFileSize } = utils; + // There is some magic happening that makes it unclear how the + // query('GET_MAX_FILE_SIZE') is converting strings like '5mb' + // to ints like 5000000, so hacking that behavior in here for + // mime-based limits. Ideally should use the same logic the other + // max file size limit uses, but api documentation for plugins + // is sadly rather lacking. :( + + const _strToBytes = (str) => { + // Multipliers should probably be 1024 vs 1000, + // but this mimics the internal behavior. + const multiplier = { b: 1, kb: 1000, mb: 1000**2, gb: 1000**3, tb: 1000**4, pb: 1000**5 } + const num = Number(str.match(/\d/).toString()) + const type = str.match(/[a-zA-Z]+/).toString().toLowerCase() + return num * multiplier[type] + } + // filtering if an item is allowed in hopper addFilter('ALLOW_HOPPER_ITEM', (file, { query }) => { if (!query('GET_ALLOW_FILE_SIZE_VALIDATION')) { @@ -39,6 +55,62 @@ const plugin = ({ addFilter, utils }) => { return resolve(file); } + // reject or resolve base on max file size by mime type + const mimeMaxFileSizes = query('GET_MIME_MAX_FILE_SIZES'); + if (mimeMaxFileSizes !== null) { + Object.keys(mimeMaxFileSizes).forEach(mime => { + if (file.type === mime || + (mime.substring(2, -2) === '/*' + && file.type.split('/')[0] === mime.slice(0, -2)) + ) { + if (file.size > _strToBytes(mimeMaxFileSizes[mime])) { + reject({ + status: { + main: query('GET_LABEL_MAX_FILE_SIZE_EXCEEDED'), + sub: replaceInString(query('GET_LABEL_MAX_FILE_SIZE'), { + filesize: toNaturalFileSize( + _strToBytes(mimeMaxFileSizes[mime]), + '.', + query('GET_FILE_SIZE_BASE'), + query('GET_FILE_SIZE_LABELS', query) + ), + }), + }, + }); + return; + } + } + }) + } + + // reject or resolve base on min file size by mime type + const mimeMinFileSizes = query('GET_MIME_MIN_FILE_SIZES'); + if (mimeMinFileSizes !== null) { + Object.keys(mimeMinFileSizes).forEach(mime => { + if (file.type === mime || + (mime.substring(2, -2) === '/*' + && file.type.split('/')[0] === mime.slice(0, -2)) + ) { + if (file.size < _strToBytes(mimeMinFileSizes[mime])) { + reject({ + status: { + main: query('GET_LABEL_MIN_FILE_SIZE_EXCEEDED'), + sub: replaceInString(query('GET_LABEL_MIN_FILE_SIZE'), { + filesize: toNaturalFileSize( + _strToBytes(mimeMinFileSizes[mime]), + '.', + query('GET_FILE_SIZE_BASE'), + query('GET_FILE_SIZE_LABELS', query) + ), + }), + }, + }); + return; + } + } + }) + } + // reject or resolve based on file size const sizeMax = query('GET_MAX_FILE_SIZE'); if (sizeMax !== null && file.size > sizeMax) { @@ -113,10 +185,16 @@ const plugin = ({ addFilter, utils }) => { options: { // Enable or disable file type validation allowFileSizeValidation: [true, Type.BOOLEAN], + + // Max individual file size in bytes by mime type + mimeMaxFileSizes: [null, Type.OBJECT], + + // Max individual file size in bytes by mime type + mimeMinFileSizes: [null, Type.OBJECT], // Max individual file size in bytes maxFileSize: [null, Type.INT], - + // Min individual file size in bytes minFileSize: [null, Type.INT], diff --git a/types/index.d.ts b/types/index.d.ts index 268c391..332a477 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -11,6 +11,10 @@ declare module "filepond" { labelMinFileSizeExceeded?: string; /** Message shown when the file size is lower than the {filesize}. {filesize} is replaced with the value of the minFileSize property */ labelMinFileSize?: string; + /** Maximum file sizes by mime type, ie: { 'image/*': 2MB, 'video/mp4': 100MB } */ + mimeMaxFileSizes?: object | null; + /** Minimum file sizes by mime type, ie: { 'image/*': 2MB, 'video/mp4': 100MB } */ + mimeMinFileSizes?: object | null; /** The maximum size of a file, for instance 5MB or 750KB. */ maxFileSize?: string | null; /** Maximum size of all files in list, same format as maxFileSize. */ From d80d2cf1f7ead2ec67a352f4937e3541737100c3 Mon Sep 17 00:00:00 2001 From: Will Vincent Date: Tue, 21 Nov 2023 15:53:21 -0600 Subject: [PATCH 2/2] build the plugin. --- .idea/workspace.xml | 68 +++++++++++++ .../filepond-plugin-file-validate-size.esm.js | 95 ++++++++++++------ ...epond-plugin-file-validate-size.esm.min.js | 2 +- dist/filepond-plugin-file-validate-size.js | 96 +++++++++++++------ .../filepond-plugin-file-validate-size.min.js | 2 +- 5 files changed, 201 insertions(+), 62 deletions(-) create mode 100644 .idea/workspace.xml diff --git a/.idea/workspace.xml b/.idea/workspace.xml new file mode 100644 index 0000000..ba288f1 --- /dev/null +++ b/.idea/workspace.xml @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + { + "keyToString": { + "RunOnceActivity.ShowReadmeOnStart": "true", + "RunOnceActivity.laravel-idea.search-composer-json": "true", + "WebServerToolWindowFactoryState": "false", + "git-widget-placeholder": "master", + "node.js.detected.package.eslint": "true", + "node.js.detected.package.tslint": "true", + "node.js.selected.package.eslint": "(autodetect)", + "node.js.selected.package.tslint": "(autodetect)", + "nodejs_package_manager_path": "npm", + "settings.editor.selected.configurable": "preferences.lookFeel", + "ts.external.directory.path": "/Applications/PhpStorm.app/Contents/plugins/javascript-impl/jsLanguageServicesImpl/external", + "vue.rearranger.settings.migration": "true" + } +} + + + + + 1700585266282 + + + + + + \ No newline at end of file diff --git a/dist/filepond-plugin-file-validate-size.esm.js b/dist/filepond-plugin-file-validate-size.esm.js index 85e658f..db178b0 100644 --- a/dist/filepond-plugin-file-validate-size.esm.js +++ b/dist/filepond-plugin-file-validate-size.esm.js @@ -10,6 +10,32 @@ const plugin = ({ addFilter, utils }) => { // get quick reference to Type utils const { Type, replaceInString, toNaturalFileSize } = utils; + // There is some magic happening that makes it unclear how the + // query('GET_MAX_FILE_SIZE') is converting strings like '5mb' + // to ints like 5000000, so hacking that behavior in here for + // mime-based limits. Ideally should use the same logic the other + // max file size limit uses, but api documentation for plugins + // is sadly rather lacking. :( + + const _strToBytes = str => { + // Multipliers should probably be 1024 vs 1000, + // but this mimics the internal behavior. + const multiplier = { + b: 1, + kb: 1000, + mb: 1000 ** 2, + gb: 1000 ** 3, + tb: 1000 ** 4, + pb: 1000 ** 5, + }; + const num = Number(str.match(/\d/).toString()); + const type = str + .match(/[a-zA-Z]+/) + .toString() + .toLowerCase(); + return num * multiplier[type]; + }; + // filtering if an item is allowed in hopper addFilter('ALLOW_HOPPER_ITEM', (file, { query }) => { if (!query('GET_ALLOW_FILE_SIZE_VALIDATION')) { @@ -47,45 +73,51 @@ const plugin = ({ addFilter, utils }) => { return resolve(file); } - // reject or resolve base on file size by mime type - const mimeSizes = query('GET_MIME_FILE_SIZE'); - if (mimeSizes !== null) { - // It's unclear how the query('GET_MAX_FILE_SIZE') is converting strings - // like '5mb' to ints like 5000000, so hacking behavior in here for - // mime-based limits. Ideally should use the same logic the other - // max file size limit uses, but api documentation is virtually - // non existent. :( - - const _strToBytes = str => { - const multiplier = { - b: 1, - kb: 1000, - mb: 1000 ** 2, - gb: 1000 ** 3, - tb: 1000 ** 4, - pb: 1000 ** 5, - }; - const num = Number(str.match(/\d/).toString()); - const type = str - .match(/[a-zA-Z]+/) - .toString() - .toLowerCase(); - return num * multiplier[type]; - }; - - Object.keys(mimeSizes).forEach(mime => { + // reject or resolve base on max file size by mime type + const mimeMaxFileSizes = query('GET_MIME_MAX_FILE_SIZES'); + if (mimeMaxFileSizes !== null) { + Object.keys(mimeMaxFileSizes).forEach(mime => { if ( file.type === mime || (mime.substring(2, -2) === '/*' && file.type.split('/')[0] === mime.slice(0, -2)) ) { - if (file.size > _strToBytes(mimeSizes[mime])) { + if (file.size > _strToBytes(mimeMaxFileSizes[mime])) { reject({ status: { main: query('GET_LABEL_MAX_FILE_SIZE_EXCEEDED'), sub: replaceInString(query('GET_LABEL_MAX_FILE_SIZE'), { filesize: toNaturalFileSize( - _strToBytes(mimeSizes[mime]), + _strToBytes(mimeMaxFileSizes[mime]), + '.', + query('GET_FILE_SIZE_BASE'), + query('GET_FILE_SIZE_LABELS', query) + ), + }), + }, + }); + return; + } + } + }); + } + + // reject or resolve base on min file size by mime type + const mimeMinFileSizes = query('GET_MIME_MIN_FILE_SIZES'); + if (mimeMinFileSizes !== null) { + Object.keys(mimeMinFileSizes).forEach(mime => { + if ( + file.type === mime || + (mime.substring(2, -2) === '/*' && + file.type.split('/')[0] === mime.slice(0, -2)) + ) { + if (file.size < _strToBytes(mimeMinFileSizes[mime])) { + reject({ + status: { + main: query('GET_LABEL_MIN_FILE_SIZE_EXCEEDED'), + sub: replaceInString(query('GET_LABEL_MIN_FILE_SIZE'), { + filesize: toNaturalFileSize( + _strToBytes(mimeMinFileSizes[mime]), '.', query('GET_FILE_SIZE_BASE'), query('GET_FILE_SIZE_LABELS', query) @@ -175,7 +207,10 @@ const plugin = ({ addFilter, utils }) => { allowFileSizeValidation: [true, Type.BOOLEAN], // Max individual file size in bytes by mime type - mimeSizes: [null, Type.OBJECT], + mimeMaxFileSizes: [null, Type.OBJECT], + + // Max individual file size in bytes by mime type + mimeMinFileSizes: [null, Type.OBJECT], // Max individual file size in bytes maxFileSize: [null, Type.INT], diff --git a/dist/filepond-plugin-file-validate-size.esm.min.js b/dist/filepond-plugin-file-validate-size.esm.min.js index 1681a7d..75c50f2 100644 --- a/dist/filepond-plugin-file-validate-size.esm.min.js +++ b/dist/filepond-plugin-file-validate-size.esm.min.js @@ -6,4 +6,4 @@ /* eslint-disable */ -const e=({addFilter:e,utils:E})=>{const{Type:i,replaceInString:_,toNaturalFileSize:l}=E;return e("ALLOW_HOPPER_ITEM",(e,{query:E})=>{if(!E("GET_ALLOW_FILE_SIZE_VALIDATION"))return!0;const i=E("GET_MAX_FILE_SIZE");if(null!==i&&e.size>i)return!1;const _=E("GET_MIN_FILE_SIZE");return!(null!==_&&e.size<_)}),e("LOAD_FILE",(e,{query:E})=>new Promise((i,I)=>{if(!E("GET_ALLOW_FILE_SIZE_VALIDATION"))return i(e);const t=E("GET_FILE_VALIDATE_SIZE_FILTER");if(t&&!t(e))return i(e);const L=E("GET_MIME_FILE_SIZE");if(null!==L){const i=e=>{return Number(e.match(/\d/).toString())*{b:1,kb:1e3,mb:1e6,gb:1e9,tb:1e12,pb:1e15}[e.match(/[a-zA-Z]+/).toString().toLowerCase()]};Object.keys(L).forEach(t=>{(e.type===t||"/*"===t.substring(2,-2)&&e.type.split("/")[0]===t.slice(0,-2))&&e.size>i(L[t])&&I({status:{main:E("GET_LABEL_MAX_FILE_SIZE_EXCEEDED"),sub:_(E("GET_LABEL_MAX_FILE_SIZE"),{filesize:l(i(L[t]),".",E("GET_FILE_SIZE_BASE"),E("GET_FILE_SIZE_LABELS",E))})}})})}const n=E("GET_MAX_FILE_SIZE");if(null!==n&&e.size>n)return void I({status:{main:E("GET_LABEL_MAX_FILE_SIZE_EXCEEDED"),sub:_(E("GET_LABEL_MAX_FILE_SIZE"),{filesize:l(n,".",E("GET_FILE_SIZE_BASE"),E("GET_FILE_SIZE_LABELS",E))})}});const S=E("GET_MIN_FILE_SIZE");if(null!==S&&e.sizee+E.fileSize,0)>s)return void I({status:{main:E("GET_LABEL_MAX_TOTAL_FILE_SIZE_EXCEEDED"),sub:_(E("GET_LABEL_MAX_TOTAL_FILE_SIZE"),{filesize:l(s,".",E("GET_FILE_SIZE_BASE"),E("GET_FILE_SIZE_LABELS",E))})}})}i(e)})),{options:{allowFileSizeValidation:[!0,i.BOOLEAN],mimeSizes:[null,i.OBJECT],maxFileSize:[null,i.INT],minFileSize:[null,i.INT],maxTotalFileSize:[null,i.INT],fileValidateSizeFilter:[null,i.FUNCTION],labelMinFileSizeExceeded:["File is too small",i.STRING],labelMinFileSize:["Minimum file size is {filesize}",i.STRING],labelMaxFileSizeExceeded:["File is too large",i.STRING],labelMaxFileSize:["Maximum file size is {filesize}",i.STRING],labelMaxTotalFileSizeExceeded:["Maximum total size exceeded",i.STRING],labelMaxTotalFileSize:["Maximum total file size is {filesize}",i.STRING]}}};"undefined"!=typeof window&&void 0!==window.document&&document.dispatchEvent(new CustomEvent("FilePond:pluginloaded",{detail:e}));export default e; +const E=({addFilter:E,utils:e})=>{const{Type:i,replaceInString:_,toNaturalFileSize:l}=e,I=E=>{return Number(E.match(/\d/).toString())*{b:1,kb:1e3,mb:1e6,gb:1e9,tb:1e12,pb:1e15}[E.match(/[a-zA-Z]+/).toString().toLowerCase()]};return E("ALLOW_HOPPER_ITEM",(E,{query:e})=>{if(!e("GET_ALLOW_FILE_SIZE_VALIDATION"))return!0;const i=e("GET_MAX_FILE_SIZE");if(null!==i&&E.size>i)return!1;const _=e("GET_MIN_FILE_SIZE");return!(null!==_&&E.size<_)}),E("LOAD_FILE",(E,{query:e})=>new Promise((i,L)=>{if(!e("GET_ALLOW_FILE_SIZE_VALIDATION"))return i(E);const t=e("GET_FILE_VALIDATE_SIZE_FILTER");if(t&&!t(E))return i(E);const s=e("GET_MIME_MAX_FILE_SIZES");null!==s&&Object.keys(s).forEach(i=>{(E.type===i||"/*"===i.substring(2,-2)&&E.type.split("/")[0]===i.slice(0,-2))&&E.size>I(s[i])&&L({status:{main:e("GET_LABEL_MAX_FILE_SIZE_EXCEEDED"),sub:_(e("GET_LABEL_MAX_FILE_SIZE"),{filesize:l(I(s[i]),".",e("GET_FILE_SIZE_BASE"),e("GET_FILE_SIZE_LABELS",e))})}})});const S=e("GET_MIME_MIN_FILE_SIZES");null!==S&&Object.keys(S).forEach(i=>{(E.type===i||"/*"===i.substring(2,-2)&&E.type.split("/")[0]===i.slice(0,-2))&&E.sizen)return void L({status:{main:e("GET_LABEL_MAX_FILE_SIZE_EXCEEDED"),sub:_(e("GET_LABEL_MAX_FILE_SIZE"),{filesize:l(n,".",e("GET_FILE_SIZE_BASE"),e("GET_FILE_SIZE_LABELS",e))})}});const T=e("GET_MIN_FILE_SIZE");if(null!==T&&E.sizeE+e.fileSize,0)>a)return void L({status:{main:e("GET_LABEL_MAX_TOTAL_FILE_SIZE_EXCEEDED"),sub:_(e("GET_LABEL_MAX_TOTAL_FILE_SIZE"),{filesize:l(a,".",e("GET_FILE_SIZE_BASE"),e("GET_FILE_SIZE_LABELS",e))})}})}i(E)})),{options:{allowFileSizeValidation:[!0,i.BOOLEAN],mimeMaxFileSizes:[null,i.OBJECT],mimeMinFileSizes:[null,i.OBJECT],maxFileSize:[null,i.INT],minFileSize:[null,i.INT],maxTotalFileSize:[null,i.INT],fileValidateSizeFilter:[null,i.FUNCTION],labelMinFileSizeExceeded:["File is too small",i.STRING],labelMinFileSize:["Minimum file size is {filesize}",i.STRING],labelMaxFileSizeExceeded:["File is too large",i.STRING],labelMaxFileSize:["Maximum file size is {filesize}",i.STRING],labelMaxTotalFileSizeExceeded:["Maximum total size exceeded",i.STRING],labelMaxTotalFileSize:["Maximum total file size is {filesize}",i.STRING]}}};"undefined"!=typeof window&&void 0!==window.document&&document.dispatchEvent(new CustomEvent("FilePond:pluginloaded",{detail:E}));export default E; diff --git a/dist/filepond-plugin-file-validate-size.js b/dist/filepond-plugin-file-validate-size.js index aa5396e..2351448 100644 --- a/dist/filepond-plugin-file-validate-size.js +++ b/dist/filepond-plugin-file-validate-size.js @@ -23,6 +23,32 @@ replaceInString = utils.replaceInString, toNaturalFileSize = utils.toNaturalFileSize; + // There is some magic happening that makes it unclear how the + // query('GET_MAX_FILE_SIZE') is converting strings like '5mb' + // to ints like 5000000, so hacking that behavior in here for + // mime-based limits. Ideally should use the same logic the other + // max file size limit uses, but api documentation for plugins + // is sadly rather lacking. :( + + var _strToBytes = function _strToBytes(str) { + // Multipliers should probably be 1024 vs 1000, + // but this mimics the internal behavior. + var multiplier = { + b: 1, + kb: 1000, + mb: Math.pow(1000, 2), + gb: Math.pow(1000, 3), + tb: Math.pow(1000, 4), + pb: Math.pow(1000, 5), + }; + var num = Number(str.match(/\d/).toString()); + var type = str + .match(/[a-zA-Z]+/) + .toString() + .toLowerCase(); + return num * multiplier[type]; + }; + // filtering if an item is allowed in hopper addFilter('ALLOW_HOPPER_ITEM', function(file, _ref2) { var query = _ref2.query; @@ -60,45 +86,52 @@ return resolve(file); } - // reject or resolve base on file size by mime type - var mimeSizes = query('GET_MIME_FILE_SIZE'); - if (mimeSizes !== null) { - // It's unclear how the query('GET_MAX_FILE_SIZE') is converting strings - // like '5mb' to ints like 5000000, so hacking behavior in here for - // mime-based limits. Ideally should use the same logic the other - // max file size limit uses, but api documentation is virtually - // non existent. :( - - var _strToBytes = function _strToBytes(str) { - var multiplier = { - b: 1, - kb: 1000, - mb: Math.pow(1000, 2), - gb: Math.pow(1000, 3), - tb: Math.pow(1000, 4), - pb: Math.pow(1000, 5), - }; - var num = Number(str.match(/\d/).toString()); - var type = str - .match(/[a-zA-Z]+/) - .toString() - .toLowerCase(); - return num * multiplier[type]; - }; - - Object.keys(mimeSizes).forEach(function(mime) { + // reject or resolve base on max file size by mime type + var mimeMaxFileSizes = query('GET_MIME_MAX_FILE_SIZES'); + if (mimeMaxFileSizes !== null) { + Object.keys(mimeMaxFileSizes).forEach(function(mime) { if ( file.type === mime || (mime.substring(2, -2) === '/*' && file.type.split('/')[0] === mime.slice(0, -2)) ) { - if (file.size > _strToBytes(mimeSizes[mime])) { + if (file.size > _strToBytes(mimeMaxFileSizes[mime])) { reject({ status: { main: query('GET_LABEL_MAX_FILE_SIZE_EXCEEDED'), sub: replaceInString(query('GET_LABEL_MAX_FILE_SIZE'), { filesize: toNaturalFileSize( - _strToBytes(mimeSizes[mime]), + _strToBytes(mimeMaxFileSizes[mime]), + '.', + query('GET_FILE_SIZE_BASE'), + query('GET_FILE_SIZE_LABELS', query) + ), + }), + }, + }); + + return; + } + } + }); + } + + // reject or resolve base on min file size by mime type + var mimeMinFileSizes = query('GET_MIME_MIN_FILE_SIZES'); + if (mimeMinFileSizes !== null) { + Object.keys(mimeMinFileSizes).forEach(function(mime) { + if ( + file.type === mime || + (mime.substring(2, -2) === '/*' && + file.type.split('/')[0] === mime.slice(0, -2)) + ) { + if (file.size < _strToBytes(mimeMinFileSizes[mime])) { + reject({ + status: { + main: query('GET_LABEL_MIN_FILE_SIZE_EXCEEDED'), + sub: replaceInString(query('GET_LABEL_MIN_FILE_SIZE'), { + filesize: toNaturalFileSize( + _strToBytes(mimeMinFileSizes[mime]), '.', query('GET_FILE_SIZE_BASE'), query('GET_FILE_SIZE_LABELS', query) @@ -192,7 +225,10 @@ allowFileSizeValidation: [true, Type.BOOLEAN], // Max individual file size in bytes by mime type - mimeSizes: [null, Type.OBJECT], + mimeMaxFileSizes: [null, Type.OBJECT], + + // Max individual file size in bytes by mime type + mimeMinFileSizes: [null, Type.OBJECT], // Max individual file size in bytes maxFileSize: [null, Type.INT], diff --git a/dist/filepond-plugin-file-validate-size.min.js b/dist/filepond-plugin-file-validate-size.min.js index 82682c1..72edd4f 100644 --- a/dist/filepond-plugin-file-validate-size.min.js +++ b/dist/filepond-plugin-file-validate-size.min.js @@ -6,4 +6,4 @@ /* eslint-disable */ -!function(e,i){"object"==typeof exports&&"undefined"!=typeof module?module.exports=i():"function"==typeof define&&define.amd?define(i):(e=e||self).FilePondPluginFileValidateSize=i()}(this,function(){"use strict";var e=function(e){var i=e.addFilter,E=e.utils,_=E.Type,l=E.replaceInString,t=E.toNaturalFileSize;return i("ALLOW_HOPPER_ITEM",function(e,i){var E=i.query;if(!E("GET_ALLOW_FILE_SIZE_VALIDATION"))return!0;var _=E("GET_MAX_FILE_SIZE");if(null!==_&&e.size>_)return!1;var l=E("GET_MIN_FILE_SIZE");return!(null!==l&&e.sizea(I[i])&&_({status:{main:E("GET_LABEL_MAX_FILE_SIZE_EXCEEDED"),sub:l(E("GET_LABEL_MAX_FILE_SIZE"),{filesize:t(a(I[i]),".",E("GET_FILE_SIZE_BASE"),E("GET_FILE_SIZE_LABELS",E))})}})})}var L=E("GET_MAX_FILE_SIZE");if(null!==L&&e.size>L)_({status:{main:E("GET_LABEL_MAX_FILE_SIZE_EXCEEDED"),sub:l(E("GET_LABEL_MAX_FILE_SIZE"),{filesize:t(L,".",E("GET_FILE_SIZE_BASE"),E("GET_FILE_SIZE_LABELS",E))})}});else{var u=E("GET_MIN_FILE_SIZE");if(null!==u&&e.sizeS)return void _({status:{main:E("GET_LABEL_MAX_TOTAL_FILE_SIZE_EXCEEDED"),sub:l(E("GET_LABEL_MAX_TOTAL_FILE_SIZE"),{filesize:t(S,".",E("GET_FILE_SIZE_BASE"),E("GET_FILE_SIZE_LABELS",E))})}});i(e)}}})}),{options:{allowFileSizeValidation:[!0,_.BOOLEAN],mimeSizes:[null,_.OBJECT],maxFileSize:[null,_.INT],minFileSize:[null,_.INT],maxTotalFileSize:[null,_.INT],fileValidateSizeFilter:[null,_.FUNCTION],labelMinFileSizeExceeded:["File is too small",_.STRING],labelMinFileSize:["Minimum file size is {filesize}",_.STRING],labelMaxFileSizeExceeded:["File is too large",_.STRING],labelMaxFileSize:["Maximum file size is {filesize}",_.STRING],labelMaxTotalFileSizeExceeded:["Maximum total size exceeded",_.STRING],labelMaxTotalFileSize:["Maximum total file size is {filesize}",_.STRING]}}};return"undefined"!=typeof window&&void 0!==window.document&&document.dispatchEvent(new CustomEvent("FilePond:pluginloaded",{detail:e})),e}); +!function(e,E){"object"==typeof exports&&"undefined"!=typeof module?module.exports=E():"function"==typeof define&&define.amd?define(E):(e=e||self).FilePondPluginFileValidateSize=E()}(this,function(){"use strict";var e=function(e){var E=e.addFilter,i=e.utils,_=i.Type,l=i.replaceInString,t=i.toNaturalFileSize,I=function(e){var E={b:1,kb:1e3,mb:Math.pow(1e3,2),gb:Math.pow(1e3,3),tb:Math.pow(1e3,4),pb:Math.pow(1e3,5)};return Number(e.match(/\d/).toString())*E[e.match(/[a-zA-Z]+/).toString().toLowerCase()]};return E("ALLOW_HOPPER_ITEM",function(e,E){var i=E.query;if(!i("GET_ALLOW_FILE_SIZE_VALIDATION"))return!0;var _=i("GET_MAX_FILE_SIZE");if(null!==_&&e.size>_)return!1;var l=i("GET_MIN_FILE_SIZE");return!(null!==l&&e.sizeI(L[E])&&_({status:{main:i("GET_LABEL_MAX_FILE_SIZE_EXCEEDED"),sub:l(i("GET_LABEL_MAX_FILE_SIZE"),{filesize:t(I(L[E]),".",i("GET_FILE_SIZE_BASE"),i("GET_FILE_SIZE_LABELS",i))})}})});var a=i("GET_MIME_MIN_FILE_SIZES");null!==a&&Object.keys(a).forEach(function(E){(e.type===E||"/*"===E.substring(2,-2)&&e.type.split("/")[0]===E.slice(0,-2))&&e.sizeS)_({status:{main:i("GET_LABEL_MAX_FILE_SIZE_EXCEEDED"),sub:l(i("GET_LABEL_MAX_FILE_SIZE"),{filesize:t(S,".",i("GET_FILE_SIZE_BASE"),i("GET_FILE_SIZE_LABELS",i))})}});else{var u=i("GET_MIN_FILE_SIZE");if(null!==u&&e.sizes)return void _({status:{main:i("GET_LABEL_MAX_TOTAL_FILE_SIZE_EXCEEDED"),sub:l(i("GET_LABEL_MAX_TOTAL_FILE_SIZE"),{filesize:t(s,".",i("GET_FILE_SIZE_BASE"),i("GET_FILE_SIZE_LABELS",i))})}});E(e)}}})}),{options:{allowFileSizeValidation:[!0,_.BOOLEAN],mimeMaxFileSizes:[null,_.OBJECT],mimeMinFileSizes:[null,_.OBJECT],maxFileSize:[null,_.INT],minFileSize:[null,_.INT],maxTotalFileSize:[null,_.INT],fileValidateSizeFilter:[null,_.FUNCTION],labelMinFileSizeExceeded:["File is too small",_.STRING],labelMinFileSize:["Minimum file size is {filesize}",_.STRING],labelMaxFileSizeExceeded:["File is too large",_.STRING],labelMaxFileSize:["Maximum file size is {filesize}",_.STRING],labelMaxTotalFileSizeExceeded:["Maximum total size exceeded",_.STRING],labelMaxTotalFileSize:["Maximum total file size is {filesize}",_.STRING]}}};return"undefined"!=typeof window&&void 0!==window.document&&document.dispatchEvent(new CustomEvent("FilePond:pluginloaded",{detail:e})),e});