Files
docuseal/app/javascript/submission_form/areas.vue
T

199 lines
5.2 KiB
Vue
Raw Normal View History

2023-05-25 22:47:52 +03:00
<template>
<template
2024-08-07 23:18:03 +03:00
v-for="(step, stepIndex) in steps"
2023-06-16 00:04:05 +03:00
:key="step[0].uuid"
2023-05-25 22:47:52 +03:00
>
<template
2023-06-16 00:04:05 +03:00
v-for="(field, fieldIndex) in step"
:key="field.uuid"
2023-05-25 22:47:52 +03:00
>
2023-06-16 00:04:05 +03:00
<template
v-for="(area, areaIndex) in field.areas"
:key="areaIndex"
>
2025-09-26 20:52:44 +03:00
<template
v-for="(pageElem, index) in [findPageElementForArea(area)]"
:key="index"
2023-07-26 23:17:24 +03:00
>
2025-09-26 20:52:44 +03:00
<Teleport
v-if="pageElem"
:to="pageElem"
>
<FieldArea
:ref="setAreaRef"
v-model="values[field.uuid]"
:values="values"
:field="field"
:area="area"
:submittable="submittable"
:page-width="1400"
:page-height="(1400.0 / pageElem.offsetWidth) * pageElem.offsetHeight"
:field-index="fieldIndex"
:is-inline-size="isInlineSize"
:scroll-padding="scrollPadding"
:submitter="submitter"
:with-field-placeholder="withFieldPlaceholder"
:with-signature-id="withSignatureId"
:is-active="currentStep === step"
:with-label="withLabel && !withFieldPlaceholder && step.length < 2"
:is-value-set="step.some((f) => f.uuid in values)"
:attachments-index="attachmentsIndex"
@click="[$emit('focus-step', stepIndex), maybeScrollOnClick(field, area)]"
/>
</Teleport>
</template>
2023-06-16 00:04:05 +03:00
</template>
2023-05-25 22:47:52 +03:00
</template>
</template>
</template>
<script>
import FieldArea from './area'
export default {
name: 'FieldAreas',
components: {
FieldArea
},
props: {
2023-06-16 00:04:05 +03:00
steps: {
2023-05-25 22:47:52 +03:00
type: Array,
required: false,
default: () => []
},
2024-07-24 20:55:35 +03:00
withSignatureId: {
type: Boolean,
required: false,
default: false
},
2024-09-04 00:29:38 +03:00
submittable: {
type: Boolean,
required: false,
default: true
},
2024-07-24 20:55:35 +03:00
submitter: {
type: Object,
required: true
},
2023-05-25 22:47:52 +03:00
values: {
type: Object,
required: false,
default: () => ({})
},
2024-07-19 09:40:56 +03:00
withFieldPlaceholder: {
type: Boolean,
required: false,
default: false
},
2024-07-02 20:27:25 +03:00
scrollPadding: {
type: String,
required: false,
default: '-80px'
},
2023-05-25 22:47:52 +03:00
attachmentsIndex: {
type: Object,
required: false,
default: () => ({})
2023-06-15 01:05:04 +03:00
},
2023-07-31 00:48:51 +03:00
withLabel: {
type: Boolean,
required: false,
default: true
},
2024-07-22 17:42:29 +03:00
scrollEl: {
type: Object,
required: false,
default: null
},
2023-06-16 00:04:05 +03:00
currentStep: {
type: Array,
2023-06-15 01:05:04 +03:00
required: false,
2023-06-16 00:04:05 +03:00
default: () => []
2023-05-25 22:47:52 +03:00
}
},
2023-06-16 00:04:05 +03:00
emits: ['focus-step'],
2023-05-25 22:47:52 +03:00
data () {
return {
areaRefs: []
}
},
2025-01-29 16:08:09 +02:00
computed: {
2025-07-14 12:53:15 +03:00
isInlineSize () {
return CSS.supports('container-type: size')
},
2025-01-29 16:08:09 +02:00
isMobileContainer () {
const root = this.$root.$el.parentNode.getRootNode()
const container = root.body || root.querySelector('div')
return container.style.overflow === 'hidden'
}
},
2023-05-25 22:47:52 +03:00
beforeUpdate () {
this.areaRefs = []
},
methods: {
2023-08-12 12:34:02 +03:00
findPageElementForArea (area) {
return (this.$root.$el?.parentNode?.getRootNode() || document).getElementById(`page-${area.attachment_uuid}-${area.page}`)
},
2023-05-25 22:47:52 +03:00
scrollIntoField (field) {
2024-01-06 17:21:15 +02:00
if (field?.areas) {
this.scrollIntoArea(field.areas[0])
}
},
2025-01-29 16:08:09 +02:00
maybeScrollOnClick (field, area) {
if (['text', 'number', 'cells'].includes(field.type) && this.isMobileContainer) {
this.scrollIntoArea(area)
}
},
2024-01-06 17:21:15 +02:00
scrollIntoArea (area) {
const areaRef = this.areaRefs.find((a) => a.area === area)
2023-08-12 12:34:02 +03:00
2024-01-06 17:21:15 +02:00
if (areaRef) {
2025-01-29 16:08:09 +02:00
if (this.isMobileContainer) {
2024-01-06 17:21:15 +02:00
this.scrollInContainer(areaRef.$el)
2023-05-25 22:47:52 +03:00
} else {
2024-07-22 17:42:29 +03:00
const targetRect = areaRef.$refs.scrollToElem.getBoundingClientRect()
const scrollEl = this.scrollEl || window
2024-09-20 22:21:09 +03:00
let rootRect = {}
if (this.scrollEl === document.documentElement) {
rootRect = this.scrollEl.getBoundingClientRect()
} else {
const root = this.$root.$el?.parentNode?.classList?.contains('ds') ? this.$root.$el : document.body
rootRect = root.getBoundingClientRect()
}
2024-07-22 17:42:29 +03:00
scrollEl.scrollTo({ top: targetRect.top - rootRect.top, behavior: 'smooth' })
2023-05-25 22:47:52 +03:00
}
2024-01-06 17:21:15 +02:00
return true
}
2023-05-25 22:47:52 +03:00
},
2023-07-03 00:03:29 +03:00
scrollInContainer (target) {
2023-08-12 12:34:02 +03:00
const root = this.$root.$el.parentNode.getRootNode()
const scrollbox = root.getElementById('scrollbox')
const formContainer = root.getElementById('form_container')
const container = root.body || root.querySelector('div')
2025-01-17 01:37:23 +02:00
const isAndroid = /android/i.test(navigator.userAgent)
const padding = isAndroid ? 128 : 64
const scrollboxTop = isAndroid ? scrollbox.getBoundingClientRect().top : 0
2023-08-12 12:34:02 +03:00
const boxRect = scrollbox.children[0].getBoundingClientRect()
2023-07-03 00:03:29 +03:00
const targetRect = target.getBoundingClientRect()
const targetTopRelativeToBox = targetRect.top - boxRect.top
2025-01-17 01:37:23 +02:00
scrollbox.scrollTo({ top: targetTopRelativeToBox + scrollboxTop - container.offsetHeight + formContainer.offsetHeight + target.offsetHeight + padding, behavior: 'smooth' })
2023-07-03 00:03:29 +03:00
},
2023-05-25 22:47:52 +03:00
setAreaRef (el) {
if (el) {
this.areaRefs.push(el)
}
}
}
}
</script>