Skip to content
This repository was archived by the owner on Jun 26, 2020. It is now read-only.

Commit a01252a

Browse files
authored
Merge pull request #60 from ckeditor/t/16
Fix: The `MergeCellCommand` should check if merging cells results in an empty row and remove it. Closes #16.
2 parents 4fc04c8 + 8314c8f commit a01252a

File tree

2 files changed

+99
-1
lines changed

2 files changed

+99
-1
lines changed

src/commands/mergecellcommand.js

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import Command from '@ckeditor/ckeditor5-core/src/command';
1111
import Position from '@ckeditor/ckeditor5-engine/src/model/position';
1212
import Range from '@ckeditor/ckeditor5-engine/src/model/range';
1313
import TableWalker from '../tablewalker';
14+
import { updateNumericAttribute } from './utils';
1415

1516
/**
1617
* The merge cell command.
@@ -92,16 +93,25 @@ export default class MergeCellCommand extends Command {
9293
const cellToExpand = isMergeNext ? tableCell : cellToMerge;
9394
const cellToRemove = isMergeNext ? cellToMerge : tableCell;
9495

96+
// Cache the parent of cell to remove for later check.
97+
const removedTableCellRow = cellToRemove.parent;
98+
99+
// Remove table cell and merge it contents with merged cell.
95100
writer.move( Range.createIn( cellToRemove ), Position.createAt( cellToExpand, 'end' ) );
96101
writer.remove( cellToRemove );
97102

98103
const spanAttribute = this.isHorizontal ? 'colspan' : 'rowspan';
99104
const cellSpan = parseInt( tableCell.getAttribute( spanAttribute ) || 1 );
100105
const cellToMergeSpan = parseInt( cellToMerge.getAttribute( spanAttribute ) || 1 );
101106

107+
// Update table cell span attribute and merge set selection on merged contents.
102108
writer.setAttribute( spanAttribute, cellSpan + cellToMergeSpan, cellToExpand );
103-
104109
writer.setSelection( Range.createIn( cellToExpand ) );
110+
111+
// Remove empty row after merging.
112+
if ( !removedTableCellRow.childCount ) {
113+
removeEmptyRow( removedTableCellRow, writer );
114+
}
105115
} );
106116
}
107117

@@ -195,3 +205,23 @@ function getVerticalCell( tableCell, direction ) {
195205

196206
return cellToMergeData && cellToMergeData.cell;
197207
}
208+
209+
// Properly removes empty row from a table. Will update `rowspan` attribute of cells that overlaps removed row.
210+
//
211+
// @param {module:engine/model/element~Element} removedTableCellRow
212+
// @param {module:engine/model/writer~Writer} writer
213+
function removeEmptyRow( removedTableCellRow, writer ) {
214+
const table = removedTableCellRow.parent;
215+
216+
const removedRowIndex = table.getChildIndex( removedTableCellRow );
217+
218+
for ( const { cell, row, rowspan } of new TableWalker( table, { endRow: removedRowIndex } ) ) {
219+
const overlapsRemovedRow = row + rowspan - 1 >= removedRowIndex;
220+
221+
if ( overlapsRemovedRow ) {
222+
updateNumericAttribute( 'rowspan', rowspan - 1, cell, writer );
223+
}
224+
}
225+
226+
writer.remove( removedTableCellRow );
227+
}

tests/commands/mergecellcommand.js

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,40 @@ describe( 'MergeCellCommand', () => {
394394
[ '10' ]
395395
] ) );
396396
} );
397+
398+
it( 'should remove empty row if merging table cells ', () => {
399+
setData( model, modelTable( [
400+
[ { rowspan: 2, contents: '00' }, '01[]', { rowspan: 3, contents: '02' } ],
401+
[ '11' ],
402+
[ '20', '21' ]
403+
] ) );
404+
405+
command.execute();
406+
407+
expect( formatTable( getData( model ) ) ).to.equal( formattedModelTable( [
408+
[ '00', '[0111]', { rowspan: 2, contents: '02' } ],
409+
[ '20', '21' ]
410+
] ) );
411+
} );
412+
413+
it( 'should not reduce rowspan on cells above removed empty row when merging table cells ', () => {
414+
setData( model, modelTable( [
415+
[ { rowspan: 2, contents: '00' }, '01', '02' ],
416+
[ '11', '12' ],
417+
[ { rowspan: 2, contents: '20' }, '21[]', { rowspan: 3, contents: '22' } ],
418+
[ '31' ],
419+
[ '40', '41' ]
420+
] ) );
421+
422+
command.execute();
423+
424+
expect( formatTable( getData( model ) ) ).to.equal( formattedModelTable( [
425+
[ { rowspan: 2, contents: '00' }, '01', '02' ],
426+
[ '11', '12' ],
427+
[ '20', '[2131]', { rowspan: 2, contents: '22' } ],
428+
[ '40', '41' ]
429+
] ) );
430+
} );
397431
} );
398432
} );
399433

@@ -542,6 +576,40 @@ describe( 'MergeCellCommand', () => {
542576
[ { colspan: 2, contents: '40' }, '42' ]
543577
] ) );
544578
} );
579+
580+
it( 'should remove empty row if merging table cells ', () => {
581+
setData( model, modelTable( [
582+
[ { rowspan: 2, contents: '00' }, '01', { rowspan: 3, contents: '02' } ],
583+
[ '11[]' ],
584+
[ '20', '21' ]
585+
] ) );
586+
587+
command.execute();
588+
589+
expect( formatTable( getData( model ) ) ).to.equal( formattedModelTable( [
590+
[ '00', '[0111]', { rowspan: 2, contents: '02' } ],
591+
[ '20', '21' ]
592+
] ) );
593+
} );
594+
595+
it( 'should not reduce rowspan on cells above removed empty row when merging table cells ', () => {
596+
setData( model, modelTable( [
597+
[ { rowspan: 2, contents: '00' }, '01', '02' ],
598+
[ '11', '12' ],
599+
[ { rowspan: 2, contents: '20' }, '21', { rowspan: 3, contents: '22' } ],
600+
[ '31[]' ],
601+
[ '40', '41' ]
602+
] ) );
603+
604+
command.execute();
605+
606+
expect( formatTable( getData( model ) ) ).to.equal( formattedModelTable( [
607+
[ { rowspan: 2, contents: '00' }, '01', '02' ],
608+
[ '11', '12' ],
609+
[ '20', '[2131]', { rowspan: 2, contents: '22' } ],
610+
[ '40', '41' ]
611+
] ) );
612+
} );
545613
} );
546614
} );
547615
} );

0 commit comments

Comments
 (0)