|
|
@ -78,6 +78,252 @@ export const FileExplorer = (props: FileExplorerProps) => { |
|
|
|
setState(workspaceState) |
|
|
|
setState(workspaceState) |
|
|
|
}, [workspaceState]) |
|
|
|
}, [workspaceState]) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
|
|
|
|
if (treeRef.current) { |
|
|
|
|
|
|
|
const keyPressHandler = (e: KeyboardEvent) => { |
|
|
|
|
|
|
|
if (e.shiftKey) { |
|
|
|
|
|
|
|
setState((prevState) => { |
|
|
|
|
|
|
|
return { ...prevState, ctrlKey: true } |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const keyUpHandler = (e: KeyboardEvent) => { |
|
|
|
|
|
|
|
if (!e.shiftKey) { |
|
|
|
|
|
|
|
setState((prevState) => { |
|
|
|
|
|
|
|
return { ...prevState, ctrlKey: false } |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
const targetDocument = treeRef.current |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
targetDocument.addEventListener('keydown', keyPressHandler) |
|
|
|
|
|
|
|
targetDocument.addEventListener('keyup', keyUpHandler) |
|
|
|
|
|
|
|
return () => { |
|
|
|
|
|
|
|
targetDocument.removeEventListener('keydown', keyPressHandler) |
|
|
|
|
|
|
|
targetDocument.removeEventListener('keyup', keyUpHandler) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}, [treeRef.current]) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
|
|
|
|
const performDeletion = async () => { |
|
|
|
|
|
|
|
const path: string[] = [] |
|
|
|
|
|
|
|
if (feTarget?.length > 0 && feTarget[0]?.key.length > 0) { |
|
|
|
|
|
|
|
feTarget.forEach((one) => { |
|
|
|
|
|
|
|
path.push(one.key) |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
await deletePath(path) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (treeRef.current) { |
|
|
|
|
|
|
|
const deleteKeyPressHandler = async (eve: KeyboardEvent) => { |
|
|
|
|
|
|
|
if (eve.key === 'Delete' ) { |
|
|
|
|
|
|
|
feWindow._paq.push(['trackEvent', 'fileExplorer', 'deleteKey', 'deletePath']) |
|
|
|
|
|
|
|
setState((prevState) => { |
|
|
|
|
|
|
|
return { ...prevState, deleteKey: true } |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
performDeletion() |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (eve.metaKey) { |
|
|
|
|
|
|
|
if (eve.key === 'Backspace') { |
|
|
|
|
|
|
|
feWindow._paq.push(['trackEvent', 'fileExplorer', 'osxDeleteKey', 'deletePath']) |
|
|
|
|
|
|
|
setState((prevState) => { |
|
|
|
|
|
|
|
return { ...prevState, deleteKey: true } |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
performDeletion() |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
const deleteKeyPressUpHandler = async (eve: KeyboardEvent) => { |
|
|
|
|
|
|
|
if (eve.key === 'Delete' ) { |
|
|
|
|
|
|
|
setState((prevState) => { |
|
|
|
|
|
|
|
return { ...prevState, deleteKey: false } |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (eve.metaKey) { |
|
|
|
|
|
|
|
if (eve.key === 'Backspace') { |
|
|
|
|
|
|
|
setState((prevState) => { |
|
|
|
|
|
|
|
return { ...prevState, deleteKey: false } |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
treeRef.current?.addEventListener('keydown', deleteKeyPressHandler) |
|
|
|
|
|
|
|
treeRef.current?.addEventListener('keyup', deleteKeyPressUpHandler) |
|
|
|
|
|
|
|
return () => { |
|
|
|
|
|
|
|
treeRef.current?.removeEventListener('keydown', deleteKeyPressHandler) |
|
|
|
|
|
|
|
treeRef.current?.removeEventListener('keyup', deleteKeyPressUpHandler) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}, [treeRef.current, feTarget]) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
|
|
|
|
const performRename = async () => { |
|
|
|
|
|
|
|
if (feTarget?.length > 1 && feTarget[0]?.key.length > 1) { |
|
|
|
|
|
|
|
await plugin.call('notification', 'alert', { id: 'renameAlert', message: 'You cannot rename multiple files at once!' }) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
props.editModeOn(feTarget[0].key, feTarget[0].type, false) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (treeRef.current) { |
|
|
|
|
|
|
|
const F2KeyPressHandler = async (eve: KeyboardEvent) => { |
|
|
|
|
|
|
|
if (eve.key === 'F2' ) { |
|
|
|
|
|
|
|
feWindow._paq.push(['trackEvent', 'fileExplorer', 'f2ToRename', 'RenamePath']) |
|
|
|
|
|
|
|
await performRename() |
|
|
|
|
|
|
|
setState((prevState) => { |
|
|
|
|
|
|
|
return { ...prevState, F2Key: true } |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
const F2KeyPressUpHandler = async (eve: KeyboardEvent) => { |
|
|
|
|
|
|
|
if (eve.key === 'F2' ) { |
|
|
|
|
|
|
|
setState((prevState) => { |
|
|
|
|
|
|
|
return { ...prevState, F2Key: false } |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
treeRef.current?.addEventListener('keydown', F2KeyPressHandler) |
|
|
|
|
|
|
|
treeRef.current?.addEventListener('keyup', F2KeyPressUpHandler) |
|
|
|
|
|
|
|
return () => { |
|
|
|
|
|
|
|
treeRef.current?.removeEventListener('keydown', F2KeyPressHandler) |
|
|
|
|
|
|
|
treeRef.current?.removeEventListener('keyup', F2KeyPressUpHandler) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}, [treeRef.current, feTarget]) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
|
|
|
|
const performCopy = async () => { |
|
|
|
|
|
|
|
if (feTarget?.length > 0 && feTarget[0]?.key.length > 0) { |
|
|
|
|
|
|
|
if (feTarget?.length > 1) { |
|
|
|
|
|
|
|
handleMultiCopies(feTarget) |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
handleCopyClick(feTarget[0].key, feTarget[0].type) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const performCut = async () => { |
|
|
|
|
|
|
|
if (feTarget) { |
|
|
|
|
|
|
|
if (feTarget.length > 0 && feTarget[0].key.length > 0) { |
|
|
|
|
|
|
|
handleMultiCopies(feTarget) |
|
|
|
|
|
|
|
setCutActivated(true) |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
handleCopyClick(feTarget[0].key, feTarget[0].type) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const performPaste = async () => { |
|
|
|
|
|
|
|
if (feTarget.length > 0 && feTarget[0]?.key.length >= 0) { |
|
|
|
|
|
|
|
if (cutActivated) { |
|
|
|
|
|
|
|
if (state.copyElement.length > 1) { |
|
|
|
|
|
|
|
const promisesToKeep = state.copyElement.filter(x => x).map(async (item) => { |
|
|
|
|
|
|
|
if (item.type === 'file') { |
|
|
|
|
|
|
|
props.dispatchMoveFile(item.key, feTarget[0].key) |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
props.dispatchMoveFolder(item.key, feTarget[0].key) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
await Promise.all(promisesToKeep) |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
if (state.copyElement[0].type === 'file') { |
|
|
|
|
|
|
|
props.dispatchMoveFile(state.copyElement[0].key, feTarget[0].key) |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
props.dispatchMoveFolder(state.copyElement[0].key, feTarget[0].key) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
handlePasteClick(feTarget[0].key, feTarget[0].type) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (treeRef.current) { |
|
|
|
|
|
|
|
const targetDocument = treeRef.current |
|
|
|
|
|
|
|
let CopyComboHandler: (eve: KeyboardEvent) => Promise<void> |
|
|
|
|
|
|
|
let CutHandler: (eve: KeyboardEvent) => Promise<void> |
|
|
|
|
|
|
|
let pasteHandler: (eve: KeyboardEvent) => Promise<void> |
|
|
|
|
|
|
|
let pcCopyHandler: (eve: KeyboardEvent) => Promise<void> |
|
|
|
|
|
|
|
let pcCutHandler: (eve: KeyboardEvent) => Promise<void> |
|
|
|
|
|
|
|
let pcPasteHandler: (eve: KeyboardEvent) => Promise<void> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if ((window as any).navigator.userAgentData.platform === 'macOS') { |
|
|
|
|
|
|
|
CopyComboHandler = async (eve: KeyboardEvent) => { |
|
|
|
|
|
|
|
if (eve.metaKey && eve.code === 'KeyC') { |
|
|
|
|
|
|
|
feWindow._paq.push(['trackEvent', 'fileExplorer', 'f2ToRename', 'RenamePath']) |
|
|
|
|
|
|
|
await performCopy() |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CutHandler = async (eve: KeyboardEvent) => { |
|
|
|
|
|
|
|
if (eve.metaKey && eve.code === 'KeyX') { |
|
|
|
|
|
|
|
feWindow._paq.push(['trackEvent', 'fileExplorer', 'f2ToRename', 'RenamePath']) |
|
|
|
|
|
|
|
await performCut() |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pasteHandler = async (eve: KeyboardEvent) => { |
|
|
|
|
|
|
|
if (eve.metaKey && eve.code === 'KeyV') { |
|
|
|
|
|
|
|
feWindow._paq.push(['trackEvent', 'fileExplorer', 'metaVToPaste', 'PasteCopiedContent']) |
|
|
|
|
|
|
|
performPaste() |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
pcCopyHandler = async (eve: KeyboardEvent) => { |
|
|
|
|
|
|
|
if (eve.ctrlKey && (eve.key === 'c' || eve.key === 'C')) { |
|
|
|
|
|
|
|
feWindow._paq.push(['trackEvent', 'fileExplorer', 'f2ToRename', 'RenamePath']) |
|
|
|
|
|
|
|
await performCopy() |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pcCutHandler = async (eve: KeyboardEvent) => { |
|
|
|
|
|
|
|
if (eve.ctrlKey && eve.code === 'KeyX') { |
|
|
|
|
|
|
|
feWindow._paq.push(['trackEvent', 'fileExplorer', 'f2ToRename', 'RenamePath']) |
|
|
|
|
|
|
|
await performCut() |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pcPasteHandler = async (eve: KeyboardEvent) => { |
|
|
|
|
|
|
|
if (eve.key === 'Control' && eve.code === 'KeyV') { |
|
|
|
|
|
|
|
feWindow._paq.push(['trackEvent', 'fileExplorer', 'ctrlVToPaste', 'PasteCopiedContent']) |
|
|
|
|
|
|
|
performPaste() |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
targetDocument?.addEventListener('keydown', CopyComboHandler) |
|
|
|
|
|
|
|
targetDocument?.addEventListener('keydown', CutHandler) |
|
|
|
|
|
|
|
targetDocument?.addEventListener('keydown', pasteHandler) |
|
|
|
|
|
|
|
targetDocument?.addEventListener('keydown', pcPasteHandler) |
|
|
|
|
|
|
|
targetDocument?.addEventListener('keydown', pcCopyHandler) |
|
|
|
|
|
|
|
targetDocument?.addEventListener('keydown', pcCutHandler) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return () => { |
|
|
|
|
|
|
|
targetDocument?.removeEventListener('keydown', pasteHandler) |
|
|
|
|
|
|
|
targetDocument?.removeEventListener('keydown', pcPasteHandler) |
|
|
|
|
|
|
|
targetDocument?.removeEventListener('keydown', CutHandler) |
|
|
|
|
|
|
|
targetDocument?.removeEventListener('keydown', pcCutHandler) |
|
|
|
|
|
|
|
targetDocument?.removeEventListener('keydown', CopyComboHandler) |
|
|
|
|
|
|
|
targetDocument?.removeEventListener('keydown', pcCopyHandler) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}, [treeRef.current, feTarget]) |
|
|
|
|
|
|
|
|
|
|
|
const hasReservedKeyword = (content: string): boolean => { |
|
|
|
const hasReservedKeyword = (content: string): boolean => { |
|
|
|
if (state.reservedKeywords.findIndex((value) => content.startsWith(value)) !== -1) return true |
|
|
|
if (state.reservedKeywords.findIndex((value) => content.startsWith(value)) !== -1) return true |
|
|
|
else return false |
|
|
|
else return false |
|
|
|