Browse Source

Added: The `downcastAttributeChange()` conversion helper should accept `asWidget` option.

Maciej Gołaszewski 7 years ago
parent
commit
66c06d034e

+ 18 - 2
packages/ckeditor5-table/src/converters/downcast.js

@@ -150,7 +150,10 @@ export function downcastInsertCell( options = {} ) {
  *
  * @returns {Function} Conversion helper.
  */
-export function downcastAttributeChange( attribute ) {
+export function downcastAttributeChange( options ) {
+	const attribute = options.attribute;
+	const asWidget = !!options.asWidget;
+
 	return dispatcher => dispatcher.on( `attribute:${ attribute }:table`, ( evt, data, conversionApi ) => {
 		const table = data.item;
 
@@ -199,7 +202,20 @@ export function downcastAttributeChange( attribute ) {
 			// If in single change we're converting attribute changes and inserting cell the table cell might not be inserted into view
 			// because of child conversion is done after parent.
 			if ( viewCell && viewCell.name !== desiredCellElementName ) {
-				conversionApi.writer.rename( viewCell, desiredCellElementName );
+				let renamedCell;
+
+				if ( asWidget ) {
+					const editable = conversionApi.writer.createEditableElement( desiredCellElementName, viewCell.getAttributes() );
+					renamedCell = toWidgetEditable( editable, conversionApi.writer );
+
+					conversionApi.writer.insert( ViewPosition.createAfter( viewCell ), renamedCell );
+					conversionApi.writer.move( ViewRange.createIn( viewCell ), ViewPosition.createAt( renamedCell ) );
+					conversionApi.writer.remove( ViewRange.createOn( viewCell ) );
+				} else {
+					renamedCell = conversionApi.writer.rename( viewCell, desiredCellElementName );
+				}
+
+				conversionApi.mapper.bindElements( cell, renamedCell );
 			}
 		}
 

+ 10 - 5
packages/ckeditor5-table/src/converters/upcasttable.js

@@ -29,11 +29,16 @@ export default function upcastTable() {
 
 			const { rows, headingRows, headingColumns } = scanTable( viewTable );
 
-			// Nullify 0 values so they are not stored in model.
-			const attributes = {
-				headingColumns: headingColumns || null,
-				headingRows: headingRows || null
-			};
+			// Only set attributes if values is greater then 0.
+			const attributes = {};
+
+			if ( headingColumns ) {
+				attributes.headingColumns = headingColumns;
+			}
+
+			if ( headingRows ) {
+				attributes.headingRows = headingRows;
+			}
 
 			const table = conversionApi.writer.createElement( 'table', attributes );
 

+ 12 - 1
packages/ckeditor5-table/src/tableediting.js

@@ -13,7 +13,13 @@ import Range from '@ckeditor/ckeditor5-engine/src/model/range';
 import { keyCodes } from '@ckeditor/ckeditor5-utils/src/keyboard';
 
 import upcastTable from './converters/upcasttable';
-import { downcastInsertCell, downcastInsertRow, downcastInsertTable, downcastRemoveRow } from './converters/downcast';
+import {
+	downcastAttributeChange,
+	downcastInsertCell,
+	downcastInsertRow,
+	downcastInsertTable,
+	downcastRemoveRow
+} from './converters/downcast';
 import InsertTableCommand from './commands/inserttablecommand';
 import InsertRowCommand from './commands/insertrowcommand';
 import InsertColumnCommand from './commands/insertcolumncommand';
@@ -83,6 +89,11 @@ export default class TablesEditing extends Plugin {
 		conversion.attributeToAttribute( { model: 'colspan', view: 'colspan' } );
 		conversion.attributeToAttribute( { model: 'rowspan', view: 'rowspan' } );
 
+		conversion.for( 'editingDowncast' ).add( downcastAttributeChange( { attribute: 'headingRows', asWidget: true } ) );
+		conversion.for( 'dataDowncast' ).add( downcastAttributeChange( { attribute: 'headingRows' } ) );
+		conversion.for( 'editingDowncast' ).add( downcastAttributeChange( { attribute: 'headingColumns', asWidget: true } ) );
+		conversion.for( 'dataDowncast' ).add( downcastAttributeChange( { attribute: 'headingColumns' } ) );
+
 		editor.commands.add( 'insertTable', new InsertTableCommand( editor ) );
 		editor.commands.add( 'insertRow', new InsertRowCommand( editor ) );
 		editor.commands.add( 'insertColumn', new InsertColumnCommand( editor ) );

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

@@ -56,7 +56,7 @@ function makeRows( tableData, cellElement, rowElement, headingElement = 'th' ) {
  * @returns {String}
  */
 export function modelTable( tableData, attributes ) {
-	const tableRows = makeRows( tableData, 'tableCell', 'tableRow' );
+	const tableRows = makeRows( tableData, 'tableCell', 'tableRow', 'tableCell' );
 
 	return `<table${ formatAttributes( attributes ) }>${ tableRows }</table>`;
 }

+ 90 - 2
packages/ckeditor5-table/tests/converters/downcast.js

@@ -63,8 +63,8 @@ describe( 'downcast converters', () => {
 
 				conversion.for( 'downcast' ).add( downcastRemoveRow() );
 
-				conversion.for( 'downcast' ).add( downcastAttributeChange( 'headingRows' ) );
-				conversion.for( 'downcast' ).add( downcastAttributeChange( 'headingColumns' ) );
+				conversion.for( 'downcast' ).add( downcastAttributeChange( { attribute: 'headingRows' } ) );
+				conversion.for( 'downcast' ).add( downcastAttributeChange( { attribute: 'headingColumns' } ) );
 			} );
 	} );
 
@@ -886,6 +886,24 @@ describe( 'downcast converters', () => {
 			] ) );
 		} );
 
+		it( 'should work for changing heading columns to a smaller number', () => {
+			setModelData( model, modelTable( [
+				[ { isHeading: true, contents: '11' }, { isHeading: true, contents: '12' }, { isHeading: true, contents: '13' }, '14' ],
+				[ { isHeading: true, contents: '21' }, { isHeading: true, contents: '22' }, { isHeading: true, contents: '23' }, '24' ]
+			], { headingColumns: 3 } ) );
+
+			const table = root.getChild( 0 );
+
+			model.change( writer => {
+				writer.setAttribute( 'headingColumns', 1, table );
+			} );
+
+			expect( getViewData( viewDocument, { withoutSelection: true } ) ).to.equal( viewTable( [
+				[ { isHeading: true, contents: '11' }, '12', '13', '14' ],
+				[ { isHeading: true, contents: '21' }, '22', '23', '24' ]
+			], { headingColumns: 3 } ) );
+		} );
+
 		it( 'should work for removing heading columns', () => {
 			setModelData( model, modelTable( [
 				[ '11', '12' ],
@@ -958,6 +976,76 @@ describe( 'downcast converters', () => {
 				]
 			] ) );
 		} );
+
+		describe( 'asWidget', () => {
+			beforeEach( () => {
+				return VirtualTestEditor.create()
+					.then( newEditor => {
+						editor = newEditor;
+						model = editor.model;
+						doc = model.document;
+						root = doc.getRoot( 'main' );
+						viewDocument = editor.editing.view;
+
+						const conversion = editor.conversion;
+						const schema = model.schema;
+
+						schema.register( 'table', {
+							allowWhere: '$block',
+							allowAttributes: [ 'headingRows', 'headingColumns' ],
+							isBlock: true,
+							isObject: true
+						} );
+
+						schema.register( 'tableRow', {
+							allowIn: 'table',
+							allowAttributes: [],
+							isBlock: true,
+							isLimit: true
+						} );
+
+						schema.register( 'tableCell', {
+							allowIn: 'tableRow',
+							allowContentOf: '$block',
+							allowAttributes: [ 'colspan', 'rowspan' ],
+							isBlock: true,
+							isLimit: true
+						} );
+
+						conversion.for( 'downcast' ).add( downcastInsertTable( { asWidget: true } ) );
+						conversion.for( 'downcast' ).add( downcastInsertRow( { asWidget: true } ) );
+						conversion.for( 'downcast' ).add( downcastInsertCell( { asWidget: true } ) );
+
+						conversion.for( 'downcast' ).add( downcastAttributeChange( { attribute: 'headingRows', asWidget: true } ) );
+						conversion.for( 'downcast' ).add( downcastAttributeChange( { attribute: 'headingColumns', asWidget: true } ) );
+
+						conversion.attributeToAttribute( { model: 'colspan', view: 'colspan' } );
+						conversion.attributeToAttribute( { model: 'rowspan', view: 'rowspan' } );
+					} );
+			} );
+
+			it( 'should create renamed cell inside as a widget', () => {
+				setModelData( model,
+					'<table>' +
+					'<tableRow><tableCell>foo</tableCell></tableRow>' +
+					'</table>'
+				);
+
+				const table = root.getChild( 0 );
+
+				model.change( writer => {
+					writer.setAttribute( 'headingColumns', 1, table );
+				} );
+
+				expect( getViewData( viewDocument, { withoutSelection: true } ) ).to.equal(
+					'<table class="ck-widget" contenteditable="false">' +
+					'<tbody>' +
+					'<tr><th class="ck-editor__editable ck-editor__nested-editable" contenteditable="true">foo</th></tr>' +
+					'</tbody>' +
+					'</table>'
+				);
+			} );
+		} );
 	} );
 
 	describe( 'downcastRemoveRow()', () => {