Skip to content

Commit

Permalink
fix(a11y): Make form editable with keyboard
Browse files Browse the repository at this point in the history
Signed-off-by: Christian Hartmann <chris-hartmann@gmx.de>
  • Loading branch information
Chartman123 committed Nov 9, 2023
1 parent a6fb2d5 commit 869cd3c
Show file tree
Hide file tree
Showing 9 changed files with 126 additions and 222 deletions.
15 changes: 10 additions & 5 deletions src/components/Questions/AnswerInput.vue
@@ -1,5 +1,5 @@
<template>
<li class="question__item">
<li class="question__item" @focusout="handleTabbing">
<div :is="pseudoIcon"
v-if="!isDropdown"
class="question__item__pseudoInput" />
Expand Down Expand Up @@ -98,6 +98,10 @@ export default {
},
methods: {
handleTabbing() {
this.$emit('tabbed-out')
},
/**
* Focus the input
*/
Expand Down Expand Up @@ -221,13 +225,14 @@ export default {
.question__input {
width: 100%;
position: relative;
margin-inline-end: 2px !important;
inset-inline-start: -12px;
margin-inline-end: -12px !important;
&--shifted {
inset-inline-start: -30px;
inset-inline-start: -34px;
inset-block-start: 1px;
margin-inline-end: -30px !important;
padding-inline-start: 32px !important;
margin-inline-end: -34px !important;
padding-inline-start: 36px !important;
}
}
}
Expand Down
44 changes: 7 additions & 37 deletions src/components/Questions/Question.vue
Expand Up @@ -21,14 +21,12 @@
-->

<template>
<li v-click-outside="disableEdit"
:class="{
<li :class="{
'question': true,
'question--edit': edit,
'question--edit': !readOnly,
'question--editable': !readOnly
}"
:aria-label="t('forms', 'Question number {index}', {index})"
@click="enableEdit">
:aria-label="t('forms', 'Question number {index}', {index})">
<!-- Drag handle -->
<!-- TODO: implement arrow key mapping to reorder question -->
<div v-if="!readOnly"
Expand Down Expand Up @@ -62,7 +60,7 @@
<!-- Header -->
<div class="question__header">
<div class="question__header__title">
<input v-if="edit || !questionValid"
<input v-if="!readOnly || !questionValid"
:placeholder="titlePlaceholder"
:aria-label="t('forms', 'Title of question number {index}', {index})"
:value="text"
Expand All @@ -79,7 +77,7 @@
dir="auto">
{{ computedText }}
</h3>
<div v-if="!edit && !questionValid"
<div v-if="!readOnly && !questionValid"
v-tooltip.auto="warningInvalid"
class="question__header__title__warning"
tabindex="0">
Expand Down Expand Up @@ -111,8 +109,8 @@
</NcActionButton>
</NcActions>
</div>
<div v-if="hasDescription || edit || !questionValid" class="question__header__description">
<textarea v-if="edit || !questionValid"
<div v-if="hasDescription || !readOnly || !questionValid" class="question__header__description">
<textarea v-if="!readOnly || !questionValid"
ref="description"
dir="auto"
:value="description"
Expand All @@ -131,8 +129,6 @@
</template>

<script>
import { directive as ClickOutside } from 'v-click-outside'
import NcActions from '@nextcloud/vue/dist/Components/NcActions.js'
import NcActionButton from '@nextcloud/vue/dist/Components/NcActionButton.js'
import NcActionCheckbox from '@nextcloud/vue/dist/Components/NcActionCheckbox.js'
Expand All @@ -149,10 +145,6 @@ import IconIdentifier from 'vue-material-design-icons/Identifier.vue'
export default {
name: 'Question',
directives: {
ClickOutside,
},
components: {
IconAlertCircleOutline,
IconArrowDown,
Expand Down Expand Up @@ -194,10 +186,6 @@ export default {
type: Boolean,
default: false,
},
edit: {
type: Boolean,
required: true,
},
readOnly: {
type: Boolean,
default: false,
Expand Down Expand Up @@ -319,24 +307,6 @@ export default {
this.$nextTick(() => this.$refs.buttonUp.$el.focus())
},
/**
* Enable the edit mode
*/
enableEdit() {
if (!this.readOnly) {
this.$emit('update:edit', true)
}
},
/**
* Disable the edit mode
*/
disableEdit() {
if (!this.readOnly) {
this.$emit('update:edit', false)
}
},
/**
* Delete this question
*/
Expand Down
4 changes: 4 additions & 0 deletions src/components/Questions/QuestionDate.vue
Expand Up @@ -128,6 +128,10 @@ export default {
.mx-datepicker {
width: 300px;
&.disabled {
inset-inline-start: -12px;
}
:deep(.mx-input) {
height: 44px !important;
}
Expand Down
63 changes: 31 additions & 32 deletions src/components/Questions/QuestionDropdown.vue
Expand Up @@ -33,7 +33,7 @@
{{ t('forms', 'Shuffle options') }}
</NcActionCheckbox>
</template>
<NcSelect v-if="!edit"
<NcSelect v-if="readOnly"
v-model="selectedOption"
:name="name || undefined"
:placeholder="selectOptionPlaceholder"
Expand All @@ -44,7 +44,7 @@
label="text"
@input="onInput" />
<ol v-if="edit" class="question__content">
<ol v-if="!readOnly" class="question__content">
<!-- Answer text input edit -->
<AnswerInput v-for="(answer, index) in options"
:key="index /* using index to keep the same vnode after new answer creation */"
Expand All @@ -56,17 +56,18 @@
:max-option-length="maxStringLengths.optionText"
@add="addNewEntry"
@delete="deleteOption"
@update:answer="updateAnswer" />
@update:answer="updateAnswer"
@focusout="checkValidOption" />
<li v-if="!isLastEmpty || hasNoAnswer" class="question__item">
<input :aria-label="t('forms', 'Add a new answer')"
<input v-model="inputValue"
:aria-label="t('forms', 'Add a new answer')"
:placeholder="t('forms', 'Add a new answer')"
class="question__input"
:maxlength="maxStringLengths.optionText"
minlength="1"
type="text"
@click="addNewEntry"
@focus="addNewEntry">
@input="addNewEntry">
</li>
</ol>
</Question>
Expand Down Expand Up @@ -99,6 +100,7 @@ export default {
data() {
return {
selectedOption: null,
inputValue: '',
}
},
Expand Down Expand Up @@ -133,7 +135,7 @@ export default {
},
shiftDragHandle() {
return this.edit && this.options.length !== 0 && !this.isLastEmpty
return !this.readOnly && this.options.length !== 0 && !this.isLastEmpty
},
},
Expand All @@ -146,26 +148,6 @@ export default {
},
methods: {
/**
* Handle toggling the edit mode
* @param {boolean} enabled Whether the edit mode is enabled
*/
onUpdateEdit(enabled) {
// When leaving edit mode, filter and delete empty options
if (!enabled) {
const options = this.options.filter(option => {
if (!option.text) {
this.deleteOptionFromDatabase(option)
return false
}
return true
})
// update parent
this.updateOptions(options)
}
},
onInput(option) {
if (Array.isArray(option)) {
this.$emit('update:values', [...new Set(option.map((opt) => opt.id))])
Expand All @@ -176,6 +158,20 @@ export default {
this.$emit('update:values', option ? [option.id] : [])
},
checkValidOption() {
// When leaving edit mode, filter and delete empty options
const options = this.options.filter(option => {
if (!option.text) {
this.deleteOption(option.id)
return false
}
return true
})
// update parent
this.updateOptions(options)
},
/**
* Update the options
*
Expand Down Expand Up @@ -204,23 +200,25 @@ export default {
* Add a new empty answer locally
*/
addNewEntry() {
// If entering from non-edit-mode (possible by click), activate edit-mode
this.edit = true
// Add local entry
const options = this.options.slice()
options.push({
id: GenRandomId(),
questionId: this.id,
text: '',
text: this.inputValue,
local: true,
})
this.inputValue = ''
// Update question
this.updateOptions(options)
this.$nextTick(() => {
this.focusIndex(options.length - 1)
// Trigger onInput on new AnswerInput for posting the new option to the API
this.$refs.input[options.length - 1].onInput()
})
},
Expand Down Expand Up @@ -320,7 +318,8 @@ export default {
.question__input {
width: 100%;
position: relative;
margin-inline-end: 46px !important;
inset-inline-start: -12px;
margin-inline-end: 32px !important;
}
}
</style>
2 changes: 2 additions & 0 deletions src/components/Questions/QuestionLong.vue
Expand Up @@ -98,6 +98,8 @@ export default {
// Just overrides Server CSS-Styling for disabled inputs. -> Not Good??
background-color: var(--color-main-background);
color: var(--color-main-text);
width: calc(100% - 32px) !important;
margin-inline-start: -12px;
}
}
Expand Down

0 comments on commit 869cd3c

Please sign in to comment.