174 lines
4.1 KiB
TypeScript
174 lines
4.1 KiB
TypeScript
/**
|
|
* 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
|