Skip to content

Commit

Permalink
Writing Flow: Consider horizontal handled by stopPropagation in RichText
Browse files Browse the repository at this point in the history
  • Loading branch information
aduth committed May 11, 2018
1 parent d70ec18 commit 2512df9
Showing 1 changed file with 70 additions and 7 deletions.
77 changes: 70 additions & 7 deletions editor/components/rich-text/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,27 @@ import { EVENTS } from './constants';
import { withBlockEditContext } from '../block-edit/context';
import { domToFormat, valueToString } from './format';

const { BACKSPACE, DELETE, ENTER, rawShortcut } = keycodes;
/**
* Browser dependencies
*/

const { Node } = window;

/**
* Module constants
*/

const { LEFT, RIGHT, BACKSPACE, DELETE, ENTER, rawShortcut } = keycodes;

/**
* Zero-width space character used by TinyMCE as a caret landing point for
* inline boundary nodes.
*
* @see tinymce/src/core/main/ts/text/Zwsp.ts
*
* @type {string}
*/
const TINYMCE_ZWSP = '\uFEFF';

/**
* Returns true if the node is the inline node boundary. This is used in node
Expand All @@ -61,7 +81,7 @@ const { BACKSPACE, DELETE, ENTER, rawShortcut } = keycodes;
*/
export function isEmptyInlineBoundary( node ) {
const text = node.nodeName === 'A' ? node.innerText : node.textContent;
return text === '\uFEFF';
return text === TINYMCE_ZWSP;
}

/**
Expand Down Expand Up @@ -114,6 +134,7 @@ export class RichText extends Component {
this.onChange = this.onChange.bind( this );
this.onNewBlock = this.onNewBlock.bind( this );
this.onNodeChange = this.onNodeChange.bind( this );
this.onHorizontalNavigationKeyDown = this.onHorizontalNavigationKeyDown.bind( this );
this.onKeyDown = this.onKeyDown.bind( this );
this.onKeyUp = this.onKeyUp.bind( this );
this.changeFormats = this.changeFormats.bind( this );
Expand Down Expand Up @@ -438,27 +459,64 @@ export class RichText extends Component {
left: position.left - containerPosition.left + ( position.width / 2 ) + toolbarOffset.left,
};
}
/**
* Handles a horizontal navigation key down event to stop propagation if it
* can be inferred that it will be handled by TinyMCE (notably transitions
* out of an inline boundary node).
*
* @param {KeyboardEvent} event Keydown event.
*/
onHorizontalNavigationKeyDown( event ) {
const { focusNode, focusOffset } = window.getSelection();
const { nodeType, nodeValue } = focusNode;

if ( nodeType !== Node.TEXT_NODE ) {
return;
}

const isReverse = event.keyCode === LEFT;

let offset = focusOffset;
if ( isReverse ) {
offset--;
}

// [WORKAROUND]: When in a new paragraph in a new inline boundary node,
// while typing the zero-width space occurs as the first child instead
// of at the end of the inline boundary where the caret is. This should
// only be exempt when focusNode is not _only_ the ZWSP, which occurs
// when caret is placed on the right outside edge of inline boundary.
if ( ! isReverse && focusOffset === nodeValue.length &&
nodeValue.length > 1 && nodeValue[ 0 ] === TINYMCE_ZWSP ) {
offset = 0;
}

if ( nodeValue[ offset ] === TINYMCE_ZWSP ) {
event.stopPropagation();
}
}

/**
* Handles a keydown event from tinyMCE.
*
* @param {KeydownEvent} event The keydow event as triggered by tinyMCE.
* @param {KeyboardEvent} event Keydown event.
*/
onKeyDown( event ) {
const dom = this.editor.dom;
const rootNode = this.editor.getBody();
const { keyCode } = event;

if (
( event.keyCode === BACKSPACE && isHorizontalEdge( rootNode, true ) ) ||
( event.keyCode === DELETE && isHorizontalEdge( rootNode, false ) )
( keyCode === BACKSPACE && isHorizontalEdge( rootNode, true ) ) ||
( keyCode === DELETE && isHorizontalEdge( rootNode, false ) )
) {
if ( ! this.props.onMerge && ! this.props.onRemove ) {
return;
}

this.onCreateUndoLevel();

const forward = event.keyCode === DELETE;
const forward = keyCode === DELETE;

if ( this.props.onMerge ) {
this.props.onMerge( forward );
Expand All @@ -476,9 +534,14 @@ export class RichText extends Component {
event.stopImmediatePropagation();
}

const isHorizontalNavigation = keyCode === LEFT || keyCode === RIGHT;
if ( isHorizontalNavigation ) {
this.onHorizontalNavigationKeyDown( event );
}

// If we click shift+Enter on inline RichTexts, we avoid creating two contenteditables
// We also split the content and call the onSplit prop if provided.
if ( event.keyCode === ENTER ) {
if ( keyCode === ENTER ) {
if ( this.props.multiline ) {
if ( ! this.props.onSplit ) {
return;
Expand Down

0 comments on commit 2512df9

Please sign in to comment.