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',