Skip to content
This repository has been archived by the owner on May 24, 2021. It is now read-only.

Commit

Permalink
Merge pull request #645 from alexander-heimbuch/feature/accessibility
Browse files Browse the repository at this point in the history
feat(accessibility): Improves accessibility
  • Loading branch information
alexander-heimbuch committed Jun 2, 2018
2 parents 4e9dc00 + 76b1cc9 commit 224e8b6
Show file tree
Hide file tree
Showing 45 changed files with 748 additions and 290 deletions.
2 changes: 1 addition & 1 deletion cypress/selectors/tabs/share.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ module.exports = cy => ({
'google-plus': () => cy.get(`#tab-share--channels--google-plus a`),
mail: () => cy.get(`#tab-share--channels--mail a`),
pinterest: () => cy.get(`#tab-share--channels--pinterest a`),
embed: () => cy.get(`#tab-share--channels--embed a`)
embed: () => cy.get(`#tab-share--channels--embed button`)
},
overlay: {
modal: () => cy.get('#share-tab--share-overlay'),
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
"dist/"
],
"dependencies": {
"@podlove/html5-audio-driver": "1.1.1",
"@podlove/html5-audio-driver": "1.1.2",
"babel-polyfill": "6.26.0",
"binary-search": "1.3.3",
"color": "3.0.0",
Expand Down
20 changes: 16 additions & 4 deletions src/components/header/Info.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<div class="info" id="header-info" v-if="hasPoster || hasShowTitle || hasEpisodeTitle || hasDescription">
<div class="poster" v-if="hasPoster" id="header-poster">
<div class="poster-container" :style="posterStyle">
<img class="poster-image" :src="episode.poster || show.poster" @error="onImageLoad">
<img class="poster-image" :src="episode.poster || show.poster" :alt="alternativeText" @error="onImageLoad">
</div>
</div>
<div class="description">
Expand All @@ -14,7 +14,7 @@
<a :href="episode.link" target="_blank" v-if="episode.link">{{ episode.title }}</a>
<span v-else>{{ episode.title }}</span>
</h1>
<div class="subtitle" :style="subtitleStyle" v-if="hasDescription" id="header-subtitle">{{ episode.subtitle }}</div>
<h3 class="subtitle" :style="subtitleStyle" v-if="hasDescription" id="header-subtitle">{{ episode.subtitle }}</h3>
</div>
</div>
</template>
Expand Down Expand Up @@ -62,6 +62,15 @@
},
hasDescription () {
return this.episode.subtitle && this.visibleComponents.subtitle
},
alternativeText () {
if (this.episode.poster) {
return this.$t('A11Y.ALT_EPISODE_COVER')
}
if (this.show.poster) {
return this.$t('A11Y.ALT_SHOW_COVER')
}
}
},
methods: {
Expand Down Expand Up @@ -103,7 +112,7 @@
.title {
margin-top: 0;
margin-bottom: $margin / 3;
margin-bottom: $margin / 4;
font-weight: inherit;
font-size: 1.8em;
Expand Down Expand Up @@ -132,7 +141,10 @@
.subtitle {
overflow: hidden;
height: 1.5 * 2em;
margin: 0;
height: 2.75em;
line-height: 1.3em;
font-weight: 100;
}
}
Expand Down
26 changes: 23 additions & 3 deletions src/components/player/control-bar/ChapterBackButton.vue
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
<template>
<button class="control-button" @click="onButtonClick()" :disabled="playtime === 0" id="control-bar--chapter-back-button">
<chapter-back-icon :color="theme.player.actions.background"></chapter-back-icon>
<button class="control-button" @click="onButtonClick()" :disabled="isDisabled" id="control-bar--chapter-back-button">
<chapter-back-icon :color="theme.player.actions.background" aria-hidden="true"></chapter-back-icon>
<span class="visually-hidden">{{ a11y }}</span>
</button>
</template>

<script>
import { currentChapter, currentChapterIndex } from 'utils/chapters'
import { currentChapter, currentChapterIndex, previousChapter } from 'utils/chapters'
import store from 'store'
import ChapterBackIcon from 'icons/ChapterBackIcon'
Expand All @@ -21,6 +22,25 @@
playtime: this.$select('playtime')
}
},
computed: {
a11y () {
const chapter = currentChapter(this.chapters)
if (chapter.index === 1) {
return this.$t('A11Y.PLAYER_CHAPTER_CURRENT', { ...chapter })
}
if (this.playtime - chapter.start < 2000) {
return this.$t('A11Y.PLAYER_CHAPTER_PREVIOUS', { ...previousChapter(this.chapters) })
}
return this.$t('A11Y.PLAYER_CHAPTER_CURRENT', { ...chapter })
},
isDisabled () {
return this.playtime === 0
}
},
methods: {
onButtonClick () {
const current = currentChapter(this.chapters)
Expand Down
19 changes: 17 additions & 2 deletions src/components/player/control-bar/ChapterNextButton.vue
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
<template>
<button class="control-button" @click="onButtonClick()" :disabled="playtime === duration" id="control-bar--chapter-next-button">
<chapter-next-icon :color="theme.player.actions.background"></chapter-next-icon>
<button class="control-button" @click="onButtonClick()" :disabled="isDisabled" id="control-bar--chapter-next-button">
<chapter-next-icon :color="theme.player.actions.background" aria-hidden="true"></chapter-next-icon>
<span class="visually-hidden">{{ a11y }}</span>
</button>
</template>

<script>
import store from 'store'
import ChapterNextIcon from 'icons/ChapterNextIcon'
import { nextChapter, currentChapter } from 'utils/chapters'
export default {
components: {
ChapterNextIcon
Expand All @@ -20,6 +23,18 @@
duration: this.$select('duration')
}
},
computed: {
a11y () {
if (currentChapter(this.chapters).index === this.chapters.length) {
return this.$t('A11Y.PLAYER_CHAPTER_END')
}
return this.$t('A11Y.PLAYER_CHAPTER_NEXT', { ...nextChapter(this.chapters) })
},
isDisabled () {
return this.playtime === this.duration
}
},
methods: {
onButtonClick () {
store.dispatch(store.actions.nextChapter())
Expand Down
43 changes: 34 additions & 9 deletions src/components/player/control-bar/PlayButton.vue
Original file line number Diff line number Diff line change
@@ -1,46 +1,49 @@
<template>
<button class="control-button" @click="onButtonClick()" id="control-bar--play-button">
<button class="control-button" @click="onButtonClick()" id="control-bar--play-button" ref="playbutton">
<span class="play-button" :style="wrapperStyle" :class="{
wide: components.controls.button.loading ||
components.controls.button.remaining ||
components.controls.button.duration ||
components.controls.button.replay ||
components.controls.button.retry
}">
<span class="inner" v-if="components.controls.button.loading" id="control-bar--play-button--loading">
<span class="inner" v-if="components.controls.button.loading" id="control-bar--play-button--loading" aria-hidden="true">
<loading-indicator></loading-indicator>
</span>

<pause-icon :color="theme.player.actions.icon" v-if="components.controls.button.playing" id="control-bar--play-button--pause"></pause-icon>
<pause-icon :color="theme.player.actions.icon" v-if="components.controls.button.playing" id="control-bar--play-button--pause" aria-hidden="true"></pause-icon>

<play-icon size="21" :color="theme.player.actions.icon" class="reset" v-if="components.controls.button.pause" id="control-bar--play-button--play"></play-icon>
<play-icon size="21" :color="theme.player.actions.icon" class="reset" v-if="components.controls.button.pause" id="control-bar--play-button--play" aria-hidden="true"></play-icon>

<span class="inner" v-if="components.controls.button.remaining" id="control-bar--play-button--remaining">
<span class="inner" v-if="components.controls.button.remaining" id="control-bar--play-button--remaining" aria-hidden="true">
<play-icon size="21" :color="theme.player.actions.icon"></play-icon>
<span class="label" :style="textStyle">{{ fromPlayerTime(playtime) }}</span>
</span>

<span class="inner" v-if="components.controls.button.duration" id="control-bar--play-button--duration">
<span class="inner" v-if="components.controls.button.duration" id="control-bar--play-button--duration" aria-hidden="true">
<play-icon size="21" :color="theme.player.actions.icon"></play-icon>
<span class="label" :style="textStyle">{{ fromPlayerTime(duration) }}</span>
</span>

<span class="inner" v-if="components.controls.button.replay" id="control-bar--play-button--replay">
<span class="inner" v-if="components.controls.button.replay" id="control-bar--play-button--replay" aria-hidden="true">
<play-icon size="21" :color="theme.player.actions.icon"></play-icon>
<span class="label truncate" :style="textStyle">{{ $t('PLAYER.REPLAY') }}</span>
</span>

<span class="inner" v-if="components.controls.button.retry" id="control-bar--play-button--retry">
<span class="inner" v-if="components.controls.button.retry" id="control-bar--play-button--retry" aria-hidden="true">
<reload-icon :color="theme.player.actions.icon"></reload-icon>
<span class="label truncate" :style="textStyle">{{ $t('PLAYER.RETRY') }}</span>
</span>
</span>

<!-- Accessibility -->
<span class="visually-hidden">{{ a11y }}</span>
</button>
</template>

<script>
import store from 'store'
import { fromPlayerTime } from 'utils/time'
import { fromPlayerTime, calcSeconds, calcMinutes, calcHours } from 'utils/time'
import PlayIcon from 'icons/PlayIcon'
import PauseIcon from 'icons/PauseIcon'
Expand Down Expand Up @@ -76,6 +79,27 @@
return {
color: this.theme.player.actions.icon
}
},
a11y () {
switch (this.playstate) {
case 'start':
return this.$t('A11Y.PLAYER_START', {
hours: calcHours(this.duration),
minutes: calcMinutes(this.duration),
seconds: calcSeconds(this.duration)
})
case 'idle':
case 'pause':
return this.$t('A11Y.PLAYER_PLAY')
case 'end':
return this.$t('A11Y.PLAYER_RESTART')
case 'loading':
return this.$t('A11Y.PLAYER_LOADING')
case 'error':
return this.$t('A11Y.PLAYER_ERROR')
default:
return this.$t('A11Y.PLAYER_PAUSE')
}
}
},
methods: {
Expand All @@ -96,6 +120,7 @@
break
default:
store.dispatch(store.actions.pause())
break
}
}
}
Expand Down
5 changes: 2 additions & 3 deletions src/components/player/control-bar/StepBackButton.vue
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
<template>
<button class="control-button" :class="playstate" @click="onButtonClick()" :disabled="isDisabled(playtime)" id="control-bar--step-back-button">
<StepBackIcon
:color="theme.player.actions.background"
></StepBackIcon>
<StepBackIcon :color="theme.player.actions.background" aria-hidden="true"></StepBackIcon>
<span class="visually-hidden">{{ $t('A11Y.PLAYER_STEPPER_BACK', { seconds: 15 }) }}</span>
</button>
</template>

Expand Down
3 changes: 2 additions & 1 deletion src/components/player/control-bar/StepForwardButton.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<template>
<button class="control-button" :class="playstate" @click="onButtonClick()" :disabled="isDisabled(playtime, duration)" id="control-bar--step-forward-button">
<step-forward-icon :color="theme.player.actions.background"></step-forward-icon>
<step-forward-icon :color="theme.player.actions.background" aria-hidden="true"></step-forward-icon>
<span class="visually-hidden">{{ $t('A11Y.PLAYER_STEPPER_FORWARD', { seconds: 30 }) }}</span>
</button>
</template>

Expand Down
6 changes: 5 additions & 1 deletion src/components/player/progress-bar/CurrentChapter.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<div class="timer-chapter truncate" id="progress-bar--current-chapter">
<span class="chapter-title"
<span class="chapter-title" :aria-label="a11y" tabindex="0"
:style="chapterStyle"
v-if="currentChapterIndex(chapters) > -1">
{{chapterTitle}}
Expand Down Expand Up @@ -37,6 +37,10 @@
}
return get(current, 'title', '')
},
a11y () {
return this.$t('A11Y.TIMER_CHAPTER', { ...currentChapter(this.chapters) })
}
},
methods: {
Expand Down
2 changes: 2 additions & 0 deletions src/components/player/progress-bar/Progress.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@
@input="onInput"
@mousemove="onMouseMove"
@mouseout="onMouseOut"
:title="$t('A11Y.PROGRESSBAR_INPUT')"
>
<input v-else
type="range"
min="0" :max="interpolate(duration)"
:value="interpolate(playtime)"
@change="onChange"
@input="onInput"
:title="$t('A11Y.PROGRESSBAR_INPUT')"
>
<span class="progress-range" :style="rangeStyle"></span>
<span class="progress-buffer" v-for="(buffering, index) in buffer" :style="bufferStyle(buffering)" :key="`buffer-${index}`"></span>
Expand Down
12 changes: 9 additions & 3 deletions src/components/player/progress-bar/Timer.vue
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
<template>
<div class="timer-progress" :class="playstate" :style="timerStyle">
<span class="current" id="progress-bar--timer-current">{{ fromPlayerTime(ghost.active ? ghost.time : playtime) }}</span>
<span class="current" id="progress-bar--timer-current" :aria-label="a11y.current" tabindex="0">{{ fromPlayerTime(ghost.active ? ghost.time : playtime) }}</span>
<current-chapter class="chapter"></current-chapter>
<span class="time" id="progress-bar--timer-left">-{{ fromPlayerTime(duration - (ghost.active ? ghost.time : playtime)) }}</span>
<span class="time" id="progress-bar--timer-left" :aria-label="a11y.left" tabindex="0">-{{ fromPlayerTime(duration - (ghost.active ? ghost.time : playtime)) }}</span>
</div>
</template>

<script>
import color from 'color'
import { fromPlayerTime } from 'utils/time'
import { fromPlayerTime, calcHours, calcMinutes, calcSeconds } from 'utils/time'
import CurrentChapter from './CurrentChapter'
export default {
Expand All @@ -28,6 +28,12 @@ export default {
return {
color: color(this.theme.player.timer.text).fade(0.5)
}
},
a11y () {
return {
current: this.$t('A11Y.TIMER_CURRENT', { hours: calcHours(this.playtime), minutes: calcMinutes(this.playtime), seconds: calcSeconds(this.playtime) }),
left: this.$t('A11Y.TIMER_LEFT', { hours: calcHours(this.duration - this.playtime), minutes: calcMinutes(this.duration - this.playtime), seconds: calcSeconds(this.duration - this.playtime) })
}
}
},
methods: {
Expand Down
16 changes: 12 additions & 4 deletions src/components/shared/Overlay.vue
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
<template>
<div class="overlay-container" :class="{open: visible}">
<div class="overlay" :style="backgroundStyle">
<div class="overlay-inner">
<div class="overlay-inner" tabindex="0" ref="overlay" :aria-label="title">
<div class="overlay-header">
<slot name="header"></slot>
<button class="overlay-close" @click="onClose()"><close-icon></close-icon></button>
<button class="overlay-close" @click="onClose()">
<close-icon aria-hidden="true"></close-icon>
<span class="visually-hidden">{{ $t('A11Y.OVERLAY_CLOSE') }}</span>
</button>
</div>
<div class="overlay-body">
<slot></slot>
Expand All @@ -15,11 +18,11 @@
</template>

<script>
import ButtonComponent from './Button'
import CloseIcon from 'icons/CloseIcon'
import ButtonComponent from './Button'
export default {
props: ['visible', 'onClose'],
props: ['visible', 'onClose', 'title'],
data () {
return {
theme: this.$select('theme')
Expand All @@ -32,6 +35,11 @@
}
}
},
watch: {
visible () {
this.$refs.overlay && this.$refs.overlay.focus()
}
},
components: {
CloseIcon,
ButtonComponent
Expand Down
6 changes: 3 additions & 3 deletions src/components/shared/TabBody.vue
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<template>
<div class="tab-body" :class="{active}" :style="display === 'native' ? bodyStyle : {}">
<slot></slot>
<div class="tab-body" :class="{active}" :style="display === 'native' ? bodyStyle : {}" role="tabpanel" :aria-labelledby="`trigger-${name}`" tabindex="0" :aria-hidden="!active">
<slot tabindex="0"></slot>
</div>
</template>
<script>
export default {
props: ['active'],
props: ['active', 'name', 'index'],
data () {
return {
theme: this.$select('theme'),
Expand Down
2 changes: 1 addition & 1 deletion src/components/shared/TabHeader.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<ul class="tab-header" :class="{ overflows }" v-resize="resizeHandler">
<ul class="tab-header" :class="{ overflows }" v-resize="resizeHandler" role="tablist">
<span class="header-shadow" :style="headerShadowStyle"></span>
<slot></slot>
</ul>
Expand Down
Loading

0 comments on commit 224e8b6

Please sign in to comment.