Files
docuseal/app/javascript/elements/dashboard_dropzone.js
T

249 lines
7.3 KiB
JavaScript
Raw Normal View History

2025-04-25 21:19:28 +03:00
import { target, targets, targetable } from '@github/catalyst/lib/targetable'
2025-05-10 12:11:35 +03:00
const loadingIconHtml = `<svg xmlns="http://www.w3.org/2000/svg" class="animate-spin" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M12 3a9 9 0 1 0 9 9" />
</svg>`
2025-05-09 00:01:50 +03:00
export default targetable(class extends HTMLElement {
static [targets.static] = [
'hiddenOnDrag',
'folderCards',
'templateCards'
]
2025-04-25 21:19:28 +03:00
static [target.static] = [
2025-05-09 00:01:50 +03:00
'form',
'fileDropzone',
2025-07-20 08:28:19 +03:00
'folderDropzone',
2025-05-09 00:01:50 +03:00
'fileDropzoneLoading'
2025-04-25 21:19:28 +03:00
]
connectedCallback () {
document.addEventListener('drop', this.onWindowDragdrop)
document.addEventListener('dragover', this.onWindowDropover)
2025-05-09 00:01:50 +03:00
2025-04-25 21:19:28 +03:00
window.addEventListener('dragleave', this.onWindowDragleave)
2025-05-09 00:01:50 +03:00
this.fileDropzone?.addEventListener('drop', this.onDropFile)
2025-07-20 08:28:19 +03:00
this.folderDropzone?.addEventListener('drop', this.onDropNewFolder)
2025-05-09 00:01:50 +03:00
2025-05-10 12:11:35 +03:00
this.folderCards.forEach((el) => el.addEventListener('drop', (e) => this.onDropFolder(e, el)))
2025-05-09 00:01:50 +03:00
this.templateCards.forEach((el) => el.addEventListener('drop', this.onDropTemplate))
2025-05-10 12:11:35 +03:00
this.templateCards.forEach((el) => el.addEventListener('dragstart', this.onTemplateDragStart))
2025-04-25 21:19:28 +03:00
2025-07-20 08:28:19 +03:00
return [this.fileDropzone, this.folderDropzone, ...this.folderCards, ...this.templateCards].forEach((el) => {
2025-05-09 00:01:50 +03:00
el?.addEventListener('dragover', this.onDragover)
el?.addEventListener('dragleave', this.onDragleave)
})
2025-04-25 21:19:28 +03:00
}
disconnectedCallback () {
document.removeEventListener('drop', this.onWindowDragdrop)
document.removeEventListener('dragover', this.onWindowDropover)
2025-05-09 00:01:50 +03:00
2025-04-25 21:19:28 +03:00
window.removeEventListener('dragleave', this.onWindowDragleave)
2025-05-10 12:11:35 +03:00
}
2025-04-25 21:19:28 +03:00
2025-05-10 12:11:35 +03:00
onTemplateDragStart = (e) => {
const id = e.target.href.split('/').pop()
2025-04-25 21:19:28 +03:00
2025-07-20 08:28:19 +03:00
this.folderCards.forEach((el) => el.classList.remove('bg-base-200', 'before:hidden'))
this.folderDropzone?.classList?.remove('hidden')
window.flash?.remove()
2025-05-10 12:11:35 +03:00
e.dataTransfer.effectAllowed = 'move'
2025-05-09 00:01:50 +03:00
2025-05-10 12:11:35 +03:00
if (id) {
e.dataTransfer.setData('template_id', id)
const dragPreview = e.target.cloneNode(true)
const rect = e.target.getBoundingClientRect()
2025-05-10 19:55:37 +03:00
const height = e.target.children[0].getBoundingClientRect().height + 50
2025-05-10 12:11:35 +03:00
dragPreview.children[1].remove()
dragPreview.style.width = `${rect.width}px`
2025-05-10 19:55:37 +03:00
dragPreview.style.height = `${height}px`
2025-05-10 12:11:35 +03:00
dragPreview.style.position = 'absolute'
2025-05-11 16:11:02 +03:00
dragPreview.style.top = '-1000px'
2025-05-10 12:11:35 +03:00
dragPreview.style.pointerEvents = 'none'
dragPreview.style.opacity = '0.9'
document.body.appendChild(dragPreview)
2025-05-10 19:55:37 +03:00
e.dataTransfer.setDragImage(dragPreview, rect.width / 2, height / 2)
2025-05-10 12:11:35 +03:00
setTimeout(() => document.body.removeChild(dragPreview), 0)
}
2025-04-25 21:19:28 +03:00
}
2025-05-09 00:01:50 +03:00
onDropFile = (e) => {
2025-04-25 21:19:28 +03:00
e.preventDefault()
2025-05-09 00:01:50 +03:00
this.fileDropzoneLoading.classList.remove('hidden')
this.fileDropzoneLoading.previousElementSibling.classList.add('hidden')
this.fileDropzoneLoading.classList.add('opacity-50')
2025-04-25 21:19:28 +03:00
2025-05-09 00:01:50 +03:00
this.uploadFiles(e.dataTransfer.files, '/templates_upload')
2025-04-25 21:19:28 +03:00
}
2025-05-10 12:11:35 +03:00
onDropFolder = (e, el) => {
2025-05-09 00:01:50 +03:00
e.preventDefault()
2025-05-10 12:11:35 +03:00
const templateId = e.dataTransfer.getData('template_id')
2025-05-09 00:01:50 +03:00
2025-05-10 12:11:35 +03:00
if (e.dataTransfer.files.length || templateId) {
const loading = document.createElement('div')
const svg = el.querySelector('svg')
2025-05-09 00:01:50 +03:00
2025-05-10 12:11:35 +03:00
loading.innerHTML = loadingIconHtml
loading.children[0].classList.add(...svg.classList)
2025-05-09 00:01:50 +03:00
2025-05-10 12:11:35 +03:00
el.replaceChild(loading.children[0], svg)
el.classList.add('opacity-50')
2025-05-09 00:01:50 +03:00
2025-05-10 12:11:35 +03:00
if (e.dataTransfer.files.length) {
2025-07-12 12:35:19 +03:00
const params = new URLSearchParams({ folder_name: el.innerText.trim() }).toString()
2025-05-10 12:11:35 +03:00
this.uploadFiles(e.dataTransfer.files, `/templates_upload?${params}`)
} else {
const formData = new FormData()
2025-07-20 08:28:19 +03:00
formData.append('name', el.dataset.fullName)
2025-05-10 12:11:35 +03:00
fetch(`/templates/${templateId}/folder`, {
method: 'PUT',
redirect: 'manual',
body: formData,
headers: {
'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').content
}
}).finally(() => {
2025-05-10 19:55:37 +03:00
window.Turbo.cache.clear()
2025-05-10 12:11:35 +03:00
window.Turbo.visit(location.href)
})
}
}
2025-04-25 21:19:28 +03:00
}
2025-05-09 00:01:50 +03:00
onDropTemplate = (e) => {
2025-04-25 21:19:28 +03:00
e.preventDefault()
2025-05-10 12:11:35 +03:00
if (e.dataTransfer.files.length) {
const loading = document.createElement('div')
loading.classList.add('bottom-5', 'left-0', 'flex', 'justify-center', 'w-full', 'absolute')
loading.innerHTML = loadingIconHtml
2025-04-25 21:19:28 +03:00
2025-05-10 12:11:35 +03:00
e.target.appendChild(loading)
e.target.classList.add('opacity-50')
2025-05-09 00:01:50 +03:00
2025-05-10 12:11:35 +03:00
const id = e.target.href.split('/').pop()
2025-04-25 21:19:28 +03:00
2025-05-10 12:11:35 +03:00
this.uploadFiles(e.dataTransfer.files, `/templates/${id}/clone_and_replace`)
}
2025-04-25 21:19:28 +03:00
}
2025-05-10 12:11:35 +03:00
onWindowDragdrop = (e) => {
e.preventDefault()
2025-05-09 00:01:50 +03:00
if (!this.isLoading) this.hideDraghover()
}
uploadFiles (files, url) {
this.isLoading = true
this.form.action = url
this.form.querySelector('[type="file"]').files = files
2025-04-25 21:19:28 +03:00
2025-05-09 00:01:50 +03:00
this.form.querySelector('[type="submit"]').click()
2025-04-25 21:19:28 +03:00
}
onWindowDropover = (e) => {
e.preventDefault()
if (e.dataTransfer?.types?.includes('Files')) {
this.showDraghover()
}
}
2025-05-10 12:11:35 +03:00
onDragover (e) {
if (e.dataTransfer?.types?.includes('Files') || this.dataset.targets !== 'dashboard-dropzone.templateCards') {
this.style.backgroundColor = '#F7F3F0'
2025-05-14 00:54:48 +03:00
if (this.classList.contains('before:border-base-300')) {
this.classList.remove('before:border-base-300')
2025-05-15 13:59:06 +03:00
this.classList.add('before:border-base-content/30')
2025-05-14 00:54:48 +03:00
} else if (this.classList.contains('border-base-300')) {
this.classList.remove('border-base-300')
2025-05-15 13:59:06 +03:00
this.classList.add('border-base-content/30')
2025-05-14 00:54:48 +03:00
}
2025-05-10 12:11:35 +03:00
}
2025-05-09 00:01:50 +03:00
}
2025-07-20 08:28:19 +03:00
onDropNewFolder (e) {
e.preventDefault()
const templateId = e.dataTransfer.getData('template_id')
const a = document.createElement('a')
a.href = `/templates/${templateId}/folder/edit?autocomplete=false`
a.dataset.turboFrame = 'modal'
a.classList.add('hidden')
document.body.append(a)
a.click()
a.remove()
}
2025-05-09 00:01:50 +03:00
onDragleave () {
this.style.backgroundColor = null
2025-05-14 00:54:48 +03:00
2025-05-15 13:59:06 +03:00
if (this.classList.contains('before:border-base-content/30')) {
this.classList.remove('before:border-base-content/30')
2025-05-14 00:54:48 +03:00
this.classList.add('before:border-base-300')
2025-05-15 13:59:06 +03:00
} else if (this.classList.contains('border-base-content/30')) {
this.classList.remove('border-base-content/30')
2025-05-14 00:54:48 +03:00
this.classList.add('border-base-300')
}
2025-05-09 00:01:50 +03:00
}
2025-04-25 21:19:28 +03:00
onWindowDragleave = (e) => {
if (e.clientX <= 0 || e.clientY <= 0 || e.clientX >= window.innerWidth || e.clientY >= window.innerHeight) {
this.hideDraghover()
}
}
2025-05-09 00:01:50 +03:00
showDraghover = () => {
if (this.isDrag) return
2025-04-25 21:19:28 +03:00
2025-05-09 00:01:50 +03:00
this.isDrag = true
2025-04-25 21:19:28 +03:00
2025-07-20 08:28:19 +03:00
window.flash?.remove()
2025-05-09 00:01:50 +03:00
this.fileDropzone?.classList?.remove('hidden')
2025-04-25 21:19:28 +03:00
2025-05-09 00:01:50 +03:00
this.hiddenOnDrag.forEach((el) => { el.style.display = 'none' })
2025-04-25 21:19:28 +03:00
2025-05-09 00:01:50 +03:00
return [...this.folderCards, ...this.templateCards].forEach((el) => {
el.classList.remove('bg-base-200', 'before:hidden')
})
2025-04-25 21:19:28 +03:00
}
hideDraghover = () => {
2025-05-09 00:01:50 +03:00
this.isDrag = false
this.fileDropzone?.classList?.add('hidden')
2025-07-20 08:28:19 +03:00
this.folderDropzone?.classList?.add('hidden')
2025-05-09 00:01:50 +03:00
this.hiddenOnDrag.forEach((el) => { el.style.display = null })
return [...this.folderCards, ...this.templateCards].forEach((el) => {
el.classList.add('bg-base-200', 'before:hidden')
})
}
})