mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
Allow Shift-click to select a range of items in the file tree (#15147)
GitOrigin-RevId: 4651b5d094c45fb8a7447d1f3439c2f6b3578403
This commit is contained in:
parent
f67e19f6d2
commit
bbbda35d63
1 changed files with 59 additions and 1 deletions
|
@ -19,6 +19,7 @@ import { useLayoutContext } from '../../../shared/context/layout-context'
|
||||||
import usePersistedState from '../../../shared/hooks/use-persisted-state'
|
import usePersistedState from '../../../shared/hooks/use-persisted-state'
|
||||||
import usePreviousValue from '../../../shared/hooks/use-previous-value'
|
import usePreviousValue from '../../../shared/hooks/use-previous-value'
|
||||||
import { useFileTreeMainContext } from '@/features/file-tree/contexts/file-tree-main'
|
import { useFileTreeMainContext } from '@/features/file-tree/contexts/file-tree-main'
|
||||||
|
import { fileCollator } from '@/features/file-tree/util/file-collator'
|
||||||
|
|
||||||
const FileTreeSelectableContext = createContext()
|
const FileTreeSelectableContext = createContext()
|
||||||
|
|
||||||
|
@ -223,6 +224,38 @@ export function useSelectableEntity(id, type) {
|
||||||
|
|
||||||
const isSelected = selectedEntityIds.has(id)
|
const isSelected = selectedEntityIds.has(id)
|
||||||
|
|
||||||
|
const buildSelectedRange = useCallback(
|
||||||
|
id => {
|
||||||
|
const selected = []
|
||||||
|
|
||||||
|
let started = false
|
||||||
|
|
||||||
|
for (const itemId of sortedItems(fileTreeData)) {
|
||||||
|
if (itemId === id) {
|
||||||
|
selected.push(itemId)
|
||||||
|
if (started) {
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
started = true
|
||||||
|
}
|
||||||
|
} else if (selectedEntityIds.has(itemId)) {
|
||||||
|
// TODO: should only look at latest ("main") selected item
|
||||||
|
selected.push(itemId)
|
||||||
|
if (started) {
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
started = true
|
||||||
|
}
|
||||||
|
} else if (started) {
|
||||||
|
selected.push(itemId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return selected
|
||||||
|
},
|
||||||
|
[fileTreeData, selectedEntityIds]
|
||||||
|
)
|
||||||
|
|
||||||
const chooseView = useCallback(() => {
|
const chooseView = useCallback(() => {
|
||||||
for (const id of selectedEntityIds) {
|
for (const id of selectedEntityIds) {
|
||||||
const selectedEntity = findInTree(fileTreeData, id)
|
const selectedEntity = findInTree(fileTreeData, id)
|
||||||
|
@ -251,7 +284,13 @@ export function useSelectableEntity(id, type) {
|
||||||
const multiSelect =
|
const multiSelect =
|
||||||
!isRootFolderSelected && (isMac ? ev.metaKey : ev.ctrlKey)
|
!isRootFolderSelected && (isMac ? ev.metaKey : ev.ctrlKey)
|
||||||
setIsRootFolderSelected(false)
|
setIsRootFolderSelected(false)
|
||||||
|
|
||||||
|
if (ev.shiftKey) {
|
||||||
|
// use Shift to select a range of items
|
||||||
|
selectOrMultiSelectEntity(buildSelectedRange(id))
|
||||||
|
} else {
|
||||||
selectOrMultiSelectEntity(id, multiSelect)
|
selectOrMultiSelectEntity(id, multiSelect)
|
||||||
|
}
|
||||||
|
|
||||||
if (type === 'file') {
|
if (type === 'file') {
|
||||||
setView('file')
|
setView('file')
|
||||||
|
@ -268,6 +307,7 @@ export function useSelectableEntity(id, type) {
|
||||||
selectOrMultiSelectEntity,
|
selectOrMultiSelectEntity,
|
||||||
setView,
|
setView,
|
||||||
type,
|
type,
|
||||||
|
buildSelectedRange,
|
||||||
chooseView,
|
chooseView,
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
@ -328,3 +368,21 @@ export function useFileTreeSelectable() {
|
||||||
|
|
||||||
return context
|
return context
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const alphabetical = (a, b) => fileCollator.compare(a.name, b.name)
|
||||||
|
|
||||||
|
function* sortedItems(folder) {
|
||||||
|
yield folder._id
|
||||||
|
|
||||||
|
const folders = [...folder.folders].sort(alphabetical)
|
||||||
|
for (const subfolder of folders) {
|
||||||
|
for (const id of sortedItems(subfolder)) {
|
||||||
|
yield id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const files = [...folder.docs, ...folder.fileRefs].sort(alphabetical)
|
||||||
|
for (const file of files) {
|
||||||
|
yield file._id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue