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

I/6119: Clear table contents on clipboard "cut" and keyboard delete #254

Merged
merged 17 commits into from
Feb 28, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 5 additions & 19 deletions src/tableclipboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,18 +48,18 @@ export default class TableClipboard extends Plugin {
*/
this._tableSelection = editor.plugins.get( 'TableSelection' );

this.listenTo( viewDocument, 'copy', ( evt, data ) => this._onCopy( evt, data ), { priority: 'normal' } );
this.listenTo( viewDocument, 'cut', ( evt, data ) => this._onCut( evt, data ), { priority: 'high' } );
this.listenTo( viewDocument, 'copy', ( evt, data ) => this._onCopyCut( evt, data ) );
this.listenTo( viewDocument, 'cut', ( evt, data ) => this._onCopyCut( evt, data ) );
}

/**
* A clipboard "copy" event handler.
* Copies table content to a clipboard on "copy" & "cut" events.
*
* @param {module:utils/eventinfo~EventInfo} evt An object containing information about the handled event.
* @param {Object} data Clipboard event data.
* @private
*/
_onCopy( evt, data ) {
_onCopyCut( evt, data ) {
const tableSelection = this._tableSelection;

if ( !tableSelection.hasMultiCellSelection ) {
Expand All @@ -72,26 +72,12 @@ export default class TableClipboard extends Plugin {
const dataController = this.editor.data;
const viewDocument = this.editor.editing.view.document;

const content = dataController.toView( tableSelection.getSelectionAsFragment() );
const content = dataController.toView( this._tableSelection.getSelectionAsFragment() );

viewDocument.fire( 'clipboardOutput', {
dataTransfer: data.dataTransfer,
content,
method: evt.name
} );
}

/**
* A clipboard "cut" event handler.
*
* @param {module:utils/eventinfo~EventInfo} evt An object containing information about the handled event.
* @param {Object} data Clipboard event data.
* @private
*/
_onCut( evt, data ) {
if ( this._tableSelection.hasMultiCellSelection ) {
data.preventDefault();
evt.stop();
}
}
}
76 changes: 74 additions & 2 deletions src/tableselection.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import TableUtils from './tableutils';
import { setupTableSelectionHighlighting } from './tableselection/converters';
import MouseSelectionHandler from './tableselection/mouseselectionhandler';
import { findAncestor } from './commands/utils';
import { clearTableCellsContents } from './tableselection/utils';
import cropTable from './tableselection/croptable';

import '../theme/tableselection.css';
Expand Down Expand Up @@ -95,13 +96,38 @@ export default class TableSelection extends Plugin {
*/
init() {
const editor = this.editor;
const selection = editor.model.document.selection;
const model = editor.model;
const selection = model.document.selection;

this._tableUtils = editor.plugins.get( 'TableUtils' );

setupTableSelectionHighlighting( editor, this );

selection.on( 'change:range', () => this._clearSelectionOnExternalChange( selection ) );
this.listenTo( selection, 'change:range', () => this._clearSelectionOnExternalChange( selection ) );
this.listenTo( model, 'deleteContent', ( evt, args ) => this._handleDeleteContent( evt, args ), { priority: 'high' } );
}

/**
* @inheritDoc
*/
afterInit() {
const editor = this.editor;

const deleteCommand = editor.commands.get( 'delete' );

if ( deleteCommand ) {
this.listenTo( deleteCommand, 'execute', event => {
this._handleDeleteCommand( event, { isForward: false } );
}, { priority: 'high' } );
}

const forwardDeleteCommand = editor.commands.get( 'forwardDelete' );

if ( forwardDeleteCommand ) {
this.listenTo( forwardDeleteCommand, 'execute', event => {
this._handleDeleteCommand( event, { isForward: true } );
}, { priority: 'high' } );
}
}

/**
Expand Down Expand Up @@ -279,4 +305,50 @@ export default class TableSelection extends Plugin {
this.clearSelection();
}
}

/**
* It overrides default `model.deleteContent()` behavior over a selected table fragment.
*
* @private
* @param {module:utils/eventinfo~EventInfo} event
* @param {Array.<*>} args Delete content method arguments.
*/
_handleDeleteContent( event, args ) {
const [ selection ] = args;
const model = this.editor.model;

if ( this.hasMultiCellSelection && selection.is( 'documentSelection' ) ) {
event.stop();

clearTableCellsContents( model, this.getSelectedTableCells() );

model.change( writer => {
writer.setSelection( Array.from( this.getSelectedTableCells() ).pop(), 0 );
} );
}
}

/**
* It overrides default `DeleteCommand` behavior over a selected table fragment.
*
* @private
* @param {module:utils/eventinfo~EventInfo} event
* @param {Object} options
* @param {Boolean} options.isForward Whether it handles forward or backward delete.
*/
_handleDeleteCommand( event, options ) {
const model = this.editor.model;

if ( this.hasMultiCellSelection ) {
event.stop();

clearTableCellsContents( model, this.getSelectedTableCells() );

const tableCell = options.isForward ? this._startElement : this._endElement;

model.change( writer => {
writer.setSelection( tableCell, 0 );
} );
}
}
}
2 changes: 1 addition & 1 deletion src/tableselection/croptable.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { findAncestor } from '../commands/utils';
* tableSelection.startSelectingFrom( startCell )
* tableSelection.setSelectingFrom( endCell )
*
* const croppedTable = cropTable( tableSelection.getSelectedTableCells );
* const croppedTable = cropTable( tableSelection.getSelectedTableCells() );
*
* **Note**: This function is used also by {@link module:table/tableselection~TableSelection#getSelectionAsFragment}
*
Expand Down
31 changes: 31 additions & 0 deletions src/tableselection/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/**
* @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/

/**
* @module table/tableselection/utils
*/

/**
* Clears contents of the passed table cells.
*
* This is to be used with table selection
*
* tableSelection.startSelectingFrom( startCell )
* tableSelection.setSelectingFrom( endCell )
*
* clearTableCellsContents( editor.model, tableSelection.getSelectedTableCells() );
*
* **Note**: This function is used also by {@link module:table/tableselection~TableSelection#getSelectionAsFragment}
*
* @param {module:engine/model/model~Model} model
* @param {Iterable.<module:engine/model/element~Element>} tableCells
*/
export function clearTableCellsContents( model, tableCells ) {
model.change( writer => {
for ( const tableCell of tableCells ) {
model.deleteContent( writer.createSelection( tableCell, 'in' ) );
}
} );
}
Loading