Skip to content

Commit dfb14cd

Browse files
authored
fix:delay folder upload until all children files are parsed when drag (#561)
* fix:delay folder upload until all children files are parsed when drag * fix: isAcceptable case * feat: use queue * feat: readEntries add errorCallback * fix: improve code * feat:improve code * fix:ci * feat: improve code
1 parent d077f39 commit dfb14cd

File tree

2 files changed

+78
-30
lines changed

2 files changed

+78
-30
lines changed

src/traverseFileTree.ts

Lines changed: 30 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -10,30 +10,28 @@ interface InternalDataTransferItem extends DataTransferItem {
1010
path: string;
1111
}
1212

13-
function loopFiles(item: InternalDataTransferItem, callback) {
14-
const dirReader = item.createReader();
15-
let fileList = [];
13+
const traverseFileTree = (files: InternalDataTransferItem[], callback, isAccepted) => {
14+
const flattenFileList = [];
15+
const progressFileList = [];
16+
files.forEach(file => progressFileList.push(file.webkitGetAsEntry() as any));
17+
function loopFiles(item: InternalDataTransferItem) {
18+
const dirReader = item.createReader();
1619

17-
function sequence() {
18-
dirReader.readEntries((entries: InternalDataTransferItem[]) => {
19-
const entryList = Array.prototype.slice.apply(entries);
20-
fileList = fileList.concat(entryList);
20+
function sequence() {
21+
dirReader.readEntries((entries: InternalDataTransferItem[]) => {
22+
const entryList = Array.prototype.slice.apply(entries);
2123

22-
// Check if all the file has been viewed
23-
const isFinished = !entryList.length;
24+
progressFileList.push(...entryList);
25+
// Check if all the file has been viewed
26+
const isFinished = !entryList.length;
27+
if (!isFinished) {
28+
sequence();
29+
}
30+
});
31+
}
2432

25-
if (isFinished) {
26-
callback(fileList);
27-
} else {
28-
sequence();
29-
}
30-
});
33+
sequence();
3134
}
32-
33-
sequence();
34-
}
35-
36-
const traverseFileTree = (files: InternalDataTransferItem[], callback, isAccepted) => {
3735
// eslint-disable-next-line @typescript-eslint/naming-convention
3836
const _traverseFileTree = (item: InternalDataTransferItem, path?: string) => {
3937
if (!item) {
@@ -59,20 +57,23 @@ const traverseFileTree = (files: InternalDataTransferItem[], callback, isAccepte
5957
},
6058
});
6159
}
62-
callback([file]);
60+
flattenFileList.push(file);
6361
}
6462
});
6563
} else if (item.isDirectory) {
66-
loopFiles(item, (entries: InternalDataTransferItem[]) => {
67-
entries.forEach(entryItem => {
68-
_traverseFileTree(entryItem, `${path}${item.name}/`);
69-
});
70-
});
64+
loopFiles(item);
7165
}
7266
};
73-
files.forEach(file => {
74-
_traverseFileTree(file.webkitGetAsEntry() as any);
75-
});
67+
68+
function walkFiles() {
69+
let wipIndex = 0;
70+
while (wipIndex < progressFileList.length) {
71+
_traverseFileTree(progressFileList[wipIndex]);
72+
wipIndex++;
73+
}
74+
callback(flattenFileList);
75+
}
76+
walkFiles();
7677
};
7778

7879
export default traverseFileTree;

tests/uploader.spec.tsx

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ const makeFileSystemEntry = item => {
2525
return {
2626
readEntries(handle) {
2727
if (!first) {
28-
return [];
28+
return handle([]);
2929
}
3030

3131
first = false;
@@ -373,7 +373,54 @@ describe('uploader', () => {
373373
beforeEach(() => {
374374
uploader = render(<Upload {...props} />);
375375
});
376+
it('beforeUpload should run after all children files are parsed', done => {
377+
const props = { action: '/test', directory: true, accept: '.png' };
378+
const mockBeforeUpload = jest.fn();
379+
const beforeUpload = (file, fileList) => {
380+
console.log('beforeUpload', file, fileList);
381+
mockBeforeUpload(file, fileList);
382+
};
383+
const Test = () => {
384+
return <Upload {...props} beforeUpload={beforeUpload} />;
385+
};
376386

387+
const { container } = render(<Test />);
388+
const files = {
389+
name: 'foo',
390+
children: [
391+
{
392+
name: 'bar',
393+
children: [
394+
{
395+
name: '1.png',
396+
},
397+
{
398+
name: '2.png',
399+
},
400+
{
401+
name: 'rc',
402+
children: [
403+
{
404+
name: '5.webp',
405+
},
406+
{
407+
name: '4.webp',
408+
},
409+
],
410+
},
411+
],
412+
},
413+
],
414+
};
415+
const input = container.querySelector('input')!;
416+
fireEvent.drop(input, { dataTransfer: { items: [makeDataTransferItem(files)] } });
417+
setTimeout(() => {
418+
expect(mockBeforeUpload.mock.calls.length).toBe(2);
419+
expect(mockBeforeUpload.mock.calls[0][1].length).toBe(2);
420+
expect(mockBeforeUpload.mock.calls[1][1].length).toBe(2);
421+
done();
422+
}, 100);
423+
});
377424
it('unaccepted type files to upload will not trigger onStart', done => {
378425
const input = uploader.container.querySelector('input')!;
379426
const files = {

0 commit comments

Comments
 (0)