Procházet zdrojové kódy

Merge pull request #258 from ckeditor/i/6125

Other: Added a possibility to insert column or row with multiple selected cells. Closes ckeditor/ckeditor5#6125.
Piotrek Koszuliński před 5 roky
rodič
revize
5ac9088e00

+ 6 - 5
packages/ckeditor5-table/src/commands/insertcolumncommand.js

@@ -8,7 +8,7 @@
  */
 
 import Command from '@ckeditor/ckeditor5-core/src/command';
-import { findAncestor } from './utils';
+import { getRangeContainedElement, findAncestor } from './utils';
 
 /**
  * The insert column command.
@@ -70,15 +70,16 @@ export default class InsertColumnCommand extends Command {
 		const editor = this.editor;
 		const selection = editor.model.document.selection;
 		const tableUtils = editor.plugins.get( 'TableUtils' );
+		const insertBefore = this.order === 'left';
 
-		const firstPosition = selection.getFirstPosition();
+		const referencePosition = insertBefore ? selection.getFirstPosition() : selection.getLastPosition();
+		const referenceRange = insertBefore ? selection.getFirstRange() : selection.getLastRange();
 
-		const tableCell = findAncestor( 'tableCell', firstPosition );
+		const tableCell = getRangeContainedElement( referenceRange ) || findAncestor( 'tableCell', referencePosition );
 		const table = tableCell.parent.parent;
 
 		const { column } = tableUtils.getCellLocation( tableCell );
-		const insertAt = this.order === 'right' ? column + 1 : column;
 
-		tableUtils.insertColumns( table, { columns: 1, at: insertAt } );
+		tableUtils.insertColumns( table, { columns: 1, at: insertBefore ? column : column + 1 } );
 	}
 }

+ 7 - 4
packages/ckeditor5-table/src/commands/insertrowcommand.js

@@ -8,7 +8,7 @@
  */
 
 import Command from '@ckeditor/ckeditor5-core/src/command';
-import { findAncestor } from './utils';
+import { getRangeContainedElement, findAncestor } from './utils';
 
 /**
  * The insert row command.
@@ -69,14 +69,17 @@ export default class InsertRowCommand extends Command {
 		const editor = this.editor;
 		const selection = editor.model.document.selection;
 		const tableUtils = editor.plugins.get( 'TableUtils' );
+		const insertAbove = this.order === 'above';
 
-		const tableCell = findAncestor( 'tableCell', selection.getFirstPosition() );
+		const referencePosition = insertAbove ? selection.getFirstPosition() : selection.getLastPosition();
+		const referenceRange = insertAbove ? selection.getFirstRange() : selection.getLastRange();
+
+		const tableCell = getRangeContainedElement( referenceRange ) || findAncestor( 'tableCell', referencePosition );
 		const tableRow = tableCell.parent;
 		const table = tableRow.parent;
 
 		const row = table.getChildIndex( tableRow );
-		const insertAt = this.order === 'below' ? row + 1 : row;
 
-		tableUtils.insertRows( table, { rows: 1, at: insertAt } );
+		tableUtils.insertRows( table, { rows: 1, at: this.order === 'below' ? row + 1 : row } );
 	}
 }

+ 13 - 0
packages/ckeditor5-table/src/commands/utils.js

@@ -30,6 +30,19 @@ export function findAncestor( parentName, positionOrElement ) {
 }
 
 /**
+ * Returns an element contained by a range, if it's the only one element contained by the range and if it's fully contained.
+ *
+ * @param {module:engine/model/range~Range} range
+ * @returns {module:engine/model/element~Element|null}
+ */
+export function getRangeContainedElement( range ) {
+	const nodeAfterStart = range.start.nodeAfter;
+	const nodeBeforeEnd = range.end.nodeBefore;
+
+	return ( nodeAfterStart && nodeAfterStart.is( 'element' ) && nodeAfterStart == nodeBeforeEnd ) ? nodeAfterStart : null;
+}
+
+/**
  * A common method to update the numeric value. If a value is the default one, it will be unset.
  *
  * @param {String} key An attribute key.

+ 54 - 3
packages/ckeditor5-table/tests/commands/insertcolumncommand.js

@@ -7,7 +7,8 @@ import ModelTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/modeltestedit
 import { getData, setData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model';
 
 import InsertColumnCommand from '../../src/commands/insertcolumncommand';
-import { defaultConversion, defaultSchema, modelTable } from '../_utils/utils';
+import TableSelection from '../../src/tableselection';
+import { assertSelectedCells, defaultConversion, defaultSchema, modelTable } from '../_utils/utils';
 import TableUtils from '../../src/tableutils';
 import { assertEqualMarkup } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
 
@@ -17,7 +18,7 @@ describe( 'InsertColumnCommand', () => {
 	beforeEach( () => {
 		return ModelTestEditor
 			.create( {
-				plugins: [ TableUtils ]
+				plugins: [ TableUtils, TableSelection ]
 			} )
 			.then( newEditor => {
 				editor = newEditor;
@@ -76,7 +77,7 @@ describe( 'InsertColumnCommand', () => {
 				] ) );
 			} );
 
-			it( 'should insert columns at table end', () => {
+			it( 'should insert column at table end', () => {
 				setData( model, modelTable( [
 					[ '11', '12' ],
 					[ '21', '22[]' ]
@@ -90,6 +91,31 @@ describe( 'InsertColumnCommand', () => {
 				] ) );
 			} );
 
+			it( 'should insert column after a multi column selection', () => {
+				setData( model, modelTable( [
+					[ '11', '12', '13' ],
+					[ '21', '22', '23' ]
+				] ) );
+
+				const tableSelection = editor.plugins.get( TableSelection );
+				const modelRoot = model.document.getRoot();
+
+				tableSelection.startSelectingFrom( modelRoot.getNodeByPath( [ 0, 0, 0 ] ) );
+				tableSelection.setSelectingTo( modelRoot.getNodeByPath( [ 0, 1, 1 ] ) );
+
+				command.execute();
+
+				assertEqualMarkup( getData( model, { withoutSelection: true } ), modelTable( [
+					[ '11', '12', '', '13' ],
+					[ '21', '22', '', '23' ]
+				] ) );
+
+				assertSelectedCells( model, [
+					[ 1, 1, 0, 0 ],
+					[ 1, 1, 0, 0 ]
+				] );
+			} );
+
 			it( 'should update table heading columns attribute when inserting column in headings section', () => {
 				setData( model, modelTable( [
 					[ '11[]', '12' ],
@@ -214,6 +240,31 @@ describe( 'InsertColumnCommand', () => {
 				] ) );
 			} );
 
+			it( 'should insert column before a multi column selection', () => {
+				setData( model, modelTable( [
+					[ '11', '12', '13' ],
+					[ '21', '22', '23' ]
+				] ) );
+
+				const tableSelection = editor.plugins.get( TableSelection );
+				const modelRoot = model.document.getRoot();
+
+				tableSelection.startSelectingFrom( modelRoot.getNodeByPath( [ 0, 0, 0 ] ) );
+				tableSelection.setSelectingTo( modelRoot.getNodeByPath( [ 0, 1, 1 ] ) );
+
+				command.execute();
+
+				assertEqualMarkup( getData( model, { withoutSelection: true } ), modelTable( [
+					[ '', '11', '12', '13' ],
+					[ '', '21', '22', '23' ]
+				] ) );
+
+				assertSelectedCells( model, [
+					[ 0, 1, 1, 0 ],
+					[ 0, 1, 1, 0 ]
+				] );
+			} );
+
 			it( 'should update table heading columns attribute when inserting column in headings section', () => {
 				setData( model, modelTable( [
 					[ '11', '12[]' ],

+ 63 - 2
packages/ckeditor5-table/tests/commands/insertrowcommand.js

@@ -7,7 +7,8 @@ import ModelTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/modeltestedit
 import { getData, setData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model';
 
 import InsertRowCommand from '../../src/commands/insertrowcommand';
-import { defaultConversion, defaultSchema, modelTable } from '../_utils/utils';
+import TableSelection from '../../src/tableselection';
+import { assertSelectedCells, defaultConversion, defaultSchema, modelTable } from '../_utils/utils';
 import TableUtils from '../../src/tableutils';
 import { assertEqualMarkup } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
 
@@ -17,7 +18,7 @@ describe( 'InsertRowCommand', () => {
 	beforeEach( () => {
 		return ModelTestEditor
 			.create( {
-				plugins: [ TableUtils ]
+				plugins: [ TableUtils, TableSelection ]
 			} )
 			.then( newEditor => {
 				editor = newEditor;
@@ -181,6 +182,36 @@ describe( 'InsertRowCommand', () => {
 					[ '', '' ]
 				] ) );
 			} );
+
+			it( 'should insert a row when multiple rows are selected', () => {
+				setData( model, modelTable( [
+					[ '11', '12' ],
+					[ '21', '22' ],
+					[ '31', '32' ]
+				] ) );
+
+				const tableSelection = editor.plugins.get( TableSelection );
+				const modelRoot = model.document.getRoot();
+
+				tableSelection.startSelectingFrom( modelRoot.getNodeByPath( [ 0, 0, 0 ] ) );
+				tableSelection.setSelectingTo( modelRoot.getNodeByPath( [ 0, 1, 1 ] ) );
+
+				command.execute();
+
+				assertEqualMarkup( getData( model, { withoutSelection: true } ), modelTable( [
+					[ '11', '12' ],
+					[ '21', '22' ],
+					[ '', '' ],
+					[ '31', '32' ]
+				] ) );
+
+				assertSelectedCells( model, [
+					[ 1, 1 ],
+					[ 1, 1 ],
+					[ 0, 0 ],
+					[ 0, 0 ]
+				] );
+			} );
 		} );
 	} );
 
@@ -284,6 +315,36 @@ describe( 'InsertRowCommand', () => {
 					[ '20[]', '21' ]
 				], { headingRows: 2 } ) );
 			} );
+
+			it( 'should insert a row when multiple rows are selected', () => {
+				setData( model, modelTable( [
+					[ '11', '12' ],
+					[ '21', '22' ],
+					[ '31', '32' ]
+				] ) );
+
+				const tableSelection = editor.plugins.get( TableSelection );
+				const modelRoot = model.document.getRoot();
+
+				tableSelection.startSelectingFrom( modelRoot.getNodeByPath( [ 0, 0, 0 ] ) );
+				tableSelection.setSelectingTo( modelRoot.getNodeByPath( [ 0, 1, 1 ] ) );
+
+				command.execute();
+
+				assertEqualMarkup( getData( model, { withoutSelection: true } ), modelTable( [
+					[ '', '' ],
+					[ '11', '12' ],
+					[ '21', '22' ],
+					[ '31', '32' ]
+				] ) );
+
+				assertSelectedCells( model, [
+					[ 0, 0 ],
+					[ 1, 1 ],
+					[ 1, 1 ],
+					[ 0, 0 ]
+				] );
+			} );
 		} );
 	} );
 } );