Skip to content

Commit

Permalink
Convert to blocks: upgrade and remove spans if possible
Browse files Browse the repository at this point in the history
  • Loading branch information
ellatrix committed Jun 18, 2024
1 parent 0181965 commit dcc35e8
Show file tree
Hide file tree
Showing 9 changed files with 109 additions and 60 deletions.
25 changes: 25 additions & 0 deletions packages/blocks/src/api/raw-handling/anchor-reducer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
export default function anchorReducer( node ) {
if ( node.nodeName === 'A' ) {
// In jsdom-jscore, 'node.target' can be null.
// TODO: Explore fixing this by patching jsdom-jscore.
if ( node.target && node.target.toLowerCase() === '_blank' ) {
node.rel = 'noreferrer noopener';
} else {
node.removeAttribute( 'target' );
node.removeAttribute( 'rel' );
}

// Saves anchor elements name attribute as id
if ( node.name && ! node.id ) {
node.id = node.name;
}

// Keeps id only if there is an internal link pointing to it
if (
node.id &&
! node.ownerDocument.querySelector( `[href="#${ node.id }"]` )
) {
node.removeAttribute( 'id' );
}
}
}
11 changes: 11 additions & 0 deletions packages/blocks/src/api/raw-handling/empty-span-remover.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/**
* WordPress dependencies
*/
import { unwrap } from '@wordpress/dom';

export default ( node ) => {
// Remove spans with no attributes.
if ( node.nodeName === 'SPAN' && ! node.attributes.length ) {
unwrap( node );
}
};
4 changes: 4 additions & 0 deletions packages/blocks/src/api/raw-handling/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import specialCommentConverter from './special-comment-converter';
import listReducer from './list-reducer';
import blockquoteNormaliser from './blockquote-normaliser';
import figureContentReducer from './figure-content-reducer';
import phrasingContentReducer from './phrasing-content-reducer';
import emptySpanRemover from './empty-span-remover';
import shortcodeConverter from './shortcode-converter';
import { deepFilterHTML, getBlockContentSchema } from './utils';

Expand Down Expand Up @@ -69,9 +71,11 @@ export function rawHandler( { HTML = '' } ) {
specialCommentConverter,
// Needed to create media blocks.
figureContentReducer,
phrasingContentReducer,
// Needed to create the quote block, which cannot handle text
// without wrapper paragraphs.
blockquoteNormaliser( { raw: true } ),
emptySpanRemover,
];

piece = deepFilterHTML( piece, filters, blockContentSchema );
Expand Down
3 changes: 3 additions & 0 deletions packages/blocks/src/api/raw-handling/paste-handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import specialCommentConverter from './special-comment-converter';
import commentRemover from './comment-remover';
import isInlineContent from './is-inline-content';
import phrasingContentReducer from './phrasing-content-reducer';
import anchorReducer from './anchor-reducer';
import headRemover from './head-remover';
import msListConverter from './ms-list-converter';
import msListIgnore from './ms-list-ignore';
Expand Down Expand Up @@ -48,6 +49,7 @@ function filterInlineHTML( HTML ) {
googleDocsUIDRemover,
msListIgnore,
phrasingContentReducer,
anchorReducer,
commentRemover,
] );
HTML = removeInvalidHTML( HTML, getPhrasingContentSchema( 'paste' ), {
Expand Down Expand Up @@ -193,6 +195,7 @@ export function pasteHandler( {
listReducer,
imageCorrector,
phrasingContentReducer,
anchorReducer,
specialCommentConverter,
commentRemover,
iframeRemover,
Expand Down
38 changes: 16 additions & 22 deletions packages/blocks/src/api/raw-handling/phrasing-content-reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@
*/
import { wrap, replaceTag } from '@wordpress/dom';

function removeStyle( node, property ) {
node.style[ property ] = '';
if ( ! node.style.length ) {
node.removeAttribute( 'style' );
}
}

export default function phrasingContentReducer( node, doc ) {
// In jsdom-jscore, 'node.style' can be null.
// TODO: Explore fixing this by patching jsdom-jscore.
Expand All @@ -15,11 +22,17 @@ export default function phrasingContentReducer( node, doc ) {
verticalAlign,
} = node.style;

if ( fontWeight === 'normal' || fontWeight === '400' ) {
removeStyle( node, 'fontWeight' );
}

if ( fontWeight === 'bold' || fontWeight === '700' ) {
removeStyle( node, 'fontWeight' );
wrap( doc.createElement( 'strong' ), node );
}

if ( fontStyle === 'italic' ) {
removeStyle( node, 'fontStyle' );
wrap( doc.createElement( 'em' ), node );
}

Expand All @@ -30,39 +43,20 @@ export default function phrasingContentReducer( node, doc ) {
textDecorationLine === 'line-through' ||
textDecoration.includes( 'line-through' )
) {
removeStyle( node, 'textDecoration' );
wrap( doc.createElement( 's' ), node );
}

if ( verticalAlign === 'super' ) {
removeStyle( node, 'verticalAlign' );
wrap( doc.createElement( 'sup' ), node );
} else if ( verticalAlign === 'sub' ) {
removeStyle( node, 'verticalAlign' );
wrap( doc.createElement( 'sub' ), node );
}
} else if ( node.nodeName === 'B' ) {
node = replaceTag( node, 'strong' );
} else if ( node.nodeName === 'I' ) {
node = replaceTag( node, 'em' );
} else if ( node.nodeName === 'A' ) {
// In jsdom-jscore, 'node.target' can be null.
// TODO: Explore fixing this by patching jsdom-jscore.
if ( node.target && node.target.toLowerCase() === '_blank' ) {
node.rel = 'noreferrer noopener';
} else {
node.removeAttribute( 'target' );
node.removeAttribute( 'rel' );
}

// Saves anchor elements name attribute as id
if ( node.name && ! node.id ) {
node.id = node.name;
}

// Keeps id only if there is an internal link pointing to it
if (
node.id &&
! node.ownerDocument.querySelector( `[href="#${ node.id }"]` )
) {
node.removeAttribute( 'id' );
}
}
}
35 changes: 35 additions & 0 deletions packages/blocks/src/api/raw-handling/test/anchor-reducer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/**
* Internal dependencies
*/
import anchorReducer from '../anchor-reducer';
import { deepFilterHTML } from '../utils';

describe( 'anchorReducer', () => {
it( 'should normalise the rel attribute', () => {
const input =
'<a href="https://wordpress.org" target="_blank">WordPress</a>';
const output =
'<a href="https://wordpress.org" target="_blank" rel="noreferrer noopener">WordPress</a>';
expect( deepFilterHTML( input, [ anchorReducer ], {} ) ).toEqual(
output
);
} );

it( 'should only allow target="_blank"', () => {
const input =
'<a href="https://wordpress.org" target="_self">WordPress</a>';
const output = '<a href="https://wordpress.org">WordPress</a>';
expect( deepFilterHTML( input, [ anchorReducer ], {} ) ).toEqual(
output
);
} );

it( 'should remove the rel attribute when target is not set', () => {
const input =
'<a href="https://wordpress.org" rel="noopener">WordPress</a>';
const output = '<a href="https://wordpress.org">WordPress</a>';
expect( deepFilterHTML( input, [ anchorReducer ], {} ) ).toEqual(
output
);
} );
} );
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,7 @@ describe( 'phrasingContentReducer', () => {
[ phrasingContentReducer ],
{}
)
).toEqual(
'<strong><span style="font-weight:bold">test</span></strong>'
);
).toEqual( '<strong><span>test</span></strong>' );
} );

it( 'should transform numeric font weight', () => {
Expand All @@ -24,9 +22,7 @@ describe( 'phrasingContentReducer', () => {
[ phrasingContentReducer ],
{}
)
).toEqual(
'<strong><span style="font-weight:700">test</span></strong>'
);
).toEqual( '<strong><span>test</span></strong>' );
} );

it( 'should transform font style', () => {
Expand All @@ -36,7 +32,7 @@ describe( 'phrasingContentReducer', () => {
[ phrasingContentReducer ],
{}
)
).toEqual( '<em><span style="font-style:italic">test</span></em>' );
).toEqual( '<em><span>test</span></em>' );
} );

it( 'should transform nested formatting', () => {
Expand All @@ -46,36 +42,6 @@ describe( 'phrasingContentReducer', () => {
[ phrasingContentReducer ],
{}
)
).toEqual(
'<strong><em><span style="font-style:italic;font-weight:bold">test</span></em></strong>'
);
} );

it( 'should normalise the rel attribute', () => {
const input =
'<a href="https://wordpress.org" target="_blank">WordPress</a>';
const output =
'<a href="https://wordpress.org" target="_blank" rel="noreferrer noopener">WordPress</a>';
expect(
deepFilterHTML( input, [ phrasingContentReducer ], {} )
).toEqual( output );
} );

it( 'should only allow target="_blank"', () => {
const input =
'<a href="https://wordpress.org" target="_self">WordPress</a>';
const output = '<a href="https://wordpress.org">WordPress</a>';
expect(
deepFilterHTML( input, [ phrasingContentReducer ], {} )
).toEqual( output );
} );

it( 'should remove the rel attribute when target is not set', () => {
const input =
'<a href="https://wordpress.org" rel="noopener">WordPress</a>';
const output = '<a href="https://wordpress.org">WordPress</a>';
expect(
deepFilterHTML( input, [ phrasingContentReducer ], {} )
).toEqual( output );
).toEqual( '<strong><em><span>test</span></em></strong>' );
} );
} );
Original file line number Diff line number Diff line change
Expand Up @@ -218,3 +218,9 @@ exports[`rawHandler should preserve all paragraphs 1`] = `
<p></p>
<!-- /wp:paragraph -->"
`;

exports[`rawHandler should remove convertable spans 1`] = `
"<!-- wp:paragraph -->
<p>a</p>
<!-- /wp:paragraph -->"
`;
5 changes: 5 additions & 0 deletions test/integration/blocks-raw-handling.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -569,4 +569,9 @@ describe( 'rawHandler', () => {
<p style="border: 1px solid tomato;"></p>`;
expect( serialize( rawHandler( { HTML } ) ) ).toMatchSnapshot();
} );

it( 'should remove convertable spans', () => {
const HTML = `<span style="font-weight: 400">a</span>`;
expect( serialize( rawHandler( { HTML } ) ) ).toMatchSnapshot();
} );
} );

0 comments on commit dcc35e8

Please sign in to comment.