From 8d1eb2f1c768586a8e41367bc4dc62e1d360b3be Mon Sep 17 00:00:00 2001 From: Kuba Niegowski Date: Mon, 1 Jun 2020 14:40:10 +0200 Subject: [PATCH 1/3] Renamed TableNavigation as TableKeyboard. --- packages/ckeditor5-table/src/table.js | 6 +- .../{tablenavigation.js => tablekeyboard.js} | 6 +- packages/ckeditor5-table/tests/table.js | 6 +- .../ckeditor5-table/tests/tablenavigation.js | 126 +++++++++--------- 4 files changed, 72 insertions(+), 72 deletions(-) rename packages/ckeditor5-table/src/{tablenavigation.js => tablekeyboard.js} (99%) diff --git a/packages/ckeditor5-table/src/table.js b/packages/ckeditor5-table/src/table.js index e8428e450d0..8bd1d5ed9bc 100644 --- a/packages/ckeditor5-table/src/table.js +++ b/packages/ckeditor5-table/src/table.js @@ -13,7 +13,7 @@ import TableEditing from './tableediting'; import TableUI from './tableui'; import TableSelection from './tableselection'; import TableClipboard from './tableclipboard'; -import TableNavigation from './tablenavigation'; +import TableKeyboard from './tablekeyboard'; import Widget from '@ckeditor/ckeditor5-widget/src/widget'; import '../theme/table.css'; @@ -27,7 +27,7 @@ import '../theme/table.css'; * * * {@link module:table/tableediting~TableEditing editing feature}, * * {@link module:table/tableselection~TableSelection selection feature}, - * * {@link module:table/tablenavigation~TableNavigation keyboard navigation feature}, + * * {@link module:table/tablekeyboard~TableKeyboard keyboard navigation feature}, * * {@link module:table/tableclipboard~TableClipboard clipboard feature}, * * {@link module:table/tableui~TableUI UI feature}. * @@ -38,7 +38,7 @@ export default class Table extends Plugin { * @inheritDoc */ static get requires() { - return [ TableEditing, TableUI, TableSelection, TableClipboard, TableNavigation, Widget ]; + return [ TableEditing, TableUI, TableSelection, TableClipboard, TableKeyboard, Widget ]; } /** diff --git a/packages/ckeditor5-table/src/tablenavigation.js b/packages/ckeditor5-table/src/tablekeyboard.js similarity index 99% rename from packages/ckeditor5-table/src/tablenavigation.js rename to packages/ckeditor5-table/src/tablekeyboard.js index 12c832efa8a..73f6a8e6b9d 100644 --- a/packages/ckeditor5-table/src/tablenavigation.js +++ b/packages/ckeditor5-table/src/tablekeyboard.js @@ -4,7 +4,7 @@ */ /** - * @module table/tablenavigation + * @module table/tablekeyboard */ import TableSelection from './tableselection'; @@ -23,12 +23,12 @@ import { findAncestor } from './utils/common'; * * @extends module:core/plugin~Plugin */ -export default class TableNavigation extends Plugin { +export default class TableKeyboard extends Plugin { /** * @inheritDoc */ static get pluginName() { - return 'TableNavigation'; + return 'TableKeyboard'; } /** diff --git a/packages/ckeditor5-table/tests/table.js b/packages/ckeditor5-table/tests/table.js index d37ae22e683..0cc6043508d 100644 --- a/packages/ckeditor5-table/tests/table.js +++ b/packages/ckeditor5-table/tests/table.js @@ -8,12 +8,12 @@ import TableEditing from '../src/tableediting'; import TableUI from '../src/tableui'; import TableSelection from '../src/tableselection'; import TableClipboard from '../src/tableclipboard'; -import TableNavigation from '../src/tablenavigation'; +import TableKeyboard from '../src/tablekeyboard'; import Widget from '@ckeditor/ckeditor5-widget/src/widget'; describe( 'Table', () => { - it( 'requires TableEditing, TableUI, TableSelection, TableClipboard, TableNavigation and Widget', () => { - expect( Table.requires ).to.deep.equal( [ TableEditing, TableUI, TableSelection, TableClipboard, TableNavigation, Widget ] ); + it( 'requires TableEditing, TableUI, TableSelection, TableClipboard, TableKeyboard and Widget', () => { + expect( Table.requires ).to.deep.equal( [ TableEditing, TableUI, TableSelection, TableClipboard, TableKeyboard, Widget ] ); } ); it( 'has proper name', () => { diff --git a/packages/ckeditor5-table/tests/tablenavigation.js b/packages/ckeditor5-table/tests/tablenavigation.js index 4bac88c8aab..fd3f35c741e 100644 --- a/packages/ckeditor5-table/tests/tablenavigation.js +++ b/packages/ckeditor5-table/tests/tablenavigation.js @@ -3,7 +3,7 @@ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license */ -import TableNavigation from '../src/tablenavigation'; +import TableKeyboard from '../src/tablekeyboard'; import Table from '../src/table'; import TableEditing from '../src/tableediting'; import TableSelection from '../src/tableselection'; @@ -27,8 +27,8 @@ import { assertEqualMarkup } from '@ckeditor/ckeditor5-utils/tests/_utils/utils' import global from '@ckeditor/ckeditor5-utils/src/dom/global'; import env from '@ckeditor/ckeditor5-utils/src/env'; -describe( 'TableNavigation', () => { - let editor, model, modelRoot, tableSelection, tableNavigation, selection; +describe( 'TableKeyboard', () => { + let editor, model, modelRoot, tableSelection, tableKeyboard, selection; const imageUrl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAAAUCAQAAADRyVAeAAAAKklEQVR42u3PAQ0AAAwCI' + 'O0f+u/hoAHNZUJFRERERERERERERERERLYiD9N4FAFj2iK6AAAAAElFTkSuQmCC'; @@ -36,7 +36,7 @@ describe( 'TableNavigation', () => { beforeEach( () => { return VirtualTestEditor .create( { - plugins: [ TableEditing, TableNavigation, TableSelection, Paragraph, ImageEditing, ImageCaptionEditing, MediaEmbedEditing, + plugins: [ TableEditing, TableKeyboard, TableSelection, Paragraph, ImageEditing, ImageCaptionEditing, MediaEmbedEditing, HorizontalLineEditing ] } ) .then( newEditor => { @@ -46,7 +46,7 @@ describe( 'TableNavigation', () => { selection = model.document.selection; modelRoot = model.document.getRoot(); tableSelection = editor.plugins.get( TableSelection ); - tableNavigation = editor.plugins.get( TableNavigation ); + tableKeyboard = editor.plugins.get( TableKeyboard ); } ); } ); @@ -55,7 +55,7 @@ describe( 'TableNavigation', () => { } ); it( 'should have pluginName', () => { - expect( TableNavigation.pluginName ).to.equal( 'TableNavigation' ); + expect( TableKeyboard.pluginName ).to.equal( 'TableKeyboard' ); } ); describe( 'Tab key handling', () => { @@ -465,7 +465,7 @@ describe( 'TableNavigation', () => { } ); it( 'should navigate to the start position of the cell on the right when the direction is "right"', () => { - tableNavigation._navigateFromCellInDirection( tableCell, 'right' ); + tableKeyboard._navigateFromCellInDirection( tableCell, 'right' ); assertEqualMarkup( getModelData( model ), 'foo' + modelTable( [ [ '00', '[]01', '02' ], @@ -475,7 +475,7 @@ describe( 'TableNavigation', () => { } ); it( 'should navigate to the start position of the cell below when the direction is "down"', () => { - tableNavigation._navigateFromCellInDirection( tableCell, 'down' ); + tableKeyboard._navigateFromCellInDirection( tableCell, 'down' ); assertEqualMarkup( getModelData( model ), 'foo' + modelTable( [ [ '00', '01', '02' ], @@ -485,7 +485,7 @@ describe( 'TableNavigation', () => { } ); it( 'should select a whole table when the direction is "up"', () => { - tableNavigation._navigateFromCellInDirection( tableCell, 'up' ); + tableKeyboard._navigateFromCellInDirection( tableCell, 'up' ); assertEqualMarkup( getModelData( model ), 'foo[' + modelTable( [ [ '00', '01', '02' ], @@ -495,7 +495,7 @@ describe( 'TableNavigation', () => { } ); it( 'should select a whole table when the direction is "left"', () => { - tableNavigation._navigateFromCellInDirection( tableCell, 'left' ); + tableKeyboard._navigateFromCellInDirection( tableCell, 'left' ); assertEqualMarkup( getModelData( model ), 'foo[' + modelTable( [ [ '00', '01', '02' ], @@ -513,7 +513,7 @@ describe( 'TableNavigation', () => { } ); it( 'should navigate to the end position of the cell on the left when the direction is "left"', () => { - tableNavigation._navigateFromCellInDirection( tableCell, 'left' ); + tableKeyboard._navigateFromCellInDirection( tableCell, 'left' ); assertEqualMarkup( getModelData( model ), 'foo' + modelTable( [ [ '00', '01', '02' ], @@ -523,7 +523,7 @@ describe( 'TableNavigation', () => { } ); it( 'should navigate to the end position of the cell above when the direction is "up"', () => { - tableNavigation._navigateFromCellInDirection( tableCell, 'up' ); + tableKeyboard._navigateFromCellInDirection( tableCell, 'up' ); assertEqualMarkup( getModelData( model ), 'foo' + modelTable( [ [ '00', '01', '02' ], @@ -533,7 +533,7 @@ describe( 'TableNavigation', () => { } ); it( 'should select a whole table when the direction is "down"', () => { - tableNavigation._navigateFromCellInDirection( tableCell, 'down' ); + tableKeyboard._navigateFromCellInDirection( tableCell, 'down' ); assertEqualMarkup( getModelData( model ), 'foo[' + modelTable( [ [ '00', '01', '02' ], @@ -543,7 +543,7 @@ describe( 'TableNavigation', () => { } ); it( 'should select a whole table when the direction is "right"', () => { - tableNavigation._navigateFromCellInDirection( tableCell, 'right' ); + tableKeyboard._navigateFromCellInDirection( tableCell, 'right' ); assertEqualMarkup( getModelData( model ), 'foo[' + modelTable( [ [ '00', '01', '02' ], @@ -561,7 +561,7 @@ describe( 'TableNavigation', () => { } ); it( 'should navigate to start position of the cell on the right when the direction is "right"', () => { - tableNavigation._navigateFromCellInDirection( tableCell, 'right' ); + tableKeyboard._navigateFromCellInDirection( tableCell, 'right' ); assertEqualMarkup( getModelData( model ), 'foo' + modelTable( [ [ '00', '01', '02' ], @@ -571,7 +571,7 @@ describe( 'TableNavigation', () => { } ); it( 'should navigate to the end position of the cell above when the direction is "up"', () => { - tableNavigation._navigateFromCellInDirection( tableCell, 'up' ); + tableKeyboard._navigateFromCellInDirection( tableCell, 'up' ); assertEqualMarkup( getModelData( model ), 'foo' + modelTable( [ [ '00[]', '01', '02' ], @@ -581,7 +581,7 @@ describe( 'TableNavigation', () => { } ); it( 'should navigate to the start position of the cell below when the direction is "down"', () => { - tableNavigation._navigateFromCellInDirection( tableCell, 'down' ); + tableKeyboard._navigateFromCellInDirection( tableCell, 'down' ); assertEqualMarkup( getModelData( model ), 'foo' + modelTable( [ [ '00', '01', '02' ], @@ -591,7 +591,7 @@ describe( 'TableNavigation', () => { } ); it( 'should navigate to the end position of the last cell in the previous row when the direction is "left"', () => { - tableNavigation._navigateFromCellInDirection( tableCell, 'left' ); + tableKeyboard._navigateFromCellInDirection( tableCell, 'left' ); assertEqualMarkup( getModelData( model ), 'foo' + modelTable( [ [ '00', '01', '02[]' ], @@ -609,7 +609,7 @@ describe( 'TableNavigation', () => { } ); it( 'should navigate to the end position of the cell on the left when the direction is "left"', () => { - tableNavigation._navigateFromCellInDirection( tableCell, 'left' ); + tableKeyboard._navigateFromCellInDirection( tableCell, 'left' ); assertEqualMarkup( getModelData( model ), 'foo' + modelTable( [ [ '00', '01', '02' ], @@ -619,7 +619,7 @@ describe( 'TableNavigation', () => { } ); it( 'should navigate to the end position the cell above when the direction is "up"', () => { - tableNavigation._navigateFromCellInDirection( tableCell, 'up' ); + tableKeyboard._navigateFromCellInDirection( tableCell, 'up' ); assertEqualMarkup( getModelData( model ), 'foo' + modelTable( [ [ '00', '01', '02[]' ], @@ -629,7 +629,7 @@ describe( 'TableNavigation', () => { } ); it( 'should navigate to the start position of the cell below when the direction is "down"', () => { - tableNavigation._navigateFromCellInDirection( tableCell, 'down' ); + tableKeyboard._navigateFromCellInDirection( tableCell, 'down' ); assertEqualMarkup( getModelData( model ), 'foo' + modelTable( [ [ '00', '01', '02' ], @@ -639,7 +639,7 @@ describe( 'TableNavigation', () => { } ); it( 'should navigate to the start position of the first cell in the next row when the direction is "right"', () => { - tableNavigation._navigateFromCellInDirection( tableCell, 'right' ); + tableKeyboard._navigateFromCellInDirection( tableCell, 'right' ); assertEqualMarkup( getModelData( model ), 'foo' + modelTable( [ [ '00', '01', '02' ], @@ -676,7 +676,7 @@ describe( 'TableNavigation', () => { it( 'should navigate to the row-col-spanned cell when approaching from the upper-spanned row', () => { const tableCell = modelRoot.getNodeByPath( [ 0, 1, 0 ] ); - tableNavigation._navigateFromCellInDirection( tableCell, 'right' ); + tableKeyboard._navigateFromCellInDirection( tableCell, 'right' ); assertEqualMarkup( getModelData( model ), modelTable( [ [ '00', '01', '02', '03', '04' ], @@ -690,7 +690,7 @@ describe( 'TableNavigation', () => { it( 'should navigate to the row-col-spanned cell when approaching from the lower-spanned row', () => { const tableCell = modelRoot.getNodeByPath( [ 0, 2, 0 ] ); - tableNavigation._navigateFromCellInDirection( tableCell, 'right' ); + tableKeyboard._navigateFromCellInDirection( tableCell, 'right' ); assertEqualMarkup( getModelData( model ), modelTable( [ [ '00', '01', '02', '03', '04' ], @@ -704,7 +704,7 @@ describe( 'TableNavigation', () => { it( 'should navigate to the row-spanned cell when approaching from the other row-spanned cell', () => { const tableCell = modelRoot.getNodeByPath( [ 0, 1, 1 ] ); - tableNavigation._navigateFromCellInDirection( tableCell, 'right' ); + tableKeyboard._navigateFromCellInDirection( tableCell, 'right' ); assertEqualMarkup( getModelData( model ), modelTable( [ [ '00', '01', '02', '03', '04' ], @@ -718,7 +718,7 @@ describe( 'TableNavigation', () => { it( 'should navigate to the cell in the upper-spanned row when approaching from the row-spanned cell', () => { const tableCell = modelRoot.getNodeByPath( [ 0, 1, 2 ] ); // Cell 13. - tableNavigation._navigateFromCellInDirection( tableCell, 'right' ); + tableKeyboard._navigateFromCellInDirection( tableCell, 'right' ); assertEqualMarkup( getModelData( model ), modelTable( [ [ '00', '01', '02', '03', '04' ], @@ -732,7 +732,7 @@ describe( 'TableNavigation', () => { it( 'should navigate to the col-spanned cell', () => { const tableCell = modelRoot.getNodeByPath( [ 0, 3, 0 ] ); - tableNavigation._navigateFromCellInDirection( tableCell, 'right' ); + tableKeyboard._navigateFromCellInDirection( tableCell, 'right' ); assertEqualMarkup( getModelData( model ), modelTable( [ [ '00', '01', '02', '03', '04' ], @@ -746,7 +746,7 @@ describe( 'TableNavigation', () => { it( 'should navigate from the col-spanned cell', () => { const tableCell = modelRoot.getNodeByPath( [ 0, 3, 1 ] ); - tableNavigation._navigateFromCellInDirection( tableCell, 'right' ); + tableKeyboard._navigateFromCellInDirection( tableCell, 'right' ); assertEqualMarkup( getModelData( model ), modelTable( [ [ '00', '01', '02', '03', '04' ], @@ -762,7 +762,7 @@ describe( 'TableNavigation', () => { it( 'should navigate to the row-spanned cell when approaching from the upper-spanned row', () => { const tableCell = modelRoot.getNodeByPath( [ 0, 1, 3 ] ); // Cell 14. - tableNavigation._navigateFromCellInDirection( tableCell, 'left' ); + tableKeyboard._navigateFromCellInDirection( tableCell, 'left' ); assertEqualMarkup( getModelData( model ), modelTable( [ [ '00', '01', '02', '03', '04' ], @@ -776,7 +776,7 @@ describe( 'TableNavigation', () => { it( 'should navigate to the row-spanned cell when approaching from the lower-spanned row', () => { const tableCell = modelRoot.getNodeByPath( [ 0, 2, 1 ] ); // Cell 24. - tableNavigation._navigateFromCellInDirection( tableCell, 'left' ); + tableKeyboard._navigateFromCellInDirection( tableCell, 'left' ); assertEqualMarkup( getModelData( model ), modelTable( [ [ '00', '01', '02', '03', '04' ], @@ -790,7 +790,7 @@ describe( 'TableNavigation', () => { it( 'should navigate to the row-spanned cell when approaching from the other row-spanned cell', () => { const tableCell = modelRoot.getNodeByPath( [ 0, 1, 2 ] ); // Cell 13. - tableNavigation._navigateFromCellInDirection( tableCell, 'left' ); + tableKeyboard._navigateFromCellInDirection( tableCell, 'left' ); assertEqualMarkup( getModelData( model ), modelTable( [ [ '00', '01', '02', '03', '04' ], @@ -804,7 +804,7 @@ describe( 'TableNavigation', () => { it( 'should navigate to the cell in the upper-spanned row when approaching from the row-spanned cell', () => { const tableCell = modelRoot.getNodeByPath( [ 0, 1, 1 ] ); // Cell 11. - tableNavigation._navigateFromCellInDirection( tableCell, 'left' ); + tableKeyboard._navigateFromCellInDirection( tableCell, 'left' ); assertEqualMarkup( getModelData( model ), modelTable( [ [ '00', '01', '02', '03', '04' ], @@ -818,7 +818,7 @@ describe( 'TableNavigation', () => { it( 'should navigate to the col-spanned cell', () => { const tableCell = modelRoot.getNodeByPath( [ 0, 3, 2 ] ); // Cell 33. - tableNavigation._navigateFromCellInDirection( tableCell, 'left' ); + tableKeyboard._navigateFromCellInDirection( tableCell, 'left' ); assertEqualMarkup( getModelData( model ), modelTable( [ [ '00', '01', '02', '03', '04' ], @@ -832,7 +832,7 @@ describe( 'TableNavigation', () => { it( 'should navigate from the col-spanned cell', () => { const tableCell = modelRoot.getNodeByPath( [ 0, 3, 1 ] ); - tableNavigation._navigateFromCellInDirection( tableCell, 'left' ); + tableKeyboard._navigateFromCellInDirection( tableCell, 'left' ); assertEqualMarkup( getModelData( model ), modelTable( [ [ '00', '01', '02', '03', '04' ], @@ -848,7 +848,7 @@ describe( 'TableNavigation', () => { it( 'should navigate to the row-col-spanned cell when approaching from the first spanned column', () => { const tableCell = modelRoot.getNodeByPath( [ 0, 0, 1 ] ); - tableNavigation._navigateFromCellInDirection( tableCell, 'down' ); + tableKeyboard._navigateFromCellInDirection( tableCell, 'down' ); assertEqualMarkup( getModelData( model ), modelTable( [ [ '00', '01', '02', '03', '04' ], @@ -862,7 +862,7 @@ describe( 'TableNavigation', () => { it( 'should navigate to the row-col-spanned cell when approaching from the last spanned column', () => { const tableCell = modelRoot.getNodeByPath( [ 0, 0, 2 ] ); - tableNavigation._navigateFromCellInDirection( tableCell, 'down' ); + tableKeyboard._navigateFromCellInDirection( tableCell, 'down' ); assertEqualMarkup( getModelData( model ), modelTable( [ [ '00', '01', '02', '03', '04' ], @@ -876,7 +876,7 @@ describe( 'TableNavigation', () => { it( 'should navigate to the row-spanned cell when approaching from the other col-spanned cell', () => { const tableCell = modelRoot.getNodeByPath( [ 0, 1, 1 ] ); - tableNavigation._navigateFromCellInDirection( tableCell, 'down' ); + tableKeyboard._navigateFromCellInDirection( tableCell, 'down' ); assertEqualMarkup( getModelData( model ), modelTable( [ [ '00', '01', '02', '03', '04' ], @@ -890,7 +890,7 @@ describe( 'TableNavigation', () => { it( 'should navigate to the cell in the first spanned column when approaching from the col-spanned cell', () => { const tableCell = modelRoot.getNodeByPath( [ 0, 1, 1 ] ); // Cell 11. - tableNavigation._navigateFromCellInDirection( tableCell, 'down' ); + tableKeyboard._navigateFromCellInDirection( tableCell, 'down' ); assertEqualMarkup( getModelData( model ), modelTable( [ [ '00', '01', '02', '03', '04' ], @@ -904,7 +904,7 @@ describe( 'TableNavigation', () => { it( 'should navigate to the row-spanned cell', () => { const tableCell = modelRoot.getNodeByPath( [ 0, 0, 3 ] ); - tableNavigation._navigateFromCellInDirection( tableCell, 'down' ); + tableKeyboard._navigateFromCellInDirection( tableCell, 'down' ); assertEqualMarkup( getModelData( model ), modelTable( [ [ '00', '01', '02', '03', '04' ], @@ -918,7 +918,7 @@ describe( 'TableNavigation', () => { it( 'should navigate from the row-spanned cell', () => { const tableCell = modelRoot.getNodeByPath( [ 0, 1, 2 ] ); // Cell 13. - tableNavigation._navigateFromCellInDirection( tableCell, 'down' ); + tableKeyboard._navigateFromCellInDirection( tableCell, 'down' ); assertEqualMarkup( getModelData( model ), modelTable( [ [ '00', '01', '02', '03', '04' ], @@ -934,7 +934,7 @@ describe( 'TableNavigation', () => { it( 'should navigate to the col-spanned cell when approaching from the first spanned column', () => { const tableCell = modelRoot.getNodeByPath( [ 0, 4, 1 ] ); - tableNavigation._navigateFromCellInDirection( tableCell, 'up' ); + tableKeyboard._navigateFromCellInDirection( tableCell, 'up' ); assertEqualMarkup( getModelData( model ), modelTable( [ [ '00', '01', '02', '03', '04' ], @@ -948,7 +948,7 @@ describe( 'TableNavigation', () => { it( 'should navigate to the col-spanned cell when approaching from the last spanned column', () => { const tableCell = modelRoot.getNodeByPath( [ 0, 4, 2 ] ); - tableNavigation._navigateFromCellInDirection( tableCell, 'up' ); + tableKeyboard._navigateFromCellInDirection( tableCell, 'up' ); assertEqualMarkup( getModelData( model ), modelTable( [ [ '00', '01', '02', '03', '04' ], @@ -962,7 +962,7 @@ describe( 'TableNavigation', () => { it( 'should navigate to the row-col-spanned cell when approaching from the other col-spanned cell', () => { const tableCell = modelRoot.getNodeByPath( [ 0, 3, 1 ] ); - tableNavigation._navigateFromCellInDirection( tableCell, 'up' ); + tableKeyboard._navigateFromCellInDirection( tableCell, 'up' ); assertEqualMarkup( getModelData( model ), modelTable( [ [ '00', '01', '02', '03', '04' ], @@ -976,7 +976,7 @@ describe( 'TableNavigation', () => { it( 'should navigate to the cell in the first spanned column when approaching from the col-spanned cell', () => { const tableCell = modelRoot.getNodeByPath( [ 0, 1, 1 ] ); - tableNavigation._navigateFromCellInDirection( tableCell, 'up' ); + tableKeyboard._navigateFromCellInDirection( tableCell, 'up' ); assertEqualMarkup( getModelData( model ), modelTable( [ [ '00', '01[]', '02', '03', '04' ], @@ -990,7 +990,7 @@ describe( 'TableNavigation', () => { it( 'should navigate to the row-spanned cell', () => { const tableCell = modelRoot.getNodeByPath( [ 0, 3, 2 ] ); // Cell 33. - tableNavigation._navigateFromCellInDirection( tableCell, 'up' ); + tableKeyboard._navigateFromCellInDirection( tableCell, 'up' ); assertEqualMarkup( getModelData( model ), modelTable( [ [ '00', '01', '02', '03', '04' ], @@ -1004,7 +1004,7 @@ describe( 'TableNavigation', () => { it( 'should navigate from the row-spanned cell', () => { const tableCell = modelRoot.getNodeByPath( [ 0, 1, 2 ] ); // Cell 13. - tableNavigation._navigateFromCellInDirection( tableCell, 'up' ); + tableKeyboard._navigateFromCellInDirection( tableCell, 'up' ); assertEqualMarkup( getModelData( model ), modelTable( [ [ '00', '01', '02', '03[]', '04' ], @@ -1034,7 +1034,7 @@ describe( 'TableNavigation', () => { } ); it( 'should expand the selection to the cell on the right when the direction is "right"', () => { - tableNavigation._navigateFromCellInDirection( tableCell, 'right', true ); + tableKeyboard._navigateFromCellInDirection( tableCell, 'right', true ); expect( tableSelection.getAnchorCell() ).to.equal( tableCell ); expect( tableSelection.getFocusCell() ).to.equal( modelRoot.getNodeByPath( [ 0, 0, 1 ] ) ); @@ -1042,7 +1042,7 @@ describe( 'TableNavigation', () => { } ); it( 'should expand the selection to the cell below when the direction is "down"', () => { - tableNavigation._navigateFromCellInDirection( tableCell, 'down', true ); + tableKeyboard._navigateFromCellInDirection( tableCell, 'down', true ); expect( tableSelection.getAnchorCell() ).to.equal( tableCell ); expect( tableSelection.getFocusCell() ).to.equal( modelRoot.getNodeByPath( [ 0, 1, 0 ] ) ); @@ -1050,7 +1050,7 @@ describe( 'TableNavigation', () => { } ); it( 'should select a whole table when the direction is "up"', () => { - tableNavigation._navigateFromCellInDirection( tableCell, 'up', true ); + tableKeyboard._navigateFromCellInDirection( tableCell, 'up', true ); assertEqualMarkup( getModelData( model ), '[' + modelTable( [ [ '00', '01', '02' ], @@ -1060,7 +1060,7 @@ describe( 'TableNavigation', () => { } ); it( 'should select a whole table when the direction is "left"', () => { - tableNavigation._navigateFromCellInDirection( tableCell, 'left', true ); + tableKeyboard._navigateFromCellInDirection( tableCell, 'left', true ); assertEqualMarkup( getModelData( model ), '[' + modelTable( [ [ '00', '01', '02' ], @@ -1079,7 +1079,7 @@ describe( 'TableNavigation', () => { } ); it( 'should expand the selection to the cell on the left when the direction is "left"', () => { - tableNavigation._navigateFromCellInDirection( tableCell, 'left', true ); + tableKeyboard._navigateFromCellInDirection( tableCell, 'left', true ); expect( tableSelection.getAnchorCell() ).to.equal( tableCell ); expect( tableSelection.getFocusCell() ).to.equal( modelRoot.getNodeByPath( [ 0, 2, 1 ] ) ); @@ -1087,7 +1087,7 @@ describe( 'TableNavigation', () => { } ); it( 'should expand the selection to the cell above when the direction is "up"', () => { - tableNavigation._navigateFromCellInDirection( tableCell, 'up', true ); + tableKeyboard._navigateFromCellInDirection( tableCell, 'up', true ); expect( tableSelection.getAnchorCell() ).to.equal( tableCell ); expect( tableSelection.getFocusCell() ).to.equal( modelRoot.getNodeByPath( [ 0, 1, 2 ] ) ); @@ -1095,7 +1095,7 @@ describe( 'TableNavigation', () => { } ); it( 'should select a whole table when the direction is "down"', () => { - tableNavigation._navigateFromCellInDirection( tableCell, 'down', true ); + tableKeyboard._navigateFromCellInDirection( tableCell, 'down', true ); assertEqualMarkup( getModelData( model ), '[' + modelTable( [ [ '00', '01', '02' ], @@ -1105,7 +1105,7 @@ describe( 'TableNavigation', () => { } ); it( 'should select a whole table when the direction is "right"', () => { - tableNavigation._navigateFromCellInDirection( tableCell, 'right', true ); + tableKeyboard._navigateFromCellInDirection( tableCell, 'right', true ); assertEqualMarkup( getModelData( model ), '[' + modelTable( [ [ '00', '01', '02' ], @@ -1124,7 +1124,7 @@ describe( 'TableNavigation', () => { } ); it( 'should expand the selection to the cell on the right when the direction is "right"', () => { - tableNavigation._navigateFromCellInDirection( tableCell, 'right', true ); + tableKeyboard._navigateFromCellInDirection( tableCell, 'right', true ); expect( tableSelection.getAnchorCell() ).to.equal( tableCell ); expect( tableSelection.getFocusCell() ).to.equal( modelRoot.getNodeByPath( [ 0, 1, 1 ] ) ); @@ -1132,7 +1132,7 @@ describe( 'TableNavigation', () => { } ); it( 'should expand the selection to the cell above when the direction is "up"', () => { - tableNavigation._navigateFromCellInDirection( tableCell, 'up', true ); + tableKeyboard._navigateFromCellInDirection( tableCell, 'up', true ); expect( tableSelection.getAnchorCell() ).to.equal( tableCell ); expect( tableSelection.getFocusCell() ).to.equal( modelRoot.getNodeByPath( [ 0, 0, 0 ] ) ); @@ -1140,7 +1140,7 @@ describe( 'TableNavigation', () => { } ); it( 'should expand the selection to the cell below when the direction is "down"', () => { - tableNavigation._navigateFromCellInDirection( tableCell, 'down', true ); + tableKeyboard._navigateFromCellInDirection( tableCell, 'down', true ); expect( tableSelection.getAnchorCell() ).to.equal( tableCell ); expect( tableSelection.getFocusCell() ).to.equal( modelRoot.getNodeByPath( [ 0, 2, 0 ] ) ); @@ -1148,7 +1148,7 @@ describe( 'TableNavigation', () => { } ); it( 'should expand the selection to the cell above when the direction is "left"', () => { - tableNavigation._navigateFromCellInDirection( tableCell, 'left', true ); + tableKeyboard._navigateFromCellInDirection( tableCell, 'left', true ); expect( tableSelection.getAnchorCell() ).to.equal( tableCell ); expect( tableSelection.getFocusCell() ).to.equal( modelRoot.getNodeByPath( [ 0, 0, 0 ] ) ); @@ -1165,7 +1165,7 @@ describe( 'TableNavigation', () => { } ); it( 'should expand the selection to the cell on the left when the direction is "left"', () => { - tableNavigation._navigateFromCellInDirection( tableCell, 'left', true ); + tableKeyboard._navigateFromCellInDirection( tableCell, 'left', true ); expect( tableSelection.getAnchorCell() ).to.equal( tableCell ); expect( tableSelection.getFocusCell() ).to.equal( modelRoot.getNodeByPath( [ 0, 1, 1 ] ) ); @@ -1173,7 +1173,7 @@ describe( 'TableNavigation', () => { } ); it( 'should expand the selection to the cell above when the direction is "up"', () => { - tableNavigation._navigateFromCellInDirection( tableCell, 'up', true ); + tableKeyboard._navigateFromCellInDirection( tableCell, 'up', true ); expect( tableSelection.getAnchorCell() ).to.equal( tableCell ); expect( tableSelection.getFocusCell() ).to.equal( modelRoot.getNodeByPath( [ 0, 0, 2 ] ) ); @@ -1181,7 +1181,7 @@ describe( 'TableNavigation', () => { } ); it( 'should expand the selection to the cell below when the direction is "down"', () => { - tableNavigation._navigateFromCellInDirection( tableCell, 'down', true ); + tableKeyboard._navigateFromCellInDirection( tableCell, 'down', true ); expect( tableSelection.getAnchorCell() ).to.equal( tableCell ); expect( tableSelection.getFocusCell() ).to.equal( modelRoot.getNodeByPath( [ 0, 2, 2 ] ) ); @@ -1189,7 +1189,7 @@ describe( 'TableNavigation', () => { } ); it( 'should expand the selection to the cell below when the direction is "right"', () => { - tableNavigation._navigateFromCellInDirection( tableCell, 'right', true ); + tableKeyboard._navigateFromCellInDirection( tableCell, 'right', true ); expect( tableSelection.getAnchorCell() ).to.equal( tableCell ); expect( tableSelection.getFocusCell() ).to.equal( modelRoot.getNodeByPath( [ 0, 2, 2 ] ) ); @@ -2979,7 +2979,7 @@ describe( 'TableNavigation', () => { beforeEach( () => { return VirtualTestEditor .create( { - plugins: [ TableEditing, TableNavigation, TableSelection, Paragraph, ImageEditing, MediaEmbedEditing ], + plugins: [ TableEditing, TableKeyboard, TableSelection, Paragraph, ImageEditing, MediaEmbedEditing ], language: 'ar' } ) .then( newEditor => { From b362e2454c2281e6b18ac26e96a230f08e1c0219 Mon Sep 17 00:00:00 2001 From: Kuba Niegowski Date: Mon, 1 Jun 2020 15:24:15 +0200 Subject: [PATCH 2/3] Extracted mouse handlers from the TableSelection plugin to the new TableMouse plugin. --- packages/ckeditor5-table/src/table.js | 3 +- packages/ckeditor5-table/src/tablemouse.js | 223 +++++++ .../mouseeventsobserver.js | 0 .../ckeditor5-table/src/tableselection.js | 176 +----- packages/ckeditor5-table/tests/table.js | 7 +- .../{tablenavigation.js => tablekeyboard.js} | 0 packages/ckeditor5-table/tests/tablemouse.js | 569 ++++++++++++++++++ .../ckeditor5-table/tests/tableselection.js | 513 +--------------- .../tableselection/mouseeventsobserver.js | 2 +- 9 files changed, 808 insertions(+), 685 deletions(-) create mode 100644 packages/ckeditor5-table/src/tablemouse.js rename packages/ckeditor5-table/src/{tableselection => tablemouse}/mouseeventsobserver.js (100%) rename packages/ckeditor5-table/tests/{tablenavigation.js => tablekeyboard.js} (100%) create mode 100644 packages/ckeditor5-table/tests/tablemouse.js diff --git a/packages/ckeditor5-table/src/table.js b/packages/ckeditor5-table/src/table.js index 8bd1d5ed9bc..119fb78da9a 100644 --- a/packages/ckeditor5-table/src/table.js +++ b/packages/ckeditor5-table/src/table.js @@ -14,6 +14,7 @@ import TableUI from './tableui'; import TableSelection from './tableselection'; import TableClipboard from './tableclipboard'; import TableKeyboard from './tablekeyboard'; +import TableMouse from './tablemouse'; import Widget from '@ckeditor/ckeditor5-widget/src/widget'; import '../theme/table.css'; @@ -38,7 +39,7 @@ export default class Table extends Plugin { * @inheritDoc */ static get requires() { - return [ TableEditing, TableUI, TableSelection, TableClipboard, TableKeyboard, Widget ]; + return [ TableEditing, TableUI, TableSelection, TableMouse, TableKeyboard, TableClipboard, Widget ]; } /** diff --git a/packages/ckeditor5-table/src/tablemouse.js b/packages/ckeditor5-table/src/tablemouse.js new file mode 100644 index 00000000000..94d5f783c8a --- /dev/null +++ b/packages/ckeditor5-table/src/tablemouse.js @@ -0,0 +1,223 @@ +/** + * @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/tablemouse + */ + +import Plugin from '@ckeditor/ckeditor5-core/src/plugin'; + +import TableSelection from './tableselection'; +import MouseEventsObserver from './tablemouse/mouseeventsobserver'; + +import { findAncestor } from './utils/common'; +import { getTableCellsContainingSelection } from './utils/selection'; + +/** + * This plugin enables a table cells' selection with the mouse. + * It is loaded automatically by the {@link module:table/table~Table} plugin. + * + * @extends module:core/plugin~Plugin + */ +export default class TableMouse extends Plugin { + /** + * @inheritDoc + */ + static get pluginName() { + return 'TableMouse'; + } + + /** + * @inheritDoc + */ + static get requires() { + return [ TableSelection ]; + } + + /** + * @inheritDoc + */ + init() { + const editor = this.editor; + + // Currently the MouseObserver only handles `mouseup` events. + // TODO move to the engine? + editor.editing.view.addObserver( MouseEventsObserver ); + + this._enableShiftClickSelection(); + this._enableMouseDragSelection(); + } + + /** + * Enables making cells selection by Shift+click. Creates a selection from the cell which previously held + * the selection to the cell which was clicked. It can be the same cell, in which case it selects a single cell. + * + * @private + */ + _enableShiftClickSelection() { + const editor = this.editor; + let blockSelectionChange = false; + + const tableSelection = editor.plugins.get( TableSelection ); + + this.listenTo( editor.editing.view.document, 'mousedown', ( evt, domEventData ) => { + if ( !this.isEnabled || !tableSelection.isEnabled ) { + return; + } + + if ( !domEventData.domEvent.shiftKey ) { + return; + } + + const anchorCell = tableSelection.getAnchorCell() || getTableCellsContainingSelection( editor.model.document.selection )[ 0 ]; + + if ( !anchorCell ) { + return; + } + + const targetCell = this._getModelTableCellFromDomEvent( domEventData ); + + if ( targetCell && haveSameTableParent( anchorCell, targetCell ) ) { + blockSelectionChange = true; + tableSelection.setCellSelection( anchorCell, targetCell ); + + domEventData.preventDefault(); + } + } ); + + this.listenTo( editor.editing.view.document, 'mouseup', () => { + blockSelectionChange = false; + } ); + + // We need to ignore a `selectionChange` event that is fired after we render our new table cells selection. + // When downcasting table cells selection to the view, we put the view selection in the last selected cell + // in a place that may not be natively a "correct" location. This is – we put it directly in the `` element. + // All browsers fire the native `selectionchange` event. + // However, all browsers except Safari return the selection in the exact place where we put it + // (even though it's visually normalized). Safari returns `

^foo` that makes our selection observer + // fire our `selectionChange` event (because the view selection that we set in the first step differs from the DOM selection). + // Since `selectionChange` is fired, we automatically update the model selection that moves it that paragraph. + // This breaks our dear cells selection. + // + // Theoretically this issue concerns only Safari that is the only browser that do normalize the selection. + // However, to avoid code branching and to have a good coverage for this event blocker, I enabled it for all browsers. + // + // Note: I'm keeping the `blockSelectionChange` state separately for shift+click and mouse drag (exact same logic) + // so I don't have to try to analyze whether they don't overlap in some weird cases. Probably they don't. + // But I have other things to do, like writing this comment. + this.listenTo( editor.editing.view.document, 'selectionChange', evt => { + if ( blockSelectionChange ) { + // @if CK_DEBUG // console.log( 'Blocked selectionChange to avoid breaking table cells selection.' ); + + evt.stop(); + } + }, { priority: 'highest' } ); + } + + /** + * Enables making cells selection by dragging. + * + * The selection is made only on mousemove. Mouse tracking is started on mousedown. + * However, the cells selection is enabled only after the mouse cursor left the anchor cell. + * Thanks to that normal text selection within one cell works just fine. However, you can still select + * just one cell by leaving the anchor cell and moving back to it. + * + * @private + */ + _enableMouseDragSelection() { + const editor = this.editor; + let anchorCell, targetCell; + let beganCellSelection = false; + let blockSelectionChange = false; + + const tableSelection = editor.plugins.get( TableSelection ); + + this.listenTo( editor.editing.view.document, 'mousedown', ( evt, domEventData ) => { + if ( !this.isEnabled || !tableSelection.isEnabled ) { + return; + } + + // Make sure to not conflict with the shift+click listener and any other possible handler. + if ( domEventData.domEvent.shiftKey || domEventData.domEvent.ctrlKey || domEventData.domEvent.altKey ) { + return; + } + + anchorCell = this._getModelTableCellFromDomEvent( domEventData ); + } ); + + this.listenTo( editor.editing.view.document, 'mousemove', ( evt, domEventData ) => { + if ( !domEventData.domEvent.buttons ) { + return; + } + + if ( !anchorCell ) { + return; + } + + const newTargetCell = this._getModelTableCellFromDomEvent( domEventData ); + + if ( newTargetCell && haveSameTableParent( anchorCell, newTargetCell ) ) { + targetCell = newTargetCell; + + // Switch to the cell selection mode after the mouse cursor left the anchor cell. + // Switch off only on mouseup (makes selecting a single cell possible). + if ( !beganCellSelection && targetCell != anchorCell ) { + beganCellSelection = true; + } + } + + // Yep, not making a cell selection yet. See method docs. + if ( !beganCellSelection ) { + return; + } + + blockSelectionChange = true; + tableSelection.setCellSelection( anchorCell, targetCell ); + + domEventData.preventDefault(); + } ); + + this.listenTo( editor.editing.view.document, 'mouseup', () => { + beganCellSelection = false; + blockSelectionChange = false; + anchorCell = null; + targetCell = null; + } ); + + // See the explanation in `_enableShiftClickSelection()`. + this.listenTo( editor.editing.view.document, 'selectionChange', evt => { + if ( blockSelectionChange ) { + // @if CK_DEBUG // console.log( 'Blocked selectionChange to avoid breaking table cells selection.' ); + + evt.stop(); + } + }, { priority: 'highest' } ); + } + + /** + * Returns the model table cell element based on the target element of the passed DOM event. + * + * @private + * @param {module:engine/view/observer/domeventdata~DomEventData} domEventData + * @returns {module:engine/model/element~Element|undefined} Returns the table cell or `undefined`. + */ + _getModelTableCellFromDomEvent( domEventData ) { + // Note: Work with positions (not element mapping) because the target element can be an attribute or other non-mapped element. + const viewTargetElement = domEventData.target; + const viewPosition = this.editor.editing.view.createPositionAt( viewTargetElement, 0 ); + const modelPosition = this.editor.editing.mapper.toModelPosition( viewPosition ); + const modelElement = modelPosition.parent; + + if ( modelElement.is( 'tableCell' ) ) { + return modelElement; + } + + return findAncestor( 'tableCell', modelElement ); + } +} + +function haveSameTableParent( cellA, cellB ) { + return cellA.parent.parent == cellB.parent.parent; +} diff --git a/packages/ckeditor5-table/src/tableselection/mouseeventsobserver.js b/packages/ckeditor5-table/src/tablemouse/mouseeventsobserver.js similarity index 100% rename from packages/ckeditor5-table/src/tableselection/mouseeventsobserver.js rename to packages/ckeditor5-table/src/tablemouse/mouseeventsobserver.js diff --git a/packages/ckeditor5-table/src/tableselection.js b/packages/ckeditor5-table/src/tableselection.js index 20d8fe75068..79578c7d112 100644 --- a/packages/ckeditor5-table/src/tableselection.js +++ b/packages/ckeditor5-table/src/tableselection.js @@ -12,11 +12,10 @@ import first from '@ckeditor/ckeditor5-utils/src/first'; import TableWalker from './tablewalker'; import TableUtils from './tableutils'; -import MouseEventsObserver from './tableselection/mouseeventsobserver'; import { findAncestor } from './utils/common'; import { cropTableToDimensions } from './utils/structure'; -import { getColumnIndexes, getRowIndexes, getSelectedTableCells, getTableCellsContainingSelection } from './utils/selection'; +import { getColumnIndexes, getRowIndexes, getSelectedTableCells } from './utils/selection'; import '../theme/tableselection.css'; @@ -50,13 +49,7 @@ export default class TableSelection extends Plugin { this.listenTo( model, 'deleteContent', ( evt, args ) => this._handleDeleteContent( evt, args ), { priority: 'high' } ); - // Currently the MouseObserver only handles `mouseup` events. - // TODO move to the engine? - editor.editing.view.addObserver( MouseEventsObserver ); - this._defineSelectionConverter(); - this._enableShiftClickSelection(); - this._enableMouseDragSelection(); this._enablePluginDisabling(); // sic! } @@ -223,148 +216,6 @@ export default class TableSelection extends Plugin { } } - /** - * Enables making cells selection by Shift+click. Creates a selection from the cell which previously held - * the selection to the cell which was clicked. It can be the same cell, in which case it selects a single cell. - * - * @private - */ - _enableShiftClickSelection() { - const editor = this.editor; - let blockSelectionChange = false; - - this.listenTo( editor.editing.view.document, 'mousedown', ( evt, domEventData ) => { - if ( !this.isEnabled ) { - return; - } - - if ( !domEventData.domEvent.shiftKey ) { - return; - } - - const anchorCell = this.getAnchorCell() || getTableCellsContainingSelection( editor.model.document.selection )[ 0 ]; - - if ( !anchorCell ) { - return; - } - - const targetCell = this._getModelTableCellFromDomEvent( domEventData ); - - if ( targetCell && haveSameTableParent( anchorCell, targetCell ) ) { - blockSelectionChange = true; - this.setCellSelection( anchorCell, targetCell ); - - domEventData.preventDefault(); - } - } ); - - this.listenTo( editor.editing.view.document, 'mouseup', () => { - blockSelectionChange = false; - } ); - - // We need to ignore a `selectionChange` event that is fired after we render our new table cells selection. - // When downcasting table cells selection to the view, we put the view selection in the last selected cell - // in a place that may not be natively a "correct" location. This is – we put it directly in the `` element. - // All browsers fire the native `selectionchange` event. - // However, all browsers except Safari return the selection in the exact place where we put it - // (even though it's visually normalized). Safari returns `

^foo` that makes our selection observer - // fire our `selectionChange` event (because the view selection that we set in the first step differs from the DOM selection). - // Since `selectionChange` is fired, we automatically update the model selection that moves it that paragraph. - // This breaks our dear cells selection. - // - // Theoretically this issue concerns only Safari that is the only browser that do normalize the selection. - // However, to avoid code branching and to have a good coverage for this event blocker, I enabled it for all browsers. - // - // Note: I'm keeping the `blockSelectionChange` state separately for shift+click and mouse drag (exact same logic) - // so I don't have to try to analyze whether they don't overlap in some weird cases. Probably they don't. - // But I have other things to do, like writing this comment. - this.listenTo( editor.editing.view.document, 'selectionChange', evt => { - if ( blockSelectionChange ) { - // @if CK_DEBUG // console.log( 'Blocked selectionChange to avoid breaking table cells selection.' ); - - evt.stop(); - } - }, { priority: 'highest' } ); - } - - /** - * Enables making cells selection by dragging. - * - * The selection is made only on mousemove. Mouse tracking is started on mousedown. - * However, the cells selection is enabled only after the mouse cursor left the anchor cell. - * Thanks to that normal text selection within one cell works just fine. However, you can still select - * just one cell by leaving the anchor cell and moving back to it. - * - * @private - */ - _enableMouseDragSelection() { - const editor = this.editor; - let anchorCell, targetCell; - let beganCellSelection = false; - let blockSelectionChange = false; - - this.listenTo( editor.editing.view.document, 'mousedown', ( evt, domEventData ) => { - if ( !this.isEnabled ) { - return; - } - - // Make sure to not conflict with the shift+click listener and any other possible handler. - if ( domEventData.domEvent.shiftKey || domEventData.domEvent.ctrlKey || domEventData.domEvent.altKey ) { - return; - } - - anchorCell = this._getModelTableCellFromDomEvent( domEventData ); - } ); - - this.listenTo( editor.editing.view.document, 'mousemove', ( evt, domEventData ) => { - if ( !domEventData.domEvent.buttons ) { - return; - } - - if ( !anchorCell ) { - return; - } - - const newTargetCell = this._getModelTableCellFromDomEvent( domEventData ); - - if ( newTargetCell && haveSameTableParent( anchorCell, newTargetCell ) ) { - targetCell = newTargetCell; - - // Switch to the cell selection mode after the mouse cursor left the anchor cell. - // Switch off only on mouseup (makes selecting a single cell possible). - if ( !beganCellSelection && targetCell != anchorCell ) { - beganCellSelection = true; - } - } - - // Yep, not making a cell selection yet. See method docs. - if ( !beganCellSelection ) { - return; - } - - blockSelectionChange = true; - this.setCellSelection( anchorCell, targetCell ); - - domEventData.preventDefault(); - } ); - - this.listenTo( editor.editing.view.document, 'mouseup', () => { - beganCellSelection = false; - blockSelectionChange = false; - anchorCell = null; - targetCell = null; - } ); - - // See the explanation in `_enableShiftClickSelection()`. - this.listenTo( editor.editing.view.document, 'selectionChange', evt => { - if ( blockSelectionChange ) { - // @if CK_DEBUG // console.log( 'Blocked selectionChange to avoid breaking table cells selection.' ); - - evt.stop(); - } - }, { priority: 'highest' } ); - } - /** * Creates a listener that reacts to changes in {@link #isEnabled} and, if the plugin was disabled, * it collapses the multi-cell selection to a regular selection placed inside a table cell. @@ -434,27 +285,6 @@ export default class TableSelection extends Plugin { } ); } - /** - * Returns the model table cell element based on the target element of the passed DOM event. - * - * @private - * @param {module:engine/view/observer/domeventdata~DomEventData} domEventData - * @returns {module:engine/model/element~Element|undefined} Returns the table cell or `undefined`. - */ - _getModelTableCellFromDomEvent( domEventData ) { - // Note: Work with positions (not element mapping) because the target element can be an attribute or other non-mapped element. - const viewTargetElement = domEventData.target; - const viewPosition = this.editor.editing.view.createPositionAt( viewTargetElement, 0 ); - const modelPosition = this.editor.editing.mapper.toModelPosition( viewPosition ); - const modelElement = modelPosition.parent; - - if ( modelElement.is( 'tableCell' ) ) { - return modelElement; - } - - return findAncestor( 'tableCell', modelElement ); - } - /** * Returns an array of table cells that should be selected based on the * given anchor cell and target (focus) cell. @@ -508,7 +338,3 @@ export default class TableSelection extends Plugin { }; } } - -function haveSameTableParent( cellA, cellB ) { - return cellA.parent.parent == cellB.parent.parent; -} diff --git a/packages/ckeditor5-table/tests/table.js b/packages/ckeditor5-table/tests/table.js index 0cc6043508d..21669c1bc0b 100644 --- a/packages/ckeditor5-table/tests/table.js +++ b/packages/ckeditor5-table/tests/table.js @@ -10,10 +10,13 @@ import TableSelection from '../src/tableselection'; import TableClipboard from '../src/tableclipboard'; import TableKeyboard from '../src/tablekeyboard'; import Widget from '@ckeditor/ckeditor5-widget/src/widget'; +import TableMouse from '../src/tablemouse'; describe( 'Table', () => { - it( 'requires TableEditing, TableUI, TableSelection, TableClipboard, TableKeyboard and Widget', () => { - expect( Table.requires ).to.deep.equal( [ TableEditing, TableUI, TableSelection, TableClipboard, TableKeyboard, Widget ] ); + it( 'requires TableEditing, TableUI, TableSelection, TableMouse, TableKeyboard, TableClipboard and Widget', () => { + expect( Table.requires ).to.deep.equal( [ + TableEditing, TableUI, TableSelection, TableMouse, TableKeyboard, TableClipboard, Widget + ] ); } ); it( 'has proper name', () => { diff --git a/packages/ckeditor5-table/tests/tablenavigation.js b/packages/ckeditor5-table/tests/tablekeyboard.js similarity index 100% rename from packages/ckeditor5-table/tests/tablenavigation.js rename to packages/ckeditor5-table/tests/tablekeyboard.js diff --git a/packages/ckeditor5-table/tests/tablemouse.js b/packages/ckeditor5-table/tests/tablemouse.js new file mode 100644 index 00000000000..3a378b32aaa --- /dev/null +++ b/packages/ckeditor5-table/tests/tablemouse.js @@ -0,0 +1,569 @@ +/** + * @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, console */ + +import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph'; +import ClassicTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/classictesteditor'; +import { setData as setModelData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model'; + +import TableEditing from '../src/tableediting'; +import TableSelection from '../src/tableselection'; +import TableMouse from '../src/tablemouse'; +import { assertSelectedCells, modelTable } from './_utils/utils'; +import DomEventData from '@ckeditor/ckeditor5-engine/src/view/observer/domeventdata'; +import Typing from '@ckeditor/ckeditor5-typing/src/typing'; + +describe( 'TableMouse', () => { + let editorElement, editor, model, tableMouse, modelRoot, view, viewDocument; + + beforeEach( () => { + editorElement = document.createElement( 'div' ); + document.body.appendChild( editorElement ); + } ); + + afterEach( async () => { + editorElement.remove(); + await editor.destroy(); + } ); + + describe( 'plugin', () => { + beforeEach( async () => { + editor = await createEditor(); + } ); + + it( 'should have pluginName', () => { + expect( TableMouse.pluginName ).to.equal( 'TableMouse' ); + } ); + } ); + + describe( 'selection by Shift+click', () => { + beforeEach( async () => { + editor = await createEditor(); + model = editor.model; + modelRoot = model.document.getRoot(); + view = editor.editing.view; + viewDocument = view.document; + tableMouse = editor.plugins.get( TableMouse ); + + setModelData( model, modelTable( [ + [ '11[]', '12', '13' ], + [ '21', '22', '23' ], + [ '31', '32', '33' ] + ] ) ); + } ); + + it( 'should do nothing if the plugin is disabled', () => { + tableMouse.isEnabled = false; + + viewDocument.fire( 'mousedown', new DomEventData( view, {} ) ); + + assertSelectedCells( model, [ + [ 0, 0, 0 ], + [ 0, 0, 0 ], + [ 0, 0, 0 ] + ] ); + } ); + + it( 'should do nothing if the TableSelection plugin is disabled', () => { + editor.plugins.get( 'TableSelection' ).isEnabled = false; + + viewDocument.fire( 'mousedown', new DomEventData( view, {} ) ); + + assertSelectedCells( model, [ + [ 0, 0, 0 ], + [ 0, 0, 0 ], + [ 0, 0, 0 ] + ] ); + } ); + + it( 'should abort if Shift key was not pressed', () => { + viewDocument.fire( 'mousedown', new DomEventData( view, { + shiftKey: false, + target: view.domConverter.mapViewToDom( + // figure > table > tbody > tr > td + viewDocument.getRoot().getChild( 0 ).getChild( 1 ).getChild( 0 ).getChild( 0 ).getChild( 2 ) + ) + } ) ); + + assertSelectedCells( model, [ + [ 0, 0, 0 ], + [ 0, 0, 0 ], + [ 0, 0, 0 ] + ] ); + } ); + + it( 'should abort if Shift+clicked an element outside a table', () => { + const preventDefault = sinon.spy(); + + model.change( writer => { + const paragraph = writer.createElement( 'paragraph' ); + const text = writer.createText( 'foo' ); + + writer.insert( text, paragraph ); + writer.insert( paragraph, model.document.getRoot(), 'end' ); + writer.setSelection( paragraph, 'end' ); + } ); + + viewDocument.fire( 'mousedown', new DomEventData( view, { + shiftKey: true, + target: view.domConverter.mapViewToDom( + viewDocument.getRoot().getChild( 1 ) + ), + preventDefault + } ) ); + + assertSelectedCells( model, [ + [ 0, 0, 0 ], + [ 0, 0, 0 ], + [ 0, 0, 0 ] + ] ); + + expect( preventDefault.called ).to.equal( false ); + } ); + + it( 'should abort if clicked a cell that belongs to another table', () => { + const preventDefault = sinon.spy(); + + setModelData( model, [ + modelTable( [ + [ '1.11[]', '1.12' ], + [ '1.21', '1.22' ] + ] ), + modelTable( [ + [ '2.11', '2.12' ], + [ '2.21', '2.22' ] + ] ) + ].join( '' ) ); + + const domEventDataMock = new DomEventData( view, { + shiftKey: true, + target: view.domConverter.mapViewToDom( + // The second table: figure > table > tbody > tr > td + viewDocument.getRoot().getChild( 1 ).getChild( 1 ).getChild( 0 ).getChild( 1 ).getChild( 1 ) + ), + preventDefault + } ); + + viewDocument.fire( 'mousedown', domEventDataMock ); + + assertSelectedCells( model, [ + [ 0, 0 ], + [ 0, 0 ] + ] ); + + expect( preventDefault.called ).to.equal( false ); + } ); + + it( 'should select all cells in first row', () => { + const preventDefault = sinon.spy(); + + const domEventDataMock = new DomEventData( view, { + shiftKey: true, + target: view.domConverter.mapViewToDom( + // figure > table > tbody > tr > td + viewDocument.getRoot().getChild( 0 ).getChild( 1 ).getChild( 0 ).getChild( 0 ).getChild( 2 ) + ), + preventDefault + } ); + + viewDocument.fire( 'mousedown', domEventDataMock ); + + assertSelectedCells( model, [ + [ 1, 1, 1 ], + [ 0, 0, 0 ], + [ 0, 0, 0 ] + ] ); + + expect( preventDefault.called ).to.equal( true ); + } ); + + it( 'should use the anchor cell from the selection if possible', () => { + const preventDefault = sinon.spy(); + + const domEventDataMock = new DomEventData( view, { + shiftKey: true, + target: view.domConverter.mapViewToDom( + // figure > table > tbody > tr > td + viewDocument.getRoot().getChild( 0 ).getChild( 1 ).getChild( 0 ).getChild( 0 ).getChild( 2 ) + ), + preventDefault + } ); + + editor.plugins.get( 'TableSelection' ).setCellSelection( + modelRoot.getNodeByPath( [ 0, 1, 0 ] ), + modelRoot.getNodeByPath( [ 0, 2, 1 ] ) + ); + assertSelectedCells( model, [ + [ 0, 0, 0 ], + [ 1, 1, 0 ], + [ 1, 1, 0 ] + ] ); + + viewDocument.fire( 'mousedown', domEventDataMock ); + + assertSelectedCells( model, [ + [ 1, 1, 1 ], + [ 1, 1, 1 ], + [ 0, 0, 0 ] + ] ); + + expect( preventDefault.called ).to.equal( true ); + } ); + + it( 'should ignore `selectionChange` event when selecting cells', () => { + const consoleLog = sinon.stub( console, 'log' ); + const preventDefault = sinon.spy(); + const selectionChangeCallback = sinon.spy(); + + // Adding a new callback to check whether it will be executed (whether `evt.stop()` is being called). + viewDocument.on( 'selectionChange', selectionChangeCallback ); + + // Shift+click a cell to create a selection. Should disable listening to `selectionChange`. + viewDocument.fire( 'mousedown', new DomEventData( view, { + shiftKey: true, + target: view.domConverter.mapViewToDom( + // figure > table > tbody > tr > td + viewDocument.getRoot().getChild( 0 ).getChild( 1 ).getChild( 0 ).getChild( 0 ).getChild( 2 ) + ), + preventDefault + } ) ); + + // Due to browsers "fixing" the selection (e.g. moving it to text nodes), after we set a selection + // the browser fill fire native selectionchange, which triggers our selectionChange. We need to ignore it. + // See a broader explanation in tablemouse.js. + viewDocument.fire( 'selectionChange' ); + + // The callback shouldn't be executed because + // `selectionChange` event should be canceled. + expect( selectionChangeCallback.called ).to.equal( false ); + expect( consoleLog.called ).to.equal( true ); + expect( consoleLog.firstCall.args[ 0 ] ).to.equal( 'Blocked selectionChange to avoid breaking table cells selection.' ); + + // Enables listening to `selectionChange` event. + viewDocument.fire( 'mouseup' ); + + viewDocument.fire( 'selectionChange', { + newSelection: view.document.selection + } ); + + expect( selectionChangeCallback.called ).to.equal( true ); + + consoleLog.restore(); + } ); + } ); + + describe( 'selection by mouse drag', () => { + let preventDefault; + + beforeEach( async () => { + editor = await createEditor(); + model = editor.model; + modelRoot = model.document.getRoot(); + view = editor.editing.view; + viewDocument = view.document; + tableMouse = editor.plugins.get( TableMouse ); + + setModelData( model, modelTable( [ + [ '11[]', '12', '13' ], + [ '21', '22', '23' ], + [ '31', '32', '33' ] + ] ) ); + + preventDefault = sinon.spy(); + } ); + + it( 'should do nothing if the plugin is disabled', () => { + tableMouse.isEnabled = false; + + const domEventDataMock = new DomEventData( view, {} ); + + viewDocument.fire( 'mousedown', domEventDataMock ); + + assertSelectedCells( model, [ + [ 0, 0, 0 ], + [ 0, 0, 0 ], + [ 0, 0, 0 ] + ] ); + } ); + + it( 'should do nothing if the TableSelection plugin is disabled', () => { + editor.plugins.get( 'TableSelection' ).isEnabled = false; + + const domEventDataMock = new DomEventData( view, {} ); + + viewDocument.fire( 'mousedown', domEventDataMock ); + + assertSelectedCells( model, [ + [ 0, 0, 0 ], + [ 0, 0, 0 ], + [ 0, 0, 0 ] + ] ); + } ); + + it( 'should abort if Ctrl is pressed', () => { + const domEventDataMock = new DomEventData( view, { + ctrlKey: true + } ); + + viewDocument.fire( 'mousedown', domEventDataMock ); + + assertSelectedCells( model, [ + [ 0, 0, 0 ], + [ 0, 0, 0 ], + [ 0, 0, 0 ] + ] ); + } ); + + it( 'should abort if Alt is pressed', () => { + const domEventDataMock = new DomEventData( view, { + altKey: true + } ); + + viewDocument.fire( 'mousedown', domEventDataMock ); + + assertSelectedCells( model, [ + [ 0, 0, 0 ], + [ 0, 0, 0 ], + [ 0, 0, 0 ] + ] ); + } ); + + it( 'should do nothing if any of mouse buttons was not clicked', () => { + viewDocument.fire( 'mousemove', new DomEventData( view, { + buttons: 0 + } ) ); + + assertSelectedCells( model, [ + [ 0, 0, 0 ], + [ 0, 0, 0 ], + [ 0, 0, 0 ] + ] ); + } ); + + it( 'should do nothing if started dragging outside of table', () => { + model.change( writer => { + const paragraph = writer.createElement( 'paragraph' ); + const text = writer.createText( 'foo' ); + + writer.insert( text, paragraph ); + writer.insert( paragraph, model.document.getRoot(), 'end' ); + writer.setSelection( paragraph, 'end' ); + } ); + + viewDocument.fire( 'mousedown', new DomEventData( view, { + target: view.domConverter.mapViewToDom( + viewDocument.getRoot().getChild( 1 ) + ) + } ) ); + + viewDocument.fire( 'mousemove', new DomEventData( view, { + buttons: 1 + } ) ); + + assertSelectedCells( model, [ + [ 0, 0, 0 ], + [ 0, 0, 0 ], + [ 0, 0, 0 ] + ] ); + } ); + + it( 'should do nothing if ended dragging outside of table', () => { + model.change( writer => { + const paragraph = writer.createElement( 'paragraph' ); + const text = writer.createText( 'foo' ); + + writer.insert( text, paragraph ); + writer.insert( paragraph, model.document.getRoot(), 'end' ); + writer.setSelection( paragraph, 'end' ); + } ); + + viewDocument.fire( 'mousedown', new DomEventData( view, { + target: view.domConverter.mapViewToDom( + viewDocument.getRoot().getChild( 0 ).getChild( 1 ).getChild( 0 ).getChild( 0 ).getChild( 0 ) + ) + } ) ); + + viewDocument.fire( 'mousemove', new DomEventData( view, { + target: view.domConverter.mapViewToDom( + viewDocument.getRoot().getChild( 1 ) + ), + buttons: 1 + } ) ); + + assertSelectedCells( model, [ + [ 0, 0, 0 ], + [ 0, 0, 0 ], + [ 0, 0, 0 ] + ] ); + } ); + + it( 'should do nothing if ended dragging inside another table', () => { + setModelData( model, [ + modelTable( [ + [ '1.11[]', '1.12' ], + [ '1.21', '1.22' ] + ] ), + modelTable( [ + [ '2.11', '2.12' ], + [ '2.21', '2.22' ] + ] ) + ].join( '' ) ); + + viewDocument.fire( 'mousedown', new DomEventData( view, { + target: view.domConverter.mapViewToDom( + viewDocument.getRoot().getChild( 0 ).getChild( 1 ).getChild( 0 ).getChild( 0 ).getChild( 0 ) + ) + } ) ); + + viewDocument.fire( 'mousemove', new DomEventData( view, { + target: view.domConverter.mapViewToDom( + viewDocument.getRoot().getChild( 1 ).getChild( 1 ).getChild( 0 ).getChild( 1 ).getChild( 1 ) + ), + buttons: 1 + } ) ); + + assertSelectedCells( model, [ + [ 0, 0 ], + [ 0, 0 ] + ] ); + } ); + + it( 'should do nothing if ended in the same cell', () => { + viewDocument.fire( 'mousedown', new DomEventData( view, { + target: view.domConverter.mapViewToDom( + viewDocument.getRoot().getChild( 0 ).getChild( 1 ).getChild( 0 ).getChild( 0 ).getChild( 0 ) + ) + } ) ); + + viewDocument.fire( 'mousemove', new DomEventData( view, { + target: view.domConverter.mapViewToDom( + viewDocument.getRoot().getChild( 0 ).getChild( 1 ).getChild( 0 ).getChild( 0 ).getChild( 0 ) + ), + buttons: 1 + } ) ); + + assertSelectedCells( model, [ + [ 0, 0, 0 ], + [ 0, 0, 0 ], + [ 0, 0, 0 ] + ] ); + } ); + + it( 'should select started and ended dragging in the same cell but went over its border', () => { + viewDocument.fire( 'mousedown', new DomEventData( view, { + target: view.domConverter.mapViewToDom( + viewDocument.getRoot().getChild( 0 ).getChild( 1 ).getChild( 0 ).getChild( 0 ).getChild( 0 ) + ) + } ) ); + + // Select the next one. + viewDocument.fire( 'mousemove', new DomEventData( view, { + target: view.domConverter.mapViewToDom( + viewDocument.getRoot().getChild( 0 ).getChild( 1 ).getChild( 0 ).getChild( 0 ).getChild( 1 ) + ), + buttons: 1, + preventDefault: sinon.spy() + } ) ); + + // And back to the "started" cell. + viewDocument.fire( 'mousemove', new DomEventData( view, { + target: view.domConverter.mapViewToDom( + viewDocument.getRoot().getChild( 0 ).getChild( 1 ).getChild( 0 ).getChild( 0 ).getChild( 0 ) + ), + buttons: 1, + preventDefault: sinon.spy() + } ) ); + + viewDocument.fire( 'mouseup' ); + + assertSelectedCells( model, [ + [ 1, 0, 0 ], + [ 0, 0, 0 ], + [ 0, 0, 0 ] + ] ); + } ); + + it( 'should select all cells in first row', () => { + viewDocument.fire( 'mousedown', new DomEventData( view, { + target: view.domConverter.mapViewToDom( + // figure > table > tbody > tr > td + viewDocument.getRoot().getChild( 0 ).getChild( 1 ).getChild( 0 ).getChild( 0 ).getChild( 0 ) + ) + } ) ); + + viewDocument.fire( 'mousemove', new DomEventData( view, { + target: view.domConverter.mapViewToDom( + // figure > table > tbody > tr > td + viewDocument.getRoot().getChild( 0 ).getChild( 1 ).getChild( 0 ).getChild( 0 ).getChild( 2 ) + ), + buttons: 1, + preventDefault + } ) ); + + viewDocument.fire( 'mouseup' ); + + assertSelectedCells( model, [ + [ 1, 1, 1 ], + [ 0, 0, 0 ], + [ 0, 0, 0 ] + ] ); + + expect( preventDefault.called ).to.equal( true ); + } ); + + it( 'should ignore `selectionChange` event when selecting cells ', () => { + const consoleLog = sinon.stub( console, 'log' ); + const preventDefault = sinon.spy(); + const selectionChangeCallback = sinon.spy(); + + // Adding a new callback to check whether it will be executed (whether `evt.stop()` is being called). + viewDocument.on( 'selectionChange', selectionChangeCallback ); + + // Click on a cell. + viewDocument.fire( 'mousedown', new DomEventData( view, { + target: view.domConverter.mapViewToDom( + // figure > table > tbody > tr > td + viewDocument.getRoot().getChild( 0 ).getChild( 1 ).getChild( 0 ).getChild( 0 ).getChild( 1 ) + ) + } ) ); + + // Then move the mouse to another cell. Disables listening to `selectionChange`. + viewDocument.fire( 'mousemove', new DomEventData( view, { + buttons: 1, + target: view.domConverter.mapViewToDom( + // figure > table > tbody > tr > td + viewDocument.getRoot().getChild( 0 ).getChild( 1 ).getChild( 0 ).getChild( 0 ).getChild( 2 ) + ), + preventDefault + } ) ); + + // See explanation why do we fire it in the similar test for Shift+click. + viewDocument.fire( 'selectionChange' ); + + // `selectionChange` event should be canceled. + expect( selectionChangeCallback.called ).to.equal( false ); + expect( consoleLog.called ).to.equal( true ); + expect( consoleLog.firstCall.args[ 0 ] ).to.equal( 'Blocked selectionChange to avoid breaking table cells selection.' ); + + // Enables listening to `selectionChange` event. + viewDocument.fire( 'mouseup' ); + + viewDocument.fire( 'selectionChange', { + newSelection: view.document.selection + } ); + + expect( selectionChangeCallback.called ).to.equal( true ); + + consoleLog.restore(); + } ); + } ); + + function createEditor() { + return ClassicTestEditor.create( editorElement, { + plugins: [ TableEditing, TableSelection, TableMouse, Paragraph, Typing ] + } ); + } +} ); diff --git a/packages/ckeditor5-table/tests/tableselection.js b/packages/ckeditor5-table/tests/tableselection.js index df8bef047b7..52199edfe1c 100644 --- a/packages/ckeditor5-table/tests/tableselection.js +++ b/packages/ckeditor5-table/tests/tableselection.js @@ -3,7 +3,7 @@ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license */ -/* globals document, console */ +/* globals document */ import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph'; import ClassicTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/classictesteditor'; @@ -17,12 +17,11 @@ import TableEditing from '../src/tableediting'; import TableSelection from '../src/tableselection'; import { assertSelectedCells, modelTable } from './_utils/utils'; import DocumentFragment from '@ckeditor/ckeditor5-engine/src/model/documentfragment'; -import DomEventData from '@ckeditor/ckeditor5-engine/src/view/observer/domeventdata'; import Typing from '@ckeditor/ckeditor5-typing/src/typing'; import { assertEqualMarkup } from '@ckeditor/ckeditor5-utils/tests/_utils/utils'; -describe( 'table selection', () => { - let editorElement, editor, model, tableSelection, modelRoot, view, viewDocument; +describe( 'TableSelection', () => { + let editorElement, editor, model, tableSelection, modelRoot; beforeEach( () => { editorElement = document.createElement( 'div' ); @@ -48,6 +47,10 @@ describe( 'table selection', () => { ] ) ); } ); + it( 'should have pluginName', () => { + expect( TableSelection.pluginName ).to.equal( 'TableSelection' ); + } ); + describe( 'plugin disabling support', () => { it( 'should collapse multi-cell selection when the plugin gets disabled', () => { const firstCell = modelRoot.getNodeByPath( [ 0, 0, 0 ] ); @@ -98,509 +101,11 @@ describe( 'table selection', () => { } ); } ); - describe( 'selection by Shift+click', () => { - beforeEach( async () => { - editor = await createEditor(); - model = editor.model; - modelRoot = model.document.getRoot(); - view = editor.editing.view; - viewDocument = view.document; - tableSelection = editor.plugins.get( TableSelection ); - - setModelData( model, modelTable( [ - [ '11[]', '12', '13' ], - [ '21', '22', '23' ], - [ '31', '32', '33' ] - ] ) ); - } ); - - it( 'should do nothing if the plugin is disabled', () => { - tableSelection.isEnabled = false; - - viewDocument.fire( 'mousedown', new DomEventData( view, {} ) ); - - assertSelectedCells( model, [ - [ 0, 0, 0 ], - [ 0, 0, 0 ], - [ 0, 0, 0 ] - ] ); - } ); - - it( 'should abort if Shift key was not pressed', () => { - viewDocument.fire( 'mousedown', new DomEventData( view, { - shiftKey: false, - target: view.domConverter.mapViewToDom( - // figure > table > tbody > tr > td - viewDocument.getRoot().getChild( 0 ).getChild( 1 ).getChild( 0 ).getChild( 0 ).getChild( 2 ) - ) - } ) ); - - assertSelectedCells( model, [ - [ 0, 0, 0 ], - [ 0, 0, 0 ], - [ 0, 0, 0 ] - ] ); - } ); - - it( 'should abort if Shift+clicked an element outside a table', () => { - const preventDefault = sinon.spy(); - - model.change( writer => { - const paragraph = writer.createElement( 'paragraph' ); - const text = writer.createText( 'foo' ); - - writer.insert( text, paragraph ); - writer.insert( paragraph, model.document.getRoot(), 'end' ); - writer.setSelection( paragraph, 'end' ); - } ); - - viewDocument.fire( 'mousedown', new DomEventData( view, { - shiftKey: true, - target: view.domConverter.mapViewToDom( - viewDocument.getRoot().getChild( 1 ) - ), - preventDefault - } ) ); - - assertSelectedCells( model, [ - [ 0, 0, 0 ], - [ 0, 0, 0 ], - [ 0, 0, 0 ] - ] ); - - expect( preventDefault.called ).to.equal( false ); - } ); - - it( 'should abort if clicked a cell that belongs to another table', () => { - const preventDefault = sinon.spy(); - - setModelData( model, [ - modelTable( [ - [ '1.11[]', '1.12' ], - [ '1.21', '1.22' ] - ] ), - modelTable( [ - [ '2.11', '2.12' ], - [ '2.21', '2.22' ] - ] ) - ].join( '' ) ); - - const domEventDataMock = new DomEventData( view, { - shiftKey: true, - target: view.domConverter.mapViewToDom( - // The second table: figure > table > tbody > tr > td - viewDocument.getRoot().getChild( 1 ).getChild( 1 ).getChild( 0 ).getChild( 1 ).getChild( 1 ) - ), - preventDefault - } ); - - viewDocument.fire( 'mousedown', domEventDataMock ); - - assertSelectedCells( model, [ - [ 0, 0 ], - [ 0, 0 ] - ] ); - - expect( preventDefault.called ).to.equal( false ); - } ); - - it( 'should select all cells in first row', () => { - const preventDefault = sinon.spy(); - - const domEventDataMock = new DomEventData( view, { - shiftKey: true, - target: view.domConverter.mapViewToDom( - // figure > table > tbody > tr > td - viewDocument.getRoot().getChild( 0 ).getChild( 1 ).getChild( 0 ).getChild( 0 ).getChild( 2 ) - ), - preventDefault - } ); - - viewDocument.fire( 'mousedown', domEventDataMock ); - - assertSelectedCells( model, [ - [ 1, 1, 1 ], - [ 0, 0, 0 ], - [ 0, 0, 0 ] - ] ); - - expect( preventDefault.called ).to.equal( true ); - } ); - - it( 'should use the anchor cell from the selection if possible', () => { - const preventDefault = sinon.spy(); - - const domEventDataMock = new DomEventData( view, { - shiftKey: true, - target: view.domConverter.mapViewToDom( - // figure > table > tbody > tr > td - viewDocument.getRoot().getChild( 0 ).getChild( 1 ).getChild( 0 ).getChild( 0 ).getChild( 2 ) - ), - preventDefault - } ); - - tableSelection.setCellSelection( - modelRoot.getNodeByPath( [ 0, 1, 0 ] ), - modelRoot.getNodeByPath( [ 0, 2, 1 ] ) - ); - assertSelectedCells( model, [ - [ 0, 0, 0 ], - [ 1, 1, 0 ], - [ 1, 1, 0 ] - ] ); - - viewDocument.fire( 'mousedown', domEventDataMock ); - - assertSelectedCells( model, [ - [ 1, 1, 1 ], - [ 1, 1, 1 ], - [ 0, 0, 0 ] - ] ); - - expect( preventDefault.called ).to.equal( true ); - } ); - - it( 'should ignore `selectionChange` event when selecting cells', () => { - const consoleLog = sinon.stub( console, 'log' ); - const preventDefault = sinon.spy(); - const selectionChangeCallback = sinon.spy(); - - // Adding a new callback to check whether it will be executed (whether `evt.stop()` is being called). - viewDocument.on( 'selectionChange', selectionChangeCallback ); - - // Shift+click a cell to create a selection. Should disable listening to `selectionChange`. - viewDocument.fire( 'mousedown', new DomEventData( view, { - shiftKey: true, - target: view.domConverter.mapViewToDom( - // figure > table > tbody > tr > td - viewDocument.getRoot().getChild( 0 ).getChild( 1 ).getChild( 0 ).getChild( 0 ).getChild( 2 ) - ), - preventDefault - } ) ); - - // Due to browsers "fixing" the selection (e.g. moving it to text nodes), after we set a selection - // the browser fill fire native selectionchange, which triggers our selectionChange. We need to ignore it. - // See a broader explanation in tableselection.js. - viewDocument.fire( 'selectionChange' ); - - // The callback shouldn't be executed because - // `selectionChange` event should be canceled. - expect( selectionChangeCallback.called ).to.equal( false ); - expect( consoleLog.called ).to.equal( true ); - expect( consoleLog.firstCall.args[ 0 ] ).to.equal( 'Blocked selectionChange to avoid breaking table cells selection.' ); - - // Enables listening to `selectionChange` event. - viewDocument.fire( 'mouseup' ); - - viewDocument.fire( 'selectionChange', { - newSelection: view.document.selection - } ); - - expect( selectionChangeCallback.called ).to.equal( true ); - - consoleLog.restore(); - } ); - } ); - - describe( 'selection by mouse drag', () => { - let preventDefault; - - beforeEach( async () => { - editor = await createEditor(); - model = editor.model; - modelRoot = model.document.getRoot(); - view = editor.editing.view; - viewDocument = view.document; - tableSelection = editor.plugins.get( TableSelection ); - - setModelData( model, modelTable( [ - [ '11[]', '12', '13' ], - [ '21', '22', '23' ], - [ '31', '32', '33' ] - ] ) ); - - preventDefault = sinon.spy(); - } ); - - it( 'should do nothing if the plugin is disabled', () => { - tableSelection.isEnabled = false; - - const domEventDataMock = new DomEventData( view, {} ); - - viewDocument.fire( 'mousedown', domEventDataMock ); - - assertSelectedCells( model, [ - [ 0, 0, 0 ], - [ 0, 0, 0 ], - [ 0, 0, 0 ] - ] ); - } ); - - it( 'should abort if Ctrl is pressed', () => { - const domEventDataMock = new DomEventData( view, { - ctrlKey: true - } ); - - viewDocument.fire( 'mousedown', domEventDataMock ); - - assertSelectedCells( model, [ - [ 0, 0, 0 ], - [ 0, 0, 0 ], - [ 0, 0, 0 ] - ] ); - } ); - - it( 'should abort if Alt is pressed', () => { - const domEventDataMock = new DomEventData( view, { - altKey: true - } ); - - viewDocument.fire( 'mousedown', domEventDataMock ); - - assertSelectedCells( model, [ - [ 0, 0, 0 ], - [ 0, 0, 0 ], - [ 0, 0, 0 ] - ] ); - } ); - - it( 'should do nothing if any of mouse buttons was not clicked', () => { - viewDocument.fire( 'mousemove', new DomEventData( view, { - buttons: 0 - } ) ); - - assertSelectedCells( model, [ - [ 0, 0, 0 ], - [ 0, 0, 0 ], - [ 0, 0, 0 ] - ] ); - } ); - - it( 'should do nothing if started dragging outside of table', () => { - model.change( writer => { - const paragraph = writer.createElement( 'paragraph' ); - const text = writer.createText( 'foo' ); - - writer.insert( text, paragraph ); - writer.insert( paragraph, model.document.getRoot(), 'end' ); - writer.setSelection( paragraph, 'end' ); - } ); - - viewDocument.fire( 'mousedown', new DomEventData( view, { - target: view.domConverter.mapViewToDom( - viewDocument.getRoot().getChild( 1 ) - ) - } ) ); - - viewDocument.fire( 'mousemove', new DomEventData( view, { - buttons: 1 - } ) ); - - assertSelectedCells( model, [ - [ 0, 0, 0 ], - [ 0, 0, 0 ], - [ 0, 0, 0 ] - ] ); - } ); - - it( 'should do nothing if ended dragging outside of table', () => { - model.change( writer => { - const paragraph = writer.createElement( 'paragraph' ); - const text = writer.createText( 'foo' ); - - writer.insert( text, paragraph ); - writer.insert( paragraph, model.document.getRoot(), 'end' ); - writer.setSelection( paragraph, 'end' ); - } ); - - viewDocument.fire( 'mousedown', new DomEventData( view, { - target: view.domConverter.mapViewToDom( - viewDocument.getRoot().getChild( 0 ).getChild( 1 ).getChild( 0 ).getChild( 0 ).getChild( 0 ) - ) - } ) ); - - viewDocument.fire( 'mousemove', new DomEventData( view, { - target: view.domConverter.mapViewToDom( - viewDocument.getRoot().getChild( 1 ) - ), - buttons: 1 - } ) ); - - assertSelectedCells( model, [ - [ 0, 0, 0 ], - [ 0, 0, 0 ], - [ 0, 0, 0 ] - ] ); - } ); - - it( 'should do nothing if ended dragging inside another table', () => { - setModelData( model, [ - modelTable( [ - [ '1.11[]', '1.12' ], - [ '1.21', '1.22' ] - ] ), - modelTable( [ - [ '2.11', '2.12' ], - [ '2.21', '2.22' ] - ] ) - ].join( '' ) ); - - viewDocument.fire( 'mousedown', new DomEventData( view, { - target: view.domConverter.mapViewToDom( - viewDocument.getRoot().getChild( 0 ).getChild( 1 ).getChild( 0 ).getChild( 0 ).getChild( 0 ) - ) - } ) ); - - viewDocument.fire( 'mousemove', new DomEventData( view, { - target: view.domConverter.mapViewToDom( - viewDocument.getRoot().getChild( 1 ).getChild( 1 ).getChild( 0 ).getChild( 1 ).getChild( 1 ) - ), - buttons: 1 - } ) ); - - assertSelectedCells( model, [ - [ 0, 0 ], - [ 0, 0 ] - ] ); - } ); - - it( 'should do nothing if ended in the same cell', () => { - viewDocument.fire( 'mousedown', new DomEventData( view, { - target: view.domConverter.mapViewToDom( - viewDocument.getRoot().getChild( 0 ).getChild( 1 ).getChild( 0 ).getChild( 0 ).getChild( 0 ) - ) - } ) ); - - viewDocument.fire( 'mousemove', new DomEventData( view, { - target: view.domConverter.mapViewToDom( - viewDocument.getRoot().getChild( 0 ).getChild( 1 ).getChild( 0 ).getChild( 0 ).getChild( 0 ) - ), - buttons: 1 - } ) ); - - assertSelectedCells( model, [ - [ 0, 0, 0 ], - [ 0, 0, 0 ], - [ 0, 0, 0 ] - ] ); - } ); - - it( 'should select started and ended dragging in the same cell but went over its border', () => { - viewDocument.fire( 'mousedown', new DomEventData( view, { - target: view.domConverter.mapViewToDom( - viewDocument.getRoot().getChild( 0 ).getChild( 1 ).getChild( 0 ).getChild( 0 ).getChild( 0 ) - ) - } ) ); - - // Select the next one. - viewDocument.fire( 'mousemove', new DomEventData( view, { - target: view.domConverter.mapViewToDom( - viewDocument.getRoot().getChild( 0 ).getChild( 1 ).getChild( 0 ).getChild( 0 ).getChild( 1 ) - ), - buttons: 1, - preventDefault: sinon.spy() - } ) ); - - // And back to the "started" cell. - viewDocument.fire( 'mousemove', new DomEventData( view, { - target: view.domConverter.mapViewToDom( - viewDocument.getRoot().getChild( 0 ).getChild( 1 ).getChild( 0 ).getChild( 0 ).getChild( 0 ) - ), - buttons: 1, - preventDefault: sinon.spy() - } ) ); - - viewDocument.fire( 'mouseup' ); - - assertSelectedCells( model, [ - [ 1, 0, 0 ], - [ 0, 0, 0 ], - [ 0, 0, 0 ] - ] ); - } ); - - it( 'should select all cells in first row', () => { - viewDocument.fire( 'mousedown', new DomEventData( view, { - target: view.domConverter.mapViewToDom( - // figure > table > tbody > tr > td - viewDocument.getRoot().getChild( 0 ).getChild( 1 ).getChild( 0 ).getChild( 0 ).getChild( 0 ) - ) - } ) ); - - viewDocument.fire( 'mousemove', new DomEventData( view, { - target: view.domConverter.mapViewToDom( - // figure > table > tbody > tr > td - viewDocument.getRoot().getChild( 0 ).getChild( 1 ).getChild( 0 ).getChild( 0 ).getChild( 2 ) - ), - buttons: 1, - preventDefault - } ) ); - - viewDocument.fire( 'mouseup' ); - - assertSelectedCells( model, [ - [ 1, 1, 1 ], - [ 0, 0, 0 ], - [ 0, 0, 0 ] - ] ); - - expect( preventDefault.called ).to.equal( true ); - } ); - - it( 'should ignore `selectionChange` event when selecting cells ', () => { - const consoleLog = sinon.stub( console, 'log' ); - const preventDefault = sinon.spy(); - const selectionChangeCallback = sinon.spy(); - - // Adding a new callback to check whether it will be executed (whether `evt.stop()` is being called). - viewDocument.on( 'selectionChange', selectionChangeCallback ); - - // Click on a cell. - viewDocument.fire( 'mousedown', new DomEventData( view, { - target: view.domConverter.mapViewToDom( - // figure > table > tbody > tr > td - viewDocument.getRoot().getChild( 0 ).getChild( 1 ).getChild( 0 ).getChild( 0 ).getChild( 1 ) - ) - } ) ); - - // Then move the mouse to another cell. Disables listening to `selectionChange`. - viewDocument.fire( 'mousemove', new DomEventData( view, { - buttons: 1, - target: view.domConverter.mapViewToDom( - // figure > table > tbody > tr > td - viewDocument.getRoot().getChild( 0 ).getChild( 1 ).getChild( 0 ).getChild( 0 ).getChild( 2 ) - ), - preventDefault - } ) ); - - // See explanation why do we fire it in the similar test for Shift+click. - viewDocument.fire( 'selectionChange' ); - - // `selectionChange` event should be canceled. - expect( selectionChangeCallback.called ).to.equal( false ); - expect( consoleLog.called ).to.equal( true ); - expect( consoleLog.firstCall.args[ 0 ] ).to.equal( 'Blocked selectionChange to avoid breaking table cells selection.' ); - - // Enables listening to `selectionChange` event. - viewDocument.fire( 'mouseup' ); - - viewDocument.fire( 'selectionChange', { - newSelection: view.document.selection - } ); - - expect( selectionChangeCallback.called ).to.equal( true ); - - consoleLog.restore(); - } ); - } ); - describe( 'getSelectedTableCells()', () => { beforeEach( async () => { editor = await createEditor(); model = editor.model; modelRoot = model.document.getRoot(); - view = editor.editing.view; - viewDocument = view.document; tableSelection = editor.plugins.get( TableSelection ); setModelData( model, modelTable( [ @@ -684,8 +189,6 @@ describe( 'table selection', () => { editor = await createEditor(); model = editor.model; modelRoot = model.document.getRoot(); - view = editor.editing.view; - viewDocument = view.document; tableSelection = editor.plugins.get( TableSelection ); setModelData( model, modelTable( [ @@ -740,8 +243,6 @@ describe( 'table selection', () => { editor = await createEditor(); model = editor.model; modelRoot = model.document.getRoot(); - view = editor.editing.view; - viewDocument = view.document; tableSelection = editor.plugins.get( TableSelection ); setModelData( model, modelTable( [ diff --git a/packages/ckeditor5-table/tests/tableselection/mouseeventsobserver.js b/packages/ckeditor5-table/tests/tableselection/mouseeventsobserver.js index 48d574438ac..f23990883fb 100644 --- a/packages/ckeditor5-table/tests/tableselection/mouseeventsobserver.js +++ b/packages/ckeditor5-table/tests/tableselection/mouseeventsobserver.js @@ -6,7 +6,7 @@ /* globals document */ import View from '@ckeditor/ckeditor5-engine/src/view/view'; -import MouseEventsObserver from '../../src/tableselection/mouseeventsobserver'; +import MouseEventsObserver from '../../src/tablemouse/mouseeventsobserver'; describe( 'table selection', () => { describe( 'MouseEventsObserver', () => { From 7adbaf3414e1995403d2f734a6b0e2d0dbad61d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Go=C5=82aszewski?= Date: Tue, 2 Jun 2020 09:41:32 +0200 Subject: [PATCH 3/3] Add info that Table plugin loads TableMouse feature. --- packages/ckeditor5-table/src/table.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/ckeditor5-table/src/table.js b/packages/ckeditor5-table/src/table.js index 119fb78da9a..13fcbdf2b7a 100644 --- a/packages/ckeditor5-table/src/table.js +++ b/packages/ckeditor5-table/src/table.js @@ -29,6 +29,7 @@ import '../theme/table.css'; * * {@link module:table/tableediting~TableEditing editing feature}, * * {@link module:table/tableselection~TableSelection selection feature}, * * {@link module:table/tablekeyboard~TableKeyboard keyboard navigation feature}, + * * {@link module:table/tablemouse~TableMouse mouse selection feature}, * * {@link module:table/tableclipboard~TableClipboard clipboard feature}, * * {@link module:table/tableui~TableUI UI feature}. *