1
0
mirror of https://gitlab.com/bramw/baserow.git synced 2024-11-21 23:37:55 +00:00
bramw_baserow/web-frontend/modules/core/directives/userFileUpload.js

148 lines
4.3 KiB
JavaScript

import UserFileService from '@baserow/modules/core/services/userFile'
/**
* This directive can be used to enable drag and drop (or click) user file upload.
* The selected files will be uploaded as a user file and the response, containing
* the file name, url, thumbnails etc will be communicated via the `done` function.
* The dragging and uploading state is communicated by calling the provided functions.
* It is possible for users to drag and drop a file inside the element. Clicking on the
* element opens a file picker.
*
* Example:
* <div
* v-user-file-upload="{
* check: (file) => {
* // Check if the file is accepted.
* return true
* },
* enter: () => {
* // Entered dragging state.
* },
* leave: () => {
* // Leaving dragging state.
* },
* progress: (event) => {
* // Upload progress changes.
* const percentage = Math.round((event.loaded * 100) / event.total)
* console.log(percentage)
* },
* done: (file) => {
* // The file has been uploaded.
* console.log(file)
* },
* }"
* >
* Drop here
* </div>
*/
export default {
/**
* Registers all the needed drop, drag and click events needed.
*/
bind(el, binding, vnode) {
binding.def.update(el, binding)
// The input that is needed to open the file chooser.
el.userFileUploadElement = document.createElement('input')
el.userFileUploadElement.accept = el.userFileUploadValue.accept()
el.userFileUploadElement.type = 'file'
el.userFileUploadElement.style.display = 'none'
el.userFileUploadElement.addEventListener('change', (event) => {
binding.def.upload(el, event, vnode.context.$client)
})
// The counter that is used to calculate if the user is dragging a file over the
// drop zone. It could be that enter and leave event are going are called
// multiple times without reentering the drop zone.
el.userFileUploadDragCounter = 0
el.userFileUploadDrop = (event) => {
event.preventDefault()
binding.def.upload(el, event, vnode.context.$client)
}
el.addEventListener('drop', el.userFileUploadDrop)
el.userFileUploadDragOver = (event) => {
event.preventDefault()
}
el.addEventListener('dragover', el.userFileUploadDragOver)
el.userFileUploadDragEnter = (event) => {
event.preventDefault()
if (el.userFileUploadDragCounter === 0) {
el.userFileUploadValue.enter()
}
el.userFileUploadDragCounter++
}
el.addEventListener('dragenter', el.userFileUploadDragEnter)
el.userFileUploadDragLeave = () => {
el.userFileUploadDragCounter--
if (el.userFileUploadDragCounter === 0) {
el.userFileUploadValue.leave()
}
}
el.addEventListener('dragleave', el.userFileUploadDragLeave)
el.userFileUploadClick = (event) => {
event.preventDefault()
el.userFileUploadElement.click(event)
}
el.addEventListener('click', el.userFileUploadClick)
},
/**
* Removes all the events registered in the bind function.
*/
unbind(el) {
el.removeEventListener('drop', el.userFileUploadDrop)
el.removeEventListener('dragover', el.userFileUploadDragOver)
el.removeEventListener('dragenter', el.userFileUploadDragEnter)
el.removeEventListener('dragleave', el.userFileUploadDragLeave)
el.removeEventListener('click', el.userFileUploadClick)
},
update(el, binding) {
const defaults = {
accept() {
return '*'
},
check() {
return true
},
enter() {},
leave() {},
progress() {},
done() {},
error() {},
}
el.userFileUploadValue = Object.assign(defaults, binding.value)
},
/**
* Called when a file must be uploaded. The progress will be shared by calling the
* provided functions.
*/
async upload(el, event, client) {
const files = event.target.files
? event.target.files
: event.dataTransfer.files
if (
files === null ||
files.length === 0 ||
!el.userFileUploadValue.check(files[0])
) {
return
}
try {
const { data } = await UserFileService(client).uploadFile(
files[0],
el.userFileUploadValue.progress
)
el.userFileUploadValue.done(data)
} catch (e) {
el.userFileUploadValue.error(e)
}
},
}