瀏覽代碼

Set backward selection more precisely.

Piotrek Koszuliński 5 年之前
父節點
當前提交
9fb7532657
共有 1 個文件被更改,包括 54 次插入15 次删除
  1. 54 15
      packages/ckeditor5-table/src/tableselection.js

+ 54 - 15
packages/ckeditor5-table/src/tableselection.js

@@ -52,11 +52,16 @@ export default class TableSelection extends Plugin {
 		// TODO move to the engine?
 		editor.editing.view.addObserver( MouseEventsObserver );
 
-		this._defineConverters();
+		this._defineSelectionConverter();
 		this._enableShiftClickSelection();
 		this._enableMouseDragSelection();
 	}
 
+	/**
+	 * Returns currently selected table cells or `null` if not a table cells selection.
+	 *
+	 * @returns {Array.<module:engine/model/element~Element>}
+	 */
 	getSelectedTableCells() {
 		const selection = this.editor.model.document.selection;
 
@@ -66,6 +71,7 @@ export default class TableSelection extends Plugin {
 			return null;
 		}
 
+		// This should never happen, but let's know if it ever happens.
 		// @if CK_DEBUG //	if ( selectedCells.length != selection.rangeCount ) {
 		// @if CK_DEBUG //		console.warn( 'Mixed selection warning. The selection contains table cells and some other ranges.' );
 		// @if CK_DEBUG //	}
@@ -73,13 +79,23 @@ export default class TableSelection extends Plugin {
 		return selectedCells;
 	}
 
-	_defineConverters() {
+	/**
+	 * Defines a selection converter which marks selected cells with a specific class.
+	 *
+	 * The real DOM selection is put in the last cell. Since the order of ranges is dependent on whether the
+	 * selection is backward or not, the last cell with usually be close to the "focus" end of the selection
+	 * (a selection has anchor and focus).
+	 *
+	 * The real DOM selection is then hidden with CSS.
+	 *
+	 * @private
+	 */
+	_defineSelectionConverter() {
 		const editor = this.editor;
 		const highlighted = new Set();
 
 		editor.conversion.for( 'editingDowncast' ).add( dispatcher => dispatcher.on( 'selection', ( evt, data, conversionApi ) => {
 			const viewWriter = conversionApi.writer;
-			// const viewSelection = viewWriter.document.selection;
 
 			clearHighlightedTableCells( viewWriter );
 
@@ -109,6 +125,12 @@ export default class TableSelection extends Plugin {
 		}
 	}
 
+	/**
+	 * Enables making cell selection by Shift+click. Creates a selection from the cell which previously hold
+	 * the selection to the cell which was clicked (can be the same cell, in which case it selects a single cell).
+	 *
+	 * @private
+	 */
 	_enableShiftClickSelection() {
 		const editor = this.editor;
 		const model = editor.model;
@@ -131,11 +153,15 @@ export default class TableSelection extends Plugin {
 				return;
 			}
 
-			const cellsToSelect = this._getCellsBetweenAnchorAndTarget( anchorCell, targetCell );
+			const cellsToSelect = this._getCellsToSelect( anchorCell, targetCell );
 
 			model.change( writer => {
 				blockNextSelectionChange = true;
-				writer.setSelection( cellsToSelect.map( cell => writer.createRangeOn( cell ) ) );
+
+				writer.setSelection(
+					cellsToSelect.cells.map( cell => writer.createRangeOn( cell ) ),
+					{ backward: cellsToSelect.backward }
+				);
 			} );
 
 			domEventData.preventDefault();
@@ -171,14 +197,18 @@ export default class TableSelection extends Plugin {
 		const model = editor.model;
 		let anchorCell, targetCell;
 		let beganCellSelection = false;
-		let blockNextSelectionChange = false;
+		let blockSelectionChange = false;
 
 		const setModelSelection = () => {
-			const cellsToSelect = this._getCellsBetweenAnchorAndTarget( anchorCell, targetCell );
+			const cellsToSelect = this._getCellsToSelect( anchorCell, targetCell );
 
 			model.change( writer => {
-				blockNextSelectionChange = true;
-				writer.setSelection( cellsToSelect.map( cell => writer.createRangeOn( cell ) ) );
+				blockSelectionChange = true;
+
+				writer.setSelection(
+					cellsToSelect.cells.map( cell => writer.createRangeOn( cell ) ),
+					{ backward: cellsToSelect.backward }
+				);
 			} );
 		};
 
@@ -225,13 +255,13 @@ export default class TableSelection extends Plugin {
 
 		this.listenTo( editor.editing.view.document, 'mouseup', () => {
 			beganCellSelection = false;
-			blockNextSelectionChange = false;
+			blockSelectionChange = false;
 			anchorCell = null;
 			targetCell = null;
 		} );
 
 		this.listenTo( editor.editing.view.document, 'selectionChange', evt => {
-			if ( blockNextSelectionChange ) {
+			if ( blockSelectionChange ) {
 				// @if CK_DEBUG // console.log( 'Blocked selectionChange 2.' );
 
 				evt.stop();
@@ -291,11 +321,14 @@ export default class TableSelection extends Plugin {
 	}
 
 	/**
-	 * TODO
+	 * Returns an array of table cells that should be selected based on the
+	 * given anchor cell and target (focus) cell.
+	 *
+	 * The cells are returned in a reverse direction if the selection is backward.
 	 *
 	 * @returns {Array.<module:engine/model/element~Element>}
 	 */
-	_getCellsBetweenAnchorAndTarget( anchorCell, targetCell ) {
+	_getCellsToSelect( anchorCell, targetCell ) {
 		const tableUtils = this.editor.plugins.get( 'TableUtils' );
 		const startLocation = tableUtils.getCellLocation( anchorCell );
 		const endLocation = tableUtils.getCellLocation( targetCell );
@@ -314,11 +347,17 @@ export default class TableSelection extends Plugin {
 			}
 		}
 
+		// A selection started in the bottom right corner and finished in the upper left corner
+		// should have it ranges returned in the reverse order.
+		// However, this is only half of the story because the selection could be made to the left (then the left cell is a focus)
+		// or to the right (then the right cell is a focus), while being a forward selection in both cases
+		// (because it was made from top to bottom). This isn't handled.
+		// This method would need to be smarter, but the ROI is microscopic, so I skip this.
 		if ( checkIsBackward( startLocation, endLocation ) ) {
-			cells.reverse();
+			return { cells: cells.reverse(), backward: true };
 		}
 
-		return cells;
+		return { cells, backward: false };
 	}
 }