mirror of
https://github.com/docusealco/docuseal
synced 2026-11-04 14:42:32 -05:00
date formulas
This commit is contained in:
1 parent
ca7b9671f2
commit
439f95d87e
10 files changed
+150
-25
No files matched your search
@@ -1799,10 +1799,28 @@ export default {
|
||||
},
|
||||
calculateFormula (field) {
|
||||
const transformedFormula = this.normalizeFormula(field.preferences.formula).replace(/{{(.*?)}}/g, (match, uuid) => {
|
||||
if (this.fieldsUuidIndex[uuid]?.type === 'date') {
|
||||
return this.dateFormulaValue(this.fieldsUuidIndex[uuid].default_value)
|
||||
}
|
||||
|
||||
return this.fieldsUuidIndex[uuid]?.default_value || 0.0
|
||||
})
|
||||
|
||||
return this.math.evaluate(transformedFormula.toLowerCase())
|
||||
const value = this.math.evaluate(transformedFormula.toLowerCase())
|
||||
|
||||
if (field.type === 'date') {
|
||||
return Number.isFinite(value) ? new Date(Math.floor(value) * 86400000).toISOString().slice(0, 10) : ''
|
||||
}
|
||||
|
||||
return value
|
||||
},
|
||||
dateFormulaValue (value) {
|
||||
if (!value) return 'null'
|
||||
if (value === '{{date}}') return 'today()'
|
||||
|
||||
const [year, month, day = 1] = value.slice(0, 10).split('-').map(Number)
|
||||
|
||||
return Date.UTC(year, month - 1, day) / 86400000
|
||||
},
|
||||
evalTextFormula (field, depth = 0) {
|
||||
if (depth > 10) return ''
|
||||
|
||||
@@ -611,7 +611,7 @@ export default {
|
||||
return this.withCondition && (this.withConditions || this.nativePlatform !== 'ios') && !['stamp', 'heading'].includes(this.field.type)
|
||||
},
|
||||
showFormula () {
|
||||
return (this.field.type === 'number' || this.field.type === 'payment' || !!this.field.preferences?.formula) && (this.withFormula || this.nativePlatform !== 'ios')
|
||||
return (this.field.type === 'number' || this.field.type === 'date' || this.field.type === 'payment' || !!this.field.preferences?.formula) && (this.withFormula || this.nativePlatform !== 'ios')
|
||||
},
|
||||
showRequired () {
|
||||
return this.withRequired && !['phone', 'stamp', 'verification', 'strikethrough', 'heading'].includes(this.field.type)
|
||||
|
||||
@@ -500,7 +500,7 @@
|
||||
</label>
|
||||
</li>
|
||||
<li
|
||||
v-if="(field.type == 'number' || field.preferences?.formula) && (withFormula || nativePlatform !== 'ios')"
|
||||
v-if="(field.type == 'number' || field.type == 'date' || field.preferences?.formula) && (withFormula || nativePlatform !== 'ios')"
|
||||
class="field-settings-formula"
|
||||
>
|
||||
<label
|
||||
|
||||
@@ -71,8 +71,22 @@
|
||||
>
|
||||
<div
|
||||
target="blank"
|
||||
class="text-sm mb-2 inline space-x-2 font-mono"
|
||||
class="text-sm mb-2 flex flex-wrap gap-x-2 gap-y-1 font-mono"
|
||||
>
|
||||
<template v-if="withDateFunctions">
|
||||
<button
|
||||
class="bg-base-200 px-2 rounded-xl"
|
||||
@click="insertTextUnderCursor('today()')"
|
||||
>
|
||||
today()
|
||||
</button>
|
||||
<button
|
||||
class="bg-base-200 px-2 rounded-xl"
|
||||
@click="insertTextUnderCursor('datedif(, , "y")', 8)"
|
||||
>
|
||||
datedif(start, end, "y")
|
||||
</button>
|
||||
</template>
|
||||
<button
|
||||
class="bg-base-200 px-2 rounded-xl"
|
||||
@click="insertTextUnderCursor(' + ')"
|
||||
@@ -105,13 +119,13 @@
|
||||
</button>
|
||||
<button
|
||||
class="bg-base-200 px-2 rounded-xl"
|
||||
@click="insertTextUnderCursor('round()')"
|
||||
@click="insertTextUnderCursor('round()', 6)"
|
||||
>
|
||||
round(n, d)
|
||||
</button>
|
||||
<button
|
||||
class="bg-base-200 px-2 rounded-xl"
|
||||
@click="insertTextUnderCursor('abs()')"
|
||||
@click="insertTextUnderCursor('abs()', 4)"
|
||||
>
|
||||
abs(n)
|
||||
</button>
|
||||
@@ -171,6 +185,11 @@ export default {
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
withDateFunctions () {
|
||||
return this.field.type === 'date' || [...this.formula.matchAll(/{{(.*?)}}/g)].some(([, name]) => {
|
||||
return this.template.fields.some((f) => f.type === 'date' && (f.name || this.buildDefaultName(f)).trim() === name.trim())
|
||||
})
|
||||
},
|
||||
fields () {
|
||||
return this.template.fields.reduce((acc, f) => {
|
||||
const isAllowed = this.field.type === 'text' ? this.isTextField(f) : this.isNumberField(f)
|
||||
@@ -191,7 +210,7 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
isNumberField (field) {
|
||||
return field.type === 'number' || (['radio', 'select'].includes(field.type) && field.options?.every((o) => String(o.value).match(/^[\d.-]+$/)))
|
||||
return ['number', 'date'].includes(field.type) || (['radio', 'select'].includes(field.type) && field.options?.every((o) => String(o.value).match(/^[\d.-]+$/)))
|
||||
},
|
||||
isTextField (field) {
|
||||
return ['text', 'number', 'select', 'radio', 'cells', 'phone'].includes(field.type)
|
||||
@@ -244,18 +263,19 @@ export default {
|
||||
this.$emit('close')
|
||||
}
|
||||
},
|
||||
insertTextUnderCursor (textToInsert) {
|
||||
insertTextUnderCursor (textToInsert, cursorOffset = textToInsert.length) {
|
||||
const textarea = this.$refs.textarea
|
||||
|
||||
const selectionEnd = textarea.selectionEnd
|
||||
const cursorPos = selectionEnd
|
||||
const { selectionStart, selectionEnd } = textarea
|
||||
const selectedText = cursorOffset < textToInsert.length ? textarea.value.substring(selectionStart, selectionEnd) : ''
|
||||
const cursorPos = selectedText ? selectionStart : selectionEnd
|
||||
|
||||
const newText = textarea.value.substring(0, cursorPos) + textToInsert + textarea.value.substring(cursorPos)
|
||||
const newText = textarea.value.substring(0, cursorPos) + textToInsert.slice(0, cursorOffset) + selectedText + textToInsert.slice(cursorOffset) + textarea.value.substring(selectionEnd)
|
||||
|
||||
this.formula = newText
|
||||
|
||||
this.$nextTick(() => {
|
||||
textarea.setSelectionRange(cursorPos + textToInsert.length, cursorPos + textToInsert.length)
|
||||
textarea.setSelectionRange(cursorPos + cursorOffset + selectedText.length, cursorPos + cursorOffset + selectedText.length)
|
||||
|
||||
textarea.focus()
|
||||
})
|
||||
|
||||
Reference in new issue
Block a user