// (c) Copyright Ascensio System SIA 2009-2024 // // This program is a free software product. // You can redistribute it and/or modify it under the terms // of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software // Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended // to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of // any third-party rights. // // This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see // the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html // // You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021. // // The interactive user interfaces in modified source and object code versions of the Program must // display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3. // // Pursuant to Section 7(b) of the License you must retain the original Product logo when // distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under // trademark law for use of our trademarks. // // All the Product's GUI elements, including illustrations and icon sets, as well as technical writing // content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0 // International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode /* eslint-disable prefer-template */ /* eslint-disable prefer-promise-reject-errors */ /* eslint-disable no-plusplus */ /* eslint-disable @typescript-eslint/no-use-before-define */ /* eslint-disable @typescript-eslint/no-explicit-any */ function toFileWithPath(file: any, path: any) { if (typeof file?.path === "string") return file; // on electron, path is already set to the absolute path const { webkitRelativePath } = file; Object.defineProperty(file, "path", { value: typeof path === "string" ? path : // If is set, // the File will have a {webkitRelativePath} property // https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/webkitdirectory typeof webkitRelativePath === "string" && webkitRelativePath.length > 0 ? webkitRelativePath : file.name, }); return file; } const FILES_TO_IGNORE = [ // Thumbnail cache files for macOS and Windows ".DS_Store", "Thumbs.db", // Windows ]; /** * Convert a DragEvent's DataTrasfer object to a list of File objects * NOTE: If some of the items are folders, * everything will be flattened and placed in the same list but the paths will be kept as a {path} property. * @param evt */ export default async function getFilesFromEvent(evt: any) { return (isDragEvt(evt) && evt.dataTransfer) || evt.clipboardData ? getDataTransferFiles(evt.dataTransfer ?? evt.clipboardData, evt.type) : getInputFiles(evt); } function isDragEvt(value: any) { return !!value.dataTransfer; } function getInputFiles(evt: any) { const files = isInput(evt.target) ? evt.target.files ? fromList(evt.target.files) : [] : []; // @ts-expect-error TS(2554): Expected 2 arguments, but got 1. return files.map((file) => toFileWithPath(file)); } function isInput(value: any) { return value !== null; } async function getDataTransferFiles(dt: any, type: any) { // IE11 does not support dataTransfer.items // See https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer/items#Browser_compatibility if (dt.items) { const items = fromList(dt.items).filter((item) => item.kind === "file"); // According to https://html.spec.whatwg.org/multipage/dnd.html#dndevents, // only 'dragstart' and 'drop' has access to the data (source node) if (type !== "drop" && type !== "paste") { return items; } const files = await Promise.all(items.map(toFilePromises)); return noIgnoredFiles(flatten(files)); } // @ts-expect-error TS(2554): Expected 2 arguments, but got 1. return noIgnoredFiles(fromList(dt.files).map((file) => toFileWithPath(file))); } function noIgnoredFiles(files: any) { return files.filter((file: any) => FILES_TO_IGNORE.indexOf(file.name) === -1); } // IE11 does not support Array.from() // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from#Browser_compatibility // https://developer.mozilla.org/en-US/docs/Web/API/FileList // https://developer.mozilla.org/en-US/docs/Web/API/DataTransferItemList function fromList(items: any) { const files = []; // tslint:disable: prefer-for-of for (let i = 0; i < items.length; i++) { const file = items[i]; files.push(file); } return files; } // https://developer.mozilla.org/en-US/docs/Web/API/DataTransferItem function toFilePromises(item: any) { if (typeof item.webkitGetAsEntry !== "function") { return fromDataTransferItem(item); } const entry = item.webkitGetAsEntry(); // Safari supports dropping an image node from a different window and can be retrieved using // the DataTransferItem.getAsFile() API // NOTE: FileSystemEntry.file() throws if trying to get the file if (entry && entry.isDirectory) { return fromDirEntry(entry); } return fromDataTransferItem(item); } function flatten(items: any) { return items.reduce( (acc: any, files: any) => [ ...acc, ...(Array.isArray(files) ? flatten(files) : [files]), ], [], ); } function fromDataTransferItem(item: any) { const file = item.getAsFile(); if (!file) { return Promise.reject(`${item} is not a File`); } // @ts-expect-error TS(2554): Expected 2 arguments, but got 1. const fwp = toFileWithPath(file); return Promise.resolve(fwp); } // https://developer.mozilla.org/en-US/docs/Web/API/FileSystemEntry async function fromEntry(entry: any) { return entry.isDirectory ? fromDirEntry(entry) : fromFileEntry(entry); } // https://developer.mozilla.org/en-US/docs/Web/API/FileSystemDirectoryEntry function fromDirEntry(entry: any) { const reader = entry.createReader(); return new Promise((resolve, reject) => { const entries: any = []; let empty = true; function readEntries() { // https://developer.mozilla.org/en-US/docs/Web/API/FileSystemDirectoryEntry/createReader // https://developer.mozilla.org/en-US/docs/Web/API/FileSystemDirectoryReader/readEntries reader.readEntries( async (batch: any) => { if (!batch.length) { // Done reading directory try { const files = await Promise.all(entries); if (empty) { files.push([createEmptyDirFile(entry)]); } resolve(files); } catch (err) { reject(err); } } else { const items = Promise.all(batch.map(fromEntry)); entries.push(items); // Continue reading empty = false; readEntries(); } }, (err: any) => { reject(err); }, ); } readEntries(); }); } function createEmptyDirFile(entry: any) { const file = new File([], entry.name); const fwp = toFileWithPath(file, entry.fullPath + "/"); Object.defineProperty(fwp, "isEmptyDirectory", { value: true, }); return fwp; } // https://developer.mozilla.org/en-US/docs/Web/API/FileSystemFileEntry async function fromFileEntry(entry: any) { return new Promise((resolve, reject) => { entry.file( (file: any) => { const fwp = toFileWithPath(file, entry.fullPath); resolve(fwp); }, (err: any) => { reject(err); }, ); }); }