Skip to content

Commit

Permalink
fix
Browse files Browse the repository at this point in the history
Signed-off-by: Christian Hartmann <[email protected]>
  • Loading branch information
Chartman123 committed Feb 16, 2025
1 parent 3cd1722 commit c688bff
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 134 deletions.
68 changes: 47 additions & 21 deletions src/components/Questions/AnswerInput.vue
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@
dir="auto"
@input="debounceOnInput"
@keydown.delete="deleteEntry"
@keydown.enter.prevent="focusNextInput" />
@keydown.enter.prevent="focusNextInput"
@compositionstart="onCompositionEnd"
@compositionend="onCompositionEnd" />

<!-- Actions for reordering and deleting the option -->
<div class="option__actions">
Expand Down Expand Up @@ -129,6 +131,7 @@ export default {
return {
queue: null,
debounceOnInput: null,
isIMEComposing: false,
}
},

Expand Down Expand Up @@ -158,8 +161,8 @@ export default {
this.queue = new PQueue({ concurrency: 1 })

// As data instead of method, to have a separate debounce per AnswerInput
this.debounceOnInput = debounce(() => {
return this.queue.add(() => this.onInput())
this.debounceOnInput = debounce((event) => {
return this.queue.add(() => this.onInput(event))
}, 500)
},

Expand All @@ -177,24 +180,29 @@ export default {

/**
* Option changed, processing the data
*
* @param {InputEvent} event The input event that triggered adding a new entry
*/
async onInput() {
// clone answer
const answer = Object.assign({}, this.answer)
answer.text = this.$refs.input.value

if (this.answer.local) {
// Dispatched for creation. Marked as synced
this.$set(this.answer, 'local', false)
const newAnswer = await this.createAnswer(answer)

// Forward changes, but use current answer.text to avoid erasing
// any in-between changes while creating the answer
newAnswer.text = this.$refs.input.value
this.$emit('update:answer', newAnswer)
} else {
await this.updateAnswer(answer)
this.$emit('update:answer', answer)
async onInput({ target, isComposing }) {
if (!isComposing && !this.isIMEComposing && target.value !== '') {
// clone answer
const answer = Object.assign({}, this.answer)
answer.text = this.$refs.input.value

if (this.answer.local) {
// Dispatched for creation. Marked as synced
this.$set(this.answer, 'local', false)
const newAnswer = await this.createAnswer(answer)

// Forward changes, but use current answer.text to avoid erasing
// any in-between changes while creating the answer
newAnswer.text = this.$refs.input.value

this.$emit('create-answer', this.index, newAnswer)
} else {
await this.updateAnswer(answer)
this.$emit('update:answer', this.index, answer)
}
}
},

Expand Down Expand Up @@ -258,7 +266,7 @@ export default {

// Was synced once, this is now up to date with the server
delete answer.local
return { ...answer, ...OcsResponse2Data(response) }
return OcsResponse2Data(response)[0]
} catch (error) {
logger.error('Error while saving answer', { answer, error })
showError(t('forms', 'Error while saving the answer'))
Expand Down Expand Up @@ -317,6 +325,24 @@ export default {
this.$nextTick(() => this.$refs.buttonDown.$el.focus())
}
},

/**
* Handle compostion start event for IME inputs
*/
onCompositionStart() {
this.isIMEComposing = true
},

/**
* Handle compostion end event for IME inputs
* @param {CompositionEvent} event The input event that triggered adding a new entry
*/
onCompositionEnd({ target, isComposing }) {
this.isIMEComposing = false
if (!isComposing) {
this.onInput({ target, isComposing })
}
},
},
}
</script>
Expand Down
19 changes: 3 additions & 16 deletions src/components/Questions/QuestionDropdown.vue
Original file line number Diff line number Diff line change
Expand Up @@ -54,26 +54,13 @@
:is-unique="!isMultiple"
:max-index="options.length - 1"
:max-option-length="maxStringLengths.optionText"
@move-up="onOptionMoveUp(index)"
@move-down="onOptionMoveDown(index)"
@create-answer="onCreateAnswer"
@update:answer="updateAnswer(index, $event)"
@delete="deleteOption"
@focus-next="focusNextInput"
@move-up="onOptionMoveUp(index)"
@move-down="onOptionMoveDown(index)"
@tabbed-out="checkValidOption" />

<li v-if="!isLastEmpty || hasNoAnswer" class="question__item">
<input
ref="pseudoInput"
class="question__input"
:aria-label="t('forms', 'Add a new answer')"
:placeholder="t('forms', 'Add a new answer')"
:maxlength="maxStringLengths.optionText"
minlength="1"
type="text"
@input="addNewEntry"
@compositionstart="onCompositionStart"
@compositionend="onCompositionEnd" />
</li>
</TransitionList>
</template>

Expand Down
21 changes: 4 additions & 17 deletions src/components/Questions/QuestionMultiple.vue
Original file line number Diff line number Diff line change
Expand Up @@ -131,11 +131,12 @@
:is-dropdown="false"
:max-index="options.length - 1"
:max-option-length="maxStringLengths.optionText"
@move-up="onOptionMoveUp(index)"
@move-down="onOptionMoveDown(index)"
@delete="deleteOption"
@create-answer="onCreateAnswer"
@update:answer="updateAnswer"
@delete="deleteOption"
@focus-next="focusNextInput"
@move-up="onOptionMoveUp(index)"
@move-down="onOptionMoveDown(index)"
@tabbed-out="checkValidOption" />
<li
v-if="allowOtherAnswer"
Expand All @@ -151,20 +152,6 @@
type="text"
:readonly="!readOnly" />
</li>
<li v-if="!isLastEmpty || hasNoAnswer" class="question__item">
<div :is="pseudoIcon" class="question__item__pseudoInput" />
<input
ref="pseudoInput"
class="question__input"
:aria-label="t('forms', 'Add a new answer')"
:placeholder="t('forms', 'Add a new answer')"
:maxlength="maxStringLengths.optionText"
minlength="1"
type="text"
@input="addNewEntry"
@compositionstart="onCompositionStart"
@compositionend="onCompositionEnd" />
</li>
</TransitionList>
</template>

Expand Down
67 changes: 0 additions & 67 deletions src/mixins/QuestionMixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import axios from '@nextcloud/axios'
import debounce from 'debounce'

import logger from '../utils/Logger.js'
import GenRandomId from '../utils/GenRandomId.js'
import OcsResponse2Data from '../utils/OcsResponse2Data.js'
import Question from '../components/Questions/Question.vue'

Expand Down Expand Up @@ -164,14 +163,6 @@ export default {
type: Boolean,
default: false,
},

/**
* isComposing for IME handling
*/
isIMEComposing: {
type: Boolean,
default: false,
},
},

components: {
Expand Down Expand Up @@ -408,63 +399,5 @@ export default {
}
this.isLoading = false
},

/**
* Add a new empty answer locally
* @param {InputEvent} event The input event that triggered adding a new entry
*/
addNewEntry({ target, isComposing }) {
/*
* Check for !isComposing needed for languages using IME like Japanese or Chinese
* Check for !this.isComposing needed for IME inputs handled by CompositionEvents
* Check for target.value !== '' needed for Linux/Mac for characters like á or è
*/
if (!isComposing && !this.isIMEComposing && target.value !== '') {
// Add local entry
const options = [
...this.options,
{
id: GenRandomId(),
questionId: this.id,
text: target.value,
local: true,
},
]

// Reset the "new answer" input if needed
if (this.$refs.pseudoInput) {
this.$refs.pseudoInput.value = ''
}

// Update questions
this.updateOptions(options)

this.$nextTick(() => {
// Set focus to the created input element
this.focusIndex(options.length - 1)

// Trigger onInput on new AnswerInput for posting the new option to the API
this.$refs.input[options.length - 1].debounceOnInput()
})
}
},

/**
* Handle compostion start event for IME inputs
*/
onCompositionStart() {
this.isIMEComposing = true
},

/**
* Handle compostion end event for IME inputs
* @param {CompositionEvent} event The input event that triggered adding a new entry
*/
onCompositionEnd({ target, isComposing }) {
this.isIMEComposing = false
if (!isComposing) {
this.addNewEntry({ target, isComposing })
}
},
},
}
14 changes: 14 additions & 0 deletions src/mixins/QuestionMultipleMixin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,20 @@ export default defineComponent({
}
},

/**
* Handles the creation of a new answer option.
*
* @param index the index of the answer
* @param {FormsOption} answer - The new answer option to be added.
* @return {void}
*/
onCreateAnswer(index: number, answer: FormsOption): void {
this.$nextTick(() => {
this.$nextTick(() => this.focusIndex(index))
})
this.updateOptions([...this.options, answer])
},

/**
* Update the options
* This will handle updating the form (emitting the changes) and update last changed property
Expand Down
13 changes: 0 additions & 13 deletions src/utils/GenRandomId.js

This file was deleted.

0 comments on commit c688bff

Please sign in to comment.