Skip to content

Commit

Permalink
Writing Flow: Test horizontal navigation as handled
Browse files Browse the repository at this point in the history
Specifically for TinyMCE's overrides on inline boundary traversal
  • Loading branch information
aduth committed May 3, 2018
1 parent 6dd05fc commit 291c19c
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 2 deletions.
38 changes: 37 additions & 1 deletion editor/components/writing-flow/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,41 @@ const isTabbableTextField = overEvery( [
focus.tabbable.isTabbableIndex,
] );

/**
* Returns true if the given node is a TinyMCE inline boundary node.
*
* @param {Node} node Node to test.
*
* @return {boolean} Whether node is a TinyMCE inline boundary node.
*/
function isInlineBoundary( node ) {
return node.getAttribute( 'data-mce-selected' ) === 'inline-boundary';
}

/**
* Returns true if it can be inferred that horizontal navigation has already
* been handled in the desired direction, or false otherwise. Specifically,
* this accounts for TinyMCE's inline boundary traversal, where its keydown
* event takes effect before the event propagates to WritingFlow. This avoids
* the caret from being moved outside the block when inline boundary occurs at
* the end of a RichText.
*
* @see tinymce/src/core/main/ts/keyboard/ArrowKeys.ts (executeKeydownOverride)
*
* @param {boolean} isReverse Whether to test in reverse.
*
* @return {boolean} Whether horizontal navigation has been handled.
*/
function isHorizontalNavigationHandled( isReverse ) {
const { isCollapsed, focusNode } = getSelection();
if ( ! isCollapsed ) {
return false;
}

const siblingNode = focusNode[ isReverse ? 'nextSibling' : 'previousSibling' ];
return !! siblingNode && isInlineBoundary( siblingNode );
}

class WritingFlow extends Component {
constructor() {
super( ...arguments );
Expand Down Expand Up @@ -217,7 +252,8 @@ class WritingFlow extends Component {
placeCaretAtVerticalEdge( closestTabbable, isReverse, this.verticalRect );
event.preventDefault();
}
} else if ( isHorizontal && getSelection().isCollapsed && isHorizontalEdge( target, isReverse ) ) {
} else if ( isHorizontal && getSelection().isCollapsed &&
! isHorizontalNavigationHandled( isReverse ) && isHorizontalEdge( target, isReverse ) ) {
const closestTabbable = this.getClosestTabbable( target, isReverse );
placeCaretAtHorizontalEdge( closestTabbable, isReverse );
event.preventDefault();
Expand Down
22 changes: 22 additions & 0 deletions test/e2e/specs/__snapshots__/writing-flow.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,25 @@ exports[`adding blocks Should navigate with arrow keys 5`] = `"The Greeting: <br
exports[`adding blocks Should navigate with arrow keys 6`] = `"Prefix: Hello"`;
exports[`adding blocks Should navigate with arrow keys 7`] = `"The Greeting: <br>Hello to the World! (Suffix)"`;
exports[`adding blocks Should navigate with arrow keys 8`] = `"<span id=\\"_mce_caret\\" data-mce-bogus=\\"1\\"><strong data-mce-selected=\\"inline-boundary\\">Bolded</strong></span><br data-mce-bogus=\\"1\\">"`;
exports[`adding blocks Should navigate with arrow keys 9`] = `"<strong data-mce-selected=\\"inline-boundary\\">Bolded Words</strong><br data-mce-bogus=\\"1\\">"`;
exports[`adding blocks Should navigate with arrow keys 10`] = `"<strong>Bolded Words</strong>After<br data-mce-bogus=\\"1\\">"`;
exports[`adding blocks Should navigate with arrow keys 11`] = `"The Greeting: <br>Hello to the World! (Suffixed)"`;
exports[`adding blocks Should navigate with arrow keys 12`] = `
"<!-- wp:paragraph -->
<p>The Greeting: <br/>Hello to the World! (Suffixed)</p>
<!-- /wp:paragraph -->
<!-- wp:paragraph -->
<p><strong>Bolded Words</strong>After</p>
<!-- /wp:paragraph -->
<!-- wp:paragraph -->
<p>Prefix: Hello</p>
<!-- /wp:paragraph -->"
`;
38 changes: 37 additions & 1 deletion test/e2e/specs/writing-flow.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@ import { times } from 'lodash';
* Internal dependencies
*/
import '../support/bootstrap';
import { newPost, newDesktopBrowserPage, pressWithModifier } from '../support/utils';
import {
newPost,
newDesktopBrowserPage,
pressWithModifier,
getHTMLFromCodeEditor,
} from '../support/utils';

describe( 'adding blocks', () => {
beforeAll( async () => {
Expand Down Expand Up @@ -111,5 +116,36 @@ describe( 'adding blocks', () => {
await page.keyboard.up( 'Shift' );
await page.keyboard.type( ' (Suffix)' );
await expectParagraphToMatchSnapshot( 1 );

// Should arrow once to escape out of inline boundary (bold, etc), and
// escaping out should nullify any block traversal.
await page.keyboard.press( 'Enter' );
await pressWithModifier( 'Mod', 'B' ); // Bold
await page.keyboard.type( 'Bolded' );
await expectParagraphToMatchSnapshot( 2 );

// Pressing space while having escaped on right edge of inline boundary
// should continue text as bolded.
await page.keyboard.press( 'ArrowRight' );
await page.keyboard.type( ' Words' );
await expectParagraphToMatchSnapshot( 2 );

// But typing immediately after escaping should not be within.
await page.keyboard.press( 'ArrowRight' );
await page.keyboard.type( 'After' );
await expectParagraphToMatchSnapshot( 2 );

// Navigate back to previous block. Change "(Suffix)" to "(Suffixed)"
//
// "Bolded WordsAfter" = 17 characters
// + 2 inline boundaries
// + 1 horizontal block traversal
// + 1 into parenthesis
// = 21
await promiseSequence( times( 21, () => () => page.keyboard.press( 'ArrowLeft' ) ) );
await page.keyboard.type( 'ed' );
await expectParagraphToMatchSnapshot( 1 );

expect( await getHTMLFromCodeEditor() ).toMatchSnapshot();
} );
} );

0 comments on commit 291c19c

Please sign in to comment.