From ded35e43a04cf01c94f4b30f9c0b9f58d2ba6db2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20V=C3=A1gner?= Date: Tue, 2 Oct 2018 13:55:24 +0200 Subject: [PATCH 1/3] A11y: repurpose more divs into AccessibleButtons. With this more of the controls that look like buttons can be operated via the keyboard and navigated to by screen reader users. This includes editor buttons such as File upload, Audio / Video call, Right pannel hide button, Jump to the bottom timeline button, and some more buttons found in the user settings. Also I have added alt texts to some images that in turn label buttons which these happen to be packed in and removed some untranslated alt texts from decorative non-actionable images that might add more verbosity when talking about screen reader user experience. --- src/components/structures/RightPanel.js | 7 +++-- src/components/structures/RoomStatusBar.js | 11 +++++--- src/components/structures/UserSettings.js | 28 +++++++++---------- src/components/views/elements/AppWarning.js | 2 +- src/components/views/globals/CookieBar.js | 4 +-- src/components/views/globals/MatrixToolbar.js | 4 +-- src/components/views/globals/NewVersionBar.js | 2 +- .../views/globals/PasswordNagBar.js | 2 +- .../views/globals/UpdateCheckBar.js | 6 ++-- src/components/views/rooms/AppsDrawer.js | 7 ++--- src/components/views/rooms/MemberInfo.js | 2 +- src/components/views/rooms/MessageComposer.js | 23 +++++++-------- src/components/views/settings/DevicesPanel.js | 5 ++-- src/components/views/voip/CallView.js | 5 ++-- 14 files changed, 57 insertions(+), 51 deletions(-) diff --git a/src/components/structures/RightPanel.js b/src/components/structures/RightPanel.js index 86870718e8e..9017447a343 100644 --- a/src/components/structures/RightPanel.js +++ b/src/components/structures/RightPanel.js @@ -51,6 +51,7 @@ class HeaderButton extends React.Component { return @@ -345,11 +346,11 @@ module.exports = React.createClass({ // being put in the RoomHeader or GroupView header, so only show the minimise // button on these 2 screens or you won't be able to re-expand the panel. headerButtons.push( -
- -
, + +
, ); } diff --git a/src/components/structures/RoomStatusBar.js b/src/components/structures/RoomStatusBar.js index fec59aadd57..4f9ac153f5e 100644 --- a/src/components/structures/RoomStatusBar.js +++ b/src/components/structures/RoomStatusBar.js @@ -223,14 +223,15 @@ module.exports = React.createClass({ ); } + const AccessibleButton = sdk.getComponent("elements.AccessibleButton"); if (!this.props.atEndOfLiveTimeline) { return ( -
{_t("Scroll -
+ ); } @@ -385,7 +386,7 @@ module.exports = React.createClass({ } return
- {_t("Warning")} +
{ title } @@ -485,7 +486,9 @@ module.exports = React.createClass({
{ indicator }
- { content } +
+ { content } +
); }, diff --git a/src/components/structures/UserSettings.js b/src/components/structures/UserSettings.js index 68009a74a87..7b79eebbb66 100644 --- a/src/components/structures/UserSettings.js +++ b/src/components/structures/UserSettings.js @@ -831,9 +831,9 @@ module.exports = React.createClass({
{ _t('Privacy is important to us, so we don\'t collect any personal' + ' or identifiable data for our analytics.') } -
+ { _t('Learn more about how we use analytics.') } -
+ { ANALYTICS_SETTINGS.map( this._renderDeviceSetting ) }
; @@ -1065,9 +1065,9 @@ module.exports = React.createClass({ _renderWebRtcDeviceSettings: function() { if (this.state.mediaDevices === false) { return ( -

+ { _t('Missing Media Permissions, click here to request.') } -

+ ); } else if (!this.state.mediaDevices) return; @@ -1233,10 +1233,10 @@ module.exports = React.createClass({ value={this.presentableTextForThreepid(val)} disabled /> -
+ {_t("Remove")} -
+ ); }); @@ -1258,9 +1258,9 @@ module.exports = React.createClass({ blurToCancel={false} onValueChanged={this._onAddEmailEditFinished} /> -
+ {_t("Add")} -
+ ); } @@ -1328,25 +1328,25 @@ module.exports = React.createClass({
-
+ {_t("Remove -
+
-
+ -
+
@@ -1395,11 +1395,11 @@ module.exports = React.createClass({
{ _t('Access Token:') + ' ' } - <{ _t("click to reveal") }> - +
{ _t("Homeserver is") } { MatrixClientPeg.get().getHomeserverUrl() } diff --git a/src/components/views/elements/AppWarning.js b/src/components/views/elements/AppWarning.js index f4015ae5b70..60809f5ca1c 100644 --- a/src/components/views/elements/AppWarning.js +++ b/src/components/views/elements/AppWarning.js @@ -6,7 +6,7 @@ const AppWarning = (props) => { return (
- {_t('Warning!')} +
{ props.errorMsg } diff --git a/src/components/views/globals/CookieBar.js b/src/components/views/globals/CookieBar.js index a63a163dd15..3dc618edf5c 100644 --- a/src/components/views/globals/CookieBar.js +++ b/src/components/views/globals/CookieBar.js @@ -51,7 +51,7 @@ export default class CookieBar extends React.Component { const toolbarClasses = "mx_MatrixToolbar"; return (
- Warning +
{ this.props.policyUrl ? _t( "Please help improve Riot.im by sending anonymous usage data. " + @@ -95,7 +95,7 @@ export default class CookieBar extends React.Component { { _t("Yes, I want to help!") } - + {_t('Close')}/
); diff --git a/src/components/views/globals/MatrixToolbar.js b/src/components/views/globals/MatrixToolbar.js index f85a30bcdfb..45feede5a08 100644 --- a/src/components/views/globals/MatrixToolbar.js +++ b/src/components/views/globals/MatrixToolbar.js @@ -35,11 +35,11 @@ module.exports = React.createClass({ render: function() { return (
- Warning +
{ _t('You are not receiving desktop notifications') } { _t('Enable them now') }
- + {_t('Close')}/
); }, diff --git a/src/components/views/globals/NewVersionBar.js b/src/components/views/globals/NewVersionBar.js index 527df5f8641..1bd0bde5263 100644 --- a/src/components/views/globals/NewVersionBar.js +++ b/src/components/views/globals/NewVersionBar.js @@ -96,7 +96,7 @@ export default React.createClass({ } return (
- Warning +
{_t("A new version of Riot is available.")}
diff --git a/src/components/views/globals/PasswordNagBar.js b/src/components/views/globals/PasswordNagBar.js index 4233363b954..5e3da3ad6d8 100644 --- a/src/components/views/globals/PasswordNagBar.js +++ b/src/components/views/globals/PasswordNagBar.js @@ -34,7 +34,7 @@ export default React.createClass({ src="img/warning.svg" width="24" height="23" - alt="Warning" + alt="" />
{ _t( diff --git a/src/components/views/globals/UpdateCheckBar.js b/src/components/views/globals/UpdateCheckBar.js index 53801311d8c..e499ddab314 100644 --- a/src/components/views/globals/UpdateCheckBar.js +++ b/src/components/views/globals/UpdateCheckBar.js @@ -71,9 +71,9 @@ export default React.createClass({ let image; if (doneStatuses.includes(this.props.status)) { - image = {warning}/; + image = ; } else { - image = {message}/; + image = ; } return ( @@ -83,7 +83,7 @@ export default React.createClass({ {message}
- + {_t('Close')}/
); diff --git a/src/components/views/rooms/AppsDrawer.js b/src/components/views/rooms/AppsDrawer.js index e6fe445b451..77d912ef2ae 100644 --- a/src/components/views/rooms/AppsDrawer.js +++ b/src/components/views/rooms/AppsDrawer.js @@ -30,6 +30,7 @@ import ScalarMessaging from '../../../ScalarMessaging'; import { _t } from '../../../languageHandler'; import WidgetUtils from '../../../utils/WidgetUtils'; import WidgetEchoStore from "../../../stores/WidgetEchoStore"; +import AccessibleButton from '../elements/AccessibleButton'; // The maximum number of widgets that can be added in a room const MAX_WIDGETS = 2; @@ -193,17 +194,15 @@ module.exports = React.createClass({ if (this.props.showApps && this._canUserModify() ) { - addWidget =
[+] { _t('Add a widget') } -
; + ; } let spinner; diff --git a/src/components/views/rooms/MemberInfo.js b/src/components/views/rooms/MemberInfo.js index e6e63500839..ff5f41c7d10 100644 --- a/src/components/views/rooms/MemberInfo.js +++ b/src/components/views/rooms/MemberInfo.js @@ -935,7 +935,7 @@ module.exports = withMatrixClient(React.createClass({
- + {_t('Close')}
diff --git a/src/components/views/rooms/MessageComposer.js b/src/components/views/rooms/MessageComposer.js index c5e389aa069..66f3fdaa974 100644 --- a/src/components/views/rooms/MessageComposer.js +++ b/src/components/views/rooms/MessageComposer.js @@ -292,21 +292,22 @@ export default class MessageComposer extends React.Component { let videoCallButton; let hangupButton; + const AccessibleButton = sdk.getComponent('elements.AccessibleButton'); // Call buttons if (this.props.callState && this.props.callState !== 'ended') { hangupButton = -
+ {_t('Hangup')} -
; + ; } else { callButton = -
+ -
; + ; videoCallButton = -
+ -
; + ; } const canSendMessages = !this.state.tombstone && @@ -317,18 +318,19 @@ export default class MessageComposer extends React.Component { // check separately for whether we can call, but this is slightly // complex because of conference calls. const uploadButton = ( -
-
+ ); const formattingButton = this.state.inputState.isRichTextEnabled ? ( - {_t("Show
@@ -423,7 +424,7 @@ export default class MessageComposer extends React.Component { onMouseDown={this.onToggleMarkdownClicked} className="mx_MessageComposer_formatbar_markdown mx_filterFlipColor" src={`img/button-md-${!this.state.inputState.isRichTextEnabled}.png`} /> - diff --git a/src/components/views/settings/DevicesPanel.js b/src/components/views/settings/DevicesPanel.js index f0fec2cf63c..25850819bd5 100644 --- a/src/components/views/settings/DevicesPanel.js +++ b/src/components/views/settings/DevicesPanel.js @@ -164,6 +164,7 @@ export default class DevicesPanel extends React.Component { render() { const Spinner = sdk.getComponent("elements.Spinner"); + const AccessibleButton = sdk.getComponent("elements.AccessibleButton"); if (this.state.deviceLoadError !== undefined) { const classes = classNames(this.props.className, "error"); @@ -185,9 +186,9 @@ export default class DevicesPanel extends React.Component { const deleteButton = this.state.deleting ? : -
+ { _t("Delete %(count)s devices", {count: this.state.selectedDevices.length}) } -
; + ; const classes = classNames(this.props.className, "mx_DevicesPanel"); return ( diff --git a/src/components/views/voip/CallView.js b/src/components/views/voip/CallView.js index 47e8ae22db9..1a84d23f9bb 100644 --- a/src/components/views/voip/CallView.js +++ b/src/components/views/voip/CallView.js @@ -125,14 +125,15 @@ module.exports = React.createClass({ render: function() { const VideoView = sdk.getComponent('voip.VideoView'); + const AccessibleButton = sdk.getComponent('elements.AccessibleButton'); let voice; if (this.state.call && this.state.call.type === "voice" && this.props.showVoice) { const callRoom = MatrixClientPeg.get().getRoom(this.state.call.roomId); voice = ( -
+ { _t("Active call (%(roomName)s)", {roomName: callRoom.name}) } -
+ ); } From e05ae29146d2fe13208cbc50ea2657593aaa5582 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20V=C3=A1gner?= Date: Tue, 2 Oct 2018 20:19:21 +0200 Subject: [PATCH 2/3] Also fix accessibility of sticker buttons --- src/components/views/rooms/Stickerpicker.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/components/views/rooms/Stickerpicker.js b/src/components/views/rooms/Stickerpicker.js index 841cfb9b03a..40b17682826 100644 --- a/src/components/views/rooms/Stickerpicker.js +++ b/src/components/views/rooms/Stickerpicker.js @@ -151,8 +151,8 @@ export default class Stickerpicker extends React.Component {

{ _t("You don't currently have any stickerpacks enabled") }

-

Add some now

- {_t('Add +

{ _t("Add some now") }

+
); } @@ -344,7 +344,7 @@ export default class Stickerpicker extends React.Component { if (this.state.showStickers) { // Show hide-stickers button stickersButton = -
-
; + ; } else { // Show show-stickers button stickersButton = -
-
; + ; } return
{stickersButton} From 2b394c18697457772e59d32a74edd270b70cba49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20V=C3=A1gner?= Date: Tue, 2 Oct 2018 20:32:54 +0200 Subject: [PATCH 3/3] Address review comments and fix lint errors --- src/components/structures/UserSettings.js | 16 ++++++++-------- src/components/views/elements/AppWarning.js | 1 - src/components/views/globals/CookieBar.js | 2 +- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/components/structures/UserSettings.js b/src/components/structures/UserSettings.js index 7b79eebbb66..129278907f2 100644 --- a/src/components/structures/UserSettings.js +++ b/src/components/structures/UserSettings.js @@ -1233,10 +1233,10 @@ module.exports = React.createClass({ value={this.presentableTextForThreepid(val)} disabled />
- - {_t("Remove")} + - +
); }); @@ -1258,9 +1258,9 @@ module.exports = React.createClass({ blurToCancel={false} onValueChanged={this._onAddEmailEditFinished} />
- - {_t("Add")} - +
+ +
); } @@ -1339,14 +1339,14 @@ module.exports = React.createClass({
- +
- +
diff --git a/src/components/views/elements/AppWarning.js b/src/components/views/elements/AppWarning.js index 60809f5ca1c..38d3476d537 100644 --- a/src/components/views/elements/AppWarning.js +++ b/src/components/views/elements/AppWarning.js @@ -1,6 +1,5 @@ import React from 'react'; // eslint-disable-line no-unused-vars import PropTypes from 'prop-types'; -import { _t } from '../../../languageHandler'; const AppWarning = (props) => { return ( diff --git a/src/components/views/globals/CookieBar.js b/src/components/views/globals/CookieBar.js index 3dc618edf5c..deb1cbffa8d 100644 --- a/src/components/views/globals/CookieBar.js +++ b/src/components/views/globals/CookieBar.js @@ -95,7 +95,7 @@ export default class CookieBar extends React.Component { { _t("Yes, I want to help!") } - {_t('Close')}/ + {_t('Close')} );