fix refactor dropzone
This commit is contained in:
@@ -127,7 +127,7 @@ safeRegisterElement('template-builder', class extends HTMLElement {
|
||||
withSendButton: this.dataset.withSendButton !== 'false',
|
||||
withSignYourselfButton: this.dataset.withSignYourselfButton !== 'false',
|
||||
withConditions: this.dataset.withConditions === 'true',
|
||||
withReplaceAndCloneUpload: this.dataset.withReplaceAndCloneUpload !== 'false',
|
||||
withReplaceAndCloneUpload: true,
|
||||
currencies: (this.dataset.currencies || '').split(',').filter(Boolean),
|
||||
acceptFileTypes: this.dataset.acceptFileTypes,
|
||||
showTourStartForm: this.dataset.showTourStartForm === 'true'
|
||||
|
||||
@@ -1,74 +1,106 @@
|
||||
import { actionable } from '@github/catalyst/lib/actionable'
|
||||
import { target, targets, targetable } from '@github/catalyst/lib/targetable'
|
||||
|
||||
export default actionable(targetable(class extends HTMLElement {
|
||||
static [targets.static] = ['hiddenOnHover']
|
||||
export default targetable(class extends HTMLElement {
|
||||
static [targets.static] = [
|
||||
'hiddenOnDrag',
|
||||
'folderCards',
|
||||
'templateCards'
|
||||
]
|
||||
|
||||
static [target.static] = [
|
||||
'loading',
|
||||
'icon',
|
||||
'input',
|
||||
'fileDropzone'
|
||||
'form',
|
||||
'fileDropzone',
|
||||
'fileDropzoneLoading'
|
||||
]
|
||||
|
||||
connectedCallback () {
|
||||
this.showOnlyOnWindowHover = this.dataset.showOnlyOnWindowHover === 'true'
|
||||
|
||||
document.addEventListener('drop', this.onWindowDragdrop)
|
||||
document.addEventListener('dragover', this.onWindowDropover)
|
||||
|
||||
window.addEventListener('dragleave', this.onWindowDragleave)
|
||||
|
||||
this.addEventListener('dragover', this.onDragover)
|
||||
this.addEventListener('dragleave', this.onDragleave)
|
||||
this.fileDropzone?.addEventListener('drop', this.onDropFile)
|
||||
|
||||
this.fileDropzone.addEventListener('drop', this.onDrop)
|
||||
this.fileDropzone.addEventListener('turbo:submit-start', this.showDraghover)
|
||||
this.fileDropzone.addEventListener('turbo:submit-end', this.hideDraghover)
|
||||
this.folderCards.forEach((el) => el.addEventListener('drop', this.onDropFolder))
|
||||
this.templateCards.forEach((el) => el.addEventListener('drop', this.onDropTemplate))
|
||||
|
||||
return [this.fileDropzone, ...this.folderCards, ...this.templateCards].forEach((el) => {
|
||||
el?.addEventListener('dragover', this.onDragover)
|
||||
el?.addEventListener('dragleave', this.onDragleave)
|
||||
})
|
||||
}
|
||||
|
||||
disconnectedCallback () {
|
||||
document.removeEventListener('drop', this.onWindowDragdrop)
|
||||
document.removeEventListener('dragover', this.onWindowDropover)
|
||||
|
||||
window.removeEventListener('dragleave', this.onWindowDragleave)
|
||||
|
||||
this.removeEventListener('dragover', this.onDragover)
|
||||
this.removeEventListener('dragleave', this.onDragleave)
|
||||
this.fileDropzone?.removeEventListener('drop', this.onDropFile)
|
||||
|
||||
this.fileDropzone.removeEventListener('drop', this.onDrop)
|
||||
this.fileDropzone.removeEventListener('turbo:submit-start', this.showDraghover)
|
||||
this.fileDropzone.removeEventListener('turbo:submit-end', this.hideDraghover)
|
||||
this.folderCards.forEach((el) => el.removeEventListener('drop', this.onDropFolder))
|
||||
this.templateCards.forEach((el) => el.removeEventListener('drop', this.onDropTemplate))
|
||||
|
||||
return [this.fileDropzone, ...this.folderCards, ...this.templateCards].forEach((el) => {
|
||||
el?.removeEventListener('dragover', this.onDragover)
|
||||
el?.removeEventListener('dragleave', this.onDragleave)
|
||||
})
|
||||
}
|
||||
|
||||
onDrop = (e) => {
|
||||
onDropFile = (e) => {
|
||||
e.preventDefault()
|
||||
|
||||
this.input.files = e.dataTransfer.files
|
||||
this.fileDropzoneLoading.classList.remove('hidden')
|
||||
this.fileDropzoneLoading.previousElementSibling.classList.add('hidden')
|
||||
this.fileDropzoneLoading.classList.add('opacity-50')
|
||||
|
||||
this.uploadFiles(e.dataTransfer.files)
|
||||
this.uploadFiles(e.dataTransfer.files, '/templates_upload')
|
||||
}
|
||||
|
||||
onDropFolder = (e) => {
|
||||
e.preventDefault()
|
||||
|
||||
const loading = document.createElement('div')
|
||||
const svg = e.target.querySelector('svg')
|
||||
|
||||
loading.innerHTML = this.loadingIconHtml
|
||||
loading.children[0].classList.add(...svg.classList)
|
||||
|
||||
e.target.replaceChild(loading.children[0], svg)
|
||||
e.target.classList.add('opacity-50')
|
||||
|
||||
const params = new URLSearchParams({ folder_name: e.target.innerText }).toString()
|
||||
|
||||
this.uploadFiles(e.dataTransfer.files, `/templates_upload?${params}`)
|
||||
}
|
||||
|
||||
onDropTemplate = (e) => {
|
||||
e.preventDefault()
|
||||
|
||||
const loading = document.createElement('div')
|
||||
loading.classList.add('bottom-5', 'left-0', 'flex', 'justify-center', 'w-full', 'absolute')
|
||||
loading.innerHTML = this.loadingIconHtml
|
||||
|
||||
e.target.appendChild(loading)
|
||||
e.target.classList.add('opacity-50')
|
||||
|
||||
const id = e.target.href.split('/').pop()
|
||||
|
||||
this.uploadFiles(e.dataTransfer.files, `/templates/${id}/clone_and_replace`)
|
||||
}
|
||||
|
||||
onWindowDragdrop = () => {
|
||||
if (!this.hovered) this.hideDraghover()
|
||||
if (!this.isLoading) this.hideDraghover()
|
||||
}
|
||||
|
||||
onSelectFiles (e) {
|
||||
e.preventDefault()
|
||||
uploadFiles (files, url) {
|
||||
this.isLoading = true
|
||||
|
||||
this.uploadFiles(this.input.files)
|
||||
}
|
||||
this.form.action = url
|
||||
|
||||
toggleLoading = (e) => {
|
||||
if (e && e.target && (!e.target.contains(this) || !e.detail?.formSubmission?.formElement?.contains(this))) {
|
||||
return
|
||||
}
|
||||
this.form.querySelector('[type="file"]').files = files
|
||||
|
||||
this.loading?.classList?.toggle('hidden')
|
||||
this.icon?.classList?.toggle('hidden')
|
||||
}
|
||||
|
||||
uploadFiles () {
|
||||
this.toggleLoading()
|
||||
|
||||
this.fileDropzone.querySelector('button[type="submit"]').click()
|
||||
this.form.querySelector('[type="submit"]').click()
|
||||
}
|
||||
|
||||
onWindowDropover = (e) => {
|
||||
@@ -79,45 +111,50 @@ export default actionable(targetable(class extends HTMLElement {
|
||||
}
|
||||
}
|
||||
|
||||
onDragover () {
|
||||
this.style.backgroundColor = '#F7F3F0'
|
||||
}
|
||||
|
||||
onDragleave () {
|
||||
this.style.backgroundColor = null
|
||||
}
|
||||
|
||||
onWindowDragleave = (e) => {
|
||||
if (e.clientX <= 0 || e.clientY <= 0 || e.clientX >= window.innerWidth || e.clientY >= window.innerHeight) {
|
||||
this.hideDraghover()
|
||||
}
|
||||
}
|
||||
|
||||
onDragover (e) {
|
||||
e.preventDefault()
|
||||
|
||||
this.hovered = true
|
||||
this.style.backgroundColor = '#F7F3F0'
|
||||
}
|
||||
|
||||
onDragleave (e) {
|
||||
e.preventDefault()
|
||||
|
||||
this.hovered = false
|
||||
this.style.backgroundColor = null
|
||||
}
|
||||
|
||||
showDraghover = () => {
|
||||
if (this.showOnlyOnWindowHover) {
|
||||
this.classList.remove('hidden')
|
||||
}
|
||||
if (this.isDrag) return
|
||||
|
||||
this.classList.remove('bg-base-200', 'border-transparent')
|
||||
this.classList.add('bg-base-100', 'border-base-300', 'border-dashed')
|
||||
this.fileDropzone.classList.remove('hidden')
|
||||
this.hiddenOnHover.forEach((el) => { el.style.display = 'none' })
|
||||
this.isDrag = true
|
||||
|
||||
this.fileDropzone?.classList?.remove('hidden')
|
||||
|
||||
this.hiddenOnDrag.forEach((el) => { el.style.display = 'none' })
|
||||
|
||||
return [...this.folderCards, ...this.templateCards].forEach((el) => {
|
||||
el.classList.remove('bg-base-200', 'before:hidden')
|
||||
})
|
||||
}
|
||||
|
||||
hideDraghover = () => {
|
||||
if (this.showOnlyOnWindowHover) {
|
||||
this.classList.add('hidden')
|
||||
}
|
||||
this.isDrag = false
|
||||
|
||||
this.classList.add('bg-base-200', 'border-transparent')
|
||||
this.classList.remove('bg-base-100', 'border-base-300', 'border-dashed')
|
||||
this.fileDropzone.classList.add('hidden')
|
||||
this.hiddenOnHover.forEach((el) => { el.style.display = null })
|
||||
this.fileDropzone?.classList?.add('hidden')
|
||||
|
||||
this.hiddenOnDrag.forEach((el) => { el.style.display = null })
|
||||
|
||||
return [...this.folderCards, ...this.templateCards].forEach((el) => {
|
||||
el.classList.add('bg-base-200', 'before:hidden')
|
||||
})
|
||||
}
|
||||
}))
|
||||
|
||||
get loadingIconHtml () {
|
||||
return `<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>`
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
<template>
|
||||
<HoverDropzone
|
||||
v-if="sortedDocuments.length && (withUploadButton || withAddPageButton)"
|
||||
:is-dragging="isDragging"
|
||||
:template-id="template.id"
|
||||
:accept-file-types="acceptFileTypes"
|
||||
:with-replace-and-clone="withReplaceAndCloneUpload"
|
||||
hover-class="bg-base-200/50"
|
||||
@add="[updateFromUpload($event), isDragging = false]"
|
||||
@replace="[onDocumentsReplace($event), isDragging = false]"
|
||||
@replace-and-clone="[onDocumentsReplaceAndTemplateClone($event), isDragging = false]"
|
||||
@error="onUploadFailed"
|
||||
/>
|
||||
<div
|
||||
ref="dragContainer"
|
||||
style="max-width: 1600px"
|
||||
class="mx-auto pl-3 h-full"
|
||||
:class="isMobile ? 'pl-4' : 'md:pl-4'"
|
||||
@dragover="onDragover"
|
||||
@drop="isDragging = false"
|
||||
@drop="isDragFile = false"
|
||||
>
|
||||
<HoverDropzone
|
||||
v-if="sortedDocuments.length && withUploadButton && editable"
|
||||
:is-dragging="isDragFile"
|
||||
:template-id="template.id"
|
||||
:accept-file-types="acceptFileTypes"
|
||||
:with-replace-and-clone="withReplaceAndCloneUpload"
|
||||
hover-class="bg-base-200/50"
|
||||
@add="[updateFromUpload($event), isDragFile = false]"
|
||||
@replace="[onDocumentsReplace($event), isDragFile = false]"
|
||||
@replace-and-clone="onDocumentsReplaceAndTemplateClone($event)"
|
||||
@error="[onUploadFailed($event), isDragFile = false]"
|
||||
/>
|
||||
<DragPlaceholder
|
||||
ref="dragPlaceholder"
|
||||
:field="fieldsDragFieldRef.value || toRaw(dragField)"
|
||||
@@ -683,7 +683,7 @@ export default {
|
||||
withReplaceAndCloneUpload: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: true
|
||||
default: false
|
||||
},
|
||||
withPhone: {
|
||||
type: Boolean,
|
||||
@@ -745,7 +745,7 @@ export default {
|
||||
drawFieldType: null,
|
||||
drawOption: null,
|
||||
dragField: null,
|
||||
isDragging: false
|
||||
isDragFile: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -892,12 +892,12 @@ export default {
|
||||
ref.x = e.clientX - ref.offsetX
|
||||
ref.y = e.clientY - ref.offsetY
|
||||
} else if (e.dataTransfer?.types?.includes('Files')) {
|
||||
this.isDragging = true
|
||||
this.isDragFile = true
|
||||
}
|
||||
},
|
||||
onWindowDragLeave (event) {
|
||||
if (event.clientX <= 0 || event.clientY <= 0 || event.clientX >= window.innerWidth || event.clientY >= window.innerHeight) {
|
||||
this.isDragging = false
|
||||
this.isDragFile = false
|
||||
}
|
||||
},
|
||||
reorderFields (item) {
|
||||
@@ -1560,8 +1560,6 @@ export default {
|
||||
}, 'image/png')
|
||||
},
|
||||
onUploadFailed (error) {
|
||||
this.isDragging = false
|
||||
|
||||
if (error) alert(error)
|
||||
},
|
||||
updateFromUpload (data) {
|
||||
@@ -1685,7 +1683,7 @@ export default {
|
||||
this.save()
|
||||
},
|
||||
onDocumentsReplace (data) {
|
||||
data.schema.forEach((schemaItem , index) => {
|
||||
data.schema.forEach((schemaItem, index) => {
|
||||
const existingSchemaItem = this.template.schema[index]
|
||||
|
||||
if (this.template.schema[index]) {
|
||||
|
||||
@@ -10,12 +10,12 @@
|
||||
id="document_dropzone"
|
||||
class="w-full relative rounded-md border-2 border-base-content/10 border-dashed"
|
||||
:for="inputId"
|
||||
:class="[{ 'opacity-50': isLoading || isProcessing, 'hover:bg-base-200': !hoverClass }, isDragEntering && hoverClass ? hoverClass : '']"
|
||||
:class="[{ 'opacity-50': isLoading, 'hover:bg-base-200/30': !hoverClass }, isDragEntering && hoverClass ? hoverClass : '']"
|
||||
>
|
||||
<div class="absolute top-0 right-0 left-0 bottom-0 flex items-center justify-center pointer-events-none">
|
||||
<div class="flex flex-col items-center">
|
||||
<IconInnerShadowTop
|
||||
v-if="isLoading || isProcessing"
|
||||
v-if="isLoading"
|
||||
class="animate-spin"
|
||||
:width="40"
|
||||
:height="40"
|
||||
@@ -29,6 +29,7 @@
|
||||
<div
|
||||
v-if="message"
|
||||
class="font-medium text-lg mb-1"
|
||||
:class="{ 'mt-1': !withDescription }"
|
||||
>
|
||||
{{ message }}
|
||||
</div>
|
||||
@@ -97,10 +98,10 @@ export default {
|
||||
required: false,
|
||||
default: true
|
||||
},
|
||||
header: {
|
||||
type: Object,
|
||||
title: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: () => ({})
|
||||
default: ''
|
||||
},
|
||||
acceptFileTypes: {
|
||||
type: String,
|
||||
@@ -108,11 +109,10 @@ export default {
|
||||
default: 'image/*, application/pdf'
|
||||
}
|
||||
},
|
||||
emits: ['success', 'error', 'loading', 'processing'],
|
||||
emits: ['success', 'error', 'loading'],
|
||||
data () {
|
||||
return {
|
||||
isLoading: false,
|
||||
isProcessing: false,
|
||||
isDragEntering: false
|
||||
}
|
||||
},
|
||||
@@ -122,7 +122,7 @@ export default {
|
||||
},
|
||||
uploadUrl () {
|
||||
if (this.cloneTemplateOnUpload) {
|
||||
return `/templates/${this.templateId}/replace_documents`
|
||||
return `/templates/${this.templateId}/clone_and_replace`
|
||||
} else {
|
||||
return `/templates/${this.templateId}/documents`
|
||||
}
|
||||
@@ -130,21 +130,16 @@ export default {
|
||||
message () {
|
||||
if (this.isLoading) {
|
||||
return this.t('uploading')
|
||||
} else if (this.isProcessing) {
|
||||
return this.t('processing_')
|
||||
} else if (this.acceptFileTypes === 'image/*, application/pdf') {
|
||||
return this.header.pdf_documents_or_images || this.header.documents_or_images || this.t('add_pdf_documents_or_images')
|
||||
return this.title || this.t('add_pdf_documents_or_images')
|
||||
} else {
|
||||
return this.header.documents_or_images || this.t('add_documents_or_images')
|
||||
return this.title || this.t('add_documents_or_images')
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
isLoading (value) {
|
||||
this.$emit('loading', value)
|
||||
},
|
||||
isProcessing (value) {
|
||||
this.$emit('processing', value)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div
|
||||
v-if="isDragging || isLoading || isProcessing"
|
||||
v-if="isDragging || isLoading"
|
||||
class="modal modal-open"
|
||||
>
|
||||
<div class="flex flex-col gap-2 p-4 items-center bg-base-100 h-full max-h-[85vh] max-w-6xl rounded-2xl w-full">
|
||||
@@ -11,10 +11,9 @@
|
||||
:template-id="templateId"
|
||||
:accept-file-types="acceptFileTypes"
|
||||
:with-description="false"
|
||||
:header="{ documents_or_images: t('upload_new_document') }"
|
||||
:title="t('upload_a_new_document')"
|
||||
type="add_files"
|
||||
@loading="isLoading = $event"
|
||||
@processing="isProcessing = $event"
|
||||
@success="$emit('add', $event)"
|
||||
@error="$emit('error', $event)"
|
||||
/>
|
||||
@@ -26,9 +25,8 @@
|
||||
:template-id="templateId"
|
||||
:accept-file-types="acceptFileTypes"
|
||||
:with-description="false"
|
||||
:header="{ documents_or_images: t('replace_existing_document') }"
|
||||
:title="t('replace_existing_document')"
|
||||
@loading="isLoading = $event"
|
||||
@processing="isProcessing = $event"
|
||||
@success="$emit('replace', $event)"
|
||||
@error="$emit('error', $event)"
|
||||
/>
|
||||
@@ -41,9 +39,8 @@
|
||||
:accept-file-types="acceptFileTypes"
|
||||
:with-description="false"
|
||||
:clone-template-on-upload="true"
|
||||
:header="{ documents_or_images: t('clone_template_and_replace_documents') }"
|
||||
:title="t('clone_and_replace_documents')"
|
||||
@loading="isLoading = $event"
|
||||
@processing="isProcessing = $event"
|
||||
@success="$emit('replace-and-clone', $event)"
|
||||
@error="$emit('error', $event)"
|
||||
/>
|
||||
@@ -85,8 +82,7 @@ export default {
|
||||
emits: ['add', 'replace', 'replace-and-clone', 'error'],
|
||||
data () {
|
||||
return {
|
||||
isLoading: false,
|
||||
isProcessing: false
|
||||
isLoading: false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,9 +63,9 @@ const en = {
|
||||
processing_: 'Processing...',
|
||||
add_pdf_documents_or_images: 'Add PDF documents or images',
|
||||
add_documents_or_images: 'Add documents or images',
|
||||
upload_new_document: 'Upload new document',
|
||||
upload_a_new_document: 'Upload a new document',
|
||||
replace_existing_document: 'Replace existing document',
|
||||
clone_template_and_replace_documents: 'Clone template and replace documents',
|
||||
clone_and_replace_documents: 'Clone and replace documents',
|
||||
required: 'Required',
|
||||
default_value: 'Default value',
|
||||
format: 'Format',
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<label
|
||||
:for="inputId"
|
||||
class="btn btn-neutral btn-xs text-white transition-none replace-document-button"
|
||||
:class="{ 'opacity-100': isLoading || isProcessing }"
|
||||
:class="{ 'opacity-100': isLoading }"
|
||||
>
|
||||
{{ message }}
|
||||
<form
|
||||
@@ -41,8 +41,7 @@ export default {
|
||||
emits: ['success'],
|
||||
data () {
|
||||
return {
|
||||
isLoading: false,
|
||||
isProcessing: false
|
||||
isLoading: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -52,8 +51,6 @@ export default {
|
||||
message () {
|
||||
if (this.isLoading) {
|
||||
return this.t('uploading_')
|
||||
} else if (this.isProcessing) {
|
||||
return this.t('processing_')
|
||||
} else {
|
||||
return this.t('replace')
|
||||
}
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
id="add_document_button"
|
||||
:for="inputId"
|
||||
class="btn btn-outline w-full add-document-button"
|
||||
:class="{ 'btn-disabled': isLoading || isProcessing }"
|
||||
:class="{ 'btn-disabled': isLoading }"
|
||||
>
|
||||
<IconInnerShadowTop
|
||||
v-if="isLoading || isProcessing"
|
||||
v-if="isLoading"
|
||||
width="20"
|
||||
class="animate-spin"
|
||||
/>
|
||||
@@ -18,9 +18,6 @@
|
||||
<span v-if="isLoading">
|
||||
{{ t('uploading_') }}
|
||||
</span>
|
||||
<span v-else-if="isProcessing">
|
||||
{{ t('processing_') }}
|
||||
</span>
|
||||
<span v-else>
|
||||
{{ t('add_document') }}
|
||||
</span>
|
||||
@@ -66,8 +63,7 @@ export default {
|
||||
emits: ['success', 'error'],
|
||||
data () {
|
||||
return {
|
||||
isLoading: false,
|
||||
isProcessing: false
|
||||
isLoading: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -91,6 +87,7 @@ export default {
|
||||
resp.json().then((data) => {
|
||||
this.$emit('success', data)
|
||||
this.$refs.input.value = ''
|
||||
this.isLoading = false
|
||||
})
|
||||
} else if (resp.status === 422) {
|
||||
resp.json().then((data) => {
|
||||
@@ -106,22 +103,26 @@ export default {
|
||||
if (resp.ok) {
|
||||
this.$emit('success', await resp.json())
|
||||
this.$refs.input.value = ''
|
||||
this.isLoading = false
|
||||
} else {
|
||||
alert(this.t('wrong_password'))
|
||||
|
||||
this.$emit('error', await resp.json().error)
|
||||
this.isLoading = false
|
||||
}
|
||||
})
|
||||
} else {
|
||||
this.$emit('error', data.error)
|
||||
this.isLoading = false
|
||||
}
|
||||
})
|
||||
} else {
|
||||
resp.json().then((data) => {
|
||||
this.$emit('error', data.error)
|
||||
this.isLoading = false
|
||||
})
|
||||
}
|
||||
}).finally(() => {
|
||||
}).catch(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user