removerowcommand.js 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  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 { getRowIndexes, getSelectionAffectedTableCells } from '../utils/selection';
  10. import { findAncestor } from '../utils/common';
  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, () => {
  54. const rowsToRemove = removedRowIndexes.last - removedRowIndexes.first + 1;
  55. this.editor.plugins.get( 'TableUtils' ).removeRows( table, {
  56. at: removedRowIndexes.first,
  57. rows: rowsToRemove,
  58. batch
  59. } );
  60. } );
  61. model.enqueueChange( batch, writer => {
  62. const cellToFocus = getCellToFocus( table, removedRowIndexes.first, columnIndexToFocus );
  63. writer.setSelection( writer.createPositionAt( cellToFocus, 0 ) );
  64. } );
  65. }
  66. }
  67. // Returns a cell that should be focused before removing the row, belonging to the same column as the currently focused cell.
  68. // * If the row was not the last one, the cell to focus will be in the row that followed it (before removal).
  69. // * If the row was the last one, the cell to focus will be in the row that preceded it (before removal).
  70. function getCellToFocus( table, removedRowIndex, columnToFocus ) {
  71. const row = table.getChild( removedRowIndex ) || table.getChild( table.childCount - 1 );
  72. // Default to first table cell.
  73. let cellToFocus = row.getChild( 0 );
  74. let column = 0;
  75. for ( const tableCell of row.getChildren() ) {
  76. if ( column > columnToFocus ) {
  77. return cellToFocus;
  78. }
  79. cellToFocus = tableCell;
  80. column += parseInt( tableCell.getAttribute( 'colspan' ) || 1 );
  81. }
  82. return cellToFocus;
  83. }