diff --git a/blocks/api/raw-handling/strip-attributes.js b/blocks/api/raw-handling/strip-attributes.js index 6d5ade2f436c47..832f71c9e36d5f 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,27 @@ 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 ) => name && isClassWhitelisted( tag, name ) ) + .join( ' ' ); + + if ( newClasses.length ) { + node.setAttribute( 'class', newClasses ); + } 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 38689919f2c990..777c0796eaafb9 100644 --- a/blocks/api/raw-handling/utils.js +++ b/blocks/api/raw-handling/utils.js @@ -49,7 +49,7 @@ const inlineWrapperWhiteList = { const whitelist = { ...inlineWhitelist, ...inlineWrapperWhiteList, - img: { attributes: [ 'src', 'alt' ] }, + img: { attributes: [ 'src', 'alt' ], classes: [ 'alignleft', 'aligncenter', 'alignright', 'alignnone' ] }, figure: {}, blockquote: {}, hr: {}, @@ -100,6 +100,14 @@ export function isInline( node, tagName ) { return !! inlineWhitelist[ nodeName ] || isInlineForTag( nodeName, tagName ); } +export function isClassWhitelisted( tag, name ) { + return ( + whitelist[ tag ] && + whitelist[ tag ].classes && + whitelist[ tag ].classes.indexOf( name ) !== -1 + ); +} + export function isInlineWrapper( node ) { return !! inlineWrapperWhiteList[ node.nodeName.toLowerCase() ]; } diff --git a/blocks/library/image/index.js b/blocks/library/image/index.js index 4c94d5f26de71b..1148571aef77a0 100644 --- a/blocks/library/image/index.js +++ b/blocks/library/image/index.js @@ -9,7 +9,7 @@ import { createMediaFromFile } from '@wordpress/utils'; */ import './style.scss'; import './editor.scss'; -import { registerBlockType, createBlock } from '../../api'; +import { registerBlockType, createBlock, getBlockAttributes, getBlockType } from '../../api'; import ImageBlock from './block'; registerBlockType( 'core/image', { @@ -63,13 +63,22 @@ registerBlockType( 'core/image', { from: [ { type: 'raw', - isMatch: ( node ) => { + isMatch( node ) { const tag = node.nodeName.toLowerCase(); const hasText = !! node.textContent.trim(); const hasImage = node.querySelector( 'img' ); 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 ); + const align = matches ? matches[ 1 ] : undefined; + const blockType = getBlockType( 'core/image' ); + const attributes = getBlockAttributes( blockType, targetNode.outerHTML, { align } ); + + return createBlock( 'core/image', attributes ); + }, }, { type: 'files',