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

Commit 729cc00

Browse files
authoredApr 6, 2020
Merge pull request #295 from ckeditor/i/6500
Feature: "Select entire column/row" added to table column and row dropdowns. Closes ckeditor/ckeditor5#6500.
2 parents 0e0e6fe + 302526b commit 729cc00

12 files changed

+1139
-3
lines changed
 

‎docs/features/table.md

+8
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,14 @@ The {@link module:table/tabletoolbar~TableToolbar} plugin introduces two balloon
394394
<td><code>'removeTableRow'</code></td>
395395
<td>{@link module:table/commands/removerowcommand~RemoveRowCommand}</td>
396396
</tr>
397+
<tr>
398+
<td><code>'selectTableColumn'</code></td>
399+
<td>{@link module:table/commands/selectcolumncommand~SelectColumnCommand}</td>
400+
</tr>
401+
<tr>
402+
<td><code>'selectTableRow'</code></td>
403+
<td>{@link module:table/commands/selectrowcommand~SelectRowCommand}</td>
404+
</tr>
397405
<tr>
398406
<td><code>'setTableColumnHeader'</code></td>
399407
<td>{@link module:table/commands/setheadercolumncommand~SetHeaderColumnCommand}</td>

‎lang/contexts.json

+2
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@
44
"Insert column left": "Label for the insert table column to the left of the current one button.",
55
"Insert column right": "Label for the insert table column to the right of the current one button.",
66
"Delete column": "Label for the delete table column button.",
7+
"Select column": "Label for the select table entire column button.",
78
"Column": "Label for the table column dropdown button.",
89
"Header row": "Label for the set/unset table header row button.",
910
"Insert row below": "Label for the insert row below button.",
1011
"Insert row above": "Label for the insert row above button.",
1112
"Delete row": "Label for the delete table row button.",
13+
"Select row": "Label for the select table entire row button.",
1214
"Row": "Label for the table row dropdown button.",
1315
"Merge cell up": "Label for the merge table cell up button.",
1416
"Merge cell right": "Label for the merge table cell right button.",

‎src/commands/selectcolumncommand.js

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/**
2+
* @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.
3+
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4+
*/
5+
6+
/**
7+
* @module table/commands/selectcolumncommand
8+
*/
9+
10+
import Command from '@ckeditor/ckeditor5-core/src/command';
11+
12+
import TableWalker from '../tablewalker';
13+
import { findAncestor } from './utils';
14+
import { getSelectionAffectedTableCells } from '../utils';
15+
16+
/**
17+
* The select column command.
18+
*
19+
* The command is registered by {@link module:table/tableediting~TableEditing} as the `'selectTableColumn'` editor command.
20+
*
21+
* To select the columns containing the selected cells, execute the command:
22+
*
23+
* editor.execute( 'selectTableColumn' );
24+
*
25+
* @extends module:core/command~Command
26+
*/
27+
export default class SelectColumnCommand extends Command {
28+
/**
29+
* @inheritDoc
30+
*/
31+
refresh() {
32+
const selectedCells = getSelectionAffectedTableCells( this.editor.model.document.selection );
33+
34+
this.isEnabled = selectedCells.length > 0;
35+
}
36+
37+
/**
38+
* @inheritDoc
39+
*/
40+
execute() {
41+
const model = this.editor.model;
42+
const referenceCells = getSelectionAffectedTableCells( model.document.selection );
43+
const firstCell = referenceCells[ 0 ];
44+
const lastCell = referenceCells.pop();
45+
46+
const tableUtils = this.editor.plugins.get( 'TableUtils' );
47+
const startLocation = tableUtils.getCellLocation( firstCell );
48+
const endLocation = tableUtils.getCellLocation( lastCell );
49+
50+
const startColumn = Math.min( startLocation.column, endLocation.column );
51+
const endColumn = Math.max( startLocation.column, endLocation.column );
52+
53+
const rangesToSelect = [];
54+
55+
for ( const cellInfo of new TableWalker( findAncestor( 'table', firstCell ) ) ) {
56+
if ( cellInfo.column >= startColumn && cellInfo.column <= endColumn ) {
57+
rangesToSelect.push( model.createRangeOn( cellInfo.cell ) );
58+
}
59+
}
60+
61+
model.change( writer => {
62+
writer.setSelection( rangesToSelect );
63+
} );
64+
}
65+
}

‎src/commands/selectrowcommand.js

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/**
2+
* @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.
3+
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4+
*/
5+
6+
/**
7+
* @module table/commands/selectrowcommand
8+
*/
9+
10+
import Command from '@ckeditor/ckeditor5-core/src/command';
11+
12+
import { findAncestor } from './utils';
13+
import { getRowIndexes, getSelectionAffectedTableCells } from '../utils';
14+
15+
/**
16+
* The select row command.
17+
*
18+
* The command is registered by {@link module:table/tableediting~TableEditing} as the `'selectTableRow'` editor command.
19+
*
20+
* To select the rows containing the selected cells, execute the command:
21+
*
22+
* editor.execute( 'selectTableRow' );
23+
*
24+
* @extends module:core/command~Command
25+
*/
26+
export default class SelectRowCommand extends Command {
27+
/**
28+
* @inheritDoc
29+
*/
30+
refresh() {
31+
const selectedCells = getSelectionAffectedTableCells( this.editor.model.document.selection );
32+
33+
this.isEnabled = selectedCells.length > 0;
34+
}
35+
36+
/**
37+
* @inheritDoc
38+
*/
39+
execute() {
40+
const model = this.editor.model;
41+
const referenceCells = getSelectionAffectedTableCells( model.document.selection );
42+
const rowIndexes = getRowIndexes( referenceCells );
43+
44+
const table = findAncestor( 'table', referenceCells[ 0 ] );
45+
const rangesToSelect = [];
46+
47+
for ( let rowIndex = rowIndexes.first; rowIndex <= rowIndexes.last; rowIndex++ ) {
48+
for ( const cell of table.getChild( rowIndex ).getChildren() ) {
49+
rangesToSelect.push( model.createRangeOn( cell ) );
50+
}
51+
}
52+
53+
model.change( writer => {
54+
writer.setSelection( rangesToSelect );
55+
} );
56+
}
57+
}

‎src/tableediting.js

+5
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ import RemoveColumnCommand from './commands/removecolumncommand';
2929
import SetHeaderRowCommand from './commands/setheaderrowcommand';
3030
import SetHeaderColumnCommand from './commands/setheadercolumncommand';
3131
import MergeCellsCommand from './commands/mergecellscommand';
32+
import SelectRowCommand from './commands/selectrowcommand';
33+
import SelectColumnCommand from './commands/selectcolumncommand';
3234
import { getTableCellsContainingSelection } from './utils';
3335
import TableUtils from '../src/tableutils';
3436

@@ -142,6 +144,9 @@ export default class TableEditing extends Plugin {
142144
editor.commands.add( 'setTableColumnHeader', new SetHeaderColumnCommand( editor ) );
143145
editor.commands.add( 'setTableRowHeader', new SetHeaderRowCommand( editor ) );
144146

147+
editor.commands.add( 'selectTableRow', new SelectRowCommand( editor ) );
148+
editor.commands.add( 'selectTableColumn', new SelectColumnCommand( editor ) );
149+
145150
injectTableLayoutPostFixer( model );
146151
injectTableCellRefreshPostFixer( model );
147152
injectTableCellParagraphPostFixer( model );

‎src/tableui.js

+14
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,13 @@ export default class TableUI extends Plugin {
113113
commandName: 'removeTableColumn',
114114
label: t( 'Delete column' )
115115
}
116+
},
117+
{
118+
type: 'button',
119+
model: {
120+
commandName: 'selectTableColumn',
121+
label: t( 'Select column' )
122+
}
116123
}
117124
];
118125

@@ -150,6 +157,13 @@ export default class TableUI extends Plugin {
150157
commandName: 'removeTableRow',
151158
label: t( 'Delete row' )
152159
}
160+
},
161+
{
162+
type: 'button',
163+
model: {
164+
commandName: 'selectTableRow',
165+
label: t( 'Select row' )
166+
}
153167
}
154168
];
155169

‎src/tableutils.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ export default class TableUtils extends Plugin {
108108
* | | f | g | | | | |
109109
* 3 +---+---+---+ + +---+---+ 3
110110
* | | d | e |
111-
* +---+---+---+ 4
111+
* + +---+---+ 4
112112
* + + f | g |
113113
* +---+---+---+ 5
114114
*

‎tests/_utils/utils.js

+37
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,43 @@ export function assertTableCellStyle( editor, tableCellStyle ) {
340340
* The above call will check if table has second column selected (assuming no spans).
341341
*
342342
* **Note**: This function operates on child indexes - not rows/columns.
343+
*
344+
* Examples:
345+
*
346+
* +----+----+----+----+
347+
* | 00 | 01 | 02 | 03 |
348+
* +----+ +----+----+
349+
* |[10]| |[12]|[13]|
350+
* +----+----+----+----+
351+
* | 20 | 21 | 22 | 23 |
352+
* +----+----+----+----+
353+
* | 30 | 31 | 33 |
354+
* +----+----+----+----+
355+
*
356+
* assertSelectedCells( model, [
357+
* [ 0, 0, 0, 0 ],
358+
* [ 1, 1, 1 ],
359+
* [ 0, 0, 0, 0 ],
360+
* [ 0, 0, 0 ]
361+
* ] );
362+
*
363+
* +----+----+----+----+
364+
* | 00 |[01]| 02 | 03 |
365+
* +----+ +----+----+
366+
* | 10 | | 12 | 13 |
367+
* +----+----+----+----+
368+
* | 20 |[21]| 22 | 23 |
369+
* +----+----+----+----+
370+
* | 30 |[31] | 33 |
371+
* +----+----+----+----+
372+
*
373+
* assertSelectedCells( model, [
374+
* [ 0, 1, 0, 0 ],
375+
* [ 0, 0, 0 ],
376+
* [ 0, 1, 0, 0 ],
377+
* [ 0, 1, 0 ]
378+
* ] );
379+
*
343380
*/
344381
export function assertSelectedCells( model, tableMap ) {
345382
const tableIndex = 0;

‎tests/commands/selectcolumncommand.js

+450
Large diffs are not rendered by default.

‎tests/commands/selectrowcommand.js

+469
Large diffs are not rendered by default.

‎tests/tableediting.js

+10
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ import InsertTableCommand from '../src/commands/inserttablecommand';
1616
import InsertColumnCommand from '../src/commands/insertcolumncommand';
1717
import RemoveRowCommand from '../src/commands/removerowcommand';
1818
import RemoveColumnCommand from '../src/commands/removecolumncommand';
19+
import SelectRowCommand from '../src/commands/selectrowcommand';
20+
import SelectColumnCommand from '../src/commands/selectcolumncommand';
1921
import SplitCellCommand from '../src/commands/splitcellcommand';
2022
import MergeCellCommand from '../src/commands/mergecellcommand';
2123
import SetHeaderRowCommand from '../src/commands/setheaderrowcommand';
@@ -111,6 +113,14 @@ describe( 'TableEditing', () => {
111113
expect( editor.commands.get( 'removeTableColumn' ) ).to.be.instanceOf( RemoveColumnCommand );
112114
} );
113115

116+
it( 'adds selectRow command', () => {
117+
expect( editor.commands.get( 'selectTableRow' ) ).to.be.instanceOf( SelectRowCommand );
118+
} );
119+
120+
it( 'adds selectColumn command', () => {
121+
expect( editor.commands.get( 'selectTableColumn' ) ).to.be.instanceOf( SelectColumnCommand );
122+
} );
123+
114124
it( 'adds splitCellVertically command', () => {
115125
expect( editor.commands.get( 'splitTableCellVertically' ) ).to.be.instanceOf( SplitCellCommand );
116126
} );

‎tests/tableui.js

+21-2
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,9 @@ describe( 'TableUI', () => {
137137

138138
const labels = listView.items.map( item => item instanceof ListSeparatorView ? '|' : item.children.first.label );
139139

140-
expect( labels ).to.deep.equal( [ 'Header row', '|', 'Insert row below', 'Insert row above', 'Delete row' ] );
140+
expect( labels ).to.deep.equal(
141+
[ 'Header row', '|', 'Insert row below', 'Insert row above', 'Delete row', 'Select row' ]
142+
);
141143
} );
142144

143145
it( 'should bind items in panel to proper commands', () => {
@@ -147,16 +149,19 @@ describe( 'TableUI', () => {
147149
const insertRowBelowCommand = editor.commands.get( 'insertTableRowBelow' );
148150
const insertRowAboveCommand = editor.commands.get( 'insertTableRowAbove' );
149151
const removeRowCommand = editor.commands.get( 'removeTableRow' );
152+
const selectRowCommand = editor.commands.get( 'selectTableRow' );
150153

151154
setRowHeaderCommand.isEnabled = true;
152155
insertRowBelowCommand.isEnabled = true;
153156
insertRowAboveCommand.isEnabled = true;
154157
removeRowCommand.isEnabled = true;
158+
selectRowCommand.isEnabled = true;
155159

156160
expect( items.first.children.first.isEnabled ).to.be.true;
157161
expect( items.get( 2 ).children.first.isEnabled ).to.be.true;
158162
expect( items.get( 3 ).children.first.isEnabled ).to.be.true;
159163
expect( items.get( 4 ).children.first.isEnabled ).to.be.true;
164+
expect( items.get( 5 ).children.first.isEnabled ).to.be.true;
160165
expect( dropdown.buttonView.isEnabled ).to.be.true;
161166

162167
setRowHeaderCommand.isEnabled = false;
@@ -176,6 +181,11 @@ describe( 'TableUI', () => {
176181
removeRowCommand.isEnabled = false;
177182

178183
expect( items.get( 4 ).children.first.isEnabled ).to.be.false;
184+
expect( dropdown.buttonView.isEnabled ).to.be.true;
185+
186+
selectRowCommand.isEnabled = false;
187+
188+
expect( items.get( 5 ).children.first.isEnabled ).to.be.false;
179189
expect( dropdown.buttonView.isEnabled ).to.be.false;
180190
} );
181191

@@ -238,7 +248,9 @@ describe( 'TableUI', () => {
238248

239249
const labels = listView.items.map( item => item instanceof ListSeparatorView ? '|' : item.children.first.label );
240250

241-
expect( labels ).to.deep.equal( [ 'Header column', '|', 'Insert column left', 'Insert column right', 'Delete column' ] );
251+
expect( labels ).to.deep.equal(
252+
[ 'Header column', '|', 'Insert column left', 'Insert column right', 'Delete column', 'Select column' ]
253+
);
242254
} );
243255

244256
it( 'should bind items in panel to proper commands (LTR content)', () => {
@@ -248,16 +260,19 @@ describe( 'TableUI', () => {
248260
const insertColumnLeftCommand = editor.commands.get( 'insertTableColumnLeft' );
249261
const insertColumnRightCommand = editor.commands.get( 'insertTableColumnRight' );
250262
const removeColumnCommand = editor.commands.get( 'removeTableColumn' );
263+
const selectColumnCommand = editor.commands.get( 'selectTableColumn' );
251264

252265
setColumnHeaderCommand.isEnabled = true;
253266
insertColumnLeftCommand.isEnabled = true;
254267
insertColumnRightCommand.isEnabled = true;
255268
removeColumnCommand.isEnabled = true;
269+
selectColumnCommand.isEnabled = true;
256270

257271
expect( items.first.children.first.isEnabled ).to.be.true;
258272
expect( items.get( 2 ).children.first.isEnabled ).to.be.true;
259273
expect( items.get( 3 ).children.first.isEnabled ).to.be.true;
260274
expect( items.get( 4 ).children.first.isEnabled ).to.be.true;
275+
expect( items.get( 5 ).children.first.isEnabled ).to.be.true;
261276
expect( dropdown.buttonView.isEnabled ).to.be.true;
262277

263278
setColumnHeaderCommand.isEnabled = false;
@@ -275,6 +290,10 @@ describe( 'TableUI', () => {
275290

276291
removeColumnCommand.isEnabled = false;
277292
expect( items.get( 4 ).children.first.isEnabled ).to.be.false;
293+
294+
selectColumnCommand.isEnabled = false;
295+
expect( items.get( 5 ).children.first.isEnabled ).to.be.false;
296+
278297
expect( dropdown.buttonView.isEnabled ).to.be.false;
279298
} );
280299

0 commit comments

Comments
 (0)
This repository has been archived.