Skip to content

fix: not possible to drag&drop file with multiple dots #487

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 19, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 52 additions & 36 deletions packages/uui-file-dropzone/lib/uui-file-dropzone.element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,18 +61,45 @@ export class UUIFileDropzoneElement extends LabelMixin('', LitElement) {
@query('#dropzone')
private _dropzone!: HTMLElement;

private _acceptedFileExtensions: string[] = [];
private _acceptedMimeTypes: string[] = [];

/**
* Comma-separated list of accepted filetypes. Will allow all types if empty.
* Comma-separated list of accepted mime types or file extensions (denoted with a `.`).
* If this is left empty, it will allow all types.
*
* @type {string}
* @attr
* @default false
* @examples [
* "image/png,image/jpeg,image/gif",
* "gif,png,jpg,jpeg",
* "image/*,application/pdf",
* ".gif,.png,.jpg,.jpeg,.pdf",
* ]
*/
@property({ type: String })
public accept: string = '';
public set accept(value: string) {
if (value) {
const mimetypes: string[] = [];
const fileextensions: string[] = [];

// Create the arrays defined above
value.split(',').forEach(item => {
item = item.trim().toLowerCase();

// If the item is a mime type, add it to the accept list
if (/[a-z]+\/[a-z*]/s.test(item)) {
mimetypes.push(item);
} else {
fileextensions.push(item.replace(/^\./, ''));
}
});

this._acceptedMimeTypes = mimetypes;
this._acceptedFileExtensions = fileextensions;
} else {
this._acceptedMimeTypes = [];
this._acceptedFileExtensions = [];
}
}

/**
* Allows for multiple files to be selected.
Expand Down Expand Up @@ -105,40 +132,20 @@ export class UUIFileDropzoneElement extends LabelMixin('', LitElement) {
demandCustomElement(this, 'uui-symbol-file-dropzone');
}

protected _checkIsItDirectory(dtItem: DataTransferItem): boolean {
// @ts-ignore // TODO: fix typescript error
return !dtItem.type ? dtItem.webkitGetAsEntry().isDirectory : false;
}

private async _getAllFileEntries(
dataTransferItemList: DataTransferItemList
): Promise<File[]> {
const fileEntries: File[] = [];
// Use BFS to traverse entire directory/file structure
const queue = [...dataTransferItemList];

const acceptList: string[] = [];
const wildcards: string[] = [];

// if the accept filer is set
if (this.accept) {
// Create the arrays defined above
this.accept.split(',').forEach(item => {
if (item.includes('*')) {
wildcards.push(item.split('*')[0].trim().toLowerCase());
} else {
acceptList.push(item.trim().toLowerCase());
}
});
}

while (queue.length > 0) {
const entry = queue.shift()!;

if (entry.kind === 'file') {
const file = entry.getAsFile();
if (!file) continue;
if (this._isAccepted(acceptList, wildcards, file)) {
if (this._isAccepted(file)) {
fileEntries.push(file);
}
} else if (entry.kind === 'directory') {
Expand Down Expand Up @@ -179,24 +186,33 @@ export class UUIFileDropzoneElement extends LabelMixin('', LitElement) {
}
}

private _isAccepted(acceptList: string[], wildcards: string[], file: File) {
if (acceptList.length === 0 && wildcards.length === 0) {
private _isAccepted(file: File) {
if (
this._acceptedFileExtensions.length === 0 &&
this._acceptedMimeTypes.length === 0
) {
return true;
}

const fileType = file.type.toLowerCase();
const fileExtension = '.' + file.name.split('.')[1].toLowerCase();

if (acceptList.includes(fileExtension)) {
return true;
}
const fileExtension = file.name.split('.').pop();

if (acceptList.includes(fileType)) {
if (
fileExtension &&
this._acceptedFileExtensions.includes(fileExtension.toLowerCase())
) {
return true;
}

if (wildcards.some(wildcard => fileType.startsWith(wildcard))) {
return true;
for (const mimeType in this._acceptedMimeTypes) {
if (fileType === mimeType) {
return true;
} else if (
mimeType.endsWith('/*') &&
fileType.startsWith(mimeType.replace('/*', ''))
) {
return true;
}
}

return false;
Expand Down