Skip to content

Commit

Permalink
Handle horizontal arrow keys
Browse files Browse the repository at this point in the history
  • Loading branch information
ellatrix committed Aug 10, 2017
1 parent 1487604 commit 8ee9e35
Showing 1 changed file with 118 additions and 49 deletions.
167 changes: 118 additions & 49 deletions editor/modes/visual-editor/block.js
Original file line number Diff line number Diff line change
Expand Up @@ -251,78 +251,147 @@ class VisualEditorBlock extends Component {

onKeyDown( event ) {
const { keyCode, target } = event;
const { previousBlock, nextBlock, onFocus } = this.props;
const up = keyCode === UP;
const down = keyCode === DOWN;
const left = keyCode === LEFT;
const right = keyCode === RIGHT;

const isVerticalEdge = ( { editor, reverse } ) => {
const rangeRect = editor.selection.getBoundingClientRect();
const buffer = rangeRect.height / 2;
const editableRect = editor.getBody().getBoundingClientRect();

// Too low.
if ( reverse && rangeRect.top - buffer > editableRect.top ) {
return false;
}

if ( keyCode === UP || keyCode === DOWN || keyCode === LEFT || keyCode === RIGHT ) {
const direction = keyCode === UP || keyCode === LEFT ? 'previous' : 'next';
const nextBlock = this.node[ `${ direction }Sibling` ];
// Too high.
if ( ! reverse && rangeRect.bottom + buffer < editableRect.bottom ) {
return false;
}

if ( target === this.node ) {
nextBlock.focus();
} else if ( keyCode === UP || keyCode === DOWN ) {
const selection = window.getSelection();
const range = selection.rangeCount ? selection.getRangeAt( 0 ) : null;
return rangeRect;
};

if ( ! range ) {
return;
}
const isHorizontalEdge = ( { editor, reverse } ) => {
const position = reverse ? 'start' : 'end';
const order = reverse ? 'first' : 'last';
const range = editor.selection.getRng();
const offset = range[ `${ position }Offset` ];
const rootNode = editor.getBody();
let node = range.startContainer;

const rects = range.getClientRects();
if ( ! range.collapsed ) {
return false;
}

if ( ! rects.length ) {
return;
}
if ( reverse && offset !== 0 ) {
return false;
}

const rangeRect = rects[ 0 ];
const buffer = rangeRect.height / 2;
const editableRect = target.getBoundingClientRect();
if ( ! reverse && offset !== node.data.length ) {
return false;
}

// Too low.
if ( keyCode === UP && rangeRect.top - buffer > editableRect.top ) {
return;
}
while ( node !== rootNode ) {
const parentNode = node.parentNode;

// Too high.
if ( keyCode === DOWN && rangeRect.bottom + buffer < editableRect.bottom ) {
return;
if ( parentNode[ `${ order }Child` ] !== node ) {
return false;
}

const selector = '.editor-visual-editor [contenteditable="true"]';
const editableNodes = Array.from( document.querySelectorAll( selector ) );
node = parentNode;
}

if ( keyCode === UP ) {
editableNodes.reverse();
}
return true;
};

const index = editableNodes.indexOf( target );
const nextEditableNode = editableNodes[ index + 1 ];
const getNextEditor = ( { node, reverse } ) => {
const selector = '.editor-visual-editor [contenteditable="true"]';
const editableNodes = Array.from( document.querySelectorAll( selector ) );

if ( ! nextBlock ) {
return;
}
if ( reverse ) {
editableNodes.reverse();
}

event.preventDefault();
const index = editableNodes.indexOf( target );
const nextEditableNode = editableNodes[ index + 1 ];
const direction = reverse ? 'previous' : 'next';
const nextBlockNode = node[ `${ direction }Sibling` ];

if ( ! nextEditableNode ) {
nextBlock.focus();
return;
if ( ! nextBlockNode || ! nextEditableNode ) {
return;
}

const editor = tinymce.get( nextEditableNode.id );

if ( ! editor ) {
return;
}

if ( ! node.contains( nextEditableNode ) && ! nextBlockNode.contains( nextEditableNode ) ) {
return;
}

return editor;
};

if ( up || down || left || right ) {
const editor = target.id && tinymce.get( target.id );

if ( target === this.node ) {
const reverse = up || left;
const followingBlock = reverse ? previousBlock : nextBlock;

if ( followingBlock ) {
event.preventDefault();
onFocus( followingBlock.uid, { offset: reverse ? -1 : 0 } );
}
}

if ( editor ) {
const reverse = up || left;
const horizontal = left || right;
const followingBlock = reverse ? previousBlock : nextBlock;

const rect = horizontal ?
isHorizontalEdge( { editor, reverse } ) :
isVerticalEdge( { editor, reverse } );

if ( ! this.node.contains( nextEditableNode ) && ! nextBlock.contains( nextEditableNode ) ) {
nextBlock.focus();
if ( ! rect ) {
return;
}

const editor = tinymce.get( nextEditableNode.id );
event.preventDefault();

editor.focus();
const followingEditor = getNextEditor( { node: this.node, reverse } );

window.setTimeout( () => {
const nextEditableRect = nextEditableNode.getBoundingClientRect();
const x = rangeRect.left;
const y = keyCode === UP ? nextEditableRect.bottom - buffer : nextEditableRect.top + buffer;
if ( ! followingEditor ) {
if ( followingBlock ) {
onFocus( followingBlock.uid, { offset: reverse ? -1 : 0 } );
}

editor.selection.placeCaretAt( x, y );
} );
return;
}

followingEditor.focus();

if ( horizontal ) {
if ( reverse ) {
followingEditor.selection.select( followingEditor.getBody(), true );
followingEditor.selection.collapse( false );
}
} else {
window.setTimeout( () => {
const buffer = rect.height / 2;
const editorRect = followingEditor.getBody().getBoundingClientRect();
const y = reverse ? editorRect.bottom - buffer : editorRect.top + buffer;

followingEditor.selection.placeCaretAt( rect.left, y );
} );
}
}
}

Expand Down

0 comments on commit 8ee9e35

Please sign in to comment.