Skip to content

Commit

Permalink
Merge pull request #4599 from ckeditor/t/4583
Browse files Browse the repository at this point in the history
Add support for new syntaxes in `CKEDITOR.tools.color`
  • Loading branch information
sculpt0r authored Apr 6, 2021
2 parents 05e2b11 + 36e4a0f commit 7481c47
Show file tree
Hide file tree
Showing 3 changed files with 130 additions and 31 deletions.
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ CKEditor 4 Changelog

New Features:

* [#4583](/~https://github.com/ckeditor/ckeditor4/issues/4583): Added support for new, comma-less color syntax to [`CKEDITOR.tools.color`](https://ckeditor.com/docs/ckeditor4/latest/api/CKEDITOR_tools_color.html).
* [#4467](/~https://github.com/ckeditor/ckeditor4/issues/4467): Inserting content next to block [widgets](https://ckeditor.com/cke4/addon/widget) using keyboard navigation is now possible. Thanks to [bunglegrind](/~https://github.com/bunglegrind)!

## CKEditor 4.16
Expand Down
81 changes: 55 additions & 26 deletions core/tools/color.js
Original file line number Diff line number Diff line change
Expand Up @@ -332,10 +332,19 @@
* @returns {Array/null}
*/
extractColorChannelsFromHex: function( colorCode ) {
// We also like to support hex-like values (so hexes without hash at the beginning).
if ( colorCode.indexOf( '#' ) === -1 ) {
colorCode = '#' + colorCode;
}

if ( colorCode.match( CKEDITOR.tools.color.hex3CharsRegExp ) ) {
colorCode = this._.hex3ToHex6( colorCode );
}

if ( colorCode.match( CKEDITOR.tools.color.hex4CharsRegExp ) ) {
colorCode = this._.hex4ToHex8( colorCode );
}

if ( !colorCode.match( CKEDITOR.tools.color.hex6CharsRegExp ) && !colorCode.match( CKEDITOR.tools.color.hex8CharsRegExp ) ) {
return null;
}
Expand Down Expand Up @@ -367,19 +376,11 @@
extractColorChannelsFromRgba: function( colorCode ) {
var channels = this._.extractColorChannelsByPattern( colorCode, CKEDITOR.tools.color.rgbRegExp );

if ( !channels ) {
if ( !channels || channels.length < 3 || channels.length > 4 ) {
return null;
}

var isColorDeclaredWithAlpha = colorCode.indexOf( 'rgba' ) === 0;

if ( isColorDeclaredWithAlpha && channels.length !== 4 ) {
return null;
}

if ( !isColorDeclaredWithAlpha && channels.length !== 3 ) {
return null;
}
var isColorDeclaredWithAlpha = channels.length === 4;

var red = tryToConvertToValidIntegerValue( channels[ 0 ], CKEDITOR.tools.color.MAX_RGB_CHANNEL_VALUE ),
green = tryToConvertToValidIntegerValue( channels[ 1 ], CKEDITOR.tools.color.MAX_RGB_CHANNEL_VALUE ),
Expand All @@ -403,19 +404,11 @@
extractColorChannelsFromHsla: function( colorCode ) {
var channels = this._.extractColorChannelsByPattern( colorCode, CKEDITOR.tools.color.hslRegExp );

if ( !channels ) {
if ( !channels || channels.length < 3 || channels.length > 4 ) {
return null;
}

var isColorDeclaredWithAlpha = colorCode.indexOf( 'hsla' ) === 0;

if ( isColorDeclaredWithAlpha && channels.length !== 4 ) {
return null;
}

if ( !isColorDeclaredWithAlpha && channels.length !== 3 ) {
return null;
}
var isColorDeclaredWithAlpha = channels.length === 4;

var hue = tryToConvertToValidIntegerValue( channels[ 0 ], CKEDITOR.tools.color.MAX_HUE_CHANNEL_VALUE ),
saturation = tryToConvertToValidFloatValue( channels[ 1 ], CKEDITOR.tools.color.MAX_SATURATION_LIGHTNESS_CHANNEL_VALUE ),
Expand Down Expand Up @@ -446,6 +439,19 @@
return '#' + parts[ 1 ] + parts[ 1 ] + parts[ 2 ] + parts[ 2 ] + parts[ 3 ] + parts[ 3 ];
},

/**
* Converts 4-characters hexadecimal color format to 8-characters one.
*
* @private
* @param {String} hex4ColorCode 4-characters hexadecimal color, e.g. `#F0F0`.
* @returns {String} 8-characters hexadecimal color e.g. `#FF00FF00`.
*/
hex4ToHex8: function( hex4ColorCode ) {
var hex6 = this._.hex3ToHex6( hex4ColorCode.substr( 0, 4 ) );

return hex6 + CKEDITOR.tools.repeat( hex4ColorCode[ 4 ], 2 );
},

/**
* Extracts color channels values based on provided regular expression.
*
Expand All @@ -461,11 +467,25 @@
return null;
}

var values = match[ 2 ].split( ',' );
var separator = match[ 1 ].indexOf( ',' ) === -1 ? /\s/ : ',',
values = match[ 1 ].split( separator );

values = CKEDITOR.tools.array.map( values, function( value ) {
return CKEDITOR.tools.trim( value );
} );
values = CKEDITOR.tools.array.reduce( values, function( trimmedValues, value ) {
var trimmedValue = CKEDITOR.tools.trim( value );

if ( trimmedValue.length === 0 ) {
return trimmedValues;
}

return trimmedValues.concat( [ trimmedValue ] );
}, [] );

// There was alpha channel in the no-comma syntax ( / <number>%?).
if ( match[ 2 ] ) {
var alpha = CKEDITOR.tools.trim( match[ 2 ].replace( '/', '' ) );

values.push( alpha );
}

return values;
},
Expand Down Expand Up @@ -612,6 +632,15 @@
*/
hex3CharsRegExp: /#([0-9a-f]{3}$)/gim,

/**
* Regular expression to match hash (`#`) followed by four characters long hexadecimal color value.
*
* @private
* @static
* @property {RegExp}
*/
hex4CharsRegExp: /#([0-9a-f]{4}$)/gim,

/**
* Regular expression to match hash (`#`) followed by six characters long hexadecimal color value.
*
Expand Down Expand Up @@ -640,7 +669,7 @@
* @static
* @property {RegExp}
*/
rgbRegExp: /(rgb[a]?)\(([.,\d\s%]*)\)/i,
rgbRegExp: /rgba?\(([.,\d\s%]*)(\s*\/\s*[\d.%]+)?\s*\)/i,

/**
* Regular expression to extract numbers from HSL and HSLA color value.
Expand All @@ -652,7 +681,7 @@
* @static
* @property {RegExp}
*/
hslRegExp: /(hsl[a]?)\(([.,\d\s%]*)\)/i,
hslRegExp: /hsla?\(([.,\d\s%]*)(\s*\/\s*[\d.%]+)?\s*\)/i,

/**
* Color list based on [W3 named colors list](https://www.w3.org/TR/css-color-4/#named-colors).
Expand Down
79 changes: 74 additions & 5 deletions tests/core/tools/color.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
// 3-HEX -> hexadecimal color with only 3 characters value: #FFF
// 6-HEX -> hexadecimal color with exactly 6 characters value: #FFFFFF
// 8-HEX -> hexadecimal color with exactly 8 characters value: #FFFFFF00. Last two characters are for alpha
// n-HEX-like -> n-HEX format without the hash at the beginning: FFF, FFF0, FFFFFF, FFFFFF00

( function() {
'use strict';
Expand Down Expand Up @@ -36,8 +37,6 @@

'test color from RGBA with outranged alpha percent value returns default value': colorTools.testColorConversion( 'rgba( 120, 120, 120, 101% )', 'default', 'getHex', 'default' ),

'test color from invalid HSL with four values returns default value': colorTools.testColorConversion( 'hsl( 40, 40%, 100%, 1 )', 'default', 'getHex', 'default' ),

'test color from outranged percent HSL value returns default value': colorTools.testColorConversion( 'hsl( 361, 101%, 101% )', 'default', 'getHex', 'default' ),

'test color from outranged normalized HSL value returns default value': colorTools.testColorConversion( 'hsl( 361, 1.1, 1.1 )', 'default', 'getHex', 'default' ),
Expand All @@ -64,8 +63,6 @@

'test color from valid string color name returns 6-HEX': colorTools.testColorConversion( 'red', '#FF0000', 'getHex' ),

'test color from invalid RGB with four values returns default value': colorTools.testColorConversion( 'rgb( 40, 40, 150, 1 )', 'default', 'getHex', 'default' ),

'test color from valid RGB string returns 6-HEX': colorTools.testColorConversion( 'rgb( 40, 40, 150 )', '#282896', 'getHex' ),

'test color from valid RGB string returns 6-HEX (max value)': colorTools.testColorConversion( 'rgb( 255, 40, 150 )', '#FF2896', 'getHex' ),
Expand Down Expand Up @@ -104,7 +101,79 @@

'test color from valid HSL string returns 8-HEX': colorTools.testColorConversion( 'hsl( 195, 1, 0.5 )', '#00BFFFFF', 'getHexWithAlpha' ),

'test color from valid RGB with percent returns valid RGB': colorTools.testColorConversion( 'rgb(20.5%,0,255)', 'rgb(52,0,255)', 'getRgb' )
'test color from valid RGB with percent returns valid RGB': colorTools.testColorConversion( 'rgb(20.5%,0,255)', 'rgb(52,0,255)', 'getRgb' ),

// (#4583)
'test color from 4-HEX returns valid 6-HEX': colorTools.testColorConversion( '#F0F0', '#FFFFFF', 'getHex' ),

// (#4583)
'test color from 4-HEX returns valid 8-HEX': colorTools.testColorConversion( '#F0F0', '#FF00FF00', 'getHexWithAlpha' ),

// (#4583)
'test color from 4-HEX returns valid RGBA': colorTools.testColorConversion( '#F0F0', 'rgba(255,0,255,0)', 'getRgba' ),

// (#4583)
'test color from 4-HEX returns valid HSLA': colorTools.testColorConversion( '#F0F0','hsla(-60,100%,50%,0)', 'getHsla' ),

// (#4583)
'test RGB values are treated like RGBA values': colorTools.testColorConversion( 'rgb( 255, 0, 255, 0)', 'rgba(255,0,255,0)', 'getRgba' ),

// (#4583)
'test HSL values are treated like HSLA values': colorTools.testColorConversion( 'hsl( 195, 100%, 50%, 0 )', 'hsla(195,100%,50%,0)', 'getHsla' ),

// (#4583)
'test RGB value with no-comma syntax': colorTools.testColorConversion( 'rgb( 255 0 255 )', 'rgb(255,0,255)', 'getRgb' ),

// (#4583)
'test RGB value with alpha (number) and no-comma syntax': colorTools.testColorConversion( 'rgb( 255 0 255 / 0.1 )', 'rgba(255,0,255,0.1)', 'getRgba' ),

// (#4583)
'test RGB value with alpha (percentage) and no-comma syntax': colorTools.testColorConversion( 'rgb( 255 0 255 / 10% )', 'rgba(255,0,255,0.1)', 'getRgba' ),

// (#4583)
'test RGBA value with no-comma syntax': colorTools.testColorConversion( 'rgba( 255 0 255 )', 'rgb(255,0,255)', 'getRgb' ),

// (#4583)
'test RGBA value with alpha (number) and no-comma syntax': colorTools.testColorConversion( 'rgba( 255 0 255 / 0.1 )', 'rgba(255,0,255,0.1)', 'getRgba' ),

// (#4583)
'test RGBA value with alpha (percentage) and no-comma syntax': colorTools.testColorConversion( 'rgba( 255 0 255 / 10% )', 'rgba(255,0,255,0.1)', 'getRgba' ),

// (#4583)
// The expected value is incorrect due to #4597.
'test HSL value with no-comma syntax': colorTools.testColorConversion( 'hsl( 200 50% 10% )', 'hsl(199,0%,10%)', 'getHsl' ),

// (#4583)
// The expected value is incorrect due to #4597.
'test HSL value with alpha (number) and no-comma syntax': colorTools.testColorConversion( 'hsl( 200 50% 10% / 0.1 )', 'hsla(199,0%,10%,0.1)', 'getHsla' ),

// (#4583)
// The expected value is incorrect due to #4597.
'test HSL value with alpha (percentage) and no-comma syntax': colorTools.testColorConversion( 'hsl( 200 50% 10% / 10% )', 'hsla(199,0%,10%,0.1)', 'getHsla' ),

// (#4583)
// The expected value is incorrect due to #4597.
'test HSLA value with no-comma syntax': colorTools.testColorConversion( 'hsla( 200 50% 10% )', 'hsl(199,0%,10%)', 'getHsl' ),

// (#4583)
// The expected value is incorrect due to #4597.
'test HSLA value with alpha (number) and no-comma syntax': colorTools.testColorConversion( 'hsla( 200 50% 10% / 0.1 )', 'hsla(199,0%,10%,0.1)', 'getHsla' ),

// (#4583)
// The expected value is incorrect due to #4597.
'test HSLA value with alpha (percentage) and no-comma syntax': colorTools.testColorConversion( 'hsla( 200 50% 10% / 10% )', 'hsla(199,0%,10%,0.1)', 'getHsla' ),

// (#4583)
'test 6-HEX-like value is treated as 6-HEX value': colorTools.testColorConversion( 'FF0000', '#FF0000', 'getHex' ),

// (#4583)
'test 3-HEX-like value is treated as 3-HEX value': colorTools.testColorConversion( 'F00', '#FF0000', 'getHex' ),

// (#4583)
'test 8-HEX-like value is treated as 8-HEX value': colorTools.testColorConversion( 'FF0000FF', '#FF0000FF', 'getHexWithAlpha' ),

// (#4583)
'test 4-HEX-like value is treated as 8-HEX value': colorTools.testColorConversion( 'F00F', '#FF0000FF', 'getHexWithAlpha' )
} );

} )();

0 comments on commit 7481c47

Please sign in to comment.