Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Docs and API: clarify naming around block registration #842

Merged
merged 12 commits into from
Jun 1, 2017
8 changes: 4 additions & 4 deletions blocks/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ function RandomImage( props ) {
} );
}

wp.blocks.registerBlock( 'myplugin/random-image', {
wp.blocks.registerBlockType( 'myplugin/random-image', {
title: 'Random Image',

icon: 'format-image',
Expand Down Expand Up @@ -121,7 +121,7 @@ In the random image block above, we've given the `alt` attribute of the image a

## API

### `wp.blocks.registerBlock( slug: string, settings: Object )`
### `wp.blocks.registerBlockType( name: string, typeDefinition: Object )`

Registers a new block provided a unique slug and an object defining its behavior. Once registered, the block is made available as an option to any editor interface where blocks are implemented.

Expand All @@ -146,9 +146,9 @@ Registers a new block-level control. Controls appear in a block's toolbar when i

Inline controls for [`Editable`](#editable) elements are identical for every block and cannot be modified.

### `wp.blocks.getBlockSettings( slug: string )`
### `wp.blocks.getBlockType( slug: string )`

Returns settings associated with a registered block.
Returns type definitions associated with a registered block.

### `wp.blocks.getControlSettings( slug: string )`

Expand Down
46 changes: 25 additions & 21 deletions blocks/api/factory.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,30 @@ import { get, castArray, findIndex, isObjectLike, find } from 'lodash';
/**
* Internal dependencies
*/
import { getBlockSettings } from './registration';
import { getBlockType } from './registration';

/**
* Returns a block object given its type and attributes
* Returns a block object given its type and attributes.
*
* @param {String} blockType BlockType
* @param {String} name Block name
* @param {Object} attributes Block attributes
* @return {Object} Block object
*/
export function createBlock( blockType, attributes = {} ) {
const blockSettings = getBlockSettings( blockType );
export function createBlock( name, attributes = {} ) {
// Get the type definition associated with a registered block.
const blockType = getBlockType( name );

// Do we need this? What purpose does it have?
let defaultAttributes;
if ( blockSettings ) {
defaultAttributes = blockSettings.defaultAttributes;
if ( blockType ) {
defaultAttributes = blockType.defaultAttributes;
}

// Blocks are stored with a unique ID, the assigned type name,
// and the block attributes.
return {
uid: uuid(),
blockType,
name,
attributes: {
...defaultAttributes,
...attributes,
Expand All @@ -35,24 +39,24 @@ export function createBlock( blockType, attributes = {} ) {
}

/**
* Switch a block into one or more blocks of the new block type
* Switch a block into one or more blocks of the new block type.
*
* @param {Object} block Block object
* @param {string} blockType BlockType
* @param {string} name Block name
* @return {Array} Block object
*/
export function switchToBlockType( block, blockType ) {
export function switchToBlockType( block, name ) {
// Find the right transformation by giving priority to the "to"
// transformation.
const destinationSettings = getBlockSettings( blockType );
const sourceSettings = getBlockSettings( block.blockType );
const transformationsFrom = get( destinationSettings, 'transforms.from', [] );
const transformationsTo = get( sourceSettings, 'transforms.to', [] );
const destinationType = getBlockType( name );
const sourceType = getBlockType( block.name );
const transformationsFrom = get( destinationType, 'transforms.from', [] );
const transformationsTo = get( sourceType, 'transforms.to', [] );
const transformation =
find( transformationsTo, t => t.blocks.indexOf( blockType ) !== -1 ) ||
find( transformationsFrom, t => t.blocks.indexOf( block.blockType ) !== -1 );
find( transformationsTo, t => t.blocks.indexOf( name ) !== -1 ) ||
find( transformationsFrom, t => t.blocks.indexOf( block.name ) !== -1 );

// If no valid transformation, stop. (How did we get here?)
// Stop if there is no valid transformation. (How did we get here?)
if ( ! transformation ) {
return null;
}
Expand All @@ -71,11 +75,11 @@ export function switchToBlockType( block, blockType ) {

// Ensure that every block object returned by the transformation has a
// valid block type.
if ( transformationResults.some( ( result ) => ! getBlockSettings( result.blockType ) ) ) {
if ( transformationResults.some( ( result ) => ! getBlockType( result.name ) ) ) {
return null;
}

const firstSwitchedBlock = findIndex( transformationResults, ( result ) => result.blockType === blockType );
const firstSwitchedBlock = findIndex( transformationResults, ( result ) => result.name === name );

// Ensure that at least one block object returned by the transformation has
// the expected "destination" block type.
Expand All @@ -88,7 +92,7 @@ export function switchToBlockType( block, blockType ) {
// The first transformed block whose type matches the "destination"
// type gets to keep the existing block's UID.
uid: index === firstSwitchedBlock ? block.uid : result.uid,
blockType: result.blockType,
name: result.name,
attributes: result.attributes,
};
} );
Expand Down
8 changes: 4 additions & 4 deletions blocks/api/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ export { default as parse } from './parser';
export { default as serialize } from './serializer';
export { getCategories } from './categories';
export {
registerBlock,
unregisterBlock,
registerBlockType,
unregisterBlockType,
setUnknownTypeHandler,
getUnknownTypeHandler,
getBlockSettings,
getBlocks,
getBlockType,
getBlockTypes,
} from './registration';
78 changes: 41 additions & 37 deletions blocks/api/parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,18 @@ import { escape, unescape, pickBy } from 'lodash';
* Internal dependencies
*/
import { parse as grammarParse } from './post.pegjs';
import { getBlockSettings, getUnknownTypeHandler } from './registration';
import { getBlockType, getUnknownTypeHandler } from './registration';
import { createBlock } from './factory';

/**
* Returns the block attributes parsed from raw content.
*
* @param {String} rawContent Raw block content
* @param {Object} blockSettings Block settings
* @param {Object} blockType Block type
* @return {Object} Block attributes
*/
export function parseBlockAttributes( rawContent, blockSettings ) {
const { attributes } = blockSettings;
export function parseBlockAttributes( rawContent, blockType ) {
const { attributes } = blockType;
if ( 'function' === typeof attributes ) {
return attributes( rawContent );
} else if ( attributes ) {
Expand All @@ -39,21 +39,22 @@ export function parseBlockAttributes( rawContent, blockSettings ) {
}

/**
* Returns the block attributes of a registered block node given its settings.
* Returns the block attributes of a registered block node given its type.
*
* @param {?Object} blockSettings Block settings
* @param {?Object} blockType Block type
* @param {string} rawContent Raw block content
* @param {?Object} attributes Known block attributes (from delimiters)
* @return {Object} All block attributes
*/
export function getBlockAttributes( blockSettings, rawContent, attributes ) {
// Merge any attributes from comment delimiters with block implementation
export function getBlockAttributes( blockType, rawContent, attributes ) {
// Merge any attributes present in comment delimiters with those
// that are specified in the block implementation.
attributes = attributes || {};
if ( blockSettings ) {
if ( blockType ) {
attributes = {
...attributes,
...blockSettings.defaultAttributes,
...parseBlockAttributes( rawContent, blockSettings ),
...blockType.defaultAttributes,
...parseBlockAttributes( rawContent, blockType ),
};
}

Expand All @@ -63,32 +64,32 @@ export function getBlockAttributes( blockSettings, rawContent, attributes ) {
/**
* Creates a block with fallback to the unknown type handler.
*
* @param {?String} blockType Block type slug
* @param {?String} name Block type slug
* @param {String} rawContent Raw block content
* @param {?Object} attributes Attributes obtained from block delimiters
* @return {?Object} An initialized block object (if possible)
*/
export function createBlockWithFallback( blockType, rawContent, attributes ) {
// Use type from block content, otherwise find unknown handler
blockType = blockType || getUnknownTypeHandler();

// Try finding settings for known block type, else again fall back
let blockSettings = getBlockSettings( blockType );
const fallbackBlockType = getUnknownTypeHandler();
if ( ! blockSettings ) {
blockType = fallbackBlockType;
blockSettings = getBlockSettings( blockType );
export function createBlockWithFallback( name, rawContent, attributes ) {
// Use type from block content, otherwise find unknown handler.
name = name || getUnknownTypeHandler();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to standardize on name vs. slug ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe it to be clearer (slug usually not including slashes).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there's a few instances where we're already using slug.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I'm fine with cleaning up later.


// Try finding type for known block name, else fall back again.
let blockType = getBlockType( name );
const fallbackBlock = getUnknownTypeHandler();
if ( ! blockType ) {
name = fallbackBlock;
blockType = getBlockType( name );
}

// Include in set only if settings were determined
// Include in set only if type were determined.
// TODO do we ever expect there to not be an unknown type handler?
if ( blockSettings && ( rawContent.trim() || blockType !== fallbackBlockType ) ) {
if ( blockType && ( rawContent.trim() || name !== fallbackBlock ) ) {
// 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(
blockType,
getBlockAttributes( blockSettings, rawContent.trim(), attributes )
name,
getBlockAttributes( blockType, rawContent.trim(), attributes )
);
return block;
}
Expand Down Expand Up @@ -123,27 +124,30 @@ export function parseWithTinyMCE( content ) {
}
);

// Create a custom HTML schema
// Create a custom HTML schema.
const schema = new tinymce.html.Schema();
// Add <wp-block> "tags" to our schema

// Add <wp-block> "tags" to our schema.
schema.addCustomElements( 'wp-block' );
// Add valid <wp-block> "attributes" also

// Add valid <wp-block> "attributes" also.
schema.addValidElements( 'wp-block[slug|attributes]' );
// Initialize the parser with our custom schema

// Initialize the parser with our custom schema.
const parser = new tinymce.html.DomParser( { validate: true }, schema );

// Parse the content into an object tree
// Parse the content into an object tree.
const tree = parser.parse( content );

// Create a serializer that we will use to pass strings to blocks.
// TODO: pass parse trees instead, and verify them against the markup
// shapes that each block can accept.
const serializer = new tinymce.html.Serializer( { validate: true }, schema );

// Walk the tree and initialize blocks
// Walk the tree and initialize blocks.
const blocks = [];

// Store markup we found in between blocks
// Store markup we found in between blocks.
let contentBetweenBlocks = null;
function flushContentBetweenBlocks() {
if ( contentBetweenBlocks && contentBetweenBlocks.firstChild ) {
Expand All @@ -164,19 +168,19 @@ export function parseWithTinyMCE( content ) {
while ( currentNode ) {
if ( currentNode.name === 'wp-block' ) {
// Set node type to document fragment so that the TinyMCE
// serializer doesn't output its markup
// serializer doesn't output its markup.
currentNode.type = 11;

// Serialize the content
const rawContent = serializer.serialize( currentNode );

// Retrieve the attributes from the <wp-block> tag
// Retrieve the attributes from the <wp-block> tag.
const nodeAttributes = currentNode.attributes.reduce( ( memo, attr ) => {
memo[ attr.name ] = attr.value;
return memo;
}, {} );

// Retrieve the block attributes from the original delimiters
// Retrieve the block attributes from the original delimiters.
const attributesMatcher = /([a-z0-9_-]+)(="([^"]*)")?/g;
const blockAttributes = {};
let match;
Expand All @@ -187,7 +191,7 @@ export function parseWithTinyMCE( content ) {
}
} while ( !! match );

// Try to create the block
// Try to create the block.
const block = createBlockWithFallback(
nodeAttributes.slug,
rawContent,
Expand Down
12 changes: 6 additions & 6 deletions blocks/api/registration.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ let unknownTypeHandler;
* @return {?WPBlock} The block, if it has been successfully
* registered; otherwise `undefined`.
*/
export function registerBlock( slug, settings ) {
export function registerBlockType( slug, settings ) {
if ( typeof slug !== 'string' ) {
console.error(
'Block slugs must be strings.'
Expand Down Expand Up @@ -55,7 +55,7 @@ export function registerBlock( slug, settings ) {
* @return {?WPBlock} The previous block value, if it has been
* successfully unregistered; otherwise `undefined`.
*/
export function unregisterBlock( slug ) {
export function unregisterBlockType( slug ) {
if ( ! blocks[ slug ] ) {
console.error(
'Block "' + slug + '" is not registered.'
Expand Down Expand Up @@ -87,12 +87,12 @@ export function getUnknownTypeHandler() {
}

/**
* Returns settings associated with a registered block.
* Returns a registered block type.
*
* @param {string} slug Block slug
* @return {?Object} Block settings
* @return {?Object} Block type
*/
export function getBlockSettings( slug ) {
export function getBlockType( slug ) {
return blocks[ slug ];
}

Expand All @@ -101,6 +101,6 @@ export function getBlockSettings( slug ) {
*
* @return {Array} Block settings
*/
export function getBlocks() {
export function getBlockTypes() {
return Object.values( blocks );
}
Loading