/** * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved. * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license */ /* globals document */ import ClassicTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/classictesteditor'; import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph'; import Delete from '@ckeditor/ckeditor5-typing/src/delete'; import Clipboard from '@ckeditor/ckeditor5-clipboard/src/clipboard'; import HorizontalLine from '@ckeditor/ckeditor5-horizontal-line/src/horizontalline'; import TableEditing from '../src/tableediting'; import TableSelection from '../src/tableselection'; import TableClipboard from '../src/tableclipboard'; import { getData as getModelData, setData as setModelData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model'; import { modelTable } from './_utils/utils'; import { assertEqualMarkup } from '@ckeditor/ckeditor5-utils/tests/_utils/utils'; import DomEventData from '@ckeditor/ckeditor5-engine/src/view/observer/domeventdata'; import { getCode } from '@ckeditor/ckeditor5-utils/src/keyboard'; import Input from '@ckeditor/ckeditor5-typing/src/input'; import ViewText from '@ckeditor/ckeditor5-engine/src/view/text'; import UndoEditing from '@ckeditor/ckeditor5-undo/src/undoediting'; describe( 'TableSelection - integration', () => { let editor, model, tableSelection, modelRoot, element, viewDocument; afterEach( async () => { element.remove(); await editor.destroy(); } ); describe( 'on delete', () => { beforeEach( async () => { await setupEditor( [ Delete ] ); } ); it( 'should clear contents of the selected table cells and put selection in last cell on backward delete', () => { tableSelection.setCellSelection( modelRoot.getNodeByPath( [ 0, 0, 0 ] ), modelRoot.getNodeByPath( [ 0, 1, 1 ] ) ); const domEventData = new DomEventData( viewDocument, { preventDefault: sinon.spy() }, { direction: 'backward', unit: 'character', sequence: 1 } ); viewDocument.fire( 'delete', domEventData ); assertEqualMarkup( getModelData( model ), modelTable( [ [ '', '', '13' ], [ '', '[]', '23' ], [ '31', '32', '33' ] ] ) ); } ); it( 'should clear contents of the selected table cells and put selection in last cell on forward delete', () => { tableSelection.setCellSelection( modelRoot.getNodeByPath( [ 0, 0, 0 ] ), modelRoot.getNodeByPath( [ 0, 1, 1 ] ) ); const domEventData = new DomEventData( viewDocument, { preventDefault: sinon.spy() }, { direction: 'forward', unit: 'character', sequence: 1 } ); viewDocument.fire( 'delete', domEventData ); assertEqualMarkup( getModelData( model ), modelTable( [ [ '[]', '', '13' ], [ '', '', '23' ], [ '31', '32', '33' ] ] ) ); } ); it( 'should not interfere with default key handler if no table selection', () => { setModelData( model, modelTable( [ [ '11[]', '12', '13' ], [ '21', '22', '23' ], [ '31', '32', '33' ] ] ) ); const domEventData = new DomEventData( viewDocument, { preventDefault: sinon.spy() }, { direction: 'backward', unit: 'character', sequence: 1 } ); viewDocument.fire( 'delete', domEventData ); assertEqualMarkup( getModelData( model ), modelTable( [ [ '1[]', '12', '13' ], [ '21', '22', '23' ], [ '31', '32', '33' ] ] ) ); } ); } ); describe( 'on user input', () => { beforeEach( async () => { await setupEditor( [ Input ] ); } ); it( 'should clear contents of the selected table cells and put selection in last cell on user input', () => { tableSelection.setCellSelection( modelRoot.getNodeByPath( [ 0, 0, 0 ] ), modelRoot.getNodeByPath( [ 0, 1, 1 ] ) ); viewDocument.fire( 'keydown', { keyCode: getCode( 'x' ) } ); // Mutate at the place where the document selection was put; it's more realistic // than mutating at some arbitrary position. const placeOfMutation = viewDocument.selection.getFirstRange().start.parent; viewDocument.fire( 'mutations', [ { type: 'children', oldChildren: [], newChildren: [ new ViewText( viewDocument, 'x' ) ], node: placeOfMutation } ] ); assertEqualMarkup( getModelData( model ), modelTable( [ [ '', '', '13' ], [ '', 'x[]', '23' ], [ '31', '32', '33' ] ] ) ); } ); it( 'should not interfere with default key handler if no table selection', () => { viewDocument.fire( 'keydown', { keyCode: getCode( 'x' ) } ); // Mutate at the place where the document selection was put; it's more realistic // than mutating at some arbitrary position. const placeOfMutation = viewDocument.selection.getFirstRange().start.parent; viewDocument.fire( 'mutations', [ { type: 'children', oldChildren: [], newChildren: [ new ViewText( viewDocument, 'x' ) ], node: placeOfMutation } ] ); assertEqualMarkup( getModelData( model ), modelTable( [ [ 'x[]11', '12', '13' ], [ '21', '22', '23' ], [ '31', '32', '33' ] ] ) ); } ); } ); describe( 'with other features', () => { beforeEach( async () => { await setupEditor( [ Clipboard, HorizontalLine ] ); } ); it( 'allows pasting over multi-cell selection', () => { tableSelection.setCellSelection( modelRoot.getNodeByPath( [ 0, 0, 0 ] ), modelRoot.getNodeByPath( [ 0, 1, 1 ] ) ); const dataTransferMock = { getData: sinon.stub().withArgs( 'text/plain' ).returns( 'foo' ) }; editor.editing.view.document.fire( 'clipboardInput', { dataTransfer: dataTransferMock, stop: sinon.spy() } ); assertEqualMarkup( getModelData( model ), modelTable( [ [ 'foo[]', '', '13' ], [ '', '', '23' ], [ '31', '32', '33' ] ] ) ); } ); it( 'allows inserting a horizontal line over a multi-range selection', () => { tableSelection.setCellSelection( modelRoot.getNodeByPath( [ 0, 0, 0 ] ), modelRoot.getNodeByPath( [ 0, 1, 1 ] ) ); editor.execute( 'horizontalLine' ); assertEqualMarkup( getModelData( model ), '