-
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
Use nested blocks for quotes #6054
Conversation
blocks/api/parser.js
Outdated
@@ -281,7 +281,8 @@ export function createBlockWithFallback( blockNode ) { | |||
|
|||
if ( attributesParsedWithDeprecatedVersion ) { | |||
block.isValid = true; | |||
block.attributes = attributesParsedWithDeprecatedVersion; | |||
block.attributes = omit( attributesParsedWithDeprecatedVersion, '_innerBlocks' ); | |||
block.innerBlocks = attributesParsedWithDeprecatedVersion._innerBlocks || block.innerBlocks; |
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 is ugly, but I didn't want to change the deprecation API for this, and I suspect this will be a very rare thing to do. Might still want to change it though.
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.
A similar issue is being resolved in #5932 Let's try to find the best approach there.
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.
Rebased.
f967804
to
de6c04b
Compare
blocks/rich-text/README.md
Outdated
@@ -31,9 +31,9 @@ a traditional `input` field, usually when the user exits the field. | |||
|
|||
*Optional.* By default, a line break will be inserted on <kbd>Enter</kbd>. If the editable field can contain multiple paragraphs, this property can be set to `p` to create new paragraphs on <kbd>Enter</kbd>. | |||
|
|||
### `onSplit( before: Array, after: Array, ...blocks: Object ): Function` | |||
### `onSplit( after: Array, ...blocks: Object ): Function` |
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.
Can you elaborate on how this works, it's a bit unclear?
Before, the HTML was splitted between two similar formats (after, and before) but right now it seems that the HTML before the split position is transformed to a block before calling the function (If I understand properly)? How do you decide which block to use since in the RichText component we don't really know the parent block?
Alson If this is the case, why can't we just use onReplace
and replace the after
with a block as well.
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.
Also, it seems that we need to provide a deprecation message in any case.
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, the HTML was splitted between two similar formats (after, and before) but right now it seems that the HTML before the split position is transformed to a block before calling the function (If I understand properly)?
No, since the "before" content always lands in the some RichText area, we can do this as part of RichText. I don't thing there's a need to pass it to the block registration, which would only set attributes on the same block affecting the same RichText instance, which already has the correct content. So there's no need to pass as RichText is already setting it, currently the content is being set twice.
Good point about the deprecation message. Me might actually want to improve the shape of the arguments here as it's a bit of a mess. Maybe { blocks, afterValue }
or something similar.
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.
Alson If this is the case, why can't we just use onReplace and replace the after with a block as well.
Not sure I'm following here. The block needs to determine what to do with the split off value, which is arguably always a new block with the content set at the same attribute as the "before" value (the value that stays). The problem is that RichText should not be aware of the shape of the block's 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.
Don't worry about this comment ;) I thought initially you were doing some magic (transforming to blocks) but it's not the case. So my issue right now is more #6054 (comment)
blocks/rich-text/index.js
Outdated
* | ||
* @param {Array} before content before the split position | ||
* @param {Array} after content after the split position | ||
* @param {?Array} blocks blocks to insert at the split position | ||
*/ | ||
restoreContentAndSplit( before, after, blocks = [] ) { | ||
this.updateContent(); | ||
this.props.onSplit( before, after, ...blocks ); | ||
this.setContent( before ); |
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 see, so you apply the content directly beforing calling the onSplit
. I believe we avoided this until now because the block can decide to not split and don't support the Enter
behavior. If the block don't provide the onSplit
it's better to keep content as is instead of removing the part that's after the split point. How do you handle this?
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 there's no onSplit
prop, restoreContentAndSplit
will never be called, just like before? updateContent
is being replaced by setContent
here, because the only thing we want to do is set the content.
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.
There was actually an inconsistency where some use called setContent
before restoreContentAndSplit
.
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.
👍 Sounds good to me. Let's try to build a good deprecation strategy though
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.
Will do :) I'll ponder a bit over maybe using onReplace
... would be much simpler, but right now onSplit
is also used as an indicator whether splitting is possible as you mentioned, whereas onReplace is used for other things too. One solution to both problems might be to have something like this:
onSplit: ( value ) => createBlock ( name, {
content: value,
}
So here the block provided RichText with the info it needs to split the block, and then we can use onReplace
with [ ...blocks, onSplit( value ) ]
.
But one problem with this is that we currently insert an empty paragraph for the list block if blocks
is empty...
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.
Also maybe onSplit
always create a defaultBlock
for the "after" content in which case, we can replace it entirely?
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 need will go away though once we use innerBlocks
for the list block too...
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.
Atm I'm tempted to continue passing the before
value, but remove the setAttributes
, then revise the whole function once we work on lists.
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.
Fine to leave for another refactor though 👍
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.
Cool, let's take care of this when we handle lists.
insertBlocks( blocks, orderOfRoot + 1, rootUIDOfRoot ); | ||
} else { | ||
insertBlocks( blocks, order + 1, rootUID ); | ||
} |
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.
Can you explain the need of this separate handler and its logic, not obvious at first sight :)
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 sure! Forgot to comment. It's so escape the nested block list on double enter.
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.
A small e2e test for the double enter behavior might be good. It's something that can regress easily without noticing.
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.
Done.
@@ -0,0 +1,69 @@ | |||
/** |
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.
Can we leave unwrapping to a separate PR. Not saying we shouldn't do it, but it seems better (at least for me) to discuss separately?
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.
Sure, but how do I take care of the block transforms in this PR? Or should I only add the unwrapping if the block has specified a transform (vs always offering unwrap if the block has innerBlocks)?
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 is a new feature in this PR right? Is it something needed to replace an existing feature? I suspect it's here to replace some transforms that are not possible in the nested approach? Maybe we don't care that much about these transforms at the moment?
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.
Yes, it's to take care of quote => paragraph/heading. See https://github.com/WordPress/gutenberg/pull/6054/files#diff-cda27cec5557c5b032f2b19c44309a1dL106. I added the unwrapping to show it's easier to take care of these kind of transformations. But I agree this should maybe be discussed more. Are you fine with dropping these transformations then at the moment?
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.
Okay I removed this for now.
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.
Nice work on this PR. I left some comments but it's great to see how these blocks become way simpler now.
Sorry I haven't followed so much so maybe I'm missing something, in that case please ignore my question. Could you please specify what you mean by:
Worth noting the |
@youknowriad that was my concern...
That sounds totally weird to me. Quotes are not meant to be used for visual purposes. A In the meantime, I'd suggest to have a look at the specification and all the HTML examples there: https://www.w3.org/TR/html52/grouping-content.html#the-blockquote-element |
@afercia It should be possible to use lists and other blocks in a quote block. I should be able to quote this issue:
This is also possible currently in the classic editor and elsewhere (e.g. Markdown). This PR is also about more than just allowing other blocks in the quote. It's also about simplifying the way the nested paragraphs are implemented. If we end up deciding only paragraphs should be allowed in quotes, we can restrict the blocks that are allowed in a quote. |
@iseulde sorry that's not a quote in a semantic sense as described in the HTML specification :) That's something more similar to a reply with the original message attached and indented as email clients do with
It would be great to have access to this feedback and see what are the real use cases users wish to have. |
Why not? Could you elaborate?
I should be able to quote content form another source, including its semantic structure. |
@iseulde That's not to say a block for your use case can't be done but then it shouldn't use a
I'd point out the part "quoted from another source". See also the NOTE about how to represent a conversation:
Examples here: https://www.w3.org/TR/html52/common-idioms-without-dedicated-elements.html#conversations |
@afercia According to the link you shared. The content of the blockquote allows any "Flow Content" element which means any of these elements: https://www.w3.org/TR/html52/dom.html#flow-content-2 This is also confirmed by other sources like https://developer.mozilla.org/en-US/docs/Web/HTML/Element/blockquote |
According to the specs at MDN, a quote can contain flow content, so headings and list and such are allowed. Looking at the actual meaning and good use of a blockquote, resticting this to only a But for a CMS like WordPress where a blockquote is used already in so many ways, forcing this on content managers, out of pure semantics, seem a bridge too far to me, also for backwards compatibility of text in older posts. |
While the purist in me agrees 100% that quotes are - and should be - quotes and nothing but quotes, in real-life I've seen lots of sites using quotes to make something stand out. I assume the reason for this is because lots of themes just make quotes pretty and visually appealing. Is it wrong? definitely. Do people still use it just to make a visual impression? Unfortunately yes. |
@youknowriad as I've previously commented, yeah it seems to be valid HTML. However, my point is about semantics. See the above comments and the NOTE on the specification. |
That's a perfect use case for another block type that doesn't use the |
I'm not representing conversion. I want to quote a source. E.g.
|
@iseulde yeah, seems a valid edge case. Question: how many users will abuse this block and use it just for visual purposes? |
So help me, I will turn this car around if you kids don't stop arguing. 😉 |
The block clearly says it's a quote, we can even elaborate in the description. You can misuse any block for that. We have to trust the user somewhere. It's more likely they will misuse headings for big text... Not that it is a good argument in every situation, but we also allowed this content in the classic editor, and it's semantic and valid HTML. |
I'm guessing that depends on the theme they use, but I don't think it will be any different than what we have now... Those that abuse it will continue to abuse it, and if we add a description that elaborates a bit more like @iseulde suggested maybe some of them will understand and stop. I don't think there's anything more that can - or should - be done. |
1429a3b
to
6662c36
Compare
ec7f609
to
feb649f
Compare
Rebased (and squashed). |
await button.click( 'button' ); | ||
} | ||
|
||
export async function getHTMLFromCodeEditor() { |
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.
Nice refactoring, we talked about having a special jest asserter, but this is nice as well.
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.
LGTM 👍 Nice job
I was wondering if we should wait for the quote PR to limit the allowed blocks before merging. |
feb649f
to
efcadd4
Compare
81aec55 Don't use rawHandler for migration 188e4a8 Make paste work 86770b7 Adjust e2e, multi selection does not work across nested levels 23027a7 Preserve citation when unwrapping the blocks 188150c Update demo content 2900215 ENTER twice should remove nesting f69f171 Avoid updateContent call on split a54b12d Restore before arg in onSplit, refactor later bf8c171 Handle block (un)wrapping in a separate PR 8929b5f Add e2e test for nested block splitting ef09336 Commits on Apr 12, 2018 Use moveBlockToPosition 6662c36 Fix TinyMCE error on double enter split 6ab8eea Fix split and merge ec7f609
efcadd4
to
1924ae2
Compare
Rebased. I'm going to merge, we can limit the blocks allowed once the other PR is merged. |
Should this be removed from the 2.8 milestone since it got reverted? |
I've instead added both this and its revert to the milestone, so we have history of this work. |
Thanks! :) |
Description
Related: #5265.
This branch changes both quotes block so that they use nested blocks for the content. This enables the user to add content other than paragraphs and simplifies the block registration.
WIP, to do:Preserve citation when unwrapping the blocks.Make paste work.Double enter should exit the quote.Should this be a general nested block behaviour?Update demo content.How Has This Been Tested?
> + SPACE
both with and without existing content.Checklist: