Skip to content

Commit

Permalink
Writing Flow: Move selected block focus to BlockListBlock (#5102)
Browse files Browse the repository at this point in the history
* Writing Flow: Move selected block focus to BlockListBlock

* Writing Flow: Account for initial position in tabbable target
  • Loading branch information
aduth authored Feb 16, 2018
1 parent 8859e1b commit 7e26164
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 45 deletions.
61 changes: 58 additions & 3 deletions editor/components/block-list/block.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@
*/
import { connect } from 'react-redux';
import classnames from 'classnames';
import { get, reduce, size, castArray, noop } from 'lodash';
import { get, reduce, size, castArray, noop, first, last } from 'lodash';
import tinymce from 'tinymce';

/**
* WordPress dependencies
*/
import { Component, findDOMNode, compose } from '@wordpress/element';
import { keycodes } from '@wordpress/utils';
import { keycodes, focus } from '@wordpress/utils';
import {
BlockEdit,
createBlock,
Expand All @@ -25,7 +26,11 @@ import { __, sprintf } from '@wordpress/i18n';
/**
* Internal dependencies
*/
import { getScrollContainer } from '../../utils/dom';
import {
getScrollContainer,
placeCaretAtHorizontalEdge,
placeCaretAtVerticalEdge,
} from '../../utils/dom';
import BlockMover from '../block-mover';
import BlockDropZone from '../block-drop-zone';
import BlockSettingsMenu from '../block-settings-menu';
Expand Down Expand Up @@ -67,6 +72,7 @@ import {
isTyping,
getBlockMode,
getCurrentPostType,
getSelectedBlocksInitialCaretPosition,
} from '../../store/selectors';

const { BACKSPACE, ESCAPE, DELETE, ENTER, UP, RIGHT, DOWN, LEFT } = keycodes;
Expand Down Expand Up @@ -126,6 +132,10 @@ export class BlockListBlock extends Component {
document.addEventListener( 'mousemove', this.stopTypingOnMouseMove );
}
document.addEventListener( 'selectionchange', this.onSelectionChange );

if ( this.props.isSelected ) {
this.focusTabbable();
}
}

componentWillReceiveProps( newProps ) {
Expand Down Expand Up @@ -158,6 +168,10 @@ export class BlockListBlock extends Component {
this.removeStopTypingListener();
}
}

if ( this.props.isSelected && ! prevProps.isSelected ) {
this.focusTabbable();
}
}

componentWillUnmount() {
Expand Down Expand Up @@ -189,6 +203,46 @@ export class BlockListBlock extends Component {
this.node = findDOMNode( node );
}

/**
* When a block becomces selected, transition focus to an inner tabbable.
*/
focusTabbable() {
const { initialPosition } = this.props;

if ( this.node.contains( document.activeElement ) ) {
return;
}

// Find all tabbables within node.
const tabbables = focus.tabbable.find( this.node );

// If reversed (e.g. merge via backspace), use the last in the set of
// tabbables.
const isReverse = -1 === initialPosition;
const target = ( isReverse ? last : first )( tabbables );

if ( ! target ) {
return;
}

target.focus();

// In reverse case, need to explicitly place caret position.
if ( isReverse ) {
// Special case RichText component because the placeCaret utilities
// aren't working correctly. When merging two paragraph blocks, the
// focus is not moved to the correct position.
const editor = tinymce.get( target.getAttribute( 'id' ) );
if ( editor ) {
editor.selection.select( editor.getBody(), true );
editor.selection.collapse( false );
} else {
placeCaretAtHorizontalEdge( target, true );
placeCaretAtVerticalEdge( target, true );
}
}
}

setAttributes( attributes ) {
const { block, onChange } = this.props;
const type = getBlockType( block.name );
Expand Down Expand Up @@ -625,6 +679,7 @@ const mapStateToProps = ( state, { uid, rootUID } ) => {
mode: getBlockMode( state, uid ),
isSelectionEnabled: isSelectionEnabled( state ),
postType: getCurrentPostType( state ),
initialPosition: getSelectedBlocksInitialCaretPosition( state ),
isSelected,
};
};
Expand Down
42 changes: 0 additions & 42 deletions editor/components/writing-flow/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import { connect } from 'react-redux';
import 'element-closest';
import { find, last, reverse, get } from 'lodash';
import tinymce from 'tinymce';

/**
* WordPress dependencies
Expand All @@ -29,7 +28,6 @@ import {
getMultiSelectedBlocksStartUid,
getMultiSelectedBlocks,
getSelectedBlock,
getSelectedBlocksInitialCaretPosition,
} from '../../store/selectors';
import {
multiSelect,
Expand Down Expand Up @@ -110,19 +108,6 @@ class WritingFlow extends Component {
} );
}

getInnerTabbable( target, isReverse ) {
let focusableNodes = this.getVisibleTabbables();
if ( isReverse ) {
focusableNodes = reverse( focusableNodes );
}

const innerItem = find( focusableNodes, ( node ) => {
return target !== node && target.contains( node );
} );

return innerItem ? innerItem : target;
}

isInLastNonEmptyBlock( target ) {
const tabbables = this.getVisibleTabbables();

Expand Down Expand Up @@ -252,32 +237,6 @@ class WritingFlow extends Component {
}
}

componentDidUpdate( prevProps ) {
// When selecting a new block, we focus its first editable or the container
if (
this.props.selectedBlockUID &&
( ! prevProps.selectedBlockUID || this.props.selectedBlockUID !== prevProps.selectedBlockUID )
) {
const blockContainer = this.container.querySelector( `[data-block="${ this.props.selectedBlockUID }"]` );
if ( blockContainer && ! blockContainer.contains( document.activeElement ) ) {
const target = this.getInnerTabbable( blockContainer, this.props.initialPosition === -1 );
target.focus();
if ( this.props.initialPosition === -1 ) {
// Special casing RichText components because the two functions at the bottom are not working as expected.
// When merging two sibling paragraph blocks (backspacing) the focus is not moved to the right position.
const editor = tinymce.get( target.getAttribute( 'id' ) );
if ( editor ) {
editor.selection.select( editor.getBody(), true );
editor.selection.collapse( false );
} else {
placeCaretAtHorizontalEdge( target, true );
placeCaretAtVerticalEdge( target, true );
}
}
}
}
}

render() {
const { children } = this.props;

Expand All @@ -304,7 +263,6 @@ export default connect(
selectionStart: getMultiSelectedBlocksStartUid( state ),
hasMultiSelection: getMultiSelectedBlocks( state ).length > 1,
selectedBlockUID: get( getSelectedBlock( state ), [ 'uid' ] ),
initialPosition: getSelectedBlocksInitialCaretPosition( state ),
} ),
{
onMultiSelect: multiSelect,
Expand Down

0 comments on commit 7e26164

Please sign in to comment.