Merge pull request #347 from nextcloud/enh/mandatory
Mandatory option on questions
This commit is contained in:
commit
0904899811
7 changed files with 150 additions and 61 deletions
|
|
@ -43,10 +43,13 @@
|
|||
minlength="1"
|
||||
:maxlength="maxQuestionLength"
|
||||
required
|
||||
@input="onInput"
|
||||
@keyup="onTitleChange">
|
||||
<h3 v-else class="question__header-title" v-text="text" />
|
||||
@input="onTitleChange">
|
||||
<h3 v-else class="question__header-title" v-text="computedText" />
|
||||
<Actions v-if="!readOnly" class="question__header-menu" :force-menu="true">
|
||||
<ActionCheckbox :checked="mandatory"
|
||||
@update:checked="onMandatoryChange">
|
||||
{{ t('forms', 'Mandatory') }}
|
||||
</ActionCheckbox>
|
||||
<ActionButton icon="icon-delete" @click="onDelete">
|
||||
{{ t('forms', 'Delete question') }}
|
||||
</ActionButton>
|
||||
|
|
@ -59,14 +62,10 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import axios from '@nextcloud/axios'
|
||||
import debounce from 'debounce'
|
||||
import { generateUrl } from '@nextcloud/router'
|
||||
import { showError } from '@nextcloud/dialogs'
|
||||
import { directive as ClickOutside } from 'v-click-outside'
|
||||
|
||||
import Actions from '@nextcloud/vue/dist/Components/Actions'
|
||||
import ActionButton from '@nextcloud/vue/dist/Components/ActionButton'
|
||||
import ActionCheckbox from '@nextcloud/vue/dist/Components/ActionCheckbox'
|
||||
|
||||
export default {
|
||||
name: 'Question',
|
||||
|
|
@ -78,13 +77,10 @@ export default {
|
|||
components: {
|
||||
Actions,
|
||||
ActionButton,
|
||||
ActionCheckbox,
|
||||
},
|
||||
|
||||
props: {
|
||||
id: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
index: {
|
||||
type: Number,
|
||||
required: true,
|
||||
|
|
@ -93,6 +89,10 @@ export default {
|
|||
type: String,
|
||||
required: true,
|
||||
},
|
||||
mandatory: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
edit: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
|
|
@ -107,11 +107,28 @@ export default {
|
|||
},
|
||||
},
|
||||
|
||||
computed: {
|
||||
/**
|
||||
* Extend text with asterisk if question is mandatory
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
computedText() {
|
||||
if (this.mandatory) {
|
||||
return this.text + ' *'
|
||||
}
|
||||
return this.text
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
onInput({ target }) {
|
||||
onTitleChange({ target }) {
|
||||
this.$emit('update:text', target.value)
|
||||
},
|
||||
|
||||
onMandatoryChange(mandatory) {
|
||||
this.$emit('update:mandatory', mandatory)
|
||||
},
|
||||
|
||||
/**
|
||||
* Enable the edit mode
|
||||
*/
|
||||
|
|
@ -136,25 +153,6 @@ export default {
|
|||
onDelete() {
|
||||
this.$emit('delete')
|
||||
},
|
||||
|
||||
onTitleChange: debounce(function() {
|
||||
this.saveQuestionProperty('text')
|
||||
}, 200),
|
||||
|
||||
async saveQuestionProperty(key) {
|
||||
try {
|
||||
// TODO: add loading status feedback ?
|
||||
await axios.post(generateUrl('/apps/forms/api/v1/question/update'), {
|
||||
id: this.id,
|
||||
keyValuePairs: {
|
||||
[key]: this[key],
|
||||
},
|
||||
})
|
||||
} catch (error) {
|
||||
showError(t('forms', 'Error while saving question'))
|
||||
console.error(error)
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -24,16 +24,18 @@
|
|||
<Question
|
||||
v-bind.sync="$attrs"
|
||||
:text="text"
|
||||
:mandatory="mandatory"
|
||||
:edit.sync="edit"
|
||||
:max-question-length="maxStringLengths.questionText"
|
||||
@delete="onDelete"
|
||||
@update:text="onTitleChange">
|
||||
@update:text="onTitleChange"
|
||||
@update:mandatory="onMandatoryChange"
|
||||
@delete="onDelete">
|
||||
<div class="question__content">
|
||||
<!-- TODO: properly choose max length -->
|
||||
<textarea ref="textarea"
|
||||
:aria-label="t('forms', 'A long answer for the question “{text}”', { text })"
|
||||
:placeholder="t('forms', 'Long answer text')"
|
||||
:required="true /* TODO: implement required option */"
|
||||
:required="mandatory"
|
||||
:value="values[0]"
|
||||
class="question__text"
|
||||
:maxlength="maxStringLengths.answerText"
|
||||
|
|
|
|||
|
|
@ -22,13 +22,14 @@
|
|||
|
||||
<template>
|
||||
<Question
|
||||
:id="id"
|
||||
v-bind.sync="$attrs"
|
||||
:text="text"
|
||||
:mandatory="mandatory"
|
||||
:edit.sync="edit"
|
||||
:max-question-length="maxStringLengths.questionText"
|
||||
@delete="onDelete"
|
||||
@update:text="onTitleChange">
|
||||
@update:text="onTitleChange"
|
||||
@update:mandatory="onMandatoryChange"
|
||||
@delete="onDelete">
|
||||
<ul class="question__content">
|
||||
<template v-for="(answer, index) in options">
|
||||
<li v-if="!edit" :key="answer.id" class="question__item">
|
||||
|
|
@ -96,13 +97,6 @@ export default {
|
|||
|
||||
mixins: [QuestionMixin],
|
||||
|
||||
props: {
|
||||
id: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
|
||||
computed: {
|
||||
isLastEmpty() {
|
||||
const value = this.options[this.options.length - 1]
|
||||
|
|
@ -172,10 +166,18 @@ export default {
|
|||
* @returns {boolean}
|
||||
*/
|
||||
isRequired(id) {
|
||||
// false, if question not mandatory
|
||||
if (!this.mandatory) {
|
||||
return false
|
||||
}
|
||||
|
||||
// true for Radiobuttons
|
||||
if (this.isUnique) {
|
||||
return true
|
||||
}
|
||||
return this.areNoneChecked || this.isChecked(id)
|
||||
|
||||
// For checkboxes, only required if no other is checked
|
||||
return this.areNoneChecked
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -24,16 +24,18 @@
|
|||
<Question
|
||||
v-bind.sync="$attrs"
|
||||
:text="text"
|
||||
:mandatory="mandatory"
|
||||
:edit.sync="edit"
|
||||
:max-question-length="maxStringLengths.questionText"
|
||||
@delete="onDelete"
|
||||
@update:text="onTitleChange">
|
||||
@update:text="onTitleChange"
|
||||
@update:mandatory="onMandatoryChange"
|
||||
@delete="onDelete">
|
||||
<div class="question__content">
|
||||
<!-- TODO: properly choose max length -->
|
||||
<input ref="input"
|
||||
:aria-label="t('forms', 'A short answer for the question “{text}”', { text })"
|
||||
:placeholder="t('forms', 'Short answer text')"
|
||||
:required="true /* TODO: implement required option */"
|
||||
:required="mandatory"
|
||||
:value="values[0]"
|
||||
class="question__input"
|
||||
:maxlength="maxStringLengths.answerText"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue