Skip to content

Commit ca28f62

Browse files
committed
fix: fix regression in 9c8be3a and close #9
1 parent 1471fed commit ca28f62

File tree

2 files changed

+73
-11
lines changed

2 files changed

+73
-11
lines changed

src/file-selector.spec.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,26 @@ it('should return the evt {target} {files} if the passed event is an input evt',
3333
expect(file.path).toBe(name);
3434
});
3535

36+
it('should return {files} from DataTransfer if {items} is not defined (e.g. IE11)', async () => {
37+
const name = 'test.json';
38+
const mockFile = createFile(name, {ping: true}, {
39+
type: 'application/json'
40+
});
41+
const evt = dragEvt([mockFile]);
42+
43+
const files = await fromEvent(evt);
44+
expect(files).toHaveLength(1);
45+
expect(files.every(file => file instanceof File)).toBe(true);
46+
47+
const [file] = files as FileWithPath[];
48+
49+
expect(file.name).toBe(mockFile.name);
50+
expect(file.type).toBe(mockFile.type);
51+
expect(file.size).toBe(mockFile.size);
52+
expect(file.lastModified).toBe(mockFile.lastModified);
53+
expect(file.path).toBe(name);
54+
});
55+
3656
it('should return an empty array if the evt {target} has no {files} prop', async () => {
3757
const evt = inputEvtFromFiles();
3858
const files = await fromEvent(evt);
@@ -156,6 +176,15 @@ it(
156176
}
157177
);
158178

179+
it('filters thumbnail cache files', async () => {
180+
const mockFile = createFile('Thumbs.db', {ping: true}, {
181+
type: 'text/plain'
182+
});
183+
const evt = dragEvt([mockFile]);
184+
const items = await fromEvent(evt);
185+
expect(items).toHaveLength(0);
186+
});
187+
159188
it('should throw if reading dir entries fails', async done => {
160189
const mockFiles = sortFiles([
161190
createFile('ping.json', {ping: true}),
@@ -220,6 +249,13 @@ function dragEvtFromItems(items: DataTransferItem | DataTransferItem[], type: st
220249
} as any;
221250
}
222251

252+
function dragEvt(files?: File[], items?: DataTransferItem[], type: string = 'drop'): DragEvent {
253+
return {
254+
type,
255+
dataTransfer: {items, files}
256+
} as any;
257+
}
258+
223259
function dragEvtFromFilesAndItems(files: File[], items: DataTransferItem[], type: string = 'drop'): DragEvent {
224260
return {
225261
type,

src/file-selector.ts

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import {FileWithPath, toFileWithPath} from './file';
22

33

44
const FILES_TO_IGNORE = [
5+
// Thumbnail cache files for macOS and Windows
56
'.DS_Store', // macOs
67
'Thumbs.db' // Windows
78
];
@@ -26,7 +27,7 @@ function isDragEvt(value: any): value is DragEvent {
2627
function getInputFiles(evt: Event) {
2728
const files = isInput(evt.target)
2829
? evt.target.files
29-
? Array.from(evt.target.files)
30+
? fromList<File>(evt.target.files)
3031
: []
3132
: [];
3233
return files.map(file => toFileWithPath(file));
@@ -37,17 +38,42 @@ function isInput(value: EventTarget | null): value is HTMLInputElement {
3738
}
3839

3940
async function getDataTransferFiles(dt: DataTransfer, type: string) {
40-
const items = Array.from(dt.items)
41-
.filter(item => item.kind === 'file');
42-
// According to https://html.spec.whatwg.org/multipage/dnd.html#dndevents,
43-
// only 'dragstart' and 'drop' has access to the data (source node),
44-
// hence return the DataTransferItem for other event types
45-
if (type === 'drop') {
46-
const files = await Promise.all(items.map(item => toFilePromises(item)));
47-
return flatten<FileWithPath>(files)
48-
.filter(file => !FILES_TO_IGNORE.includes(file.name));
41+
// IE11 does not support dataTransfer.items
42+
// See https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer/items#Browser_compatibility
43+
if (dt.items) {
44+
const items = fromList<DataTransferItem>(dt.items)
45+
.filter(item => item.kind === 'file');
46+
// According to https://html.spec.whatwg.org/multipage/dnd.html#dndevents,
47+
// only 'dragstart' and 'drop' has access to the data (source node)
48+
if (type !== 'drop') {
49+
return items;
50+
}
51+
const files = await Promise.all(items.map(toFilePromises));
52+
return noIgnoredFiles(flatten<FileWithPath>(files));
53+
}
54+
55+
return noIgnoredFiles(fromList<File>(dt.files)
56+
.map(file => toFileWithPath(file)));
57+
}
58+
59+
function noIgnoredFiles(files: FileWithPath[]) {
60+
return files.filter(file => FILES_TO_IGNORE.indexOf(file.name) === -1);
61+
}
62+
63+
// IE11 does not support Array.from()
64+
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from#Browser_compatibility
65+
// https://developer.mozilla.org/en-US/docs/Web/API/FileList
66+
// https://developer.mozilla.org/en-US/docs/Web/API/DataTransferItemList
67+
function fromList<T>(items: DataTransferItemList | FileList): T[] {
68+
const files = [];
69+
70+
// tslint:disable: prefer-for-of
71+
for (let i = 0; i < items.length; i++) {
72+
const file = items[i];
73+
files.push(file);
4974
}
50-
return items;
75+
76+
return files as any;
5177
}
5278

5379
// https://developer.mozilla.org/en-US/docs/Web/API/DataTransferItem

0 commit comments

Comments
 (0)