Skip to content

Commit a5306aa

Browse files
pdanpdanrstoenescu
andcommitted
docs(QFile): Add upload progress example quasarframework#6193 (quasarframework#6199)
* docs(QFile): Add upload progress example quasarframework#6193 * feat(QFile): Try to update the input real model if browser allows * Use local test server for upload * Update QFile.js Co-authored-by: Razvan Stoenescu <razvan.stoenescu@gmail.com>
1 parent 1a27dfe commit a5306aa

File tree

5 files changed

+181
-9
lines changed

5 files changed

+181
-9
lines changed
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
<template>
2+
<div class="q-pa-md column items-start q-gutter-y-md">
3+
<q-file
4+
:value="files"
5+
@input="updateFiles"
6+
label="Pick files"
7+
outlined
8+
multiple
9+
:clearable="uploading === null"
10+
style="max-width: 400px"
11+
>
12+
<template v-slot:file="{ index, file }">
13+
<q-chip
14+
class="full-width q-my-xs"
15+
:removable="uploading !== null && uploadProgress[index].percent < 1"
16+
square
17+
@remove="cancelFile(index)"
18+
>
19+
<q-linear-progress
20+
class="absolute-full full-height"
21+
:value="uploadProgress[index].percent"
22+
:color="uploadProgress[index].color"
23+
track-color="grey-2"
24+
stripped
25+
/>
26+
27+
<q-avatar>
28+
<q-icon :name="uploadProgress[index].icon" />
29+
</q-avatar>
30+
31+
<div class="ellipsis relative-position">
32+
{{ file.name }}
33+
</div>
34+
35+
<q-tooltip>
36+
{{ file.name }}
37+
</q-tooltip>
38+
</q-chip>
39+
</template>
40+
</q-file>
41+
42+
<q-btn class="q-mt-sm" color="primary" label="Upload" @click="upload" />
43+
</div>
44+
</template>
45+
46+
<script>
47+
export default {
48+
data () {
49+
return {
50+
files: null,
51+
uploadProgress: [],
52+
uploading: null
53+
}
54+
},
55+
56+
methods: {
57+
cancelFile (index) {
58+
this.uploadProgress[index] = {
59+
...this.uploadProgress[index],
60+
error: true,
61+
color: 'orange-2'
62+
}
63+
},
64+
65+
updateFiles (files) {
66+
this.files = files
67+
this.uploadProgress = (files || []).map(file => ({
68+
error: false,
69+
color: 'green-2',
70+
percent: 0,
71+
icon: file.type.indexOf('video/') === 0
72+
? 'movie'
73+
: (file.type.indexOf('image/') === 0
74+
? 'photo'
75+
: (file.type.indexOf('audio/') === 0
76+
? 'audiotrack'
77+
: 'insert_drive_file'
78+
)
79+
)
80+
}))
81+
},
82+
83+
upload () {
84+
clearTimeout(this.uploading)
85+
86+
const allDone = this.uploadProgress.every(progress => progress.percent === 1)
87+
88+
this.uploadProgress = this.uploadProgress.map(progress => ({
89+
...progress,
90+
error: false,
91+
color: 'green-2',
92+
percent: allDone === true ? 0 : progress.percent
93+
}))
94+
95+
this.__updateUploadProgress()
96+
},
97+
98+
__updateUploadProgress () {
99+
let done = true
100+
101+
this.uploadProgress = this.uploadProgress.map(progress => {
102+
if (progress.percent === 1 || progress.error === true) {
103+
return progress
104+
}
105+
106+
const percent = Math.min(1, progress.percent + Math.random() / 10)
107+
const error = percent < 1 && Math.random() > 0.95
108+
109+
if (error === false && percent < 1 && done === true) {
110+
done = false
111+
}
112+
113+
return {
114+
...progress,
115+
error,
116+
color: error === true ? 'red-2' : 'green-2',
117+
percent
118+
}
119+
})
120+
121+
this.uploading = done !== true
122+
? setTimeout(this.__updateUploadProgress, 300)
123+
: null
124+
}
125+
},
126+
127+
beforeDestroy () {
128+
clearTimeout(this.uploading)
129+
}
130+
}
131+
</script>

docs/src/pages/vue-components/file-picker.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,10 @@ Under the covers, QFile uses a native input. Due to browser security policy, it
6363

6464
<doc-example title="With chips" file="QFile/WithChips" />
6565

66+
### Using progress indicator
67+
68+
<doc-example title="With progress indicator" file="QFile/WithProgress" />
69+
6670
### Restricting files
6771

6872
<doc-example title="Basic restrictions" file="QFile/RestrictionBasic" />
Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
<template>
22
<div class="q-layout-padding">
3-
<div style="max-width: 600px;" class="q-gutter-y-md">
4-
<q-file filled v-model="fileS" label="Single" clearable />
5-
<q-file color="yellow" filled v-model="fileM" multiple label="Multiple" clearable />
3+
<form action="http://localhost:4444/upload" method="post" enctype="multipart/form-data" target="wind1" style="max-width: 600px;" class="q-gutter-y-md">
4+
<q-file name="file1" filled v-model="fileS" label="Single" clearable />
5+
<q-file name="file2" color="yellow" filled v-model="fileM" multiple label="Multiple" clearable />
66

7-
<q-file color="accent" filled v-model="fileS" use-chips label="Single chips" clearable />
8-
<q-file color="accent" filled v-model="fileM" multiple use-chips label="Multiple chips" clearable counter max-files="3" />
9-
</div>
7+
<q-file name="file3" color="accent" filled v-model="fileS" use-chips label="Single chips" clearable />
8+
<q-file name="file4" color="accent" filled v-model="fileM" multiple use-chips label="Multiple chips" clearable counter max-files="3" />
9+
10+
<q-btn label="Move first file to single" @click="testMove" />
11+
12+
<q-btn type="submit" label="Submit" />
13+
</form>
1014
</div>
1115
</template>
1216

@@ -17,6 +21,16 @@ export default {
1721
fileS: null,
1822
fileM: null
1923
}
24+
},
25+
26+
methods: {
27+
testMove () {
28+
if (Array.isArray(this.fileM) === false || this.fileM.length === 0) {
29+
return
30+
}
31+
32+
this.fileS = this.fileM.splice(0, 1)[0]
33+
}
2034
}
2135
}
2236
</script>

ui/dev/upload-server/server.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,6 @@ app.post('/upload', (req, res) => {
4646
})
4747

4848
app.listen(port, () => {
49-
console.log('\nUpload server running on http://localhost:' + port)
49+
console.log('\nUpload server running on http://localhost:' + port + '/upload')
5050
console.log('You can now upload from main dev server using QUploader')
5151
})

ui/src/components/file/QFile.js

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,32 @@ export default Vue.extend({
4343

4444
watch: {
4545
value (val) {
46-
if (val === void 0 || val === null) {
47-
this.$refs.input.value = null
46+
if (this.$refs.input === void 0) {
47+
return
4848
}
49+
50+
try {
51+
if (val === void 0 || val === null) {
52+
this.$refs.input.value = ''
53+
return
54+
}
55+
56+
const dt = 'DataTransfer' in window
57+
? new DataTransfer()
58+
: ('ClipboardEvent' in window
59+
? new ClipboardEvent('').clipboardData
60+
: void 0
61+
)
62+
63+
if (dt !== void 0) {
64+
(Array.isArray(val) === true ? val : [val]).forEach(file => {
65+
dt.items.add(file)
66+
})
67+
68+
this.$refs.input.files = dt.files
69+
}
70+
}
71+
catch (e) { }
4972
}
5073
},
5174

0 commit comments

Comments
 (0)