Skip to content

Commit

Permalink
Fix deletion of custom block classes
Browse files Browse the repository at this point in the history
If you add a custom class to a block and then remove that custom class it would flag the block as invalid. The reason is that the custom class became part of the blocks ‘default’ attributes, and it would then add it back and this then the expected HTML wouldn’t match the current HTML.

This change ensures the block contains the default class names + whatever classes are currently in the HTML, ignoring any custom ones in the block itself. It also handles the
situation where the block's default class doesn't exist in the HTML

The unit tests have been beefed up to cope with several edge case situations
  • Loading branch information
johngodley committed Jul 28, 2018
1 parent a975273 commit 5d986b5
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 3 deletions.
12 changes: 9 additions & 3 deletions packages/editor/src/hooks/custom-class-name.js
Original file line number Diff line number Diff line change
Expand Up @@ -136,15 +136,21 @@ export function addParsedDifference( blockAttributes, blockType, innerHTML ) {
// To determine difference, serialize block given the known set of
// attributes. If there are classes which are mismatched with the
// incoming HTML of the block, add to filtered result.
// If existing classes have been removed then ensure they don't appear in the output
const serialized = getSaveContent( blockType, blockAttributes );
const blockClasses = blockAttributes.className ? blockAttributes.className.split( ' ' ) : [];
const classes = getHTMLRootElementClasses( serialized );
const parsedClasses = getHTMLRootElementClasses( innerHTML );
const customClasses = difference( parsedClasses, classes );

const filteredClassName = compact( [
blockAttributes.className,
// The remaining classes consist of the block's current classes (with default classes removed if they don't already exist in the block)
// along with any custom classes, removing any class that doesn't appear in the innerHTML
const remaining = [
...classes.filter( ( item ) => blockClasses.indexOf( item ) !== -1 ),
...customClasses,
] ).join( ' ' );
].filter( ( item ) => parsedClasses.indexOf( item ) !== -1 );

const filteredClassName = compact( remaining ).join( ' ' );

if ( filteredClassName ) {
blockAttributes.className = filteredClassName;
Expand Down
40 changes: 40 additions & 0 deletions packages/editor/src/hooks/test/custom-class-name.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,5 +110,45 @@ describe( 'custom className', () => {

expect( attributes.className ).toBeUndefined();
} );

it( 'should add a custom class name to an element without a class', () => {
const attributes = addParsedDifference(
{},
blockSettings,
'<div class="foo"></div>'
);

expect( attributes.className ).toBe( 'foo' );
} );

it( 'should remove the custom class and retain default class', () => {
const attributes = addParsedDifference(
{ className: 'default custom' },
blockSettings,
'<div class="default"></div>'
);

expect( attributes.className ).toBe( 'default' );
} );

it( 'should remove the custom class from an element originally without a class', () => {
const attributes = addParsedDifference(
{ className: 'foo' },
blockSettings,
'<div></div>'
);

expect( attributes.className ).toBeUndefined();
} );

it( 'should remove the custom classes and retain default and other custom class', () => {
const attributes = addParsedDifference(
{ className: 'default custom1 custom2 custom3' },
blockSettings,
'<div class="default custom1 custom3"></div>'
);

expect( attributes.className ).toBe( 'default custom1 custom3' );
} );
} );
} );

0 comments on commit 5d986b5

Please sign in to comment.