diff --git a/blocks/api/factory.js b/blocks/api/factory.js
index 310fcae6c0708b..5e07a08c863b34 100644
--- a/blocks/api/factory.js
+++ b/blocks/api/factory.js
@@ -21,15 +21,17 @@ import { __ } from '@wordpress/i18n';
* Internal dependencies
*/
import { getBlockType } from './registration';
+import { getBlockAttributes } from './parser';
/**
* Returns a block object given its type and attributes.
*
- * @param {String} name Block name
- * @param {Object} blockAttributes Block attributes
- * @return {Object} Block object
+ * @param {String} name Block name
+ * @param {Object} blockAttributes Block attributes
+ * @param {?String} innerHTML Block HTML
+ * @return {Object} Block object
*/
-export function createBlock( name, blockAttributes = {} ) {
+export function createBlock( name, blockAttributes = {}, innerHTML ) {
// Get the type definition associated with a registered block.
const blockType = getBlockType( name );
@@ -52,7 +54,7 @@ export function createBlock( name, blockAttributes = {} ) {
uid: uuid(),
name,
isValid: true,
- attributes,
+ attributes: innerHTML ? getBlockAttributes( blockType, innerHTML, attributes ) : attributes,
};
}
diff --git a/blocks/api/raw-handling/strip-attributes.js b/blocks/api/raw-handling/strip-attributes.js
index 6d5ade2f436c47..f3635def25dd7a 100644
--- a/blocks/api/raw-handling/strip-attributes.js
+++ b/blocks/api/raw-handling/strip-attributes.js
@@ -6,7 +6,7 @@ const { ELEMENT_NODE } = window.Node;
/**
* Internal dependencies
*/
-import { isAttributeWhitelisted } from './utils';
+import { isAttributeWhitelisted, isClassWhitelisted } from './utils';
export default function( node ) {
if ( node.nodeType !== ELEMENT_NODE ) {
@@ -20,10 +20,26 @@ export default function( node ) {
const tag = node.nodeName.toLowerCase();
Array.from( node.attributes ).forEach( ( { name } ) => {
- if ( isAttributeWhitelisted( tag, name ) ) {
+ if ( name === 'class' || isAttributeWhitelisted( tag, name ) ) {
return;
}
node.removeAttribute( name );
} );
+
+ const oldClasses = node.getAttribute( 'class' );
+
+ if ( ! oldClasses ) {
+ return;
+ }
+
+ const newClasses = oldClasses.split( ' ' ).filter( ( name ) => {
+ return name && isClassWhitelisted( tag, name );
+ } );
+
+ if ( newClasses.length ) {
+ node.setAttribute( 'class', newClasses.join( ' ' ) );
+ } else {
+ node.removeAttribute( 'class' );
+ }
}
diff --git a/blocks/api/raw-handling/test/strip-attributes.js b/blocks/api/raw-handling/test/strip-attributes.js
index 43dc12511364df..a68469cb202f4f 100644
--- a/blocks/api/raw-handling/test/strip-attributes.js
+++ b/blocks/api/raw-handling/test/strip-attributes.js
@@ -29,4 +29,8 @@ describe( 'stripAttributes', () => {
it( 'should keep some attributes', () => {
equal( deepFilterHTML( 'test', [ stripAttributes ] ), 'test' );
} );
+
+ it( 'should keep some classes', () => {
+ equal( deepFilterHTML( '
', [ stripAttributes ] ), '
' );
+ } );
} );
diff --git a/blocks/api/raw-handling/utils.js b/blocks/api/raw-handling/utils.js
index 1d17199c97bad3..53a44b06535bef 100644
--- a/blocks/api/raw-handling/utils.js
+++ b/blocks/api/raw-handling/utils.js
@@ -34,7 +34,7 @@ const inlineWrapperWhiteList = {
const whitelist = {
...inlineWhitelist,
...inlineWrapperWhiteList,
- img: { attributes: [ 'src', 'alt' ] },
+ img: { attributes: [ 'src', 'alt' ], classes: [ 'alignleft', 'aligncenter', 'alignright', 'alignnone' ] },
figure: {},
blockquote: {},
hr: {},
@@ -63,6 +63,14 @@ export function isAttributeWhitelisted( tag, attribute ) {
);
}
+export function isClassWhitelisted( tag, name ) {
+ return (
+ whitelist[ tag ] &&
+ whitelist[ tag ].classes &&
+ whitelist[ tag ].classes.indexOf( name ) !== -1
+ );
+}
+
export function isInline( node ) {
return !! inlineWhitelist[ node.nodeName.toLowerCase() ];
}
diff --git a/blocks/library/image/index.js b/blocks/library/image/index.js
index 4c94d5f26de71b..8718388cdbff46 100644
--- a/blocks/library/image/index.js
+++ b/blocks/library/image/index.js
@@ -70,6 +70,14 @@ registerBlockType( 'core/image', {
return tag === 'img' || ( hasImage && ! hasText ) || ( hasImage && tag === 'figure' );
},
+ transform: ( node ) => {
+ const targetNode = node.parentNode.querySelector( 'figure,img' );
+ const matches = /align(left|center|right)/.exec( targetNode.className );
+
+ return createBlock( 'core/image', {
+ align: matches ? matches[ 1 ] : undefined,
+ }, targetNode.outerHTML );
+ },
},
{
type: 'files',