Initial commit
This commit is contained in:
173
src/composables/useFileSelection.ts
Normal file
173
src/composables/useFileSelection.ts
Normal file
@@ -0,0 +1,173 @@
|
||||
/**
|
||||
* File selection composable
|
||||
* Provides reactive selection management for file manager
|
||||
*/
|
||||
|
||||
import { ref, computed } from 'vue'
|
||||
import type { Ref, ComputedRef } from 'vue'
|
||||
import { FileCollectionObject } from '@FileManager/models/collection'
|
||||
import { FileEntityObject } from '@FileManager/models/entity'
|
||||
|
||||
type NodeRecord = FileCollectionObject | FileEntityObject
|
||||
|
||||
export interface UseFileSelectionOptions {
|
||||
multiple?: boolean
|
||||
allowFolders?: boolean
|
||||
allowFiles?: boolean
|
||||
}
|
||||
|
||||
export function useFileSelection(options: UseFileSelectionOptions = {}) {
|
||||
const {
|
||||
multiple = true,
|
||||
allowFolders = true,
|
||||
allowFiles = true
|
||||
} = options
|
||||
|
||||
const selectedIds: Ref<Set<string>> = ref(new Set())
|
||||
const selectedNodes: Ref<Map<string, NodeRecord>> = ref(new Map())
|
||||
|
||||
// Get selected count
|
||||
const count: ComputedRef<number> = computed(() => selectedIds.value.size)
|
||||
|
||||
// Check if any selected
|
||||
const hasSelection: ComputedRef<boolean> = computed(() => selectedIds.value.size > 0)
|
||||
|
||||
// Get selected IDs as array
|
||||
const selectedIdArray: ComputedRef<string[]> = computed(() =>
|
||||
Array.from(selectedIds.value)
|
||||
)
|
||||
|
||||
// Get selected nodes as array
|
||||
const selectedNodeArray: ComputedRef<NodeRecord[]> = computed(() =>
|
||||
Array.from(selectedNodes.value.values())
|
||||
)
|
||||
|
||||
// Get selected collections only
|
||||
const selectedCollections: ComputedRef<FileCollectionObject[]> = computed(() =>
|
||||
selectedNodeArray.value.filter(
|
||||
(node): node is FileCollectionObject => node['@type'] === 'files.collection'
|
||||
)
|
||||
)
|
||||
|
||||
// Get selected entities only
|
||||
const selectedEntities: ComputedRef<FileEntityObject[]> = computed(() =>
|
||||
selectedNodeArray.value.filter(
|
||||
(node): node is FileEntityObject => node['@type'] === 'files.entity'
|
||||
)
|
||||
)
|
||||
|
||||
// Check if a node is selected
|
||||
const isSelected = (nodeId: string): boolean => {
|
||||
return selectedIds.value.has(nodeId)
|
||||
}
|
||||
|
||||
// Check if node type is allowed
|
||||
const isTypeAllowed = (node: NodeRecord): boolean => {
|
||||
if (node['@type'] === 'files.collection' && !allowFolders) {
|
||||
return false
|
||||
}
|
||||
if (node['@type'] === 'files.entity' && !allowFiles) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Select a node
|
||||
const select = (node: NodeRecord) => {
|
||||
if (!isTypeAllowed(node)) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!multiple) {
|
||||
// Clear previous selection for single select
|
||||
selectedIds.value.clear()
|
||||
selectedNodes.value.clear()
|
||||
}
|
||||
|
||||
selectedIds.value.add(node.id)
|
||||
selectedNodes.value.set(node.id, node)
|
||||
}
|
||||
|
||||
// Deselect a node
|
||||
const deselect = (nodeId: string) => {
|
||||
selectedIds.value.delete(nodeId)
|
||||
selectedNodes.value.delete(nodeId)
|
||||
}
|
||||
|
||||
// Toggle selection
|
||||
const toggle = (node: NodeRecord) => {
|
||||
if (isSelected(node.id)) {
|
||||
deselect(node.id)
|
||||
} else {
|
||||
select(node)
|
||||
}
|
||||
}
|
||||
|
||||
// Select multiple nodes
|
||||
const selectMultiple = (nodes: NodeRecord[]) => {
|
||||
if (!multiple) {
|
||||
// For single select, only select the last one
|
||||
const lastNode = nodes[nodes.length - 1]
|
||||
if (lastNode && isTypeAllowed(lastNode)) {
|
||||
selectedIds.value.clear()
|
||||
selectedNodes.value.clear()
|
||||
selectedIds.value.add(lastNode.id)
|
||||
selectedNodes.value.set(lastNode.id, lastNode)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
for (const node of nodes) {
|
||||
if (isTypeAllowed(node)) {
|
||||
selectedIds.value.add(node.id)
|
||||
selectedNodes.value.set(node.id, node)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Select all from a list
|
||||
const selectAll = (nodes: NodeRecord[]) => {
|
||||
if (!multiple) {
|
||||
return
|
||||
}
|
||||
selectMultiple(nodes)
|
||||
}
|
||||
|
||||
// Clear selection
|
||||
const clear = () => {
|
||||
selectedIds.value.clear()
|
||||
selectedNodes.value.clear()
|
||||
}
|
||||
|
||||
// Set selection (replace current)
|
||||
const setSelection = (nodes: NodeRecord[]) => {
|
||||
clear()
|
||||
selectMultiple(nodes)
|
||||
}
|
||||
|
||||
return {
|
||||
// State
|
||||
selectedIds,
|
||||
selectedNodes,
|
||||
|
||||
// Computed
|
||||
count,
|
||||
hasSelection,
|
||||
selectedIdArray,
|
||||
selectedNodeArray,
|
||||
selectedCollections,
|
||||
selectedEntities,
|
||||
|
||||
// Methods
|
||||
isSelected,
|
||||
select,
|
||||
deselect,
|
||||
toggle,
|
||||
selectMultiple,
|
||||
selectAll,
|
||||
clear,
|
||||
setSelection,
|
||||
}
|
||||
}
|
||||
|
||||
export default useFileSelection
|
||||
Reference in New Issue
Block a user