Merge pull request #3562 from matrix-org/t3chguy/a11y_iteration

A11Y fixes in the Left Panel
pull/21833/head
Michael Telatynski 2019-10-23 16:17:17 +01:00 committed by GitHub
commit fc45a69bb7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 54 additions and 53 deletions

View File

@ -1,5 +1,6 @@
/*
Copyright 2015, 2016 OpenMarket Ltd
Copyright 2019 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -19,7 +20,7 @@ import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import { MatrixClient } from 'matrix-js-sdk';
import { KeyCode } from '../../Keyboard';
import { Key } from '../../Keyboard';
import sdk from '../../index';
import dis from '../../dispatcher';
import VectorConferenceHandler from '../../VectorConferenceHandler';
@ -117,35 +118,21 @@ const LeftPanel = createReactClass({
_onKeyDown: function(ev) {
if (!this.focusedElement) return;
let handled = true;
switch (ev.keyCode) {
case KeyCode.TAB:
this._onMoveFocus(ev.shiftKey);
switch (ev.key) {
case Key.TAB:
this._onMoveFocus(ev, ev.shiftKey);
break;
case KeyCode.UP:
this._onMoveFocus(true);
case Key.ARROW_UP:
this._onMoveFocus(ev, true, true);
break;
case KeyCode.DOWN:
this._onMoveFocus(false);
case Key.ARROW_DOWN:
this._onMoveFocus(ev, false, true);
break;
case KeyCode.ENTER:
this._onMoveFocus(false);
if (this.focusedElement) {
this.focusedElement.click();
}
break;
default:
handled = false;
}
if (handled) {
ev.stopPropagation();
ev.preventDefault();
}
},
_onMoveFocus: function(up) {
_onMoveFocus: function(ev, up, trap) {
let element = this.focusedElement;
// unclear why this isn't needed
@ -179,29 +166,24 @@ const LeftPanel = createReactClass({
if (element) {
classes = element.classList;
if (classes.contains("mx_LeftPanel")) { // we hit the top
element = up ? element.lastElementChild : element.firstElementChild;
descending = true;
}
}
} while (element && !(
classes.contains("mx_RoomTile") ||
classes.contains("mx_RoomSubList_label") ||
classes.contains("mx_textinput_search")));
classes.contains("mx_LeftPanel_filterRooms")));
if (element) {
ev.stopPropagation();
ev.preventDefault();
element.focus();
this.focusedElement = element;
this.focusedDescending = descending;
} else if (trap) {
// if navigation is via up/down arrow-keys, trap in the widget so it doesn't send to composer
ev.stopPropagation();
ev.preventDefault();
}
},
onHideClick: function() {
dis.dispatch({
action: 'hide_left_panel',
});
},
onSearch: function(term) {
this.setState({ searchFilter: term });
},
@ -269,6 +251,7 @@ const LeftPanel = createReactClass({
}
const searchBox = (<SearchBox
className="mx_LeftPanel_filterRooms"
enableRoomSearchFocus={true}
blurredPlaceholder={ _t('Filter') }
placeholder={ _t('Filter rooms…') }
@ -286,20 +269,22 @@ const LeftPanel = createReactClass({
return (
<div className={containerClasses}>
{ tagPanelContainer }
<aside className={"mx_LeftPanel dark-panel"} onKeyDown={ this._onKeyDown } onFocus={ this._onFocus } onBlur={ this._onBlur }>
<TopLeftMenuButton collapsed={ this.props.collapsed } />
<aside className="mx_LeftPanel dark-panel">
<TopLeftMenuButton collapsed={this.props.collapsed} />
{ breadcrumbs }
<div className="mx_LeftPanel_exploreAndFilterRow">
{ exploreButton }
{ searchBox }
</div>
<CallPreview ConferenceHandler={VectorConferenceHandler} />
<RoomList
ref={this.collectRoomList}
resizeNotifier={this.props.resizeNotifier}
collapsed={this.props.collapsed}
searchFilter={this.state.searchFilter}
ConferenceHandler={VectorConferenceHandler} />
<div className="mx_LeftPanel_Rooms" onKeyDown={this._onKeyDown} onFocus={this._onFocus} onBlur={this._onBlur}>
<div className="mx_LeftPanel_exploreAndFilterRow">
{ exploreButton }
{ searchBox }
</div>
<RoomList
ref={this.collectRoomList}
resizeNotifier={this.props.resizeNotifier}
collapsed={this.props.collapsed}
searchFilter={this.state.searchFilter}
ConferenceHandler={VectorConferenceHandler} />
</div>
</aside>
</div>
);

View File

@ -324,6 +324,7 @@ const RoomSubList = createReactClass({
aria-expanded={!isCollapsed}
inputRef={this._headerButton}
role="treeitem"
aria-level="1"
>
{ chevron }
<span>{this.props.label}</span>

View File

@ -346,8 +346,15 @@ export default class RoomBreadcrumbs extends React.Component {
}
return (
<AccessibleButton className={classes} key={r.room.roomId} onClick={() => this._viewRoom(r.room, i)}
onMouseEnter={() => this._onMouseEnter(r.room)} onMouseLeave={() => this._onMouseLeave(r.room)}>
<AccessibleButton
className={classes}
key={r.room.roomId}
onClick={() => this._viewRoom(r.room, i)}
onMouseEnter={() => this._onMouseEnter(r.room)}
onMouseLeave={() => this._onMouseLeave(r.room)}
aria-label={_t("Room %(name)s", {name: r.room.name})}
role="listitem"
>
<RoomAvatar room={r.room} width={32} height={32} />
{badge}
{dmIndicator}
@ -356,10 +363,16 @@ export default class RoomBreadcrumbs extends React.Component {
);
});
return (
<IndicatorScrollbar ref="scroller" className="mx_RoomBreadcrumbs"
trackHorizontalOverflow={true} verticalScrollsHorizontally={true}>
{ avatars }
</IndicatorScrollbar>
<div role="list" aria-orientation="horizontal" aria-roledescription={_t("Recent rooms")}>
<IndicatorScrollbar
ref="scroller"
className="mx_RoomBreadcrumbs"
trackHorizontalOverflow={true}
verticalScrollsHorizontally={true}
>
{ avatars }
</IndicatorScrollbar>
</div>
);
}
}

View File

@ -896,6 +896,8 @@
"Seen by %(displayName)s (%(userName)s) at %(dateTime)s": "Seen by %(displayName)s (%(userName)s) at %(dateTime)s",
"Replying": "Replying",
"Direct Chat": "Direct Chat",
"Room %(name)s": "Room %(name)s",
"Recent rooms": "Recent rooms",
"No rooms to show": "No rooms to show",
"Unnamed room": "Unnamed room",
"World readable": "World readable",