From 716811f11e24e11cf8a76756a6bba5a13409f971 Mon Sep 17 00:00:00 2001
From: Andrew Duthie
Date: Mon, 27 Mar 2017 15:29:12 -0400
Subject: [PATCH 1/9] Render blocks as components
---
editor/blocks/text/index.js | 4 ++--
editor/editor/mode/visual.js | 15 ++++++++++-----
2 files changed, 12 insertions(+), 7 deletions(-)
diff --git a/editor/blocks/text/index.js b/editor/blocks/text/index.js
index 863256be4a27d4..6acb2083751216 100644
--- a/editor/blocks/text/index.js
+++ b/editor/blocks/text/index.js
@@ -10,7 +10,7 @@ wp.blocks.registerBlock( 'core/text', {
value: html()
},
- edit( attributes, onChange ) {
+ edit( { attributes, onChange } ) {
return (
{ attributes.value }
;
}
} );
diff --git a/editor/editor/mode/visual.js b/editor/editor/mode/visual.js
index 945783aecddae1..ca5117b497b0b7 100644
--- a/editor/editor/mode/visual.js
+++ b/editor/editor/mode/visual.js
@@ -20,11 +20,16 @@ function Blocks( { blocks, onChange } ) {
return (
- { blocks.map( ( block, index ) =>
-
- { wp.blocks.getBlockSettings( block.blockType ).edit( block.attributes, onChangeBlock( index ) ) }
-
- ) }
+ { blocks.map( ( block, index ) => {
+ const settings = wp.blocks.getBlockSettings( block.blockType );
+
+ return (
+
+ );
+ } ) }
From 67adf4df84f2c1060aa67b4a134b4da4724b819c Mon Sep 17 00:00:00 2001
From: Andrew Duthie
Date: Tue, 28 Mar 2017 19:32:30 -0400
Subject: [PATCH 2/9] Add missing test for fallback parsed on undefined
attributes
---
blocks/test/parser.js | 21 ++++++++++++++++++++-
1 file changed, 20 insertions(+), 1 deletion(-)
diff --git a/blocks/test/parser.js b/blocks/test/parser.js
index 907489f7552e50..90b38e1b5d211a 100644
--- a/blocks/test/parser.js
+++ b/blocks/test/parser.js
@@ -50,14 +50,33 @@ describe( 'block parser', () => {
const blockNode = {
blockType: 'core/test-block',
- attrs: {},
+ attrs: {
+ align: 'left'
+ },
rawContent: 'Ribs & Chicken'
};
expect( getBlockAttributes( blockNode, blockSettings ) ).to.eql( {
+ align: 'left',
emphasis: '& Chicken'
} );
} );
+
+ it( 'should return parsed attributes for block without attributes defined', () => {
+ const blockSettings = {};
+
+ const blockNode = {
+ blockType: 'core/test-block',
+ attrs: {
+ align: 'left'
+ },
+ rawContent: 'Ribs & Chicken'
+ };
+
+ expect( getBlockAttributes( blockNode, blockSettings ) ).to.eql( {
+ align: 'left'
+ } );
+ } );
} );
describe( 'parse()', () => {
From ba9635b97a41b7d9598be1cf51b7795a10550bee Mon Sep 17 00:00:00 2001
From: Andrew Duthie
Date: Thu, 30 Mar 2017 10:28:04 -0400
Subject: [PATCH 3/9] Disable react/display-name ESLint rule
---
.eslintrc.json | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/.eslintrc.json b/.eslintrc.json
index 2cb6635e3c1330..339e9ac6111fe4 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -63,6 +63,8 @@
"one-var": "off",
"padded-blocks": [ "error", "never" ],
"quote-props": [ "error", "as-needed", { "keywords": true } ],
+ "react/prop-types": "off",
+ "react/display-name": "off",
"semi": "error",
"semi-spacing": "error",
"space-before-blocks": [ "error", "always" ],
@@ -74,7 +76,6 @@
"!": true
}
} ],
- "valid-jsdoc": [ "error", { "requireReturn": false } ],
- "react/prop-types": "off"
+ "valid-jsdoc": [ "error", { "requireReturn": false } ]
}
}
From 2b6130548301bd23b6ed8fc1f2503a1f01e02f83 Mon Sep 17 00:00:00 2001
From: Andrew Duthie
Date: Thu, 30 Mar 2017 10:30:42 -0400
Subject: [PATCH 4/9] Include unknown blocks in parse return value
---
blocks/parser.js | 34 +++++++++++++++++-----------------
blocks/test/parser.js | 20 ++++++++++++++------
2 files changed, 31 insertions(+), 23 deletions(-)
diff --git a/blocks/parser.js b/blocks/parser.js
index d89ea1fddd5551..171aca649d0fcf 100644
--- a/blocks/parser.js
+++ b/blocks/parser.js
@@ -12,19 +12,21 @@ import { getBlockSettings } from './registration';
/**
* Returns the block attributes of a registered block node given its settings.
*
- * @param {Object} blockNode Parsed block node
- * @param {Object} blockSettings Block settings
- * @return {Object} Block state, or undefined if type unknown
+ * @param {Object} blockNode Parsed block node
+ * @param {Object} blockSettings Block settings
+ * @return {Object} Block attributes
*/
export function getBlockAttributes( blockNode, blockSettings ) {
const { rawContent } = blockNode;
// Merge attributes from parse with block implementation
let { attrs } = blockNode;
- if ( 'function' === typeof blockSettings.attributes ) {
- attrs = { ...attrs, ...blockSettings.attributes( rawContent ) };
- } else if ( blockSettings.attributes ) {
- attrs = { ...attrs, ...query.parse( rawContent, blockSettings.attributes ) };
+ if ( blockSettings ) {
+ if ( 'function' === typeof blockSettings.attributes ) {
+ attrs = { ...attrs, ...blockSettings.attributes( rawContent ) };
+ } else if ( blockSettings.attributes ) {
+ attrs = { ...attrs, ...query.parse( rawContent, blockSettings.attributes ) };
+ }
}
return attrs;
@@ -37,16 +39,14 @@ export function getBlockAttributes( blockNode, blockSettings ) {
* @return {Array} Block list
*/
export default function parse( content ) {
- return grammarParse( content ).reduce( ( memo, blockNode ) => {
+ return grammarParse( content ).map( ( blockNode ) => {
const settings = getBlockSettings( blockNode.blockType );
+ const { blockType, rawContent } = blockNode;
- if ( settings ) {
- memo.push( {
- blockType: blockNode.blockType,
- attributes: getBlockAttributes( blockNode, settings )
- } );
- }
-
- return memo;
- }, [] );
+ return {
+ blockType,
+ rawContent,
+ attributes: getBlockAttributes( blockNode, settings )
+ };
+ } );
}
diff --git a/blocks/test/parser.js b/blocks/test/parser.js
index 90b38e1b5d211a..eaecdc850c8e24 100644
--- a/blocks/test/parser.js
+++ b/blocks/test/parser.js
@@ -80,7 +80,7 @@ describe( 'block parser', () => {
} );
describe( 'parse()', () => {
- it( 'should parse the post content properly and ignore unknown blocks', () => {
+ it( 'should parse the post content properly', () => {
const blockSettings = {
attributes: function( rawContent ) {
return {
@@ -93,12 +93,20 @@ describe( 'block parser', () => {
const postContent = 'Ribs' +
'Ribs';
- expect( parse( postContent ) ).to.eql( [ {
- blockType: 'core/test-block',
- attributes: {
- content: 'Ribs & Chicken'
+ expect( parse( postContent ) ).to.eql( [
+ {
+ blockType: 'core/test-block',
+ attributes: {
+ content: 'Ribs & Chicken'
+ },
+ rawContent: 'Ribs'
+ },
+ {
+ blockType: 'core/unknown-block',
+ attributes: {},
+ rawContent: 'Ribs'
}
- } ] );
+ ] );
} );
} );
} );
From a4e2994b00278584dda5ff5ef531ee2c40d3817a Mon Sep 17 00:00:00 2001
From: Andrew Duthie
Date: Thu, 30 Mar 2017 10:31:14 -0400
Subject: [PATCH 5/9] Fall back to dangerous div rendering with undefined edit
---
editor/editor/mode/visual.js | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/editor/editor/mode/visual.js b/editor/editor/mode/visual.js
index ca5117b497b0b7..a635937dcbfbe6 100644
--- a/editor/editor/mode/visual.js
+++ b/editor/editor/mode/visual.js
@@ -23,8 +23,17 @@ function Blocks( { blocks, onChange } ) {
{ blocks.map( ( block, index ) => {
const settings = wp.blocks.getBlockSettings( block.blockType );
+ let Edit;
+ if ( settings ) {
+ Edit = settings.edit || settings.save;
+ }
+
+ if ( ! Edit ) {
+ Edit = () => ;
+ }
+
return (
-
From 9bf268cdfff496e182fa5c9131a48fa77282c2fb Mon Sep 17 00:00:00 2001
From: Andrew Duthie
Date: Fri, 31 Mar 2017 10:36:31 -0400
Subject: [PATCH 6/9] Allow assignment of unknown block type handler
---
blocks/index.js | 9 +++++++-
blocks/parser.js | 34 ++++++++++++++++++---------
blocks/post.pegjs | 1 -
blocks/registration.js | 27 +++++++++++++++++++++-
blocks/test/parser.js | 45 +++++++++++++++++++++---------------
blocks/test/registration.js | 30 ++++++++++++++++++++----
editor/editor/mode/visual.js | 34 +++++++++++++--------------
7 files changed, 125 insertions(+), 55 deletions(-)
diff --git a/blocks/index.js b/blocks/index.js
index 83d496a96f7aa3..714407089947f0 100644
--- a/blocks/index.js
+++ b/blocks/index.js
@@ -7,4 +7,11 @@ export { query };
export { default as Editable } from './components/editable';
export { default as parse } from './parser';
export { getCategories } from './categories';
-export { registerBlock, unregisterBlock, getBlockSettings, getBlocks } from './registration';
+export {
+ registerBlock,
+ unregisterBlock,
+ setUnknownTypeHandler,
+ getUnknownTypeHandler,
+ getBlockSettings,
+ getBlocks
+} from './registration';
diff --git a/blocks/parser.js b/blocks/parser.js
index 171aca649d0fcf..39d74c6a36b018 100644
--- a/blocks/parser.js
+++ b/blocks/parser.js
@@ -7,7 +7,7 @@ import * as query from 'hpq';
* Internal dependencies
*/
import { parse as grammarParse } from './post.pegjs';
-import { getBlockSettings } from './registration';
+import { getBlockSettings, getUnknownTypeHandler } from './registration';
/**
* Returns the block attributes of a registered block node given its settings.
@@ -39,14 +39,26 @@ export function getBlockAttributes( blockNode, blockSettings ) {
* @return {Array} Block list
*/
export default function parse( content ) {
- return grammarParse( content ).map( ( blockNode ) => {
- const settings = getBlockSettings( blockNode.blockType );
- const { blockType, rawContent } = blockNode;
-
- return {
- blockType,
- rawContent,
- attributes: getBlockAttributes( blockNode, settings )
- };
- } );
+ return grammarParse( content ).reduce( ( memo, blockNode ) => {
+ // Use type from block node, otherwise find unknown handler
+ let { blockType = getUnknownTypeHandler() } = blockNode;
+
+ // Try finding settings for known block type, else again fall back
+ let settings = getBlockSettings( blockType );
+ if ( ! settings ) {
+ blockType = getUnknownTypeHandler();
+ settings = getBlockSettings( blockType );
+ }
+
+ // Include in set only if settings were determined
+ if ( settings ) {
+ memo.push( {
+ blockType,
+ rawContent: blockNode.rawContent,
+ attributes: getBlockAttributes( blockNode, settings )
+ } );
+ }
+
+ return memo;
+ }, [] );
}
diff --git a/blocks/post.pegjs b/blocks/post.pegjs
index af19f0f396a418..b77b8a82ac14b3 100644
--- a/blocks/post.pegjs
+++ b/blocks/post.pegjs
@@ -20,7 +20,6 @@ WP_Block_Html
= ts:(!WP_Block_Balanced c:Any { return c })+
{
return {
- blockType: 'html',
attrs: {},
rawContent: ts.join( '' )
}
diff --git a/blocks/registration.js b/blocks/registration.js
index f3593ce9b09f8e..edc182a9d082a0 100644
--- a/blocks/registration.js
+++ b/blocks/registration.js
@@ -3,10 +3,17 @@
/**
* Block settings keyed by block slug.
*
- * @var {Object} blocks
+ * @type {Object}
*/
const blocks = {};
+/**
+ * Slug of block handling unknown types.
+ *
+ * @type {?string}
+ */
+let unknownTypeHandler;
+
/**
* 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
@@ -60,6 +67,24 @@ export function unregisterBlock( slug ) {
return oldBlock;
}
+/**
+ * Assigns slug of block handling unknown block types.
+ *
+ * @param {string} slug Block slug
+ */
+export function setUnknownTypeHandler( slug ) {
+ unknownTypeHandler = slug;
+}
+
+/**
+ * Retrieves slug of block handling unknown block types.
+ *
+ * @return {string} Blog slug
+ */
+export function getUnknownTypeHandler() {
+ return unknownTypeHandler;
+}
+
/**
* Returns settings associated with a registered block.
*
diff --git a/blocks/test/parser.js b/blocks/test/parser.js
index eaecdc850c8e24..d22fc241ce7964 100644
--- a/blocks/test/parser.js
+++ b/blocks/test/parser.js
@@ -8,10 +8,11 @@ import { text } from 'hpq';
* Internal dependencies
*/
import { default as parse, getBlockAttributes } from '../parser';
-import { getBlocks, unregisterBlock, registerBlock } from '../registration';
+import { getBlocks, unregisterBlock, setUnknownTypeHandler, registerBlock } from '../registration';
describe( 'block parser', () => {
- beforeEach( () => {
+ afterEach( () => {
+ setUnknownTypeHandler( undefined );
getBlocks().forEach( ( block ) => {
unregisterBlock( block.slug );
} );
@@ -80,33 +81,39 @@ describe( 'block parser', () => {
} );
describe( 'parse()', () => {
- it( 'should parse the post content properly', () => {
- const blockSettings = {
+ it( 'should parse the post content, ignoring unknown blocks', () => {
+ registerBlock( 'core/test-block', {
attributes: function( rawContent ) {
return {
content: rawContent + ' & Chicken'
};
}
- };
- registerBlock( 'core/test-block', blockSettings );
+ } );
const postContent = 'Ribs' +
+ 'Broccoli
' +
'Ribs';
- expect( parse( postContent ) ).to.eql( [
- {
- blockType: 'core/test-block',
- attributes: {
- content: 'Ribs & Chicken'
- },
- rawContent: 'Ribs'
+ expect( parse( postContent ) ).to.eql( [ {
+ blockType: 'core/test-block',
+ attributes: {
+ content: 'Ribs & Chicken'
},
- {
- blockType: 'core/unknown-block',
- attributes: {},
- rawContent: 'Ribs'
- }
- ] );
+ rawContent: 'Ribs'
+ } ] );
+ } );
+
+ it( 'should parse the post content, using unknown block handler', () => {
+ registerBlock( 'core/test-block', {} );
+ registerBlock( 'core/unknown-block', {} );
+
+ setUnknownTypeHandler( 'core/unknown-block' );
+
+ const postContent = 'Ribs' +
+ 'Broccoli
' +
+ 'Ribs';
+
+ expect( parse( postContent ) ).to.have.lengthOf( 3 );
} );
} );
} );
diff --git a/blocks/test/registration.js b/blocks/test/registration.js
index ee6e15137c17d3..3af2d10dfe6c18 100644
--- a/blocks/test/registration.js
+++ b/blocks/test/registration.js
@@ -9,18 +9,26 @@ import sinon from 'sinon';
/**
* Internal dependencies
*/
-import { getBlocks, unregisterBlock, registerBlock, getBlockSettings } from '../registration';
+import {
+ registerBlock,
+ unregisterBlock,
+ setUnknownTypeHandler,
+ getUnknownTypeHandler,
+ getBlockSettings,
+ getBlocks
+} from '../registration';
describe( 'blocks', () => {
// Reset block state before each test.
beforeEach( () => {
- getBlocks().forEach( block => {
- unregisterBlock( block.slug );
- } );
sinon.stub( console, 'error' );
} );
afterEach( () => {
+ getBlocks().forEach( block => {
+ unregisterBlock( block.slug );
+ } );
+ setUnknownTypeHandler( undefined );
console.error.restore();
} );
@@ -86,6 +94,20 @@ describe( 'blocks', () => {
} );
} );
+ describe( 'setUnknownTypeHandler()', () => {
+ it( 'assigns unknown type handler', () => {
+ setUnknownTypeHandler( 'core/test-block' );
+
+ expect( getUnknownTypeHandler() ).to.equal( 'core/test-block' );
+ } );
+ } );
+
+ describe( 'getUnknownTypeHandler()', () => {
+ it( 'defaults to undefined', () => {
+ expect( getUnknownTypeHandler() ).to.be.undefined();
+ } );
+ } );
+
describe( 'getBlockSettings()', () => {
it( 'should return { slug } for blocks with no settings', () => {
registerBlock( 'core/test-block' );
diff --git a/editor/editor/mode/visual.js b/editor/editor/mode/visual.js
index a635937dcbfbe6..97346147f12800 100644
--- a/editor/editor/mode/visual.js
+++ b/editor/editor/mode/visual.js
@@ -19,27 +19,25 @@ function Blocks( { blocks, onChange } ) {
return (
-
- { blocks.map( ( block, index ) => {
- const settings = wp.blocks.getBlockSettings( block.blockType );
+ { blocks.map( ( block, index ) => {
+ const settings = wp.blocks.getBlockSettings( block.blockType );
- let Edit;
- if ( settings ) {
- Edit = settings.edit || settings.save;
- }
+ let BlockEdit;
+ if ( settings ) {
+ BlockEdit = settings.edit || settings.save;
+ }
- if ( ! Edit ) {
- Edit = () =>
;
- }
+ if ( ! BlockEdit ) {
+ return;
+ }
- return (
-
- );
- } ) }
-
+ return (
+
+ );
+ } ) }
);
From 8ff84e97851f26ec905645ecb313ff7f888b49af Mon Sep 17 00:00:00 2001
From: Andrew Duthie
Date: Fri, 31 Mar 2017 10:36:41 -0400
Subject: [PATCH 7/9] Register freeform block as unknown block handler
---
editor/blocks/freeform/index.js | 23 +++++++++++++++++++++++
editor/blocks/index.js | 1 +
2 files changed, 24 insertions(+)
create mode 100644 editor/blocks/freeform/index.js
diff --git a/editor/blocks/freeform/index.js b/editor/blocks/freeform/index.js
new file mode 100644
index 00000000000000..b31c419aaf2d6e
--- /dev/null
+++ b/editor/blocks/freeform/index.js
@@ -0,0 +1,23 @@
+const { html } = wp.blocks.query;
+
+wp.blocks.registerBlock( 'core/freeform', {
+ title: 'Freeform',
+
+ icon: 'text',
+
+ category: 'common',
+
+ attributes: {
+ html: html()
+ },
+
+ edit( { attributes } ) {
+ return { attributes.html }
;
+ },
+
+ save( { attributes } ) {
+ return attributes.html;
+ }
+} );
+
+wp.blocks.setUnknownTypeHandler( 'core/freeform' );
diff --git a/editor/blocks/index.js b/editor/blocks/index.js
index 7319406b858f04..a31abdee56c194 100644
--- a/editor/blocks/index.js
+++ b/editor/blocks/index.js
@@ -1 +1,2 @@
+import './freeform';
import './text';
From eaa5dfc1959c2e291311d3c01e50278a4b90de0e Mon Sep 17 00:00:00 2001
From: Andrew Duthie
Date: Fri, 31 Mar 2017 10:38:10 -0400
Subject: [PATCH 8/9] Clarify possible undefined return value from unknown type
getter
---
blocks/registration.js | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/blocks/registration.js b/blocks/registration.js
index edc182a9d082a0..3dcd1f86b356c6 100644
--- a/blocks/registration.js
+++ b/blocks/registration.js
@@ -77,9 +77,10 @@ export function setUnknownTypeHandler( slug ) {
}
/**
- * Retrieves slug of block handling unknown block types.
+ * Retrieves slug of block handling unknown block types, or undefined if no
+ * handler has been defined.
*
- * @return {string} Blog slug
+ * @return {?string} Blog slug
*/
export function getUnknownTypeHandler() {
return unknownTypeHandler;
From 15db036eb14f71665424c4d79e17b9c08f629123 Mon Sep 17 00:00:00 2001
From: Andrew Duthie
Date: Fri, 31 Mar 2017 11:15:31 -0400
Subject: [PATCH 9/9] Test block type of parsed unknown blocks
---
blocks/test/parser.js | 23 ++++++++++++++++-------
1 file changed, 16 insertions(+), 7 deletions(-)
diff --git a/blocks/test/parser.js b/blocks/test/parser.js
index d22fc241ce7964..41dd68a5a45454 100644
--- a/blocks/test/parser.js
+++ b/blocks/test/parser.js
@@ -90,11 +90,13 @@ describe( 'block parser', () => {
}
} );
- const postContent = 'Ribs' +
+ const parsed = parse(
+ 'Ribs' +
'Broccoli
' +
- 'Ribs';
+ 'Ribs'
+ );
- expect( parse( postContent ) ).to.eql( [ {
+ expect( parsed ).to.eql( [ {
blockType: 'core/test-block',
attributes: {
content: 'Ribs & Chicken'
@@ -109,11 +111,18 @@ describe( 'block parser', () => {
setUnknownTypeHandler( 'core/unknown-block' );
- const postContent = 'Ribs' +
+ const parsed = parse(
+ 'Ribs' +
'Broccoli
' +
- 'Ribs';
-
- expect( parse( postContent ) ).to.have.lengthOf( 3 );
+ 'Ribs'
+ );
+
+ expect( parsed ).to.have.lengthOf( 3 );
+ expect( parsed.map( ( { blockType } ) => blockType ) ).to.eql( [
+ 'core/test-block',
+ 'core/unknown-block',
+ 'core/unknown-block'
+ ] );
} );
} );
} );