Skip to content

Commit

Permalink
Add block to represent unregistered block types
Browse files Browse the repository at this point in the history
  • Loading branch information
brandonpayton committed Aug 24, 2018
1 parent 2d338db commit 4518c16
Show file tree
Hide file tree
Showing 22 changed files with 415 additions and 47 deletions.
8 changes: 6 additions & 2 deletions block-library/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
import {
registerBlockType,
setDefaultBlockName,
setUnknownTypeHandlerName,
setUnstructuredTypeHandlerName,
setUnregisteredTypeHandlerName,
} from '@wordpress/blocks';

/**
Expand All @@ -31,6 +32,7 @@ import * as file from '../packages/block-library/src/file';
import * as latestComments from '../packages/block-library/src/latest-comments';
import * as latestPosts from '../packages/block-library/src/latest-posts';
import * as list from '../packages/block-library/src/list';
import * as missing from '../packages/block-library/src/missing';
import * as more from '../packages/block-library/src/more';
import * as nextpage from '../packages/block-library/src/nextpage';
import * as preformatted from '../packages/block-library/src/preformatted';
Expand Down Expand Up @@ -80,6 +82,7 @@ export const registerCoreBlocks = () => {
html,
latestComments,
latestPosts,
missing,
more,
nextpage,
preformatted,
Expand All @@ -97,5 +100,6 @@ export const registerCoreBlocks = () => {
} );

setDefaultBlockName( paragraph.name );
setUnknownTypeHandlerName( freeform.name );
setUnstructuredTypeHandlerName( freeform.name );
setUnregisteredTypeHandlerName( missing.name );
};
2 changes: 2 additions & 0 deletions docs/reference/deprecated.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ Gutenberg's deprecation policy is intended to support backwards-compatibility fo
- `wp.editor.getColorName` has been removed. Please use `wp.editor.getColorObjectByColorValue` instead.
- `wp.editor.getColorClass` has been renamed. Please use `wp.editor.getColorClassName` instead.
- `value` property in color objects passed by `wp.editor.withColors` has been removed. Please use color property instead.
- `wp.blocks.setUnknownTypeHandlerName` has been removed. Please use `setUnstructuredTypeHandlerName` and `setUnregisteredTypeHandlerName` instead.
- `wp.blocks.getUnknownTypeHandlerName` has been removed. Please use `getUnstructuredTypeHandlerName` and `getUnregisteredTypeHandlerName` instead.

## 3.8.0

Expand Down
15 changes: 15 additions & 0 deletions packages/block-library/src/missing/editor.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
.editor-block-list__block[data-type="core/missing"] {
.editor-warning {
position: static;

// Round corners for a better visual separation between the warning border
// and the unrounded corners of the selected block outline.
border-radius: 4px;
}

.editor-warning__contents {
// Ensure action buttons display on the same line as the text.
flex-wrap: nowrap;
align-items: flex-start;
}
}
46 changes: 46 additions & 0 deletions packages/block-library/src/missing/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
import { RawHTML } from '@wordpress/element';

/**
* Internal dependencies.
*/
import MissingBlockWarning from './missing-block-warning';
import './editor.scss';

export const name = 'core/missing';

export const settings = {
name,
category: 'common',
title: __( 'Missing Block' ),

supports: {
className: false,
customClassName: false,
inserter: false,
html: false,
preserveOriginalContent: true,
},

attributes: {
originalName: {
type: 'string',
},
originalUndelimitedContent: {
type: 'string',
},
originalContent: {
type: 'string',
source: 'html',
},
},

edit: MissingBlockWarning,
save( { attributes } ) {
// Preserve the missing block's content.
return <RawHTML>{ attributes.originalContent }</RawHTML>;
},
};
62 changes: 62 additions & 0 deletions packages/block-library/src/missing/missing-block-warning.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/**
* WordPress dependencies
*/
import { __, sprintf } from '@wordpress/i18n';
import { Button } from '@wordpress/components';
import { getBlockType, createBlock } from '@wordpress/blocks';
import { withSelect, withDispatch } from '@wordpress/data';
import { compose } from '@wordpress/compose';
import { Warning } from '@wordpress/editor';

export const name = 'core/unknown';

export function MissingBlockWarning( { attributes, convertToHTML } ) {
const { originalName, originalUndelimitedContent } = attributes;
const hasContent = !! originalUndelimitedContent;
const hasHTMLBlock = getBlockType( 'core/html' );

const actions = [];
let messageHTML;
if ( hasContent && hasHTMLBlock ) {
actions.push(
<Button key="convert" onClick={ convertToHTML } isLarge isPrimary>
{ __( 'HTML Block' ) }
</Button>
);
messageHTML = sprintf(
__( 'Your site doesn\'t include support for the <code>%s</code> block. You can leave this block intact, convert its content to a Custom HTML block, or remove it entirely.' ),
originalName
);
} else {
messageHTML = sprintf(
__( 'Your site doesn\'t include support for the <code>%s</code> block. You can leave this block intact or remove it entirely.' ),
originalName
);
}

return (
<Warning actions={ actions }>
<span dangerouslySetInnerHTML={ { __html: messageHTML } } />
</Warning>
);
}

export default compose( [
withSelect( ( select, { clientId } ) => {
const { getBlock } = select( 'core/editor' );
return {
block: getBlock( clientId ),
};
} ),
withDispatch( ( dispatch, { block, attributes } ) => {
const { replaceBlock } = dispatch( 'core/editor' );
return {
convertToHTML() {
replaceBlock( block.clientId, createBlock( 'core/html', {
content: attributes.originalUndelimitedContent,
} ) );
},
};
} ),
] )( MissingBlockWarning );

4 changes: 4 additions & 0 deletions packages/blocks/src/api/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ export {
unregisterBlockType,
setUnknownTypeHandlerName,
getUnknownTypeHandlerName,
setUnstructuredTypeHandlerName,
getUnstructuredTypeHandlerName,
setUnregisteredTypeHandlerName,
getUnregisteredTypeHandlerName,
setDefaultBlockName,
getDefaultBlockName,
getDefaultBlockForPostFormat,
Expand Down
44 changes: 30 additions & 14 deletions packages/blocks/src/api/parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,12 @@ import { parse as grammarParse } from '@wordpress/block-serialization-spec-parse
/**
* Internal dependencies
*/
import { getBlockType, getUnknownTypeHandlerName } from './registration';
import {
getBlockType,
getUnknownTypeHandlerName,
getUnstructuredTypeHandlerName,
getUnregisteredTypeHandlerName,
} from './registration';
import { createBlock } from './factory';
import { isValidBlock } from './validation';
import { getCommentDelimitedContent } from './serializer';
Expand Down Expand Up @@ -281,54 +286,65 @@ export function getMigratedBlock( block ) {
* @return {?Object} An initialized block object (if possible).
*/
export function createBlockWithFallback( blockNode ) {
const { blockName: originalName } = blockNode;
let {
blockName: name,
attrs: attributes,
innerBlocks = [],
innerHTML,
} = blockNode;
const fallbackBlock = getUnknownTypeHandlerName();
const unstructuredFallbackBlock = getUnstructuredTypeHandlerName();
const unregisteredFallbackBlock = getUnregisteredTypeHandlerName();
const isUnstructuredFallback = ( name ) => (
name === unstructuredFallbackBlock ||
name === fallbackBlock
);
const isFallbackBlock = ( name ) => (
name === unstructuredFallbackBlock ||
name === unregisteredFallbackBlock ||
name === fallbackBlock
);

attributes = attributes || {};

// Trim content to avoid creation of intermediary freeform segments.
innerHTML = innerHTML.trim();
const originalUndelimitedContent = innerHTML = innerHTML.trim();

// Use type from block content, otherwise find unknown handler.
name = name || getUnknownTypeHandlerName();
let name = originalName || unstructuredFallbackBlock || fallbackBlock;

// Convert 'core/text' blocks in existing content to 'core/paragraph'.
if ( 'core/text' === name || 'core/cover-text' === name ) {
name = 'core/paragraph';
}

// Try finding the type for known block name, else fall back again.
let blockType = getBlockType( name );

const fallbackBlock = getUnknownTypeHandlerName();

// Fallback content may be upgraded from classic editor expecting implicit
// automatic paragraphs, so preserve them. Assumes wpautop is idempotent,
// meaning there are no negative consequences to repeated autop calls.
if ( name === fallbackBlock ) {
if ( isUnstructuredFallback( name ) ) {
innerHTML = autop( innerHTML ).trim();
}

// Try finding the type for known block name, else fall back again.
let blockType = getBlockType( name );

if ( ! blockType ) {
// If detected as a block which is not registered, preserve comment
// delimiters in content of unknown type handler.
// delimiters in content of unregistered type handler.
if ( name ) {
innerHTML = getCommentDelimitedContent( name, attributes, innerHTML );
}

name = fallbackBlock;
name = unregisteredFallbackBlock || fallbackBlock;
attributes = { originalName, originalUndelimitedContent };
blockType = getBlockType( name );
}

// Coerce inner blocks from parsed form to canonical form.
innerBlocks = innerBlocks.map( createBlockWithFallback );

// Include in set only if type were determined.
if ( ! blockType || ( ! innerHTML && name === fallbackBlock ) ) {
if ( ! blockType || ( ! innerHTML && isFallbackBlock( name ) ) ) {
return;
}

Expand All @@ -342,7 +358,7 @@ export function createBlockWithFallback( blockNode ) {
// provided there are no changes in attributes. The validation procedure thus compares the
// provided source value with the serialized output before there are any modifications to
// the block. When both match, the block is marked as valid.
if ( name !== fallbackBlock ) {
if ( ! isFallbackBlock( name ) ) {
block.isValid = isValidBlock( innerHTML, blockType, block.attributes );
}

Expand Down
44 changes: 44 additions & 0 deletions packages/blocks/src/api/registration.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { get, isFunction, some } from 'lodash';
*/
import { applyFilters, addFilter } from '@wordpress/hooks';
import { select, dispatch } from '@wordpress/data';
import deprecated from '@wordpress/deprecated';

/**
* Internal dependencies
Expand Down Expand Up @@ -190,6 +191,11 @@ export function unregisterBlockType( name ) {
* @param {string} name Block name.
*/
export function setUnknownTypeHandlerName( name ) {
deprecated( 'setUnknownTypeHandlerName', {
plugin: 'Gutenberg',
version: '3.8',
alternative: 'setUnstructuredTypeHandlerName and setUnregisteredTypeHandlerName',
} );
dispatch( 'core/blocks' ).setFallbackBlockName( name );
}

Expand All @@ -203,6 +209,44 @@ export function getUnknownTypeHandlerName() {
return select( 'core/blocks' ).getFallbackBlockName();
}

/**
* Assigns name of block for handling non-block content.
*
* @param {string} name Block name.
*/
export function setUnstructuredTypeHandlerName( name ) {
dispatch( 'core/blocks' ).setUnstructuredFallbackBlockName( name );
}

/**
* Retrieves name of block handling non-block content, or undefined if no
* handler has been defined.
*
* @return {?string} Blog name.
*/
export function getUnstructuredTypeHandlerName() {
return select( 'core/blocks' ).getUnstructuredFallbackBlockName();
}

/**
* Assigns name of block handling unregistered block types.
*
* @param {string} name Block name.
*/
export function setUnregisteredTypeHandlerName( name ) {
dispatch( 'core/blocks' ).setUnregisteredFallbackBlockName( name );
}

/**
* Retrieves name of block handling unregistered block types, or undefined if no
* handler has been defined.
*
* @return {?string} Blog name.
*/
export function getUnregisteredTypeHandlerName() {
return select( 'core/blocks' ).getUnregisteredFallbackBlockName();
}

/**
* Assigns the default block name.
*
Expand Down
9 changes: 8 additions & 1 deletion packages/blocks/src/api/serializer.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,12 @@ import isShallowEqual from '@wordpress/is-shallow-equal';
/**
* Internal dependencies
*/
import { getBlockType, getUnknownTypeHandlerName } from './registration';
import {
getBlockType,
getUnknownTypeHandlerName,
getUnstructuredTypeHandlerName,
getUnregisteredTypeHandlerName,
} from './registration';
import BlockContentProvider from '../block-content-provider';

/**
Expand Down Expand Up @@ -261,6 +266,8 @@ export function serializeBlock( block ) {
const saveAttributes = getCommentAttributes( block.attributes, blockType );

switch ( blockName ) {
case getUnstructuredTypeHandlerName():
case getUnregisteredTypeHandlerName():
case getUnknownTypeHandlerName():
return saveContent;

Expand Down
3 changes: 1 addition & 2 deletions packages/blocks/src/api/test/factory.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
getBlockTransforms,
findTransform,
} from '../factory';
import { getBlockTypes, unregisterBlockType, setUnknownTypeHandlerName, registerBlockType } from '../registration';
import { getBlockTypes, unregisterBlockType, registerBlockType } from '../registration';

describe( 'block factory', () => {
const defaultBlockSettings = {
Expand All @@ -35,7 +35,6 @@ describe( 'block factory', () => {
} );

afterEach( () => {
setUnknownTypeHandlerName( undefined );
getBlockTypes().forEach( ( block ) => {
unregisterBlockType( block.name );
} );
Expand Down
Loading

0 comments on commit 4518c16

Please sign in to comment.