Merge pull request #347 from nextcloud/enh/mandatory

Mandatory option on questions
This commit is contained in:
Jan-Christoph Borchardt 2020-05-05 23:40:35 +02:00 committed by GitHub
commit 0904899811
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 150 additions and 61 deletions

View file

@ -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>

View file

@ -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"

View file

@ -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
},
/**

View file

@ -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"