Skip to content

Commit 2db438f

Browse files
hamza221Chartman123
authored andcommitted
Add multiple options with one paste #337
Signed-off-by: hamza221 <[email protected]>
1 parent 73c0aa7 commit 2db438f

File tree

4 files changed

+126
-3
lines changed

4 files changed

+126
-3
lines changed

src/components/Questions/Question.vue

Lines changed: 94 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,33 @@
5555
</template>
5656
</NcButton>
5757
</div>
58-
58+
<NcModal v-if="isModalOpen"
59+
size="normal"
60+
title="Add multiple options"
61+
:out-transition="true"
62+
:has-next="false"
63+
:has-previous="false"
64+
@close="closeModal">
65+
<div class="modal__content">
66+
<h1>Add multiple options {{ isModalOpen }}</h1>
67+
<textarea ref="input"
68+
v-model="inputedOptions"
69+
:aria-label="t('forms', 'An answer for the {index} option', { index: index + 1 })"
70+
:placeholder="t('forms', 'Answer number {index}', { index: index + 1 })"
71+
class="question__input"
72+
type="text" />
73+
<div class="options">
74+
<div v-for="(option, i) in multipleOptions" :key="i" class="single_option">
75+
<p>{{ option }}</p>
76+
</div>
77+
</div>
78+
<div>
79+
<NcButton @click="onMultipleOptions">
80+
Add options
81+
</NcButton>
82+
</div>
83+
</div>
84+
</NcModal>
5985
<!-- Header -->
6086
<div class="question__header">
6187
<div class="question__header__title">
@@ -118,6 +144,12 @@
118144
</template>
119145
{{ t('forms', 'Copy question') }}
120146
</NcActionButton>
147+
<NcActionButton @click="openModal">
148+
<template #icon>
149+
<IconContentPaste :size="20" />
150+
</template>
151+
{{ t('forms', 'Multiple Options') }}
152+
</NcActionButton>
121153
<NcActionButton @click="onDelete">
122154
<template #icon>
123155
<IconDelete :size="20" />
@@ -151,13 +183,16 @@ import NcActionButton from '@nextcloud/vue/dist/Components/NcActionButton.js'
151183
import NcActionCheckbox from '@nextcloud/vue/dist/Components/NcActionCheckbox.js'
152184
import NcActionInput from '@nextcloud/vue/dist/Components/NcActionInput.js'
153185
import NcButton from '@nextcloud/vue/dist/Components/NcButton.js'
186+
import NcModal from '@nextcloud/vue/dist/Components/NcModal.js'
187+
import { showError } from '@nextcloud/dialogs'
154188
155189
import IconAlertCircleOutline from 'vue-material-design-icons/AlertCircleOutline.vue'
156190
import IconArrowDown from 'vue-material-design-icons/ArrowDown.vue'
157191
import IconArrowUp from 'vue-material-design-icons/ArrowUp.vue'
158192
import IconAsterisk from 'vue-material-design-icons/Asterisk.vue'
159193
import IconContentCopy from 'vue-material-design-icons/ContentCopy.vue'
160194
import IconDelete from 'vue-material-design-icons/Delete.vue'
195+
import IconContentPaste from 'vue-material-design-icons/ContentPaste.vue'
161196
import IconDragHorizontalVariant from 'vue-material-design-icons/DragHorizontalVariant.vue'
162197
import IconDotsHorizontal from 'vue-material-design-icons/DotsHorizontal.vue'
163198
import IconIdentifier from 'vue-material-design-icons/Identifier.vue'
@@ -172,6 +207,7 @@ export default {
172207
IconArrowUp,
173208
IconAsterisk,
174209
IconContentCopy,
210+
IconContentPaste,
175211
IconDelete,
176212
IconDragHorizontalVariant,
177213
IconDotsHorizontal,
@@ -182,6 +218,7 @@ export default {
182218
NcActionCheckbox,
183219
NcActionInput,
184220
NcButton,
221+
NcModal,
185222
},
186223
187224
inject: ['$markdownit'],
@@ -241,6 +278,13 @@ export default {
241278
},
242279
},
243280
281+
data() {
282+
return {
283+
isModalOpen: false,
284+
inputedOptions: '',
285+
}
286+
},
287+
244288
computed: {
245289
/**
246290
* Extend text with asterisk if question is required
@@ -278,12 +322,40 @@ export default {
278322
hasDescription() {
279323
return this.description !== ''
280324
},
325+
multipleOptions() {
326+
const allOptions = this.inputedOptions.split(/\r?\n/g)
327+
return allOptions.filter(answer => { return answer.trim().length > 0 })
328+
},
281329
},
282330
// Ensure description is sized correctly on initial render
283331
mounted() {
284332
this.$nextTick(() => this.resizeDescription())
285333
},
286334
methods: {
335+
closeModal() {
336+
this.isModalOpen = false
337+
},
338+
339+
openModal() {
340+
this.isModalOpen = true
341+
},
342+
343+
onMultipleOptions() {
344+
this.isModalOpen = false
345+
this.$nextTick(() => {
346+
this.$emit('update:edit', true)
347+
if (this.multipleOptions.length > 1) {
348+
// extract all options entries to parent
349+
this.$emit('multiple-answers', this.multipleOptions)
350+
this.inputedOptions = ''
351+
return
352+
}
353+
// in case of only one option, just show an error message because it is probably missuse of the feature
354+
showError(t('forms', 'Options should seperated by new line!'))
355+
})
356+
357+
},
358+
287359
onTitleChange({ target }) {
288360
this.$emit('update:text', target.value)
289361
},
@@ -481,5 +553,26 @@ export default {
481553
}
482554
}
483555
}
556+
.modal__content {
557+
padding: 20px;
558+
display: flex;
559+
flex-direction: column;
560+
}
561+
.options{
562+
display: flex !important;
563+
flex-wrap: wrap;
564+
width: 100%;
565+
padding: 10px;
566+
justify-content: flex-start;
567+
max-height: 300px;
568+
overflow-y: auto;
569+
margin: 5px 0px;
570+
}
571+
.single_option{
572+
width: max-content;
573+
padding: 5px;
574+
margin: 5px;
575+
border: 1px solid var(--color-primary);
576+
}
484577
485578
</style>

src/components/Questions/QuestionDropdown.vue

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@
2626
:warning-invalid="answerType.warningInvalid"
2727
:content-valid="contentValid"
2828
:shift-drag-handle="shiftDragHandle"
29-
v-on="commonListeners">
29+
v-on="commonListeners"
30+
@multiple-answers="handleMultipleOptions">
3031
<template #actions>
3132
<NcActionCheckbox :checked="extraSettings?.shuffleOptions"
3233
@update:checked="onShuffleOptionsChange">

src/components/Questions/QuestionMultiple.vue

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@
2626
:warning-invalid="answerType.warningInvalid"
2727
:content-valid="contentValid"
2828
:shift-drag-handle="shiftDragHandle"
29-
v-on="commonListeners">
29+
v-on="commonListeners"
30+
@multiple-answers="handleMultipleOptions">
3031
<template #actions>
3132
<NcActionCheckbox :checked="extraSettings?.shuffleOptions"
3233
@update:checked="onShuffleOptionsChange">

src/mixins/QuestionMixin.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import { emit } from '@nextcloud/event-bus'
2424
import { generateOcsUrl } from '@nextcloud/router'
2525
import axios from '@nextcloud/axios'
2626
import debounce from 'debounce'
27+
import GenRandomId from '../utils/GenRandomId.js'
2728

2829
import logger from '../utils/Logger.js'
2930
import Question from '../components/Questions/Question.vue'
@@ -359,5 +360,32 @@ export default {
359360
showError(t('forms', 'Error while saving question'))
360361
}
361362
},
363+
async handleMultipleOptions(answers) {
364+
this.edit = true
365+
const options = this.options.slice()
366+
for (let i = 0; i < answers.length; i++) {
367+
options.push({
368+
id: GenRandomId(),
369+
questionId: this.id,
370+
text: answers[i],
371+
local: false,
372+
})
373+
374+
await axios.post(generateOcsUrl('apps/forms/api/v2/option'), {
375+
questionId: this.id,
376+
text: answers[i],
377+
})
378+
}
379+
options.push({
380+
id: GenRandomId(),
381+
questionId: this.id,
382+
text: '',
383+
local: true,
384+
})
385+
this.updateOptions(options)
386+
this.$nextTick(() => {
387+
this.focusIndex(options.length - 1)
388+
})
389+
},
362390
},
363391
}

0 commit comments

Comments
 (0)