浏览代码

Refactor MergeCellCommand.

Maciej Gołaszewski 7 年之前
父节点
当前提交
23cec2d665

+ 1 - 3
packages/ckeditor5-table/src/commands/insertrowcommand.js

@@ -49,9 +49,7 @@ export default class InsertRowCommand extends Command {
 	}
 	}
 
 
 	/**
 	/**
-	 * Executes the command.
-	 *
-	 * @fires execute
+	 * @inheritDoc
 	 */
 	 */
 	execute() {
 	execute() {
 		const editor = this.editor;
 		const editor = this.editor;

+ 1 - 7
packages/ckeditor5-table/src/commands/inserttablecommand.js

@@ -31,13 +31,7 @@ export default class InsertTableCommand extends Command {
 	}
 	}
 
 
 	/**
 	/**
-	 * Executes the command.
-	 *
-	 * @param {Object} [options] Options for the executed command.
-	 * @param {Number} [options.rows=2] Number of rows to create in inserted table.
-	 * @param {Number} [options.columns=2] Number of columns to create in inserted table.
-	 *
-	 * @fires execute
+	 * @inheritDoc
 	 */
 	 */
 	execute( options = {} ) {
 	execute( options = {} ) {
 		const model = this.editor.model;
 		const model = this.editor.model;

+ 65 - 45
packages/ckeditor5-table/src/commands/mergecellcommand.js

@@ -19,12 +19,22 @@ import TableWalker from '../tablewalker';
  */
  */
 export default class MergeCellCommand extends Command {
 export default class MergeCellCommand extends Command {
 	/**
 	/**
-	 * @param editor
-	 * @param options
+	 * Creates a new `MergeCellCommand` instance.
+	 *
+	 * @param {module:core/editor/editor~Editor} editor Editor on which this command will be used.
+	 * @param {Object} options
+	 * @param {String} options.direction Indicates which cell merge to currently selected one.
+	 * Possible values are: "left", "right", "up" and "down".
 	 */
 	 */
 	constructor( editor, options ) {
 	constructor( editor, options ) {
 		super( editor );
 		super( editor );
 
 
+		/**
+		 * The direction indicates which cell will be merged to currently selected one.
+		 *
+		 * @readonly
+		 * @member {String} module:table/commands/insertrowcommand~InsertRowCommand#order
+		 */
 		this.direction = options.direction;
 		this.direction = options.direction;
 	}
 	}
 
 
@@ -32,33 +42,35 @@ export default class MergeCellCommand extends Command {
 	 * @inheritDoc
 	 * @inheritDoc
 	 */
 	 */
 	refresh() {
 	refresh() {
-		const cellToMerge = this._getCellToMerge();
+		const cellToMerge = this._getMergeableCell();
 
 
 		this.isEnabled = !!cellToMerge;
 		this.isEnabled = !!cellToMerge;
+		// In order to check if currently selected cell can be merged with one defined by #direction some computation are done beforehand.
+		// As such we can cache it as a command's value.
 		this.value = cellToMerge;
 		this.value = cellToMerge;
 	}
 	}
 
 
 	/**
 	/**
-	 * Executes the command.
-	 *
-	 * @fires execute
+	 * @inheritDoc
 	 */
 	 */
 	execute() {
 	execute() {
 		const model = this.editor.model;
 		const model = this.editor.model;
 		const doc = model.document;
 		const doc = model.document;
 		const tableCell = doc.selection.getFirstPosition().parent;
 		const tableCell = doc.selection.getFirstPosition().parent;
 		const cellToMerge = this.value;
 		const cellToMerge = this.value;
+		const direction = this.direction;
 
 
 		model.change( writer => {
 		model.change( writer => {
-			const isMergeNext = this.direction == 'right' || this.direction == 'down';
+			const isMergeNext = direction == 'right' || direction == 'down';
 
 
+			// The merge mechanism is always the same so sort cells to be merged.
 			const mergeInto = isMergeNext ? tableCell : cellToMerge;
 			const mergeInto = isMergeNext ? tableCell : cellToMerge;
 			const removeCell = isMergeNext ? cellToMerge : tableCell;
 			const removeCell = isMergeNext ? cellToMerge : tableCell;
 
 
 			writer.move( Range.createIn( removeCell ), Position.createAt( mergeInto, 'end' ) );
 			writer.move( Range.createIn( removeCell ), Position.createAt( mergeInto, 'end' ) );
 			writer.remove( removeCell );
 			writer.remove( removeCell );
 
 
-			const spanAttribute = isHorizontal( this.direction ) ? 'colspan' : 'rowspan';
+			const spanAttribute = isHorizontal( direction ) ? 'colspan' : 'rowspan';
 			const cellSpan = parseInt( tableCell.getAttribute( spanAttribute ) || 1 );
 			const cellSpan = parseInt( tableCell.getAttribute( spanAttribute ) || 1 );
 			const cellToMergeSpan = parseInt( cellToMerge.getAttribute( spanAttribute ) || 1 );
 			const cellToMergeSpan = parseInt( cellToMerge.getAttribute( spanAttribute ) || 1 );
 
 
@@ -69,12 +81,12 @@ export default class MergeCellCommand extends Command {
 	}
 	}
 
 
 	/**
 	/**
-	 * Returns a cell that it mergable with current cell depending on command's direction.
+	 * Returns a cell that it mergeable with current cell depending on command's direction.
 	 *
 	 *
-	 * @returns {*}
+	 * @returns {module:engine/model/element|undefined}
 	 * @private
 	 * @private
 	 */
 	 */
-	_getCellToMerge() {
+	_getMergeableCell() {
 		const model = this.editor.model;
 		const model = this.editor.model;
 		const doc = model.document;
 		const doc = model.document;
 		const element = doc.selection.getFirstPosition().parent;
 		const element = doc.selection.getFirstPosition().parent;
@@ -83,14 +95,16 @@ export default class MergeCellCommand extends Command {
 			return;
 			return;
 		}
 		}
 
 
+		// First get the cell on proper direction.
 		const cellToMerge = isHorizontal( this.direction ) ?
 		const cellToMerge = isHorizontal( this.direction ) ?
-			getHorizontal( element, this.direction ) :
-			getVertical( element, this.direction );
+			getHorizontalCell( element, this.direction ) :
+			getVerticalCell( element, this.direction );
 
 
 		if ( !cellToMerge ) {
 		if ( !cellToMerge ) {
 			return;
 			return;
 		}
 		}
 
 
+		// If found check if the span perpendicular to merge direction is equal on both cells.
 		const spanAttribute = isHorizontal( this.direction ) ? 'rowspan' : 'colspan';
 		const spanAttribute = isHorizontal( this.direction ) ? 'rowspan' : 'colspan';
 		const span = parseInt( element.getAttribute( spanAttribute ) || 1 );
 		const span = parseInt( element.getAttribute( spanAttribute ) || 1 );
 
 
@@ -99,46 +113,52 @@ export default class MergeCellCommand extends Command {
 		if ( cellToMergeSpan === span ) {
 		if ( cellToMergeSpan === span ) {
 			return cellToMerge;
 			return cellToMerge;
 		}
 		}
+	}
+}
 
 
-		function getVertical( tableCell, direction ) {
-			const tableRow = tableCell.parent;
-			const table = tableRow.parent;
-
-			const rowIndex = table.getChildIndex( tableRow );
-
-			if ( direction === 'down' && rowIndex === table.childCount - 1 || direction === 'up' && rowIndex === 0 ) {
-				return;
-			}
+// Checks whether merge direction is horizontal.
+//
+// returns {Boolean}
+function isHorizontal( direction ) {
+	return direction == 'right' || direction == 'left';
+}
 
 
-			const rowspan = parseInt( tableCell.getAttribute( 'rowspan' ) || 1 );
-			const targetMergeRow = direction === 'up' ? rowIndex : rowIndex + rowspan;
+// Returns horizontally mergeable cell.
+//
+// @param {module:engine/model/element~Element} tableCell
+// @param {String} direction
+// @returns {module:engine/model/node~Node|null}
+function getHorizontalCell( tableCell, direction ) {
+	return direction == 'right' ? tableCell.nextSibling : tableCell.previousSibling;
+}
 
 
-			const tableWalker = new TableWalker( table, { endRow: targetMergeRow } );
-			const tableWalkerValues = [ ...tableWalker ];
+// Returns vertically mergeable cell.
+//
+// @param {module:engine/model/element~Element} tableCell
+// @param {String} direction
+// @returns {module:engine/model/node~Node|null}
+function getVerticalCell( tableCell, direction ) {
+	const tableRow = tableCell.parent;
+	const table = tableRow.parent;
 
 
-			const cellData = tableWalkerValues.find( value => value.cell === tableCell );
+	const rowIndex = table.getChildIndex( tableRow );
 
 
-			const cellToMerge = tableWalkerValues.find( value => {
-				const row = value.row;
-				const column = value.column;
+	// Don't search for mergeable cell if direction points out of the table.
+	if ( direction == 'down' && rowIndex === table.childCount - 1 || direction == 'up' && rowIndex === 0 ) {
+		return;
+	}
 
 
-				return column === cellData.column && ( direction === 'down' ? targetMergeRow === row : rowspan + row === rowIndex );
-			} );
+	const rowspan = parseInt( tableCell.getAttribute( 'rowspan' ) || 1 );
+	const mergeRow = direction == 'down' ? rowIndex + rowspan : rowIndex;
 
 
-			const colspan = parseInt( tableCell.getAttribute( 'colspan' ) || 1 );
+	const tableMap = [ ...new TableWalker( table, { endRow: mergeRow } ) ];
 
 
-			if ( cellToMerge && cellToMerge.colspan === colspan ) {
-				return cellToMerge.cell;
-			}
-		}
+	const currentCellData = tableMap.find( value => value.cell === tableCell );
+	const mergeColumn = currentCellData.column;
 
 
-		function getHorizontal( tableCell, direction ) {
-			return direction == 'right' ? tableCell.nextSibling : tableCell.previousSibling;
-		}
-	}
-}
+	const cellToMergeData = tableMap.find( ( { row, column } ) => {
+		return column === mergeColumn && ( direction == 'down' ? mergeRow === row : mergeRow === rowspan + row );
+	} );
 
 
-// @private
-function isHorizontal( direction ) {
-	return direction == 'right' || direction == 'left';
+	return cellToMergeData && cellToMergeData.cell;
 }
 }

+ 1 - 3
packages/ckeditor5-table/src/commands/removecolumncommand.js

@@ -30,9 +30,7 @@ export default class RemoveColumnCommand extends Command {
 	}
 	}
 
 
 	/**
 	/**
-	 * Executes the command.
-	 *
-	 * @fires execute
+	 * @inheritDoc
 	 */
 	 */
 	execute() {
 	execute() {
 		const model = this.editor.model;
 		const model = this.editor.model;

+ 1 - 3
packages/ckeditor5-table/src/commands/removerowcommand.js

@@ -31,9 +31,7 @@ export default class RemoveRowCommand extends Command {
 	}
 	}
 
 
 	/**
 	/**
-	 * Executes the command.
-	 *
-	 * @fires execute
+	 * @inheritDoc
 	 */
 	 */
 	execute() {
 	execute() {
 		const model = this.editor.model;
 		const model = this.editor.model;

+ 1 - 7
packages/ckeditor5-table/src/commands/settableheaderscommand.js

@@ -33,13 +33,7 @@ export default class SetTableHeadersCommand extends Command {
 	}
 	}
 
 
 	/**
 	/**
-	 * Executes the command.
-	 *
-	 * @param {Object} [options] Options for the executed command.
-	 * @param {Number} [options.rows] Number of rows to set as headers.
-	 * @param {Number} [options.columns] Number of columns to set as headers.
-	 *
-	 * @fires execute
+	 * @inheritDoc
 	 */
 	 */
 	execute( options = {} ) {
 	execute( options = {} ) {
 		const model = this.editor.model;
 		const model = this.editor.model;

+ 1 - 3
packages/ckeditor5-table/src/commands/splitcellcommand.js

@@ -39,9 +39,7 @@ export default class SplitCellCommand extends Command {
 	}
 	}
 
 
 	/**
 	/**
-	 * Executes the command.
-	 *
-	 * @fires execute
+	 * @inheritDoc
 	 */
 	 */
 	execute() {
 	execute() {
 		const model = this.editor.model;
 		const model = this.editor.model;

+ 11 - 6
packages/ckeditor5-table/src/tableediting.js

@@ -88,6 +88,7 @@ export default class TablesEditing extends Plugin {
 		conversion.for( 'upcast' ).add( upcastElementToElement( { model: 'tableCell', view: 'td' } ) );
 		conversion.for( 'upcast' ).add( upcastElementToElement( { model: 'tableCell', view: 'td' } ) );
 		conversion.for( 'upcast' ).add( upcastElementToElement( { model: 'tableCell', view: 'th' } ) );
 		conversion.for( 'upcast' ).add( upcastElementToElement( { model: 'tableCell', view: 'th' } ) );
 
 
+		// Table attributes conversion.
 		conversion.attributeToAttribute( { model: 'colspan', view: 'colspan' } );
 		conversion.attributeToAttribute( { model: 'colspan', view: 'colspan' } );
 		conversion.attributeToAttribute( { model: 'rowspan', view: 'rowspan' } );
 		conversion.attributeToAttribute( { model: 'rowspan', view: 'rowspan' } );
 
 
@@ -97,18 +98,22 @@ export default class TablesEditing extends Plugin {
 		conversion.for( 'dataDowncast' ).add( downcastAttributeChange( { attribute: 'headingColumns' } ) );
 		conversion.for( 'dataDowncast' ).add( downcastAttributeChange( { attribute: 'headingColumns' } ) );
 
 
 		editor.commands.add( 'insertTable', new InsertTableCommand( editor ) );
 		editor.commands.add( 'insertTable', new InsertTableCommand( editor ) );
-		editor.commands.add( 'insertRowAbove', new InsertRowCommand( editor, { location: 'above' } ) );
-		editor.commands.add( 'insertRowBelow', new InsertRowCommand( editor, { location: 'below' } ) );
-		editor.commands.add( 'insertColumnBefore', new InsertColumnCommand( editor, { location: 'before' } ) );
-		editor.commands.add( 'insertColumnAfter', new InsertColumnCommand( editor, { location: 'after' } ) );
-		editor.commands.add( 'splitCellVertically', new SplitCellCommand( editor, { direction: 'vertically' } ) );
-		editor.commands.add( 'splitCellHorizontally', new SplitCellCommand( editor, { direction: 'horizontally' } ) );
+		editor.commands.add( 'insertRowAbove', new InsertRowCommand( editor, { order: 'above' } ) );
+		editor.commands.add( 'insertRowBelow', new InsertRowCommand( editor, { order: 'below' } ) );
+		editor.commands.add( 'insertColumnBefore', new InsertColumnCommand( editor, { order: 'before' } ) );
+		editor.commands.add( 'insertColumnAfter', new InsertColumnCommand( editor, { order: 'after' } ) );
+
 		editor.commands.add( 'removeRow', new RemoveRowCommand( editor ) );
 		editor.commands.add( 'removeRow', new RemoveRowCommand( editor ) );
 		editor.commands.add( 'removeColumn', new RemoveColumnCommand( editor ) );
 		editor.commands.add( 'removeColumn', new RemoveColumnCommand( editor ) );
+
+		editor.commands.add( 'splitCellVertically', new SplitCellCommand( editor, { direction: 'vertically' } ) );
+		editor.commands.add( 'splitCellHorizontally', new SplitCellCommand( editor, { direction: 'horizontally' } ) );
+
 		editor.commands.add( 'mergeRight', new MergeCellCommand( editor, { direction: 'right' } ) );
 		editor.commands.add( 'mergeRight', new MergeCellCommand( editor, { direction: 'right' } ) );
 		editor.commands.add( 'mergeLeft', new MergeCellCommand( editor, { direction: 'left' } ) );
 		editor.commands.add( 'mergeLeft', new MergeCellCommand( editor, { direction: 'left' } ) );
 		editor.commands.add( 'mergeDown', new MergeCellCommand( editor, { direction: 'down' } ) );
 		editor.commands.add( 'mergeDown', new MergeCellCommand( editor, { direction: 'down' } ) );
 		editor.commands.add( 'mergeUp', new MergeCellCommand( editor, { direction: 'up' } ) );
 		editor.commands.add( 'mergeUp', new MergeCellCommand( editor, { direction: 'up' } ) );
+
 		editor.commands.add( 'setTableHeaders', new SetTableHeadersCommand( editor ) );
 		editor.commands.add( 'setTableHeaders', new SetTableHeadersCommand( editor ) );
 
 
 		this.listenTo( editor.editing.view.document, 'keydown', ( ...args ) => this._handleTabOnSelectedTable( ...args ) );
 		this.listenTo( editor.editing.view.document, 'keydown', ( ...args ) => this._handleTabOnSelectedTable( ...args ) );