|
507 | 507 | var files = []; |
508 | 508 | var len = entries.length; |
509 | 509 | var cb = 0; |
| 510 | + if (!len) { |
| 511 | + onDone(files); |
| 512 | + } |
510 | 513 |
|
511 | 514 | function increaseCb() { |
512 | 515 | cb++; |
|
545 | 548 | } |
546 | 549 |
|
547 | 550 | function itemsToFiles(dataTransferItems, onDone) { |
| 551 | + var files = []; |
| 552 | + var len = dataTransferItems.length; |
| 553 | + if (!len) { |
| 554 | + onDone(files); |
| 555 | + } |
| 556 | + |
548 | 557 | var entries = []; |
549 | | - for (var i = 0, len = dataTransferItems.length; i < len; i++) { |
550 | | - var entry = dataTransferItems[i].webkitGetAsEntry(); |
551 | | - entries.push(entry); |
| 558 | + for (var i = 0; i < len; i++) { |
| 559 | + var item = dataTransferItems[i]; |
| 560 | + var entry = item.webkitGetAsEntry(); |
| 561 | + if (!entry) { |
| 562 | + continue; |
| 563 | + } |
| 564 | + if (entry.isFile) { |
| 565 | + // Safari cannot get file from entry by entry.file(), if it is a pasted image |
| 566 | + // so workaround is for all browsers, just get first hierarchy of files by item.getAsFile() |
| 567 | + var file = item.getAsFile(); |
| 568 | + files.push({file: file, relativePath: file.name}); |
| 569 | + } else { |
| 570 | + entries.push(entry); |
| 571 | + } |
552 | 572 | } |
553 | | - entriesToFiles(entries, onDone); |
| 573 | + |
| 574 | + entriesToFiles(entries, function (entryFiles) { |
| 575 | + files.push.apply(files, entryFiles); |
| 576 | + onDone(files); |
| 577 | + }); |
554 | 578 | } |
555 | 579 |
|
556 | 580 | function itemsHasDir(dataTransferItems) { |
|
562 | 586 | if (items.length && items[0].webkitGetAsEntry) { |
563 | 587 | for (var i = 0, len = items.length; i < len; i++) { |
564 | 588 | var entry = items[i].webkitGetAsEntry(); |
565 | | - if (entry.isDirectory) { |
| 589 | + if (entry && entry.isDirectory) { |
566 | 590 | hasDir = true; |
567 | 591 | break; |
568 | 592 | } |
|
579 | 603 | } |
580 | 604 |
|
581 | 605 | function switchToDirMode() { |
582 | | - if (!optDirFile && !optInnerDirFile) { |
583 | | - return; |
| 606 | + if (optDirFile) { |
| 607 | + if (optActive !== optDirFile) { |
| 608 | + optDirFile.focus(); |
| 609 | + optDirFile.click(); |
| 610 | + } |
| 611 | + } else if (optInnerDirFile) { |
| 612 | + if (optActive !== optInnerDirFile) { |
| 613 | + optInnerDirFile.focus(); |
| 614 | + optInnerDirFile.click(); |
| 615 | + } |
584 | 616 | } |
| 617 | + } |
| 618 | + |
| 619 | + function switchToAnyDirMode() { |
585 | 620 | if (optActive === optFile) { |
586 | 621 | if (optDirFile) { |
587 | 622 | optDirFile.focus(); |
|
818 | 853 | return; |
819 | 854 | } |
820 | 855 |
|
821 | | - if (itemsHasDir(e.dataTransfer.items)) { |
| 856 | + var items = e.dataTransfer.items; |
| 857 | + if (itemsHasDir(items)) { |
822 | 858 | if (!uploadProgressively) { |
823 | 859 | // must use progressive upload by JS if has directory |
824 | 860 | return; |
825 | 861 | } |
826 | | - switchToDirMode(); |
827 | 862 | btnSubmit.disabled = true; // disable earlier |
828 | | - itemsToFiles(e.dataTransfer.items, function (files) { |
| 863 | + var itemsCount = items.length; // save items count earlier, items will be lost after calling FileSystemFileEntry.file() |
| 864 | + itemsToFiles(items, function (files) { |
| 865 | + itemsCount > 1 ? switchToDirMode() : switchToAnyDirMode(); |
829 | 866 | uploadProgressively(files); |
830 | 867 | }); |
831 | 868 | } else { |
|
861 | 898 | } |
862 | 899 |
|
863 | 900 | var typeTextPlain = 'text/plain'; |
| 901 | + var createTextFile; |
| 902 | + var textFilename = 'text.txt'; |
| 903 | + if (Blob && Blob.prototype.msClose) { // legacy Edge |
| 904 | + createTextFile = function (content) { |
| 905 | + var file = new Blob([content], {type: typeTextPlain}); |
| 906 | + file.name = textFilename; |
| 907 | + return file; |
| 908 | + }; |
| 909 | + } else if (File) { |
| 910 | + createTextFile = function (content) { |
| 911 | + return new File([content], textFilename, {type: typeTextPlain}); |
| 912 | + } |
| 913 | + } |
| 914 | + |
| 915 | + var nonTextInputTypes = ['hidden', 'radio', 'checkbox', 'button', 'reset', 'submit', 'image']; |
864 | 916 |
|
865 | 917 | function uploadPastedFiles(files) { |
866 | 918 | switchToFileMode(); |
|
880 | 932 | uploadProgressively(files); |
881 | 933 | } |
882 | 934 |
|
883 | | - var createTextFile; |
884 | | - var textFilename = 'text.txt'; |
885 | | - if (Blob && Blob.prototype.msClose) { // legacy Edge |
886 | | - createTextFile = function (content) { |
887 | | - var file = new Blob([content], {type: typeTextPlain}); |
888 | | - file.name = textFilename; |
889 | | - return file; |
890 | | - }; |
891 | | - } else if (File) { |
892 | | - createTextFile = function (content) { |
893 | | - return new File([content], textFilename, {type: typeTextPlain}); |
894 | | - } |
895 | | - } |
896 | | - |
897 | | - var nonTextInputTypes = ['hidden', 'radio', 'checkbox', 'button', 'reset', 'submit', 'image']; |
898 | | - document.documentElement.addEventListener('paste', function (e) { |
899 | | - var tagName = e.target.tagName; |
900 | | - if (tagName === 'INPUT') { |
901 | | - if (nonTextInputTypes.indexOf(e.target.type) < 0) { |
902 | | - return; |
903 | | - } |
904 | | - } |
905 | | - if (tagName === 'TEXTAREA') { |
906 | | - return; |
907 | | - } |
908 | | - var data = e.clipboardData; |
909 | | - if (!data) { |
910 | | - return; |
911 | | - } |
912 | | - |
| 935 | + function generatePastedFiles(data) { |
913 | 936 | var files; |
914 | 937 | var items; |
915 | 938 | if (data.files && data.files.length) { |
| 939 | + // pasted content is image |
916 | 940 | files = Array.prototype.slice.call(data.files); |
917 | 941 | } else if (data.items && data.items.length) { |
| 942 | + // pasted content is text |
918 | 943 | items = Array.prototype.slice.call(data.items); |
919 | 944 | files = items.map(function (item) { |
920 | 945 | return item.getAsFile(); |
|
948 | 973 | } |
949 | 974 | }); |
950 | 975 | } |
| 976 | + } |
| 977 | + |
| 978 | + document.documentElement.addEventListener('paste', function (e) { |
| 979 | + var tagName = e.target.tagName; |
| 980 | + if (tagName === 'INPUT') { |
| 981 | + if (nonTextInputTypes.indexOf(e.target.type) < 0) { |
| 982 | + return; |
| 983 | + } |
| 984 | + } |
| 985 | + if (tagName === 'TEXTAREA') { |
| 986 | + return; |
| 987 | + } |
| 988 | + var data = e.clipboardData; |
| 989 | + if (!data) { |
| 990 | + return; |
| 991 | + } |
| 992 | + |
| 993 | + var items = data.items; |
| 994 | + var itemsCount = items.length; // save items count earlier, items will be lost after calling FileSystemFileEntry.file() |
| 995 | + if (!items || !itemsCount) { |
| 996 | + generatePastedFiles(data); |
| 997 | + return; |
| 998 | + } |
| 999 | + var hasDir = itemsHasDir(items); |
| 1000 | + itemsToFiles(items, function (files) { |
| 1001 | + if (!files.length) { |
| 1002 | + // for pasted text |
| 1003 | + generatePastedFiles(data); |
| 1004 | + return; |
| 1005 | + } |
| 1006 | + if (files.length === 1 && files[0].file.type === 'image/png') { |
| 1007 | + // suppose for pasted image |
| 1008 | + files = files.map(function (fileInfo) { |
| 1009 | + return fileInfo && fileInfo.file; |
| 1010 | + }); |
| 1011 | + generatePastedFiles({files: files}); |
| 1012 | + return; |
| 1013 | + } |
| 1014 | + // pasted real files, not image binary |
| 1015 | + if (hasDir) { |
| 1016 | + itemsCount > 1 ? switchToDirMode() : switchToAnyDirMode(); |
| 1017 | + } else { |
| 1018 | + switchToFileMode(); |
| 1019 | + } |
| 1020 | + uploadProgressively(files); |
| 1021 | + }); |
951 | 1022 | }); |
952 | 1023 | } |
953 | 1024 |
|
|
0 commit comments