Compare commits
2 Commits
main
...
fix-descri
| Author | SHA1 | Date |
|---|---|---|
|
|
8d86f09b50 | |
|
|
f86be0adf0 |
|
|
@ -172,8 +172,7 @@
|
|||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import {ref, shallowReactive, computed, watch} from 'vue'
|
||||
import {useDropZone} from '@vueuse/core'
|
||||
import {ref, shallowReactive, computed, watch, onMounted, onUnmounted} from 'vue'
|
||||
|
||||
import User from '@/components/misc/User.vue'
|
||||
import ProgressBar from '@/components/misc/ProgressBar.vue'
|
||||
|
|
@ -227,6 +226,17 @@ function eventTargetsEditor(event: Event | null | undefined): boolean {
|
|||
return false
|
||||
}
|
||||
|
||||
function isFileDrag(event: DragEvent | null | undefined): boolean {
|
||||
if (!event?.dataTransfer) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Check if the drag contains files
|
||||
// dataTransfer.types is a DOMStringList containing the types of data
|
||||
// 'Files' indicates a file drag from the OS or another application
|
||||
return Array.from(event.dataTransfer.types).includes('Files')
|
||||
}
|
||||
|
||||
const taskStore = useTaskStore()
|
||||
const {t} = useI18n({useScope: 'global'})
|
||||
|
||||
|
|
@ -239,67 +249,112 @@ const loading = computed(() => attachmentService.loading || taskStore.isLoading)
|
|||
|
||||
const isDraggingFiles = ref(false)
|
||||
const isDragOverEditor = ref(false)
|
||||
// Track drag depth to handle nested elements properly
|
||||
const dragDepth = ref(0)
|
||||
|
||||
function resetDragState() {
|
||||
isDraggingFiles.value = false
|
||||
isDragOverEditor.value = false
|
||||
dragDepth.value = 0
|
||||
}
|
||||
|
||||
const {isOverDropZone} = useDropZone(document, {
|
||||
onEnter(files, event) {
|
||||
if (!props.editEnabled) {
|
||||
return
|
||||
}
|
||||
|
||||
function handleDragEnter(event: DragEvent) {
|
||||
// Only handle file drags - let text drags work natively
|
||||
if (!isFileDrag(event)) {
|
||||
return
|
||||
}
|
||||
|
||||
dragDepth.value++
|
||||
|
||||
if (dragDepth.value === 1) {
|
||||
isDraggingFiles.value = true
|
||||
isDragOverEditor.value = eventTargetsEditor(event)
|
||||
},
|
||||
onOver(files, event) {
|
||||
if (!props.editEnabled) {
|
||||
return
|
||||
}
|
||||
}
|
||||
isDragOverEditor.value = eventTargetsEditor(event)
|
||||
}
|
||||
|
||||
isDragOverEditor.value = eventTargetsEditor(event)
|
||||
},
|
||||
onLeave(files, event) {
|
||||
if (!props.editEnabled) {
|
||||
return
|
||||
}
|
||||
function handleDragOver(event: DragEvent) {
|
||||
// Only prevent default for file drags - this is the key fix!
|
||||
// Not preventing default allows native text dragging to work
|
||||
if (!isFileDrag(event)) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!isOverDropZone.value) {
|
||||
resetDragState()
|
||||
return
|
||||
}
|
||||
event.preventDefault()
|
||||
isDragOverEditor.value = eventTargetsEditor(event)
|
||||
}
|
||||
|
||||
isDragOverEditor.value = eventTargetsEditor(event)
|
||||
},
|
||||
onDrop(files, event) {
|
||||
if (!props.editEnabled) {
|
||||
return
|
||||
}
|
||||
function handleDragLeave(event: DragEvent) {
|
||||
if (!isFileDrag(event)) {
|
||||
return
|
||||
}
|
||||
|
||||
const dropOverEditor = eventTargetsEditor(event)
|
||||
dragDepth.value--
|
||||
|
||||
if (dragDepth.value === 0) {
|
||||
resetDragState()
|
||||
} else {
|
||||
isDragOverEditor.value = eventTargetsEditor(event)
|
||||
}
|
||||
}
|
||||
|
||||
// Ignore drops over editor - let TipTap handle them
|
||||
if (dropOverEditor || !files || files.length === 0) {
|
||||
return
|
||||
}
|
||||
function handleDrop(event: DragEvent) {
|
||||
// Only handle file drops - let text drops work natively
|
||||
if (!isFileDrag(event)) {
|
||||
return
|
||||
}
|
||||
|
||||
uploadFilesToTask(files)
|
||||
},
|
||||
event.preventDefault()
|
||||
dragDepth.value = 0
|
||||
|
||||
const dropOverEditor = eventTargetsEditor(event)
|
||||
resetDragState()
|
||||
|
||||
// Ignore drops over editor - let TipTap handle them
|
||||
const files = event.dataTransfer?.files
|
||||
if (dropOverEditor || !files || files.length === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
uploadFilesToTask(files)
|
||||
}
|
||||
|
||||
function addDragListeners() {
|
||||
document.addEventListener('dragenter', handleDragEnter)
|
||||
document.addEventListener('dragover', handleDragOver)
|
||||
document.addEventListener('dragleave', handleDragLeave)
|
||||
document.addEventListener('drop', handleDrop)
|
||||
}
|
||||
|
||||
function removeDragListeners() {
|
||||
document.removeEventListener('dragenter', handleDragEnter)
|
||||
document.removeEventListener('dragover', handleDragOver)
|
||||
document.removeEventListener('dragleave', handleDragLeave)
|
||||
document.removeEventListener('drop', handleDrop)
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (props.editEnabled) {
|
||||
addDragListeners()
|
||||
}
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
removeDragListeners()
|
||||
})
|
||||
|
||||
watch(() => props.editEnabled, (enabled) => {
|
||||
if (enabled) {
|
||||
addDragListeners()
|
||||
} else {
|
||||
removeDragListeners()
|
||||
resetDragState()
|
||||
}
|
||||
})
|
||||
|
||||
const showDropzone = computed(() =>
|
||||
props.editEnabled && isDraggingFiles.value && !isDragOverEditor.value,
|
||||
)
|
||||
|
||||
watch(() => props.editEnabled, enabled => {
|
||||
if (!enabled) {
|
||||
resetDragState()
|
||||
}
|
||||
})
|
||||
|
||||
function downloadAttachment(attachment: IAttachment) {
|
||||
attachmentService.download(attachment)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue