-
Notifications
You must be signed in to change notification settings - Fork 4.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Keep and handle image alignment classes for raw transforms #3724
Conversation
Codecov Report
@@ Coverage Diff @@
## master #3724 +/- ##
==========================================
- Coverage 39.08% 37.96% -1.12%
==========================================
Files 295 278 -17
Lines 7016 6806 -210
Branches 1290 1247 -43
==========================================
- Hits 2742 2584 -158
+ Misses 3588 3557 -31
+ Partials 686 665 -21
Continue to review full report at Codecov.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This works well for me, but I need to sleep on the block API changes and the whitelisting approach in order to form an opinion. 😄
|
||
const newClasses = oldClasses.split( ' ' ).filter( ( name ) => { | ||
return name && isClassWhitelisted( tag, name ); | ||
} ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For type consistency with oldClasses
, the join should happen here:
const newClasses = oldClasses.split( ' ' ).filter( … ).join( ' ' );
also, that filter predicate is a great candidate for implicit return
.filter( ( name ) => name && …
The subsequent newClasses.length
would still work (switching from Array#length
to String#length
).
@@ -34,7 +34,7 @@ const inlineWrapperWhiteList = { | |||
const whitelist = { | |||
...inlineWhitelist, | |||
...inlineWrapperWhiteList, | |||
img: { attributes: [ 'src', 'alt' ] }, | |||
img: { attributes: [ 'src', 'alt' ], classes: [ 'alignleft', 'aligncenter', 'alignright', 'alignnone' ] }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Side thought: we should start to consider performance and do some measuring. Some of the predicates that consume this data could perhaps benefit from a more barebones switch
construct, for instance.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you give an example?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, I just had this benchmark in the back of my head.
blocks/library/image/index.js
Outdated
@@ -70,6 +70,14 @@ registerBlockType( 'core/image', { | |||
|
|||
return tag === 'img' || ( hasImage && ! hasText ) || ( hasImage && tag === 'figure' ); | |||
}, | |||
transform: ( node ) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor suggestion: shorthand transform( node ) {
blocks/library/image/index.js
Outdated
@@ -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 ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
matches
doesn't mean much in the context of the entire transform. I suggest encapsulating the whole thing such that you get
const align = parseAlignment( node );
// or, if you prefer (I personally don't):
const align = parseAlignment( node.parentNode.querySelector( 'figure, img' ) );
return createBlock( …, { align }, targetNode.outerHTML );
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't really understand the need here to wrap that in another function. Also, the second option would be needed to get targetNode
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't feel as strongly as I did when I wrote this. :)
blocks/api/factory.js
Outdated
* @param {String} name Block name | ||
* @param {Object} blockAttributes Block attributes | ||
* @param {?String} innerHTML Block HTML | ||
* @return {Object} Block object |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm still undecided on this API change; in any case, I suggest explaining in the jsdoc what the implications of passing that optional innerHTML
are, or why one should use it.
blocks/api/factory.js
Outdated
@@ -52,7 +54,7 @@ export function createBlock( name, blockAttributes = {} ) { | |||
uid: uuid(), | |||
name, | |||
isValid: true, | |||
attributes, | |||
attributes: innerHTML ? getBlockAttributes( blockType, innerHTML, attributes ) : attributes, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If it helps the discussion, getBlockAttributes
is already part of the public interface of @wordpress/blocks
; in other words, this change is more about the convenience we offer block authors with this polymorphic version of createBlock
rather than keeping some piece of the blocks module private.
blocks/api/factory.js
Outdated
*/ | ||
export function createBlock( name, blockAttributes = {} ) { | ||
export function createBlock( name, blockAttributes = {}, innerHTML ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Before this change, createBlock
meant something very basic: run a simple check against blockType.attributes
to grab the default values when values are missing, and return a plain object representing a block. No parsing is involved, etc.
- Are we OK with changing that?
- Do we prefer adding a dedicated function, e.g.
createBlockFromHTML( name, innerHTML, extraAttributes )
? - Do we prefer not adding anything and requiring authors to combine
createBlock
andgetBlockAttributes
on their own?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel bad not mentioning this in the PR description. Yes, there are some options here, and code wise all of them don't require much extra. I first used getBlockAttributes
, but then thought it made sense as part of createBlock. A block usually consists of a name, attributes and HTML, so it makes sense to be able to create a block from all that information?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could simplify things internally as well. In parser.js we do:
const block = createBlock(
name,
getBlockAttributes( blockType, innerHTML, attributes )
);
So why not:
const block = createBlock( name, attributes, innerHTML );
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can understand where this idea comes from. We never used getBlockAttributes
outside the api
yet I think.
But I think I'll be in favor of keeping the createBlock
simple. And compose the two functions when needed because there's a major difference in the expected "attributes" argument here.
the attributes parameter of createBlock
can be any attribute allowed by the block, it behaves like "defaultAttributes" somehow. While the "attributes" parameter of getBlockAttributes
represent only the "comment" attributes (the parsed JSON).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See also #3745, conflicting changes with API and intending to pass inner children nodes.
5d4f9a2
to
ec6e5e7
Compare
ec6e5e7
to
a22c959
Compare
@mcsf Does this look better? I'm not quite liking how |
I was quite torn, because I agree that it doesn't look great. Ultimately, I'd say it may be best to err on the conservative side and not touch the |
Description
This PR updates raw handling to preserve WordPress alignment classes and updates the image block transformation to detect the classes and set the align attribute.
How Has This Been Tested?
Paste the following structure:
This would previously not preserve alignment.
Checklist: