-
Notifications
You must be signed in to change notification settings - Fork 2.5k
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
Ability to configure split button in config.toolbar property #2094
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.
The direction is good, and it works pretty well.
But the biggest concern now is that due to that change, now the API becomes less consistent. I'm talking about default
option here.
I don't like the fact that we have more than one way to set the default action of the Split Button, that is:
- set the default action name directly in Split Button configuration object
- set the default action name Split Button's items, by adding
default: true
It seems to me that the first option (having it directly in splitbutton definition, single prop) is better, and should be the only one to remain.
plugins/toolbar/plugin.js
Outdated
@@ -535,6 +535,12 @@ | |||
|
|||
// Ignore items that are configured to be removed. | |||
if ( !removeButtons || CKEDITOR.tools.indexOf( removeButtons, name ) == -1 ) { | |||
// Option to define Split Button or other UI elements in `config.toolbar` #2091 | |||
if ( item.type ) { |
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.
Please simplify 2 subsequent if
s to just a single if ( cond1 && cond2 ){}
.
plugins/toolbar/plugin.js
Outdated
@@ -535,6 +535,12 @@ | |||
|
|||
// Ignore items that are configured to be removed. | |||
if ( !removeButtons || CKEDITOR.tools.indexOf( removeButtons, name ) == -1 ) { | |||
// Option to define Split Button or other UI elements in `config.toolbar` #2091 |
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 only limited to Split Button UI element alone. Similarly you can now create regular buttons, dropdowns etc. So adjust the docs so that it does refer to known UI types.
Also when doing inline docs follow the regular format, that is:
- place ticket reference in parenthesis,
- end the sentence with a dot.
See the following as an example: https://github.com/ckeditor/ckeditor-dev/blob/ecfbb1e/plugins/stylescombo/plugin.js#L145
@@ -0,0 +1,11 @@ | |||
@bender-ui: collapsed | |||
@bender-tags: feature, 4.10.0, 1679 |
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.
Ticket in tag should refer to this particular feature issue id, rather than the whole Split Button feature.
plugins/splitbutton/plugin.js
Outdated
@@ -34,7 +43,21 @@ | |||
} | |||
|
|||
for ( i in allItems ) { | |||
item = allItems[ i ]; | |||
itemName = item = allItems[ i ]; |
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 using itemName
in just a single place, that is:
https://github.com/ckeditor/ckeditor-dev/blob/ecfbb1e/plugins/splitbutton/plugin.js#L56
You don't have to create a temp variable for the name to access it there, the name is still available at item.name
. Use it, and remove itemName
- this will reduce the complexity.
plugins/splitbutton/plugin.js
Outdated
previousButton, | ||
defaultButton; | ||
|
||
if ( face ) { | ||
// Split Button can be defined with simpler definition via strings, needed by #2091 |
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.
Format should be adjusted same as before. This also occurs later on in this PR, check for other occurrences.
plugins/splitbutton/plugin.js
Outdated
previousButton, | ||
defaultButton; | ||
|
||
if ( face ) { | ||
// Split Button can be defined with simpler definition via strings, needed by #2091 | ||
if ( typeof face === 'string' ) { | ||
face = editor.ui.items[ face ]; |
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 assigning an object that you modify few lines below. That means you're modifying referenced icon.
We can not do that, you should clone it first and work on it clone instead.
items: items | ||
} ); | ||
|
||
editor.ui.add( 'customclick', CKEDITOR.UI_SPLITBUTTON, { |
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.
Code registered as customclick
handler is duplicated, extract it to common parts.
face: { | ||
icon: 'underline', | ||
click: function() { | ||
counter.faceClick++; |
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 whole counter
concept could be simplified by using sinon's stubs. Since you're using them in tests, you could just define stubs in test-scope or in context of tests
object.
Then you'd want to reset it in setup/teardown
function to make sure that test can not be affected by other unit tests.
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.
Refactor of tests/plugins/splitbutton/splitbutton.js
is extracted to #2098
I've pushed to this branch commit form #2098. |
plugins/splitbutton/plugin.js
Outdated
face = CKEDITOR.tools.clone( editor.ui.items[ face ] ); | ||
|
||
if ( !face.icon ) { | ||
face.icon = face.name || face.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.
What is the use case for this? If there is no icon in the original button it's fine to leave it without an 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.
Actually this one can be removed, but next case is required, explanations below.
item = CKEDITOR.tools.clone( editor.ui.items[ item ] ); | ||
|
||
if ( !item.icon ) { | ||
item.icon = item.name || item.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.
Similar case as before.
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 is how button plugin works.
https://github.com/ckeditor/ckeditor-dev/blob/6c0469b530cbc767946379e00b5aedcb01e2ba5a/plugins/button/plugin.js#L262-L266
If there is no buttonDefinition.icon
property, then icon will fallback to name or command. But menu plugins
doesn't do that, so in order for menu item to have an icon we need to find that icon same way as button plugin
does.
Example opening ~/workspace/ckeditor/ckeditor-dev/samples/index.html
and executing following in console:
CKEDITOR.instances.editor.ui.get( 'Bold' );
Returned object will not have any icon property. Actually when writing this I'm thinking if maybe we should change how button works, so it always have icon
property when there is icon on button. WDYT @mlewand?
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.
As for assigning the icon
property during button creation - this sounds reasonable if only we started with such approach. Now there might be 3rd party integrations that rely on this property, and rely on it being a "falsy" value. So such change could break some solutions, we don't want to break things.
This rationale sounds reasonable. In this case it make sense to revert this fallback, thanks for clarifying.
Please just drop a short note, or a link to your comment here.
Also make sure to convert the code link above to a perma link, so something like that: https://github.com/ckeditor/ckeditor-dev/blob/6c0469b530cbc767946379e00b5aedcb01e2ba5a/plugins/button/plugin.js#L262-L263
plugins/splitbutton/plugin.js
Outdated
@@ -94,12 +115,12 @@ | |||
|
|||
editor.addFeature( properties.buttons[ item.id ] ); | |||
|
|||
// First button as default. It might be overwritten by actual default button. | |||
if ( !defaultButton && !item[ 'default' ] ) { | |||
// If no default button was defined then first button will act as default. |
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 logic could be now simplified. Here, in the loop, you could just leave if ( definition[ 'default' ] && definition[ 'default' ] === item.name ) {
check over here.
Then the second if
should go outside the loop, and that would check for conditions:
- whether
defaultButton
was not picked, with the logic above ☝️ - whether
definition[ 'default' ]
was not defined at all
Then assign the first item as a default button (if there was at least one item).
plugins/splitbutton/plugin.js
Outdated
previousButton = properties.buttons[ item.id ]; | ||
defaultButton = properties.buttons[ item.id ]; | ||
} else { | ||
if ( item[ 'default' ] ) { | ||
if ( definition[ 'default' ] && definition[ 'default' ].toLowerCase() === item.name ) { |
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.
definition.default
should be given as a button name, thus it should not be case-sensitive. We expect name Bold
, Image
etc.
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 case when we define split button in short forms with items as strings.
To get an item via ui.get
we need to pass an uppercased name eg. Bold
. But this uppercased name exists only in ui.items
/ ui.instances
as a key.
Object returned via ui.get
has property name
lowercased.
Example:
~/workspace/ckeditor/ckeditor-dev/samples/index.html
var bold = CKEDITOR.instances.editor.ui.get( 'bold' );
console.log( bold ); // undefined
bold = CKEDITOR.instances.editor.ui.get( 'Bold' );
console.log( bold.name ) // 'bold'
plugins/button/plugin.js
Outdated
@@ -448,9 +448,9 @@ | |||
* @param {String} definition.command The command to be executed once the button is activated. | |||
* @param {String} definition.toolbar The {@link CKEDITOR.config#toolbarGroups toolbar group} into which | |||
* the button will be added. An optional index value (separated by a comma) determines the button position within the group. | |||
* @param {String} definition.style The optional inline style that will be applied on button. Custom button styles are supported sins the **4.10.0** version. | |||
* @param {String} definition.style The optional inline style that will be applied on button. Custom button styles are supported sins the **4.11.0** version. |
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.
Typo in "are supported sins the"
@@ -535,6 +535,10 @@ | |||
|
|||
// Ignore items that are configured to be removed. | |||
if ( !removeButtons || CKEDITOR.tools.indexOf( removeButtons, name ) == -1 ) { | |||
// Option to define UI element in `config.toolbar` (#2091). | |||
if ( item.type && item.type in editor.ui._.handlers ) { |
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 feature of supporting type property is nowhere to be found in the API docs. It needs to be reflected in API docs.
@@ -1,5 +1,5 @@ | |||
@bender-ui: collapsed | |||
@bender-tags: feature, 4.10.0, 1679 | |||
@bender-tags: feature, 4.11.0, 1679 |
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.
Technically this change is out of scope of this issue. It would be nice if you could extract this commit from history and move it to a proper feature branch - but it's not a big deal if it will remain here in case it's tough to do so.
item = CKEDITOR.tools.clone( editor.ui.items[ item ] ); | ||
|
||
if ( !item.icon ) { | ||
item.icon = item.name || item.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.
As for assigning the icon
property during button creation - this sounds reasonable if only we started with such approach. Now there might be 3rd party integrations that rely on this property, and rely on it being a "falsy" value. So such change could break some solutions, we don't want to break things.
This rationale sounds reasonable. In this case it make sense to revert this fallback, thanks for clarifying.
Please just drop a short note, or a link to your comment here.
Also make sure to convert the code link above to a perma link, so something like that: https://github.com/ckeditor/ckeditor-dev/blob/6c0469b530cbc767946379e00b5aedcb01e2ba5a/plugins/button/plugin.js#L262-L263
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 code breaks if you set default
with an invalid string. Such cases could happen and it should not break the editor.
For instance:
Open https://github.com/ckeditor/ckeditor-dev/blob/b2cb7cc/tests/plugins/splitbutton/manual/toolbar.html#L9-L24 and use the following snippet:
CKEDITOR.replace( 'editor', {
toolbar: [ [ {
type: 'splitbutton',
name: 'BasicStylesSplitButton',
label: 'Basic styles',
face: 'Bold',
items: [ 'Bold' , 'Italic', 'Underline' ]
} ], [ {
type: 'splitbutton',
name: 'JustifySplitButton',
label: 'Justify',
items: [ 'JustifyLeft' , 'JustifyCenter', 'JustifyRight', 'JustifyBlock' ],
'default': 'JustifyRight123'
} ]
]
} );
Of course it must be covered by a unit test.
4f9a760
to
46f2eec
Compare
c97c489
to
f67f714
Compare
46f2eec
to
507a5ec
Compare
Removed item.default property default item should be defined in definition.default
…ems defined as objects
507a5ec
to
362a192
Compare
Rebased, as parent branch was rebased also. |
What is the purpose of this pull request?
New feature
Does your PR contain necessary tests?
All patches which change the editor code must include tests. You can always read more
on PR testing,
how to set the testing environment and
how to create tests
in the official CKEditor documentation.
This PR contains
What changes did you make?
This feature is rather straight forward. I've selected base as
t/1679
so GH displays real diff for this branch.Closes #2091