Make poll accessible
This commit is contained in:
parent
18c0cf1845
commit
129e4a2034
|
@ -0,0 +1 @@
|
||||||
|
Make poll accessible
|
|
@ -540,7 +540,9 @@ textarea,
|
||||||
}
|
}
|
||||||
|
|
||||||
&[type="radio"] {
|
&[type="radio"] {
|
||||||
display: none;
|
&:not(.visible-for-screenreader-only) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
&:checked + label::before {
|
&:checked + label::before {
|
||||||
box-shadow: 0 0 2px black inset, 0 0 0 4px $fallback--fg inset;
|
box-shadow: 0 0 2px black inset, 0 0 0 4px $fallback--fg inset;
|
||||||
|
@ -597,6 +599,7 @@ textarea,
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
content: "✓";
|
content: "✓";
|
||||||
|
content: "✓" / "";
|
||||||
transition: color 200ms;
|
transition: color 200ms;
|
||||||
width: 1.1em;
|
width: 1.1em;
|
||||||
height: 1.1em;
|
height: 1.1em;
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import Timeago from 'components/timeago/timeago.vue'
|
import Timeago from 'components/timeago/timeago.vue'
|
||||||
import genRandomSeed from '../../services/random_seed/random_seed.service.js'
|
import genRandomSeed from '../../services/random_seed/random_seed.service.js'
|
||||||
import RichContent from 'components/rich_content/rich_content.jsx'
|
import RichContent from 'components/rich_content/rich_content.jsx'
|
||||||
import { forEach, map } from 'lodash'
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Poll',
|
name: 'Poll',
|
||||||
|
@ -81,25 +80,17 @@ export default {
|
||||||
this.$store.dispatch('refreshPoll', { id: this.statusId, pollId: this.poll.id })
|
this.$store.dispatch('refreshPoll', { id: this.statusId, pollId: this.poll.id })
|
||||||
},
|
},
|
||||||
activateOption (index) {
|
activateOption (index) {
|
||||||
// forgive me father: doing checking the radio/checkboxes
|
|
||||||
// in code because of customized input elements need either
|
|
||||||
// a) an extra element for the actual graphic, or b) use a
|
|
||||||
// pseudo element for the label. We use b) which mandates
|
|
||||||
// using "for" and "id" matching which isn't nice when the
|
|
||||||
// same poll appears multiple times on the site (notifs and
|
|
||||||
// timeline for example). With code we can make sure it just
|
|
||||||
// works without altering the pseudo element implementation.
|
|
||||||
const allElements = this.$el.querySelectorAll('input')
|
|
||||||
const clickedElement = this.$el.querySelector(`input[value="${index}"]`)
|
|
||||||
if (this.poll.multiple) {
|
if (this.poll.multiple) {
|
||||||
// Checkboxes, toggle only the clicked one
|
// Multiple choice: toggle the current index
|
||||||
clickedElement.checked = !clickedElement.checked
|
const nextChoices = [...this.choices]
|
||||||
|
nextChoices[index] = !nextChoices[index]
|
||||||
|
this.choices = nextChoices
|
||||||
} else {
|
} else {
|
||||||
// Radio button, uncheck everything and check the clicked one
|
// Radio button, uncheck everything and check the clicked one
|
||||||
forEach(allElements, element => { element.checked = false })
|
const nextChoices = new Array(this.choices.length).fill(false)
|
||||||
clickedElement.checked = true
|
nextChoices[index] = true
|
||||||
|
this.choices = nextChoices
|
||||||
}
|
}
|
||||||
this.choices = map(allElements, e => e.checked)
|
|
||||||
},
|
},
|
||||||
optionId (index) {
|
optionId (index) {
|
||||||
return `poll${this.poll.id}-${index}`
|
return `poll${this.poll.id}-${index}`
|
||||||
|
|
|
@ -31,36 +31,41 @@
|
||||||
:style="{ 'width': `${percentageForOption(option.votes_count)}%` }"
|
:style="{ 'width': `${percentageForOption(option.votes_count)}%` }"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<template
|
||||||
v-else
|
v-else
|
||||||
tabindex="0"
|
|
||||||
:role="poll.multiple ? 'checkbox' : 'radio'"
|
|
||||||
:aria-labelledby="`option-vote-${randomSeed}-${index}`"
|
|
||||||
:aria-checked="choices[index]"
|
|
||||||
@click="activateOption(index)"
|
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
v-if="poll.multiple"
|
v-if="poll.multiple"
|
||||||
|
:id="`option-vote-input-${randomSeed}-${index}`"
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
class="poll-checkbox"
|
tabindex="0"
|
||||||
|
class="visible-for-screenreader-only"
|
||||||
:disabled="loading"
|
:disabled="loading"
|
||||||
:value="index"
|
:value="index"
|
||||||
|
:checked="choices[index]"
|
||||||
|
@change="activateOption(index)"
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
v-else
|
v-else
|
||||||
|
:id="`option-vote-input-${randomSeed}-${index}`"
|
||||||
type="radio"
|
type="radio"
|
||||||
|
class="visible-for-screenreader-only"
|
||||||
:disabled="loading"
|
:disabled="loading"
|
||||||
:value="index"
|
:value="index"
|
||||||
|
:checked="choices[index]"
|
||||||
|
@change="activateOption(index)"
|
||||||
|
>
|
||||||
|
<label
|
||||||
|
class="option-vote"
|
||||||
|
:for="`option-vote-input-${randomSeed}-${index}`"
|
||||||
>
|
>
|
||||||
<label class="option-vote">
|
|
||||||
<RichContent
|
<RichContent
|
||||||
:id="`option-vote-${randomSeed}-${index}`"
|
|
||||||
:html="option.title_html"
|
:html="option.title_html"
|
||||||
:handle-links="false"
|
:handle-links="false"
|
||||||
:emoji="emoji"
|
:emoji="emoji"
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="footer faint">
|
<div class="footer faint">
|
||||||
|
@ -171,9 +176,5 @@
|
||||||
padding: 0 0.5em;
|
padding: 0 0.5em;
|
||||||
margin-right: 0.5em;
|
margin-right: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.poll-checkbox {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
Loading…
Reference in New Issue