Skip to content

Commit

Permalink
Consolidate block accessibility label to use the same functionality o…
Browse files Browse the repository at this point in the history
…n mobile and web
  • Loading branch information
talldan committed Dec 4, 2019
1 parent 7ec7fac commit 07e2ee0
Show file tree
Hide file tree
Showing 10 changed files with 98 additions and 104 deletions.
5 changes: 1 addition & 4 deletions packages/block-editor/src/components/block-list/block.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import {
__experimentalGetAccessibleBlockLabel as getAccessibleBlockLabel,
} from '@wordpress/blocks';
import { KeyboardShortcuts, withFilters } from '@wordpress/components';
import { __, sprintf } from '@wordpress/i18n';
import {
withDispatch,
withSelect,
Expand Down Expand Up @@ -411,9 +410,7 @@ function BlockListBlock( {
const isHovered = isBlockHovered && ! isPartOfMultiSelection;
const blockType = getBlockType( name );

// translators: %s: Type of block (i.e. Text, Image etc)
const blockAriaLabel = sprintf( __( 'Block: %s' ), getAccessibleBlockLabel( blockType, attributes, ' - ' ) );

const blockAriaLabel = getAccessibleBlockLabel( blockType, attributes );
const isUnregisteredBlock = name === getUnregisteredTypeHandlerName();

// If the block is selected and we're typing the block should not appear.
Expand Down
40 changes: 9 additions & 31 deletions packages/block-editor/src/components/block-list/block.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,11 @@ import { Component } from '@wordpress/element';
import { ToolbarButton, Toolbar } from '@wordpress/components';
import { withDispatch, withSelect } from '@wordpress/data';
import { compose } from '@wordpress/compose';
import { getBlockType } from '@wordpress/blocks';
import { __, sprintf } from '@wordpress/i18n';
import {
getBlockType,
__experimentalGetAccessibleBlockLabel as getAccessibleBlockLabel,
} from '@wordpress/blocks';
import { __ } from '@wordpress/i18n';

/**
* Internal dependencies
Expand Down Expand Up @@ -80,39 +83,17 @@ class BlockListBlock extends Component {
);
}

getAccessibilityLabel() {
const { attributes, name, order, title, getAccessibilityLabelExtra } = this.props;

let blockName = '';

if ( name === 'core/missing' ) { // is the block unrecognized?
blockName = title;
} else {
blockName = sprintf(
/* translators: accessibility text. %s: block name. */
__( '%s Block' ),
title, //already localized
);
}

blockName += '. ' + sprintf( __( 'Row %d.' ), order + 1 );

if ( getAccessibilityLabelExtra ) {
const blockAccessibilityLabel = getAccessibilityLabelExtra( attributes );
blockName += blockAccessibilityLabel ? ' ' + blockAccessibilityLabel : '';
}

return blockName;
}

render() {
const {
attributes,
borderStyle,
blockType,
clientId,
focusedBorderColor,
icon,
isSelected,
isValid,
order,
showTitle,
title,
showFloatingToolbar,
Expand All @@ -122,8 +103,7 @@ class BlockListBlock extends Component {

const borderColor = isSelected ? focusedBorderColor : 'transparent';

const accessibilityLabel = this.getAccessibilityLabel();

const accessibilityLabel = getAccessibleBlockLabel( blockType, attributes, order + 1 );
return (
<>
{ showFloatingToolbar && ( ! isFirstBlock || parentId === '' ) && <FloatingToolbar.Slot /> }
Expand Down Expand Up @@ -185,7 +165,6 @@ export default compose( [
const blockType = getBlockType( name || 'core/missing' );
const title = blockType.title;
const icon = blockType.icon;
const getAccessibilityLabelExtra = blockType.__experimentalGetAccessibilityLabel;

const selectedBlock = getSelectedBlock();
const parentId = getBlockRootClientId( clientId );
Expand All @@ -211,7 +190,6 @@ export default compose( [
isLastBlock,
isSelected,
isValid,
getAccessibilityLabelExtra,
showFloatingToolbar,
parentId,
};
Expand Down
7 changes: 2 additions & 5 deletions packages/block-library/src/heading/index.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { isEmpty } from 'lodash';
* WordPress dependencies
*/
import { __, sprintf } from '@wordpress/i18n';
import { create } from '@wordpress/rich-text';

/**
* Internal dependencies
Expand All @@ -18,11 +17,9 @@ export { metadata, name } from './index.js';

export const settings = {
...webSettings,
__experimentalGetAccessibilityLabel( attributes ) {
__experimentalGetLabel( attributes ) {
const { content, level } = attributes;

const plainTextContent = ( html ) => create( { html } ).text || '';

return isEmpty( content ) ?
sprintf(
/* translators: accessibility text. %s: heading level. */
Expand All @@ -33,7 +30,7 @@ export const settings = {
/* translators: accessibility text. 1: heading level. 2: heading content. */
__( 'Level %1$s. %2$s' ),
level,
plainTextContent( content )
content
);
},
};
2 changes: 1 addition & 1 deletion packages/block-library/src/image/index.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export { metadata, name } from './index.js';

export const settings = {
...webSettings,
__experimentalGetAccessibilityLabel( attributes ) {
__experimentalGetLabel( attributes ) {
const { caption, alt, url } = attributes;

if ( ! url ) {
Expand Down
2 changes: 1 addition & 1 deletion packages/block-library/src/missing/index.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export { metadata, name } from './index.js';

export const settings = {
...webSettings,
__experimentalGetAccessibilityLabel( attributes ) {
__experimentalGetLabel( attributes ) {
const { originalName } = attributes;

const originalBlockType = originalName && coreBlocks[ originalName ];
Expand Down
2 changes: 1 addition & 1 deletion packages/block-library/src/more/index.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export { metadata, name } from './index.js';

export const settings = {
...webSettings,
__experimentalGetAccessibilityLabel( attributes ) {
__experimentalGetLabel( attributes ) {
return attributes.customText;
},
};
2 changes: 1 addition & 1 deletion packages/block-library/src/navigation-link/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export const settings = {

description: __( 'Add a page, link, or other item to your navigation.' ),

__experimentalDisplayName: 'label',
__experimentalGetLabel: ( { label } ) => label,

edit,
save,
Expand Down
8 changes: 2 additions & 6 deletions packages/block-library/src/paragraph/index.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { isEmpty } from 'lodash';
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
import { create } from '@wordpress/rich-text';

/**
* Internal dependencies
Expand All @@ -18,11 +17,8 @@ export { metadata, name } from './index.js';

export const settings = {
...webSettings,
__experimentalGetAccessibilityLabel( attributes ) {
__experimentalGetLabel( attributes ) {
const { content } = attributes;

const plainTextContent = ( html ) => create( { html } ).text || '';

return isEmpty( content ) ? __( 'Empty' ) : plainTextContent( content );
return isEmpty( content ) ? __( 'Empty' ) : content;
},
};
80 changes: 37 additions & 43 deletions packages/blocks/src/api/test/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,83 +101,77 @@ describe( 'block helpers', () => {
} );
} );

describe( 'getAccessibleBlockLabel', () => {
it( 'returns only the block title when the block has no display name', () => {
describe( 'getVisualBlockLabel', () => {
it( 'returns only the block title when the block has no `getLabel` function', () => {
const blockType = { title: 'Recipe' };
const attributes = {};

expect( getAccessibleBlockLabel( blockType, attributes ) ).toBe( 'Recipe' );
expect( getVisualBlockLabel( blockType, attributes ) ).toBe( 'Recipe' );
} );

it( 'returns only the block title when the block has a display name, but the attribute is undefined', () => {
const blockType = { title: 'Recipe', __experimentalDisplayName: 'heading' };
it( 'returns only the block title when the block has a `getLabel` function, but it returns a falsey value', () => {
const blockType = { title: 'Recipe', __experimentalGetLabel: () => '' };
const attributes = {};

expect( getAccessibleBlockLabel( blockType, attributes ) ).toBe( 'Recipe' );
} );

it( 'returns only the block title when the block has a display name, but the attribute is an empty string', () => {
const blockType = { title: 'Recipe', __experimentalDisplayName: 'heading' };
const attributes = { heading: '' };

expect( getAccessibleBlockLabel( blockType, attributes ) ).toBe( 'Recipe' );
expect( getVisualBlockLabel( blockType, attributes ) ).toBe( 'Recipe' );
} );

it( 'returns the block title with the display name when the display name and its attribute are defined', () => {
const blockType = { title: 'Recipe', __experimentalDisplayName: 'heading' };
it( 'returns the block title with the label when the `getLabel` function returns a value', () => {
const blockType = { title: 'Recipe', __experimentalGetLabel: ( { heading } ) => heading };
const attributes = { heading: 'Cupcakes!' };

expect( getAccessibleBlockLabel( blockType, attributes ) ).toBe( 'Recipe: Cupcakes!' );
expect( getVisualBlockLabel( blockType, attributes ) ).toBe( 'Cupcakes!' );
} );

it( 'removes any html elements from the display name attribute', () => {
const blockType = { title: 'Recipe', __experimentalDisplayName: 'heading' };
it( 'removes any html elements from the output of the `getLabel` function', () => {
const blockType = { title: 'Recipe', __experimentalGetLabel: ( { heading } ) => heading };
const attributes = { heading: '<b><span class="my-class">Cupcakes!</span></b>' };

expect( getAccessibleBlockLabel( blockType, attributes ) ).toBe( 'Recipe: Cupcakes!' );
} );

it( 'allows specification of a custom separator', () => {
const blockType = { title: 'Recipe', __experimentalDisplayName: 'heading' };
const attributes = { heading: 'Cupcakes!' };

expect( getAccessibleBlockLabel( blockType, attributes, ' - ' ) ).toBe( 'Recipe - Cupcakes!' );
expect( getVisualBlockLabel( blockType, attributes ) ).toBe( 'Cupcakes!' );
} );
} );

describe( 'getVisualBlockLabel', () => {
it( 'returns only the block title when the block has no display name', () => {
describe( 'getAccessibleBlockLabel', () => {
it( 'returns only the block title when the block has no `getLabel` function', () => {
const blockType = { title: 'Recipe' };
const attributes = {};

expect( getVisualBlockLabel( blockType, attributes ) ).toBe( 'Recipe' );
expect( getAccessibleBlockLabel( blockType, attributes ) ).toBe( 'Recipe Block' );
} );

it( 'returns only the block title when the block has a display name, but the attribute is undefined', () => {
const blockType = { title: 'Recipe', __experimentalDisplayName: 'heading' };
it( 'returns only the block title when the block has a `getLabel` function, but it returns a falsey value', () => {
const blockType = { title: 'Recipe', __experimentalGetLabel: () => '' };
const attributes = {};

expect( getVisualBlockLabel( blockType, attributes ) ).toBe( 'Recipe' );
expect( getAccessibleBlockLabel( blockType, attributes ) ).toBe( 'Recipe Block' );
} );

it( 'returns only the block title when the block has a display name, but the attribute is an empty string', () => {
const blockType = { title: 'Recipe', __experimentalDisplayName: 'heading' };
const attributes = { heading: '' };
it( 'returns the block title with the label when the `getLabel` function returns a value', () => {
const blockType = { title: 'Recipe', __experimentalGetLabel: ( { heading } ) => heading };
const attributes = { heading: 'Cupcakes!' };

expect( getVisualBlockLabel( blockType, attributes ) ).toBe( 'Recipe' );
expect( getAccessibleBlockLabel( blockType, attributes ) ).toBe( 'Recipe Block. Cupcakes!' );
} );

it( 'removes any html elements from the output of the `getLabel` function', () => {
const blockType = { title: 'Recipe', __experimentalGetLabel: ( { heading } ) => heading };
const attributes = { heading: '<b><span class="my-class">Cupcakes!</span></b>' };

expect( getAccessibleBlockLabel( blockType, attributes ) ).toBe( 'Recipe Block. Cupcakes!' );
} );

it( 'returns the display name when the display name and its attribute are defined', () => {
const blockType = { title: 'Recipe', __experimentalDisplayName: 'heading' };
it( 'outputs the block title and label with a row number indicating the position of the block, when the optional third parameter is provided', () => {
const blockType = { title: 'Recipe', __experimentalGetLabel: ( { heading } ) => heading };
const attributes = { heading: 'Cupcakes!' };

expect( getVisualBlockLabel( blockType, attributes ) ).toBe( 'Cupcakes!' );
expect( getAccessibleBlockLabel( blockType, attributes, 3 ) ).toBe( 'Recipe Block. Row 3. Cupcakes!' );
} );

it( 'removes any html elements from the display name attribute', () => {
const blockType = { title: 'Recipe', __experimentalDisplayName: 'heading' };
const attributes = { heading: '<b><span class="my-class">Cupcakes!</span></b>' };
it( 'outputs just the block title and row number when there no label is available for the block', () => {
const blockType = { title: 'Recipe' };
const attributes = {};

expect( getVisualBlockLabel( blockType, attributes ) ).toBe( 'Cupcakes!' );
expect( getAccessibleBlockLabel( blockType, attributes, 3 ) ).toBe( 'Recipe Block. Row 3' );
} );
} );

54 changes: 43 additions & 11 deletions packages/blocks/src/api/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { default as tinycolor, mostReadable } from 'tinycolor2';
* WordPress dependencies
*/
import { Component, isValidElement } from '@wordpress/element';
import { __, sprintf } from '@wordpress/i18n';
import { create, getTextContent } from '@wordpress/rich-text';

/**
Expand Down Expand Up @@ -134,16 +135,18 @@ export function normalizeBlockType( blockTypeOrName ) {
*/
export function getVisualBlockLabel( blockType, attributes ) {
const {
__experimentalDisplayName: displayNameAttribute,
__experimentalGetLabel: getLabel,
title: blockTitle,
} = blockType;

if ( ! displayNameAttribute || ! attributes[ displayNameAttribute ] ) {
const label = getLabel && getLabel( attributes );

if ( ! label ) {
return blockTitle;
}

// Strip any formatting.
const richTextValue = create( { html: attributes[ displayNameAttribute ] } );
const richTextValue = create( { html: label } );
const formatlessDisplayName = getTextContent( richTextValue );

return formatlessDisplayName;
Expand All @@ -156,19 +159,48 @@ export function getVisualBlockLabel( blockType, attributes ) {
*
* @param {Object} blockType The block type.
* @param {Object} attributes The values of the block's attributes.
* @param {?string} separator A separator to display between the title and
* displayName. Defaults to a colon (': ').
* @param {?number} row The row of the block in the block list.
*
* @return {string} The block label.
*/
export function getAccessibleBlockLabel( blockType, attributes, separator = ': ' ) {
export function getAccessibleBlockLabel( blockType, attributes, row ) {
// `blockTitle` is already localized, `label` is a user-supplied value.
const { title: blockTitle } = blockType;
const label = getVisualBlockLabel( blockType, attributes );
const hasRow = row !== undefined;
const hasLabel = label && label !== blockTitle;

if ( hasRow ) {
if ( hasLabel ) {
return sprintf(
/* translators: accessibility text. %s: block title, %d block row number, $s block label.. */
__( '%s Block. Row %d. %s' ),
blockTitle,
row,
label
);
}

return sprintf(
/* translators: accessibility text. %s: block title, %d block row number. */
__( '%s Block. Row %d' ),
blockTitle,
row,
);
}

const blockLabel = getVisualBlockLabel( blockType, attributes );

if ( blockTitle === blockLabel ) {
return blockTitle;
if ( hasLabel ) {
return sprintf(
/* translators: accessibility text. %s: block title. $s block label. */
__( '%s Block. %s' ),
blockTitle,
label
);
}

return `${ blockTitle }${ separator }${ blockLabel }`;
return sprintf(
/* translators: accessibility text. %s: block title. */
__( '%s Block' ),
blockTitle
);
}

0 comments on commit 07e2ee0

Please sign in to comment.