Web: Files: Hotkeys: added support for copying from desktop, removed useless files-converter
This commit is contained in:
parent
7051e55778
commit
35a4287e03
@ -61,8 +61,8 @@ const withHotkeys = (Component) => {
|
|||||||
setInviteUsersWarningDialogVisible,
|
setInviteUsersWarningDialogVisible,
|
||||||
|
|
||||||
security,
|
security,
|
||||||
setHotkeysClipboard,
|
copyToClipboard,
|
||||||
moveFilesFromClipboard,
|
uploadClipboardFiles,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
@ -118,13 +118,21 @@ const withHotkeys = (Component) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const onPaste = async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
uploadClipboardFiles(t, e);
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const throttledKeyDownEvent = throttle(onKeyDown, 300);
|
const throttledKeyDownEvent = throttle(onKeyDown, 300);
|
||||||
|
|
||||||
window.addEventListener("keydown", throttledKeyDownEvent);
|
window.addEventListener("keydown", throttledKeyDownEvent);
|
||||||
|
document.addEventListener("paste", onPaste);
|
||||||
|
|
||||||
return () =>
|
return () => {
|
||||||
window.removeEventListener("keypress", throttledKeyDownEvent);
|
window.removeEventListener("keypress", throttledKeyDownEvent);
|
||||||
|
document.removeEventListener("paste", onPaste);
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
//Select/deselect item
|
//Select/deselect item
|
||||||
@ -333,9 +341,8 @@ const withHotkeys = (Component) => {
|
|||||||
hotkeysFilter
|
hotkeysFilter
|
||||||
);
|
);
|
||||||
|
|
||||||
useHotkeys("Ctrl+c", () => setHotkeysClipboard(), hotkeysFilter);
|
useHotkeys("Ctrl+c", () => copyToClipboard(t), hotkeysFilter);
|
||||||
useHotkeys("Ctrl+x", () => setHotkeysClipboard(true), hotkeysFilter);
|
useHotkeys("Ctrl+x", () => copyToClipboard(t, true), hotkeysFilter);
|
||||||
useHotkeys("Ctrl+v", () => moveFilesFromClipboard(t), hotkeysFilter);
|
|
||||||
|
|
||||||
//Upload file
|
//Upload file
|
||||||
useHotkeys(
|
useHotkeys(
|
||||||
@ -401,8 +408,8 @@ const withHotkeys = (Component) => {
|
|||||||
selectAll,
|
selectAll,
|
||||||
activateHotkeys,
|
activateHotkeys,
|
||||||
uploadFile,
|
uploadFile,
|
||||||
setHotkeysClipboard,
|
copyToClipboard,
|
||||||
moveFilesFromClipboard,
|
uploadClipboardFiles,
|
||||||
} = hotkeyStore;
|
} = hotkeyStore;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@ -489,8 +496,9 @@ const withHotkeys = (Component) => {
|
|||||||
setInviteUsersWarningDialogVisible,
|
setInviteUsersWarningDialogVisible,
|
||||||
|
|
||||||
security,
|
security,
|
||||||
setHotkeysClipboard,
|
copyToClipboard,
|
||||||
moveFilesFromClipboard,
|
|
||||||
|
uploadClipboardFiles,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
)(observer(WithHotkeys));
|
)(observer(WithHotkeys));
|
||||||
|
@ -1,128 +0,0 @@
|
|||||||
export const onConvertFiles = (e, resolve) => {
|
|
||||||
const items = e.dataTransfer.items;
|
|
||||||
const files = [];
|
|
||||||
|
|
||||||
const callItemFromQueue = (queue, callback) => {
|
|
||||||
let i = 0;
|
|
||||||
let queueLength = queue.length;
|
|
||||||
|
|
||||||
if (!queue || !queue.length) {
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
|
|
||||||
const callNext = (i) => {
|
|
||||||
queue[i]((error) => {
|
|
||||||
if (!error && i + 1 < queueLength) {
|
|
||||||
i++;
|
|
||||||
callNext(i);
|
|
||||||
} else {
|
|
||||||
callback(error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
callNext(i);
|
|
||||||
};
|
|
||||||
|
|
||||||
const readDirEntry = (dirEntry, callback) => {
|
|
||||||
const entries = [];
|
|
||||||
const dirReader = dirEntry.createReader();
|
|
||||||
|
|
||||||
const getEntries = (entriesCallback) => {
|
|
||||||
dirReader.readEntries((moreEntries) => {
|
|
||||||
if (moreEntries.length) {
|
|
||||||
Array.prototype.push.apply(entries, moreEntries);
|
|
||||||
getEntries(entriesCallback);
|
|
||||||
} else {
|
|
||||||
entriesCallback();
|
|
||||||
}
|
|
||||||
}, entriesCallback);
|
|
||||||
};
|
|
||||||
|
|
||||||
getEntries(() => {
|
|
||||||
readEntries(entries, callback);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const readEntry = (entry, callback) => {
|
|
||||||
if (entry.isFile) {
|
|
||||||
entry.file(
|
|
||||||
(file) => {
|
|
||||||
addItem(file, entry.fullPath);
|
|
||||||
callback();
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
} else if (entry.isDirectory) {
|
|
||||||
readDirEntry(entry, callback);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const readEntries = (entries, callback) => {
|
|
||||||
const queue = [];
|
|
||||||
loop(entries, (entry) => {
|
|
||||||
queue.push((func) => {
|
|
||||||
readEntry(entry, func);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
callItemFromQueue(queue, () => callback());
|
|
||||||
};
|
|
||||||
|
|
||||||
const addFile = (file, relativePath) => {
|
|
||||||
file.path = relativePath || "";
|
|
||||||
files.push(file);
|
|
||||||
};
|
|
||||||
|
|
||||||
const loop = (items, callback) => {
|
|
||||||
let itemsLength;
|
|
||||||
|
|
||||||
if (items) {
|
|
||||||
try {
|
|
||||||
itemsLength = items.length;
|
|
||||||
} catch (err) {
|
|
||||||
itemsLength = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (itemsLength === null || typeof itemsLength !== "number") {
|
|
||||||
// Loop object items
|
|
||||||
for (let key in items) {
|
|
||||||
if (items.hasOwnProperty(key)) {
|
|
||||||
if (callback(items[key], key) === false) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Loop array items
|
|
||||||
for (let i = 0; i < itemsLength; i++) {
|
|
||||||
if (callback(items[i], i) === false) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const readItems = (items, callback) => {
|
|
||||||
const entries = [];
|
|
||||||
loop(items, (item) => {
|
|
||||||
const entry = item.webkitGetAsEntry();
|
|
||||||
if (entry) {
|
|
||||||
if (entry.isFile) {
|
|
||||||
addItem(item.getAsFile(), entry.fullPath);
|
|
||||||
} else {
|
|
||||||
entries.push(entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (entries.length) {
|
|
||||||
readEntries(entries, callback);
|
|
||||||
} else {
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
readItems(items, () => resolve(files));
|
|
||||||
};
|
|
@ -6,6 +6,7 @@ import { getCategoryUrl } from "SRC_DIR/helpers/utils";
|
|||||||
import toastr from "@docspace/components/toast/toastr";
|
import toastr from "@docspace/components/toast/toastr";
|
||||||
import { RoomsType } from "@docspace/common/constants";
|
import { RoomsType } from "@docspace/common/constants";
|
||||||
import { encryptionUploadDialog } from "../helpers/desktop";
|
import { encryptionUploadDialog } from "../helpers/desktop";
|
||||||
|
import getFilesFromEvent from "@docspace/components/drag-and-drop/get-files-from-event";
|
||||||
|
|
||||||
class HotkeyStore {
|
class HotkeyStore {
|
||||||
filesStore;
|
filesStore;
|
||||||
@ -611,12 +612,38 @@ class HotkeyStore {
|
|||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
toastr.error(e);
|
toastr.error(e);
|
||||||
clearActiveOperations(fileIds, folderIds);
|
clearActiveOperations(fileIds, folderIds);
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.filesStore.setHotkeysClipboard([]);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
toastr.error(t("Common:ErrorEmptyList"));
|
toastr.error(t("Common:ErrorEmptyList"));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
uploadClipboardFiles = async (t, event) => {
|
||||||
|
const { uploadEmptyFolders } = this.filesActionsStore;
|
||||||
|
const { startUpload } = this.uploadDataStore;
|
||||||
|
const currentFolderId = this.selectedFolderStore.id;
|
||||||
|
|
||||||
|
if (this.filesStore.hotkeysClipboard.length) {
|
||||||
|
return this.moveFilesFromClipboard(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
const files = await getFilesFromEvent(event);
|
||||||
|
|
||||||
|
const emptyFolders = files.filter((f) => f.isEmptyDirectory);
|
||||||
|
|
||||||
|
if (emptyFolders.length > 0) {
|
||||||
|
uploadEmptyFolders(emptyFolders, currentFolderId).then(() => {
|
||||||
|
const onlyFiles = files.filter((f) => !f.isEmptyDirectory);
|
||||||
|
if (onlyFiles.length > 0) startUpload(onlyFiles, currentFolderId, t);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
startUpload(files, currentFolderId, t);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
get countTilesInRow() {
|
get countTilesInRow() {
|
||||||
const isDesktopView = isDesktop();
|
const isDesktopView = isDesktop();
|
||||||
const tileGap = isDesktopView ? 16 : 14;
|
const tileGap = isDesktopView ? 16 : 14;
|
||||||
|
@ -30,8 +30,8 @@ const FILES_TO_IGNORE = [
|
|||||||
* @param evt
|
* @param evt
|
||||||
*/
|
*/
|
||||||
export default async function getFilesFromEvent(evt) {
|
export default async function getFilesFromEvent(evt) {
|
||||||
return isDragEvt(evt) && evt.dataTransfer
|
return (isDragEvt(evt) && evt.dataTransfer) || evt.clipboardData
|
||||||
? getDataTransferFiles(evt.dataTransfer, evt.type)
|
? getDataTransferFiles(evt.dataTransfer ?? evt.clipboardData, evt.type)
|
||||||
: getInputFiles(evt);
|
: getInputFiles(evt);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,7 +59,7 @@ async function getDataTransferFiles(dt, type) {
|
|||||||
const items = fromList(dt.items).filter((item) => item.kind === "file");
|
const items = fromList(dt.items).filter((item) => item.kind === "file");
|
||||||
// According to https://html.spec.whatwg.org/multipage/dnd.html#dndevents,
|
// According to https://html.spec.whatwg.org/multipage/dnd.html#dndevents,
|
||||||
// only 'dragstart' and 'drop' has access to the data (source node)
|
// only 'dragstart' and 'drop' has access to the data (source node)
|
||||||
if (type !== "drop") {
|
if (type !== "drop" && type !== "paste") {
|
||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
const files = await Promise.all(items.map(toFilePromises));
|
const files = await Promise.all(items.map(toFilePromises));
|
||||||
|
Loading…
Reference in New Issue
Block a user