|
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