Skip to content

Commit

Permalink
Merge pull request #2513 from WordPress/update/preserve-unknown-block
Browse files Browse the repository at this point in the history
Blocks: Preserve unknown block, remove freeform block comment delimiters
  • Loading branch information
aduth committed Aug 29, 2017
2 parents 09380a4 + 44b8464 commit 4effd31
Show file tree
Hide file tree
Showing 6 changed files with 188 additions and 23 deletions.
7 changes: 7 additions & 0 deletions blocks/api/parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { parse as grammarParse } from './post.pegjs';
import { getBlockType, getUnknownTypeHandlerName } from './registration';
import { createBlock } from './factory';
import { isValidBlock } from './validation';
import { getCommentDelimitedContent } from './serializer';

/**
* Returns true if the provided function is a valid attribute source, or false
Expand Down Expand Up @@ -177,6 +178,12 @@ export function createBlockWithFallback( name, rawContent, attributes ) {
let blockType = getBlockType( name );
const fallbackBlock = getUnknownTypeHandlerName();
if ( ! blockType ) {
// If detected as a block which is not registered, preserve comment
// delimiters in content of unknown type handler.
if ( name ) {
rawContent = getCommentDelimitedContent( name, attributes, rawContent );
}

name = fallbackBlock;
blockType = getBlockType( name );
}
Expand Down
55 changes: 40 additions & 15 deletions blocks/api/serializer.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { Component, createElement, renderToString, cloneElement, Children } from
/**
* Internal dependencies
*/
import { getBlockType } from './registration';
import { getBlockType, getUnknownTypeHandlerName } from './registration';

/**
* Returns the block's default classname from its name
Expand Down Expand Up @@ -139,6 +139,37 @@ export function getBeautifulContent( content ) {
} );
}

/**
* Returns the content of a block, including comment delimiters.
*
* @param {String} blockName Block name
* @param {Object} attributes Block attributes
* @param {String} content Block save content
* @return {String} Comment-delimited block content
*/
export function getCommentDelimitedContent( blockName, attributes, content ) {
const serializedAttributes = ! isEmpty( attributes )
? serializeAttributes( attributes ) + ' '
: '';

if ( ! content ) {
return `<!-- wp:${ blockName } ${ serializedAttributes }/-->`;
}

return (
`<!-- wp:${ blockName } ${ serializedAttributes }-->\n` +
getBeautifulContent( content ) +
`\n<!-- /wp:${ blockName } -->`
);
}

/**
* Returns the content of a block, including comment delimiters, determining
* serialized attributes and content form from the current state of the block.
*
* @param {Object} block Block instance
* @return {String} Serialized block
*/
export function serializeBlock( block ) {
const blockName = block.name;
const blockType = getBlockType( blockName );
Expand All @@ -154,23 +185,17 @@ export function serializeBlock( block ) {

const saveAttributes = getCommentAttributes( block.attributes, blockType.attributes );

if ( 'core/more' === blockName ) {
return `<!--more${ saveAttributes.text ? ` ${ saveAttributes.text }` : '' }-->${ saveAttributes.noTeaser ? '\n<!--noteaser-->' : '' }`;
}
switch ( blockName ) {
case 'core/more':
const { text, noTeaser } = saveAttributes;
return `<!--more${ text ? ` ${ text }` : '' }-->${ noTeaser ? '\n<!--noteaser-->' : '' }`;

const serializedAttributes = ! isEmpty( saveAttributes )
? serializeAttributes( saveAttributes ) + ' '
: '';
case getUnknownTypeHandlerName():
return saveContent;

if ( ! saveContent ) {
return `<!-- wp:${ blockName } ${ serializedAttributes }/-->`;
default:
return getCommentDelimitedContent( blockName, saveAttributes, saveContent );
}

return (
`<!-- wp:${ blockName } ${ serializedAttributes }-->\n` +
getBeautifulContent( saveContent ) +
`\n<!-- /wp:${ blockName } -->`
);
}

/**
Expand Down
19 changes: 16 additions & 3 deletions blocks/api/test/parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -199,16 +199,29 @@ describe( 'block parser', () => {
} );

it( 'should fall back to the unknown type handler for unknown blocks if present', () => {
registerBlockType( 'core/unknown-block', defaultBlockSettings );
registerBlockType( 'core/unknown-block', {
category: 'common',
attributes: {
content: {
type: 'string',
source: html(),
},
fruit: {
type: 'string',
},
},
save: ( { attributes } ) => attributes.content,
} );
setUnknownTypeHandlerName( 'core/unknown-block' );

const block = createBlockWithFallback(
'core/test-block',
'content',
{ fruit: 'Bananas' }
);
expect( block.name ).toEqual( 'core/unknown-block' );
expect( block.attributes ).toEqual( { fruit: 'Bananas' } );
expect( block.name ).toBe( 'core/unknown-block' );
expect( block.attributes.fruit ).toBe( 'Bananas' );
expect( block.attributes.content ).toContain( 'core/test-block' );
} );

it( 'should fall back to the unknown type handler if block type not specified', () => {
Expand Down
124 changes: 123 additions & 1 deletion blocks/api/test/serializer.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,20 @@ import serialize, {
getBeautifulContent,
getSaveContent,
serializeAttributes,
getCommentDelimitedContent,
serializeBlock,
} from '../serializer';
import { getBlockTypes, registerBlockType, unregisterBlockType } from '../registration';
import {
getBlockTypes,
registerBlockType,
unregisterBlockType,
setUnknownTypeHandlerName,
} from '../registration';
import { createBlock } from '../';

describe( 'block serializer', () => {
afterEach( () => {
setUnknownTypeHandlerName( undefined );
getBlockTypes().forEach( block => {
unregisterBlockType( block.name );
} );
Expand Down Expand Up @@ -210,6 +218,120 @@ describe( 'block serializer', () => {
} );
} );

describe( 'getCommentDelimitedContent()', () => {
it( 'should generate empty attributes void', () => {
const content = getCommentDelimitedContent(
'core/test-block',
{},
''
);

expect( content ).toBe( '<!-- wp:core/test-block /-->' );
} );

it( 'should generate empty attributes non-void', () => {
const content = getCommentDelimitedContent(
'core/test-block',
{},
'Delicious'
);

expect( content ).toBe( '<!-- wp:core/test-block -->\nDelicious\n<!-- /wp:core/test-block -->' );
} );

it( 'should generate non-empty attributes void', () => {
const content = getCommentDelimitedContent(
'core/test-block',
{ fruit: 'Banana' },
''
);

expect( content ).toBe(
'<!-- wp:core/test-block {"fruit":"Banana"} /-->'
);
} );

it( 'should generate non-empty attributes non-void', () => {
const content = getCommentDelimitedContent(
'core/test-block',
{ fruit: 'Banana' },
'Delicious'
);

expect( content ).toBe(
'<!-- wp:core/test-block {"fruit":"Banana"} -->\nDelicious\n<!-- /wp:core/test-block -->'
);
} );
} );

describe( 'serializeBlock()', () => {
describe( '"more" block', () => {
beforeEach( () => {
registerBlockType( 'core/more', {
category: 'layout',

attributes: {
text: {
type: 'string',
},
noTeaser: {
type: 'boolean',
default: false,
},
},

save: ( { attributes } ) => attributes.text,
} );
} );

it( 'serializes without text', () => {
const block = createBlock( 'core/more', {} );

const content = serializeBlock( block );

expect( content ).toBe( '<!--more-->' );
} );

it( 'serializes with text', () => {
const block = createBlock( 'core/more', {
text: 'Read more!',
} );

const content = serializeBlock( block );

expect( content ).toBe( '<!--more Read more!-->' );
} );

it( 'serializes with no teaser', () => {
const block = createBlock( 'core/more', {
noTeaser: true,
} );

const content = serializeBlock( block );

expect( content ).toBe( '<!--more-->\n<!--noteaser-->' );
} );
} );

it( 'serializes the fallback block without comment delimiters', () => {
registerBlockType( 'core/unknown-block', {
category: 'common',
attributes: {
fruit: {
type: 'string',
},
},
save: ( { attributes } ) => attributes.fruit,
} );
setUnknownTypeHandlerName( 'core/unknown-block' );
const block = createBlock( 'core/unknown-block', { fruit: 'Bananas' } );

const content = serializeBlock( block );

expect( content ).toBe( 'Bananas' );
} );
} );

describe( 'serialize()', () => {
it( 'should serialize the post content properly', () => {
const blockType = {
Expand Down
2 changes: 1 addition & 1 deletion blocks/test/fixtures/core__audio.parsed.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
{
"blockName": "core/audio",
"attrs": {
"align": "right"
"align": "right"
},
"rawContent": "\n<div class=\"wp-block-audio alignright\">\n <audio controls=\"\" src=\"https://media.simplecast.com/episodes/audio/80564/draft-podcast-51-livePublish2.mp3\"></audio>\n</div>\n"
},
Expand Down
4 changes: 1 addition & 3 deletions blocks/test/fixtures/core__freeform.serialized.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
<!-- wp:core/freeform -->
Testing freeform block with some
<div class="wp-some-class">
HTML <span style="color: red;">content</span>
HTML <span style="color: red;">content</span>
</div>
<!-- /wp:core/freeform -->

0 comments on commit 4effd31

Please sign in to comment.