blob: 935d5d2e7be08414624f21891c0fbb8b020f78b6 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { reactive, Ref, nextTick, onMounted } from 'vue'
import { useMessage } from 'naive-ui'
import { addFile, deleteFile, getFiles } from '@/service/modules/file'
import { useLocale } from '@/hooks'
import { remove } from 'lodash'
import { sameNameValidator } from './helper'
import { useFileStore } from '@/store/file'
import { getNameByType } from '@/utils/file'
import type { IFileState, FileType, IFileRecord } from './types'
export const useFile = (inputRef: Ref, fileRef: Ref) => {
const state = reactive({
currentKey: 0,
files: [],
isCreating: false
} as IFileState)
const message = useMessage()
const { t } = useLocale()
const fileStore = useFileStore()
const filesCached = {} as { [key: number]: IFileRecord }
const refreshFiles = () => {
fileRef.value.refresh()
}
const getCurrentFolderKey = (): number => {
if (state.currentKey === 0) return 0
const currentRecord = filesCached[state.currentKey]
return currentRecord.type ? currentRecord.pid : currentRecord.id
}
const pullFiles = async () => {
const files = await getFiles()
state.files = files
const loop = (list: IFileRecord[]) => {
list.forEach((file) => {
filesCached[file.id] = file
if (file.type) delete file.children
if (file.children) loop(file.children)
})
}
loop(files)
}
const create = async (isFile: boolean, type: FileType | '') => {
if (state.isCreating) return
state.isCreating = true
const currentFolderKey = getCurrentFolderKey()
const record = {
isEditing: true,
id: Date.now(),
name: '',
pid: currentFolderKey
} as IFileRecord
record.type = type
!isFile && (record.children = [])
filesCached[record.id] = record
if (currentFolderKey === 0) {
state.files.unshift(record)
} else {
filesCached[currentFolderKey].children?.unshift(record)
}
state.currentKey = record.id
refreshFiles()
await nextTick()
inputRef.value?.focus()
}
const save = async (name: string) => {
const currentRecord = filesCached[state.currentKey]
try {
const { id } = await addFile(currentRecord.pid, {
type: currentRecord.type || '',
name
})
message.success(t('saved_successfully'))
currentRecord.id = id
state.currentKey = id
delete filesCached[state.currentKey]
filesCached[id] = currentRecord
if (currentRecord.type) {
fileStore.openFile({
id,
name: getNameByType(currentRecord.type, name),
content: ''
})
}
return true
} catch (err) {
return false
}
}
const add = async (value: string) => {
if (!value) {
const currentFolderKey = getCurrentFolderKey()
currentFolderKey
? filesCached[currentFolderKey].children?.shift()
: state.files.shift()
delete filesCached[state.currentKey]
state.currentKey = currentFolderKey
refreshFiles()
return
}
const pid = filesCached[state.currentKey].pid
const isSame = sameNameValidator(
value,
pid ? filesCached[pid].children || [] : state.files
)
if (isSame) {
message.error(t('same_name_tips'))
return
}
const result = await save(value)
if (result) {
filesCached[state.currentKey].isEditing = false
filesCached[state.currentKey].name = value
refreshFiles()
}
}
const rename = async (value: string) => {
if (!value) {
message.error(t('empty_name_tips'))
return
}
filesCached[state.currentKey].isEditing = false
filesCached[state.currentKey].name = value
refreshFiles()
}
const onCreateFile = (type: FileType) => void create(true, type)
const onCreateFolder = () => void create(false, '')
const onSelectFile = (key: number) => {
state.currentKey = key
}
const onInputBlur = async (value: string) => {
if (state.isCreating) {
state.isCreating = false
add(value)
return
}
rename(value)
}
const onDelete = async (id: number) => {
const deletedRecord = filesCached[id]
if (!deletedRecord.type && deletedRecord.children?.length) {
message.error(t('delete_tips'))
return
}
await deleteFile(id)
const children =
deletedRecord.pid === 0
? state.files
: filesCached[deletedRecord.pid].children || []
remove(children, (record) => record.id === id)
delete filesCached[id]
fileStore.closeFile(id)
}
const onRename = (id: number) => {
const currentRecord = filesCached[id]
currentRecord.isEditing = true
state.currentKey = id
refreshFiles()
}
const onDoubleClick = (id: number) => {
const currentRecord = filesCached[id]
if (!currentRecord.type) return
if (currentRecord.isEditing) return
fileStore.openFile({
id,
name: getNameByType(currentRecord.type, currentRecord.name),
content: ''
})
}
onMounted(() => {
pullFiles()
})
return {
state,
onCreateFile,
onCreateFolder,
onSelectFile,
onInputBlur,
onDelete,
onRename,
onDoubleClick
}
}