Skip to content

Commit

Permalink
Try another approach
Browse files Browse the repository at this point in the history
  • Loading branch information
kevin940726 committed Sep 13, 2024
1 parent 7ed5e9c commit 550773b
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 169 deletions.
84 changes: 25 additions & 59 deletions packages/block-editor/src/components/block-list/block.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,7 @@ import {
isReusableBlock,
getBlockDefaultClassName,
hasBlockSupport,
__experimentalGetBlockAttributesNamesByRole,
store as blocksStore,
privateApis as blocksPrivateApis,
} from '@wordpress/blocks';
import { withFilters } from '@wordpress/components';
import { withDispatch, useDispatch, useSelect } from '@wordpress/data';
Expand All @@ -48,8 +46,6 @@ import { PrivateBlockContext } from './private-block-context';

import { unlock } from '../../lock-unlock';

const { isAttributeUnmodified } = unlock( blocksPrivateApis );

/**
* Merges wrapper props with special handling for classNames and styles.
*
Expand Down Expand Up @@ -333,26 +329,6 @@ const applyWithDispatch = withDispatch( ( dispatch, ownProps, registry ) => {
}
}

/**
* Return true if the block content is empty.
* @param {string} blockClientId The block client ID.
* @return {boolean} Whether the block content is empty.
*/
function isBlockContentEmpty( blockClientId ) {
const block = getBlock( blockClientId );
const blockType = getBlockType( block.name );
const contentAttributes =
__experimentalGetBlockAttributesNamesByRole(
block.name,
'content'
);
return contentAttributes.every( ( key ) => {
const value = block.attributes[ key ];
const definition = blockType.attributes[ key ];
return isAttributeUnmodified( definition, value );
} );
}

/**
* Moves the block with clientId up one level. If the block type
* cannot be inserted at the new location, it will be attempted to
Expand All @@ -374,16 +350,30 @@ const applyWithDispatch = withDispatch( ( dispatch, ownProps, registry ) => {
removeBlock( _clientId );
} else {
registry.batch( () => {
if (
canInsertBlockType(
getBlockName( firstClientId ),
targetRootClientId
) &&
// Don't move the block if its content is considered empty.
// Note that for a modified non-empty block, we still try to transform
// it to a default block.
// Fix for https://github.com/WordPress/gutenberg/issues/65174.
! isBlockContentEmpty( firstClientId )
const replacement = switchToBlockType(
getBlock( firstClientId ),
getDefaultBlockName()
);
const canTransformToDefaultBlock =
!! replacement?.length &&
replacement.every( ( block ) =>
canInsertBlockType(
block.name,
targetRootClientId
)
);

if ( canTransformToDefaultBlock ) {
insertBlocks(
replacement,
getBlockIndex( _clientId ),
targetRootClientId,
changeSelection
);
removeBlock( firstClientId, false );
} else if (
getBlockName( firstClientId ) ===
getDefaultBlockName()
) {
moveBlocksToPosition(
[ firstClientId ],
Expand All @@ -392,31 +382,7 @@ const applyWithDispatch = withDispatch( ( dispatch, ownProps, registry ) => {
getBlockIndex( _clientId )
);
} else {
const replacement = switchToBlockType(
getBlock( firstClientId ),
getDefaultBlockName()
);

if (
replacement &&
replacement.length &&
replacement.every( ( block ) =>
canInsertBlockType(
block.name,
targetRootClientId
)
)
) {
insertBlocks(
replacement,
getBlockIndex( _clientId ),
targetRootClientId,
changeSelection
);
removeBlock( firstClientId, false );
} else {
switchToDefaultOrRemove();
}
switchToDefaultOrRemove();
}

if (
Expand Down
2 changes: 0 additions & 2 deletions packages/blocks/src/api/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import {
getBlockBindingsSource,
getBlockBindingsSources,
} from './registration';
import { isAttributeUnmodified } from './utils';

// The blocktype is the most important concept within the block API. It defines
// all aspects of the block configuration and its interfaces, including `edit`
Expand Down Expand Up @@ -183,5 +182,4 @@ lock( privateApis, {
unregisterBlockBindingsSource,
getBlockBindingsSource,
getBlockBindingsSources,
isAttributeUnmodified,
} );
52 changes: 0 additions & 52 deletions packages/blocks/src/api/test/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import {
getBlockLabel,
__experimentalSanitizeBlockAttributes,
__experimentalGetBlockAttributesNamesByRole,
isAttributeUnmodified,
} from '../utils';

const noop = () => {};
Expand Down Expand Up @@ -397,54 +396,3 @@ describe( '__experimentalGetBlockAttributesNamesByRole', () => {
).toEqual( [] );
} );
} );

describe( 'isAttributeUnmodified', () => {
it( 'should return true if the block is unmodified', () => {
expect(
isAttributeUnmodified(
{ type: 'rich-text', __experimentalRole: 'content' },
''
)
).toBe( true );
expect(
isAttributeUnmodified(
{ type: 'rich-text', __experimentalRole: 'content' },
undefined
)
).toBe( true );
expect( isAttributeUnmodified( { type: 'string' }, undefined ) ).toBe(
true
);
expect(
isAttributeUnmodified(
{ type: 'string', default: 'default-value' },
'default-value'
)
).toBe( true );
} );

it( 'should return false if the block is modified', () => {
expect(
isAttributeUnmodified(
{ type: 'rich-text', __experimentalRole: 'content' },
'something else'
)
).toBe( false );
expect(
isAttributeUnmodified( { type: 'string' }, 'something else' )
).toBe( false );
expect( isAttributeUnmodified( { type: 'string' }, '' ) ).toBe( false );
expect(
isAttributeUnmodified(
{ type: 'string', default: 'default-value' },
''
)
).toBe( false );
expect(
isAttributeUnmodified(
{ type: 'string', default: 'default-value' },
undefined
)
).toBe( false );
} );
} );
39 changes: 14 additions & 25 deletions packages/blocks/src/api/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,30 +29,6 @@ extend( [ namesPlugin, a11yPlugin ] );
*/
const ICON_COLORS = [ '#191e23', '#f8f9f9' ];

/**
* Determines whether the block's attribute is equal to the default attribute
* which means the attribute is unmodified.
* @param {Object} attributeDefinition The attribute's definition of the block type.
* @param {*} value The attribute's value.
* @return {boolean} Whether the attribute is unmodified.
*/
export function isAttributeUnmodified( attributeDefinition, value ) {
// Every attribute that has a default must match the default.
if ( attributeDefinition.hasOwnProperty( 'default' ) ) {
return value === attributeDefinition.default;
}

// The rich text type is a bit different from the rest because it
// has an implicit default value of an empty RichTextData instance,
// so check the length of the value.
if ( attributeDefinition.type === 'rich-text' ) {
return ! value?.length;
}

// Every attribute that doesn't have a default should be undefined.
return value === undefined;
}

/**
* Determines whether the block's attributes are equal to the default attributes
* which means the block is unmodified.
Expand All @@ -66,7 +42,20 @@ export function isUnmodifiedBlock( block ) {
( [ key, definition ] ) => {
const value = block.attributes[ key ];

return isAttributeUnmodified( definition, value );
// Every attribute that has a default must match the default.
if ( definition.hasOwnProperty( 'default' ) ) {
return value === definition.default;
}

// The rich text type is a bit different from the rest because it
// has an implicit default value of an empty RichTextData instance,
// so check the length of the value.
if ( definition.type === 'rich-text' ) {
return ! value?.length;
}

// Every attribute that doesn't have a default should be undefined.
return value === undefined;
}
);
}
Expand Down
23 changes: 11 additions & 12 deletions test/e2e/specs/editor/blocks/list.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -1237,18 +1237,17 @@ test.describe( 'List (@firefox)', () => {
await page.keyboard.press( 'Backspace' );
await page.keyboard.press( 'Backspace' );

await expect.poll( editor.getBlocks ).toMatchObject( [
{ name: 'core/paragraph', attributes: { content: '' } },
{
name: 'core/list',
innerBlocks: [
{
name: 'core/list-item',
attributes: { content: '2' },
},
],
},
] );
await expect.poll( editor.getEditedPostContent ).toBe(
`<!-- wp:paragraph -->
<p></p>
<!-- /wp:paragraph -->
<!-- wp:list -->
<ul class="wp-block-list"><!-- wp:list-item -->
<li>2</li>
<!-- /wp:list-item --></ul>
<!-- /wp:list -->`
);
} );

test( 'should not change the contents when you change the list type to Ordered', async ( {
Expand Down
Loading

0 comments on commit 550773b

Please sign in to comment.