filepond-plugin-file-validate-type
Version:
File Type Validation Plugin for FilePond
211 lines (178 loc) • 7.37 kB
JavaScript
/*!
* FilePondPluginFileValidateType 1.2.9
* Licensed under MIT, https://opensource.org/licenses/MIT/
* Please visit https://pqina.nl/filepond/ for details.
*/
/* eslint-disable */
const plugin = ({ addFilter, utils }) => {
// get quick reference to Type utils
const {
Type,
isString,
replaceInString,
guesstimateMimeType,
getExtensionFromFilename,
getFilenameFromURL,
} = utils;
const mimeTypeMatchesWildCard = (mimeType, wildcard) => {
const mimeTypeGroup = (/^[^/]+/.exec(mimeType) || []).pop(); // image/png -> image
const wildcardGroup = wildcard.slice(0, -2); // image/* -> image
return mimeTypeGroup === wildcardGroup;
};
const isValidMimeType = (acceptedTypes, userInputType) =>
acceptedTypes.some(acceptedType => {
// accepted is wildcard mime type
if (/\*$/.test(acceptedType)) {
return mimeTypeMatchesWildCard(userInputType, acceptedType);
}
// is normal mime type
return acceptedType === userInputType;
});
const getItemType = item => {
// if the item is a url we guess the mime type by the extension
let type = '';
if (isString(item)) {
const filename = getFilenameFromURL(item);
const extension = getExtensionFromFilename(filename);
if (extension) {
type = guesstimateMimeType(extension);
}
} else {
type = item.type;
}
return type;
};
const validateFile = (item, acceptedFileTypes, typeDetector) => {
// no types defined, everything is allowed \o/
if (acceptedFileTypes.length === 0) {
return true;
}
// gets the item type
const type = getItemType(item);
// no type detector, test now
if (!typeDetector) {
return isValidMimeType(acceptedFileTypes, type);
}
// use type detector
return new Promise((resolve, reject) => {
typeDetector(item, type)
.then(detectedType => {
if (isValidMimeType(acceptedFileTypes, detectedType)) {
resolve();
} else {
reject();
}
})
.catch(reject);
});
};
const applyMimeTypeMap = map => acceptedFileType =>
map[acceptedFileType] === null ? false : map[acceptedFileType] || acceptedFileType;
// setup attribute mapping for accept
addFilter('SET_ATTRIBUTE_TO_OPTION_MAP', map =>
Object.assign(map, {
accept: 'acceptedFileTypes',
})
);
// filtering if an item is allowed in hopper
addFilter('ALLOW_HOPPER_ITEM', (file, { query }) => {
// if we are not doing file type validation exit
if (!query('GET_ALLOW_FILE_TYPE_VALIDATION')) {
return true;
}
// we validate the file against the accepted file types
return validateFile(file, query('GET_ACCEPTED_FILE_TYPES'));
});
// called for each file that is loaded
// right before it is set to the item state
// should return a promise
addFilter(
'LOAD_FILE',
(file, { query }) =>
new Promise((resolve, reject) => {
if (!query('GET_ALLOW_FILE_TYPE_VALIDATION')) {
resolve(file);
return;
}
const acceptedFileTypes = query('GET_ACCEPTED_FILE_TYPES');
// custom type detector method
const typeDetector = query('GET_FILE_VALIDATE_TYPE_DETECT_TYPE');
// if invalid, exit here
const validationResult = validateFile(file, acceptedFileTypes, typeDetector);
const handleRejection = () => {
const acceptedFileTypesMapped = acceptedFileTypes
.map(
applyMimeTypeMap(
query('GET_FILE_VALIDATE_TYPE_LABEL_EXPECTED_TYPES_MAP')
)
)
.filter(label => label !== false);
const acceptedFileTypesMappedUnique = acceptedFileTypesMapped.filter(
(item, index) => acceptedFileTypesMapped.indexOf(item) === index
);
reject({
status: {
main: query('GET_LABEL_FILE_TYPE_NOT_ALLOWED'),
sub: replaceInString(
query('GET_FILE_VALIDATE_TYPE_LABEL_EXPECTED_TYPES'),
{
allTypes: acceptedFileTypesMappedUnique.join(', '),
allButLastType: acceptedFileTypesMappedUnique
.slice(0, -1)
.join(', '),
lastType:
acceptedFileTypesMappedUnique[
acceptedFileTypesMappedUnique.length - 1
],
}
),
},
});
};
// has returned new filename immidiately
if (typeof validationResult === 'boolean') {
if (!validationResult) {
return handleRejection();
}
return resolve(file);
}
// is promise
validationResult
.then(() => {
resolve(file);
})
.catch(handleRejection);
})
);
// expose plugin
return {
// default options
options: {
// Enable or disable file type validation
allowFileTypeValidation: [true, Type.BOOLEAN],
// What file types to accept
acceptedFileTypes: [[], Type.ARRAY],
// - must be comma separated
// - mime types: image/png, image/jpeg, image/gif
// - extensions: .png, .jpg, .jpeg ( not enabled yet )
// - wildcards: image/*
// label to show when a type is not allowed
labelFileTypeNotAllowed: ['File is of invalid type', Type.STRING],
// nicer label
fileValidateTypeLabelExpectedTypes: [
'Expects {allButLastType} or {lastType}',
Type.STRING,
],
// map mime types to extensions
fileValidateTypeLabelExpectedTypesMap: [{}, Type.OBJECT],
// Custom function to detect type of file
fileValidateTypeDetectType: [null, Type.FUNCTION],
},
};
};
// fire pluginloaded event if running in browser, this allows registering the plugin when using async script tags
const isBrowser = typeof window !== 'undefined' && typeof window.document !== 'undefined';
if (isBrowser) {
document.dispatchEvent(new CustomEvent('FilePond:pluginloaded', { detail: plugin }));
}
export default plugin;