removerowcommand.js 3.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. /**
  2. * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md.
  4. */
  5. /**
  6. * @module table/commands/removerowcommand
  7. */
  8. import Command from '@ckeditor/ckeditor5-core/src/command';
  9. import Position from '@ckeditor/ckeditor5-engine/src/model/position';
  10. import Range from '@ckeditor/ckeditor5-engine/src/model/range';
  11. import TableWalker from '../tablewalker';
  12. import { updateNumericAttribute } from './utils';
  13. /**
  14. * The remove row command.
  15. *
  16. * The command is registered by {@link module:table/tableediting~TableEditing} as `'removeTableRow'` editor command.
  17. *
  18. * To remove the row containing the selected cell, execute the command:
  19. *
  20. * editor.execute( 'removeTableRow' );
  21. *
  22. * @extends module:core/command~Command
  23. */
  24. export default class RemoveRowCommand extends Command {
  25. /**
  26. * @inheritDoc
  27. */
  28. refresh() {
  29. const model = this.editor.model;
  30. const doc = model.document;
  31. const element = doc.selection.getFirstPosition().parent;
  32. this.isEnabled = element.is( 'tableCell' ) && element.parent.parent.childCount > 1;
  33. }
  34. /**
  35. * @inheritDoc
  36. */
  37. execute() {
  38. const model = this.editor.model;
  39. const selection = model.document.selection;
  40. const firstPosition = selection.getFirstPosition();
  41. const tableCell = firstPosition.parent;
  42. const tableRow = tableCell.parent;
  43. const table = tableRow.parent;
  44. const currentRow = table.getChildIndex( tableRow );
  45. const headingRows = table.getAttribute( 'headingRows' ) || 0;
  46. model.change( writer => {
  47. if ( headingRows && currentRow <= headingRows ) {
  48. updateNumericAttribute( 'headingRows', headingRows - 1, table, writer, 0 );
  49. }
  50. const tableMap = [ ...new TableWalker( table, { endRow: currentRow } ) ];
  51. const cellsToMove = new Map();
  52. // Get cells from removed row that are spanned over multiple rows.
  53. tableMap
  54. .filter( ( { row, rowspan } ) => row === currentRow && rowspan > 1 )
  55. .forEach( ( { column, cell, rowspan } ) => cellsToMove.set( column, { cell, rowspanToSet: rowspan - 1 } ) );
  56. // Reduce rowspan on cells that are above removed row and overlaps removed row.
  57. tableMap
  58. .filter( ( { row, rowspan } ) => row <= currentRow - 1 && row + rowspan > currentRow )
  59. .forEach( ( { cell, rowspan } ) => updateNumericAttribute( 'rowspan', rowspan - 1, cell, writer ) );
  60. // Move cells to another row.
  61. const targetRow = currentRow + 1;
  62. const tableWalker = new TableWalker( table, { includeSpanned: true, startRow: targetRow, endRow: targetRow } );
  63. let previousCell;
  64. for ( const { row, column, cell } of [ ...tableWalker ] ) {
  65. if ( cellsToMove.has( column ) ) {
  66. const { cell: cellToMove, rowspanToSet } = cellsToMove.get( column );
  67. const targetPosition = previousCell ? Position.createAfter( previousCell ) : Position.createAt( table.getChild( row ) );
  68. writer.move( Range.createOn( cellToMove ), targetPosition );
  69. updateNumericAttribute( 'rowspan', rowspanToSet, cellToMove, writer );
  70. previousCell = cellToMove;
  71. } else {
  72. previousCell = cell;
  73. }
  74. }
  75. writer.remove( tableRow );
  76. } );
  77. }
  78. }