Skip to content
This repository has been archived by the owner on Jun 26, 2020. It is now read-only.

ImageStyle #23

Merged
merged 35 commits into from
Jan 10, 2017
Merged

ImageStyle #23

merged 35 commits into from
Jan 10, 2017

Conversation

szymonkups
Copy link
Contributor

@szymonkups szymonkups commented Dec 29, 2016

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 icons align-center.svg and align-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.

@szymonkups szymonkups requested a review from Reinmar December 29, 2016 09:12
}

// If there is no default image toolbar configuration, add all image styles buttons.
const imageToolbarConfig = this.editor.config.get( 'image.toolbar' );
Copy link
Member

@Reinmar Reinmar Jan 4, 2017

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.

  1. The assumption is that ImageToolbar is loaded and sets image.defaultToolbar to an empty array in its constructor (which is "before init"). If it's not loaded, the property doesn't exist.
  2. If the property exists, the other plugins should then push their default buttons to this array in their init() callbacks.
  3. The ImageToolbar should then use image.toolbar or image.defaultToolbar.

Sounds reasonable?

Copy link
Contributor Author

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?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes.

Copy link
Member

@Reinmar Reinmar left a 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 );
Copy link
Member

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 ),
Copy link
Member

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
Copy link
Member

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 ) );
Copy link
Member

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.
Copy link
Member

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 ) {
Copy link
Member

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 ) {
Copy link
Member

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.

Copy link
Contributor Author

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.

Copy link
Contributor Author

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',
Copy link
Member

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 );
Copy link
Member

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?

Copy link
Contributor Author

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 ) {
Copy link
Member

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?

Copy link
Member

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.

Copy link
Contributor Author

@szymonkups szymonkups Jan 9, 2017

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.

Copy link
Member

@Reinmar Reinmar Jan 9, 2017

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' } );
Copy link
Member

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?

Copy link
Contributor Author

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 );
Copy link
Member

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.

Copy link
Contributor Author

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.

Copy link
Member

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.

Copy link
Member

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.

Copy link
Contributor Author

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.

Copy link
Contributor Author

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.

Copy link
Member

@Reinmar Reinmar left a 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).

@Reinmar Reinmar merged commit 4b8e71b into master Jan 10, 2017
@Reinmar Reinmar deleted the t/18 branch January 10, 2017 15:43
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Image styles
2 participants