-
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
Unify color handling #4718
Unify color handling #4718
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.
It looks like the root issue is fixed now (#4333) 👍 👍
However I'm not sure if it wouldn't be better to introduce options parameter. It would be more flexible
Well, it sounds like a good idea. When you look at some functions, that didn't use an object as an option. They end with lots of code just to provide compatibility later. For example:
Lines 1125 to 1135 in 8e5575f
setData: function( data, options, internal ) { | |
var fireSnapshot = true, | |
// Backward compatibility. | |
callback = options, | |
eventData; | |
if ( options && typeof options == 'object' ) { | |
internal = options.internal; | |
callback = options.callback; | |
fireSnapshot = !options.noSnapshot; | |
} |
It looks for now that there won't be any more thing to add, but... you never know that - until you have to add another one :)
I've also changed the way in which colors in Color History are rendered.
I found a little inconsistency here. When you explicitly type lowercase 6-HEX - it's lowercase in history. If you type it uppercase - it's uppercased.
Also, If we are allowing 6-HEX in history, why we even want them to be shortened? It looks like that creates some additional code that could be skipped? I know, we are allowing 3-HEX-es, but for sake of unify
we could decide on one format to be displayed. Therefore, even 3-HEX will be converted to 6-HEX.
Overall I see, that a few '#' and substr
disappears 👍
plugins/colorbutton/plugin.js
Outdated
} | ||
|
||
// Replace 3-character hexadecimal notation with a 6-character hexadecimal notation (#1008). | ||
return CKEDITOR.tools.normalizeHex( '#' + CKEDITOR.tools.convertRgbToHex( color || '' ) ).replace( /#/g, '' ); | ||
// It also covers other cases, like colors with alpha channel (#4351). | ||
return CKEDITOR.tools.normalizeHex( colorInstance.getHex() || '' ); |
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 function is already marked as deprecated. We already have some ambiguous normalizations
around. The one is here in ColorBox
and another in tools
. So I'm starting to wonder - what is the normalization process because it leads to very different results. It is related to parsing values from CSS attributes. So maybe we should separate the so-called normalization
and extracting value from the CSS 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.
The issue is that removing this normalization will basically nuke tests… CKEDITOR.tools.color
returns uppercase hexes and whole tests assume they are lowercase. So I'm not sure if it's worth it to refactor all 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.
Or not, nothing happened 🤔 Strange, because it suggests that there's yet another normalization on the way…
The issue is that user could want to use the original format of the color (see http://localhost:1030/tests/plugins/colorbutton/config#tests%2Fplugins%2Fcolorbutton%2Fconfig%20test%20config.colorButton\_foreStyle%20with%20color%20attribute), not the normalized one. And the current flow de facto disables the ability to force normalization for history entries (it would require creating separate And that's why I'm so unhappy with the whole refactor: the code is still messy. And with changes from this PR it becomes even messier… |
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 added a few requests for color
class extensions and few other thoughts about passing the entire value. Also, I've made some diagram which helps me with the code flow (https://miro.com/app/board/o9J_lApbiDQ=/)
If my comments would appear to be invalid due to back incompatibility, I think we will be finishing with this only with a few detailed comments I also left. 🤞 .
Indeed there is a lot going on. It takes a while before I catch up how it works.
The last thing: I think we should look at colordialog - there is also some magic with color validation and RegExps...
@@ -308,7 +308,7 @@ | |||
} | |||
}, null, colorData ); | |||
} else { | |||
setColor( color && '#' + color, colorName, history ); | |||
setColor( color && color, colorName, history ); |
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.
setColor( color && color, colorName, history ); | |
setColor( color, colorName, history ); |
@@ -269,9 +269,9 @@ | |||
finalColor = ''; | |||
} | |||
if ( type == 'fore' ) { | |||
colorData.automaticTextColor = '#' + ColorBox.normalizeColor( automaticColor ); | |||
colorData.automaticTextColor = ColorBox.normalizeColor( automaticColor ); |
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.
Should we also adjust line with automaticColor = '#ffffff';
to be used with tools.color?
Then we can use explicit `panelBlock.element.findOne( '#' + colorBoxId ).setStyle( 'background-color', automaticColor.getHex() );
|
||
return CKEDITOR.tools.normalizeHex( colorInstance.getHex() || '' ).replace( /#/g, '' ); | ||
var colorInstance = ( color instanceof CKEDITOR.tools.color ) ? color : new CKEDITOR.tools.color( color, '' ), | ||
isTransparent = Number( colorInstance._.alpha ) === 0; |
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.
Don't we already store alpha as a number in the color instance? But, what is more important, I would rather add colorInstance.isFullyTransparent()
method to the color class without taking out the inner implementation of alpha outside. We shouldn't reach for private members just to avoid problems if we decide to change something inside the color class.
* @returns {String} Returns color in hex format, but without the hash at the beginning, e.g. `ff0000` for red. | ||
* In case of transparent colors, it returns `'transparent'` string. | ||
*/ | ||
normalizeColor: function( color ) { |
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 have a problem with naming here. Since it is private - nothing should break on the client's side if we rename it? As I wrote before normalization
is a kind of a wide concept. In tools, we have normalizeHex
which means to convert styleText
into 6-HEX. Here, normalizeColor
means: return transparent
or 6-HEX or even default value which could be anything that comes with the color instance.
And we have some intention when we call this method. We want to receive some value that would be applicable as a CSS attribute. And we use it to compare two colors that come from various sources.
So maybe convertToStyleValue()
or sth similar?
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'm not sure about changing name. It's not used only for getting color suitable for [style]
attribute, e.g.
ckeditor4/plugins/colorbutton/plugin.js
Line 180 in 70d7394
color = ColorBox.normalizeColor( color ); |
In one case it's even used for the reversed operation – getting color from CSS →
ckeditor4/plugins/colorbutton/plugin.js
Line 651 in 70d7394
return color in list ? list[ color ].substr( 1 ) : ColorBox.normalizeColor( span.getComputedStyle( cssProperty ) ).toUpperCase(); |
|
||
this.setHtml(); | ||
}, | ||
|
||
statics: { | ||
getColorName: function( editor, color ) { | ||
var names = ColorBox.colorNames( editor ), | ||
hex = color.getHex().replace( /^#/g, '' ), |
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.
If we need HEX without #
sign, maybe it's good time to add another option (e.g. named withHash
or sth similar) to our getHex( optionObj )
. The same goes for the below line. It should be easier to read that we want
getHex( { withHash: false } )
than decoding replace while we are reading this logic. I know, this is not so complicated, but still - requires at least a moment to find out what is the intention here.
return colorInstance.getHex() || ''; | ||
}, | ||
|
||
getAppliableColor: function( color ) { |
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 used only inside setHtml
, why we need this to be static?
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 thought that would be more coherent with existing normalizeColor
. But there isn't any real need for that, it can be moved as a private function into setHtml
.
}, | ||
|
||
getAppliableColor: function( color ) { | ||
if ( !color._.isValidColor ) { |
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 are reaching for a private members of the color instance - which is not good practice. I try to break color-code / color-obj flow (from the getApplicableColor point of view): https://miro.com/app/board/o9J_lApbiDQ=/
I'm not sure how much of this should be affected by backward compatibility, but it looks like we are spinning around with our own value transformations. The ideal way: we are take anything from colordialog
and convert it to a color object. The same for input from config
.
If color from colordialog
is ivalid -> then we could have an empty default value (as default value returned by color class in case of invalid color). If we want to store original
input provided by the user, we can always store it as data
attribute using color.getInitialValue()
.
color.getHex( { shorten: initialValue.length === 3 } ).toLowerCase().substr( 1 ), | ||
isShortHexLike = isHexLike && initialValue.length === 3; | ||
|
||
return isHexLike ? color.getHex( { shorten: isShortHexLike } ) : initialValue; |
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 probably could return to the user getInitialValue()
without any checks. The User always gets back what was provided. And just in case someone misspells RGB value, it can be corrected instead of typing it again from scratch. But we probably should add some indicator to the colordialog in case of invalid value.
@@ -532,16 +553,19 @@ | |||
}, | |||
|
|||
setHtml: function() { | |||
var appliableColor = ColorBox.getAppliableColor( this.color ), | |||
colorStr = appliableColor ? this.color.getInitialValue() : ''; |
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.
colorStr
name seems to be low informative. Could you name it something like validatedOriginalColor
or similar?
} ); | ||
var normalizedColor = ColorBox.normalizeColor( colorCode ), | ||
index = CKEDITOR.tools.getIndex( this.boxes, function( box ) { | ||
return ColorBox.normalizeColor( box.color ) === normalizedColor; |
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.
Two instance creations of ColorBox
have color
property passed as an object. We should create compare method inside color
class that tells whenever two colors are equals.
Rebased onto latest |
After some talks with @Comandeer and @sculpt0r we have decided to freeze this PR for now. Any reasonable changes would require refactoring big part of the existing solution which would be really time consuming and due to other priorities we can't proceed with this ATM. |
What is the purpose of this pull request?
Task
Does your PR contain necessary tests?
All patches that 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
Did you follow the CKEditor 4 code style guide?
Your code should follow the guidelines from the CKEditor 4 code style guide which helps keep the entire codebase consistent.
What is the proposed changelog entry for this pull request?
What changes did you make?
I've used
CKEDITOR.tools.color
wherever it was possible. Some places still need some love and refactor, but I'm not sure if it's worth it.I've also introduced the ability to get short hex from
CKEDITOR.tools.color#getHex()
andCKEDITOR.tools.color#getHexWithAlpha()
via a new parameter,shorten
. However I'm not sure if it wouldn't be better to introduceoptions
parameter. It would be more flexible 🤔I've also changed the way in which colors in Color History are rendered.
Which issues does your PR resolve?
Closes #4592.
Closes #4726.
Closes #4333.