Fix #612: Improved accessibility by using main/section/nav tags and aria-labels in most critical places

This commit is contained in:
Eliot Berriot 2018-11-19 23:33:22 +01:00
parent 9005ebbd6d
commit 29171853b3
No known key found for this signature in database
GPG key ID: DD6965E2476E5C27
42 changed files with 1266 additions and 1122 deletions

View file

@ -1,5 +1,5 @@
<template>
<div class="ui inverted segment player-wrapper" :style="style">
<section class="ui inverted segment player-wrapper" :aria-label="labels.audioPlayer" :style="style">
<div class="player">
<audio-track
ref="currentAudio"
@ -213,18 +213,18 @@
@keydown.s.prevent.exact="shuffle"
/>
</div>
</div>
</section>
</template>
<script>
import {mapState, mapGetters, mapActions} from 'vuex'
import GlobalEvents from '@/components/utils/global-events'
import ColorThief from '@/vendor/color-thief'
import {Howl} from 'howler'
import { mapState, mapGetters, mapActions } from "vuex"
import GlobalEvents from "@/components/utils/global-events"
import ColorThief from "@/vendor/color-thief"
import { Howl } from "howler"
import AudioTrack from '@/components/audio/Track'
import TrackFavoriteIcon from '@/components/favorites/TrackFavoriteIcon'
import TrackPlaylistIcon from '@/components/playlists/TrackPlaylistIcon'
import AudioTrack from "@/components/audio/Track"
import TrackFavoriteIcon from "@/components/favorites/TrackFavoriteIcon"
import TrackPlaylistIcon from "@/components/playlists/TrackPlaylistIcon"
export default {
components: {
@ -233,8 +233,13 @@ export default {
GlobalEvents,
AudioTrack
},
data () {
let defaultAmbiantColors = [[46, 46, 46], [46, 46, 46], [46, 46, 46], [46, 46, 46]]
data() {
let defaultAmbiantColors = [
[46, 46, 46],
[46, 46, 46],
[46, 46, 46],
[46, 46, 46]
]
return {
isShuffling: false,
sliderVolume: this.volume,
@ -245,7 +250,7 @@ export default {
dummyAudio: null
}
},
mounted () {
mounted() {
// we trigger the watcher explicitely it does not work otherwise
this.sliderVolume = this.volume
// this is needed to unlock audio playing under some browsers,
@ -254,57 +259,57 @@ export default {
this.dummyAudio = new Howl({
preload: false,
autoplay: false,
src: ['noop.webm', 'noop.mp3']
src: ["noop.webm", "noop.mp3"]
})
},
destroyed () {
destroyed() {
this.dummyAudio.unload()
},
methods: {
...mapActions({
togglePlay: 'player/togglePlay',
mute: 'player/mute',
unmute: 'player/unmute',
clean: 'queue/clean',
updateProgress: 'player/updateProgress'
togglePlay: "player/togglePlay",
mute: "player/mute",
unmute: "player/unmute",
clean: "queue/clean",
updateProgress: "player/updateProgress"
}),
shuffle () {
shuffle() {
let disabled = this.queue.tracks.length === 0
if (this.isShuffling || disabled) {
return
}
let self = this
let msg = this.$gettext('Queue shuffled!')
let msg = this.$gettext("Queue shuffled!")
this.isShuffling = true
setTimeout(() => {
self.$store.dispatch('queue/shuffle', () => {
self.$store.dispatch("queue/shuffle", () => {
self.isShuffling = false
self.$store.commit('ui/addMessage', {
self.$store.commit("ui/addMessage", {
content: msg,
date: new Date()
})
})
}, 100)
},
next () {
next() {
let self = this
this.$store.dispatch('queue/next').then(() => {
self.$emit('next')
this.$store.dispatch("queue/next").then(() => {
self.$emit("next")
})
},
previous () {
previous() {
let self = this
this.$store.dispatch('queue/previous').then(() => {
self.$emit('previous')
this.$store.dispatch("queue/previous").then(() => {
self.$emit("previous")
})
},
touchProgress (e) {
touchProgress(e) {
let time
let target = this.$refs.progress
time = e.layerX / target.offsetWidth * this.duration
time = (e.layerX / target.offsetWidth) * this.duration
this.$refs.currentAudio.setCurrentTime(time)
},
updateBackground () {
updateBackground() {
if (!this.currentTrack.album.cover) {
this.ambiantColors = this.defaultAmbiantColors
return
@ -312,9 +317,9 @@ export default {
let image = this.$refs.cover
this.ambiantColors = ColorThief.prototype.getPalette(image, 4).slice(0, 4)
},
handleError ({sound, error}) {
this.$store.commit('player/isLoadingAudio', false)
this.$store.dispatch('player/trackErrored')
handleError({ sound, error }) {
this.$store.commit("player/isLoadingAudio", false)
this.$store.dispatch("player/trackErrored")
}
},
computed: {
@ -330,26 +335,34 @@ export default {
queue: state => state.queue
}),
...mapGetters({
currentTrack: 'queue/currentTrack',
hasNext: 'queue/hasNext',
emptyQueue: 'queue/isEmpty',
durationFormatted: 'player/durationFormatted',
currentTimeFormatted: 'player/currentTimeFormatted',
progress: 'player/progress'
currentTrack: "queue/currentTrack",
hasNext: "queue/hasNext",
emptyQueue: "queue/isEmpty",
durationFormatted: "player/durationFormatted",
currentTimeFormatted: "player/currentTimeFormatted",
progress: "player/progress"
}),
labels () {
let previousTrack = this.$gettext('Previous track')
let play = this.$gettext('Play track')
let pause = this.$gettext('Pause track')
let next = this.$gettext('Next track')
let unmute = this.$gettext('Unmute')
let mute = this.$gettext('Mute')
let loopingDisabled = this.$gettext('Looping disabled. Click to switch to single-track looping.')
let loopingSingle = this.$gettext('Looping on a single track. Click to switch to whole queue looping.')
let loopingWhole = this.$gettext('Looping on whole queue. Click to disable looping.')
let shuffle = this.$gettext('Shuffle your queue')
let clear = this.$gettext('Clear your queue')
labels() {
let audioPlayer = this.$gettext("Media player")
let previousTrack = this.$gettext("Previous track")
let play = this.$gettext("Play track")
let pause = this.$gettext("Pause track")
let next = this.$gettext("Next track")
let unmute = this.$gettext("Unmute")
let mute = this.$gettext("Mute")
let loopingDisabled = this.$gettext(
"Looping disabled. Click to switch to single-track looping."
)
let loopingSingle = this.$gettext(
"Looping on a single track. Click to switch to whole queue looping."
)
let loopingWhole = this.$gettext(
"Looping on whole queue. Click to disable looping."
)
let shuffle = this.$gettext("Shuffle your queue")
let clear = this.$gettext("Clear your queue")
return {
audioPlayer,
previousTrack,
play,
pause,
@ -363,29 +376,35 @@ export default {
clear
}
},
style: function () {
style: function() {
let style = {
'background': this.ambiantGradiant
background: this.ambiantGradiant
}
return style
},
ambiantGradiant: function () {
ambiantGradiant: function() {
let indexConf = [
{orientation: 330, percent: 100, opacity: 0.7},
{orientation: 240, percent: 90, opacity: 0.7},
{orientation: 150, percent: 80, opacity: 0.7},
{orientation: 60, percent: 70, opacity: 0.7}
{ orientation: 330, percent: 100, opacity: 0.7 },
{ orientation: 240, percent: 90, opacity: 0.7 },
{ orientation: 150, percent: 80, opacity: 0.7 },
{ orientation: 60, percent: 70, opacity: 0.7 }
]
let gradients = this.ambiantColors.map((e, i) => {
let [r, g, b] = e
let conf = indexConf[i]
return `linear-gradient(${conf.orientation}deg, rgba(${r}, ${g}, ${b}, ${conf.opacity}) 10%, rgba(255, 255, 255, 0) ${conf.percent}%)`
}).join(', ')
let gradients = this.ambiantColors
.map((e, i) => {
let [r, g, b] = e
let conf = indexConf[i]
return `linear-gradient(${
conf.orientation
}deg, rgba(${r}, ${g}, ${b}, ${
conf.opacity
}) 10%, rgba(255, 255, 255, 0) ${conf.percent}%)`
})
.join(", ")
return gradients
}
},
watch: {
currentTrack (newValue, oldValue) {
currentTrack(newValue, oldValue) {
if (!this.isShuffling && newValue != oldValue) {
this.audioKey = String(new Date())
}
@ -393,11 +412,11 @@ export default {
this.ambiantColors = this.defaultAmbiantColors
}
},
volume (newValue) {
volume(newValue) {
this.sliderVolume = newValue
},
sliderVolume (newValue) {
this.$store.commit('player/volume', newValue)
sliderVolume(newValue) {
this.$store.commit("player/volume", newValue)
}
}
}
@ -405,7 +424,6 @@ export default {
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss">
.ui.progress {
margin: 0.5rem 0 1rem;
}
@ -423,18 +441,21 @@ export default {
.ui.item {
.meta {
font-size: 90%;
line-height: 1.2
line-height: 1.2;
}
}
.timer.total {
text-align: right;
text-align: right;
}
.timer.start {
cursor: pointer
cursor: pointer;
}
.track-area {
margin-top: 0;
.header, .meta, .artist, .album {
.header,
.meta,
.artist,
.album {
color: white !important;
}
}
@ -468,57 +489,57 @@ export default {
left: 25%;
cursor: pointer;
}
input[type=range]:focus {
input[type="range"]:focus {
outline: none;
}
input[type=range]::-webkit-slider-runnable-track {
input[type="range"]::-webkit-slider-runnable-track {
cursor: pointer;
}
input[type=range]::-webkit-slider-thumb {
input[type="range"]::-webkit-slider-thumb {
background: white;
cursor: pointer;
-webkit-appearance: none;
border-radius: 3px;
width: 10px;
}
input[type=range]::-moz-range-track {
input[type="range"]::-moz-range-track {
cursor: pointer;
background: white;
opacity: 0.3;
}
input[type=range]::-moz-focus-outer {
input[type="range"]::-moz-focus-outer {
border: 0;
}
input[type=range]::-moz-range-thumb {
input[type="range"]::-moz-range-thumb {
background: white;
cursor: pointer;
border-radius: 3px;
width: 10px;
}
input[type=range]::-ms-track {
input[type="range"]::-ms-track {
cursor: pointer;
background: transparent;
border-color: transparent;
color: transparent;
}
input[type=range]::-ms-fill-lower {
input[type="range"]::-ms-fill-lower {
background: white;
opacity: 0.3;
}
input[type=range]::-ms-fill-upper {
input[type="range"]::-ms-fill-upper {
background: white;
opacity: 0.3;
}
input[type=range]::-ms-thumb {
input[type="range"]::-ms-thumb {
background: white;
cursor: pointer;
border-radius: 3px;
width: 10px;
}
input[type=range]:focus::-ms-fill-lower {
input[type="range"]:focus::-ms-fill-lower {
background: white;
}
input[type=range]:focus::-ms-fill-upper {
input[type="range"]:focus::-ms-fill-upper {
background: white;
}
}
@ -545,14 +566,13 @@ export default {
margin: 0;
}
@keyframes MOVE-BG {
from {
transform: translateX(0px);
}
to {
transform: translateX(46px);
}
from {
transform: translateX(0px);
}
to {
transform: translateX(46px);
}
}
.indicating.progress {
@ -565,7 +585,7 @@ export default {
.ui.inverted.progress .buffer.bar {
position: absolute;
background-color:rgba(255, 255, 255, 0.15);
background-color: rgba(255, 255, 255, 0.15);
}
.indicating.progress .bar {
left: -46px;
@ -576,12 +596,12 @@ export default {
grey 1px,
grey 10px,
transparent 10px,
transparent 20px,
) !important;
transparent 20px
) !important;
animation-name: MOVE-BG;
animation-duration: 2s;
animation-timing-function: linear;
animation-iteration-count: infinite;
animation-duration: 2s;
animation-timing-function: linear;
animation-iteration-count: infinite;
}
</style>