-
Guten Berg!
+
+
-
+
diff --git a/blocks/test/fixtures/core__cover-image.json b/blocks/test/fixtures/core__cover-image.json
index 7f12304be6f8ab..8451793404e77c 100644
--- a/blocks/test/fixtures/core__cover-image.json
+++ b/blocks/test/fixtures/core__cover-image.json
@@ -4,15 +4,30 @@
"name": "core/cover-image",
"isValid": true,
"attributes": {
- "title": [
- "Guten Berg!"
- ],
"url": "https://cldup.com/uuUqE_dXzy.jpg",
- "contentAlign": "center",
+ "id": 8398,
"hasParallax": false,
"dimRatio": 40
},
- "innerBlocks": [],
- "originalContent": "
"
+ "innerBlocks": [
+ {
+ "uid": "_uid_0",
+ "name": "core/paragraph",
+ "isValid": true,
+ "attributes": {
+ "content": [
+ "Paragraph 1"
+ ],
+ "align": "center",
+ "dropCap": false,
+ "placeholder": "Write title…",
+ "textColor": "#fff",
+ "fontSize": "large"
+ },
+ "innerBlocks": [],
+ "originalContent": "
Paragraph 1
"
+ }
+ ],
+ "originalContent": "
"
}
]
diff --git a/blocks/test/fixtures/core__cover-image.parsed.json b/blocks/test/fixtures/core__cover-image.parsed.json
index 25808e4279256f..5b285f3d447254 100644
--- a/blocks/test/fixtures/core__cover-image.parsed.json
+++ b/blocks/test/fixtures/core__cover-image.parsed.json
@@ -3,10 +3,23 @@
"blockName": "core/cover-image",
"attrs": {
"url": "https://cldup.com/uuUqE_dXzy.jpg",
+ "id": 8398,
"dimRatio": 40
},
- "innerBlocks": [],
- "innerHTML": "\n
\n"
+ "innerBlocks": [
+ {
+ "blockName": "core/paragraph",
+ "attrs": {
+ "align": "center",
+ "placeholder": "Write title…",
+ "textColor": "#fff",
+ "fontSize": "large"
+ },
+ "innerBlocks": [],
+ "innerHTML": "\n\t\t
Paragraph 1
\n\t\t"
+ }
+ ],
+ "innerHTML": "\n
\n"
},
{
"attrs": {},
diff --git a/blocks/test/fixtures/core__cover-image.serialized.html b/blocks/test/fixtures/core__cover-image.serialized.html
index 160d3aa203dbf1..bf4a6fb9d86e74 100644
--- a/blocks/test/fixtures/core__cover-image.serialized.html
+++ b/blocks/test/fixtures/core__cover-image.serialized.html
@@ -1,5 +1,9 @@
-
+
diff --git a/editor/components/block-list/block.js b/editor/components/block-list/block.js
index ec4059d9e1924d..f71047aaa6abff 100644
--- a/editor/components/block-list/block.js
+++ b/editor/components/block-list/block.js
@@ -571,7 +571,7 @@ export class BlockListBlock extends Component {
{ showSideInserter && (
-
+
( {
- items: getFrecentInserterItems( state, enabledBlockTypes, 4 ),
- } )
- ),
+ withSelect( ( select, { enabledBlockTypes, rootUID } ) => {
+ const { getFrecentInserterItems, getSupportedBlocks } = select( 'core/editor' );
+ const supportedBlocks = getSupportedBlocks( rootUID, enabledBlockTypes );
+ return {
+ items: getFrecentInserterItems( supportedBlocks, 4 ),
+ };
+ } ),
withDispatch( ( dispatch, ownProps ) => {
const { uid, rootUID, layout } = ownProps;
diff --git a/editor/components/inserter/index.js b/editor/components/inserter/index.js
index d8fb08ec6d18e8..43b092b396d780 100644
--- a/editor/components/inserter/index.js
+++ b/editor/components/inserter/index.js
@@ -87,11 +87,32 @@ class Inserter extends Component {
}
export default compose( [
- withSelect( ( select ) => ( {
- title: select( 'core/editor' ).getEditedPostAttribute( 'title' ),
- insertionPoint: select( 'core/editor' ).getBlockInsertionPoint(),
- selectedBlock: select( 'core/editor' ).getSelectedBlock(),
- } ) ),
+ withContext( 'editor' )( ( settings ) => {
+ const { blockTypes, templateLock } = settings;
+
+ return {
+ enabledBlockTypes: blockTypes,
+ isLocked: !! templateLock,
+ };
+ } ),
+ withSelect( ( select, { enabledBlockTypes } ) => {
+ const {
+ getEditedPostAttribute,
+ getBlockInsertionPoint,
+ getSelectedBlock,
+ getSupportedBlocks,
+ } = select( 'core/editor' );
+
+ const insertionPoint = getBlockInsertionPoint();
+ const { rootUID } = insertionPoint;
+ const supportedBlocks = getSupportedBlocks( rootUID, enabledBlockTypes );
+ return {
+ title: getEditedPostAttribute( 'title' ),
+ insertionPoint,
+ selectedBlock: getSelectedBlock(),
+ hasSupportedBlocks: true === supportedBlocks || ! isEmpty( supportedBlocks ),
+ };
+ } ),
withDispatch( ( dispatch, ownProps ) => ( {
showInsertionPoint: dispatch( 'core/editor' ).showInsertionPoint,
hideInsertionPoint: dispatch( 'core/editor' ).hideInsertionPoint,
@@ -106,12 +127,4 @@ export default compose( [
return dispatch( 'core/editor' ).insertBlock( insertedBlock, index, rootUID );
},
} ) ),
- withContext( 'editor' )( ( settings ) => {
- const { blockTypes, templateLock } = settings;
-
- return {
- hasSupportedBlocks: true === blockTypes || ! isEmpty( blockTypes ),
- isLocked: !! templateLock,
- };
- } ),
] )( Inserter );
diff --git a/editor/components/inserter/menu.js b/editor/components/inserter/menu.js
index 669cad3c2eefc3..3cba8ecd5671e1 100644
--- a/editor/components/inserter/menu.js
+++ b/editor/components/inserter/menu.js
@@ -35,7 +35,7 @@ import { keycodes } from '@wordpress/utils';
import './style.scss';
import NoBlocks from './no-blocks';
-import { getInserterItems, getFrecentInserterItems } from '../../store/selectors';
+import { getBlockInsertionPoint, getInserterItems, getFrecentInserterItems, getSupportedBlocks } from '../../store/selectors';
import { fetchReusableBlocks } from '../../store/actions';
import { default as InserterGroup } from './group';
import BlockPreview from '../block-preview';
@@ -349,9 +349,11 @@ export default compose(
} ),
connect(
( state, ownProps ) => {
+ const { rootUID } = getBlockInsertionPoint( state );
+ const supportedBlocks = getSupportedBlocks( state, rootUID, ownProps.enabledBlockTypes );
return {
- items: getInserterItems( state, ownProps.enabledBlockTypes ),
- frecentItems: getFrecentInserterItems( state, ownProps.enabledBlockTypes ),
+ items: getInserterItems( state, supportedBlocks ),
+ frecentItems: getFrecentInserterItems( state, supportedBlocks ),
};
},
{ fetchReusableBlocks }
diff --git a/editor/store/actions.js b/editor/store/actions.js
index dd711abbb9ce61..63246047f35ce1 100644
--- a/editor/store/actions.js
+++ b/editor/store/actions.js
@@ -616,3 +616,11 @@ export function insertDefaultBlock( attributes, rootUID, index ) {
isProvisional: true,
};
}
+
+export function updateBlockListSettings( id, settings ) {
+ return {
+ type: 'UPDATED_BLOCK_LIST_SETTINGS',
+ id,
+ settings,
+ };
+}
diff --git a/editor/store/reducer.js b/editor/store/reducer.js
index e6d0a9f7aa40d4..7700cdabcf5ce9 100644
--- a/editor/store/reducer.js
+++ b/editor/store/reducer.js
@@ -976,6 +976,42 @@ export const reusableBlocks = combineReducers( {
},
} );
+/**
+ * Reducer that for each block uid stores an object that represents its nested nestings.
+ * E.g: what blocks can be nested inside a block.
+ *
+ * @param {Object} state Current state.
+ * @param {Object} action Dispatched action.
+ *
+ * @return {Object} Updated state.
+ */
+export const blockListSettings = ( state = {}, action ) => {
+ switch ( action.type ) {
+ // even if we replace with blocksn with same uid our logic should correct the state
+ case 'REPLACE_BLOCKS' :
+ case 'REMOVE_BLOCKS': {
+ return omit( state, action.uids );
+ }
+ case 'UPDATED_BLOCK_LIST_SETTINGS': {
+ const { id, settings } = action;
+ if ( id && ! settings ) {
+ return omit( state, id );
+ }
+ const blockSettings = state[ id ];
+ const updateIsRequired = ! isEqual( blockSettings, settings );
+ if ( updateIsRequired ) {
+ return {
+ ...state,
+ [ id ]: {
+ ...settings,
+ },
+ };
+ }
+ }
+ }
+ return state;
+};
+
export default optimist( combineReducers( {
editor,
currentPost,
@@ -983,6 +1019,7 @@ export default optimist( combineReducers( {
blockSelection,
provisionalBlockUID,
blocksMode,
+ blockListSettings,
isInsertionPointVisible,
preferences,
saving,
diff --git a/editor/store/selectors.js b/editor/store/selectors.js
index 6e2ccbf6a34738..96f3652f16ba45 100644
--- a/editor/store/selectors.js
+++ b/editor/store/selectors.js
@@ -6,6 +6,7 @@ import {
first,
get,
has,
+ intersection,
last,
reduce,
compact,
@@ -1457,3 +1458,39 @@ export function isPublishingPost( state ) {
export function getProvisionalBlockUID( state ) {
return state.provisionalBlockUID;
}
+
+/**
+ * Returns the Block List settings of a block if any.
+ *
+ * @param {Object} state Editor state.
+ * @param {?string} uid Block UID.
+ *
+ * @return {?Object} Block settings of the block if set.
+ */
+export function getBlockListSettings( state, uid ) {
+ return state.blockListSettings[ uid ];
+}
+
+/**
+ * Determines the blocks that can be nested inside a given block. Or globally if a block is not specified.
+ *
+ * @param {Object} state Global application state.
+ * @param {?string} uid Block UID.
+ * @param {string[]|boolean} globallyEnabledBlockTypes Globally enabled block types, or true/false to enable/disable all types.
+ *
+ * @return {string[]|boolean} Blocks that can be nested inside the block with the specified uid, or true/false to enable/disable all types.
+ */
+export function getSupportedBlocks( state, uid, globallyEnabledBlockTypes ) {
+ if ( ! globallyEnabledBlockTypes ) {
+ return false;
+ }
+
+ const supportedNestedBlocks = get( getBlockListSettings( state, uid ), [ 'supportedBlocks' ] );
+ if ( ! supportedNestedBlocks ) {
+ return globallyEnabledBlockTypes;
+ }
+ if ( globallyEnabledBlockTypes === true ) {
+ return supportedNestedBlocks;
+ }
+ return intersection( globallyEnabledBlockTypes, supportedNestedBlocks );
+}
diff --git a/editor/utils/block-list.js b/editor/utils/block-list.js
index 74ea7a3c69ad58..19ed4ad00d5bed 100644
--- a/editor/utils/block-list.js
+++ b/editor/utils/block-list.js
@@ -1,7 +1,16 @@
+/**
+ * External dependencies
+ */
+import { isEqual, omit } from 'lodash';
+
/**
* WordPress dependencies
*/
-import { Component } from '@wordpress/element';
+import { Component, compose } from '@wordpress/element';
+import {
+ synchronizeBlocksWithTemplate,
+} from '@wordpress/blocks';
+import { withSelect, withDispatch } from '@wordpress/data';
/**
* Internal dependencies
@@ -34,29 +43,89 @@ export function createInnerBlockList( uid, renderBlockMenu, showContextualToolba
if ( ! INNER_BLOCK_LIST_CACHE[ uid ] ) {
INNER_BLOCK_LIST_CACHE[ uid ] = [
// The component class:
- class extends Component {
- componentWillMount() {
- INNER_BLOCK_LIST_CACHE[ uid ][ 1 ]++;
- }
+ compose(
+ withSelect( ( select ) => {
+ const { getBlock, getBlockListSettings } = select( 'core/editor' );
+ return {
+ block: getBlock( uid ),
+ blockListSettings: getBlockListSettings( uid ),
+ };
+ } ),
+ withDispatch( ( dispatch ) => {
+ const { insertBlocks, updateBlockListSettings } = dispatch( 'core/editor' );
+ return {
+ insertBlocks( blocks ) {
+ dispatch( insertBlocks( blocks, undefined, uid ) );
+ },
+ updateNestedSettings( settings ) {
+ dispatch( updateBlockListSettings( uid, settings ) );
+ },
+ };
+ } ),
+ )(
+ class extends Component {
+ constructor() {
+ super( ...arguments );
+ this.updateNestedSettings = this.updateNestedSettings.bind( this );
+ this.insertTemplateBlocks = this.insertTemplateBlocks.bind( this );
+ }
- componentWillUnmount() {
+ insertTemplateBlocks( template ) {
+ const { block, insertBlocks } = this.props;
+ if ( template && ! block.innerBlocks.length ) {
+ // synchronizeBlocksWithTemplate( [], template ) parses the template structure,
+ // and returns/creates the necessary blocks to represent it.
+ insertBlocks( synchronizeBlocksWithTemplate( [], template ) );
+ }
+ }
+
+ updateNestedSettings( newSettings ) {
+ if ( ! isEqual( this.props.blockListSettings, newSettings ) ) {
+ this.props.updateNestedSettings( newSettings );
+ }
+ }
+
+ componentWillMount() {
+ INNER_BLOCK_LIST_CACHE[ uid ][ 1 ]++;
+ this.updateNestedSettings( {
+ supportedBlocks: this.props.allowedBlocks,
+ } );
+ this.insertTemplateBlocks( this.props.template );
+ }
+
+ componentWillReceiveProps( nextProps ) {
+ this.updateNestedSettings( {
+ supportedBlocks: nextProps.allowedBlocks,
+ } );
+ }
+
+ componentWillUnmount() {
// If, after decrementing the tracking count, there are no
// remaining instances of the component, remove from cache.
- if ( ! INNER_BLOCK_LIST_CACHE[ uid ][ 1 ]-- ) {
- delete INNER_BLOCK_LIST_CACHE[ uid ];
+ if ( ! INNER_BLOCK_LIST_CACHE[ uid ][ 1 ]-- ) {
+ delete INNER_BLOCK_LIST_CACHE[ uid ];
+ }
}
- }
- render() {
- return (
-
- );
- }
- },
+ render() {
+ return (
+
+ );
+ }
+ } ),
// A counter tracking active mounted instances:
0,