Skip to content

Commit 1b20b4d

Browse files
committed
feat: Request: support drag and drop for q-uploader quasarframework#957
1 parent 8734ee0 commit 1b20b4d

File tree

5 files changed

+162
-63
lines changed

5 files changed

+162
-63
lines changed

dev/App.vue

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,11 @@ export default {
1212
}
1313
}
1414
</script>
15+
16+
<style lang="stylus">
17+
p.caption
18+
margin 35px 0
19+
padding 12px 0 12px 12px
20+
border-left 4px solid #027be3
21+
font-weight bold
22+
</style>

dev/components/components/uploader.vue

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,11 @@
88
<p class="caption">No Thumbnails</p>
99
<q-uploader style="max-width: 320px" no-thumbnails color="amber" :url="url" />
1010

11+
<q-toggle v-model="inverted" label="Inverted" />
1112
<p class="caption">Multiple File Upload</p>
1213
<q-uploader
14+
:inverted="inverted"
15+
auto-expand
1316
style="max-width: 320px"
1417
float-label="Upload files"
1518
multiple
@@ -86,7 +89,8 @@ export default {
8689
data () {
8790
return {
8891
url: 'http://1.1.1.195/upload.php',
89-
events: []
92+
events: [],
93+
inverted: false
9094
}
9195
},
9296
methods: {

src/components/uploader/QUploader.vue

Lines changed: 123 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
<template>
2-
<div class="q-uploader">
2+
<div
3+
class="q-uploader relative-position"
4+
@dragover.prevent.stop="__onDragOver"
5+
>
36
<q-input-frame
47
ref="input"
58
class="no-margin"
@@ -10,13 +13,13 @@
1013
:float-label="floatLabel"
1114
:error="error"
1215
:disable="disable"
13-
inverted
1416
:before="before"
1517
:after="after"
1618
:color="color"
1719
:align="align"
20+
:inverted="inverted"
1821

19-
:length="length"
22+
:length="queueLength"
2023
additional-length
2124
>
2225
<div
@@ -62,41 +65,64 @@
6265
slot="after"
6366
name="cloud_upload"
6467
class="q-if-control"
65-
:disabled="length === 0"
68+
:disabled="queueLength === 0"
6669
@click="upload"
6770
></q-icon>
71+
72+
<q-icon
73+
v-if="hasExpandedContent"
74+
slot="after"
75+
name="keyboard_arrow_down"
76+
class="q-if-control generic_transition"
77+
:class="{'rotate-180': expanded}"
78+
@click="expanded = !expanded"
79+
></q-icon>
6880
</q-input-frame>
6981

70-
<div class="q-uploader-files scroll">
71-
<q-item
72-
v-for="file in files"
73-
:key="file.name"
74-
class="q-uploader-file"
75-
>
76-
<q-progress v-if="!hideUploadProgress"
77-
class="q-uploader-progress-bg absolute-full"
78-
:color="file.__failed ? 'negative' : 'grey'"
79-
:percentage="file.__progress"
80-
></q-progress>
81-
<div class="q-uploader-progress-text absolute" v-if="!hideUploadProgress">
82-
{{ file.__progress }}%
82+
<q-slide-transition>
83+
<div v-show="expanded">
84+
<div class="q-uploader-files scroll" :style="filesStyle">
85+
<q-item
86+
v-for="file in files"
87+
:key="file.name"
88+
class="q-uploader-file"
89+
>
90+
<q-progress v-if="!hideUploadProgress"
91+
class="q-uploader-progress-bg absolute-full"
92+
:color="file.__failed ? 'negative' : 'grey'"
93+
:percentage="file.__progress"
94+
></q-progress>
95+
<div class="q-uploader-progress-text absolute" v-if="!hideUploadProgress">
96+
{{ file.__progress }}%
97+
</div>
98+
99+
<q-item-side v-if="file.__img" :image="file.__img.src"></q-item-side>
100+
<q-item-side v-else icon="insert_drive_file" :color="color"></q-item-side>
101+
102+
<q-item-main :label="file.name" :sublabel="file.__size"></q-item-main>
103+
104+
<q-item-side right>
105+
<q-item-tile
106+
:icon="file.__doneUploading ? 'done' : 'clear'"
107+
:color="color"
108+
class="cursor-pointer"
109+
@click="__remove(file)"
110+
></q-item-tile>
111+
</q-item-side>
112+
</q-item>
83113
</div>
84-
85-
<q-item-side v-if="file.__img" :image="file.__img.src"></q-item-side>
86-
<q-item-side v-else icon="insert_drive_file" :color="color"></q-item-side>
87-
88-
<q-item-main :label="file.name" :sublabel="file.__size"></q-item-main>
89-
90-
<q-item-side right>
91-
<q-item-tile
92-
:icon="file.__doneUploading ? 'done' : 'clear'"
93-
:color="color"
94-
class="cursor-pointer"
95-
@click="__remove(file)"
96-
></q-item-tile>
97-
</q-item-side>
98-
</q-item>
99-
</div>
114+
</div>
115+
</q-slide-transition>
116+
117+
<div
118+
v-if="dnd"
119+
class="q-uploader-dnd flex row items-center justify-center absolute-full"
120+
:class="dndClass"
121+
@dragenter.prevent.stop
122+
@dragover.prevent.stop
123+
@dragleave.prevent.stop="__onDragLeave"
124+
@drop.prevent.stop="__onDrop"
125+
></div>
100126
</div>
101127
</template>
102128

@@ -156,6 +182,9 @@ export default {
156182
hideUploadButton: Boolean,
157183
hideUploadProgress: Boolean,
158184
noThumbnails: Boolean,
185+
autoExpand: Boolean,
186+
expandStyle: [Array, String, Object],
187+
expandClass: [Array, String, Object],
159188
160189
color: {
161190
type: String,
@@ -170,33 +199,80 @@ export default {
170199
uploadedSize: 0,
171200
totalSize: 0,
172201
xhrs: [],
173-
focused: false
202+
focused: false,
203+
dnd: false,
204+
expanded: false
174205
}
175206
},
176207
computed: {
177-
length () {
208+
queueLength () {
178209
return this.queue.length
179210
},
211+
hasExpandedContent () {
212+
return this.files.length > 0
213+
},
180214
label () {
181215
const total = humanStorageSize(this.totalSize)
182216
return this.uploading
183217
? `${(this.progress).toFixed(2)}% (${humanStorageSize(this.uploadedSize)} / ${total})`
184-
: `${this.length} (${total})`
218+
: `${this.queueLength} (${total})`
185219
},
186220
progress () {
187221
return this.totalSize ? Math.min(99.99, this.uploadedSize / this.totalSize * 100) : 0
188222
},
189223
addDisabled () {
190-
return !this.multiple && this.length >= 1
224+
return !this.multiple && this.queueLength >= 1
225+
},
226+
filesStyle () {
227+
if (this.maxHeight) {
228+
return { maxHeight: this.maxHeight }
229+
}
230+
},
231+
dndClass () {
232+
const cls = [`text-${this.color}`]
233+
if (this.inverted) {
234+
cls.push('inverted')
235+
}
236+
return cls
237+
}
238+
},
239+
watch: {
240+
hasExpandedContent (v) {
241+
if (v === false) {
242+
this.expanded = false
243+
}
244+
else if (this.autoExpand) {
245+
this.expanded = true
246+
}
191247
}
192248
},
193249
methods: {
194-
__add (e) {
250+
__onDragOver () {
251+
console.log('dragover')
252+
this.dnd = true
253+
},
254+
__onDragLeave () {
255+
this.dnd = false
256+
console.log('leave')
257+
},
258+
__onDrop (e) {
259+
this.dnd = false
260+
console.log('drop')
261+
262+
const
263+
files = e.dataTransfer.files,
264+
count = files.length
265+
266+
if (count > 0) {
267+
this.__add(null, this.multiple ? files : [ files[0] ])
268+
}
269+
},
270+
__add (e, files) {
195271
if (this.addDisabled) {
196272
return
197273
}
198274
199-
let files = Array.prototype.slice.call(e.target.files)
275+
files = Array.prototype.slice.call(files || e.target.files)
200276
this.$refs.file.value = ''
201277
202278
files = files.filter(file => !this.queue.some(f => file.name === f.name))
@@ -222,12 +298,14 @@ export default {
222298
return file
223299
})
224300
225-
this.files = this.files.concat(files)
226-
this.$emit('add', files)
227-
this.__computeTotalSize()
301+
if (files.length > 0) {
302+
this.files = this.files.concat(files)
303+
this.$emit('add', files)
304+
this.__computeTotalSize()
305+
}
228306
},
229307
__computeTotalSize () {
230-
this.totalSize = this.length
308+
this.totalSize = this.queueLength
231309
? this.queue.map(f => f.size).reduce((total, size) => total + size)
232310
: 0
233311
},
@@ -331,7 +409,7 @@ export default {
331409
})
332410
},
333411
upload () {
334-
const length = this.length
412+
const length = this.queueLength
335413
if (length === 0) {
336414
return
337415
}
@@ -365,6 +443,7 @@ export default {
365443
this.abort()
366444
this.files = []
367445
this.queue = []
446+
this.expanded = false
368447
this.__computeTotalSize()
369448
this.$emit('reset')
370449
}
Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
1-
.q-uploader
2-
border-radius 2px
3-
box-shadow $shadow-1
4-
overflow hidden
5-
.q-if
6-
border-bottom-left-radius 0
7-
border-bottom-right-radius 0
1+
.q-uploader-expanded .q-if
2+
border-bottom-left-radius 0
3+
border-bottom-right-radius 0
84

95
.q-uploader-input
106
opacity 0
@@ -16,10 +12,11 @@
1612
display none
1713

1814
.q-uploader-files
15+
border 1px solid $grey-4
16+
border-top 0
1917
font-size 14px
20-
min-height 56px
2118
max-height 500px
22-
.q-uploader-file
19+
.q-uploader-file:not(:last-child)
2320
border-bottom 1px solid $grey-4
2421
.q-uploader-progress-bg, .q-uploader-progress-text
2522
pointer-events none
@@ -31,3 +28,10 @@
3128
opacity .1
3229
right 44px
3330
bottom 0
31+
32+
.q-uploader-dnd
33+
outline 2px dashed currentColor
34+
outline-offset -6px
35+
background rgba(255, 255, 255, .6)
36+
&.inverted
37+
background rgba(0, 0, 0, .3)
Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
1-
.q-uploader
2-
border-radius 2px
3-
box-shadow $shadow-1
4-
overflow hidden
5-
.q-if
6-
border-bottom-left-radius 0
7-
border-bottom-right-radius 0
1+
.q-uploader-expanded .q-if
2+
border-bottom-left-radius 0
3+
border-bottom-right-radius 0
84

95
.q-uploader-input
106
opacity 0
@@ -16,10 +12,11 @@
1612
display none
1713

1814
.q-uploader-files
15+
border 1px solid $grey-4
16+
border-top 0
1917
font-size 14px
20-
min-height 56px
2118
max-height 500px
22-
.q-uploader-file
19+
.q-uploader-file:not(:last-child)
2320
border-bottom 1px solid $grey-4
2421
.q-uploader-progress-bg, .q-uploader-progress-text
2522
pointer-events none
@@ -31,3 +28,10 @@
3128
opacity .1
3229
right 44px
3330
bottom 0
31+
32+
.q-uploader-dnd
33+
outline 2px dashed currentColor
34+
outline-offset -6px
35+
background rgba(255, 255, 255, .6)
36+
&.inverted
37+
background rgba(0, 0, 0, .3)

0 commit comments

Comments
 (0)