2020-02-28 19:19:44 +03:00
|
|
|
|
import nanoid from 'nanoid/non-secure'
|
2019-11-15 22:44:01 +03:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* The file upload class holds and represents a file’s upload state durring
|
|
|
|
|
* the upload flow.
|
|
|
|
|
*/
|
|
|
|
|
class FileUpload {
|
|
|
|
|
/**
|
|
|
|
|
* Create a file upload object.
|
|
|
|
|
* @param {FileList} fileList
|
|
|
|
|
* @param {object} context
|
|
|
|
|
*/
|
2019-11-19 15:15:13 +03:00
|
|
|
|
constructor (input, context, options) {
|
|
|
|
|
this.input = input
|
|
|
|
|
this.fileList = input.files
|
2019-11-15 22:44:01 +03:00
|
|
|
|
this.files = []
|
|
|
|
|
this.options = options
|
2019-11-19 15:15:13 +03:00
|
|
|
|
this.addFileList(this.fileList)
|
2019-11-15 22:44:01 +03:00
|
|
|
|
this.context = context
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Produce an array of files and alert the callback.
|
|
|
|
|
* @param {FileList}
|
|
|
|
|
*/
|
2019-11-19 15:15:13 +03:00
|
|
|
|
addFileList (fileList) {
|
2019-11-15 22:44:01 +03:00
|
|
|
|
for (let i = 0; i < fileList.length; i++) {
|
2019-11-19 15:15:13 +03:00
|
|
|
|
const file = fileList[i]
|
|
|
|
|
const uuid = nanoid()
|
|
|
|
|
const removeFile = function () {
|
|
|
|
|
this.removeFile(uuid)
|
|
|
|
|
}
|
2019-11-15 22:44:01 +03:00
|
|
|
|
this.files.push({
|
2019-11-19 15:15:13 +03:00
|
|
|
|
progress: false,
|
|
|
|
|
error: false,
|
|
|
|
|
complete: false,
|
|
|
|
|
justFinished: false,
|
2019-11-15 22:44:01 +03:00
|
|
|
|
name: file.name || 'file-upload',
|
2019-11-19 15:15:13 +03:00
|
|
|
|
file,
|
|
|
|
|
uuid,
|
2019-11-21 08:29:28 +03:00
|
|
|
|
path: false,
|
|
|
|
|
removeFile: removeFile.bind(this),
|
|
|
|
|
previewData: false
|
2019-11-15 22:44:01 +03:00
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Check if the file has an.
|
|
|
|
|
*/
|
|
|
|
|
hasUploader () {
|
|
|
|
|
return !!this.context.uploader
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-21 07:16:31 +03:00
|
|
|
|
/**
|
|
|
|
|
* Check if the given uploader is axios instance.
|
|
|
|
|
*/
|
2019-11-15 22:44:01 +03:00
|
|
|
|
uploaderIsAxios () {
|
|
|
|
|
if (
|
|
|
|
|
this.hasUploader &&
|
|
|
|
|
typeof this.hasUploader.request === 'function' &&
|
|
|
|
|
typeof this.hasUploader.get === 'function' &&
|
|
|
|
|
typeof this.hasUploader.delete === 'function' &&
|
|
|
|
|
typeof this.hasUploader.post === 'function'
|
|
|
|
|
) {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get a new uploader function.
|
|
|
|
|
*/
|
|
|
|
|
getUploader (...args) {
|
|
|
|
|
if (this.uploaderIsAxios()) {
|
|
|
|
|
const formData = new FormData()
|
|
|
|
|
formData.append(this.context.name || 'file', args[0])
|
|
|
|
|
return this.uploader.post(this.context.uploadUrl, formData, {
|
|
|
|
|
headers: {
|
|
|
|
|
'Content-Type': 'multipart/form-data'
|
|
|
|
|
},
|
|
|
|
|
onUploadProgress: progressEvent => {
|
|
|
|
|
args[1](Math.round((progressEvent.loaded * 100) / progressEvent.total))
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
.catch(err => args[2](err))
|
|
|
|
|
}
|
|
|
|
|
return this.context.uploader(...args)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Perform the file upload.
|
|
|
|
|
*/
|
|
|
|
|
upload () {
|
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
|
if (!this.hasUploader) {
|
|
|
|
|
return reject(new Error('No uploader has been defined'))
|
|
|
|
|
}
|
|
|
|
|
Promise.all(this.files.map(file => {
|
2019-11-21 07:16:31 +03:00
|
|
|
|
return file.path ? Promise.resolve(file.path) : this.getUploader(
|
2019-11-15 22:44:01 +03:00
|
|
|
|
file.file,
|
2019-11-19 15:15:13 +03:00
|
|
|
|
(progress) => {
|
|
|
|
|
file.progress = progress
|
|
|
|
|
if (progress >= 100) {
|
|
|
|
|
if (!file.complete) {
|
|
|
|
|
file.justFinished = true
|
|
|
|
|
setTimeout(() => { file.justFinished = false }, this.options.uploadJustCompleteDuration)
|
|
|
|
|
}
|
|
|
|
|
file.complete = true
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
(error) => {
|
|
|
|
|
file.progress = 0
|
|
|
|
|
file.error = error
|
|
|
|
|
file.complete = true
|
|
|
|
|
},
|
2019-11-15 22:44:01 +03:00
|
|
|
|
this.options
|
|
|
|
|
)
|
|
|
|
|
}))
|
|
|
|
|
.then(results => resolve(results))
|
|
|
|
|
.catch(err => { throw new Error(err) })
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-19 15:15:13 +03:00
|
|
|
|
/**
|
|
|
|
|
* Remove a file from the uploader (and the file list)
|
|
|
|
|
* @param {string} uuid
|
|
|
|
|
*/
|
|
|
|
|
removeFile (uuid) {
|
|
|
|
|
this.files = this.files.filter(file => file.uuid !== uuid)
|
|
|
|
|
if (window) {
|
|
|
|
|
const transfer = new DataTransfer()
|
|
|
|
|
this.files.map(file => transfer.items.add(file.file))
|
|
|
|
|
this.fileList = transfer.files
|
|
|
|
|
this.input.files = this.fileList
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-21 08:29:28 +03:00
|
|
|
|
/**
|
|
|
|
|
* load image previews for all uploads.
|
|
|
|
|
*/
|
|
|
|
|
loadPreviews () {
|
|
|
|
|
this.files.map(file => {
|
|
|
|
|
if (!file.previewData && window && window.FileReader && /^image\//.test(file.file.type)) {
|
|
|
|
|
const reader = new FileReader()
|
|
|
|
|
reader.onload = e => Object.assign(file, { previewData: e.target.result })
|
|
|
|
|
reader.readAsDataURL(file.file)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-15 22:44:01 +03:00
|
|
|
|
/**
|
|
|
|
|
* Get the files.
|
|
|
|
|
*/
|
|
|
|
|
getFileList () {
|
|
|
|
|
return this.fileList
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get the files.
|
|
|
|
|
*/
|
|
|
|
|
getFiles () {
|
|
|
|
|
return this.files
|
|
|
|
|
}
|
2020-02-26 01:32:40 +03:00
|
|
|
|
|
|
|
|
|
toString () {
|
|
|
|
|
const descriptor = this.files.length ? this.files.length + ' files' : 'empty'
|
|
|
|
|
return `FileUpload(${descriptor})`
|
|
|
|
|
}
|
2019-11-15 22:44:01 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default FileUpload
|