Skip to content

Commit 5d76500

Browse files
committed
fix(files): drag and drop events chain and cancel
Signed-off-by: John Molakvoæ <skjnldsv@protonmail.com>
1 parent 33d3370 commit 5d76500

3 files changed

Lines changed: 76 additions & 14 deletions

File tree

apps/files/src/components/DragAndDropNotice.vue

Lines changed: 67 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,23 +25,33 @@
2525
class="files-list__drag-drop-notice"
2626
@drop="onDrop">
2727
<div class="files-list__drag-drop-notice-wrapper">
28-
<TrayArrowDownIcon :size="48" />
29-
<h3 class="files-list-drag-drop-notice__title">
30-
{{ t('files', 'Drag and drop files here to upload') }}
31-
</h3>
28+
<template v-if="canUpload && !isQuotaExceeded">
29+
<TrayArrowDownIcon :size="48" />
30+
<h3 class="files-list-drag-drop-notice__title">
31+
{{ t('files', 'Drag and drop files here to upload') }}
32+
</h3>
33+
</template>
34+
35+
<!-- Not permitted to drop files here -->
36+
<template v-else>
37+
<h3 class="files-list-drag-drop-notice__title">
38+
{{ cantUploadLabel }}
39+
</h3>
40+
</template>
3241
</div>
3342
</div>
3443
</template>
3544

3645
<script lang="ts">
37-
import { translate as t } from '@nextcloud/l10n'
3846
import { defineComponent } from 'vue'
47+
import { Folder, Permission } from '@nextcloud/files'
48+
import { showError, showSuccess } from '@nextcloud/dialogs'
49+
import { translate as t } from '@nextcloud/l10n'
3950
4051
import TrayArrowDownIcon from 'vue-material-design-icons/TrayArrowDown.vue'
4152
4253
import logger from '../logger.js'
4354
import { handleDrop } from '../services/DropService'
44-
import { showSuccess } from '@nextcloud/dialogs'
4555
4656
export default defineComponent({
4757
name: 'DragAndDropNotice',
@@ -52,7 +62,7 @@ export default defineComponent({
5262
5363
props: {
5464
currentFolder: {
55-
type: Object,
65+
type: Folder,
5666
required: true,
5767
},
5868
},
@@ -63,35 +73,83 @@ export default defineComponent({
6373
}
6474
},
6575
76+
computed: {
77+
/**
78+
* Check if the current folder has create permissions
79+
*/
80+
canUpload() {
81+
return this.currentFolder && (this.currentFolder.permissions & Permission.CREATE) !== 0
82+
},
83+
isQuotaExceeded() {
84+
return this.currentFolder?.attributes?.['quota-available-bytes'] === 0
85+
},
86+
87+
cantUploadLabel() {
88+
if (this.isQuotaExceeded) {
89+
return this.t('files', 'Your have used your space quota and cannot upload files anymore')
90+
}
91+
return this.t('files', 'You don’t have permission to upload or create files here')
92+
},
93+
},
94+
6695
mounted() {
6796
// Add events on parent to cover both the table and DragAndDrop notice
6897
const mainContent = window.document.querySelector('main.app-content') as HTMLElement
6998
mainContent.addEventListener('dragover', this.onDragOver)
7099
mainContent.addEventListener('dragleave', this.onDragLeave)
100+
mainContent.addEventListener('drop', this.onContentDrop)
71101
},
72102
73103
beforeDestroy() {
74104
const mainContent = window.document.querySelector('main.app-content') as HTMLElement
75105
mainContent.removeEventListener('dragover', this.onDragOver)
76106
mainContent.removeEventListener('dragleave', this.onDragLeave)
107+
mainContent.removeEventListener('drop', this.onContentDrop)
77108
},
78109
79110
methods: {
80111
onDragOver(event: DragEvent) {
112+
// Needed to keep the drag/drop events chain working
113+
event.preventDefault()
114+
81115
const isForeignFile = event.dataTransfer?.types.includes('Files')
116+
117+
logger.debug('Drag over DragAndDropNotice', { isForeignFile, event })
82118
if (isForeignFile) {
83-
// Only handle uploading
119+
// Only handle uploading of outside files (not Nextcloud files)
84120
this.dragover = true
85121
}
86122
},
87123
88-
onDragLeave(/* event: DragEvent */) {
124+
onDragLeave(event: DragEvent) {
125+
// Counter bubbling, make sure we're ending the drag
126+
// only when we're leaving the current element
127+
// Avoid flickering
128+
const currentTarget = event.currentTarget as HTMLElement
129+
if (currentTarget?.contains(event.relatedTarget as HTMLElement)) {
130+
return
131+
}
132+
133+
if (this.dragover) {
134+
this.dragover = false
135+
}
136+
},
137+
138+
onContentDrop(event: DragEvent) {
139+
logger.debug('Drag and drop cancelled, dropped on empty space', { event })
140+
event.preventDefault()
89141
if (this.dragover) {
90142
this.dragover = false
91143
}
92144
},
93145
94146
onDrop(event: DragEvent) {
147+
if (!this.canUpload || this.isQuotaExceeded) {
148+
showError(this.cantUploadLabel)
149+
return
150+
}
151+
152+
logger.debug('Dropped on DragAndDropNotice', { event })
95153
if (this.$el.querySelector('tbody')?.contains(event.target as Node)) {
96154
return
97155
}

apps/files/src/components/FilesListVirtual.vue

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,6 @@ export default defineComponent({
128128
FileEntryGrid,
129129
headers: getFileListHeaders(),
130130
scrollToIndex: 0,
131-
dndNoticeHeight: 0,
132131
}
133132
},
134133
@@ -259,7 +258,11 @@ export default defineComponent({
259258
onDragOver(event: DragEvent) {
260259
// Detect if we're only dragging existing files or not
261260
const isForeignFile = event.dataTransfer?.types.includes('Files')
261+
262+
console.debug('Drag over FilesListVirtual', { isForeignFile, event })
262263
if (isForeignFile) {
264+
// Only handle uploading of existing Nextcloud files
265+
// See DragAndDropNotice for handling of foreign files
263266
return
264267
}
265268

apps/files/src/services/DropService.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,14 @@
2323
import type { Upload } from '@nextcloud/upload'
2424
import type { FileStat, ResponseDataDetailed } from 'webdav'
2525

26-
import { showError } from '@nextcloud/dialogs'
27-
import { emit } from '@nextcloud/event-bus'
2826
import { davGetClient, davGetDefaultPropfind, davResultToNode, davRootPath } from '@nextcloud/files'
29-
import { translate as t } from '@nextcloud/l10n'
27+
import { emit } from '@nextcloud/event-bus'
3028
import { getUploader } from '@nextcloud/upload'
31-
import logger from '../logger.js'
3229
import { joinPaths } from '@nextcloud/paths'
30+
import { showError } from '@nextcloud/dialogs'
31+
import { translate as t } from '@nextcloud/l10n'
32+
33+
import logger from '../logger.js'
3334

3435
export const handleDrop = async (data: DataTransfer) => {
3536
// TODO: Maybe handle `getAsFileSystemHandle()` in the future

0 commit comments

Comments
 (0)