Skip to content

Commit 231300c

Browse files
hamza221Chartman123
authored andcommitted
Add multiple options with one paste #337
Signed-off-by: hamza221 <[email protected]>
1 parent 82e01be commit 231300c

File tree

4 files changed

+280
-62
lines changed

4 files changed

+280
-62
lines changed

src/components/OptionInputDialog.vue

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
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', 'Entered 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 IconCancel from '@mdi/svg/svg/cancel.svg?raw'
50+
import IconCheck from '@mdi/svg/svg/check.svg?raw'
51+
52+
import { defineComponent } from 'vue'
53+
54+
export default defineComponent({
55+
name: 'OptionInputDialog',
56+
57+
components: {
58+
NcDialog,
59+
NcSelect,
60+
NcTextArea,
61+
},
62+
63+
props: {
64+
open: {
65+
type: Boolean,
66+
required: true,
67+
},
68+
},
69+
70+
emits: ['update:open'],
71+
72+
data() {
73+
return {
74+
enteredOptions: '',
75+
}
76+
},
77+
78+
computed: {
79+
buttons() {
80+
return [
81+
{
82+
label: t('forms', 'Cancel'),
83+
icon: IconCancel,
84+
callback: () => { this.$emit('update:open', false) },
85+
},
86+
{
87+
label: t('forms', 'Add options'),
88+
type: 'primary',
89+
icon: IconCheck,
90+
callback: () => { this.onMultipleOptions() },
91+
},
92+
]
93+
},
94+
95+
multipleOptions() {
96+
const allOptions = this.enteredOptions.split(/\r?\n/g)
97+
return allOptions.filter(answer => { return answer.trim().length > 0 })
98+
},
99+
},
100+
101+
methods: {
102+
t,
103+
104+
onMultipleOptions() {
105+
this.$emit('update:open', false)
106+
if (this.multipleOptions.length > 1) {
107+
// extract all options entries to parent
108+
this.$emit('multiple-answers', this.multipleOptions)
109+
this.enteredOptions = ''
110+
return
111+
}
112+
// in case of only one option, just show an error message because it is probably missuse of the feature
113+
showError(t('forms', 'Options should seperated by new line!'))
114+
},
115+
},
116+
})
117+
</script>
118+
119+
<style scoped>
120+
:deep(.options-modal) {
121+
padding: 20px;
122+
}
123+
124+
:deep(.v-select) {
125+
width: 100%;
126+
margin-top: 10px !important;
127+
display: flex;
128+
flex-direction: column;
129+
gap: 2px 0;
130+
}
131+
</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)