Various accessibility improvements
* Add announcement element with `aria-live` * Add skip to main content element Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
@@ -11,7 +11,7 @@
|
||||
)
|
||||
}}
|
||||
</p>
|
||||
<hr />
|
||||
<hr role="presentation" />
|
||||
<p class="content">
|
||||
<span>
|
||||
{{
|
||||
@@ -33,7 +33,7 @@
|
||||
"
|
||||
/>
|
||||
</p>
|
||||
<hr />
|
||||
<hr role="presentation" />
|
||||
<p class="content">
|
||||
{{
|
||||
$t(
|
||||
|
||||
@@ -137,6 +137,7 @@
|
||||
ref="commentEditor"
|
||||
v-model="newComment.text"
|
||||
mode="comment"
|
||||
:aria-label="$t('Comment body')"
|
||||
/>
|
||||
<b-button
|
||||
:disabled="newComment.text.trim().length === 0"
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
ref="commenteditor"
|
||||
mode="comment"
|
||||
v-model="newComment.text"
|
||||
:aria-label="$t('Comment body')"
|
||||
/>
|
||||
</p>
|
||||
<p class="help is-danger" v-if="emptyCommentError">
|
||||
@@ -30,9 +31,11 @@
|
||||
</p>
|
||||
</div>
|
||||
<div class="field notify-participants" v-if="isEventOrganiser">
|
||||
<b-switch v-model="newComment.isAnnouncement">{{
|
||||
$t("Notify participants")
|
||||
}}</b-switch>
|
||||
<b-switch
|
||||
aria-labelledby="notify-participants-toggle"
|
||||
v-model="newComment.isAnnouncement"
|
||||
>{{ $t("Notify participants") }}</b-switch
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -88,7 +88,7 @@
|
||||
{{ $t("[This comment has been deleted by it's author]") }}
|
||||
</div>
|
||||
<form v-else class="edition" @submit.prevent="updateComment">
|
||||
<editor v-model="updatedComment" />
|
||||
<editor v-model="updatedComment" :aria-label="$t('Comment body')" />
|
||||
<div class="buttons">
|
||||
<b-button
|
||||
native-type="submit"
|
||||
|
||||
@@ -227,6 +227,8 @@ export default class EditorComponent extends Vue {
|
||||
|
||||
@Prop({ required: false, default: 100_000_000 }) maxSize!: number;
|
||||
|
||||
@Prop({ required: false }) ariaLabel!: string;
|
||||
|
||||
currentActor!: IPerson;
|
||||
|
||||
editor: Editor | null = null;
|
||||
@@ -256,6 +258,13 @@ export default class EditorComponent extends Vue {
|
||||
|
||||
mounted(): void {
|
||||
this.editor = new Editor({
|
||||
editorProps: {
|
||||
attributes: {
|
||||
"aria-multiline": this.isShortMode.toString(),
|
||||
"aria-label": this.ariaLabel,
|
||||
role: "textbox",
|
||||
},
|
||||
},
|
||||
extensions: [
|
||||
StarterKit,
|
||||
Document,
|
||||
|
||||
@@ -103,9 +103,11 @@
|
||||
:active="copied !== false"
|
||||
always
|
||||
>
|
||||
<b-button @click="copyErrorToClipboard">{{
|
||||
$t("Copy details to clipboard")
|
||||
}}</b-button>
|
||||
<b-button
|
||||
@click="copyErrorToClipboard"
|
||||
@keyup.enter="copyErrorToClipboard"
|
||||
>{{ $t("Copy details to clipboard") }}</b-button
|
||||
>
|
||||
</b-tooltip>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
v-if="!gettingLocation"
|
||||
icon-right="target"
|
||||
@click="locateMe"
|
||||
@keyup.enter="locateMe"
|
||||
>{{ $t("Use my location") }}</b-button
|
||||
>
|
||||
<span v-else>{{ $t("Getting location") }}</span>
|
||||
|
||||
@@ -7,25 +7,15 @@
|
||||
<div class="address-wrapper">
|
||||
<span v-if="!physicalAddress">{{ $t("No address defined") }}</span>
|
||||
<div class="address" v-if="physicalAddress">
|
||||
<div>
|
||||
<address>
|
||||
<p
|
||||
class="addressDescription"
|
||||
:title="physicalAddress.poiInfos.name"
|
||||
>
|
||||
{{ physicalAddress.poiInfos.name }}
|
||||
</p>
|
||||
<p class="has-text-grey-dark">
|
||||
{{ physicalAddress.poiInfos.alternativeName }}
|
||||
</p>
|
||||
</address>
|
||||
</div>
|
||||
<span
|
||||
<address-info :address="physicalAddress" />
|
||||
<b-button
|
||||
type="is-text"
|
||||
class="map-show-button"
|
||||
@click="showMap = !showMap"
|
||||
v-if="physicalAddress.geom"
|
||||
>{{ $t("Show map") }}</span
|
||||
>
|
||||
{{ $t("Show map") }}
|
||||
</b-button>
|
||||
</div>
|
||||
</div>
|
||||
</event-metadata-block>
|
||||
|
||||
@@ -30,18 +30,22 @@ A button to set your participation
|
||||
position="is-bottom-left"
|
||||
v-if="participation && participation.role === ParticipantRole.PARTICIPANT"
|
||||
>
|
||||
<button class="button is-success is-large" type="button" slot="trigger">
|
||||
<b-icon icon="check" />
|
||||
<template>
|
||||
<span>{{ $t("I participate") }}</span>
|
||||
</template>
|
||||
<b-icon icon="menu-down" />
|
||||
</button>
|
||||
<template #trigger="{ active }">
|
||||
<b-button
|
||||
type="is-success"
|
||||
size="is-large"
|
||||
icon-left="check"
|
||||
:icon-right="active ? 'menu-up' : 'menu-down'"
|
||||
>
|
||||
{{ $t("I participate") }}
|
||||
</b-button>
|
||||
</template>
|
||||
|
||||
<b-dropdown-item
|
||||
:value="false"
|
||||
aria-role="listitem"
|
||||
@click="confirmLeave"
|
||||
@keyup.enter="confirmLeave"
|
||||
class="has-text-danger"
|
||||
>{{ $t("Cancel my participation…") }}</b-dropdown-item
|
||||
>
|
||||
@@ -73,6 +77,7 @@ A button to set your participation
|
||||
:value="false"
|
||||
aria-role="listitem"
|
||||
@click="confirmLeave"
|
||||
@keyup.enter="confirmLeave"
|
||||
class="has-text-danger"
|
||||
>{{ $t("Cancel my participation request…") }}</b-dropdown-item
|
||||
>
|
||||
@@ -101,17 +106,21 @@ A button to set your participation
|
||||
position="is-bottom-left"
|
||||
v-else-if="!participation && currentActor.id"
|
||||
>
|
||||
<button class="button is-primary is-large" type="button" slot="trigger">
|
||||
<template>
|
||||
<span>{{ $t("Participate") }}</span>
|
||||
</template>
|
||||
<b-icon icon="menu-down" />
|
||||
</button>
|
||||
<template #trigger="{ active }">
|
||||
<b-button
|
||||
type="is-primary"
|
||||
size="is-large"
|
||||
:icon-right="active ? 'menu-up' : 'menu-down'"
|
||||
>
|
||||
{{ $t("Participate") }}
|
||||
</b-button>
|
||||
</template>
|
||||
|
||||
<b-dropdown-item
|
||||
:value="true"
|
||||
aria-role="listitem"
|
||||
@click="joinEvent(currentActor)"
|
||||
@keyup.enter="joinEvent(currentActor)"
|
||||
>
|
||||
<div class="media">
|
||||
<div class="media-left">
|
||||
@@ -136,6 +145,7 @@ A button to set your participation
|
||||
:value="false"
|
||||
aria-role="listitem"
|
||||
@click="joinModal"
|
||||
@keyup.enter="joinModal"
|
||||
v-if="identities.length > 1"
|
||||
>{{ $t("with another identity…") }}</b-dropdown-item
|
||||
>
|
||||
|
||||
@@ -25,7 +25,12 @@
|
||||
v-model="locale"
|
||||
:placeholder="$t('Select a language')"
|
||||
>
|
||||
<option v-for="(language, lang) in langs" :value="lang" :key="lang">
|
||||
<option
|
||||
v-for="(language, lang) in langs"
|
||||
:value="lang"
|
||||
:key="lang"
|
||||
:selected="isLangSelected(lang)"
|
||||
>
|
||||
{{ language }}
|
||||
</option>
|
||||
</b-select>
|
||||
@@ -48,6 +53,9 @@
|
||||
{{ $t("License") }}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#navbar">{{ $t("Back to top") }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="content has-text-centered">
|
||||
<i18n
|
||||
@@ -101,6 +109,10 @@ export default class Footer extends Vue {
|
||||
this.locale = locale;
|
||||
}
|
||||
}
|
||||
|
||||
isLangSelected(lang: string): boolean {
|
||||
return lang === this.locale;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@@ -145,6 +157,13 @@ footer.footer {
|
||||
color: $white;
|
||||
text-decoration: underline;
|
||||
text-decoration-color: $secondary;
|
||||
|
||||
&:focus {
|
||||
background-color: #000;
|
||||
color: #fff;
|
||||
outline: 3px solid #000;
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep span.select {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<template>
|
||||
<b-navbar
|
||||
id="navbar"
|
||||
type="is-secondary"
|
||||
wrapper-class="container"
|
||||
:active.sync="mobileNavbarActive"
|
||||
@@ -58,6 +59,7 @@
|
||||
href="https://mediation.koena.net/framasoft/mobilizon/"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
hreflang="fr"
|
||||
>
|
||||
<img
|
||||
src="/img/koena-a11y.svg"
|
||||
@@ -75,6 +77,10 @@
|
||||
v-if="currentActor.id && currentUser.isLoggedIn"
|
||||
right
|
||||
collapsible
|
||||
ref="user-dropdown"
|
||||
tabindex="0"
|
||||
tag="span"
|
||||
@keyup.enter="toggleMenu"
|
||||
>
|
||||
<template
|
||||
slot="label"
|
||||
@@ -109,8 +115,11 @@
|
||||
v-else
|
||||
:active="identity.id === currentActor.id"
|
||||
:key="identity.id"
|
||||
tabindex="0"
|
||||
@click="setIdentity(identity)"
|
||||
@keyup.enter="setIdentity(identity)"
|
||||
>
|
||||
<span @click="setIdentity(identity)">
|
||||
<span>
|
||||
<div class="media-left">
|
||||
<figure class="image is-32x32" v-if="identity.avatar">
|
||||
<img
|
||||
@@ -131,7 +140,7 @@
|
||||
</div>
|
||||
</span>
|
||||
|
||||
<hr class="navbar-divider" />
|
||||
<hr class="navbar-divider" role="presentation" />
|
||||
</b-navbar-item>
|
||||
|
||||
<b-navbar-item
|
||||
@@ -146,8 +155,13 @@
|
||||
>{{ $t("Administration") }}</b-navbar-item
|
||||
>
|
||||
|
||||
<b-navbar-item tag="span">
|
||||
<span @click="logout">{{ $t("Log out") }}</span>
|
||||
<b-navbar-item
|
||||
tag="span"
|
||||
tabindex="0"
|
||||
@click="logout"
|
||||
@keyup.enter="logout"
|
||||
>
|
||||
<span>{{ $t("Log out") }}</span>
|
||||
</b-navbar-item>
|
||||
</b-navbar-dropdown>
|
||||
|
||||
|
||||
@@ -71,7 +71,13 @@ import { IParticipant } from "../../types/participant.model";
|
||||
import RouteName from "../../router/name";
|
||||
import { CONFIRM_PARTICIPATION } from "../../graphql/event";
|
||||
|
||||
@Component
|
||||
@Component({
|
||||
metaInfo() {
|
||||
return {
|
||||
title: this.$t("Confirm participation") as string,
|
||||
};
|
||||
},
|
||||
})
|
||||
export default class ConfirmParticipation extends Vue {
|
||||
@Prop({ type: String, required: true }) token!: string;
|
||||
|
||||
|
||||
@@ -28,6 +28,11 @@ import { IEvent } from "@/types/event.model";
|
||||
},
|
||||
},
|
||||
},
|
||||
metaInfo() {
|
||||
return {
|
||||
title: this.$t("Participation with account") as string,
|
||||
};
|
||||
},
|
||||
})
|
||||
export default class ParticipationWithAccount extends Vue {
|
||||
@Prop({ type: String, required: true }) uuid!: string;
|
||||
|
||||
@@ -155,6 +155,11 @@ import { ApolloCache, FetchResult } from "@apollo/client/core";
|
||||
},
|
||||
config: CONFIG,
|
||||
},
|
||||
metaInfo() {
|
||||
return {
|
||||
title: this.$t("Participation without account") as string,
|
||||
};
|
||||
},
|
||||
})
|
||||
export default class ParticipationWithoutAccount extends Vue {
|
||||
@Prop({ type: String, required: true }) uuid!: string;
|
||||
|
||||
@@ -130,6 +130,11 @@ import RouteName from "../../router/name";
|
||||
},
|
||||
config: CONFIG,
|
||||
},
|
||||
metaInfo() {
|
||||
return {
|
||||
title: this.$t("Unlogged participation") as string,
|
||||
};
|
||||
},
|
||||
})
|
||||
export default class UnloggedParticipation extends Vue {
|
||||
@Prop({ type: String, required: true }) uuid!: string;
|
||||
|
||||
@@ -38,7 +38,12 @@
|
||||
</span>
|
||||
</b-upload>
|
||||
</b-field>
|
||||
<b-button type="is-text" v-if="imageSrc" @click="removeOrClearPicture">
|
||||
<b-button
|
||||
type="is-text"
|
||||
v-if="imageSrc"
|
||||
@click="removeOrClearPicture"
|
||||
@keyup.enter="removeOrClearPicture"
|
||||
>
|
||||
{{ $t("Clear") }}
|
||||
</b-button>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user