-
-
Notifications
You must be signed in to change notification settings - Fork 3.7k
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
Better BR elements handling #12033
Better BR elements handling #12033
Conversation
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 just checked how it works while BR is wrapped with some inline element and it differs from the browser rendering. Checking it. |
I don't know whether we can call this an internal change. The feature was moved from the engine to a plugin. Did you think on how the behavior of the editor without SoftBreak changed? A thing to consider is that it also touches pasting. Editors without this plugin will be quite rare so we can be rather liberal here, but let's at least have this thought through. |
Thanks for writing down these thoughts. It's an interesting idea to move the code to the plugin. It's definitely more elegant if OTOH, we're now moving logic that was resolving issues related to how semantic data has to be enhanced to show well in a browser (or strip from these enhancements) to the conversion layer. But on the third hand, that's where we clean up the content and fix where it was misformatted (e.g. autoparagraphs, wrong nesting, disallowed children, etc.). So, an important thing to consider here is that those BRs are not part of the enhancement that we did. We use So after giving it a deeper thought, I think the change makes sense. |
One more thing to consider: Performance. We had poor implementation, but probably negligible from the performance pov. Now, it's more complete, but at what cost? |
@@ -514,6 +514,43 @@ describe( 'Input feature', () => { | |||
expect( getViewData( view ) ).to.equal( '<p><strong>Foo</strong> {}</p>' ); | |||
} ); | |||
|
|||
it( 'should handle bogus br correctly (with custom br to softBreak converter)', () => { |
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.
How did you come up with these tests? Did you encounter some regressions after making this change? Does it anyhow affect beforeinput-related work?
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.
The case is that those bogus BRs are stripped while converting to the model (input compares the current model and the model generated from the modified DOM). This case won't affect the beforeinput because it's not used there anymore.
The first test I done was ctrl+a, ctrl+c in this page (this PR) and paste it to http://localhost:8125/ckeditor5/tests/manual/all-features.html Unfortunately, on this branch crashes with:
The best way to test conversion and anything related to that is to take random pieces of HTML from various websites and just paste :D |
Scenarios to check:
|
I was curious whether the PR indeed fixes the original issue. So, how paste from this document works: https://docs.google.com/document/d/1abo1Ca_RHEmuXnAX6k_z0itHihQb3g9rJRM3x4vQ25w/edit NOTE: This document is really oddly formatted. When you test a normal document, created with normal paragraphs in Google Docs (I tested some other docs I had), the result is better. So, this entire PR is about fixing a rather specific case, although, apparently, relatively frequent as well. Before<p>
<span style="background-color:transparent;color:#000000;">Sometimes, there’s nothing scarier than a blank page waiting to be filled - especially when it comes to figuring out how to start a resume. </span>
</p>
<p>
<br>
</p>
<p>
<span style="background-color:transparent;color:#000000;">For every position that you apply for, you will need to stand out in a pile of applications through your professional experience, achievements, and education, to impress recruiters. </span>
</p>
<p>
<br>
</p>
<p>
<span style="background-color:transparent;color:#000000;">Just thinking about all this may make starting your resume seem like a Herculean task. </span>
</p>
<p>
<br>
</p> On this PR<p>
<span style="background-color:transparent;color:#000000;">Sometimes, there’s nothing scarier than a blank page waiting to be filled - especially when it comes to figuring out how to start a resume. </span>
</p>
<p>
</p>
<p>
<span style="background-color:transparent;color:#000000;">For every position that you apply for, you will need to stand out in a pile of applications through your professional experience, achievements, and education, to impress recruiters. </span>
</p>
<p>
</p>
<p>
<span style="background-color:transparent;color:#000000;">Just thinking about all this may make starting your resume seem like a Herculean task. </span>
</p>
<p>
</p> Hmm... there are still empty paragraphs that aren't visible in the original document. If paragraphs are styled to have margins (as in our docs) it looks like this: So, differently than in Google Docs. However, as I mentioned, the problem is with the styling, not data. I decided to check CKE4 and TinyMCE's powerpaste out of curiosity too as they worked on their filtering systems for a couple more years. Yet, the results are identical. CKEditor 4TinyMCETo sum upThe PR resolves the reported issue but it's probably even impossible to ensure that the content look very much alike between Google Docs and other systems. |
I did some quick performance tests and for a 12kb of content that's relatively heavy with |
Co-authored-by: Piotrek Koszuliński <[email protected]>
I narrowed the crashing content to: <ul>
<li>foo<br><custom-element></custom-element></li>
</ul> |
So the problem is that
because there is no The case of known inline object elements (like foo<br><img/>
foo<br><custom-element><img/></custom-element>
<p>foo<br><img/></p>
<p>foo<br><custom-element><img/></custom-element></p> But if the custom element does not contain any content then it crashes: foo<br><custom-element></custom-element> But there might be more cases where this would fail because of the line mentioned above. |
I'm worried that in ab3e3ad you added just a single test. I'd generate a couple more for weird variations: elements before, multiple elements one by one, other inline elements, etc. I found that the tree-walking logic is often incomplete. |
I found another case that I missed before: <p><br><br><br></p> should remove only the last BR element, others should be converted as |
More details on the crashing case (fixed in one of the previous commits): The input data: <ul>
<li>foo<br></li>
</ul> The crashing line was:
because of the assumption that ckeditor5/packages/ckeditor5-engine/src/conversion/upcasthelpers.js Lines 440 to 445 in 685dfdb
there is one exception, the fallback converter expects that the element was not consumed and So if any feature is using |
In other words, the frequency will be really low. There has to be a combination of a custom converter, using |
Yes. |
At this moment after some first testing and going through those points mainly:
I was not able to crash the editor or see other issues. I can see improvement regarding the original ticket and only the styling issue (line spacing) remained, but it was discussed above. So to sum up, I haven't spotted new issues, but I think we should test this heavily during the Testing Phase. |
CI was clean apart from a usual 404 in manual tests. |
This change will be reverted in #12183. |
Suggested merge commit message (convention)
Fix (enter): A
<br>
element between blocks should be converted to an empty paragraph. Closes #10217.Test (clipboard): Added test for pasting content with
<br>
element between blocks. See #10217.Internal (engine): Handling of
<br>
elements in the data pipeline moved fromDomConverter
to thesoftBreak
conversion.Additional information
The original issue is only about pasting such content (trimmed for readability):
This content expects 3 paragraphs and the middle one is empty but got converted (because of auto-paragraphing, softBreak is not allowed in root context) as:
But since this is very generic HTML and the behavior of
<br>
elements is very specific in web browsers I did some research to find out how different<br>
scenarios are handled by a web browser and CKE5.Here is a result (from a manual test: http://fake.ckeditor.com:8125/ckeditor5-enter/tests/manual/softbreak-paragraphing.html):
The broken cases
Above cases were failing also while
<br>
was wrapped with some inline elements (like a link or strong).The only case that was explicitly handled by the editor was
<p><br></p>
and it was fragile to any whitespace around BR element.First solution attempt
I was trying to solve the issue by extending the
<p><br></p>
case that was handled in DomConverter:ckeditor5/packages/ckeditor5-engine/src/view/domconverter.js
Lines 1080 to 1083 in 2a22cd9
But it had problems:
DomConverter
but it would require triggering it multiple times to handle look-ahead checks (for checking block fillers and to trim text itself)<br/>
by a<p></p>
in some cases, it generated paragraphs nested in other paragraphs or other block elements that could contain text so the generated view structure would be messed up (but upcast conversion to the model would handle it properly)Final solution
I decided to move the main solution to
softBreak
upcast converter because:You could check how browsers and the editor are handling
<br>
s in some cases in the new manual test.