removerowcommand.js 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. /**
  2. * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
  4. */
  5. /**
  6. * @module table/commands/removerowcommand
  7. */
  8. import Command from '@ckeditor/ckeditor5-core/src/command';
  9. import { findAncestor } from './utils';
  10. import { getRowIndexes, getSelectionAffectedTableCells } from '../utils';
  11. /**
  12. * The remove row command.
  13. *
  14. * The command is registered by {@link module:table/tableediting~TableEditing} as the `'removeTableRow'` editor command.
  15. *
  16. * To remove the row containing the selected cell, execute the command:
  17. *
  18. * editor.execute( 'removeTableRow' );
  19. *
  20. * @extends module:core/command~Command
  21. */
  22. export default class RemoveRowCommand extends Command {
  23. /**
  24. * @inheritDoc
  25. */
  26. refresh() {
  27. const selectedCells = getSelectionAffectedTableCells( this.editor.model.document.selection );
  28. const firstCell = selectedCells[ 0 ];
  29. if ( firstCell ) {
  30. const table = findAncestor( 'table', firstCell );
  31. const tableRowCount = this.editor.plugins.get( 'TableUtils' ).getRows( table );
  32. const lastRowIndex = tableRowCount - 1;
  33. const selectedRowIndexes = getRowIndexes( selectedCells );
  34. const areAllRowsSelected = selectedRowIndexes.first === 0 && selectedRowIndexes.last === lastRowIndex;
  35. // Disallow selecting whole table -> delete whole table should be used instead.
  36. this.isEnabled = !areAllRowsSelected;
  37. } else {
  38. this.isEnabled = false;
  39. }
  40. }
  41. /**
  42. * @inheritDoc
  43. */
  44. execute() {
  45. const model = this.editor.model;
  46. const referenceCells = getSelectionAffectedTableCells( model.document.selection );
  47. const removedRowIndexes = getRowIndexes( referenceCells );
  48. const firstCell = referenceCells[ 0 ];
  49. const table = findAncestor( 'table', firstCell );
  50. const columnIndexToFocus = this.editor.plugins.get( 'TableUtils' ).getCellLocation( firstCell ).column;
  51. // Use single batch to modify table in steps but in one undo step.
  52. const batch = model.createBatch();
  53. model.enqueueChange( batch, writer => {
  54. // This prevents the "model-selection-range-intersects" error, caused by removing row selected cells.
  55. writer.setSelection( writer.createSelection( table, 'on' ) );
  56. const rowsToRemove = removedRowIndexes.last - removedRowIndexes.first + 1;
  57. this.editor.plugins.get( 'TableUtils' ).removeRows( table, {
  58. at: removedRowIndexes.first,
  59. rows: rowsToRemove,
  60. batch
  61. } );
  62. } );
  63. model.enqueueChange( batch, writer => {
  64. const cellToFocus = getCellToFocus( table, removedRowIndexes.first, columnIndexToFocus );
  65. writer.setSelection( writer.createPositionAt( cellToFocus, 0 ) );
  66. } );
  67. }
  68. }
  69. // Returns a cell that should be focused before removing the row, belonging to the same column as the currently focused cell.
  70. // * If the row was not the last one, the cell to focus will be in the row that followed it (before removal).
  71. // * If the row was the last one, the cell to focus will be in the row that preceded it (before removal).
  72. function getCellToFocus( table, removedRowIndex, columnToFocus ) {
  73. const row = table.getChild( removedRowIndex ) || table.getChild( table.childCount - 1 );
  74. // Default to first table cell.
  75. let cellToFocus = row.getChild( 0 );
  76. let column = 0;
  77. for ( const tableCell of row.getChildren() ) {
  78. if ( column > columnToFocus ) {
  79. return cellToFocus;
  80. }
  81. cellToFocus = tableCell;
  82. column += parseInt( tableCell.getAttribute( 'colspan' ) || 1 );
  83. }
  84. return cellToFocus;
  85. }