Skip to content

Commit 8d9a25c

Browse files
hamza221Chartman123
authored andcommitted
Add multiple options with one paste #337
Signed-off-by: hamza221 <[email protected]>
1 parent 264b932 commit 8d9a25c

File tree

4 files changed

+278
-62
lines changed

4 files changed

+278
-62
lines changed

src/components/OptionInputDialog.vue

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
<!--
2+
- @copyright Copyright (c) 2024 Christian Hartmann <[email protected]>
3+
-
4+
- @author Christian Hartmann <[email protected]>
5+
-
6+
- @license AGPL-3.0-or-later
7+
-
8+
- This program is free software: you can redistribute it and/or modify
9+
- it under the terms of the GNU Affero General Public License as
10+
- published by the Free Software Foundation, either version 3 of the
11+
- License, or (at your option) any later version.
12+
-
13+
- This program is distributed in the hope that it will be useful,
14+
- but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+
- GNU Affero General Public License for more details.
17+
-
18+
- You should have received a copy of the GNU Affero General Public License
19+
- along with this program. If not, see <http://www.gnu.org/licenses/>.
20+
-
21+
-->
22+
23+
<template>
24+
<NcDialog content-classes="options-modal"
25+
:name="t('forms', 'Add multiple options')"
26+
:open="open"
27+
:buttons="buttons"
28+
size="normal"
29+
@update:open="$emit('update:open', $event)">
30+
<NcTextArea :value.sync="enteredOptions"
31+
:label="t('forms', 'Add multiple options (one per line)')"
32+
:placeholder="t('forms', 'Add multiple options (one per line)')"
33+
resize="vertical"
34+
rows="10" />
35+
<NcSelect :input-label="t('forms', 'Options')"
36+
multiple
37+
disabled
38+
:value="multipleOptions" />
39+
</NcDialog>
40+
</template>
41+
42+
<script>
43+
import { showError } from '@nextcloud/dialogs'
44+
import { translate as t } from '@nextcloud/l10n'
45+
import NcDialog from '@nextcloud/vue/dist/Components/NcDialog.js'
46+
import NcSelect from '@nextcloud/vue/dist/Components/NcSelect.js'
47+
import NcTextArea from '@nextcloud/vue/dist/Components/NcTextArea.js'
48+
49+
import IconCheck from '@mdi/svg/svg/check.svg?raw'
50+
51+
import { defineComponent } from 'vue'
52+
53+
export default defineComponent({
54+
name: 'OptionInputDialog',
55+
56+
components: {
57+
NcDialog,
58+
NcSelect,
59+
NcTextArea,
60+
},
61+
62+
props: {
63+
open: {
64+
type: Boolean,
65+
required: true,
66+
},
67+
},
68+
69+
emits: ['update:open'],
70+
71+
data() {
72+
return {
73+
enteredOptions: '',
74+
}
75+
},
76+
77+
computed: {
78+
buttons() {
79+
return [
80+
{
81+
label: t('forms', 'Cancel'),
82+
callback: () => { this.$emit('update:open', false) },
83+
},
84+
{
85+
label: t('forms', 'Add options'),
86+
type: 'primary',
87+
icon: IconCheck,
88+
callback: () => { this.onMultipleOptions() },
89+
},
90+
]
91+
},
92+
93+
multipleOptions() {
94+
const allOptions = this.enteredOptions.split(/\r?\n/g)
95+
return allOptions.filter(answer => { return answer.trim().length > 0 })
96+
},
97+
},
98+
99+
methods: {
100+
t,
101+
102+
onMultipleOptions() {
103+
this.$emit('update:open', false)
104+
if (this.multipleOptions.length > 1) {
105+
// extract all options entries to parent
106+
this.$emit('multiple-answers', this.multipleOptions)
107+
this.enteredOptions = ''
108+
return
109+
}
110+
// in case of only one option, just show an error message because it is probably missuse of the feature
111+
showError(t('forms', 'Options should be seperated by new line!'))
112+
},
113+
},
114+
})
115+
</script>
116+
117+
<style scoped>
118+
:deep(.options-modal) {
119+
padding: 20px;
120+
}
121+
122+
:deep(.v-select) {
123+
width: 100%;
124+
margin-top: 10px !important;
125+
display: flex;
126+
flex-direction: column;
127+
gap: 2px 0;
128+
}
129+
</style>

src/components/Questions/QuestionDropdown.vue

Lines changed: 54 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,13 @@
3232
@update:checked="onShuffleOptionsChange">
3333
{{ t('forms', 'Shuffle options') }}
3434
</NcActionCheckbox>
35+
<NcActionButton close-after-click
36+
@click="isOptionDialogShown = true">
37+
<template #icon>
38+
<IconContentPaste :size="20" />
39+
</template>
40+
{{ t('forms', 'Add multiple options') }}
41+
</NcActionButton>
3542
</template>
3643
<NcSelect v-if="readOnly"
3744
v-model="selectedOption"
@@ -44,33 +51,42 @@
4451
label="text"
4552
@input="onInput" />
4653

47-
<ol v-if="!readOnly" class="question__content">
48-
<!-- Answer text input edit -->
49-
<AnswerInput v-for="(answer, index) in options"
50-
:key="index /* using index to keep the same vnode after new answer creation */"
51-
ref="input"
52-
:answer="answer"
53-
:index="index"
54-
:is-unique="!isMultiple"
55-
:is-dropdown="true"
56-
:max-option-length="maxStringLengths.optionText"
57-
@delete="deleteOption"
58-
@update:answer="updateAnswer"
59-
@focus-next="focusNextInput"
60-
@tabbed-out="checkValidOption" />
61-
62-
<li v-if="!isLastEmpty || hasNoAnswer" class="question__item">
63-
<input ref="pseudoInput"
64-
v-model="inputValue"
65-
:aria-label="t('forms', 'Add a new answer')"
66-
:placeholder="t('forms', 'Add a new answer')"
67-
class="question__input"
68-
:maxlength="maxStringLengths.optionText"
69-
minlength="1"
70-
type="text"
71-
@input="addNewEntry">
72-
</li>
73-
</ol>
54+
<template v-else>
55+
<div v-if="isLoading">
56+
<NcLoadingIcon :size="64" />
57+
</div>
58+
<ol v-else class="question__content">
59+
<!-- Answer text input edit -->
60+
<AnswerInput v-for="(answer, index) in options"
61+
:key="index /* using index to keep the same vnode after new answer creation */"
62+
ref="input"
63+
:answer="answer"
64+
:index="index"
65+
:is-unique="!isMultiple"
66+
:is-dropdown="true"
67+
:max-option-length="maxStringLengths.optionText"
68+
@delete="deleteOption"
69+
@update:answer="updateAnswer"
70+
@focus-next="focusNextInput"
71+
@tabbed-out="checkValidOption" />
72+
73+
<li v-if="!isLastEmpty || hasNoAnswer" class="question__item">
74+
<input ref="pseudoInput"
75+
v-model="inputValue"
76+
:aria-label="t('forms', 'Add a new answer')"
77+
:placeholder="t('forms', 'Add a new answer')"
78+
class="question__input"
79+
:maxlength="maxStringLengths.optionText"
80+
minlength="1"
81+
type="text"
82+
@input="addNewEntry">
83+
</li>
84+
</ol>
85+
</template>
86+
87+
<!-- Add multiple options modal -->
88+
<OptionInputDialog :open.sync="isOptionDialogShown"
89+
@multiple-answers="handleMultipleOptions" />
7490
</Question>
7591
</template>
7692

@@ -80,9 +96,14 @@ import { emit } from '@nextcloud/event-bus'
8096
import { generateOcsUrl } from '@nextcloud/router'
8197
import axios from '@nextcloud/axios'
8298
import NcActionCheckbox from '@nextcloud/vue/dist/Components/NcActionCheckbox.js'
99+
import NcActionButton from '@nextcloud/vue/dist/Components/NcActionButton.js'
100+
import NcLoadingIcon from '@nextcloud/vue/dist/Components/NcLoadingIcon.js'
83101
import NcSelect from '@nextcloud/vue/dist/Components/NcSelect.js'
84102
103+
import IconContentPaste from 'vue-material-design-icons/ContentPaste.vue'
104+
85105
import AnswerInput from './AnswerInput.vue'
106+
import OptionInputDialog from '../OptionInputDialog.vue'
86107
import QuestionMixin from '../../mixins/QuestionMixin.js'
87108
import GenRandomId from '../../utils/GenRandomId.js'
88109
import logger from '../../utils/Logger.js'
@@ -92,8 +113,12 @@ export default {
92113
93114
components: {
94115
AnswerInput,
116+
IconContentPaste,
117+
NcActionButton,
95118
NcActionCheckbox,
119+
NcLoadingIcon,
96120
NcSelect,
121+
OptionInputDialog,
97122
},
98123
99124
mixins: [QuestionMixin],
@@ -102,6 +127,8 @@ export default {
102127
return {
103128
selectedOption: null,
104129
inputValue: '',
130+
isOptionDialogShown: false,
131+
isLoading: false,
105132
}
106133
},
107134

0 commit comments

Comments
 (0)