From fd4cdd0dec78d2ea3085ab8b752a394c3f08bea9 Mon Sep 17 00:00:00 2001
From: Michael Telatynski <7t3chguy@gmail.com>
Date: Fri, 1 Nov 2019 10:50:58 +0000
Subject: [PATCH] Improve A11Y of timeline. Show TS & Actions on focus-within

---
 res/css/views/rooms/_EventTile.scss               | 7 ++++++-
 src/components/views/messages/DateSeparator.js    | 2 +-
 src/components/views/messages/MessageActionBar.js | 3 ++-
 src/components/views/messages/MessageTimestamp.js | 2 +-
 src/components/views/rooms/EventTile.js           | 9 +++++++--
 src/i18n/strings/en_EN.json                       | 1 +
 6 files changed, 18 insertions(+), 6 deletions(-)

diff --git a/res/css/views/rooms/_EventTile.scss b/res/css/views/rooms/_EventTile.scss
index fafd34f8ca..a30b219016 100644
--- a/res/css/views/rooms/_EventTile.scss
+++ b/res/css/views/rooms/_EventTile.scss
@@ -138,11 +138,13 @@ limitations under the License.
 // Explicit relationships so that it doesn't apply to nested EventTile components (e.g in Replies)
 .mx_EventTile_last > div > a > .mx_MessageTimestamp,
 .mx_EventTile:hover > div > a > .mx_MessageTimestamp,
+.mx_EventTile:focus-within > div > a > .mx_MessageTimestamp,
 .mx_EventTile.mx_EventTile_actionBarFocused > div > a > .mx_MessageTimestamp {
     visibility: visible;
 }
 
 .mx_EventTile:hover .mx_MessageActionBar,
+.mx_EventTile:focus-within .mx_MessageActionBar,
 .mx_EventTile.mx_EventTile_actionBarFocused .mx_MessageActionBar {
     visibility: visible;
 }
@@ -166,6 +168,7 @@ limitations under the License.
 }
 
 .mx_EventTile:hover .mx_EventTile_line,
+.mx_EventTile:focus-within .mx_EventTile_line,
 .mx_EventTile.mx_EventTile_actionBarFocused .mx_EventTile_line {
     background-color: $event-selected-color;
 }
@@ -465,7 +468,8 @@ div.mx_EventTile_notSent.mx_EventTile_redacted .mx_UnknownBody {
     }
 }
 
-.mx_EventTile:hover .mx_EventTile_body pre {
+.mx_EventTile:hover .mx_EventTile_body pre,
+.mx_EventTile:focus-within .mx_EventTile_body pre {
     border: 1px solid #e5e5e5; // deliberate constant as we're behind an invert filter
 }
 
@@ -487,6 +491,7 @@ div.mx_EventTile_notSent.mx_EventTile_redacted .mx_UnknownBody {
     background-image: url($copy-button-url);
 }
 
+.mx_EventTile_body .mx_EventTile_pre_container:focus-within .mx_EventTile_copyButton,
 .mx_EventTile_body .mx_EventTile_pre_container:hover .mx_EventTile_copyButton {
     visibility: visible;
 }
diff --git a/src/components/views/messages/DateSeparator.js b/src/components/views/messages/DateSeparator.js
index 900fd61914..88b59d0c26 100644
--- a/src/components/views/messages/DateSeparator.js
+++ b/src/components/views/messages/DateSeparator.js
@@ -57,7 +57,7 @@ export default class DateSeparator extends React.Component {
 
     render() {
         // ARIA treats <hr/>s as separators, here we abuse them slightly so manually treat this entire thing as one
-        return <h2 className="mx_DateSeparator" role="separator">
+        return <h2 className="mx_DateSeparator" role="separator" tabIndex={-1}>
             <hr role="none" />
             <div>{ this.getLabel() }</div>
             <hr role="none" />
diff --git a/src/components/views/messages/MessageActionBar.js b/src/components/views/messages/MessageActionBar.js
index 565c66410e..acd8263410 100644
--- a/src/components/views/messages/MessageActionBar.js
+++ b/src/components/views/messages/MessageActionBar.js
@@ -180,7 +180,8 @@ export default class MessageActionBar extends React.PureComponent {
             />;
         }
 
-        return <div className="mx_MessageActionBar">
+        // aria-live=off to not have this read out automatically as navigating around timeline, gets repetitive.
+        return <div className="mx_MessageActionBar" role="toolbar" aria-label={_t("Message Actions")} aria-live="off">
             {reactButton}
             {replyButton}
             {editButton}
diff --git a/src/components/views/messages/MessageTimestamp.js b/src/components/views/messages/MessageTimestamp.js
index 0bbb3f631e..199a6f47ce 100644
--- a/src/components/views/messages/MessageTimestamp.js
+++ b/src/components/views/messages/MessageTimestamp.js
@@ -28,7 +28,7 @@ export default class MessageTimestamp extends React.Component {
     render() {
         const date = new Date(this.props.ts);
         return (
-            <span className="mx_MessageTimestamp" title={formatFullDate(date, this.props.showTwelveHour)}>
+            <span className="mx_MessageTimestamp" title={formatFullDate(date, this.props.showTwelveHour)} aria-hidden={true}>
                 { formatTime(date, this.props.showTwelveHour) }
             </span>
         );
diff --git a/src/components/views/rooms/EventTile.js b/src/components/views/rooms/EventTile.js
index ca83dd1814..bc502d0674 100644
--- a/src/components/views/rooms/EventTile.js
+++ b/src/components/views/rooms/EventTile.js
@@ -32,6 +32,7 @@ const TextForEvent = require('../../../TextForEvent');
 import dis from '../../../dispatcher';
 import SettingsStore from "../../../settings/SettingsStore";
 import {EventStatus, MatrixClient} from 'matrix-js-sdk';
+import {formatTime} from "../../../DateUtils";
 
 const ObjectUtils = require('../../../ObjectUtils');
 
@@ -787,13 +788,17 @@ module.exports = createReactClass({
                     'replyThread',
                 );
                 return (
-                    <div className={classes}>
+                    <div className={classes} tabIndex={-1}>
                         <div className="mx_EventTile_msgOption">
                             { readAvatars }
                         </div>
                         { sender }
                         <div className="mx_EventTile_line">
-                            <a href={permalink} onClick={this.onPermalinkClicked}>
+                            <a
+                                href={permalink}
+                                onClick={this.onPermalinkClicked}
+                                aria-label={formatTime(new Date(this.props.mxEvent.getTs()), this.props.isTwelveHour)}
+                            >
                                 { timestamp }
                             </a>
                             { this._renderE2EPadlock() }
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index 524a8a1abf..86521f2594 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -1053,6 +1053,7 @@
     "React": "React",
     "Reply": "Reply",
     "Edit": "Edit",
+    "Message Actions": "Message Actions",
     "Options": "Options",
     "Attachment": "Attachment",
     "Error decrypting attachment": "Error decrypting attachment",