diff --git a/bin/create-php-parser.js b/bin/create-php-parser.js index f5cd5327fd0008..8961c38f85cf6f 100755 --- a/bin/create-php-parser.js +++ b/bin/create-php-parser.js @@ -5,7 +5,7 @@ const phpegjs = require( 'phpegjs' ); const fs = require( 'fs' ); const path = require( 'path' ); -const peg = fs.readFileSync( 'blocks/api/post.pegjs', 'utf8' ); +const peg = fs.readFileSync( 'block-api/post.pegjs', 'utf8' ); const parser = pegjs.generate( peg, diff --git a/block-api/config.js b/block-api/config.js new file mode 100644 index 00000000000000..98c4c707d0d925 --- /dev/null +++ b/block-api/config.js @@ -0,0 +1,16 @@ +/** + * External dependencies + */ +import { find } from 'lodash'; + +/** + * Retrieves the blockType from the block types config + * + * @param {String} name Block name + * @param {Object} config The block types config + * + * @return {?Object} Block type + */ +export function getBlockType( name, config ) { + return find( config.blockTypes, ( blockType ) => blockType.name === name ); +} diff --git a/blocks/api/factory.js b/block-api/factory.js similarity index 79% rename from blocks/api/factory.js rename to block-api/factory.js index 004cfb115c35bf..45cfddd1cccf32 100644 --- a/blocks/api/factory.js +++ b/block-api/factory.js @@ -14,19 +14,16 @@ import { /** * Internal dependencies */ -import { getBlockType } from './registration'; +import { getBlockType } from './config'; /** * Returns a block object given its type and attributes. * - * @param {String} name Block name + * @param {String} blockType Block type * @param {Object} attributes Block attributes * @return {Object} Block object */ -export function createBlock( name, attributes = {} ) { - // Get the type definition associated with a registered block. - const blockType = getBlockType( name ); - +export function createBlock( blockType, attributes = {} ) { // Ensure attributes contains only values defined by block type, and merge // default values for missing attributes. attributes = reduce( blockType.attributes, ( result, source, key ) => { @@ -44,7 +41,7 @@ export function createBlock( name, attributes = {} ) { // and the block attributes. return { uid: uuid(), - name, + name: blockType.name, isValid: true, attributes, }; @@ -54,14 +51,15 @@ export function createBlock( name, attributes = {} ) { * Switch a block into one or more blocks of the new block type. * * @param {Object} block Block object - * @param {string} name Block name + * @param {String} name Block name + * @param {Object} config Block Types config * @return {Array} Block object */ -export function switchToBlockType( block, name ) { +export function switchToBlockType( block, name, config ) { // Find the right transformation by giving priority to the "to" // transformation. - const destinationType = getBlockType( name ); - const sourceType = getBlockType( block.name ); + const destinationType = getBlockType( name, config ); + const sourceType = getBlockType( block.name, config ); const transformationsFrom = get( destinationType, 'transforms.from', [] ); const transformationsTo = get( sourceType, 'transforms.to', [] ); const transformation = @@ -87,10 +85,16 @@ export function switchToBlockType( block, name ) { // Ensure that every block object returned by the transformation has a // valid block type. - if ( transformationResults.some( ( result ) => ! getBlockType( result.name ) ) ) { + if ( transformationResults.some( ( result ) => ! getBlockType( result.name, config ) ) ) { return null; } + // Pass the results through the createBlockHelper + transformationResults = transformationResults.map( ( result ) => { + const blockType = getBlockType( result.name, config ); + return createBlock( blockType, result.attributes ); + } ); + const firstSwitchedBlock = findIndex( transformationResults, ( result ) => result.name === name ); // Ensure that at least one block object returned by the transformation has diff --git a/block-api/index.js b/block-api/index.js new file mode 100644 index 00000000000000..87ca08cca2a09c --- /dev/null +++ b/block-api/index.js @@ -0,0 +1,12 @@ +/** + * External dependencies + */ +import * as source from './source'; + +export { source }; +export { createBlock, switchToBlockType } from './factory'; +export { default as parse } from './parser'; +export { default as pasteHandler } from './paste'; +export { default as serialize, getBlockDefaultClassname } from './serializer'; +export { parse as grammarParse } from './post.pegjs'; +export { getBlockType } from './config'; diff --git a/blocks/api/parser.js b/block-api/parser.js similarity index 87% rename from blocks/api/parser.js rename to block-api/parser.js index c908414a775974..c766e6dc4c7d2f 100644 --- a/blocks/api/parser.js +++ b/block-api/parser.js @@ -8,9 +8,9 @@ import { mapValues, reduce, pickBy } from 'lodash'; * Internal dependencies */ import { parse as grammarParse } from './post.pegjs'; -import { getBlockType, getUnknownTypeHandlerName } from './registration'; import { createBlock } from './factory'; import { isValidBlock } from './validation'; +import { getBlockType } from './config'; /** * Returns true if the provided function is a valid attribute source, or false @@ -151,14 +151,15 @@ export function getBlockAttributes( blockType, rawContent, attributes ) { /** * Creates a block with fallback to the unknown type handler. * - * @param {?String} name Block type name - * @param {String} rawContent Raw block content - * @param {?Object} attributes Attributes obtained from block delimiters - * @return {?Object} An initialized block object (if possible) + * @param {?String} originalName Block type name + * @param {String} rawContent Raw block content + * @param {?Object} attributes Attributes obtained from block delimiters + * @param {Object} config Block Types config + * @return {?Object} An initialized block object (if possible) */ -export function createBlockWithFallback( name, rawContent, attributes ) { +export function createBlockWithFallback( originalName, rawContent, attributes, config ) { // Use type from block content, otherwise find unknown handler. - name = name || getUnknownTypeHandlerName(); + let name = originalName || config.fallbackBlockName; // Convert 'core/text' blocks in existing content to the new // 'core/paragraph'. @@ -167,21 +168,20 @@ export function createBlockWithFallback( name, rawContent, attributes ) { } // Try finding type for known block name, else fall back again. - let blockType = getBlockType( name ); - const fallbackBlock = getUnknownTypeHandlerName(); + let blockType = getBlockType( name, config ); if ( ! blockType ) { - name = fallbackBlock; - blockType = getBlockType( name ); + name = config.fallbackBlockName; + blockType = getBlockType( name, config ); } // Include in set only if type were determined. // TODO do we ever expect there to not be an unknown type handler? - if ( blockType && ( rawContent || name !== fallbackBlock ) ) { + if ( blockType && ( rawContent || name !== config.fallbackBlockName ) ) { // TODO allow blocks to opt-in to receiving a tree instead of a string. // Gradually convert all blocks to this new format, then remove the // string serialization. const block = createBlock( - name, + blockType, getBlockAttributes( blockType, rawContent, attributes ) ); @@ -201,12 +201,13 @@ export function createBlockWithFallback( name, rawContent, attributes ) { * Parses the post content with a PegJS grammar and returns a list of blocks. * * @param {String} content The post content + * @param {Object} config Block Types config * @return {Array} Block list */ -export function parseWithGrammar( content ) { +export function parse( content, config ) { return grammarParse( content ).reduce( ( memo, blockNode ) => { const { blockName, rawContent, attrs } = blockNode; - const block = createBlockWithFallback( blockName, rawContent.trim(), attrs ); + const block = createBlockWithFallback( blockName, rawContent.trim(), attrs, config ); if ( block ) { memo.push( block ); } @@ -214,4 +215,4 @@ export function parseWithGrammar( content ) { }, [] ); } -export default parseWithGrammar; +export default parse; diff --git a/blocks/api/paste.js b/block-api/paste.js similarity index 90% rename from blocks/api/paste.js rename to block-api/paste.js index 5342f34fa85ee3..82b01d46bf3dc3 100644 --- a/blocks/api/paste.js +++ b/block-api/paste.js @@ -12,8 +12,8 @@ import { nodetypes } from '@wordpress/utils'; * Internal dependencies */ import { createBlock } from './factory'; -import { getBlockTypes, getUnknownTypeHandlerName } from './registration'; import { getBlockAttributes } from './parser'; +import { getBlockType } from './config'; import stripAttributes from './paste/strip-attributes'; import removeSpans from './paste/remove-spans'; @@ -78,11 +78,11 @@ export function normaliseToBlockLevelNodes( nodes ) { return Array.from( accu.childNodes ); } -export default function( nodes ) { +export default function( nodes, config ) { const prepare = compose( [ normaliseToBlockLevelNodes, removeSpans, stripAttributes ] ); return prepare( nodes ).map( ( node ) => { - const block = getBlockTypes().reduce( ( acc, blockType ) => { + const block = config.blockTypes.reduce( ( acc, blockType ) => { if ( acc ) { return acc; } @@ -95,7 +95,7 @@ export default function( nodes ) { } return createBlock( - blockType.name, + blockType, getBlockAttributes( blockType, node.outerHTML @@ -107,7 +107,8 @@ export default function( nodes ) { return block; } - return createBlock( getUnknownTypeHandlerName(), { + const fallbackBlockType = getBlockType( config.fallbackBlockName, config ); + return createBlock( fallbackBlockType, { content: node.outerHTML, } ); } ); diff --git a/blocks/api/paste/remove-spans.js b/block-api/paste/remove-spans.js similarity index 100% rename from blocks/api/paste/remove-spans.js rename to block-api/paste/remove-spans.js diff --git a/blocks/api/paste/strip-attributes.js b/block-api/paste/strip-attributes.js similarity index 100% rename from blocks/api/paste/strip-attributes.js rename to block-api/paste/strip-attributes.js diff --git a/blocks/api/post.pegjs b/block-api/post.pegjs similarity index 100% rename from blocks/api/post.pegjs rename to block-api/post.pegjs diff --git a/blocks/api/serializer.js b/block-api/serializer.js similarity index 93% rename from blocks/api/serializer.js rename to block-api/serializer.js index c5aed9e25d3220..29b0df970f621f 100644 --- a/blocks/api/serializer.js +++ b/block-api/serializer.js @@ -13,7 +13,7 @@ import { Component, createElement, renderToString, cloneElement, Children } from /** * Internal dependencies */ -import { getBlockType } from './registration'; +import { getBlockType } from './config'; /** * Returns the block's default classname from its name @@ -131,9 +131,8 @@ export function getBeautifulContent( content ) { } ); } -export function serializeBlock( block ) { +export function serializeBlock( block, blockType ) { const blockName = block.name; - const blockType = getBlockType( blockName ); let saveContent; if ( block.isValid ) { @@ -169,8 +168,11 @@ export function serializeBlock( block ) { * Takes a block or set of blocks and returns the serialized post content. * * @param {Array} blocks Block(s) to serialize + * @param {Object} config Block Types config * @return {String} The post content */ -export default function serialize( blocks ) { - return castArray( blocks ).map( serializeBlock ).join( '\n\n' ); +export default function serialize( blocks, config ) { + return castArray( blocks ) + .map( ( block ) => serializeBlock( block, getBlockType( block.name, config ) ) ) + .join( '\n\n' ); } diff --git a/blocks/api/source.js b/block-api/source.js similarity index 100% rename from blocks/api/source.js rename to block-api/source.js diff --git a/block-api/test/config.js b/block-api/test/config.js new file mode 100644 index 00000000000000..1e76698603b288 --- /dev/null +++ b/block-api/test/config.js @@ -0,0 +1,25 @@ +/** + * Internal dependencies + */ +import { getBlockType } from '../config'; + +describe( 'block types config', () => { + describe( 'getBlockType', () => { + it( 'should return undefined if the block type was not found', () => { + const blockTypes = [ + { name: 'core/text' }, + ]; + const blockType = getBlockType( 'core/image', { blockTypes } ); + + expect( blockType ).toBeUndefined(); + } ); + + it( 'should return the correponding blockType', () => { + const textBlockType = { name: 'core/text' }; + const blockTypes = [ textBlockType ]; + const blockType = getBlockType( 'core/text', { blockTypes } ); + + expect( blockType ).toBe( textBlockType ); + } ); + } ); +} ); diff --git a/blocks/api/test/factory.js b/block-api/test/factory.js similarity index 64% rename from blocks/api/test/factory.js rename to block-api/test/factory.js index 8d1ea343252a88..cd521156b1081c 100644 --- a/blocks/api/test/factory.js +++ b/block-api/test/factory.js @@ -7,29 +7,12 @@ import { noop } from 'lodash'; * Internal dependencies */ import { createBlock, switchToBlockType } from '../factory'; -import { getBlockTypes, unregisterBlockType, setUnknownTypeHandlerName, registerBlockType } from '../registration'; describe( 'block factory', () => { - const defaultBlockSettings = { - attributes: { - value: { - type: 'string', - }, - }, - save: noop, - category: 'common', - }; - - afterEach( () => { - setUnknownTypeHandlerName( undefined ); - getBlockTypes().forEach( ( block ) => { - unregisterBlockType( block.name ); - } ); - } ); - describe( 'createBlock()', () => { it( 'should create a block given its blockType and attributes', () => { - registerBlockType( 'core/test-block', { + const blockType = { + name: 'core/test-block', attributes: { align: { type: 'string', @@ -40,9 +23,8 @@ describe( 'block factory', () => { }, }, save: noop, - category: 'common', - } ); - const block = createBlock( 'core/test-block', { + }; + const block = createBlock( blockType, { align: 'left', } ); @@ -57,8 +39,18 @@ describe( 'block factory', () => { } ); describe( 'switchToBlockType()', () => { + const defaultBlockType = { + name: 'core/text-block', + attributes: { + value: { + type: 'string', + }, + }, + save: noop, + }; it( 'should switch the blockType of a block using the "transform form"', () => { - registerBlockType( 'core/updated-text-block', { + const updatedTextBlock = { + name: 'core/updated-text-block', attributes: { value: { type: 'string', @@ -68,22 +60,27 @@ describe( 'block factory', () => { from: [ { blocks: [ 'core/text-block' ], transform: ( { value } ) => { - return createBlock( 'core/updated-text-block', { - value: 'chicken ' + value, - } ); + return { + name: 'core/updated-text-block', + attributes: { + value: 'chicken ' + value, + }, + }; }, } ], }, save: noop, category: 'common', - } ); - registerBlockType( 'core/text-block', defaultBlockSettings ); + }; + const config = { + blockTypes: [ updatedTextBlock, defaultBlockType ], + }; - const block = createBlock( 'core/text-block', { + const block = createBlock( defaultBlockType, { value: 'ribs', } ); - const transformedBlocks = switchToBlockType( block, 'core/updated-text-block' ); + const transformedBlocks = switchToBlockType( block, 'core/updated-text-block', config ); expect( transformedBlocks ).toHaveLength( 1 ); expect( transformedBlocks[ 0 ] ).toHaveProperty( 'uid' ); @@ -95,8 +92,12 @@ describe( 'block factory', () => { } ); it( 'should switch the blockType of a block using the "transform to"', () => { - registerBlockType( 'core/updated-text-block', defaultBlockSettings ); - registerBlockType( 'core/text-block', { + const updatedTextBlock = { + ...defaultBlockType, + name: 'core/updated-text-block', + }; + const textBlock = { + name: 'core/text-block', attributes: { value: { type: 'string', @@ -106,21 +107,26 @@ describe( 'block factory', () => { to: [ { blocks: [ 'core/updated-text-block' ], transform: ( { value } ) => { - return createBlock( 'core/updated-text-block', { - value: 'chicken ' + value, - } ); + return { + name: 'core/updated-text-block', + attributes: { + value: 'chicken ' + value, + }, + }; }, } ], }, save: noop, category: 'common', - } ); - - const block = createBlock( 'core/text-block', { + }; + const config = { + blockTypes: [ updatedTextBlock, textBlock ], + }; + const block = createBlock( textBlock, { value: 'ribs', } ); - const transformedBlocks = switchToBlockType( block, 'core/updated-text-block' ); + const transformedBlocks = switchToBlockType( block, 'core/updated-text-block', config ); expect( transformedBlocks ).toHaveLength( 1 ); expect( transformedBlocks[ 0 ] ).toHaveProperty( 'uid' ); @@ -132,20 +138,25 @@ describe( 'block factory', () => { } ); it( 'should return null if no transformation is found', () => { - registerBlockType( 'core/updated-text-block', defaultBlockSettings ); - registerBlockType( 'core/text-block', defaultBlockSettings ); - - const block = createBlock( 'core/text-block', { + const updatedTextBlock = { + ...defaultBlockType, + name: 'core/updated-text-block', + }; + const config = { + blockTypes: [ updatedTextBlock, defaultBlockType ], + }; + const block = createBlock( defaultBlockType, { value: 'ribs', } ); - const transformedBlocks = switchToBlockType( block, 'core/updated-text-block' ); + const transformedBlocks = switchToBlockType( block, 'core/updated-text-block', config ); expect( transformedBlocks ).toBeNull(); } ); it( 'should reject transformations that return null', () => { - registerBlockType( 'core/updated-text-block', { + const updatedTextBlock = { + name: 'core/updated-text-block', attributes: { value: { type: 'string', @@ -159,20 +170,22 @@ describe( 'block factory', () => { }, save: noop, category: 'common', - } ); - registerBlockType( 'core/text-block', defaultBlockSettings ); - - const block = createBlock( 'core/text-block', { + }; + const config = { + blockTypes: [ updatedTextBlock, defaultBlockType ], + }; + const block = createBlock( defaultBlockType, { value: 'ribs', } ); - const transformedBlocks = switchToBlockType( block, 'core/updated-text-block' ); + const transformedBlocks = switchToBlockType( block, 'core/updated-text-block', config ); expect( transformedBlocks ).toBeNull(); } ); it( 'should reject transformations that return an empty array', () => { - registerBlockType( 'core/updated-text-block', { + const updatedTextBlock = { + name: 'core/updated-text-block', attributes: { value: { type: 'string', @@ -186,20 +199,22 @@ describe( 'block factory', () => { }, save: noop, category: 'common', - } ); - registerBlockType( 'core/text-block', defaultBlockSettings ); - - const block = createBlock( 'core/text-block', { + }; + const config = { + blockTypes: [ updatedTextBlock, defaultBlockType ], + }; + const block = createBlock( defaultBlockType, { value: 'ribs', } ); - const transformedBlocks = switchToBlockType( block, 'core/updated-text-block' ); + const transformedBlocks = switchToBlockType( block, 'core/updated-text-block', config ); expect( transformedBlocks ).toBeNull(); } ); it( 'should reject single transformations that do not include block types', () => { - registerBlockType( 'core/updated-text-block', { + const updatedTextBlock = { + name: 'core/updated-text-block', attributes: { value: { type: 'string', @@ -219,20 +234,23 @@ describe( 'block factory', () => { }, save: noop, category: 'common', - } ); - registerBlockType( 'core/text-block', defaultBlockSettings ); + }; + const config = { + blockTypes: [ updatedTextBlock, defaultBlockType ], + }; - const block = createBlock( 'core/text-block', { + const block = createBlock( defaultBlockType, { value: 'ribs', } ); - const transformedBlocks = switchToBlockType( block, 'core/updated-text-block' ); + const transformedBlocks = switchToBlockType( block, 'core/updated-text-block', config ); expect( transformedBlocks ).toBeNull(); } ); it( 'should reject array transformations that do not include block types', () => { - registerBlockType( 'core/updated-text-block', { + const updatedTextBlock = { + name: 'core/updated-text-block', attributes: { value: { type: 'string', @@ -243,9 +261,12 @@ describe( 'block factory', () => { blocks: [ 'core/text-block' ], transform: ( { value } ) => { return [ - createBlock( 'core/updated-text-block', { - value: 'chicken ' + value, - } ), + { + name: 'core/updated-text-block', + attributes: { + value: 'chicken ' + value, + }, + }, { attributes: { value: 'smoked ' + value, @@ -257,21 +278,27 @@ describe( 'block factory', () => { }, save: noop, category: 'common', - } ); - registerBlockType( 'core/text-block', defaultBlockSettings ); + }; + const config = { + blockTypes: [ updatedTextBlock, defaultBlockType ], + }; - const block = createBlock( 'core/text-block', { + const block = createBlock( defaultBlockType, { value: 'ribs', } ); - const transformedBlocks = switchToBlockType( block, 'core/updated-text-block' ); + const transformedBlocks = switchToBlockType( block, 'core/updated-text-block', config ); expect( transformedBlocks ).toBeNull(); } ); it( 'should reject single transformations with unexpected block types', () => { - registerBlockType( 'core/updated-text-block', defaultBlockSettings ); - registerBlockType( 'core/text-block', { + const updatedTextBlock = { + ...defaultBlockType, + name: 'core/updated-text-block', + }; + const textBlock = { + name: 'core/text-block', attributes: { value: { type: 'string', @@ -281,28 +308,38 @@ describe( 'block factory', () => { to: [ { blocks: [ 'core/updated-text-block' ], transform: ( { value } ) => { - return createBlock( 'core/text-block', { - value: 'chicken ' + value, - } ); + return { + name: 'core/text-block', + attributes: { + value: 'chicken ' + value, + }, + }; }, } ], }, save: noop, category: 'common', - } ); + }; + const config = { + blockTypes: [ updatedTextBlock, textBlock ], + }; - const block = createBlock( 'core/text-block', { + const block = createBlock( textBlock, { value: 'ribs', } ); - const transformedBlocks = switchToBlockType( block, 'core/updated-text-block' ); + const transformedBlocks = switchToBlockType( block, 'core/updated-text-block', config ); expect( transformedBlocks ).toBeNull(); } ); it( 'should reject array transformations with unexpected block types', () => { - registerBlockType( 'core/updated-text-block', defaultBlockSettings ); - registerBlockType( 'core/text-block', { + const updatedTextBlock = { + ...defaultBlockType, + name: 'core/updated-text-block', + }; + const textBlock = { + name: 'core/text-block', attributes: { value: { type: 'string', @@ -313,32 +350,44 @@ describe( 'block factory', () => { blocks: [ 'core/updated-text-block' ], transform: ( { value } ) => { return [ - createBlock( 'core/text-block', { - value: 'chicken ' + value, - } ), - createBlock( 'core/text-block', { - value: 'smoked ' + value, - } ), + { + name: 'core/text-block', + attributes: { + value: 'chicken ' + value, + }, + }, + { + name: 'core/text-block', + attributes: { + value: 'smoked ' + value, + }, + }, ]; }, } ], }, save: noop, category: 'common', - } ); - - const block = createBlock( 'core/text-block', { + }; + const config = { + blockTypes: [ updatedTextBlock, textBlock ], + }; + const block = createBlock( textBlock, { value: 'ribs', } ); - const transformedBlocks = switchToBlockType( block, 'core/updated-text-block' ); + const transformedBlocks = switchToBlockType( block, 'core/updated-text-block', config ); expect( transformedBlocks ).toEqual( null ); } ); it( 'should accept valid array transformations', () => { - registerBlockType( 'core/updated-text-block', defaultBlockSettings ); - registerBlockType( 'core/text-block', { + const updatedTextBlock = { + ...defaultBlockType, + name: 'core/updated-text-block', + }; + const textBlock = { + name: 'core/text-block', attributes: { value: { type: 'string', @@ -349,25 +398,33 @@ describe( 'block factory', () => { blocks: [ 'core/updated-text-block' ], transform: ( { value } ) => { return [ - createBlock( 'core/text-block', { - value: 'chicken ' + value, - } ), - createBlock( 'core/updated-text-block', { - value: 'smoked ' + value, - } ), + { + name: 'core/text-block', + attributes: { + value: 'chicken ' + value, + }, + }, + { + name: 'core/updated-text-block', + attributes: { + value: 'smoked ' + value, + }, + }, ]; }, } ], }, save: noop, category: 'common', - } ); - - const block = createBlock( 'core/text-block', { + }; + const config = { + blockTypes: [ updatedTextBlock, textBlock ], + }; + const block = createBlock( textBlock, { value: 'ribs', } ); - const transformedBlocks = switchToBlockType( block, 'core/updated-text-block' ); + const transformedBlocks = switchToBlockType( block, 'core/updated-text-block', config ); // Make sure the block UIDs are set as expected: the first // transformed block whose type matches the "destination" type gets diff --git a/blocks/api/test/parser.js b/block-api/test/parser.js similarity index 80% rename from blocks/api/test/parser.js rename to block-api/test/parser.js index 5445f57233a8cb..ed104d29582a84 100644 --- a/blocks/api/test/parser.js +++ b/block-api/test/parser.js @@ -15,15 +15,10 @@ import { createBlockWithFallback, default as parse, } from '../parser'; -import { - registerBlockType, - unregisterBlockType, - getBlockTypes, - setUnknownTypeHandlerName, -} from '../registration'; describe( 'block parser', () => { - const defaultBlockSettings = { + const defaultBlockType = { + name: 'core/test-block', attributes: { fruit: { type: 'string', @@ -33,13 +28,6 @@ describe( 'block parser', () => { category: 'common', }; - afterEach( () => { - setUnknownTypeHandlerName( undefined ); - getBlockTypes().forEach( ( block ) => { - unregisterBlockType( block.name ); - } ); - } ); - describe( 'isValidSource()', () => { it( 'returns false if falsey argument', () => { expect( isValidSource() ).toBe( false ); @@ -159,56 +147,75 @@ describe( 'block parser', () => { describe( 'createBlockWithFallback', () => { it( 'should create the requested block if it exists', () => { - registerBlockType( 'core/test-block', defaultBlockSettings ); - const block = createBlockWithFallback( 'core/test-block', 'content', - { fruit: 'Bananas' } + { fruit: 'Bananas' }, + { blockTypes: [ defaultBlockType ] } ); expect( block.name ).toEqual( 'core/test-block' ); expect( block.attributes ).toEqual( { fruit: 'Bananas' } ); } ); it( 'should create the requested block with no attributes if it exists', () => { - registerBlockType( 'core/test-block', defaultBlockSettings ); - - const block = createBlockWithFallback( 'core/test-block', 'content' ); + const block = createBlockWithFallback( + 'core/test-block', + 'content', + undefined, + { blockTypes: [ defaultBlockType ] } + ); expect( block.name ).toEqual( 'core/test-block' ); expect( block.attributes ).toEqual( {} ); } ); it( 'should fall back to the unknown type handler for unknown blocks if present', () => { - registerBlockType( 'core/unknown-block', defaultBlockSettings ); - setUnknownTypeHandlerName( 'core/unknown-block' ); + const unknownBlockType = { + ...defaultBlockType, + name: 'core/unknown-block', + }; + const config = { + blockTypes: [ unknownBlockType ], + fallbackBlockName: 'core/unknown-block', + }; const block = createBlockWithFallback( 'core/test-block', 'content', - { fruit: 'Bananas' } + { fruit: 'Bananas' }, + config ); expect( block.name ).toEqual( 'core/unknown-block' ); expect( block.attributes ).toEqual( { fruit: 'Bananas' } ); } ); it( 'should fall back to the unknown type handler if block type not specified', () => { - registerBlockType( 'core/unknown-block', defaultBlockSettings ); - setUnknownTypeHandlerName( 'core/unknown-block' ); + const unknownBlockType = { + ...defaultBlockType, + name: 'core/unknown-block', + }; + const config = { + blockTypes: [ unknownBlockType ], + fallbackBlockName: 'core/unknown-block', + }; - const block = createBlockWithFallback( null, 'content' ); + const block = createBlockWithFallback( null, 'content', undefined, config ); expect( block.name ).toEqual( 'core/unknown-block' ); expect( block.attributes ).toEqual( {} ); } ); it( 'should not create a block if no unknown type handler', () => { - const block = createBlockWithFallback( 'core/test-block', 'content' ); + const config = { + blockTypes: [], + }; + const block = createBlockWithFallback( 'core/test-block', 'content', undefined, config ); expect( block ).toBeUndefined(); } ); } ); describe( 'parse()', () => { it( 'should parse the post content, including block attributes', () => { - registerBlockType( 'core/test-block', { + const testBlockType = { + name: 'core/test-block', attributes: { content: { type: 'string', @@ -220,12 +227,16 @@ describe( 'block parser', () => { }, save: noop, category: 'common', - } ); + }; + const config = { + blockTypes: [ testBlockType ], + }; const parsed = parse( '' + 'Brisket' + - '' + '', + config ); expect( parsed ).toHaveLength( 1 ); @@ -240,13 +251,14 @@ describe( 'block parser', () => { } ); it( 'should parse empty post content', () => { - const parsed = parse( '' ); + const parsed = parse( '', { blockTypes: [] } ); expect( parsed ).toEqual( [] ); } ); it( 'should parse the post content, ignoring unknown blocks', () => { - registerBlockType( 'core/test-block', { + const blockType = { + name: 'core/test-block', attributes: { content: { type: 'string', @@ -255,12 +267,16 @@ describe( 'block parser', () => { }, save: noop, category: 'common', - } ); + }; + const config = { + blockTypes: [ blockType ], + }; const parsed = parse( '\nRibs\n' + '
Broccoli
' + - 'Ribs' + 'Ribs', + config ); expect( parsed ).toHaveLength( 1 ); @@ -272,15 +288,21 @@ describe( 'block parser', () => { } ); it( 'should parse the post content, using unknown block handler', () => { - registerBlockType( 'core/test-block', defaultBlockSettings ); - registerBlockType( 'core/unknown-block', defaultBlockSettings ); + const unknownBlockType = { + ...defaultBlockType, + name: 'core/unknown-block', + }; - setUnknownTypeHandlerName( 'core/unknown-block' ); + const config = { + blockTypes: [ defaultBlockType, unknownBlockType ], + fallbackBlockName: 'core/unknown-block', + }; const parsed = parse( 'Ribs' + 'Broccoli
' + - 'Ribs' + 'Ribs', + config ); expect( parsed ).toHaveLength( 3 ); @@ -292,8 +314,8 @@ describe( 'block parser', () => { } ); it( 'should parse the post content, including raw HTML at each end', () => { - registerBlockType( 'core/test-block', defaultBlockSettings ); - registerBlockType( 'core/unknown-block', { + const unknownBlockType = { + name: 'core/unknown-block', attributes: { content: { type: 'string', @@ -302,16 +324,20 @@ describe( 'block parser', () => { }, save: noop, category: 'common', - } ); + }; - setUnknownTypeHandlerName( 'core/unknown-block' ); + const config = { + blockTypes: [ defaultBlockType, unknownBlockType ], + fallbackBlockName: 'core/unknown-block', + }; const parsed = parse( 'Cauliflower
' + 'Ribs' + '\nBroccoli
\n' + 'Ribs' + - 'Romanesco
' + 'Romanesco
', + config ); expect( parsed ).toHaveLength( 5 ); @@ -328,9 +354,12 @@ describe( 'block parser', () => { } ); it( 'should parse blocks with empty content', () => { - registerBlockType( 'core/test-block', defaultBlockSettings ); + const config = { + blockTypes: [ defaultBlockType ], + }; const parsed = parse( - '' + '', + config ); expect( parsed ).toHaveLength( 1 ); @@ -340,11 +369,17 @@ describe( 'block parser', () => { } ); it( 'should parse void blocks', () => { - registerBlockType( 'core/test-block', defaultBlockSettings ); - registerBlockType( 'core/void-block', defaultBlockSettings ); + const voidBlockType = { + ...defaultBlockType, + name: 'core/void-block', + }; + const config = { + blockTypes: [ defaultBlockType, voidBlockType ], + }; const parsed = parse( '' + - '' + '', + config ); expect( parsed ).toHaveLength( 2 ); diff --git a/blocks/api/test/paste.js b/block-api/test/paste.js similarity index 65% rename from blocks/api/test/paste.js rename to block-api/test/paste.js index 02a925a142e1d4..d74abfcce2c813 100644 --- a/blocks/api/test/paste.js +++ b/block-api/test/paste.js @@ -7,7 +7,6 @@ import { equal, deepEqual } from 'assert'; * Internal dependencies */ import paste, { normaliseToBlockLevelNodes } from '../paste'; -import { registerBlockType, unregisterBlockType, setUnknownTypeHandlerName } from '../registration'; import { createBlock } from '../factory'; import { children, prop } from '../source'; @@ -49,56 +48,53 @@ describe( 'normaliseToBlockLevelNodes', () => { } ); describe( 'paste', () => { - beforeAll( () => { - registerBlockType( 'test/small', { - category: 'common', - attributes: { - content: { - type: 'array', - source: children( 'small' ), - }, - }, - transforms: { - from: [ - { - type: 'raw', - isMatch: ( node ) => node.nodeName === 'SMALL', - }, - ], + const smallBlockType = { + name: 'text/small', + category: 'common', + attributes: { + content: { + type: 'array', + source: children( 'small' ), }, - save: () => {}, - } ); - - registerBlockType( 'test/unknown', { - category: 'common', - attributes: { - content: { - type: 'string', - source: prop( 'innerHTML' ), + }, + transforms: { + from: [ + { + type: 'raw', + isMatch: ( node ) => node.nodeName === 'SMALL', }, + ], + }, + save: () => {}, + }; + + const unknownBlockType = { + name: 'test/unknown', + category: 'common', + attributes: { + content: { + type: 'string', + source: prop( 'innerHTML' ), }, - save: () => {}, - } ); + }, + save: () => {}, + }; - setUnknownTypeHandlerName( 'test/unknown' ); - } ); - - afterAll( () => { - unregisterBlockType( 'test/small' ); - unregisterBlockType( 'test/unknown' ); - setUnknownTypeHandlerName( undefined ); - } ); + const editorConfig = { + blockTypes: [ smallBlockType, unknownBlockType ], + fallbackBlockName: 'test/unknown', + }; it( 'should convert recognised pasted content', () => { - const pastedBlock = paste( createNodes( 'test' ) )[ 0 ]; - const block = createBlock( 'test/small', { content: [ 'test' ] } ); + const pastedBlock = paste( createNodes( 'test' ), editorConfig )[ 0 ]; + const block = createBlock( smallBlockType, { content: [ 'test' ] } ); equal( pastedBlock.name, block.name ); deepEqual( pastedBlock.attributes, block.attributes ); } ); it( 'should handle unknown pasted content', () => { - const pastedBlock = paste( createNodes( 'test' ) )[ 0 ]; + const pastedBlock = paste( createNodes( 'test' ), editorConfig )[ 0 ]; equal( pastedBlock.name, 'test/unknown' ); equal( pastedBlock.attributes.content, 'test' ); diff --git a/blocks/api/test/serializer.js b/block-api/test/serializer.js similarity index 92% rename from blocks/api/test/serializer.js rename to block-api/test/serializer.js index 23c3d4b54faacc..a10050044ea24e 100644 --- a/blocks/api/test/serializer.js +++ b/block-api/test/serializer.js @@ -13,16 +13,9 @@ import serialize, { getSaveContent, serializeAttributes, } from '../serializer'; -import { getBlockTypes, registerBlockType, unregisterBlockType } from '../registration'; -import { createBlock } from '../'; +import { createBlock } from '../factory'; describe( 'block serializer', () => { - afterEach( () => { - getBlockTypes().forEach( block => { - unregisterBlockType( block.name ); - } ); - } ); - describe( 'getBeautifulContent()', () => { it( 'returns beautiful content', () => { const content = getBeautifulContent( 'Ribs & Chicken
\n'; - expect( serialize( [ block ] ) ).toEqual( expectedPostContent ); - expect( serialize( block ) ).toEqual( expectedPostContent ); + expect( serialize( [ block ], { blockTypes: [ blockType ] } ) ).toEqual( expectedPostContent ); + expect( serialize( block, { blockTypes: [ blockType ] } ) ).toEqual( expectedPostContent ); } ); } ); } ); diff --git a/blocks/api/test/source.js b/block-api/test/source.js similarity index 100% rename from blocks/api/test/source.js rename to block-api/test/source.js diff --git a/blocks/api/test/validation.js b/block-api/test/validation.js similarity index 93% rename from blocks/api/test/validation.js rename to block-api/test/validation.js index d5de25057b2fe1..16d88c481807a6 100644 --- a/blocks/api/test/validation.js +++ b/block-api/test/validation.js @@ -14,27 +14,14 @@ import { isEquivalentHTML, isValidBlock, } from '../validation'; -import { - registerBlockType, - unregisterBlockType, - getBlockTypes, - getBlockType, - setUnknownTypeHandlerName, -} from '../registration'; describe( 'validation', () => { - const defaultBlockSettings = { + const defaultBlockType = { + name: 'core/test-block', save: ( { attributes } ) => attributes.fruit, category: 'common', }; - afterEach( () => { - setUnknownTypeHandlerName( undefined ); - getBlockTypes().forEach( ( block ) => { - unregisterBlockType( block.name ); - } ); - } ); - describe( 'getTextPiecesSplitOnWhitespace()', () => { it( 'returns text pieces spilt on whitespace', () => { const pieces = getTextPiecesSplitOnWhitespace( ' a \t b \n c' ); @@ -313,21 +300,17 @@ describe( 'validation', () => { describe( 'isValidBlock()', () => { it( 'returns false is block is not valid', () => { - registerBlockType( 'core/test-block', defaultBlockSettings ); - expect( isValidBlock( 'Apples', - getBlockType( 'core/test-block' ), + defaultBlockType, { fruit: 'Bananas' } ) ).toBe( false ); } ); it( 'returns true is block is valid', () => { - registerBlockType( 'core/test-block', defaultBlockSettings ); - expect( isValidBlock( 'Bananas', - getBlockType( 'core/test-block' ), + defaultBlockType, { fruit: 'Bananas' } ) ).toBe( true ); } ); diff --git a/blocks/api/validation.js b/block-api/validation.js similarity index 100% rename from blocks/api/validation.js rename to block-api/validation.js diff --git a/blocks/api/index.js b/blocks/api/index.js index b25e28735a5c84..6f96958674522f 100644 --- a/blocks/api/index.js +++ b/blocks/api/index.js @@ -1,13 +1,3 @@ -/** - * External dependencies - */ -import * as source from './source'; - -export { source }; -export { createBlock, switchToBlockType } from './factory'; -export { default as parse } from './parser'; -export { default as pasteHandler } from './paste'; -export { default as serialize, getBlockDefaultClassname } from './serializer'; export { getCategories } from './categories'; export { registerBlockType, diff --git a/blocks/editable/index.js b/blocks/editable/index.js index 1c97d23d98d9bb..5c1d3173c7e854 100644 --- a/blocks/editable/index.js +++ b/blocks/editable/index.js @@ -22,16 +22,17 @@ import 'element-closest'; * WordPress dependencies */ import { createElement, Component, renderToString } from '@wordpress/element'; +import { parse, pasteHandler } from '@wordpress/block-api'; import { keycodes } from '@wordpress/utils'; /** * Internal dependencies */ import './style.scss'; -import { parse, pasteHandler } from '../api'; import FormatToolbar from './format-toolbar'; import TinyMCE from './tinymce'; import patterns from './patterns'; +import withEditorSettings from '../with-editor-settings'; const { BACKSPACE, DELETE, ENTER } = keycodes; @@ -51,7 +52,7 @@ function createTinyMCEElement( type, props, ...children ) { ); } -export default class Editable extends Component { +export class Editable extends Component { constructor( props ) { super( ...arguments ); @@ -108,7 +109,7 @@ export default class Editable extends Component { editor.on( 'BeforeExecCommand', this.maybePropagateUndo ); editor.on( 'PastePostProcess', this.onPastePostProcess ); - patterns.apply( this, [ editor ] ); + patterns.apply( this, [ editor, this.props.settings ] ); if ( this.props.onSetup ) { this.props.onSetup( editor ); @@ -188,11 +189,11 @@ export default class Editable extends Component { // Internal paste, so parse. if ( childNodes.some( isBlockDelimiter ) ) { - blocks = parse( event.node.innerHTML.replace( /]+>/, '' ) ); + blocks = parse( event.node.innerHTML.replace( /]+>/, '' ), this.props.settings ); // External paste with block level content, so attempt to assign // blocks. } else if ( childNodes.some( isBlockPart ) ) { - blocks = pasteHandler( childNodes ); + blocks = pasteHandler( childNodes, this.props.settings ); } if ( blocks.length ) { @@ -603,3 +604,5 @@ export default class Editable extends Component { Editable.contextTypes = { onUndo: noop, }; + +export default withEditorSettings()( Editable ); diff --git a/blocks/editable/patterns.js b/blocks/editable/patterns.js index e7adec6d41228b..d307ea62f343fb 100644 --- a/blocks/editable/patterns.js +++ b/blocks/editable/patterns.js @@ -9,11 +9,6 @@ import { find, get, escapeRegExp, groupBy, drop } from 'lodash'; */ import { keycodes } from '@wordpress/utils'; -/** - * Internal dependencies - */ -import { getBlockTypes } from '../api/registration'; - /** * Browser dependencies */ @@ -21,7 +16,7 @@ const { setTimeout } = window; const { ESCAPE, ENTER, SPACE, BACKSPACE } = keycodes; -export default function( editor ) { +export default function( editor, editorSettings ) { const getContent = this.getContent.bind( this ); const { onReplace } = this.props; @@ -32,7 +27,7 @@ export default function( editor ) { paste: pastePatterns, enter: enterPatterns, undefined: spacePatterns, - } = groupBy( getBlockTypes().reduce( ( acc, blockType ) => { + } = groupBy( editorSettings.blockTypes.reduce( ( acc, blockType ) => { const transformsFrom = get( blockType, 'transforms.from', [] ); const transforms = transformsFrom.filter( ( { type } ) => type === 'pattern' ); return [ ...acc, ...transforms ]; diff --git a/blocks/editable/test/index.js b/blocks/editable/test/index.js index 8afea0651166ee..cba16c956d435e 100644 --- a/blocks/editable/test/index.js +++ b/blocks/editable/test/index.js @@ -6,7 +6,7 @@ import { shallow } from 'enzyme'; /** * Internal dependencies */ -import Editable from '../'; +import { Editable } from '../'; describe( 'Editable', () => { describe( '.propTypes', () => { diff --git a/blocks/index.js b/blocks/index.js index be044588a67365..8c87a16d84c9b2 100644 --- a/blocks/index.js +++ b/blocks/index.js @@ -22,3 +22,4 @@ export { default as Editable } from './editable'; export { default as EditableProvider } from './editable/provider'; export { default as InspectorControls } from './inspector-controls'; export { default as MediaUploadButton } from './media-upload-button'; +export { default as withEditorSettings } from './with-editor-settings'; diff --git a/blocks/library/audio/index.js b/blocks/library/audio/index.js index 5b4052e7ce4d7a..75dc73e28c558a 100644 --- a/blocks/library/audio/index.js +++ b/blocks/library/audio/index.js @@ -7,12 +7,13 @@ */ import { __ } from '@wordpress/i18n'; import { Placeholder } from '@wordpress/components'; +import { source } from '@wordpress/block-api'; /** * Internal dependencies */ import './style.scss'; -import { registerBlockType, source } from '../../api'; +import { registerBlockType } from '../../api'; import MediaUploadButton from '../../media-upload-button'; const { attr } = source; diff --git a/blocks/library/button/index.js b/blocks/library/button/index.js index 3f84af2b106b49..fd74542642b633 100644 --- a/blocks/library/button/index.js +++ b/blocks/library/button/index.js @@ -3,13 +3,14 @@ */ import { __ } from '@wordpress/i18n'; import { IconButton } from '@wordpress/components'; +import { source } from '@wordpress/block-api'; /** * Internal dependencies */ import './editor.scss'; import './style.scss'; -import { registerBlockType, source } from '../../api'; +import { registerBlockType } from '../../api'; import Editable from '../../editable'; import UrlInput from '../../url-input'; import BlockControls from '../../block-controls'; diff --git a/blocks/library/code/index.js b/blocks/library/code/index.js index 0c6ac022796977..ded406d0e0a0b0 100644 --- a/blocks/library/code/index.js +++ b/blocks/library/code/index.js @@ -7,12 +7,13 @@ import TextareaAutosize from 'react-autosize-textarea'; * WordPress dependencies */ import { __ } from '@wordpress/i18n'; +import { source } from '@wordpress/block-api'; /** * Internal dependencies */ import './editor.scss'; -import { registerBlockType, source, createBlock } from '../../api'; +import { registerBlockType } from '../../api'; const { prop } = source; @@ -36,7 +37,7 @@ registerBlockType( 'core/code', { type: 'pattern', trigger: 'enter', regExp: /^```$/, - transform: () => createBlock( 'core/code' ), + transform: () => ( { name: 'core/code', attributes: {} } ), }, ], }, diff --git a/blocks/library/cover-image/index.js b/blocks/library/cover-image/index.js index 043fa2f40c1c7d..72b01be056317a 100644 --- a/blocks/library/cover-image/index.js +++ b/blocks/library/cover-image/index.js @@ -1,16 +1,21 @@ +/** + * External dependencies + */ +import classnames from 'classnames'; + /** * WordPress dependencies */ import { Placeholder, Toolbar, Dashicon } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; -import classnames from 'classnames'; +import { source } from '@wordpress/block-api'; /** * Internal dependencies */ import './editor.scss'; import './style.scss'; -import { registerBlockType, source } from '../../api'; +import { registerBlockType } from '../../api'; import Editable from '../../editable'; import MediaUploadButton from '../../media-upload-button'; import BlockControls from '../../block-controls'; diff --git a/blocks/library/cover-text/index.js b/blocks/library/cover-text/index.js index 773e32d966731c..b4580d9ecc391c 100644 --- a/blocks/library/cover-text/index.js +++ b/blocks/library/cover-text/index.js @@ -8,12 +8,13 @@ import classnames from 'classnames'; */ import { __ } from '@wordpress/i18n'; import { concatChildren } from '@wordpress/element'; +import { source } from '@wordpress/block-api'; /** * Internal dependencies */ import './style.scss'; -import { registerBlockType, source } from '../../api'; +import { registerBlockType } from '../../api'; import AlignmentToolbar from '../../alignment-toolbar'; import BlockControls from '../../block-controls'; import BlockAlignmentToolbar from '../../block-alignment-toolbar'; diff --git a/blocks/library/embed/index.js b/blocks/library/embed/index.js index e494ef645ac3f6..deb0a942e74a5b 100644 --- a/blocks/library/embed/index.js +++ b/blocks/library/embed/index.js @@ -10,6 +10,7 @@ import { includes } from 'lodash'; import { __, sprintf } from '@wordpress/i18n'; import { Component, renderToString } from '@wordpress/element'; import { Button, Placeholder, Spinner, SandBox } from '@wordpress/components'; +import { source, createBlock } from '@wordpress/block-api'; import { addQueryArgs } from '@wordpress/url'; /** @@ -17,7 +18,7 @@ import { addQueryArgs } from '@wordpress/url'; */ import './style.scss'; import './editor.scss'; -import { registerBlockType, source, createBlock } from '../../api'; +import { registerBlockType } from '../../api'; import Editable from '../../editable'; import BlockControls from '../../block-controls'; import BlockAlignmentToolbar from '../../block-alignment-toolbar'; @@ -229,7 +230,7 @@ function getEmbedBlockSettings( { title, icon, category = 'embed', transforms, k }; } -registerBlockType( +const embedBlockType = registerBlockType( 'core/embed', getEmbedBlockSettings( { title: 'Embed', @@ -241,7 +242,7 @@ registerBlockType( trigger: 'paste', regExp: /^\s*(https?:\/\/\S+)\s*/i, transform: ( { match } ) => { - return createBlock( 'core/embed', { + return createBlock( embedBlockType, { url: match[ 1 ], } ); }, diff --git a/blocks/library/freeform/index.js b/blocks/library/freeform/index.js index 1df0c44a58d46e..720a8e7763bf62 100644 --- a/blocks/library/freeform/index.js +++ b/blocks/library/freeform/index.js @@ -2,12 +2,13 @@ * WordPress dependencies */ import { __ } from '@wordpress/i18n'; +import { source } from '@wordpress/block-api'; /** * Internal dependencies */ import './editor.scss'; -import { registerBlockType, source, setUnknownTypeHandlerName } from '../../api'; +import { registerBlockType, setUnknownTypeHandlerName } from '../../api'; import OldEditor from './old-editor'; const { prop } = source; diff --git a/blocks/library/gallery/index.js b/blocks/library/gallery/index.js index 2faaeef761e311..966bdc84f760de 100644 --- a/blocks/library/gallery/index.js +++ b/blocks/library/gallery/index.js @@ -4,13 +4,14 @@ import { __ } from '@wordpress/i18n'; import { mediaUpload } from '@wordpress/utils'; import { Dashicon, Toolbar, Placeholder, FormFileUpload } from '@wordpress/components'; +import { source } from '@wordpress/block-api'; /** * Internal dependencies */ import './editor.scss'; import './style.scss'; -import { registerBlockType, source } from '../../api'; +import { registerBlockType } from '../../api'; import MediaUploadButton from '../../media-upload-button'; import InspectorControls from '../../inspector-controls'; import RangeControl from '../../inspector-controls/range-control'; diff --git a/blocks/library/heading/index.js b/blocks/library/heading/index.js index a3f50f8878c433..70004eb358e00d 100644 --- a/blocks/library/heading/index.js +++ b/blocks/library/heading/index.js @@ -4,12 +4,13 @@ import { __, sprintf } from '@wordpress/i18n'; import { concatChildren } from '@wordpress/element'; import { Toolbar } from '@wordpress/components'; +import { source } from '@wordpress/block-api'; /** * Internal dependencies */ import './editor.scss'; -import { registerBlockType, createBlock, source } from '../../api'; +import { registerBlockType } from '../../api'; import Editable from '../../editable'; import BlockControls from '../../block-controls'; import InspectorControls from '../../inspector-controls'; @@ -17,6 +18,7 @@ import AlignmentToolbar from '../../alignment-toolbar'; import BlockDescription from '../../block-description'; const { children, prop } = source; +const createTransformationBlock = ( name, attributes ) => ( { name, attributes } ); registerBlockType( 'core/heading', { title: __( 'Heading' ), @@ -53,7 +55,7 @@ registerBlockType( 'core/heading', { type: 'block', blocks: [ 'core/paragraph' ], transform: ( { content } ) => { - return createBlock( 'core/heading', { + return createTransformationBlock( 'core/heading', { content, } ); }, @@ -68,7 +70,7 @@ registerBlockType( 'core/heading', { transform: ( { content, match } ) => { const level = match[ 1 ].length; - return createBlock( 'core/heading', { + return createTransformationBlock( 'core/heading', { nodeName: `H${ level }`, content, } ); @@ -80,7 +82,7 @@ registerBlockType( 'core/heading', { type: 'block', blocks: [ 'core/paragraph' ], transform: ( { content } ) => { - return createBlock( 'core/paragraph', { + return createTransformationBlock( 'core/paragraph', { content, } ); }, @@ -94,7 +96,7 @@ registerBlockType( 'core/heading', { }; }, - edit( { attributes, setAttributes, focus, setFocus, mergeBlocks, insertBlocksAfter } ) { + edit( { attributes, setAttributes, focus, setFocus, mergeBlocks } ) { const { align, content, nodeName, placeholder } = attributes; return [ @@ -147,13 +149,6 @@ registerBlockType( 'core/heading', { onFocus={ setFocus } onChange={ ( value ) => setAttributes( { content: value } ) } onMerge={ mergeBlocks } - onSplit={ ( before, after, ...blocks ) => { - setAttributes( { content: before } ); - insertBlocksAfter( [ - ...blocks, - createBlock( 'core/paragraph', { content: after } ), - ] ); - } } style={ { textAlign: align } } placeholder={ placeholder || __( 'Write heading…' ) } />, diff --git a/blocks/library/html/index.js b/blocks/library/html/index.js index 1b520767647a05..98fe1640fad16d 100644 --- a/blocks/library/html/index.js +++ b/blocks/library/html/index.js @@ -8,12 +8,13 @@ import TextareaAutosize from 'react-autosize-textarea'; */ import { __ } from '@wordpress/i18n'; import { Component } from '@wordpress/element'; +import { source } from '@wordpress/block-api'; /** * Internal dependencies */ import './editor.scss'; -import { registerBlockType, source } from '../../api'; +import { registerBlockType } from '../../api'; import BlockControls from '../../block-controls'; const { html } = source; diff --git a/blocks/library/image/index.js b/blocks/library/image/index.js index 2097dd3f859ff6..27f23898f64337 100644 --- a/blocks/library/image/index.js +++ b/blocks/library/image/index.js @@ -10,14 +10,15 @@ import ResizableBox from 'react-resizable-box'; import { __ } from '@wordpress/i18n'; import { mediaUpload } from '@wordpress/utils'; import { Placeholder, Dashicon, Toolbar, DropZone, FormFileUpload } from '@wordpress/components'; +import { source } from '@wordpress/block-api'; /** * Internal dependencies */ import './style.scss'; import './editor.scss'; -import { registerBlockType, source } from '../../api'; import withEditorSettings from '../../with-editor-settings'; +import { registerBlockType } from '../../api'; import Editable from '../../editable'; import MediaUploadButton from '../../media-upload-button'; import InspectorControls from '../../inspector-controls'; diff --git a/blocks/library/list/index.js b/blocks/library/list/index.js index bbdb512680ed13..056d0aed587503 100644 --- a/blocks/library/list/index.js +++ b/blocks/library/list/index.js @@ -8,16 +8,19 @@ import { find } from 'lodash'; */ import { Component, createElement, Children, concatChildren } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; +import { source, getBlockType, createBlock } from '@wordpress/block-api'; /** * Internal dependencies */ import './editor.scss'; -import { registerBlockType, source, createBlock } from '../../api'; +import { registerBlockType } from '../../api'; import Editable from '../../editable'; import BlockControls from '../../block-controls'; +import withEditorSettings from '../../with-editor-settings'; const { children, prop } = source; +const createTransformationBlock = ( name, attributes ) => ( { name, attributes } ); const fromBrDelimitedContent = ( content ) => { if ( undefined === content ) { @@ -100,7 +103,7 @@ registerBlockType( 'core/list', { type: 'block', blocks: [ 'core/paragraph' ], transform: ( { content } ) => { - return createBlock( 'core/list', { + return createTransformationBlock( 'core/list', { nodeName: 'UL', values: fromBrDelimitedContent( content ), } ); @@ -114,7 +117,7 @@ registerBlockType( 'core/list', { const values = citation ? concatChildren( listItems,{ toBrDelimitedContent( values ) }
], } ); }, @@ -184,7 +187,7 @@ registerBlockType( 'core/list', { }; }, - edit: class extends Component { + edit: withEditorSettings()( class extends Component { constructor() { super( ...arguments ); @@ -275,6 +278,7 @@ registerBlockType( 'core/list', { insertBlocksAfter, setAttributes, mergeBlocks, + settings, } = this.props; const { nodeName, values } = attributes; @@ -323,11 +327,11 @@ registerBlockType( 'core/list', { onMerge={ mergeBlocks } onSplit={ ( before, after, ...blocks ) => { if ( ! blocks.length ) { - blocks.push( createBlock( 'core/paragraph' ) ); + blocks.push( createBlock( getBlockType( 'core/paragraph', settings ) ) ); } if ( after.length ) { - blocks.push( createBlock( 'core/list', { + blocks.push( createBlock( getBlockType( 'core/list', settings ), { nodeName, values: after, } ) ); @@ -339,7 +343,7 @@ registerBlockType( 'core/list', { />, ]; } - }, + } ), save( { attributes } ) { const { nodeName, values } = attributes; diff --git a/blocks/library/paragraph/index.js b/blocks/library/paragraph/index.js index 1061d81e7f4256..263a2c08721ca1 100644 --- a/blocks/library/paragraph/index.js +++ b/blocks/library/paragraph/index.js @@ -3,12 +3,13 @@ */ import { __ } from '@wordpress/i18n'; import { concatChildren } from '@wordpress/element'; +import { source, createBlock } from '@wordpress/block-api'; /** * Internal dependencies */ import './style.scss'; -import { registerBlockType, createBlock, source, setDefaultBlock } from '../../api'; +import { registerBlockType, setDefaultBlock } from '../../api'; import AlignmentToolbar from '../../alignment-toolbar'; import BlockControls from '../../block-controls'; import Editable from '../../editable'; @@ -18,7 +19,7 @@ import BlockDescription from '../../block-description'; const { children } = source; -registerBlockType( 'core/paragraph', { +const textBlockType = registerBlockType( 'core/paragraph', { title: __( 'Paragraph' ), icon: 'editor-paragraph', @@ -107,7 +108,7 @@ registerBlockType( 'core/paragraph', { setAttributes( { content: before } ); insertBlocksAfter( [ ...blocks, - createBlock( 'core/paragraph', { content: after } ), + createBlock( textBlockType, { content: after } ), ] ); } } onMerge={ mergeBlocks } diff --git a/blocks/library/preformatted/index.js b/blocks/library/preformatted/index.js index bbd9f12483ae5b..bb570359732452 100644 --- a/blocks/library/preformatted/index.js +++ b/blocks/library/preformatted/index.js @@ -1,16 +1,18 @@ /** - * WordPress + * WordPress dependencies */ import { __ } from '@wordpress/i18n'; +import { source } from '@wordpress/block-api'; /** * Internal dependencies */ import './editor.scss'; -import { registerBlockType, createBlock, source } from '../../api'; +import { registerBlockType } from '../../api'; import Editable from '../../editable'; const { children } = source; +const createTransformationBlock = ( name, attributes ) => ( { name, attributes } ); registerBlockType( 'core/preformatted', { title: __( 'Preformatted' ), @@ -32,7 +34,7 @@ registerBlockType( 'core/preformatted', { type: 'block', blocks: [ 'core/paragraph' ], transform: ( attributes ) => - createBlock( 'core/preformatted', attributes ), + createTransformationBlock( 'core/preformatted', attributes ), }, ], to: [ @@ -40,7 +42,7 @@ registerBlockType( 'core/preformatted', { type: 'block', blocks: [ 'core/paragraph' ], transform: ( attributes ) => - createBlock( 'core/paragraph', attributes ), + createTransformationBlock( 'core/paragraph', attributes ), }, ], }, diff --git a/blocks/library/pullquote/index.js b/blocks/library/pullquote/index.js index a4223575338e2d..cbeb6b8c4bca22 100644 --- a/blocks/library/pullquote/index.js +++ b/blocks/library/pullquote/index.js @@ -2,13 +2,14 @@ * WordPress dependencies */ import { __ } from '@wordpress/i18n'; +import { source } from '@wordpress/block-api'; /** * Internal dependencies */ import './editor.scss'; import './style.scss'; -import { registerBlockType, source } from '../../api'; +import { registerBlockType } from '../../api'; import Editable from '../../editable'; import BlockControls from '../../block-controls'; import BlockAlignmentToolbar from '../../block-alignment-toolbar'; diff --git a/blocks/library/quote/index.js b/blocks/library/quote/index.js index 88b44b58322880..85a8e4d4195fd7 100644 --- a/blocks/library/quote/index.js +++ b/blocks/library/quote/index.js @@ -8,17 +8,19 @@ import { isString, isObject } from 'lodash'; */ import { __, sprintf } from '@wordpress/i18n'; import { Toolbar } from '@wordpress/components'; +import { source } from '@wordpress/block-api'; /** * Internal dependencies */ import './style.scss'; -import { registerBlockType, createBlock, source } from '../../api'; +import { registerBlockType } from '../../api'; import AlignmentToolbar from '../../alignment-toolbar'; import BlockControls from '../../block-controls'; import Editable from '../../editable'; const { children, node, query } = source; +const createTransformationBlock = ( name, attributes ) => ( { name, attributes } ); registerBlockType( 'core/quote', { title: __( 'Quote' ), @@ -50,7 +52,7 @@ registerBlockType( 'core/quote', { type: 'block', blocks: [ 'core/paragraph' ], transform: ( { content } ) => { - return createBlock( 'core/quote', { + return createTransformationBlock( 'core/quote', { value: [{ content }
, ], @@ -61,7 +63,7 @@ registerBlockType( 'core/quote', { type: 'block', blocks: [ 'core/heading' ], transform: ( { content } ) => { - return createBlock( 'core/quote', { + return createTransformationBlock( 'core/quote', { value: [{ content }
, ], @@ -72,7 +74,7 @@ registerBlockType( 'core/quote', { type: 'pattern', regExp: /^>\s/, transform: ( { content } ) => { - return createBlock( 'core/quote', { + return createTransformationBlock( 'core/quote', { value: [{ content }
, ], @@ -87,16 +89,16 @@ registerBlockType( 'core/quote', { transform: ( { value, citation, ...attrs } ) => { const textElement = value[ 0 ]; if ( ! textElement ) { - return createBlock( 'core/paragraph', { + return createTransformationBlock( 'core/paragraph', { content: citation, } ); } const textContent = isString( textElement ) ? textElement : textElement.props.children; if ( Array.isArray( value ) || citation ) { - const text = createBlock( 'core/paragraph', { + const text = createTransformationBlock( 'core/paragraph', { content: textContent, } ); - const quote = createBlock( 'core/quote', { + const quote = createTransformationBlock( 'core/quote', { ...attrs, citation, value: Array.isArray( value ) ? value.slice( 1 ) : '', @@ -104,7 +106,7 @@ registerBlockType( 'core/quote', { return [ text, quote ]; } - return createBlock( 'core/paragraph', { + return createTransformationBlock( 'core/paragraph', { content: textContent, } ); }, @@ -119,10 +121,10 @@ registerBlockType( 'core/quote', { ? headingElement.props.children : headingElement; if ( isMultiParagraph || citation ) { - const heading = createBlock( 'core/heading', { + const heading = createTransformationBlock( 'core/heading', { content: headingContent, } ); - const quote = createBlock( 'core/quote', { + const quote = createTransformationBlock( 'core/quote', { ...attrs, citation, value: Array.isArray( value ) ? value.slice( 1 ) : '', @@ -130,7 +132,7 @@ registerBlockType( 'core/quote', { return [ heading, quote ]; } - return createBlock( 'core/heading', { + return createTransformationBlock( 'core/heading', { content: headingContent, } ); }, diff --git a/blocks/library/separator/index.js b/blocks/library/separator/index.js index 6bb4e2cc58c835..50bca59b0bce5c 100644 --- a/blocks/library/separator/index.js +++ b/blocks/library/separator/index.js @@ -7,7 +7,7 @@ import { __ } from '@wordpress/i18n'; * Internal dependencies */ import './style.scss'; -import { registerBlockType, createBlock } from '../../api'; +import { registerBlockType } from '../../api'; registerBlockType( 'core/separator', { title: __( 'Separator' ), @@ -24,7 +24,7 @@ registerBlockType( 'core/separator', { type: 'pattern', trigger: 'enter', regExp: /^-{3,}$/, - transform: () => createBlock( 'core/separator' ), + transform: () => ( { name: 'core/separator', attributes: {} } ), }, ], }, diff --git a/blocks/library/shortcode/index.js b/blocks/library/shortcode/index.js index cfa474fe4f2e86..63c836701e5375 100644 --- a/blocks/library/shortcode/index.js +++ b/blocks/library/shortcode/index.js @@ -3,12 +3,13 @@ */ import { __ } from '@wordpress/i18n'; import { withInstanceId, Dashicon } from '@wordpress/components'; +import { source } from '@wordpress/block-api'; /** * Internal dependencies */ import './editor.scss'; -import { registerBlockType, source } from '../../api'; +import { registerBlockType } from '../../api'; import InspectorControls from '../../inspector-controls'; import BlockDescription from '../../block-description'; diff --git a/blocks/library/table/index.js b/blocks/library/table/index.js index b147a050503d29..8351b0d07e9cc3 100644 --- a/blocks/library/table/index.js +++ b/blocks/library/table/index.js @@ -1,14 +1,15 @@ /** - * External dependencies + * WordPress dependencies */ import { __ } from '@wordpress/i18n'; +import { source } from '@wordpress/block-api'; /** * Internal dependencies */ import './editor.scss'; import './style.scss'; -import { registerBlockType, source } from '../../api'; +import { registerBlockType } from '../../api'; import TableBlock from './table-block'; import BlockControls from '../../block-controls'; import BlockAlignmentToolbar from '../../block-alignment-toolbar'; diff --git a/blocks/library/text-columns/index.js b/blocks/library/text-columns/index.js index 82e92e67120459..66b8cfd85bde0c 100644 --- a/blocks/library/text-columns/index.js +++ b/blocks/library/text-columns/index.js @@ -7,13 +7,14 @@ import { times } from 'lodash'; * WordPress dependencies */ import { __ } from '@wordpress/i18n'; +import { source } from '@wordpress/block-api'; /** * Internal dependencies */ import './style.scss'; import './editor.scss'; -import { registerBlockType, source } from '../../api'; +import { registerBlockType } from '../../api'; import BlockControls from '../../block-controls'; import BlockAlignmentToolbar from '../../block-alignment-toolbar'; import RangeControl from '../../inspector-controls/range-control'; diff --git a/blocks/library/verse/index.js b/blocks/library/verse/index.js index 37ccce66f3013a..7ecd5852f2be2b 100644 --- a/blocks/library/verse/index.js +++ b/blocks/library/verse/index.js @@ -2,17 +2,19 @@ * WordPress */ import { __ } from '@wordpress/i18n'; +import { source } from '@wordpress/block-api'; /** * Internal dependencies */ import './editor.scss'; -import { registerBlockType, createBlock, source } from '../../api'; +import { registerBlockType } from '../../api'; import Editable from '../../editable'; import InspectorControls from '../../inspector-controls'; import BlockDescription from '../../block-description'; const { children } = source; +const createTransformationBlock = ( name, attributes ) => ( { name, attributes } ); registerBlockType( 'core/verse', { title: __( 'Verse' ), @@ -36,7 +38,7 @@ registerBlockType( 'core/verse', { type: 'block', blocks: [ 'core/paragraph' ], transform: ( attributes ) => - createBlock( 'core/verse', attributes ), + createTransformationBlock( 'core/verse', attributes ), }, ], to: [ @@ -44,7 +46,7 @@ registerBlockType( 'core/verse', { type: 'block', blocks: [ 'core/paragraph' ], transform: ( attributes ) => - createBlock( 'core/paragraph', attributes ), + createTransformationBlock( 'core/paragraph', attributes ), }, ], }, diff --git a/blocks/library/video/index.js b/blocks/library/video/index.js index 969763595e8304..7823dafc2284d3 100644 --- a/blocks/library/video/index.js +++ b/blocks/library/video/index.js @@ -7,11 +7,12 @@ */ import { __ } from '@wordpress/i18n'; import { Placeholder } from '@wordpress/components'; +import { source } from '@wordpress/block-api'; /** * Internal dependencies */ -import { registerBlockType, source } from '../../api'; +import { registerBlockType } from '../../api'; import MediaUploadButton from '../../media-upload-button'; import Editable from '../../editable'; diff --git a/blocks/test/full-content.js b/blocks/test/full-content.js index daf002e8c9ccc1..0bd3406e1a85ba 100644 --- a/blocks/test/full-content.js +++ b/blocks/test/full-content.js @@ -9,12 +9,16 @@ import { format } from 'util'; /** * Internal dependencies */ -import parse from '../api/parser'; -import { parse as grammarParse } from '../api/post.pegjs'; -import serialize from '../api/serializer'; +import { parse, serialize, grammarParse } from '@wordpress/block-api'; import { getBlockTypes } from '../api/registration'; +// This import registers the blocks +import '../library'; + const fixturesDir = path.join( __dirname, 'fixtures' ); +const settings = { + blockTypes: getBlockTypes(), +}; // We expect 4 different types of files for each fixture: // - fixture.html : original content @@ -133,7 +137,7 @@ describe( 'full post content fixture', () => { ) ); } - const blocksActual = parse( content ); + const blocksActual = parse( content, settings ); const blocksActualNormalized = normalizeParsedBlocks( blocksActual ); let blocksExpectedString = readFixtureFile( f + '.json' ); @@ -167,7 +171,7 @@ describe( 'full post content fixture', () => { // `serialize` doesn't have a trailing newline, but the fixture // files should. - const serializedActual = serialize( blocksActual ) + '\n'; + const serializedActual = serialize( blocksActual, settings ) + '\n'; let serializedExpected = readFixtureFile( f + '.serialized.html' ); if ( ! serializedExpected ) { diff --git a/editor/block-mover/index.js b/editor/block-mover/index.js index d127eea6b03baa..771481157572e3 100644 --- a/editor/block-mover/index.js +++ b/editor/block-mover/index.js @@ -9,7 +9,8 @@ import { first, last } from 'lodash'; */ import { __ } from '@wordpress/i18n'; import { IconButton } from '@wordpress/components'; -import { getBlockType } from '@wordpress/blocks'; +import { withEditorSettings } from '@wordpress/blocks'; +import { getBlockType } from '@wordpress/block-api'; /** * Internal dependencies @@ -59,12 +60,12 @@ function BlockMover( { onMoveUp, onMoveDown, isFirst, isLast, uids, blockType, f ); } -export default connect( +const connectComponent = connect( ( state, ownProps ) => ( { isFirst: isFirstBlock( state, first( ownProps.uids ) ), isLast: isLastBlock( state, last( ownProps.uids ) ), firstIndex: getBlockIndex( state, first( ownProps.uids ) ), - blockType: getBlockType( getBlock( state, first( ownProps.uids ) ).name ), + name: getBlock( state, first( ownProps.uids ) ).name, } ), ( dispatch, ownProps ) => ( { onMoveDown() { @@ -80,4 +81,12 @@ export default connect( } ); }, } ) -)( BlockMover ); +); + +const getEditorSettings = withEditorSettings( ( settings, ownProps ) => { + return { + blockType: getBlockType( ownProps.name, settings ), + }; +} ); + +export default connectComponent( getEditorSettings( BlockMover ) ); diff --git a/editor/block-switcher/index.js b/editor/block-switcher/index.js index 1dc86eccf5a670..e64b9344d5c1a2 100644 --- a/editor/block-switcher/index.js +++ b/editor/block-switcher/index.js @@ -2,7 +2,7 @@ * External dependencies */ import { connect } from 'react-redux'; -import { uniq, get, reduce, find } from 'lodash'; +import { uniq, get, reduce, find, flow } from 'lodash'; import clickOutside from 'react-click-outside'; /** @@ -11,7 +11,8 @@ import clickOutside from 'react-click-outside'; import { __ } from '@wordpress/i18n'; import { Component } from '@wordpress/element'; import { Dashicon, IconButton } from '@wordpress/components'; -import { getBlockType, getBlockTypes, switchToBlockType } from '@wordpress/blocks'; +import { withEditorSettings } from '@wordpress/blocks'; +import { switchToBlockType, getBlockType } from '@wordpress/block-api'; /** * Internal dependencies @@ -48,13 +49,13 @@ class BlockSwitcher extends Component { this.setState( { open: false, } ); - this.props.onTransform( this.props.block, name ); + this.props.onTransform( this.props.block, name, this.props.settings ); }; } render() { - const blockType = getBlockType( this.props.block.name ); - const blocksToBeTransformedFrom = reduce( getBlockTypes(), ( memo, block ) => { + const blockType = getBlockType( this.props.block.name, this.props.settings ); + const blocksToBeTransformedFrom = reduce( this.props.settings.blockTypes, ( memo, block ) => { const transformFrom = get( block, 'transforms.from', [] ); const transformation = find( transformFrom, t => t.type === 'block' && t.blocks.indexOf( this.props.block.name ) !== -1 ); return transformation ? memo.concat( [ block.name ] ) : memo; @@ -63,7 +64,7 @@ class BlockSwitcher extends Component { .reduce( ( memo, transformation ) => memo.concat( transformation.blocks ), [] ); const allowedBlocks = uniq( blocksToBeTransformedFrom.concat( blocksToBeTransformedTo ) ) .reduce( ( memo, name ) => { - const block = getBlockType( name ); + const block = getBlockType( name, this.props.settings ); return !! block ? memo.concat( block ) : memo; }, [] ); @@ -108,16 +109,22 @@ class BlockSwitcher extends Component { } } -export default connect( +const connectComponent = connect( ( state, ownProps ) => ( { block: getBlock( state, ownProps.uid ), } ), ( dispatch, ownProps ) => ( { - onTransform( block, name ) { + onTransform( block, name, settings ) { dispatch( replaceBlocks( [ ownProps.uid ], - switchToBlockType( block, name ) + switchToBlockType( block, name, settings ) ) ); }, } ) -)( clickOutside( BlockSwitcher ) ); +); + +export default flow( + clickOutside, + withEditorSettings(), + connectComponent, +)( BlockSwitcher ); diff --git a/editor/effects.js b/editor/effects.js index 163982fba0e503..b37ef6044a8332 100644 --- a/editor/effects.js +++ b/editor/effects.js @@ -7,7 +7,7 @@ import { get, uniqueId } from 'lodash'; /** * WordPress dependencies */ -import { parse, getBlockType, switchToBlockType } from '@wordpress/blocks'; +import { parse, switchToBlockType, getBlockType } from '@wordpress/block-api'; import { __ } from '@wordpress/i18n'; /** @@ -35,6 +35,7 @@ import { isEditedPostDirty, isEditedPostNew, isEditedPostSaveable, + getEditorSettings, } from './selectors'; const SAVE_POST_NOTICE_ID = 'SAVE_POST_NOTICE_ID'; @@ -182,9 +183,11 @@ export default { store.dispatch( createErrorNotice( message, { id: TRASH_POST_NOTICE_ID } ) ); }, MERGE_BLOCKS( action, store ) { - const { dispatch } = store; + const { dispatch, getState } = store; + const state = getState(); + const editorSettings = getEditorSettings( state ); const [ blockA, blockB ] = action.blocks; - const blockType = getBlockType( blockA.name ); + const blockType = getBlockType( blockA.name, editorSettings ); // Only focus the previous block if it's not mergeable if ( ! blockType.merge ) { @@ -196,7 +199,7 @@ export default { // thus, we transform the block to merge first const blocksWithTheSameType = blockA.name === blockB.name ? [ blockB ] - : switchToBlockType( blockB, blockA.name ); + : switchToBlockType( blockB, blockA.name, editorSettings ); // If the block types can not match, do nothing if ( ! blocksWithTheSameType || ! blocksWithTheSameType.length ) { @@ -251,13 +254,14 @@ export default { dispatch( savePost() ); }, - SET_INITIAL_POST( action ) { + SET_INITIAL_POST( action, { getState } ) { const { post } = action; const effects = []; // Parse content as blocks if ( post.content.raw ) { - effects.push( resetBlocks( parse( post.content.raw ) ) ); + const editorSettings = getEditorSettings( getState() ); + effects.push( resetBlocks( parse( post.content.raw, editorSettings ) ) ); } // Resetting post should occur after blocks have been reset, since it's diff --git a/editor/index.js b/editor/index.js index 6d62c169567b78..be1c46b36efa95 100644 --- a/editor/index.js +++ b/editor/index.js @@ -11,7 +11,7 @@ import 'moment-timezone/moment-timezone-utils'; /** * WordPress dependencies */ -import { EditableProvider } from '@wordpress/blocks'; +import { EditableProvider, getBlockTypes, getUnknownTypeHandlerName, getDefaultBlock, getCategories } from '@wordpress/blocks'; import { createElement, render } from '@wordpress/element'; import { PopoverProvider } from '@wordpress/components'; import { settings as dateSettings } from '@wordpress/date'; @@ -71,9 +71,16 @@ export function createEditorInstance( id, post, settings ) { settings = { ...DEFAULT_SETTINGS, ...settings, + blockTypes: getBlockTypes(), + fallbackBlockName: getUnknownTypeHandlerName(), + defaultBlockName: getDefaultBlock(), + categories: getCategories(), }; - store.dispatch( { type: 'SETUP_EDITOR' } ); + store.dispatch( { + type: 'SETUP_EDITOR', + settings, + } ); store.dispatch( setInitialPost( post ) ); diff --git a/editor/inserter/index.js b/editor/inserter/index.js index 6bc3df1d8696fc..04cc267d37f406 100644 --- a/editor/inserter/index.js +++ b/editor/inserter/index.js @@ -2,6 +2,7 @@ * External dependencies */ import { connect } from 'react-redux'; +import { flow } from 'lodash'; /** * WordPress dependencies @@ -9,7 +10,8 @@ import { connect } from 'react-redux'; import { __ } from '@wordpress/i18n'; import { Component } from '@wordpress/element'; import { Popover, IconButton } from '@wordpress/components'; -import { createBlock } from '@wordpress/blocks'; +import { createBlock, getBlockType } from '@wordpress/block-api'; +import { withEditorSettings } from '@wordpress/blocks'; /** * Internal dependencies @@ -60,9 +62,10 @@ class Inserter extends Component { const { insertionPoint, onInsertBlock, + settings, } = this.props; onInsertBlock( - name, + getBlockType( name, settings ), insertionPoint ); } @@ -98,7 +101,7 @@ class Inserter extends Component { } } -export default connect( +const connectComponent = connect( ( state ) => { return { insertionPoint: getBlockInsertionPoint( state ), @@ -106,12 +109,17 @@ export default connect( }; }, ( dispatch ) => ( { - onInsertBlock( name, after ) { + onInsertBlock( blockType, after ) { dispatch( hideInsertionPoint() ); dispatch( insertBlock( - createBlock( name ), + createBlock( blockType ), after ) ); }, } ) +); + +export default flow( + withEditorSettings(), + connectComponent, )( Inserter ); diff --git a/editor/inserter/menu.js b/editor/inserter/menu.js index 525ac4ae3320c5..0a3028147ac500 100644 --- a/editor/inserter/menu.js +++ b/editor/inserter/menu.js @@ -11,7 +11,7 @@ import { __, _n, sprintf } from '@wordpress/i18n'; import { Component } from '@wordpress/element'; import { withFocusReturn, withInstanceId, withSpokenMessages } from '@wordpress/components'; import { keycodes } from '@wordpress/utils'; -import { getCategories, getBlockTypes, BlockIcon } from '@wordpress/blocks'; +import { withEditorSettings, BlockIcon } from '@wordpress/blocks'; /** * Internal dependencies @@ -60,7 +60,7 @@ export class InserterMenu extends Component { } componentDidUpdate( prevProps, prevState ) { - const searchResults = this.searchBlocks( getBlockTypes() ); + const searchResults = this.searchBlocks( this.props.settings.blockTypes ); // Announce the blocks search results to screen readers. if ( !! searchResults.length ) { this.props.debouncedSpeak( sprintf( _n( @@ -108,15 +108,15 @@ export class InserterMenu extends Component { getBlocksForCurrentTab() { // if we're searching, use everything, otherwise just get the blocks visible in this tab if ( this.state.filterValue ) { - return getBlockTypes(); + return this.props.settings.blockTypes; } switch ( this.state.tab ) { case 'recent': return this.props.recentlyUsedBlocks; case 'blocks': - return filter( getBlockTypes(), ( block ) => block.category !== 'embed' ); + return filter( this.props.settings.blockTypes, ( block ) => block.category !== 'embed' ); case 'embeds': - return filter( getBlockTypes(), ( block ) => block.category === 'embed' ); + return filter( this.props.settings.blockTypes, ( block ) => block.category === 'embed' ); } } @@ -126,7 +126,7 @@ export class InserterMenu extends Component { } const getCategoryIndex = ( item ) => { - return findIndex( getCategories(), ( category ) => category.slug === item.category ); + return findIndex( this.props.settings.categories, ( category ) => category.slug === item.category ); }; return sortBy( blockTypes, getCategoryIndex ); @@ -351,7 +351,7 @@ export class InserterMenu extends Component { } { this.state.tab === 'blocks' && ! isSearching && - getCategories() + this.props.settings.categories .map( ( category ) => !! visibleBlocksByCategory[ category.slug ] && (