-
Notifications
You must be signed in to change notification settings - Fork 37
ImageStyle #23
ImageStyle #23
Conversation
…uration is provided.
} | ||
|
||
// If there is no default image toolbar configuration, add all image styles buttons. | ||
const imageToolbarConfig = this.editor.config.get( 'image.toolbar' ); |
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 not going to work this way... Because, if there's any other plugin which would like to extend this toolbar, it won't do that, because the toolbar is already set by this plugin.
So, unfortunately, we must make this a bit more complex.
- The assumption is that
ImageToolbar
is loaded and setsimage.defaultToolbar
to an empty array in its constructor (which is "before init"). If it's not loaded, the property doesn't exist. - If the property exists, the other plugins should then push their default buttons to this array in their
init()
callbacks. - The ImageToolbar should then use
image.toolbar
orimage.defaultToolbar
.
Sounds reasonable?
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.
You're right. I didn't take other plugins into consideration. So we will use image.defaultToolbar
configuration only if image.toolbar
is not specified. Is that correct?
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.
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 feature works great and there are just 2 rather simple code refactorings to do – the command split and how the default config is created.
* @param {Array.<module:image/imagestyle/imagestyleengine~ImageStyleFormat>} styles Allowed styles. | ||
*/ | ||
constructor( editor, styles ) { | ||
super( editor ); |
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.
Missing new line.
const view = new ButtonView( locale ); | ||
|
||
view.set( { | ||
label: t( style.title ), |
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.
It can't be used like that. t()
must be always used with a string. So the t()
function should be used here: https://github.com/ckeditor/ckeditor5-image/pull/23/files#diff-00366adf927974c568c9ea53d58ede26R44
|
||
view.set( { | ||
label: t( style.title ), | ||
icon: style.icon |
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.
You can now also add tooltip: true
} | ||
|
||
// Register image style command. | ||
editor.commands.set( 'imagestyle', new ImageStyleCommand( editor, styles ) ); |
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.
We're rather going to split the heading command into multiple heading commands, so the same should happen here. See https://github.com/ckeditor/ckeditor5-heading/issues/53. There should be a separate command per each style.
} | ||
|
||
/** | ||
* Image style format descriptor. |
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.
Some example would do nicely :P
* @param {module:engine/model/element~Element} modelElement | ||
* @returns {Boolean} | ||
*/ | ||
export function isImage( modelElement ) { |
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.
Would rather make for some base image utils. I can see there src/utils.js
.
* @param {Array.<module:image/imagestyle/imagestyleengine~ImageStyleFormat> } styles | ||
* @return {module:image/imagestyle/imagestyleengine~ImageStyleFormat|undefined} | ||
*/ | ||
export function getStyleByValue( value, styles ) { |
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 guess this won't be necessary after the proposed change to split the command.
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.
It is also used by converters to be sure if applied value is correct with provided configuration.
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.
But now it is used only there and looks like it can be just a private to that module. This way we can get rid of utils file.
Template.extend( panel.template, { | ||
attributes: { | ||
class: [ | ||
'ck-toolbar__container', |
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.
Trailing comma.
viewElement.addClass( newStyle.className ); | ||
} | ||
|
||
consumable.consume( data.item, consumableType ); |
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.
Why is it kept here? Can't it replace the consumable.test()
call?
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 did some other checks and return points in this function so I wanted to test first and then consume when everything is validated.
const viewElement = conversionApi.mapper.toViewElement( data.item ); | ||
|
||
if ( eventType == 'changeAttribute' || eventType == 'removeAttribute' ) { | ||
if ( !oldStyle ) { |
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 get it... why do you check it here?
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 style attribute is used by this feature. If the getStyleByValue
method can't find it, then something's really broken and we're just hiding the bug this way.
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 wasn't sure how to handle it to be honest. On the one hand we have ImageStyle
plugin that have its configuration and I wanted to build a converter that will only handle values from that configuration. On the other hand - there won't be probably any other plugin that will write something to imageStyle
attribute.
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.
Actually, that condition could even be there, but if it wasn't so... distinguished :D. The code needs to be intuitive. Now, you read "if something, then ... if not something ABORT... do something". This isn't very natural of expressing this logic.
This would be better:
if ( oldStyle && needToRemove( eventName ) ) {
remove();
}
(See how you don't have to parse eventName
in this callback and how well the code reads?)
And I agree – it's more error safe to check if oldStyle
was found. But how was the value of the model element attribute set in the first place? There would need to be an additional feature which uses the same attribute – I don't think this should happen. But I may be wrong :P.
Anyway, since you have tests for this already, then we can keep it. Just make the code more intuitive. Also, you could consider splitting the function to two – one to handle change and remove attribute and other for add and change.
I also wrote a comment in https://github.com/ckeditor/ckeditor5-engine/issues/736 that we need better tools to write converters, because, e.g. in this case, there are too many listeners needed. Let's keep collecting use case to simplify.
// Converter for figure element from view to model. | ||
// Create converter only for non-null values. | ||
if ( style.value !== null ) { | ||
data.viewToModel.on( 'element:figure', viewToModelImageStyle( style ), { priority: 'low' } ); |
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't we have a single listener for all styles? Like for the opposite conversion?
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.
That's a good point, I'll try to do this with one listener.
doc.enqueueChanges( () => { | ||
const batch = options.batch || doc.batch(); | ||
|
||
batch.setAttribute( imageElement, 'imageStyle', this.style.value ); |
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 attribute should be called 'style'
. It's image element's attribute after all.
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 wanted to call it 'style'
but we have this: https://github.com/ckeditor/ckeditor5-engine/issues/559 that prevents us from using test utils.
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.
That's a very bad reason for choosing this name :P. Let's see if we can do something to fix that bug. It's a very serious problem.
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.
Note: This is quite important what attribute name we use because this is kind of a public API of this feature.
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.
That's a very bad reason for choosing this name :P. Let's see if we can do something to fix that bug. It's a very serious problem.
I will fix other issues with this PR and then look into that issue.
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've created separate issue for that: https://github.com/ckeditor/ckeditor5-image/issues/25.
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.
Some questions regarding conversion and one issue (name of the attribute).
This reverts commit 9ba4a3d.
Fixes ckeditor/ckeditor5#5040.
For now icons are added inside this PR, this will change when common icons will land in core: https://github.com/ckeditor/ckeditor5-theme-lark/issues/59.EDIT:
For now core iconsalign-center.svg
andalign-right.svg
are used. This will be changed to when proper icons land in core: https://github.com/ckeditor/ckeditor5-theme-lark/issues/59.EDIT v2: Proper icons are used.