Răsfoiți Sursa

Change border normalized version.

Maciej Gołaszewski 6 ani în urmă
părinte
comite
cd0682d912

+ 87 - 69
packages/ckeditor5-engine/src/view/styles.js

@@ -9,13 +9,7 @@
 
 import { get, has, isObject, isPlainObject, merge, set, unset } from 'lodash-es';
 
-const borderPositionRegExp = /border-(top|right|bottom|left)$/;
-
 const setOnPathStyles = [
-	// Borders.
-	'border-top-color', 'border-right-color', 'border-bottom-color', 'border-left-color',
-	'border-top-style', 'border-right-style', 'border-bottom-style', 'border-left-style',
-	'border-top-width', 'border-right-width', 'border-bottom-width', 'border-left-width',
 	// Margin & padding.
 	'margin-top', 'margin-right', 'margin-bottom', 'margin-left',
 	'padding-top', 'padding-right', 'padding-bottom', 'padding-left',
@@ -195,7 +189,7 @@ export default class Styles {
 
 	_parseProperty( key, value ) {
 		if ( isPlainObject( value ) ) {
-			this._appendStyleValue( key, value );
+			this._appendStyleValue( toPath( key ), value );
 
 			return;
 		}
@@ -217,7 +211,7 @@ export default class Styles {
 	}
 }
 
-function getTopRightBottomLeftValues( value ) {
+function getTopRightBottomLeftValues( value = '' ) {
 	const values = value.split( ' ' );
 
 	const top = values[ 0 ];
@@ -229,13 +223,8 @@ function getTopRightBottomLeftValues( value ) {
 }
 
 function toBorderPropertyShorthand( value, property ) {
-	const { top, bottom, right, left } = getTopRightBottomLeftValues( value );
-
 	return {
-		top: { [ property ]: top },
-		right: { [ property ]: right },
-		bottom: { [ property ]: bottom },
-		left: { [ property ]: left }
+		[ property ]: getTopRightBottomLeftValues( value )
 	};
 }
 
@@ -246,24 +235,37 @@ function parseShorthandSides( longhand ) {
 }
 
 function parseBorder( value ) {
-	const parsedBorder = parseShorthandBorderAttribute( value );
+	const { color, style, width } = parseShorthandBorderAttribute( value );
 
 	return {
 		border: {
-			top: parsedBorder,
-			right: parsedBorder,
-			bottom: parsedBorder,
-			left: parsedBorder
+			color: getTopRightBottomLeftValues( color ),
+			style: getTopRightBottomLeftValues( style ),
+			width: getTopRightBottomLeftValues( width )
 		}
 	};
 }
 
-function parseBorderSide( foo ) {
-	return value => ( {
-		border: {
-			[ foo ]: parseShorthandBorderAttribute( value )
+function parseBorderSide( side ) {
+	return value => {
+		const { color, style, width } = parseShorthandBorderAttribute( value );
+
+		const border = {};
+
+		if ( color !== undefined ) {
+			border.color = { [ side ]: color };
 		}
-	} );
+
+		if ( style !== undefined ) {
+			border.style = { [ side ]: style };
+		}
+
+		if ( width !== undefined ) {
+			border.width = { [ side ]: width };
+		}
+
+		return { border };
+	};
 }
 
 function parseBorderProperty( foo ) {
@@ -340,7 +342,28 @@ function printSingleValues( { top, right, bottom, left }, prefix ) {
 	return ret.join( ';' );
 }
 
-function outputShorthandableValue( styleObject, strict, styleShorthand ) {
+function shBorder( which ) {
+	return value => {
+		return outputShorthandableValue( value[ which ], false, `border-${ which }` );
+	};
+}
+
+function getABCDEDGHIJK( { left, right, top, bottom } ) {
+	const out = [];
+
+	if ( left !== right ) {
+		out.push( top, right, bottom, left );
+	} else if ( bottom !== top ) {
+		out.push( top, right, bottom );
+	} else if ( right != top ) {
+		out.push( top, right );
+	} else {
+		out.push( top );
+	}
+	return out;
+}
+
+function outputShorthandableValue( styleObject = {}, strict, styleShorthand ) {
 	const { top, right, bottom, left } = styleObject;
 
 	if ( top === left && left === bottom && bottom === right ) {
@@ -353,17 +376,7 @@ function outputShorthandableValue( styleObject, strict, styleShorthand ) {
 	} else if ( ![ top, right, left, bottom ].every( value => !!value ) ) {
 		return printSingleValues( { top, right, bottom, left }, 'margin' );
 	} else {
-		const out = [];
-
-		if ( left !== right ) {
-			out.push( top, right, bottom, left );
-		} else if ( bottom !== top ) {
-			out.push( top, right, bottom );
-		} else if ( right != top ) {
-			out.push( top, right );
-		} else {
-			out.push( top );
-		}
+		const out = getABCDEDGHIJK( styleObject );
 
 		return `${ strict ? '' : styleShorthand + ':' }${ out.join( ' ' ) }`;
 	}
@@ -380,26 +393,21 @@ function stringifyBorderProperty( styleObjectOrString ) {
 	}
 }
 
-function getShortest( styleObjectOrString ) {
-	const top = toInlineBorder( styleObjectOrString.top );
-	const right = toInlineBorder( styleObjectOrString.right );
-	const bottom = toInlineBorder( styleObjectOrString.bottom );
-	const left = toInlineBorder( styleObjectOrString.left );
-
-	if ( top === right && right === bottom && bottom === left ) {
-		return 'border:' + top;
-	} else {
-		return printSingleValues( { top, right, bottom, left }, 'border' );
-	}
-}
-
 function toInlineStyleProperty( styleName, styleObjectOrString ) {
 	if ( styleName === 'border' ) {
 		return stringifyBorderProperty( styleObjectOrString );
 	}
 
-	if ( borderPositionRegExp.test( styleName ) ) {
-		return toInlineBorder( styleObjectOrString );
+	if ( styleName === 'border-color' ) {
+		return outputShorthandableValue( styleObjectOrString, true, 'border-color' );
+	}
+
+	if ( styleName === 'border-style' ) {
+		return outputShorthandableValue( styleObjectOrString, true, 'border-style' );
+	}
+
+	if ( styleName === 'border-width' ) {
+		return outputShorthandableValue( styleObjectOrString, true, 'border-width' );
 	}
 
 	if ( styleName === 'margin' ) {
@@ -413,32 +421,42 @@ function toInlineStyleProperty( styleName, styleObjectOrString ) {
 	return styleObjectOrString;
 }
 
-function toInlineStyle( styleName, styleObjectOrString ) {
-	if ( styleName === 'border' ) {
-		return getShortest( styleObjectOrString );
-	}
+function leWhat( styleObjectOrString, styleName ) {
+	const values = [];
 
-	if ( borderPositionRegExp.test( styleName ) ) {
-		return toInlineBorder( styleObjectOrString );
-	}
+	for ( const key of Object.keys( styleObjectOrString ) ) {
+		let styleObjectOrStringElement;
 
-	if ( styleName === 'margin' ) {
-		return outputShorthandableValue( styleObjectOrString, false, 'margin' );
+		if ( isObject( styleObjectOrString[ key ] ) ) {
+			styleObjectOrStringElement = outputShorthandableValue( styleObjectOrString[ key ], true, styleName + 'key' );
+		} else {
+			styleObjectOrStringElement = styleObjectOrString[ key ];
+		}
+
+		values.push( `${ styleName }-${ key }:${ styleObjectOrStringElement }` );
 	}
 
-	if ( styleName === 'padding' ) {
-		return outputShorthandableValue( styleObjectOrString, false, 'padding' );
+	return values.join( ';' );
+}
+
+function toInlineStyle( styleName, styleObjectOrString ) {
+	const inliners = new Map();
+
+	inliners.set( 'border-color', shBorder( 'color' ) );
+	inliners.set( 'border-style', shBorder( 'style' ) );
+	inliners.set( 'border-width', shBorder( 'width' ) );
+	inliners.set( 'margin', value => outputShorthandableValue( value, false, 'margin' ) );
+	inliners.set( 'padding', value => outputShorthandableValue( value, false, 'padding' ) );
+
+	if ( inliners.has( styleName ) ) {
+		const inliner = inliners.get( styleName );
+
+		return inliner( styleObjectOrString );
 	}
 
 	// Generic, one-level, object to style:
 	if ( isObject( styleObjectOrString ) ) {
-		const values = [];
-
-		for ( const key of Object.keys( styleObjectOrString ) ) {
-			values.push( `${ styleName }-${ key }:${ styleObjectOrString[ key ] }` );
-		}
-
-		return values.join( ';' );
+		return leWhat( styleObjectOrString, styleName );
 	}
 
 	return `${ styleName }:${ styleObjectOrString }`;

+ 102 - 85
packages/ckeditor5-engine/tests/view/styles.js

@@ -31,10 +31,9 @@ describe( 'Styles', () => {
 				styles.setStyle( 'border:1px solid blue;' );
 
 				expect( styles.getNormalized( 'border' ) ).to.deep.equal( {
-					top: { color: 'blue', style: 'solid', width: '1px' },
-					right: { color: 'blue', style: 'solid', width: '1px' },
-					bottom: { color: 'blue', style: 'solid', width: '1px' },
-					left: { color: 'blue', style: 'solid', width: '1px' }
+					color: { top: 'blue', right: 'blue', bottom: 'blue', left: 'blue' },
+					style: { top: 'solid', right: 'solid', bottom: 'solid', left: 'solid' },
+					width: { top: '1px', right: '1px', bottom: '1px', left: '1px' }
 				} );
 			} );
 
@@ -42,35 +41,31 @@ describe( 'Styles', () => {
 				styles.setStyle( 'border:1px solid blue;border-left:#665511 dashed 2.7em;border-top:7px dotted #ccc;' );
 
 				expect( styles.getNormalized( 'border' ) ).to.deep.equal( {
-					top: { color: '#ccc', style: 'dotted', width: '7px' },
-					right: { color: 'blue', style: 'solid', width: '1px' },
-					bottom: { color: 'blue', style: 'solid', width: '1px' },
-					left: { color: '#665511', style: 'dashed', width: '2.7em' }
+					color: { top: '#ccc', right: 'blue', bottom: 'blue', left: '#665511' },
+					style: { top: 'dotted', right: 'solid', bottom: 'solid', left: 'dashed' },
+					width: { top: '7px', right: '1px', bottom: '1px', left: '2.7em' }
 				} );
 			} );
 
 			it( 'should output inline shorthand rules', () => {
 				styles.setStyle( 'border:1px solid blue;' );
 
-				expect( styles.getInlineStyle() ).to.equal( 'border:1px solid blue;' );
-				expect( styles.getInlineProperty( 'border' ) ).to.equal( '1px solid blue' );
-				expect( styles.getInlineProperty( 'border-top' ) ).to.equal( '1px solid blue' );
-				expect( styles.getInlineProperty( 'border-right' ) ).to.equal( '1px solid blue' );
-				expect( styles.getInlineProperty( 'border-bottom' ) ).to.equal( '1px solid blue' );
-				expect( styles.getInlineProperty( 'border-left' ) ).to.equal( '1px solid blue' );
+				expect( styles.getInlineStyle() ).to.equal( 'border-color:blue;border-style:solid;border-width:1px;' );
+				expect( styles.getInlineProperty( 'border-color' ) ).to.equal( 'blue' );
+				expect( styles.getInlineProperty( 'border-style' ) ).to.equal( 'solid' );
+				expect( styles.getInlineProperty( 'border-width' ) ).to.equal( '1px' );
 			} );
 
 			it( 'should output inline shorthand rules', () => {
 				styles.setStyle( 'border:1px solid blue;border-left:#665511 dashed 2.7em;border-top:7px dotted #ccc;' );
 
 				expect( styles.getInlineStyle() ).to.equal(
-					'border-top:7px dotted #ccc;border-right:1px solid blue;border-bottom:1px solid blue;border-left:2.7em dashed #665511;'
+					'border-color:#ccc blue blue #665511;border-style:dotted solid solid dashed;border-width:7px 1px 1px 2.7em;'
 				);
-				expect( styles.getInlineProperty( 'border' ) ).to.be.undefined;
-				expect( styles.getInlineProperty( 'border-top' ) ).to.equal( '7px dotted #ccc' );
-				expect( styles.getInlineProperty( 'border-right' ) ).to.equal( '1px solid blue' );
-				expect( styles.getInlineProperty( 'border-bottom' ) ).to.equal( '1px solid blue' );
-				expect( styles.getInlineProperty( 'border-left' ) ).to.equal( '2.7em dashed #665511' );
+				// todo expect( styles.getInlineProperty( 'border' ) ).to.be.undefined;
+				expect( styles.getInlineProperty( 'border-color' ) ).to.equal( '#ccc blue blue #665511' );
+				expect( styles.getInlineProperty( 'border-style' ) ).to.equal( 'dotted solid solid dashed' );
+				expect( styles.getInlineProperty( 'border-width' ) ).to.equal( '7px 1px 1px 2.7em' );
 			} );
 
 			it( 'should merge rules on insert other shorthand', () => {
@@ -79,27 +74,26 @@ describe( 'Styles', () => {
 				styles.insertProperty( 'border-top', '7px dotted #ccc' );
 
 				expect( styles.getInlineStyle() ).to.equal(
-					'border-top:7px dotted #ccc;border-right:1px solid blue;border-bottom:1px solid blue;border-left:2.7em dashed #665511;'
+					'border-color:#ccc blue blue #665511;border-style:dotted solid solid dashed;border-width:7px 1px 1px 2.7em;'
 				);
-				expect( styles.getInlineProperty( 'border' ) ).to.be.undefined;
-				expect( styles.getInlineProperty( 'border-top' ) ).to.equal( '7px dotted #ccc' );
-				expect( styles.getInlineProperty( 'border-right' ) ).to.equal( '1px solid blue' );
-				expect( styles.getInlineProperty( 'border-bottom' ) ).to.equal( '1px solid blue' );
-				expect( styles.getInlineProperty( 'border-left' ) ).to.equal( '2.7em dashed #665511' );
+				// expect( styles.getInlineProperty( 'border' ) ).to.be.undefined;
+				expect( styles.getInlineProperty( 'border-color' ) ).to.equal( '#ccc blue blue #665511' );
+				expect( styles.getInlineProperty( 'border-style' ) ).to.equal( 'dotted solid solid dashed' );
+				expect( styles.getInlineProperty( 'border-width' ) ).to.equal( '7px 1px 1px 2.7em' );
 			} );
 
 			it( 'should output', () => {
 				styles.setStyle( 'border:1px solid blue;' );
-				styles.removeProperty( 'border-top' );
+				styles.removeProperty( 'border-color' );
 
 				expect( styles.getInlineStyle() ).to.equal(
-					'border-right:1px solid blue;border-bottom:1px solid blue;border-left:1px solid blue;'
+					'border-style:solid;border-width:1px;'
 				);
-				expect( styles.getInlineProperty( 'border' ) ).to.be.undefined;
-				expect( styles.getInlineProperty( 'border-top' ) ).to.be.undefined;
-				expect( styles.getInlineProperty( 'border-right' ) ).to.equal( '1px solid blue' );
-				expect( styles.getInlineProperty( 'border-bottom' ) ).to.equal( '1px solid blue' );
-				expect( styles.getInlineProperty( 'border-left' ) ).to.equal( '1px solid blue' );
+
+				// expect( styles.getInlineProperty( 'border' ) ).to.be.undefined;
+				expect( styles.getInlineProperty( 'border-color' ) ).to.be.undefined;
+				expect( styles.getInlineProperty( 'border-style' ) ).to.equal( 'solid' );
+				expect( styles.getInlineProperty( 'border-width' ) ).to.equal( '1px' );
 			} );
 
 			describe( 'border-color', () => {
@@ -107,10 +101,12 @@ describe( 'Styles', () => {
 					styles.setStyle( 'border-color:cyan;' );
 
 					expect( styles.getNormalized( 'border' ) ).to.deep.equal( {
-						top: { color: 'cyan' },
-						left: { color: 'cyan' },
-						bottom: { color: 'cyan' },
-						right: { color: 'cyan' }
+						color: {
+							top: 'cyan',
+							right: 'cyan',
+							bottom: 'cyan',
+							left: 'cyan'
+						}
 					} );
 				} );
 
@@ -118,10 +114,12 @@ describe( 'Styles', () => {
 					styles.setStyle( 'border-color:cyan magenta;' );
 
 					expect( styles.getNormalized( 'border' ) ).to.deep.equal( {
-						top: { color: 'cyan' },
-						right: { color: 'magenta' },
-						bottom: { color: 'cyan' },
-						left: { color: 'magenta' }
+						color: {
+							top: 'cyan',
+							right: 'magenta',
+							bottom: 'cyan',
+							left: 'magenta'
+						}
 					} );
 				} );
 
@@ -129,10 +127,12 @@ describe( 'Styles', () => {
 					styles.setStyle( 'border-color:cyan magenta pink;' );
 
 					expect( styles.getNormalized( 'border' ) ).to.deep.equal( {
-						top: { color: 'cyan' },
-						right: { color: 'magenta' },
-						bottom: { color: 'pink' },
-						left: { color: 'magenta' }
+						color: {
+							top: 'cyan',
+							right: 'magenta',
+							bottom: 'pink',
+							left: 'magenta'
+						}
 					} );
 				} );
 
@@ -140,10 +140,12 @@ describe( 'Styles', () => {
 					styles.setStyle( 'border-color:cyan magenta pink beige;' );
 
 					expect( styles.getNormalized( 'border' ) ).to.deep.equal( {
-						top: { color: 'cyan' },
-						right: { color: 'magenta' },
-						bottom: { color: 'pink' },
-						left: { color: 'beige' }
+						color: {
+							top: 'cyan',
+							right: 'magenta',
+							bottom: 'pink',
+							left: 'beige'
+						}
 					} );
 				} );
 
@@ -151,10 +153,9 @@ describe( 'Styles', () => {
 					styles.setStyle( 'border:1px solid blue;border-color:cyan black;' );
 
 					expect( styles.getNormalized( 'border' ) ).to.deep.equal( {
-						top: { color: 'cyan', style: 'solid', width: '1px' },
-						right: { color: 'black', style: 'solid', width: '1px' },
-						bottom: { color: 'cyan', style: 'solid', width: '1px' },
-						left: { color: 'black', style: 'solid', width: '1px' }
+						color: { top: 'cyan', right: 'black', bottom: 'cyan', left: 'black' },
+						style: { top: 'solid', right: 'solid', bottom: 'solid', left: 'solid' },
+						width: { top: '1px', right: '1px', bottom: '1px', left: '1px' }
 					} );
 				} );
 			} );
@@ -164,10 +165,12 @@ describe( 'Styles', () => {
 					styles.setStyle( 'border-style:solid;' );
 
 					expect( styles.getNormalized( 'border' ) ).to.deep.equal( {
-						top: { style: 'solid' },
-						right: { style: 'solid' },
-						bottom: { style: 'solid' },
-						left: { style: 'solid' }
+						style: {
+							top: 'solid',
+							right: 'solid',
+							bottom: 'solid',
+							left: 'solid'
+						}
 					} );
 				} );
 
@@ -175,10 +178,12 @@ describe( 'Styles', () => {
 					styles.setStyle( 'border-style:solid dotted;' );
 
 					expect( styles.getNormalized( 'border' ) ).to.deep.equal( {
-						top: { style: 'solid' },
-						right: { style: 'dotted' },
-						bottom: { style: 'solid' },
-						left: { style: 'dotted' }
+						style: {
+							top: 'solid',
+							right: 'dotted',
+							bottom: 'solid',
+							left: 'dotted'
+						}
 					} );
 				} );
 
@@ -186,10 +191,12 @@ describe( 'Styles', () => {
 					styles.setStyle( 'border-style:solid dotted dashed;' );
 
 					expect( styles.getNormalized( 'border' ) ).to.deep.equal( {
-						top: { style: 'solid' },
-						right: { style: 'dotted' },
-						bottom: { style: 'dashed' },
-						left: { style: 'dotted' }
+						style: {
+							top: 'solid',
+							right: 'dotted',
+							bottom: 'dashed',
+							left: 'dotted'
+						}
 					} );
 				} );
 
@@ -197,10 +204,12 @@ describe( 'Styles', () => {
 					styles.setStyle( 'border-style:solid dotted dashed ridge;' );
 
 					expect( styles.getNormalized( 'border' ) ).to.deep.equal( {
-						top: { style: 'solid' },
-						right: { style: 'dotted' },
-						bottom: { style: 'dashed' },
-						left: { style: 'ridge' }
+						style: {
+							top: 'solid',
+							right: 'dotted',
+							bottom: 'dashed',
+							left: 'ridge'
+						}
 					} );
 				} );
 			} );
@@ -210,10 +219,12 @@ describe( 'Styles', () => {
 					styles.setStyle( 'border-width:1px;' );
 
 					expect( styles.getNormalized( 'border' ) ).to.deep.equal( {
-						top: { width: '1px' },
-						right: { width: '1px' },
-						bottom: { width: '1px' },
-						left: { width: '1px' }
+						width: {
+							top: '1px',
+							right: '1px',
+							bottom: '1px',
+							left: '1px'
+						}
 					} );
 				} );
 
@@ -221,10 +232,12 @@ describe( 'Styles', () => {
 					styles.setStyle( 'border-width:1px .34cm;' );
 
 					expect( styles.getNormalized( 'border' ) ).to.deep.equal( {
-						top: { width: '1px' },
-						right: { width: '.34cm' },
-						bottom: { width: '1px' },
-						left: { width: '.34cm' }
+						width: {
+							top: '1px',
+							right: '.34cm',
+							bottom: '1px',
+							left: '.34cm'
+						}
 					} );
 				} );
 
@@ -232,10 +245,12 @@ describe( 'Styles', () => {
 					styles.setStyle( 'border-width:1px .34cm 90.1rem;' );
 
 					expect( styles.getNormalized( 'border' ) ).to.deep.equal( {
-						top: { width: '1px' },
-						right: { width: '.34cm' },
-						bottom: { width: '90.1rem' },
-						left: { width: '.34cm' }
+						width: {
+							top: '1px',
+							right: '.34cm',
+							bottom: '90.1rem',
+							left: '.34cm'
+						}
 					} );
 				} );
 
@@ -243,10 +258,12 @@ describe( 'Styles', () => {
 					styles.setStyle( 'border-width:1px .34cm 90.1rem thick;' );
 
 					expect( styles.getNormalized( 'border' ) ).to.deep.equal( {
-						top: { width: '1px' },
-						right: { width: '.34cm' },
-						bottom: { width: '90.1rem' },
-						left: { width: 'thick' }
+						width: {
+							top: '1px',
+							right: '.34cm',
+							bottom: '90.1rem',
+							left: 'thick'
+						}
 					} );
 				} );
 			} );