From 393f5baa1cb640ea142c70458fdd22b8d8d2334e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ella=20Van=C2=A0Dorpe?= Date: Tue, 30 Oct 2018 17:51:04 +0100 Subject: [PATCH] RichText: fix format placeholder (#11102) * Fix format placeholder * Unduplicate logic --- packages/rich-text/src/apply-format.js | 18 ++++++++------ packages/rich-text/src/test/apply-format.js | 12 +++++----- packages/rich-text/src/to-dom.js | 1 + packages/rich-text/src/to-tree.js | 24 ++++++++++++++++++- .../__snapshots__/rich-text.test.js.snap | 6 +++++ test/e2e/specs/rich-text.test.js | 13 ++++++++++ 6 files changed, 60 insertions(+), 14 deletions(-) diff --git a/packages/rich-text/src/apply-format.js b/packages/rich-text/src/apply-format.js index ebdf6ecaecfea3..7580ebaee2086a 100644 --- a/packages/rich-text/src/apply-format.js +++ b/packages/rich-text/src/apply-format.js @@ -2,15 +2,13 @@ * External dependencies */ -import { find, reject } from 'lodash'; +import { find } from 'lodash'; /** * Internal dependencies */ import { normaliseFormats } from './normalise-formats'; -import { insert } from './insert'; -import { ZERO_WIDTH_NO_BREAK_SPACE } from './special-characters'; /** * Apply a format object to a Rich Text value from the given `startIndex` to the @@ -56,10 +54,16 @@ export function applyFormat( const previousFormat = newFormats[ startIndex - 1 ] || []; const hasType = find( previousFormat, { type: format.type } ); - return insert( { formats, text, start, end }, { - formats: hasType ? [ reject( previousFormat, { type: format.type } ) ] : [ [ ...previousFormat, format ] ], - text: ZERO_WIDTH_NO_BREAK_SPACE, - } ); + return { + formats, + text, + start, + end, + formatPlaceholder: { + index: startIndex, + format: hasType ? undefined : format, + }, + }; } } else { for ( let index = startIndex; index < endIndex; index++ ) { diff --git a/packages/rich-text/src/test/apply-format.js b/packages/rich-text/src/test/apply-format.js index 73416cdb5cfacc..3aa51c927e71c5 100644 --- a/packages/rich-text/src/test/apply-format.js +++ b/packages/rich-text/src/test/apply-format.js @@ -8,7 +8,6 @@ import deepFreeze from 'deep-freeze'; */ import { applyFormat } from '../apply-format'; -import { ZERO_WIDTH_NO_BREAK_SPACE } from '../special-characters'; import { getSparseArrayLength } from './helpers'; describe( 'applyFormat', () => { @@ -61,16 +60,17 @@ describe( 'applyFormat', () => { end: 0, }; const expected = { - formats: [ [ a2 ], , , , , [ a ], [ a ], [ a ], , , , , , , ], - text: `${ ZERO_WIDTH_NO_BREAK_SPACE }one two three`, - start: 1, - end: 1, + ...record, + formatPlaceholder: { + format: a2, + index: 0, + }, }; const result = applyFormat( deepFreeze( record ), a2 ); expect( result ).toEqual( expected ); expect( result ).not.toBe( record ); - expect( getSparseArrayLength( result.formats ) ).toBe( 4 ); + expect( getSparseArrayLength( result.formats ) ).toBe( 3 ); } ); it( 'should apply format on existing format if selection is collapsed', () => { diff --git a/packages/rich-text/src/to-dom.js b/packages/rich-text/src/to-dom.js index 319e8b61ee1377..b5851817b5db7f 100644 --- a/packages/rich-text/src/to-dom.js +++ b/packages/rich-text/src/to-dom.js @@ -159,6 +159,7 @@ export function toDom( { onEndIndex( body, pointer ) { endPath = createPathToNode( pointer, body, [ pointer.nodeValue.length ] ); }, + isEditableTree: true, } ); if ( createLinePadding ) { diff --git a/packages/rich-text/src/to-tree.js b/packages/rich-text/src/to-tree.js index d599db049ff9aa..893b331c44a37e 100644 --- a/packages/rich-text/src/to-tree.js +++ b/packages/rich-text/src/to-tree.js @@ -6,6 +6,7 @@ import { getFormatType } from './get-format-type'; import { LINE_SEPARATOR, OBJECT_REPLACEMENT_CHARACTER, + ZERO_WIDTH_NO_BREAK_SPACE, } from './special-characters'; function fromFormat( { type, attributes, object } ) { @@ -55,8 +56,9 @@ export function toTree( { appendText, onStartIndex, onEndIndex, + isEditableTree, } ) { - const { formats, text, start, end } = value; + const { formats, text, start, end, formatPlaceholder } = value; const formatsLength = formats.length + 1; const tree = createEmpty(); const multilineFormat = { type: multilineTag }; @@ -73,6 +75,22 @@ export function toTree( { append( tree, '' ); } + function setFormatPlaceholder( pointer, index ) { + if ( isEditableTree && formatPlaceholder && formatPlaceholder.index === index ) { + const parent = getParent( pointer ); + + if ( formatPlaceholder.format === undefined ) { + pointer = getParent( parent ); + } else { + pointer = append( parent, fromFormat( formatPlaceholder.format ) ); + } + + pointer = append( pointer, ZERO_WIDTH_NO_BREAK_SPACE ); + } + + return pointer; + } + for ( let i = 0; i < formatsLength; i++ ) { const character = text.charAt( i ); let characterFormats = formats[ i ]; @@ -146,6 +164,8 @@ export function toTree( { continue; } + pointer = setFormatPlaceholder( pointer, 0 ); + // If there is selection at 0, handle it before characters are inserted. if ( i === 0 ) { if ( onStartIndex && start === 0 ) { @@ -169,6 +189,8 @@ export function toTree( { } } + pointer = setFormatPlaceholder( pointer, i + 1 ); + if ( onStartIndex && start === i + 1 ) { onStartIndex( tree, pointer ); } diff --git a/test/e2e/specs/__snapshots__/rich-text.test.js.snap b/test/e2e/specs/__snapshots__/rich-text.test.js.snap index 2ddafbae544f22..fc96d2d6f1fab5 100644 --- a/test/e2e/specs/__snapshots__/rich-text.test.js.snap +++ b/test/e2e/specs/__snapshots__/rich-text.test.js.snap @@ -1,5 +1,11 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`RichText should apply formatting when selection is collapsed 1`] = ` +" +

SomeĀ bold.

+" +`; + exports[`RichText should apply formatting with access shortcut 1`] = ` "

test

diff --git a/test/e2e/specs/rich-text.test.js b/test/e2e/specs/rich-text.test.js index 398196d0a37db7..9203ec32c303dd 100644 --- a/test/e2e/specs/rich-text.test.js +++ b/test/e2e/specs/rich-text.test.js @@ -45,4 +45,17 @@ describe( 'RichText', () => { expect( await getEditedPostContent() ).toMatchSnapshot(); } ); + + it( 'should apply formatting when selection is collapsed', async () => { + await clickBlockAppender(); + await page.keyboard.type( 'Some ' ); + // All following characters should now be bold. + await pressWithModifier( META_KEY, 'b' ); + await page.keyboard.type( 'bold' ); + // All following characters should no longer be bold. + await pressWithModifier( META_KEY, 'b' ); + await page.keyboard.type( '.' ); + + expect( await getEditedPostContent() ).toMatchSnapshot(); + } ); } );