瀏覽代碼

Introducing removeEmptyRows, removeEmptyColumns and removeEmptyRowsColumns functions.

Kuba Niegowski 5 年之前
父節點
當前提交
b5bd857bc6

+ 3 - 14
packages/ckeditor5-table/src/commands/mergecellcommand.js

@@ -11,7 +11,7 @@ import Command from '@ckeditor/ckeditor5-core/src/command';
 import TableWalker from '../tablewalker';
 import { getTableCellsContainingSelection } from '../utils/selection';
 import { findAncestor, isHeadingColumnCell } from '../utils/common';
-import { getEmptyColumnsIndexes } from '../utils/structure';
+import { removeEmptyRowsColumns } from '../utils/structure';
 
 /**
  * The merge cell command.
@@ -108,19 +108,8 @@ export default class MergeCellCommand extends Command {
 			const tableUtils = this.editor.plugins.get( 'TableUtils' );
 			const table = findAncestor( 'table', removedTableCellRow );
 
-			// Remove empty row after merging.
-			if ( !removedTableCellRow.childCount ) {
-				tableUtils.removeRows( table, { at: removedTableCellRow.index, batch: writer.batch } );
-			} else {
-				// If there were some rows removed then empty columns were already verified.
-				const emptyColumnsIndexes = getEmptyColumnsIndexes( table );
-
-				if ( emptyColumnsIndexes.length ) {
-					emptyColumnsIndexes.reverse().forEach( column => {
-						tableUtils.removeColumns( table, { at: column, batch: writer.batch } );
-					} );
-				}
-			}
+			// Remove empty rows and columns after merging.
+			removeEmptyRowsColumns( table, tableUtils, writer.batch );
 		} );
 	}
 

+ 3 - 23
packages/ckeditor5-table/src/commands/mergecellscommand.js

@@ -11,7 +11,7 @@ import Command from '@ckeditor/ckeditor5-core/src/command';
 import TableUtils from '../tableutils';
 import { getSelectedTableCells, isSelectionRectangular } from '../utils/selection';
 import { findAncestor, updateNumericAttribute } from '../utils/common';
-import { getEmptyColumnsIndexes } from '../utils/structure';
+import { removeEmptyRowsColumns } from '../utils/structure';
 
 /**
  * The merge cells command.
@@ -58,34 +58,14 @@ export default class MergeCellsCommand extends Command {
 			updateNumericAttribute( 'colspan', mergeWidth, firstTableCell, writer );
 			updateNumericAttribute( 'rowspan', mergeHeight, firstTableCell, writer );
 
-			const emptyRowsIndexes = [];
-
 			for ( const tableCell of selectedTableCells ) {
-				const tableRow = tableCell.parent;
-
 				mergeTableCells( tableCell, firstTableCell, writer );
-
-				if ( !tableRow.childCount ) {
-					emptyRowsIndexes.push( tableRow.index );
-				}
 			}
 
 			const table = findAncestor( 'table', firstTableCell );
 
-			if ( emptyRowsIndexes.length ) {
-				emptyRowsIndexes.reverse().forEach( row => {
-					tableUtils.removeRows( table, { at: row, batch: writer.batch } );
-				} );
-			} else {
-				// If there were some rows removed then empty columns were already verified.
-				const emptyColumnsIndexes = getEmptyColumnsIndexes( table );
-
-				if ( emptyColumnsIndexes.length ) {
-					emptyColumnsIndexes.reverse().forEach( column => {
-						tableUtils.removeColumns( table, { at: column, batch: writer.batch } );
-					} );
-				}
-			}
+			// Remove rows and columns that become empty (have no anchored cells).
+			removeEmptyRowsColumns( table, tableUtils, writer.batch );
 
 			writer.setSelection( firstTableCell, 'in' );
 		} );

+ 5 - 22
packages/ckeditor5-table/src/tableutils.js

@@ -11,7 +11,7 @@ import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
 
 import TableWalker from './tablewalker';
 import { createEmptyTableCell, updateNumericAttribute } from './utils/common';
-import { getEmptyColumnsIndexes } from './utils/structure';
+import { removeEmptyColumns, removeEmptyRows } from './utils/structure';
 
 /**
  * The table utilities plugin.
@@ -337,14 +337,8 @@ export default class TableUtils extends Plugin {
 				updateNumericAttribute( 'rowspan', rowspan, cell, writer );
 			}
 
-			// 2d. Check if there are any empty columns (no anchored cells).
-			const emptyColumnsIndexes = getEmptyColumnsIndexes( table );
-
-			if ( emptyColumnsIndexes.length ) {
-				emptyColumnsIndexes.reverse().forEach( column => {
-					this.removeColumns( table, { at: column, batch: writer.batch } );
-				} );
-			}
+			// 2d. Remove empty columns (without anchored cells) if there are any.
+			removeEmptyColumns( table, this );
 
 			// 2e. Adjust heading rows if removed rows were in a heading section.
 			updateHeadingRows( table, first, last, model, batch );
@@ -389,31 +383,20 @@ export default class TableUtils extends Plugin {
 		model.change( writer => {
 			adjustHeadingColumns( table, { first, last }, writer );
 
-			const emptyRowsIndexes = [];
-
 			for ( let removedColumnIndex = last; removedColumnIndex >= first; removedColumnIndex-- ) {
 				for ( const { cell, column, cellWidth } of [ ...new TableWalker( table ) ] ) {
 					// If colspaned cell overlaps removed column decrease its span.
 					if ( column <= removedColumnIndex && cellWidth > 1 && column + cellWidth > removedColumnIndex ) {
 						updateNumericAttribute( 'colspan', cellWidth - 1, cell, writer );
 					} else if ( column === removedColumnIndex ) {
-						const cellRow = cell.parent;
-
 						// The cell in removed column has colspan of 1.
 						writer.remove( cell );
-
-						// If the cell was the last one in the row, get rid of the entire row.
-						// https://github.com/ckeditor/ckeditor5/issues/6429
-						if ( !cellRow.childCount ) {
-							emptyRowsIndexes.push( cellRow.index );
-						}
 					}
 				}
 			}
 
-			emptyRowsIndexes.reverse().forEach( row => {
-				this.removeRows( table, { at: row, batch: writer.batch } );
-			} );
+			// Remove empty rows that could appear after removing columns.
+			removeEmptyRows( table, this, writer.batch );
 		} );
 	}
 

+ 100 - 13
packages/ckeditor5-table/src/utils/structure.js

@@ -307,9 +307,9 @@ function addHeadingsToCroppedTable( croppedTable, sourceTable, startRow, startCo
 }
 
 /**
- * Returns array of column indexes that have no cells anchored.
+ * Removes columns that have no cells anchored.
  *
- * For this table:
+ * In table below:
  *
  *     +----+----+----+----+----+----+----+
  *     | 00 | 01      | 03 | 04      | 06 |
@@ -320,21 +320,108 @@ function addHeadingsToCroppedTable( croppedTable, sourceTable, startRow, startCo
  *     +----+----+----+----+----+----+----+
  *                  ^--- empty ---^
  *
- * Will return: [ 2, 5 ]
+ * Will remove columns 2 and 5.
+ *
+ * @param {module:engine/model/element~Element} table
+ * @param {module:table/tableutils~TableUtils} tableUtils
+ * @return {Boolean} True if removed some columns.
  */
-export function getEmptyColumnsIndexes( table ) {
-	const tableMap = Array.from( new TableWalker( table, { includeAllSlots: true } ) );
-	const lastColumn = tableMap[ tableMap.length - 1 ].column;
-
-	const columns = new Array( lastColumn + 1 ).fill( 0 );
+export function removeEmptyColumns( table, tableUtils ) {
+	const width = tableUtils.getColumns( table );
+	const columnsMap = new Array( width ).fill( 0 );
 
-	for ( const { column, isAnchor } of tableMap ) {
-		if ( isAnchor ) {
-			columns[ column ]++;
-		}
+	for ( const { column } of new TableWalker( table ) ) {
+		columnsMap[ column ]++;
 	}
 
-	return columns.reduce( ( result, cellsCount, column ) => {
+	const emptyColumns = columnsMap.reduce( ( result, cellsCount, column ) => {
 		return cellsCount ? result : [ ...result, column ];
 	}, [] );
+
+	// @if CK_DEBUG_TABLE // emptyColumns.length > 0 && console.log( `Removing empty columns: ${ emptyColumns.join( ', ' ) }.` );
+
+	emptyColumns.reverse().forEach( column => {
+		tableUtils.removeColumns( table, { at: column } );
+	} );
+
+	return emptyColumns.length > 0;
+}
+
+/**
+ * Removes rows that have no cells anchored.
+ *
+ * In table below:
+ *
+ *     +----+----+----+
+ *     | 00 | 01 | 02 |
+ *     +----+----+----+
+ *     | 10 | 11 | 12 |
+ *     +    +    +    +
+ *     |    |    |    | <-- empty
+ *     +----+----+----+
+ *     | 30 | 31 | 32 |
+ *     +----+----+----+
+ *     | 40      | 42 |
+ *     +         +    +
+ *     |         |    | <-- empty
+ *     +----+----+----+
+ *     | 60 | 61 | 62 |
+ *     +----+----+----+
+ *
+ * Will remove rows 2 and 5.
+ *
+ * @param {module:engine/model/element~Element} table
+ * @param {module:table/tableutils~TableUtils} tableUtils
+ * @param {module:engine/model/batch~Batch|null} [batch] Batch that should be used for removing empty rows.
+ * @return {Boolean} True if removed some rows.
+ */
+export function removeEmptyRows( table, tableUtils, batch ) {
+	const emptyRows = [];
+
+	for ( let rowIndex = 0; rowIndex < table.childCount; rowIndex++ ) {
+		const tableRow = table.getChild( rowIndex );
+
+		if ( tableRow.isEmpty ) {
+			emptyRows.push( rowIndex );
+		}
+	}
+
+	// @if CK_DEBUG_TABLE // emptyRows.length > 0 && console.log( `Removing empty rows: ${ emptyRows.join( ', ' ) }.` );
+
+	emptyRows.reverse().forEach( row => {
+		tableUtils.removeRows( table, { at: row, batch } );
+	} );
+
+	return emptyRows.length > 0;
+}
+
+/**
+ * Removes rows and columns that have no cells anchored.
+ *
+ * In table below:
+ *
+ *     +----+----+----+----+
+ *     | 00      | 02      |
+ *     +----+----+         +
+ *     | 10      |         |
+ *     +----+----+----+----+
+ *     | 20      | 22 | 23 |
+ *     +         +    +    +
+ *     |         |    |    | <-- empty row
+ *     +----+----+----+----+
+ *             ^--- empty column
+ *
+ * Will remove row 3 and column 1.
+ *
+ * @param {module:engine/model/element~Element} table
+ * @param {module:table/tableutils~TableUtils} tableUtils
+ * @param {module:engine/model/batch~Batch|null} [batch] Batch that should be used for removing empty rows.
+ */
+export function removeEmptyRowsColumns( table, tableUtils, batch ) {
+	const removedColumns = removeEmptyColumns( table, tableUtils );
+
+	// If there was some columns removed then cleaning empty rows was already triggered.
+	if ( !removedColumns ) {
+		removeEmptyRows( table, tableUtils, batch );
+	}
 }