diff --git a/src/components/Questions/QuestionDate.vue b/src/components/Questions/QuestionDate.vue
index 6c318657d..d45c4555c 100644
--- a/src/components/Questions/QuestionDate.vue
+++ b/src/components/Questions/QuestionDate.vue
@@ -28,7 +28,7 @@
v-on="commonListeners">
this.options.find((option) => option.id === id),
)
- this.selectedOption = this.isMultiple ? selected : selected[0]
- }
+
+ return this.isMultiple ? selected : selected[0]
+ },
},
methods: {
diff --git a/src/components/Questions/QuestionLong.vue b/src/components/Questions/QuestionLong.vue
index 2e5e13384..fbbf6728d 100644
--- a/src/components/Questions/QuestionLong.vue
+++ b/src/components/Questions/QuestionLong.vue
@@ -71,18 +71,27 @@ export default {
},
},
- mounted() {
- this.autoSizeText()
+ watch: {
+ values: {
+ handler() {
+ this.$nextTick(() => {
+ this.autoSizeText()
+ })
+ },
+ immediate: true,
+ },
},
methods: {
onInput() {
const textarea = this.$refs.textarea
this.$emit('update:values', [textarea.value])
- this.autoSizeText()
},
autoSizeText() {
const textarea = this.$refs.textarea
+ if (!textarea) {
+ return
+ }
textarea.style.cssText = 'height:auto; padding:0'
textarea.style.cssText = `height: ${textarea.scrollHeight + 28}px`
},
diff --git a/src/views/Submit.vue b/src/views/Submit.vue
index d399bbc2b..384ba1ece 100644
--- a/src/views/Submit.vue
+++ b/src/views/Submit.vue
@@ -145,17 +145,31 @@
@keydown.ctrl.enter="onKeydownCtrlEnter"
@update:values="(values) => onUpdate(question, values)" />
-
-
-
-
- {{ t('forms', 'Submit') }}
-
+
+
+
+
+
+ {{ t('forms', 'Clear form') }}
+
+
+
+
+
+ {{ t('forms', 'Submit') }}
+
+
@@ -179,6 +193,27 @@
:buttons="confirmLeaveFormButtons"
:can-close="false"
:close-on-click-outside="false" />
+
+
+
+
@@ -201,6 +236,7 @@ import NcNoteCard from '@nextcloud/vue/dist/Components/NcNoteCard.js'
import IconCancelSvg from '@mdi/svg/svg/cancel.svg?raw'
import IconCheckSvg from '@mdi/svg/svg/check.svg?raw'
+import IconRefreshSvg from '@mdi/svg/svg/refresh.svg?raw'
import IconSendSvg from '@mdi/svg/svg/send.svg?raw'
import { FormState } from '../models/FormStates.ts'
@@ -277,6 +313,7 @@ export default {
// Non reactive properties
return {
IconCheckSvg,
+ IconRefreshSvg,
IconSendSvg,
maxStringLengths: loadState('forms', 'maxStringLengths'),
@@ -297,6 +334,8 @@ export default {
submitForm: false,
showConfirmEmptyModal: false,
showConfirmLeaveDialog: false,
+ showClearFormDialog: false,
+ showClearFormDueToChangeDialog: false,
}
},
@@ -316,6 +355,10 @@ export default {
})
},
+ validQuestionsIds() {
+ return new Set(this.validQuestions.map((question) => question.id))
+ },
+
isRequiredUsed() {
return this.form.questions.reduce(
(isUsed, question) => isUsed || question.isRequired,
@@ -413,6 +456,29 @@ export default {
},
]
},
+
+ /**
+ * Buttons for the "confirm clear form" dialog
+ */
+ confirmClearFormButtons() {
+ return [
+ {
+ label: t('forms', 'Abort'),
+ icon: IconCancelSvg,
+ callback: () => {},
+ },
+ {
+ label: t('forms', 'Clear'),
+ icon: IconCheckSvg,
+ type: 'primary',
+ callback: () => this.onResetSubmission(),
+ },
+ ]
+ },
+
+ hasAnswers() {
+ return Object.keys(this.answers).length > 0
+ },
},
watch: {
@@ -437,17 +503,19 @@ export default {
window.addEventListener('beforeunload', this.beforeWindowUnload)
},
- beforeMount() {
+ async beforeMount() {
// Public Views get their form by initial-state from parent. No fetch necessary.
if (this.publicView) {
this.isLoadingForm = false
} else {
- this.fetchFullForm(this.form.id)
+ await this.fetchFullForm(this.form.id)
}
- SetWindowTitle(this.formTitle)
+
if (this.isLoggedIn) {
this.initFromLocalStorage()
}
+
+ SetWindowTitle(this.formTitle)
},
methods: {
@@ -473,8 +541,16 @@ export default {
if (!savedState) {
return
}
+
const answers = {}
for (const [questionId, answer] of Object.entries(savedState)) {
+ // Clean up answers for questions that do not exist anymore
+ if (!this.validQuestionsIds.has(parseInt(questionId))) {
+ this.showClearFormDueToChangeDialog = true
+ logger.debug('Question does not exist anymore', { questionId })
+ continue
+ }
+
answers[questionId] =
answer.type === 'QuestionMultiple'
? answer.value.map(String)
@@ -585,17 +661,6 @@ export default {
async (question) => await question.validate(),
)
- // Clean up answers for questions that do not exist anymore
- const questionIds = new Map(
- this.validQuestions.map((question) => [question.id, true]),
- )
- for (const questionId of Object.keys(this.answers)) {
- if (!questionIds.has(parseInt(questionId))) {
- logger.debug('Question does not exist anymore', { questionId })
- delete this.answers[questionId]
- }
- }
-
try {
// wait for all to be validated
const result = await Promise.all(validation)
@@ -654,6 +719,11 @@ export default {
}
},
+ onResetSubmission() {
+ this.deleteFormFieldFromLocalStorage()
+ this.resetData()
+ },
+
/**
* Reset View-Data
*/
@@ -661,6 +731,8 @@ export default {
this.answers = {}
this.loading = false
this.showConfirmLeaveDialog = false
+ this.showClearFormDialog = false
+ this.showClearFormDueToChangeDialog = false
this.success = false
this.submitForm = false
},
@@ -749,8 +821,12 @@ export default {
padding-inline-start: var(--default-clickable-area);
}
+ .form-buttons {
+ display: flex;
+ justify-content: flex-end;
+ }
+
.submit-button {
- align-self: flex-end;
margin: 5px;
margin-block-end: 160px;
padding-inline-start: 20px;