Skip to content
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

I/9213 enabling caption toolbar #9459

Merged
merged 12 commits into from
Apr 20, 2021

Conversation

magda-chrzescian
Copy link
Contributor

@magda-chrzescian magda-chrzescian commented Apr 13, 2021

Suggested merge commit message (convention)

Fix (image): The buttons in the image toolbar should be enabled when the selection is in a caption. Closes #9213.
Fix (image): Dropdowns in the image toolbar should be disabled when all of the nested buttons are disabled. See #9213.


We actually don't need the getSelectedImageWidget function anymore. Whenever we are looking for an image on which to execute a command, we are also looking for the image ancestor of the selected caption. So I replaced the getSelectedImageWidget with getSelectedOrAncestorImageWidget.

It was a public function, so I'm not sure if it's ok to change its name and behavior. But because of the changes in managing the toolbar state, our integrator probably also should start using the getSelectedOrAncestorImageWidget function.

BTW, should such renaming be considered a breaking change?

@magda-chrzescian magda-chrzescian linked an issue Apr 13, 2021 that may be closed by this pull request
@magda-chrzescian magda-chrzescian requested a review from oleq April 13, 2021 10:17
Copy link
Member

@oleq oleq left a comment

Choose a reason for hiding this comment

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

Looks good 👍

My biggest concern, though, is why was the text alternative button left disabled when the selection is the caption? Is there any reason for that?

export function getImageModelElementAncestor( selection ) {
const selectedElement = selection.getSelectedElement();

return isImage( selectedElement ) ? selectedElement : selection.getFirstPosition().findAncestor( 'image' );
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
return isImage( selectedElement ) ? selectedElement : selection.getFirstPosition().findAncestor( 'image' );
return isImage( selectedElement ) ? selectedElement : selection.getFirstPosition().findAncestor( isBlockImage );

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 seems to me that the model element findAncestor method accepts the element name only: https://ckeditor.com/docs/ckeditor5/latest/api/module_engine_model_element-Element.html#function-findAncestor. Unless I'm missing something.

Copy link
Member

Choose a reason for hiding this comment

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

You're right. I must've mistaken it with some other helper. Sorry for the confusion.

it( 'should be false when the selection is on other object', () => {
model.schema.register( 'object', { isObject: true, allowIn: '$root' } );
editor.conversion.for( 'downcast' ).elementToElement( { model: 'object', view: 'object' } );
setModelData( model, '[<object></object>]' );

expect( inlineCommand.isEnabled ).to.be.false;
} );

it( 'should be true when the selection is in a caption', () => {
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
it( 'should be true when the selection is in a caption', () => {
it( 'should be true when the selection is in a block image caption', () => {

@@ -271,6 +266,18 @@ describe( 'ImageTypeCommand', () => {
'</paragraph>'
);
} );

it( 'should convert and set selection on the new image if the selection is in a caption', () => {
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
it( 'should convert and set selection on the new image if the selection is in a caption', () => {
it( 'should convert and set selection on the new image if the selection is in a block image caption', () => {

Comment on lines 931 to 932
expect( image ).to.be.instanceOf( ModelElement );
expect( image.name ).to.equal( 'imageInline' );
Copy link
Member

Choose a reason for hiding this comment

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

expect( image.is( 'element', 'imageInline' ) ).to.be.true is enough to check this. The same applies to all tests that follow 👇

@@ -150,6 +150,9 @@ export default class ImageStyleUI extends Plugin {
}
} );

dropdownView.bind( 'isEnabled' )
.toMany( buttonViews, 'isEnabled', ( ...areEnabled ) => !!areEnabled.find( isEnabled => isEnabled ) );
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
.toMany( buttonViews, 'isEnabled', ( ...areEnabled ) => !!areEnabled.find( isEnabled => isEnabled ) );
.toMany( buttonViews, 'isEnabled', ( ...areEnabled ) => areEnabled.some( isEnabled => isEnabled ) );

Comment on lines 445 to 463
groups = groups.map( group => {
const items = group.view.toolbarView.items;

items.map( item => {
item.isEnabled = false;

return item;
} );

const activeButton = items.first;

activeButton.isEnabled = true;

return { ...group, activeButton };
} );

for ( const { buttonView } of groups ) {
expect( buttonView.isEnabled ).to.be.true;
}
Copy link
Member

Choose a reason for hiding this comment

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

This could be way simpler (why map() and return activeButton?):

Suggested change
groups = groups.map( group => {
const items = group.view.toolbarView.items;
items.map( item => {
item.isEnabled = false;
return item;
} );
const activeButton = items.first;
activeButton.isEnabled = true;
return { ...group, activeButton };
} );
for ( const { buttonView } of groups ) {
expect( buttonView.isEnabled ).to.be.true;
}
for ( const group of groups ) {
const groupItems = group.view.toolbarView.items;
for ( const item of groupItems ) {
item.isEnabled = false;
}
groupItems.first.isEnabled = true;
}
for ( const { buttonView, config } of groups ) {
expect( buttonView.isEnabled, `Failing group name: "${ config.name }"` ).to.be.true;
}

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 didn't want to mutate the groups and mess up the following tests. I missed the fact that each of these tests has its own beforeEach and thus separate groups array. Thanks for the catch :)

Comment on lines 467 to 481
groups = groups.map( group => {
const items = group.view.toolbarView.items;

items.map( item => {
item.isEnabled = false;

return item;
} );

return group;
} );

for ( const { buttonView } of groups ) {
expect( buttonView.isEnabled ).to.be.false;
}
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
groups = groups.map( group => {
const items = group.view.toolbarView.items;
items.map( item => {
item.isEnabled = false;
return item;
} );
return group;
} );
for ( const { buttonView } of groups ) {
expect( buttonView.isEnabled ).to.be.false;
}
for ( const group of groups ) {
const groupItems = group.view.toolbarView.items;
for ( const item of groupItems ) {
item.isEnabled = false;
}
}
for ( const { buttonView, config } of groups ) {
expect( buttonView.isEnabled, `Failing group name: "${ config.name }"` ).to.be.false;
}

@magda-chrzescian
Copy link
Contributor Author

magda-chrzescian commented Apr 16, 2021

My biggest concern, though, is why was the text alternative button left disabled when the selection is the caption? Is there any reason for that?

Yes, my scatterbraining. I fixed it for the text alternative and image resize buttons.
I kept the imageUpload button the way it was (disabled). Theoretically, it can be placed in the image toolbar, but having it enabled with the caret inside the caption would suggest that it is possible to insert the image in there.

@magda-chrzescian magda-chrzescian requested a review from oleq April 18, 2021 10:01
@@ -65,7 +65,7 @@ export function getSelectedImageWidgetOrAncestor( selection ) {
* @param {module:engine/view/selection~Selection|module:engine/view/documentselection~DocumentSelection} selection
* @returns {module:engine/view/element~Element|null}
*/
export function getSelectedImageWidgetAncestor( selection ) {
export function getSelectionAncestorImageWidget( selection ) {
Copy link
Member

Choose a reason for hiding this comment

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

Looks like this helper is only used internally by getSelectedOrAncestorImageWidget(). I think we should merge them.

@@ -86,7 +86,7 @@ export function getSelectedImageWidgetAncestor( selection ) {
* @returns {module:engine/model/element~Element|null}
*/

export function getSelectedImageElementOrAncestor( selection ) {
export function getSelectedOrAncestorImageElement( selection ) {
Copy link
Member

Choose a reason for hiding this comment

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

What about getClosestSelectedImageElement()?

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'm not sure, the image element returned by this function doesn't have to be formally selected (<image><caption>[Foo]</caption></image>), so wouldn't this name be misleading?
However, I don't like the name above either. I was thinking about something like getCorrelatedImageElement - a bit enigmatic, but still understandable IMO.

Copy link
Member

Choose a reason for hiding this comment

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

Maybe then simply getClosestImageElement() (getClosestImageWidget())?

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 liked the previous version better :) Changed to getClosestSelectedImageElement.

@@ -49,14 +49,14 @@ export function isImageWidget( viewElement ) {
* @param {module:engine/view/selection~Selection|module:engine/view/documentselection~DocumentSelection} selection
* @returns {module:engine/view/element~Element|null}
*/
export function getSelectedImageWidgetOrAncestor( selection ) {
export function getSelectedOrAncestorImageWidget( selection ) {
Copy link
Member

Choose a reason for hiding this comment

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

What about getClosestSelectedImageWidget()?

@magda-chrzescian
Copy link
Contributor Author

@oleq could you also refer to the following?

We actually don't need the getSelectedImageWidget function anymore. Whenever we are looking for an image on which to execute a command, we are also looking for the image ancestor of the selected caption. So I replaced the getSelectedImageWidget with getSelectedOrAncestorImageWidget.

It was a public function, so I'm not sure if it's ok to change its name and behavior. But because of the changes in managing the toolbar state, our integrator probably also should start using the getSelectedOrAncestorImageWidget function.

BTW, should such renaming be considered a breaking change?

@oleq
Copy link
Member

oleq commented Apr 19, 2021

We actually don't need the getSelectedImageWidget function anymore. Whenever we are looking for an image on which to execute a command, we are also looking for the image ancestor of the selected caption. So I replaced the getSelectedImageWidget with getSelectedOrAncestorImageWidget.

It was a public function, so I'm not sure if it's ok to change its name and behavior. But because of the changes in managing the toolbar state, our integrator probably also should start using the getSelectedOrAncestorImageWidget function.

BTW, should such renaming be considered a breaking change?

Since we're doing tons of breaking changes in this feature branch, I see nothing wrong with removing unused helpers and simplifying the names of the confusing ones.

@oleq oleq merged commit b6bb0c8 into i/2052-inline-images Apr 20, 2021
@oleq oleq deleted the i/9213-enabling-caption-toolbar branch April 20, 2021 07:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Disabled buttons in the image toolbar.
2 participants