Browse Source

Refactor the TableSelection.getSelectionAsFragment() method.

Maciej Gołaszewski 5 years ago
parent
commit
6f17e5fe6d
1 changed files with 133 additions and 115 deletions
  1. 133 115
      packages/ckeditor5-table/src/tableselection.js

+ 133 - 115
packages/ckeditor5-table/src/tableselection.js

@@ -207,120 +207,6 @@ export default class TableSelection extends Plugin {
 	}
 
 	/**
-	 * Returns selected table fragment as a document fragment.
-	 *
-	 * @returns {module:engine/model/documentfragment~DocumentFragment|undefined}
-	 */
-	getSelectionAsFragment() {
-		if ( !this.hasMultiCellSelection ) {
-			return;
-		}
-
-		return this.editor.model.change( writer => {
-			const fragment = writer.createDocumentFragment();
-
-			const tableCopy = writer.createElement( 'table' );
-
-			writer.insert( tableCopy, fragment, 0 );
-
-			const rowsMap = new Map();
-			const columnsIndexesMap = new Map();
-
-			for ( const tableCell of this.getSelectedTableCells() ) {
-				const row = tableCell.parent;
-
-				if ( !rowsMap.has( row ) ) {
-					const newRow = row._clone();
-					writer.append( newRow, tableCopy );
-					rowsMap.set( row, newRow );
-				}
-
-				const clonedCell = tableCell._clone( true );
-				columnsIndexesMap.set( clonedCell, this._tableUtils.getCellLocation( tableCell ) );
-
-				writer.append( clonedCell, rowsMap.get( row ) );
-			}
-
-			const { row: startRow, column: startColumn } = this._tableUtils.getCellLocation( this._startElement );
-			const { row: endRow, column: endColumn } = this._tableUtils.getCellLocation( this._endElement );
-
-			const sourceTable = findAncestor( 'table', this._startElement );
-
-			// Calculate headings.
-			const headingRows = parseInt( sourceTable.getAttribute( 'headingRows' ) || 0 );
-
-			if ( headingRows > 0 ) {
-				const copiedRows = headingRows - startRow;
-				writer.setAttribute( 'headingRows', copiedRows, tableCopy );
-			}
-
-			const headingColumns = parseInt( sourceTable.getAttribute( 'headingColumns' ) || 0 );
-
-			if ( headingColumns > 0 ) {
-				const copiedColumns = headingColumns - startColumn;
-				writer.setAttribute( 'headingColumns', copiedColumns, tableCopy );
-			}
-
-			// Prepend cells.
-			for ( const row of tableCopy.getChildren() ) {
-				for ( const tableCell of Array.from( row.getChildren() ) ) {
-					const { column } = this._tableUtils.getCellLocation( tableCell );
-					const { column: originalColumn } = columnsIndexesMap.get( tableCell );
-
-					const shiftedColumn = originalColumn - startColumn;
-
-					if ( column !== shiftedColumn ) {
-						for ( let i = 0; i < shiftedColumn - column; i++ ) {
-							const prepCell = writer.createElement( 'tableCell' );
-							writer.insert( prepCell, writer.createPositionBefore( tableCell ) );
-
-							const paragraph = writer.createElement( 'paragraph' );
-
-							writer.insert( paragraph, prepCell, 0 );
-							writer.insertText( '', paragraph, 0 );
-						}
-					}
-				}
-			}
-
-			// Trim table.
-			const width = endColumn - startColumn + 1;
-			const height = endRow - startRow + 1;
-
-			for ( const row of tableCopy.getChildren() ) {
-				for ( const tableCell of row.getChildren() ) {
-					const colspan = parseInt( tableCell.getAttribute( 'colspan' ) || 1 );
-					const rowspan = parseInt( tableCell.getAttribute( 'rowspan' ) || 1 );
-
-					const { row, column } = this._tableUtils.getCellLocation( tableCell );
-
-					if ( column + colspan > width ) {
-						const newSpan = width - column;
-
-						if ( newSpan > 1 ) {
-							writer.setAttribute( 'colspan', newSpan, tableCell );
-						} else {
-							writer.removeAttribute( 'colspan', tableCell );
-						}
-					}
-
-					if ( row + rowspan > height ) {
-						const newSpan = height - row;
-
-						if ( newSpan > 1 ) {
-							writer.setAttribute( 'rowspan', newSpan, tableCell );
-						} else {
-							writer.removeAttribute( 'rowspan', tableCell );
-						}
-					}
-				}
-			}
-
-			return fragment;
-		} );
-	}
-
-	/**
 	 * Returns iterator for selected table cells.
 	 *
 	 *		tableSelection.startSelectingFrom( startTableCell );
@@ -345,7 +231,7 @@ export default class TableSelection extends Plugin {
 		const startColumn = startLocation.column > endLocation.column ? endLocation.column : startLocation.column;
 		const endColumn = startLocation.column > endLocation.column ? startLocation.column : endLocation.column;
 
-		for ( const cellInfo of new TableWalker( this._startElement.parent.parent, { startRow, endRow } ) ) {
+		for ( const cellInfo of new TableWalker( findAncestor( 'table', this._startElement ), { startRow, endRow } ) ) {
 			if ( cellInfo.column >= startColumn && cellInfo.column <= endColumn ) {
 				yield cellInfo.cell;
 			}
@@ -353,6 +239,40 @@ export default class TableSelection extends Plugin {
 	}
 
 	/**
+	 * Returns selected table fragment as a document fragment.
+	 *
+	 * @returns {module:engine/model/documentfragment~DocumentFragment|undefined}
+	 */
+	getSelectionAsFragment() {
+		if ( !this.hasMultiCellSelection ) {
+			return;
+		}
+
+		return this.editor.model.change( writer => {
+			const tableUtils = this._tableUtils;
+			const selectedTableCells = Array.from( this.getSelectedTableCells() );
+
+			const { row: startRow, column: startColumn } = tableUtils.getCellLocation( this._startElement );
+
+			const tableCopy = makeTableCopy( writer, startColumn, selectedTableCells, tableUtils );
+
+			const { row: endRow, column: endColumn } = tableUtils.getCellLocation( this._endElement );
+			const selectionWidth = endColumn - startColumn + 1;
+			const selectionHeight = endRow - startRow + 1;
+
+			trimTableCopyToSelection( tableCopy, selectionWidth, selectionHeight, writer, tableUtils );
+
+			const sourceTable = findAncestor( 'table', this._startElement );
+			updateHeadings( tableCopy, sourceTable, startRow, startColumn, writer );
+
+			const documentFragment = writer.createDocumentFragment();
+			writer.insert( tableCopy, documentFragment, 0 );
+
+			return documentFragment;
+		} );
+	}
+
+	/**
 	 * Set proper model selection for currently selected table cells.
 	 *
 	 * @private
@@ -389,3 +309,101 @@ export default class TableSelection extends Plugin {
 		}
 	}
 }
+
+function makeTableCopy( writer, startColumn, selectedTableCells, tableUtils ) {
+	const tableCopy = writer.createElement( 'table' );
+
+	const rowToCopyMap = new Map();
+	const copyToOriginalColumnMap = new Map();
+
+	for ( const tableCell of selectedTableCells ) {
+		const row = findAncestor( 'tableRow', tableCell );
+
+		if ( !rowToCopyMap.has( row ) ) {
+			const rowCopy = row._clone();
+			writer.append( rowCopy, tableCopy );
+			rowToCopyMap.set( row, rowCopy );
+		}
+
+		const tableCellCopy = tableCell._clone( true );
+		const { column } = tableUtils.getCellLocation( tableCell );
+
+		copyToOriginalColumnMap.set( tableCellCopy, column );
+
+		writer.append( tableCellCopy, rowToCopyMap.get( row ) );
+	}
+
+	addMissingTableCells( tableCopy, startColumn, copyToOriginalColumnMap, writer, tableUtils );
+
+	return tableCopy;
+}
+
+function updateHeadings( tableCopy, sourceTable, startRow, startColumn, writer ) {
+	const headingRows = parseInt( sourceTable.getAttribute( 'headingRows' ) || 0 );
+
+	if ( headingRows > 0 ) {
+		const copiedRows = headingRows - startRow;
+		writer.setAttribute( 'headingRows', copiedRows, tableCopy );
+	}
+
+	const headingColumns = parseInt( sourceTable.getAttribute( 'headingColumns' ) || 0 );
+
+	if ( headingColumns > 0 ) {
+		const copiedColumns = headingColumns - startColumn;
+		writer.setAttribute( 'headingColumns', copiedColumns, tableCopy );
+	}
+}
+
+function addMissingTableCells( tableCopy, startColumn, copyToOriginalColumnMap, writer, tableUtils ) {
+	for ( const row of tableCopy.getChildren() ) {
+		for ( const tableCell of Array.from( row.getChildren() ) ) {
+			const { column } = tableUtils.getCellLocation( tableCell );
+
+			const originalColumn = copyToOriginalColumnMap.get( tableCell );
+			const shiftedColumn = originalColumn - startColumn;
+
+			if ( column !== shiftedColumn ) {
+				for ( let i = 0; i < shiftedColumn - column; i++ ) {
+					const prepCell = writer.createElement( 'tableCell' );
+					writer.insert( prepCell, writer.createPositionBefore( tableCell ) );
+
+					const paragraph = writer.createElement( 'paragraph' );
+
+					writer.insert( paragraph, prepCell, 0 );
+					writer.insertText( '', paragraph, 0 );
+				}
+			}
+		}
+	}
+}
+
+function trimTableCopyToSelection( tableCopy, width, height, writer, tableUtils ) {
+	for ( const row of tableCopy.getChildren() ) {
+		for ( const tableCell of row.getChildren() ) {
+			const colspan = parseInt( tableCell.getAttribute( 'colspan' ) || 1 );
+			const rowspan = parseInt( tableCell.getAttribute( 'rowspan' ) || 1 );
+
+			const { row, column } = tableUtils.getCellLocation( tableCell );
+
+			if ( column + colspan > width ) {
+				const newSpan = width - column;
+
+				if ( newSpan > 1 ) {
+					writer.setAttribute( 'colspan', newSpan, tableCell );
+				} else {
+					writer.removeAttribute( 'colspan', tableCell );
+				}
+			}
+
+			if ( row + rowspan > height ) {
+				const newSpan = height - row;
+
+				if ( newSpan > 1 ) {
+					writer.setAttribute( 'rowspan', newSpan, tableCell );
+				} else {
+					writer.removeAttribute( 'rowspan', tableCell );
+				}
+			}
+		}
+	}
+}