diff --git a/packages/editor/src/components/rich-text/style.scss b/packages/editor/src/components/rich-text/style.scss index b4ebf2b4b8c69f..28e27be386047f 100644 --- a/packages/editor/src/components/rich-text/style.scss +++ b/packages/editor/src/components/rich-text/style.scss @@ -8,6 +8,16 @@ margin: 0; position: relative; line-height: $editor-line-height; + // In HTML, leading and trailing spaces are not visible, and multiple spaces + // elsewhere are visually reduced to one space. This rule prevents spaces + // from collapsing so all space is visible in the editor and can be removed. + // It also prevents some browsers from inserting non-breaking spaces at the + // end of a line to prevent the space from visually disappearing. Sometimes + // these non breaking spaces can linger in the editor causing unwanted non + // breaking spaces in between words. If also prevent Firefox from inserting + // a trailing `br` node to visualise any trailing space, causing the element + // to be saved. + white-space: pre-wrap; > p:empty { min-height: $editor-font-size * $editor-line-height; diff --git a/packages/rich-text/src/create.js b/packages/rich-text/src/create.js index fdbbde943aef1a..c45d20ce088be0 100644 --- a/packages/rich-text/src/create.js +++ b/packages/rich-text/src/create.js @@ -297,11 +297,10 @@ function createFromElement( { const length = element.childNodes.length; - // Remove any line breaks in text nodes. They are not content, but used to - // format the HTML. Line breaks in HTML are stored as BR elements. - // See https://www.w3.org/TR/html5/syntax.html#newlines. const filterStringComplete = ( string ) => { - string = string.replace( /[\r\n]/g, '' ); + // Reduce any whitespace used for HTML formatting to one space + // character, because it will also be displayed as such by the browser. + string = string.replace( /[\n\r\t]+/g, ' ' ); if ( filterString ) { string = filterString( string ); diff --git a/packages/rich-text/src/test/__snapshots__/to-dom.js.snap b/packages/rich-text/src/test/__snapshots__/to-dom.js.snap index ce980dcd7589b7..0153822ba7ca8c 100644 --- a/packages/rich-text/src/test/__snapshots__/to-dom.js.snap +++ b/packages/rich-text/src/test/__snapshots__/to-dom.js.snap @@ -317,13 +317,6 @@ exports[`recordToDom should ignore formats at line separator 1`] = ` `; -exports[`recordToDom should ignore line breaks to format HTML 1`] = ` - - -
- -`; - exports[`recordToDom should preserve emoji 1`] = ` 🍒 @@ -339,6 +332,12 @@ exports[`recordToDom should preserve emoji in formatting 1`] = ` `; +exports[`recordToDom should preserve non breaking space 1`] = ` + + test  test + +`; + exports[`recordToDom should remove br with settings 1`] = ` @@ -359,6 +358,12 @@ exports[`recordToDom should remove with settings 1`] = ` `; +exports[`recordToDom should replace characters to format HTML with space 1`] = ` + + + +`; + exports[`recordToDom should unwrap with settings 1`] = ` te diff --git a/packages/rich-text/src/test/helpers/index.js b/packages/rich-text/src/test/helpers/index.js index 0b4a7b6e64b704..9673619d57be2e 100644 --- a/packages/rich-text/src/test/helpers/index.js +++ b/packages/rich-text/src/test/helpers/index.js @@ -29,8 +29,8 @@ export const spec = [ }, }, { - description: 'should ignore line breaks to format HTML', - html: '\n\n\r\n', + description: 'should replace characters to format HTML with space', + html: '\n\n\r\n\t', createRange: ( element ) => ( { startOffset: 0, startContainer: element, @@ -38,12 +38,30 @@ export const spec = [ endContainer: element, } ), startPath: [ 0, 0 ], - endPath: [ 0, 0 ], + endPath: [ 0, 1 ], record: { start: 0, - end: 0, - formats: [], - text: '', + end: 1, + formats: [ , ], + text: ' ', + }, + }, + { + description: 'should preserve non breaking space', + html: 'test\u00a0 test', + createRange: ( element ) => ( { + startOffset: 5, + startContainer: element.firstChild, + endOffset: 5, + endContainer: element.firstChild, + } ), + startPath: [ 0, 5 ], + endPath: [ 0, 5 ], + record: { + start: 5, + end: 5, + formats: [ , , , , , , , , , , ], + text: 'test\u00a0 test', }, }, { diff --git a/test/e2e/specs/__snapshots__/links.test.js.snap b/test/e2e/specs/__snapshots__/links.test.js.snap index be47f91e158f99..7dd818ef95d1c3 100644 --- a/test/e2e/specs/__snapshots__/links.test.js.snap +++ b/test/e2e/specs/__snapshots__/links.test.js.snap @@ -20,7 +20,7 @@ exports[`Links can be created instantly when a URL is selected 1`] = ` exports[`Links can be created without any text selected 1`] = ` " -

This is Gutenberg: https://wordpress.org/gutenberg

+

This is Gutenberg: https://wordpress.org/gutenberg

" `; diff --git a/test/e2e/specs/__snapshots__/rich-text.test.js.snap b/test/e2e/specs/__snapshots__/rich-text.test.js.snap index e1324add1205e7..e911f407edd680 100644 --- a/test/e2e/specs/__snapshots__/rich-text.test.js.snap +++ b/test/e2e/specs/__snapshots__/rich-text.test.js.snap @@ -2,7 +2,7 @@ exports[`RichText should apply formatting when selection is collapsed 1`] = ` " -

Some bold.

+

Some bold.

" `; diff --git a/test/e2e/specs/__snapshots__/undo.test.js.snap b/test/e2e/specs/__snapshots__/undo.test.js.snap index 1ae6c8e4458b79..49a8c19fe89fae 100644 --- a/test/e2e/specs/__snapshots__/undo.test.js.snap +++ b/test/e2e/specs/__snapshots__/undo.test.js.snap @@ -28,12 +28,12 @@ exports[`undo should undo typing after a pause 2`] = ` exports[`undo should undo typing after non input change 1`] = ` " -

before keyboard after keyboard

+

before keyboard after keyboard

" `; exports[`undo should undo typing after non input change 2`] = ` " -

before keyboard 

+

before keyboard

" `; diff --git a/test/e2e/specs/__snapshots__/writing-flow.test.js.snap b/test/e2e/specs/__snapshots__/writing-flow.test.js.snap index 77e8a9596b7729..a33dda228193e8 100644 --- a/test/e2e/specs/__snapshots__/writing-flow.test.js.snap +++ b/test/e2e/specs/__snapshots__/writing-flow.test.js.snap @@ -124,7 +124,7 @@ exports[`adding blocks should navigate around inline boundaries 1`] = ` exports[`adding blocks should not delete surrounding space when deleting a selected word 1`] = ` " -

alpha  gamma

+

alpha gamma

" `; @@ -136,7 +136,7 @@ exports[`adding blocks should not delete surrounding space when deleting a selec exports[`adding blocks should not delete surrounding space when deleting a word with Alt+Backspace 1`] = ` " -

alpha  gamma

+

alpha gamma

" `; @@ -148,7 +148,7 @@ exports[`adding blocks should not delete surrounding space when deleting a word exports[`adding blocks should not delete surrounding space when deleting a word with Backspace 1`] = ` " -

1  3

+

1 3

" `; diff --git a/test/e2e/specs/adding-inline-tokens.test.js b/test/e2e/specs/adding-inline-tokens.test.js index 00fa8c45869d3c..d1504f7e35eb7d 100644 --- a/test/e2e/specs/adding-inline-tokens.test.js +++ b/test/e2e/specs/adding-inline-tokens.test.js @@ -44,7 +44,7 @@ describe( 'adding inline tokens', () => { await page.click( '.media-modal button.media-button-select' ); // Check the content. - const regex = new RegExp( `\\s*

a\\u00A0<\\/p>\\s*` ); + const regex = new RegExp( `\\s*

a <\\/p>\\s*` ); expect( await getEditedPostContent() ).toMatch( regex ); } ); } );