Give focused status a sensible aria-label for screen readers (#8387)
* Give focused status a sensible aria-label for screen readers Fix #8192 * Use content warning in aria-label unless expanded
This commit is contained in:
		
							parent
							
								
									43b8df3228
								
							
						
					
					
						commit
						248df68c36
					
				
					 2 changed files with 26 additions and 5 deletions
				
			
		| 
						 | 
					@ -8,7 +8,7 @@ import DisplayName from './display_name';
 | 
				
			||||||
import StatusContent from './status_content';
 | 
					import StatusContent from './status_content';
 | 
				
			||||||
import StatusActionBar from './status_action_bar';
 | 
					import StatusActionBar from './status_action_bar';
 | 
				
			||||||
import AttachmentList from './attachment_list';
 | 
					import AttachmentList from './attachment_list';
 | 
				
			||||||
import { FormattedMessage } from 'react-intl';
 | 
					import { injectIntl, FormattedMessage } from 'react-intl';
 | 
				
			||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
					import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
				
			||||||
import { MediaGallery, Video } from '../features/ui/util/async-components';
 | 
					import { MediaGallery, Video } from '../features/ui/util/async-components';
 | 
				
			||||||
import { HotKeys } from 'react-hotkeys';
 | 
					import { HotKeys } from 'react-hotkeys';
 | 
				
			||||||
| 
						 | 
					@ -18,6 +18,24 @@ import classNames from 'classnames';
 | 
				
			||||||
// to use the progress bar to show download progress
 | 
					// to use the progress bar to show download progress
 | 
				
			||||||
import Bundle from '../features/ui/components/bundle';
 | 
					import Bundle from '../features/ui/components/bundle';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const textForScreenReader = (intl, status, rebloggedByText = false, expanded = false) => {
 | 
				
			||||||
 | 
					  const displayName = status.getIn(['account', 'display_name']);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const values = [
 | 
				
			||||||
 | 
					    displayName.length === 0 ? status.getIn(['account', 'acct']).split('@')[0] : displayName,
 | 
				
			||||||
 | 
					    status.get('spoiler_text') && !expanded ? status.get('spoiler_text') : status.get('search_index').slice(status.get('spoiler_text').length),
 | 
				
			||||||
 | 
					    intl.formatDate(status.get('created_at'), { hour: '2-digit', minute: '2-digit', month: 'short', day: 'numeric' }),
 | 
				
			||||||
 | 
					    status.getIn(['account', 'acct']),
 | 
				
			||||||
 | 
					  ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (rebloggedByText) {
 | 
				
			||||||
 | 
					    values.push(rebloggedByText);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return values.join(', ');
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@injectIntl
 | 
				
			||||||
export default class Status extends ImmutablePureComponent {
 | 
					export default class Status extends ImmutablePureComponent {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  static contextTypes = {
 | 
					  static contextTypes = {
 | 
				
			||||||
| 
						 | 
					@ -138,9 +156,9 @@ export default class Status extends ImmutablePureComponent {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  render () {
 | 
					  render () {
 | 
				
			||||||
    let media = null;
 | 
					    let media = null;
 | 
				
			||||||
    let statusAvatar, prepend;
 | 
					    let statusAvatar, prepend, rebloggedByText;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const { hidden, featured } = this.props;
 | 
					    const { intl, hidden, featured } = this.props;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let { status, account, ...other } = this.props;
 | 
					    let { status, account, ...other } = this.props;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -189,6 +207,8 @@ export default class Status extends ImmutablePureComponent {
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      rebloggedByText = intl.formatMessage({ id: 'status.reblogged_by', defaultMessage: '{name} boosted' }, { name: status.getIn(['account', 'acct']) });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      account = status.get('account');
 | 
					      account = status.get('account');
 | 
				
			||||||
      status  = status.get('reblog');
 | 
					      status  = status.get('reblog');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -248,7 +268,7 @@ export default class Status extends ImmutablePureComponent {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
      <HotKeys handlers={handlers}>
 | 
					      <HotKeys handlers={handlers}>
 | 
				
			||||||
        <div className={classNames('status__wrapper', `status__wrapper-${status.get('visibility')}`, { focusable: !this.props.muted })} tabIndex={this.props.muted ? null : 0} data-featured={featured ? 'true' : null}>
 | 
					        <div className={classNames('status__wrapper', `status__wrapper-${status.get('visibility')}`, { focusable: !this.props.muted })} tabIndex={this.props.muted ? null : 0} data-featured={featured ? 'true' : null} aria-label={textForScreenReader(intl, status, rebloggedByText, !status.get('hidden'))}>
 | 
				
			||||||
          {prepend}
 | 
					          {prepend}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          <div className={classNames('status', `status-${status.get('visibility')}`, { muted: this.props.muted })} data-id={status.get('id')}>
 | 
					          <div className={classNames('status', `status-${status.get('visibility')}`, { muted: this.props.muted })} data-id={status.get('id')}>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -43,6 +43,7 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
				
			||||||
import { HotKeys } from 'react-hotkeys';
 | 
					import { HotKeys } from 'react-hotkeys';
 | 
				
			||||||
import { boostModal, deleteModal } from '../../initial_state';
 | 
					import { boostModal, deleteModal } from '../../initial_state';
 | 
				
			||||||
import { attachFullscreenListener, detachFullscreenListener, isFullscreen } from '../ui/util/fullscreen';
 | 
					import { attachFullscreenListener, detachFullscreenListener, isFullscreen } from '../ui/util/fullscreen';
 | 
				
			||||||
 | 
					import { textForScreenReader } from '../../components/status';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const messages = defineMessages({
 | 
					const messages = defineMessages({
 | 
				
			||||||
  deleteConfirm: { id: 'confirmations.delete.confirm', defaultMessage: 'Delete' },
 | 
					  deleteConfirm: { id: 'confirmations.delete.confirm', defaultMessage: 'Delete' },
 | 
				
			||||||
| 
						 | 
					@ -418,7 +419,7 @@ export default class Status extends ImmutablePureComponent {
 | 
				
			||||||
            {ancestors}
 | 
					            {ancestors}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <HotKeys handlers={handlers}>
 | 
					            <HotKeys handlers={handlers}>
 | 
				
			||||||
              <div className='focusable' tabIndex='0'>
 | 
					              <div className='focusable' tabIndex='0' aria-label={textForScreenReader(intl, status, false, !status.get('hidden'))}>
 | 
				
			||||||
                <DetailedStatus
 | 
					                <DetailedStatus
 | 
				
			||||||
                  status={status}
 | 
					                  status={status}
 | 
				
			||||||
                  onOpenVideo={this.handleOpenVideo}
 | 
					                  onOpenVideo={this.handleOpenVideo}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		
		Reference in a new issue