Skip to content

Commit

Permalink
Blocks: Examine source block when converted invalid block into blocks.
Browse files Browse the repository at this point in the history
Previously when running "Convert to Blocks" on the invalid-block resolution dialog
we have been converting only a portion of the invalid block due to the way we examine
the `originalContent.`

Since #38923 we have had `__unstableBlockSource` available which tracks the entire
contents of the original block that failed to validate.

In this patch we're using that source information in order to split apart the invalid
block and then separately parse each of its constituent components.

The result of this change is that we're able to preserve more block content when
resolving an invalid block than we were before. For example, supposing we have a broken
container block full of valid inner blocks, we are now able to extract all of those
inner blocks and preserve them whereas before we would lose all block information and
the stack would turn into an empty classic block.
  • Loading branch information
dmsnell committed Apr 18, 2022
1 parent f4a031d commit 5ac742d
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 17 deletions.
11 changes: 7 additions & 4 deletions packages/block-editor/src/components/block-compare/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { diffChars } from 'diff/lib/diff/character';
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
import { getSaveContent } from '@wordpress/blocks';
import { getSaveContent, serializeRawBlock } from '@wordpress/blocks';

/**
* Internal dependencies
Expand Down Expand Up @@ -54,8 +54,11 @@ function BlockCompare( {
return newContent.join( '' );
}

const rawContent = serializeRawBlock( block.__unstableBlockSource, {
delimiters: 'no-top-level',
} );
const converted = getConvertedContent( convertor( block ) );
const difference = getDifference( block.originalContent, converted );
const difference = getDifference( rawContent, converted );

return (
<div className="block-editor-block-compare__wrapper">
Expand All @@ -64,8 +67,8 @@ function BlockCompare( {
className="block-editor-block-compare__current"
action={ onKeep }
actionText={ __( 'Convert to HTML' ) }
rawContent={ block.originalContent }
renderedContent={ block.originalContent }
rawContent={ rawContent }
renderedContent={ rawContent }
/>

<BlockView
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@
import { __, _x } from '@wordpress/i18n';
import { Button, Modal } from '@wordpress/components';
import { useState, useCallback, useMemo } from '@wordpress/element';
import { getBlockType, createBlock, rawHandler } from '@wordpress/blocks';
import {
getBlockType,
createBlock,
parse,
serializeRawBlock,
} from '@wordpress/blocks';
import { compose } from '@wordpress/compose';
import { withDispatch, withSelect } from '@wordpress/data';

Expand Down Expand Up @@ -89,16 +94,25 @@ export function BlockInvalidWarning( {

const blockToClassic = ( block ) =>
createBlock( 'core/freeform', {
content: block.originalContent,
content: serializeRawBlock( block.__unstableBlockSource, {
delimiters: 'none',
} ),
} );

const blockToHTML = ( block ) =>
createBlock( 'core/html', {
content: block.originalContent,
content: serializeRawBlock( block.__unstableBlockSource, {
delimiters: 'none',
} ),
} );

const blockToBlocks = ( block ) =>
rawHandler( {
HTML: block.originalContent,
} );
parse(
serializeRawBlock( block.__unstableBlockSource, {
delimiters: 'no-top-level',
} )
);

const recoverBlock = ( { name, attributes, innerBlocks } ) =>
createBlock( name, attributes, innerBlocks );

Expand Down
4 changes: 2 additions & 2 deletions packages/blocks/src/api/parser/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -127,13 +127,13 @@ function createMissingBlockType( rawBlock ) {
// handler. A block node's `innerHTML` isn't enough, as that field only
// carries the block's own HTML and not its nested blocks.
const originalUndelimitedContent = serializeRawBlock( rawBlock, {
isCommentDelimited: false,
delimiters: 'none',
} );

// Preserve full block content for use by the unregistered type
// handler, block boundaries included.
const originalContent = serializeRawBlock( rawBlock, {
isCommentDelimited: true,
delimiters: 'all',
} );

return {
Expand Down
17 changes: 12 additions & 5 deletions packages/blocks/src/api/parser/serialize-raw-block.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
*/
import { getCommentDelimitedContent } from '../serializer';

/** @typedef {'all' | 'none' | 'no-top-level'} DelimiterSet */

/**
* @typedef {Object} Options Serialization options.
* @property {boolean} [isCommentDelimited=true] Whether to output HTML comments around blocks.
* @typedef {Object} Options Serialization options.
* @property {DelimiterSet} [delimiters='all'] Whether to output HTML comments around blocks.
*/

/** @typedef {import("./").WPRawBlock} WPRawBlock */
Expand All @@ -31,7 +33,7 @@ import { getCommentDelimitedContent } from '../serializer';
* @return {string} An HTML string representing a block.
*/
export function serializeRawBlock( rawBlock, options = {} ) {
const { isCommentDelimited = true } = options;
const { delimiters = 'all' } = options;
const {
blockName,
attrs = {},
Expand All @@ -45,13 +47,18 @@ export function serializeRawBlock( rawBlock, options = {} ) {
// `null` denotes a nested block, otherwise we have an HTML fragment.
item !== null
? item
: serializeRawBlock( innerBlocks[ childIndex++ ], options )
: serializeRawBlock(
innerBlocks[ childIndex++ ],
delimiters === 'no-top-level'
? { ...options, delimiters: 'all' }
: options
)
)
.join( '\n' )
.replace( /\n+/g, '\n' )
.trim();

return isCommentDelimited
return 'all' === delimiters
? getCommentDelimitedContent( blockName, attrs, content )
: content;
}

0 comments on commit 5ac742d

Please sign in to comment.