Przeglądaj źródła

Add support for vertical table alignment.

Maciej Gołaszewski 6 lat temu
rodzic
commit
2c58455579

+ 86 - 4
packages/ckeditor5-table/src/tableproperites.js

@@ -31,7 +31,14 @@ export default class TableProperties extends Plugin {
 		const schema = editor.model.schema;
 		const conversion = editor.conversion;
 
-		// Border
+		this.enableBorderProperty( schema, conversion );
+		this.enableBackgroundColorProperty( schema, conversion );
+		this.enableWidthProperty( schema, conversion );
+		this.enableHeightProperty( schema, conversion );
+		this.enableAlignmentProperty( schema, conversion );
+	}
+
+	enableBorderProperty( schema, conversion ) {
 		schema.extend( 'table', {
 			allowAttributes: [ 'borderWidth', 'borderColor', 'borderStyle' ]
 		} );
@@ -39,26 +46,101 @@ export default class TableProperties extends Plugin {
 		downcastTableAttribute( conversion, 'borderColor', 'border-color' );
 		downcastTableAttribute( conversion, 'borderStyle', 'border-style' );
 		downcastTableAttribute( conversion, 'borderWidth', 'border-width' );
+	}
 
-		// Background
+	enableBackgroundColorProperty( schema, conversion ) {
 		schema.extend( 'table', {
 			allowAttributes: [ 'backgroundColor' ]
 		} );
 		upcastAttribute( conversion, 'table', 'backgroundColor', 'background-color' );
 		downcastTableAttribute( conversion, 'backgroundColor', 'background-color' );
+	}
 
-		// Width
+	enableWidthProperty( schema, conversion ) {
 		schema.extend( 'table', {
 			allowAttributes: [ 'width' ]
 		} );
 		upcastAttribute( conversion, 'table', 'width', 'width' );
 		downcastTableAttribute( conversion, 'width', 'width' );
+	}
 
-		// Height
+	enableHeightProperty( schema, conversion ) {
 		schema.extend( 'table', {
 			allowAttributes: [ 'height' ]
 		} );
 		upcastAttribute( conversion, 'table', 'height', 'height' );
 		downcastTableAttribute( conversion, 'height', 'height' );
 	}
+
+	enableAlignmentProperty( schema, conversion ) {
+		schema.extend( 'table', {
+			allowAttributes: [ 'alignment' ]
+		} );
+		conversion.for( 'upcast' )
+			.attributeToAttribute( {
+				view: {
+					styles: {
+						'margin-right': /^(auto|0(%|[a-z]{2,4})?)$/,
+						'margin-left': /^(auto|0)/
+					}
+				},
+				model: {
+					name: 'table',
+					key: 'alignment',
+					value: viewElement => {
+						// At this point we only have auto or 0 value (with a unit).
+						if ( viewElement.getStyle( 'margin-right' ) != 'auto' ) {
+							return 'right';
+						}
+
+						if ( viewElement.getStyle( 'margin-left' ) != 'auto' ) {
+							return 'left';
+						}
+
+						return 'center';
+					}
+				}
+			} )
+			// Support for backwards compatibility and pasting from other sources.
+			.attributeToAttribute( {
+				view: {
+					attributes: {
+						align: /^(left|right|center)$/
+					}
+				},
+				model: {
+					name: 'table',
+					key: 'alignment',
+					value: viewElement => viewElement.getAttribute( 'align' )
+				}
+			} );
+		conversion.for( 'downcast' ).add( dispatcher => dispatcher.on( 'attribute:alignment:table', ( evt, data, conversionApi ) => {
+			const { item, attributeNewValue } = data;
+			const { mapper, writer } = conversionApi;
+
+			const table = [ ...mapper.toViewElement( item ).getChildren() ].find( child => child.is( 'table' ) );
+
+			if ( !attributeNewValue ) {
+				writer.removeStyle( 'margin-left', table );
+				writer.removeStyle( 'margin-right', table );
+
+				return;
+			}
+
+			const styles = {
+				'margin-right': 'auto',
+				'margin-left': 'auto'
+			};
+
+			if ( attributeNewValue == 'left' ) {
+				styles[ 'margin-left' ] = '0';
+			}
+
+			if ( attributeNewValue == 'right' ) {
+				styles[ 'margin-right' ] = '0';
+			}
+
+			writer.setStyle( styles, table );
+		} ) );
+	}
 }

+ 3 - 1
packages/ckeditor5-table/tests/_utils/utils.js

@@ -235,8 +235,10 @@ export function assertTRBLAttribute( element, key, top, right = top, bottom = to
  * @param {String} tableStyle A style to assert on table.
  */
 export function assertTableStyle( editor, tableStyle ) {
+	const styleEntry = tableStyle ? ` style="${ tableStyle }"` : '';
+
 	assertEqualMarkup( editor.getData(),
-		`<figure class="table"><table style="${ tableStyle }"><tbody><tr><td>foo</td></tr></tbody></table></figure>`
+		`<figure class="table"><table${ styleEntry }><tbody><tr><td>foo</td></tr></tbody></table></figure>`
 	);
 }
 

+ 124 - 0
packages/ckeditor5-table/tests/tableproperties.js

@@ -529,6 +529,130 @@ describe( 'TableProperties', () => {
 		} );
 	} );
 
+	describe( 'alignment', () => {
+		it( 'should set proper schema rules', () => {
+			expect( model.schema.checkAttribute( [ '$root', 'table' ], 'alignment' ) ).to.be.true;
+		} );
+
+		describe( 'upcast conversion', () => {
+			it( 'should upcast style="margin-left:auto;margin-right:0" to right value', () => {
+				editor.setData( '<table style="margin-left:auto;margin-right:0"><tr><td>foo</td></tr></table>' );
+				const table = model.document.getRoot().getNodeByPath( [ 0 ] );
+
+				expect( table.getAttribute( 'alignment' ) ).to.equal( 'right' );
+			} );
+
+			it( 'should upcast style="margin-left:0;margin-right:auto" to left value', () => {
+				editor.setData( '<table style="margin-left:0;margin-right:auto"><tr><td>foo</td></tr></table>' );
+				const table = model.document.getRoot().getNodeByPath( [ 0 ] );
+
+				expect( table.getAttribute( 'alignment' ) ).to.equal( 'left' );
+			} );
+
+			it( 'should upcast style="margin-left:auto;margin-right:auto" to center value', () => {
+				editor.setData( '<table style="margin-left:auto;margin-right:auto"><tr><td>foo</td></tr></table>' );
+				const table = model.document.getRoot().getNodeByPath( [ 0 ] );
+
+				expect( table.getAttribute( 'alignment' ) ).to.equal( 'center' );
+			} );
+
+			it( 'should upcast style="margin-left:auto;margin-right:0pt" to right value', () => {
+				editor.setData( '<table style="margin-left:auto;margin-right:0pt"><tr><td>foo</td></tr></table>' );
+				const table = model.document.getRoot().getNodeByPath( [ 0 ] );
+
+				expect( table.getAttribute( 'alignment' ) ).to.equal( 'right' );
+			} );
+
+			it( 'should upcast style="margin-left:auto;margin-right:0%" to right value', () => {
+				editor.setData( '<table style="margin-left:auto;margin-right:0%"><tr><td>foo</td></tr></table>' );
+				const table = model.document.getRoot().getNodeByPath( [ 0 ] );
+
+				expect( table.getAttribute( 'alignment' ) ).to.equal( 'right' );
+			} );
+
+			it( 'should not upcast style="margin-left:auto;margin-right:0.23pt" to right value', () => {
+				editor.setData( '<table style="margin-left:auto;margin-right:0.23pt"><tr><td>foo</td></tr></table>' );
+				const table = model.document.getRoot().getNodeByPath( [ 0 ] );
+
+				expect( table.hasAttribute( 'alignment' ) ).to.be.false;
+			} );
+
+			it( 'should upcast align=right attribute', () => {
+				editor.setData( '<table align="right"><tr><td>foo</td></tr></table>' );
+				const table = model.document.getRoot().getNodeByPath( [ 0 ] );
+
+				expect( table.getAttribute( 'alignment' ) ).to.equal( 'right' );
+			} );
+
+			it( 'should upcast align=left attribute', () => {
+				editor.setData( '<table align="left"><tr><td>foo</td></tr></table>' );
+				const table = model.document.getRoot().getNodeByPath( [ 0 ] );
+
+				expect( table.getAttribute( 'alignment' ) ).to.equal( 'left' );
+			} );
+
+			it( 'should upcast align=center attribute', () => {
+				editor.setData( '<table align="center"><tr><td>foo</td></tr></table>' );
+				const table = model.document.getRoot().getNodeByPath( [ 0 ] );
+
+				expect( table.getAttribute( 'alignment' ) ).to.equal( 'center' );
+			} );
+
+			it( 'should discard align=justify attribute', () => {
+				editor.setData( '<table align="justify"><tr><td>foo</td></tr></table>' );
+				const table = model.document.getRoot().getNodeByPath( [ 0 ] );
+
+				expect( table.hasAttribute( 'alignment' ) ).to.be.false;
+			} );
+		} );
+
+		describe( 'downcast conversion', () => {
+			let table;
+
+			beforeEach( () => {
+				table = createEmptyTable();
+			} );
+
+			it( 'should downcast right alignment', () => {
+				model.change( writer => writer.setAttribute( 'alignment', 'right', table ) );
+
+				assertTableStyle( editor, 'margin-right:0;margin-left:auto;' );
+			} );
+
+			it( 'should downcast left alignment', () => {
+				model.change( writer => writer.setAttribute( 'alignment', 'left', table ) );
+
+				assertTableStyle( editor, 'margin-right:auto;margin-left:0;' );
+			} );
+
+			it( 'should downcast centered alignment', () => {
+				model.change( writer => writer.setAttribute( 'alignment', 'center', table ) );
+
+				assertTableStyle( editor, 'margin-right:auto;margin-left:auto;' );
+			} );
+
+			it( 'should downcast changed alignment', () => {
+				model.change( writer => writer.setAttribute( 'alignment', 'center', table ) );
+
+				assertTableStyle( editor, 'margin-right:auto;margin-left:auto;' );
+
+				model.change( writer => writer.setAttribute( 'alignment', 'right', table ) );
+
+				assertTableStyle( editor, 'margin-right:0;margin-left:auto;' );
+			} );
+
+			it( 'should downcast removed alignment', () => {
+				model.change( writer => writer.setAttribute( 'alignment', 'center', table ) );
+
+				assertTableStyle( editor, 'margin-right:auto;margin-left:auto;' );
+
+				model.change( writer => writer.removeAttribute( 'alignment', table ) );
+
+				assertTableStyle( editor );
+			} );
+		} );
+	} );
+
 	function createEmptyTable() {
 		setModelData(
 			model,