Skip to content

Commit

Permalink
Copy plain text variant of blocks (#41366)
Browse files Browse the repository at this point in the history
* copy plain text into the clipboard by stripping HTML from serialized block data

* rename the copy block data menu item to hopefully stress that the block markup is copied as well

* edit block tool copy and more tools copy to refer to block

* mend

* mend

* mend

* Handle BR tags and trim whitespace when producing plain text

* use `_n` for plural of block

Co-authored-by: Miguel Fonseca <[email protected]>

* import _n

* update snapshot with lesst newlines

Co-authored-by: Miguel Fonseca <[email protected]>
  • Loading branch information
draganescu and mcsf authored Jun 15, 2022
1 parent a8c8b14 commit 6f3bb8c
Show file tree
Hide file tree
Showing 8 changed files with 80 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
useCallback,
useRef,
} from '@wordpress/element';
import { __, sprintf } from '@wordpress/i18n';
import { __, _n, sprintf } from '@wordpress/i18n';
import { store as keyboardShortcutsStore } from '@wordpress/keyboard-shortcuts';
import { useCopyToClipboard } from '@wordpress/compose';

Expand All @@ -42,7 +42,8 @@ const POPOVER_PROPS = {

function CopyMenuItem( { blocks, onCopy } ) {
const ref = useCopyToClipboard( () => serialize( blocks ), onCopy );
return <MenuItem ref={ ref }>{ __( 'Copy' ) }</MenuItem>;
const copyMenuItemLabel = _n( 'Copy block', 'Copy blocks', blocks.length );
return <MenuItem ref={ ref }>{ copyMenuItemLabel }</MenuItem>;
}

export function BlockSettingsDropdown( {
Expand Down
9 changes: 7 additions & 2 deletions packages/block-editor/src/components/copy-handler/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,13 @@ Concretely, it handles the display of success messages and takes care of copying

## Table of contents

1. [Development guidelines](#development-guidelines)
2. [Related components](#related-components)
- [Copy Handler](#copy-handler)
- [Table of contents](#table-of-contents)
- [Development guidelines](#development-guidelines)
- [Usage](#usage)
- [Props](#props)
- [`children`](#children)
- [Related components](#related-components)

## Development guidelines

Expand Down
23 changes: 22 additions & 1 deletion packages/block-editor/src/components/copy-handler/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
import {
documentHasSelection,
documentHasUncollapsedSelection,
__unstableStripHTML as stripHTML,
} from '@wordpress/dom';
import { useDispatch, useSelect } from '@wordpress/data';
import { __, _n, sprintf } from '@wordpress/i18n';
Expand Down Expand Up @@ -156,7 +157,10 @@ export function useClipboardHandler() {
}
const serialized = serialize( blocks );

event.clipboardData.setData( 'text/plain', serialized );
event.clipboardData.setData(
'text/plain',
toPlainText( serialized )
);
event.clipboardData.setData( 'text/html', serialized );
}
}
Expand Down Expand Up @@ -212,6 +216,23 @@ function CopyHandler( { children } ) {
return <div ref={ useClipboardHandler() }>{ children }</div>;
}

/**
* Given a string of HTML representing serialized blocks, returns the plain
* text extracted after stripping the HTML of any tags and fixing line breaks.
*
* @param {string} html Serialized blocks.
* @return {string} The plain-text content with any html removed.
*/
function toPlainText( html ) {
// Manually handle BR tags as line breaks prior to `stripHTML` call
html = html.replace( /<br>/g, '\n' );

const plainText = stripHTML( html ).trim();

// Merge any consecutive line breaks
return plainText.replace( /\n\n+/g, '\n\n' );
}

/**
* @see https://github.com/WordPress/gutenberg/blob/HEAD/packages/block-editor/src/components/copy-handler/README.md
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,5 @@ export default function CopyContentMenuItem() {

const ref = useCopyToClipboard( getText, onSuccess );

return <MenuItem ref={ ref }>{ __( 'Copy all content' ) }</MenuItem>;
return <MenuItem ref={ ref }>{ __( 'Copy all blocks' ) }</MenuItem>;
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,5 +48,5 @@ export default function CopyContentMenuItem() {

const ref = useCopyToClipboard( getText, onSuccess );

return <MenuItem ref={ ref }>{ __( 'Copy all content' ) }</MenuItem>;
return <MenuItem ref={ ref }>{ __( 'Copy all blocks' ) }</MenuItem>;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<!-- wp:heading -->
<h2>Heading</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Paragraph</p>
<!-- /wp:paragraph -->
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!-- wp:heading -->
<h2>Heading</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Paragraph</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>ading

Paragra</code></pre>
<!-- /wp:code -->
26 changes: 26 additions & 0 deletions test/e2e/specs/editor/various/copy-cut-paste.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -371,4 +371,30 @@ test.describe( 'Copy/cut/paste', () => {
await pageUtils.pressKeyWithModifier( 'primary', 'v' );
expect( await editor.getEditedPostContent() ).toMatchSnapshot();
} );

test( 'should paste plain text in plain text context when cross block selection is copied ', async ( {
editor,
page,
pageUtils,
} ) => {
await editor.insertBlock( { name: 'core/heading' } );
await page.keyboard.type( 'Heading' );
await page.keyboard.press( 'Enter' );
await page.keyboard.type( 'Paragraph' );
expect( await editor.getEditedPostContent() ).toMatchSnapshot();
// Partial select from outer blocks.
await pageUtils.pressKeyTimes( 'ArrowLeft', 2 );
await pageUtils.pressKeyWithModifier( 'shift', 'ArrowUp' );
await pageUtils.pressKeyWithModifier( 'primary', 'c' );
await pageUtils.pressKeyWithModifier( 'primary', 'ArrowLeft' );
// Sometimes the caret has not moved to the correct position before pressing Enter.
// @see https://github.com/WordPress/gutenberg/issues/40303#issuecomment-1109434887
await page.waitForFunction(
() => window.getSelection().type === 'Caret'
);
// Create a new code block to paste there.
await editor.insertBlock( { name: 'core/code' } );
await pageUtils.pressKeyWithModifier( 'primary', 'v' );
expect( await editor.getEditedPostContent() ).toMatchSnapshot();
} );
} );

0 comments on commit 6f3bb8c

Please sign in to comment.