-
-
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
Add more conversion helpers #3921
Comments
Actually, ckeditor/ckeditor5-paragraph#12 is a very good test, because it's the 1st or 2nd time when we're implementing non-standard converters. Let's work on refactoring this code once it lands. |
Also, perhaps this is a good question whether we shouldn't always clone the conversion data object before modifying it. Making it immutable would smell much better. |
There's another case here: https://github.com/ckeditor/ckeditor5-image/pull/23/files. There's also a case for model-to-view converters. Either the existing ones aren't very useful or @szymonkups didn't know how to use the in a nice way. I don't know too, so it means that something's missing here. In other words – the image style feature should be couple of lines long. |
Cases from ImageStyle plugin: View to model helpersWe can pass a const viewMatcher = new ViewMatcher( [
{ name: 'figure', class: [ 'image', 'image-align-left' ] },
{ name: 'figure', class: [ 'image', 'image-align-right' ] }
] );
buildViewConverter()
.for( data.viewToMode )
.from( viewMatcher )
.consuming( match => /*create object with values to consume based on the match*/ );
.toAttribute( viewElement => /*create key-value pair*/ ); Model to view helpers
|
Yea, when I was reading this code I understood why it needs to be improved. In fact, we could try to get rid off |
Also, I don't like the |
Woah... This escalated quickly... You realize that what you complain about is a product of the big refactoring that took place in engine some time ago? There was a time when This led to:
Then we introduced
I understand that this was some time ago and sometimes you have to review ideas from pasts, but that was a big and long refactoring and we wouldn't make that decision "because so". Of course the main goal of refactoring was removing BTW. AFAIR you proposed |
When working on the message quote feature I had to convert: <messageQuote>
<paragraph>x</paragraph>
<paragraph>y</paragraph>
</messageQuote> to: <figure class="quote">
<blockquote>
<p>x</p>
<p>y</p>
</blockquote>
</figure> And it turned out that I can't do this using the converter builder. I think that this may be a quite popular conversion pattern (e.g. the image feature does it similarly), so either we should add support for creating bigger structures to the converter builder or consider this case for the conversion utils. |
I was working on this for couple of days, trying to find a solution for convenient conversion helpers. I really like conversion builder approach - it's easy to understand and "hides" the fact that when converting from model to view we convert changes: buildModelConverter()
.for( dispatcher )
.fromElement( 'paragraph' )
.toElement( 'p' ); At the time when builder was created it was impossible to predict what kind of utilities will be needed, and implement them inside the builder from the start. This way, some features implement own converters with tweaks matching their needs. It's not that bad, but many times it took some time to create and test them and it would be great if other features could easily re-use them. For example: image feature has caption converter, it would be great if for example table feature could use it. Why didn't we extend the builder in the first place? I think because current builder approach with I would like to propose a change to a way how conversion builder is used. It should contain only the logic to apply "conversion utilities" to given dispatchers. All the conversion logic should be moved to those utilities. This way each utility will be separated from others, it could have it's own configuration and adding new utilities would be much easier. Consider this example: buildModelConverter()
.for( dispatcher )
.use( elementToElement( 'paragraph', 'p' ) )
.use( attributeToElement( 'bold', 'strong' ) ); We keep buildModelConverter()
.for( dispatcher )
.use( elementToElement( 'caption', 'figcaption', {
// Convert only captions of images.
filter: element => isImage( element.parent )
} ) ); It would be still hard to predict all use cases, but I think this approach will encourage us to look for more general approach to conversion problems and improve our utilities instead of directly writing converters that solves only per-feature problems. I've created POC for image feature: https://github.com/ckeditor/ckeditor5-image/compare/t/ckeditor5-engine/736. It introduces the new approach and couple of utilities:
It allowed to replace almost all model to view custom converters (excluding some fixers) without tests changes. WDYT? |
If we go with such sophisticated helper functions, I don't know there's much reason in keeping |
Yeah, it looks like in this approach builder is just a little helper to passing dispatchers to utils functions. It can be easily skipped. |
I can see that we all, independently come to the same conclusions that we need helpers instead of one converter builder. That's good :) |
It wasn't really independent :P. |
I think that the mistake we (I) did, was that we focused so much on making the conversion with builder simple that we forget that conversion without the builder, for more tricky cases, need to be rather simple too. The builder is very nice, recently, @jodator notice that he really like using it because he doesn't need to get deeper and learn what does it do. It just works. Now, focusing on advance converters, we should keep in mind that is should be still very simple and intuitive to create a simple converter. Ok, enough introduction. ;) We should improve const converter = () => { /*...*/ };
this.listenTo( data.modelToView, 'addAttribute', converter );
this.listenTo( data.modelToView, 'removeAttribute', converter ); Now it should be possible to do: this.listenTo( data.modelToView, [ 'addAttribute', 'removeAttribute' ], () => { /*...*/ } ); However, converter added to multiple objects and events, even if short, is still not readable: this.listenTo( [ data.modelToView, editing.modelToView ], [ 'addAttribute', 'removeAttribute' ], () => { /*...*/ } ); At this point, I like what @szymonkups proposed very much. I think it's how the API could look, on the top of improved event listeners. Good job. In fact, we could go even further, to have just utils: convertElementToElement( {
for: [ data.modelToView, editing.modelToView ],
from: 'paragraph',
to: 'p'
} ); Or even, assuming that usually, one wants to have converters to both pipelines, both ways: convertElementToElement( editor, { viewElement: 'paragraph', modelElement: 'p' } ); But it might be too far, too magic. At the same time notice that there is still a big room for improvements in how to write such conversion utils. One thing we should improve is the fact that events names and consumables are not compatible. This is why we need code like this: https://github.com/ckeditor/ckeditor5-image/compare/t/ckeditor5-engine/736#diff-d90b5bb92fa682c8d8e05fc292e94643R19 or use helper no one remembers about: https://github.com/ckeditor/ckeditor5-engine/blob/369d636488bc75d9832c27ff28b9eaf38d8a5735/src/conversion/model-to-view-converters.js#L564-L568 It should be possible to pass event name to the I think that we could also change attribute events names: Also, note that we already think about the view to model conversion simplification together with "one API" change (https://github.com/ckeditor/ckeditor5-engine/issues/858). This topic is very related because it's view to model conversion where, at this point, we use API very different from the regular model API, so we need to change view converters together with this unification. I will create a separate ticket for this change soon. |
A bit too magical for me. Also with
Current fluent API for converters reads nice and is very intuitive also with helpers like |
Fixed by ckeditor/ckeditor5-engine#1274. |
This piece is tricky to remember:
https://github.com/ckeditor/ckeditor5-engine/blob/85dce7e914a16f065b1ac153821afc8205e4333d/src/conversion/buildviewconverter.js#L287-L298
The context on the fly modification was a total surprise, so let's create a helper.
The other thing which I noticed too late when working on ckeditor/ckeditor5-paragraph#12 is that I have to use the writer when merging paragraphs. And perhaps more.
The text was updated successfully, but these errors were encountered: