Skip to content

Commit

Permalink
Rich text: fix internal paste across multiline and single line instan…
Browse files Browse the repository at this point in the history
…ces (#35416)
  • Loading branch information
ellatrix authored and adamziel committed Oct 13, 2021
1 parent 4f3fb2b commit 7a14caf
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 14 deletions.
42 changes: 30 additions & 12 deletions packages/block-editor/src/components/rich-text/use-paste-handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,25 @@ import { filePasteHandler } from './file-paste-handler';
import { addActiveFormats, isShortcode } from './utils';
import { splitValue } from './split-value';

/** @typedef {import('@wordpress/rich-text').RichTextValue} RichTextValue */

/**
* Replaces line separators with line breaks if not multiline.
* Replaces line breaks with line separators if multiline.
*
* @param {RichTextValue} value Value to adjust.
* @param {boolean} isMultiline Whether to adjust to multiline or not.
*
* @return {RichTextValue} Adjusted value.
*/
function adjustLines( value, isMultiline ) {
if ( isMultiline ) {
return replace( value, /\n+/g, LINE_SEPARATOR );
}

return replace( value, new RegExp( LINE_SEPARATOR, 'g' ), '\n' );
}

export function usePasteHandler( props ) {
const propsRef = useRef( props );
propsRef.current = props;
Expand Down Expand Up @@ -110,13 +129,19 @@ export function usePasteHandler( props ) {
// without filtering the data. The filters are only meant for externally
// pasted content and remove inline styles.
if ( isInternal ) {
const pastedValue = create( {
const pastedMultilineTag =
clipboardData.getData( 'rich-text-multi-line-tag' ) ||
undefined;
let pastedValue = create( {
html,
multilineTag,
multilineTag: pastedMultilineTag,
multilineWrapperTags:
multilineTag === 'li' ? [ 'ul', 'ol' ] : undefined,
pastedMultilineTag === 'li'
? [ 'ul', 'ol' ]
: undefined,
preserveWhiteSpace,
} );
pastedValue = adjustLines( pastedValue, !! multilineTag );
addActiveFormats( pastedValue, value.activeFormats );
onChange( insert( value, pastedValue ) );
return;
Expand Down Expand Up @@ -190,18 +215,11 @@ export function usePasteHandler( props ) {
if ( typeof content === 'string' ) {
let valueToInsert = create( { html: content } );

addActiveFormats( valueToInsert, value.activeFormats );

// If the content should be multiline, we should process text
// separated by a line break as separate lines.
if ( multilineTag ) {
valueToInsert = replace(
valueToInsert,
/\n+/g,
LINE_SEPARATOR
);
}
valueToInsert = adjustLines( valueToInsert, !! multilineTag );

addActiveFormats( valueToInsert, value.activeFormats );
onChange( insert( value, valueToInsert ) );
} else if ( content.length > 0 ) {
if ( onReplace && isEmpty( value ) ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,26 @@ exports[`RichText should only mutate text data on input 1`] = `
<!-- /wp:paragraph -->"
`;

exports[`RichText should paste list contents into paragraph 1`] = `
"<!-- wp:list -->
<ul><li>1<ul><li>2</li></ul></li></ul>
<!-- /wp:list -->
<!-- wp:paragraph -->
<p>1<br>2</p>
<!-- /wp:paragraph -->"
`;
exports[`RichText should paste paragraph contents into list 1`] = `
"<!-- wp:paragraph -->
<p>1<br>2</p>
<!-- /wp:paragraph -->
<!-- wp:list -->
<ul><li>1</li><li>2</li></ul>
<!-- /wp:list -->"
`;
exports[`RichText should preserve internal formatting 1`] = `
"<!-- wp:paragraph -->
<p><mark style=\\"background-color:rgba(0, 0, 0, 0)\\" class=\\"has-inline-color has-cyan-bluish-gray-color\\">1</mark></p>
Expand Down
52 changes: 51 additions & 1 deletion packages/e2e-tests/specs/editor/various/rich-text.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -410,7 +410,7 @@ describe( 'RichText', () => {
// Copy the colored text.
await pressKeyWithModifier( 'primary', 'c' );

// Collapsed the selection to the end.
// Collapse the selection to the end.
await page.keyboard.press( 'ArrowRight' );

// Create a new paragraph.
Expand All @@ -422,6 +422,56 @@ describe( 'RichText', () => {
expect( await getEditedPostContent() ).toMatchSnapshot();
} );

it( 'should paste paragraph contents into list', async () => {
await clickBlockAppender();

// Create two lines of text in a paragraph.
await page.keyboard.type( '1' );
await pressKeyWithModifier( 'shift', 'Enter' );
await page.keyboard.type( '2' );

// Select all and copy.
await pressKeyWithModifier( 'primary', 'a' );
await pressKeyWithModifier( 'primary', 'c' );

// Collapse the selection to the end.
await page.keyboard.press( 'ArrowRight' );

// Create a list.
await page.keyboard.press( 'Enter' );
await page.keyboard.type( '* ' );

// Paste paragraph contents.
await pressKeyWithModifier( 'primary', 'v' );

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

it( 'should paste list contents into paragraph', async () => {
await clickBlockAppender();

// Create an indented list of two lines.
await page.keyboard.type( '* 1' );
await page.keyboard.press( 'Enter' );
await page.keyboard.type( ' 2' );

// Select all and copy.
await pressKeyWithModifier( 'primary', 'a' );
await pressKeyWithModifier( 'primary', 'c' );

// Collapse the selection to the end.
await page.keyboard.press( 'ArrowRight' );

// Create a paragraph.
await page.keyboard.press( 'Enter' );
await page.keyboard.press( 'Enter' );

// Paste paragraph contents.
await pressKeyWithModifier( 'primary', 'v' );

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

it( 'should navigate arround emoji', async () => {
await clickBlockAppender();
await page.keyboard.type( '🍓' );
Expand Down
4 changes: 4 additions & 0 deletions packages/rich-text/src/component/use-copy-handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ export function useCopyHandler( props ) {
event.clipboardData.setData( 'text/plain', plainText );
event.clipboardData.setData( 'text/html', html );
event.clipboardData.setData( 'rich-text', 'true' );
event.clipboardData.setData(
'rich-text-multi-line-tag',
multilineTag || ''
);
event.preventDefault();
}

Expand Down
2 changes: 1 addition & 1 deletion packages/rich-text/src/create.js
Original file line number Diff line number Diff line change
Expand Up @@ -511,7 +511,7 @@ function createFromElement( {
* multiline.
* @param {Array} [$1.multilineWrapperTags] Tags where lines can be found if
* nesting is possible.
* @param {boolean} [$1.currentWrapperTags] Whether to prepend a line
* @param {Array} [$1.currentWrapperTags] Whether to prepend a line
* separator.
* @param {boolean} [$1.preserveWhiteSpace] Whether or not to collapse white
* space characters.
Expand Down

0 comments on commit 7a14caf

Please sign in to comment.