Skip to content

Commit

Permalink
Merge pull request #7226 from ckeditor/i/6122-table-paste-spans
Browse files Browse the repository at this point in the history
Internal (table): Handle spanned table cells in pasting scenarios. Closes #6122.

Fix (table): Setting column as header will now split col-spanned cells. Closes #6658.
  • Loading branch information
niegowski committed May 20, 2020
2 parents de7b021 + b6e540f commit 9531af4
Show file tree
Hide file tree
Showing 8 changed files with 1,619 additions and 210 deletions.
15 changes: 12 additions & 3 deletions packages/ckeditor5-table/src/commands/setheadercolumncommand.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import Command from '@ckeditor/ckeditor5-core/src/command';

import { findAncestor, isHeadingColumnCell, updateNumericAttribute } from './utils';
import { getColumnIndexes, getSelectionAffectedTableCells } from '../utils';
import { getColumnIndexes, getSelectionAffectedTableCells, getHorizontallyOverlappingCells, splitVertically } from '../utils';

/**
* The header column command.
Expand Down Expand Up @@ -69,12 +69,21 @@ export default class SetHeaderColumnCommand extends Command {

const model = this.editor.model;
const selectedCells = getSelectionAffectedTableCells( model.document.selection );
const { first, last } = getColumnIndexes( selectedCells );
const table = findAncestor( 'table', selectedCells[ 0 ] );

const { first, last } = getColumnIndexes( selectedCells );
const headingColumnsToSet = this.value ? first : last + 1;

model.change( writer => {
const table = findAncestor( 'table', selectedCells[ 0 ] );
if ( headingColumnsToSet ) {
// Changing heading columns requires to check if any of a heading cell is overlapping horizontally the table head.
// Any table cell that has a colspan attribute > 1 will not exceed the table head so we need to fix it in columns before.
const overlappingCells = getHorizontallyOverlappingCells( table, headingColumnsToSet );

for ( const { cell, column } of overlappingCells ) {
splitVertically( cell, column, headingColumnsToSet, writer );
}
}

updateNumericAttribute( 'headingColumns', headingColumnsToSet, table, writer, 0 );
} );
Expand Down
84 changes: 5 additions & 79 deletions packages/ckeditor5-table/src/commands/setheaderrowcommand.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,8 @@

import Command from '@ckeditor/ckeditor5-core/src/command';

import { createEmptyTableCell, findAncestor, updateNumericAttribute } from './utils';
import { getRowIndexes, getSelectionAffectedTableCells } from '../utils';
import TableWalker from '../tablewalker';
import { findAncestor, updateNumericAttribute } from './utils';
import { getVerticallyOverlappingCells, getRowIndexes, getSelectionAffectedTableCells, splitHorizontally } from '../utils';

/**
* The header row command.
Expand Down Expand Up @@ -77,9 +76,10 @@ export default class SetHeaderRowCommand extends Command {
if ( headingRowsToSet ) {
// Changing heading rows requires to check if any of a heading cell is overlapping vertically the table head.
// Any table cell that has a rowspan attribute > 1 will not exceed the table head so we need to fix it in rows below.
const cellsToSplit = getOverlappingCells( table, headingRowsToSet, currentHeadingRows );
const startRow = headingRowsToSet > currentHeadingRows ? currentHeadingRows : 0;
const overlappingCells = getVerticallyOverlappingCells( table, headingRowsToSet, startRow );

for ( const cell of cellsToSplit ) {
for ( const { cell } of overlappingCells ) {
splitHorizontally( cell, headingRowsToSet, writer );
}
}
Expand All @@ -102,77 +102,3 @@ export default class SetHeaderRowCommand extends Command {
return !!headingRows && tableCell.parent.index < headingRows;
}
}

// Returns cells that span beyond the new heading section.
//
// @param {module:engine/model/element~Element} table The table to check.
// @param {Number} headingRowsToSet New heading rows attribute.
// @param {Number} currentHeadingRows Current heading rows attribute.
// @returns {Array.<module:engine/model/element~Element>}
function getOverlappingCells( table, headingRowsToSet, currentHeadingRows ) {
const cellsToSplit = [];

const startAnalysisRow = headingRowsToSet > currentHeadingRows ? currentHeadingRows : 0;
// We're analyzing only when headingRowsToSet > 0.
const endAnalysisRow = headingRowsToSet - 1;

const tableWalker = new TableWalker( table, { startRow: startAnalysisRow, endRow: endAnalysisRow } );

for ( const { row, rowspan, cell } of tableWalker ) {
if ( rowspan > 1 && row + rowspan > headingRowsToSet ) {
cellsToSplit.push( cell );
}
}

return cellsToSplit;
}

// Splits the table cell horizontally.
//
// @param {module:engine/model/element~Element} tableCell
// @param {Number} headingRows
// @param {module:engine/model/writer~Writer} writer
function splitHorizontally( tableCell, headingRows, writer ) {
const tableRow = tableCell.parent;
const table = tableRow.parent;
const rowIndex = tableRow.index;

const rowspan = parseInt( tableCell.getAttribute( 'rowspan' ) );
const newRowspan = headingRows - rowIndex;

const attributes = {};

const spanToSet = rowspan - newRowspan;

if ( spanToSet > 1 ) {
attributes.rowspan = spanToSet;
}

const colspan = parseInt( tableCell.getAttribute( 'colspan' ) || 1 );

if ( colspan > 1 ) {
attributes.colspan = colspan;
}

const startRow = table.getChildIndex( tableRow );
const endRow = startRow + newRowspan;
const tableMap = [ ...new TableWalker( table, { startRow, endRow, includeSpanned: true } ) ];

let columnIndex;

for ( const { row, column, cell, cellIndex } of tableMap ) {
if ( cell === tableCell && columnIndex === undefined ) {
columnIndex = column;
}

if ( columnIndex !== undefined && columnIndex === column && row === endRow ) {
const tableRow = table.getChild( row );
const tableCellPosition = writer.createPositionAt( tableRow, cellIndex );

createEmptyTableCell( writer, tableCellPosition, attributes );
}
}

// Update the rowspan attribute after updating table.
updateNumericAttribute( 'rowspan', newRowspan, tableCell, writer );
}
Loading

0 comments on commit 9531af4

Please sign in to comment.