From f5350eac365879d84e358c6107fa22040504f5ea Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Wed, 4 Feb 2026 16:20:18 +0200 Subject: [PATCH] prefill typed signature and initials from name --- app/javascript/submission_form/form.vue | 1 + .../submission_form/initials_step.vue | 29 ++++++++++++- .../submission_form/signature_step.vue | 43 +++++++++++++++---- 3 files changed, 62 insertions(+), 11 deletions(-) diff --git a/app/javascript/submission_form/form.vue b/app/javascript/submission_form/form.vue index 125ce6c0..92d02f8f 100644 --- a/app/javascript/submission_form/form.vue +++ b/app/javascript/submission_form/form.vue @@ -421,6 +421,7 @@ v-model="values[currentField.uuid]" :field="currentField" :dry-run="dryRun" + :submitter="submitter" :previous-value="previousInitialsValue" :attachments-index="attachmentsIndex" :show-field-names="showFieldNames" diff --git a/app/javascript/submission_form/initials_step.vue b/app/javascript/submission_form/initials_step.vue index 2dede0e4..43a5654b 100644 --- a/app/javascript/submission_form/initials_step.vue +++ b/app/javascript/submission_form/initials_step.vue @@ -175,6 +175,10 @@ export default { type: Object, required: true }, + submitter: { + type: Object, + required: true + }, dryRun: { type: Boolean, required: false, @@ -257,6 +261,14 @@ export default { this.$refs.canvas.getContext('2d').scale(scale, scale) + if (!this.isDrawInitials) { + this.$nextTick(() => { + if (this.$refs.textInput) { + this.initTextInitial() + } + }) + } + this.intersectionObserver?.disconnect() } }) @@ -332,12 +344,25 @@ export default { if (!this.isDrawInitials) { this.$nextTick(() => { - this.$refs.textInput.focus() + if (this.$refs.textInput) { + this.$refs.textInput.focus() + + this.initTextInitial() - this.$emit('start') + this.$emit('start') + } }) } }, + initTextInitial () { + if (this.submitter.name) { + this.$refs.textInput.value = this.submitter.name.trim().split(/\s+/).filter(Boolean).slice(0, 2).map((part) => part[0]?.toUpperCase() || '').join('') + } + + if (this.$refs.textInput.value) { + this.updateWrittenInitials({ target: this.$refs.textInput }) + } + }, async submit () { if (this.modelValue || this.computedPreviousValue) { if (this.computedPreviousValue) { diff --git a/app/javascript/submission_form/signature_step.vue b/app/javascript/submission_form/signature_step.vue index 91937ec9..c6679ac4 100644 --- a/app/javascript/submission_form/signature_step.vue +++ b/app/javascript/submission_form/signature_step.vue @@ -316,7 +316,7 @@ import FileDropzone from './dropzone' import MarkdownContent from './markdown_content' import { v4 } from 'uuid' -let isFontLoaded = false +let fontLoadPromise = null const scale = 3 @@ -482,6 +482,14 @@ export default { if (entry.isIntersecting) { this.setCanvasSize() + if (this.isTextSignature) { + this.$nextTick(() => { + if (this.$refs.textInput) { + this.initTypedSignature() + } + }) + } + this.intersectionObserver?.disconnect() } }) @@ -504,6 +512,10 @@ export default { }) this.resizeObserver.observe(this.$refs.canvas.parentNode) + + if (this.isTextSignature) { + this.loadFont() + } } }, beforeUnmount () { @@ -541,7 +553,7 @@ export default { this.pad.fromData(scaledData) } else if (this.isTextSignature && this.$refs.textInput) { - this.updateWrittenSignature({ target: { value: this.$refs.textInput.value } }) + this.updateWrittenSignature({ target: this.$refs.textInput }) } }, remove () { @@ -551,17 +563,17 @@ export default { this.isSignatureStarted = false }, loadFont () { - if (!isFontLoaded) { + if (!fontLoadPromise) { const font = new FontFace('Dancing Script', `url(${this.baseUrl}/fonts/DancingScript-Regular.otf) format("opentype")`) - font.load().then((loadedFont) => { + fontLoadPromise = font.load().then((loadedFont) => { document.fonts.add(loadedFont) - - isFontLoaded = true }).catch((error) => { console.error('Font loading failed:', error) }) } + + return fontLoadPromise }, showQr () { this.isShowQr = true @@ -661,14 +673,27 @@ export default { if (this.isTextSignature) { this.$nextTick(() => { - this.$refs.textInput.focus() + if (this.$refs.textInput) { + this.$refs.textInput.focus() - this.loadFont() + this.initTypedSignature() - this.$emit('start') + this.$emit('start') + } }) } }, + async initTypedSignature () { + if (this.submitter.name) { + this.$refs.textInput.value = this.submitter.name + } + + await this.loadFont() + + if (this.$refs.textInput.value) { + this.updateWrittenSignature({ target: this.$refs.textInput }) + } + }, drawImage (event) { this.remove() this.clear()