Skip to content

Commit

Permalink
[Multi-selection]: Copy whole block when selection is collapsed (#40374)
Browse files Browse the repository at this point in the history
* [Multi-selection]: Copy whole block when selection is collapsed

* rename var to shouldHandleWholeBlocks
  • Loading branch information
ntsekouras authored Apr 15, 2022
1 parent 731d178 commit ab1ec6f
Show file tree
Hide file tree
Showing 7 changed files with 88 additions and 4 deletions.
10 changes: 6 additions & 4 deletions packages/block-editor/src/components/copy-handler/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ export function useClipboardHandler() {
hasMultiSelection,
getSettings,
__unstableIsFullySelected,
__unstableIsSelectionCollapsed,
__unstableIsSelectionMergeable,
__unstableGetSelectedBlocksWithPartialSelection,
} = useSelect( blockEditorStore );
Expand Down Expand Up @@ -123,10 +124,11 @@ export function useClipboardHandler() {
const eventDefaultPrevented = event.defaultPrevented;
event.preventDefault();

const isFullySelected = __unstableIsFullySelected();
const isSelectionMergeable = __unstableIsSelectionMergeable();
const shouldHandleWholeBlocks =
__unstableIsSelectionCollapsed() || __unstableIsFullySelected();
const expandSelectionIsNeeded =
! isFullySelected && ! isSelectionMergeable;
! shouldHandleWholeBlocks && ! isSelectionMergeable;
if ( event.type === 'copy' || event.type === 'cut' ) {
if ( selectedBlockClientIds.length === 1 ) {
flashBlock( selectedBlockClientIds[ 0 ] );
Expand All @@ -139,7 +141,7 @@ export function useClipboardHandler() {
notifyCopy( event.type, selectedBlockClientIds );
let blocks;
// Check if we have partial selection.
if ( isFullySelected ) {
if ( shouldHandleWholeBlocks ) {
blocks = getBlocksByClientId( selectedBlockClientIds );
} else {
const [
Expand All @@ -165,7 +167,7 @@ export function useClipboardHandler() {
// We need to also check if at the start we needed to
// expand the selection, as in this point we might have
// programmatically fully selected the blocks above.
if ( isFullySelected && ! expandSelectionIsNeeded ) {
if ( shouldHandleWholeBlocks && ! expandSelectionIsNeeded ) {
removeBlocks( selectedBlockClientIds );
} else {
__unstableDeleteSelection();
Expand Down
19 changes: 19 additions & 0 deletions packages/block-editor/src/store/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -932,6 +932,25 @@ export function __unstableIsFullySelected( state ) {
);
}

/**
* Returns true if the selection is collapsed.
*
* @param {Object} state Editor state.
*
* @return {boolean} Whether the selection is collapsed.
*/
export function __unstableIsSelectionCollapsed( state ) {
const selectionAnchor = getSelectionStart( state );
const selectionFocus = getSelectionEnd( state );
return (
!! selectionAnchor &&
!! selectionFocus &&
selectionAnchor.clientId === selectionFocus.clientId &&
selectionAnchor.attributeKey === selectionFocus.attributeKey &&
selectionAnchor.offset === selectionFocus.offset
);
}

/**
* Check whether the selection is mergeable.
*
Expand Down
35 changes: 35 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 @@ -4,6 +4,41 @@
const { test, expect } = require( '@wordpress/e2e-test-utils-playwright' );

test.describe( 'Copy/cut/paste', () => {
test( 'should copy and paste individual blocks with collapsed selection', async ( {
page,
pageUtils,
} ) => {
await pageUtils.createNewPost();
await page.click( 'role=button[name="Add default block"i]' );
await page.keyboard.type( 'Copy - collapsed selection' );
await page.keyboard.press( 'Enter' );
await page.keyboard.type( '2' );
await page.keyboard.press( 'ArrowUp' );
await pageUtils.pressKeyWithModifier( 'primary', 'c' );
expect( await pageUtils.getEditedPostContent() ).toMatchSnapshot();

await page.keyboard.press( 'ArrowDown' );
await pageUtils.pressKeyWithModifier( 'primary', 'v' );
expect( await pageUtils.getEditedPostContent() ).toMatchSnapshot();
} );
test( 'should cut and paste individual blocks with collapsed selection', async ( {
page,
pageUtils,
} ) => {
await pageUtils.createNewPost();
await page.click( 'role=button[name="Add default block"i]' );
await page.keyboard.type( 'Cut - collapsed selection' );
await page.keyboard.press( 'Enter' );
await page.keyboard.type( '2' );
await page.keyboard.press( 'ArrowUp' );
await pageUtils.pressKeyWithModifier( 'primary', 'x' );
expect( await pageUtils.getEditedPostContent() ).toMatchSnapshot();

await page.keyboard.press( 'Tab' );
await page.keyboard.press( 'ArrowDown' );
await pageUtils.pressKeyWithModifier( 'primary', 'v' );
expect( await pageUtils.getEditedPostContent() ).toMatchSnapshot();
} );
test( 'should copy blocks when non textual elements are focused (image, spacer)', async ( {
page,
pageUtils,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<!-- wp:paragraph -->
<p>Copy - collapsed selection</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>2</p>
<!-- /wp:paragraph -->
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!-- wp:paragraph -->
<p>Copy - collapsed selection</p>
<!-- /wp:paragraph -->

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

<!-- wp:paragraph -->
<p>Copy - collapsed selection</p>
<!-- /wp:paragraph -->
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<!-- wp:paragraph -->
<p>2</p>
<!-- /wp:paragraph -->
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<!-- wp:paragraph -->
<p>2</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Cut - collapsed selection</p>
<!-- /wp:paragraph -->

0 comments on commit ab1ec6f

Please sign in to comment.