Explorar el Código

Changed: Cleanup downcast conversion & update TableWalker internals.

Maciej Gołaszewski hace 7 años
padre
commit
9bfe5b5cb8

+ 61 - 22
packages/ckeditor5-table/src/converters/downcast.js

@@ -45,10 +45,15 @@ export function downcastInsertTable( options = {} ) {
 
 		const tableWalker = new TableWalker( table );
 
+		const tableAttributes = {
+			headingRows: parseInt( table.getAttribute( 'headingRows' ) || 0 ),
+			headingColumns: parseInt( table.getAttribute( 'headingColumns' ) || 0 )
+		};
+
 		for ( const tableWalkerValue of tableWalker ) {
 			const { row, cell } = tableWalkerValue;
 
-			const tableSection = getOrCreateTableSection( getSectionName( tableWalkerValue ), tableElement, conversionApi );
+			const tableSection = getOrCreateTableSection( getSectionName( row, tableAttributes ), tableElement, conversionApi );
 			const tableRow = table.getChild( row );
 
 			// Check if row was converted
@@ -57,7 +62,9 @@ export function downcastInsertTable( options = {} ) {
 			// Consume table cell - it will be always consumed as we convert whole table at once.
 			conversionApi.consumable.consume( cell, 'insert' );
 
-			createViewTableCellElement( tableWalkerValue, ViewPosition.createAt( trElement, 'end' ), conversionApi, options );
+			const insertPosition = ViewPosition.createAt( trElement, 'end' );
+
+			createViewTableCellElement( tableWalkerValue, tableAttributes, insertPosition, conversionApi, options );
 		}
 
 		const viewPosition = conversionApi.mapper.toViewPosition( data.range.start );
@@ -90,14 +97,21 @@ export function downcastInsertRow( options = {} ) {
 
 		const tableWalker = new TableWalker( table, { startRow: row, endRow: row } );
 
+		const tableAttributes = {
+			headingRows: parseInt( table.getAttribute( 'headingRows' ) || 0 ),
+			headingColumns: parseInt( table.getAttribute( 'headingColumns' ) || 0 )
+		};
+
 		for ( const tableWalkerValue of tableWalker ) {
-			const tableSection = getOrCreateTableSection( getSectionName( tableWalkerValue ), tableElement, conversionApi );
+			const tableSection = getOrCreateTableSection( getSectionName( row, tableAttributes ), tableElement, conversionApi );
 			const trElement = getOrCreateTr( tableRow, row, tableSection, conversionApi );
 
 			// Consume table cell - it will be always consumed as we convert whole row at once.
 			conversionApi.consumable.consume( tableWalkerValue.cell, 'insert' );
 
-			createViewTableCellElement( tableWalkerValue, ViewPosition.createAt( trElement, 'end' ), conversionApi, options );
+			const insertPosition = ViewPosition.createAt( trElement, 'end' );
+
+			createViewTableCellElement( tableWalkerValue, tableAttributes, insertPosition, conversionApi, options );
 		}
 	}, { priority: 'normal' } );
 }
@@ -122,13 +136,18 @@ export function downcastInsertCell( options = {} ) {
 
 		const tableWalker = new TableWalker( table );
 
+		const tableAttributes = {
+			headingRows: parseInt( table.getAttribute( 'headingRows' ) || 0 ),
+			headingColumns: parseInt( table.getAttribute( 'headingColumns' ) || 0 )
+		};
+
 		// We need to iterate over a table in order to get proper row & column values from a walker
 		for ( const tableWalkerValue of tableWalker ) {
 			if ( tableWalkerValue.cell === tableCell ) {
 				const trElement = conversionApi.mapper.toViewElement( tableRow );
 				const insertPosition = ViewPosition.createAt( trElement, tableRow.getChildIndex( tableCell ) );
 
-				createViewTableCellElement( tableWalkerValue, insertPosition, conversionApi, options );
+				createViewTableCellElement( tableWalkerValue, tableAttributes, insertPosition, conversionApi, options );
 
 				// No need to iterate further.
 				return;
@@ -193,8 +212,13 @@ export function downcastTableHeadingRowsChange( options = {} ) {
 			// Check if cells moved from <thead> to <tbody> requires renaming to <td> as this depends on current heading columns attribute.
 			const tableWalker = new TableWalker( table, { startRow: newRows ? newRows - 1 : newRows, endRow: oldRows - 1 } );
 
+			const tableAttributes = {
+				headingRows: parseInt( table.getAttribute( 'headingRows' ) || 0 ),
+				headingColumns: parseInt( table.getAttribute( 'headingColumns' ) || 0 )
+			};
+
 			for ( const tableWalkerValue of tableWalker ) {
-				renameViewTableCellIfRequired( tableWalkerValue, conversionApi, asWidget );
+				renameViewTableCellIfRequired( tableWalkerValue, tableAttributes, conversionApi, asWidget );
 			}
 
 			// Cleanup: this will remove any empty section from the view which may happen when moving all rows from a table section.
@@ -224,9 +248,23 @@ export function downcastTableHeadingColumnsChange( options = {} ) {
 			return;
 		}
 
-		// TODO: column walk only?
+		const tableAttributes = {
+			headingRows: parseInt( table.getAttribute( 'headingRows' ) || 0 ),
+			headingColumns: parseInt( table.getAttribute( 'headingColumns' ) || 0 )
+		};
+
+		const oldColumns = data.attributeOldValue;
+		const newColumns = data.attributeNewValue;
+
+		const lastColumnToCheck = ( oldColumns > newColumns ? oldColumns : newColumns ) - 1;
+
 		for ( const tableWalkerValue of new TableWalker( table ) ) {
-			renameViewTableCellIfRequired( tableWalkerValue, conversionApi, asWidget );
+			// Skip cells that were not in heading section before and after the change.
+			if ( tableWalkerValue.column > lastColumnToCheck ) {
+				continue;
+			}
+
+			renameViewTableCellIfRequired( tableWalkerValue, tableAttributes, conversionApi, asWidget );
 		}
 	}, { priority: 'normal' } );
 }
@@ -296,13 +334,14 @@ function renameViewTableCell( tableCell, desiredCellElementName, conversionApi,
 // Renames a table cell element in a view according to it's location in table.
 //
 // @param {module:table/tablewalker~TableWalkerValue} tableWalkerValue
+// @param {{headingColumns, headingRows}} tableAttributes
 // @param {Object} conversionApi
 // @param {Boolean} asWidget
-function renameViewTableCellIfRequired( tableWalkerValue, conversionApi, asWidget ) {
+function renameViewTableCellIfRequired( tableWalkerValue, tableAttributes, conversionApi, asWidget ) {
 	const { cell } = tableWalkerValue;
 
 	// Check whether current columnIndex is overlapped by table cells from previous rows.
-	const desiredCellElementName = getCellElementName( tableWalkerValue );
+	const desiredCellElementName = getCellElementName( tableWalkerValue, tableAttributes );
 
 	const viewCell = conversionApi.mapper.toViewElement( cell );
 
@@ -318,17 +357,16 @@ function renameViewTableCellIfRequired( tableWalkerValue, conversionApi, asWidge
 // @param {module:table/tablewalker~TableWalkerValue} tableWalkerValue
 // @param {module:engine/view/position~Position} insertPosition
 // @param {Object} conversionApi
-function createViewTableCellElement( tableWalkerValue, insertPosition, conversionApi, options ) {
-	const tableCell = tableWalkerValue.cell;
-
+function createViewTableCellElement( tableWalkerValue, tableAttributes, insertPosition, conversionApi, options ) {
 	const asWidget = options && options.asWidget;
-
-	const cellElementName = getCellElementName( tableWalkerValue );
+	const cellElementName = getCellElementName( tableWalkerValue, tableAttributes );
 
 	const cellElement = asWidget ?
 		toWidgetEditable( conversionApi.writer.createEditableElement( cellElementName ), conversionApi.writer ) :
 		conversionApi.writer.createContainerElement( cellElementName );
 
+	const tableCell = tableWalkerValue.cell;
+
 	conversionApi.mapper.bindElements( tableCell, cellElement );
 	conversionApi.writer.insert( insertPosition, cellElement );
 }
@@ -363,9 +401,11 @@ function getOrCreateTr( tableRow, rowIndex, tableSection, conversionApi ) {
 // Returns `th` for heading cells and `td` for other cells for current table walker value.
 //
 // @param {module:table/tablewalker~TableWalkerValue} tableWalkerValue
+// @param {{headingColumns, headingRows}} tableAttributes
 // @returns {String}
-function getCellElementName( tableWalkerValue ) {
-	const { row, column, table: { headingRows, headingColumns } } = tableWalkerValue;
+function getCellElementName( tableWalkerValue, tableAttributes ) {
+	const { row, column } = tableWalkerValue;
+	const { headingColumns, headingRows } = tableAttributes;
 
 	// Column heading are all tableCells in the first `columnHeading` rows.
 	const isColumnHeading = headingRows && headingRows > row;
@@ -383,12 +423,11 @@ function getCellElementName( tableWalkerValue ) {
 
 // Returns table section name for current table walker value.
 //
-// @param {module:table/tablewalker~TableWalkerValue} tableWalkerValue
+// @param {Number} row
+// @param {{headingColumns, headingRows}} tableAttributes
 // @returns {String}
-function getSectionName( tableWalkerValue ) {
-	const { row, table: { headingRows } } = tableWalkerValue;
-
-	return row < headingRows ? 'thead' : 'tbody';
+function getSectionName( row, tableAttributes ) {
+	return row < tableAttributes.headingRows ? 'thead' : 'tbody';
 }
 
 // Creates or returns an existing <tbody> or <thead> element witch caching.

+ 8 - 8
packages/ckeditor5-table/src/tableutils.js

@@ -42,13 +42,13 @@ export default class TableUtils extends Plugin {
 	 *
 	 * the method will return:
 	 *
-	 *     const cellA = table.getNodeByPath( [ 0, 0 ] );
-	 *     editor.plugins.get( 'TableUtils' ).getCellLocation( cellA );
-	 *     // will return { row: 0, column: 0 }
+	 *		const cellA = table.getNodeByPath( [ 0, 0 ] );
+	 *		editor.plugins.get( 'TableUtils' ).getCellLocation( cellA );
+	 *		// will return { row: 0, column: 0 }
 	 *
-	 *     const cellD = table.getNodeByPath( [ 1, 0 ] );
-	 *     editor.plugins.get( 'TableUtils' ).getCellLocation( cellD );
-	 *     // will return { row: 1, column: 3 }
+	 *		const cellD = table.getNodeByPath( [ 1, 0 ] );
+	 *		editor.plugins.get( 'TableUtils' ).getCellLocation( cellD );
+	 *		// will return { row: 1, column: 3 }
 	 *
 	 * @param {module:engine/model/element~Element} tableCell
 	 * @returns {{row, column}}
@@ -164,7 +164,7 @@ export default class TableUtils extends Plugin {
 	/**
 	 * Inserts columns into a table.
 	 *
-	 *     editor.plugins.get( 'TableUtils' ).insertColumns( table, { at: 1, columns: 2 } );
+	 *		editor.plugins.get( 'TableUtils' ).insertColumns( table, { at: 1, columns: 2 } );
 	 *
 	 * For the table below this code
 	 *
@@ -407,7 +407,7 @@ export default class TableUtils extends Plugin {
 	/**
 	 * Returns number of columns for given table.
 	 *
-	 *     editor.plugins.get( 'TableUtils' ).getColumns( table );
+	 *		editor.plugins.get( 'TableUtils' ).getColumns( table );
 	 *
 	 * @param {module:engine/model/element~Element} table Table to analyze.
 	 * @returns {Number}

+ 178 - 94
packages/ckeditor5-table/src/tablewalker.js

@@ -13,9 +13,15 @@
  */
 export default class TableWalker {
 	/**
-	 * Creates a range iterator. All parameters are optional, but you have to specify either `boundaries` or `startPosition`.
+	 * Creates an instance of table walker.
 	 *
-	 * The most important values of iterator values are column & row of a cell.
+	 *
+	 * The TableWalker iterates internally by traversing table from row index = 0 and column index = 0.
+	 * It walks row by row and column by column in order to output values defined in constructor.
+	 * By default it will output only those locations that are occupied by a cell to include also a spanned rows & columns
+	 * pass `includeSpanned` option to a constructor.
+	 *
+	 * The most important values of iterator values are column & row indexes of a cell.
 	 *
 	 * To iterate over given row:
 	 *
@@ -37,14 +43,14 @@ export default class TableWalker {
 	 *		| 31 | 32 |                   |
 	 *		+----+----+----+----+----+----+
 	 *
-	 *	will log in the console:
+	 * will log in the console:
 	 *
 	 *		'A cell at row 1 and column 2'
 	 *		'A cell at row 1 and column 4'
 	 *		'A cell at row 1 and column 5'
 	 *		'A cell at row 2 and column 2'
 	 *
-	 *	To iterate over spanned cells also:
+	 * To iterate over spanned cells also:
 	 *
 	 *		const tableWalker = new TableWalker( table, { startRow: 1, endRow: 1, includeSpanned: true } );
 	 *
@@ -52,7 +58,7 @@ export default class TableWalker {
 	 *			console.log( 'Cell at ' + cellInfo.row + ' x ' + cellInfo.column + ' : ' + ( cellInfo.cell ? 'has data' : 'is spanned' ) );
 	 *		}
 	 *
-	 *	will log in the console for the table from previous example:
+	 * will log in the console for the table from previous example:
 	 *
 	 *		'Cell at 1 x 0 : is spanned'
 	 *		'Cell at 1 x 1 : is spanned'
@@ -97,68 +103,64 @@ export default class TableWalker {
 		/**
 		 * Enables output of spanned cells that are normally not yielded.
 		 *
-		 * @type {Boolean}
+		 * @readonly
+		 * @member {Boolean}
 		 */
 		this.includeSpanned = !!options.includeSpanned;
 
-		this._ccc = typeof options.column == 'number' ? options.column : undefined;
-
-		this._skipRows = new Set();
-
 		/**
-		 * A current row index.
+		 * If set table walker will only output cells of given column or cells that overlaps it.
 		 *
 		 * @readonly
 		 * @member {Number}
 		 */
-		this.row = 0;
+		this.column = typeof options.column == 'number' ? options.column : undefined;
 
 		/**
-		 * A current cell index in a row.
+		 * Row indexes to skip from iteration.
 		 *
 		 * @readonly
-		 * @member {Number}
+		 * @member {Set<Number>}
+		 * @private
 		 */
-		this.cell = 0;
+		this._skipRows = new Set();
 
 		/**
-		 * A current column index.
+		 * A current row index.
 		 *
 		 * @readonly
 		 * @member {Number}
+		 * @private
 		 */
-		this.column = 0;
+		this._row = 0;
 
 		/**
-		 * The previous cell in a row.
+		 * A current column index.
 		 *
 		 * @readonly
-		 * @member {module:engine/model/element~Element}
+		 * @member {Number}
 		 * @private
 		 */
-		this._previousCell = undefined;
+		this._column = 0;
 
 		/**
-		 * Holds spanned cells info to be outputed when {@link #includeSpanned} is set to true.
+		 * A cell index in a parent row. For spanned cells when {@link #includeSpanned} is set to true
+		 * this represents the index of next table cell.
 		 *
-		 * @type {Array.<module:table/tablewalker~TableWalkerValue>}
+		 * @readonly
+		 * @member {Number}
 		 * @private
 		 */
-		this._spannedCells = [];
+		this._cell = 0;
 
 		/**
-		 * Cached table properties - returned for every yielded value.
+		 * Holds map of spanned cells in a table.
 		 *
 		 * @readonly
-		 * @member {{headingRows: Number, headingColumns: Number}}
+		 * @member {Map<Number, Map.<Number, Number>>}
 		 * @private
 		 */
-		this._tableData = {
-			headingRows: parseInt( this.table.getAttribute( 'headingRows' ) || 0 ),
-			headingColumns: parseInt( this.table.getAttribute( 'headingColumns' ) || 0 )
-		};
-
-		this._spans = new Map();
+		this._spannedCells = new Map();
 	}
 
 	/**
@@ -176,120 +178,205 @@ export default class TableWalker {
 	 * @returns {module:table/tablewalker~TableWalkerValue} Next table walker's value.
 	 */
 	next() {
-		const row = this.table.getChild( this.row );
+		const row = this.table.getChild( this._row );
 
-		if ( !row || ( this.endRow !== undefined && this.row > this.endRow ) ) {
+		// Iterator is done when no row (table end) or the row is after #endRow.
+		if ( !row || this._isOverEndRow() ) {
 			return { done: true };
 		}
 
-		if ( this._isSpanned( this.row, this.column ) ) {
-			const column = this.column;
-
-			const outValue = {
-				row: this.row,
-				column,
-				rowspan: 1,
-				colspan: 1,
-				cellIndex: this.cell,
-				cell: undefined,
-				table: this._tableData
-			};
+		// Spanned cell location handling.
+		if ( this._isSpanned( this._row, this._column ) ) {
+			// Current column must be kept as it will be updated before returning current value.
+			const currentColumn = this._column;
+			const outValue = this._formatOutValue( undefined, currentColumn );
 
-			this.column++;
+			// Advance to next column - always.
+			this._column++;
 
-			if ( !this.includeSpanned || this.startRow > this.row || this._checkCCC( column, 1 ) || this._skipRows.has( this.row ) ) {
-				return this.next();
-			}
+			const skipCurrentValue = !this.includeSpanned || this._shouldSkipRow() || this._shouldSkipColumn( currentColumn, 1 );
 
-			return { done: false, value: outValue };
+			// The current value will be returned only if #includedSpanned=true and also current row and column are not skipped.
+			return skipCurrentValue ? this.next() : outValue;
 		}
 
-		const cell = row.getChild( this.cell );
+		// The cell location is not spanned by other cells.
+		const cell = row.getChild( this._cell );
 
 		if ( !cell ) {
-			this.row++;
-			this.column = 0;
-			this.cell = 0;
+			// If there are no more cells left in row advance to next row.
+			this._row++;
+			// And reset column & cell indexes.
+			this._column = 0;
+			this._cell = 0;
 
+			// Return next value.
 			return this.next();
 		}
 
+		// Read table cell attributes.
 		const colspan = parseInt( cell.getAttribute( 'colspan' ) || 1 );
 		const rowspan = parseInt( cell.getAttribute( 'rowspan' ) || 1 );
 
+		// Record this cell spans if it's not 1x1 cell.
 		if ( colspan > 1 || rowspan > 1 ) {
-			this._recordSpans( this.row, this.column, rowspan, colspan );
+			this._recordSpans( this._row, this._column, rowspan, colspan );
 		}
 
-		const column = this.column;
+		// Current column must be kept as it will be updated before returning current value.
+		const currentColumn = this._column;
+		const outValue = this._formatOutValue( cell, currentColumn, rowspan, colspan );
 
-		const outValue = {
-			cell,
-			row: this.row,
-			column,
-			rowspan,
-			colspan,
-			cellIndex: this.cell,
-			table: this._tableData
-		};
+		// Advance to next column before returning value.
+		this._column++;
 
-		this.column++;
-		this.cell++;
+		// Advance to next cell in a parent row before returning value.
+		this._cell++;
 
-		if ( this.startRow > this.row || this._skipRows.has( this.row ) || this._checkCCC( column, colspan ) ) {
-			return this.next();
-		}
+		const skipCurrentValue = this._shouldSkipRow() || this._shouldSkipColumn( currentColumn, colspan );
+
+		// The current value will be returned only if current row & column are not skipped.
+		return skipCurrentValue ? this.next() : outValue;
+	}
 
+	/**
+	 * Mark a row to skip on next iteration - will skip also cells from current row if any.
+	 *
+	 * @param {Number} row Row index to skip.
+	 */
+	skipRow( row ) {
+		this._skipRows.add( row );
+	}
+
+	/**
+	 * Check if current row is over {@link #endRow}.
+	 *
+	 * @returns {Boolean}
+	 * @private
+	 */
+	_isOverEndRow() {
+		// If {@link #endRow) is defined skipp all rows above it.
+		return this.endRow !== undefined && this._row > this.endRow;
+	}
+
+	/**
+	 * Common method for formatting iterator's out value.
+	 *
+	 * @param {module:engine/model/element~Element|undefined} cell Table cell to output. Might be undefined for spanned cell locations.
+	 * @param {Number} column Column index (use cached value)
+	 * @param {Number} rowspan Rowspan of current cell.
+	 * @param {Number} colspan Colspan of current cell.
+	 * @returns {{done: boolean, value: {cell: *, row: Number, column: *, rowspan: *, colspan: *, cellIndex: Number}}}
+	 * @private
+	 */
+	_formatOutValue( cell, column, rowspan = 1, colspan = 1 ) {
 		return {
 			done: false,
-			value: outValue
+			value: {
+				cell,
+				row: this._row,
+				column,
+				rowspan,
+				colspan,
+				cellIndex: this._cell
+			}
 		};
 	}
 
-	skipRow( row ) {
-		this._skipRows.add( row );
+	/**
+	 * Checks if current row should be skipped.
+	 *
+	 * @returns {Boolean}
+	 * @private
+	 */
+	_shouldSkipRow() {
+		const rowIsBelowStartRow = this._row < this.startRow;
+		const rowIsMarkedAsSkipped = this._skipRows.has( this._row );
+
+		return rowIsBelowStartRow || rowIsMarkedAsSkipped;
 	}
 
-	_checkCCC( column, colspan ) {
-		if ( this._ccc === undefined ) {
-			return;
+	/**
+	 * Checks if current column should be skipped.
+	 *
+	 * @param {Number} column
+	 * @param {Number} colspan
+	 * @returns {Boolean}
+	 * @private
+	 */
+	_shouldSkipColumn( column, colspan ) {
+		if ( this.column === undefined ) {
+			// The {@link #column} is not defined so output all columns.
+			return false;
 		}
 
-		return !( column === this._ccc || ( column < this._ccc && column + colspan > this._ccc ) );
+		// When outputting cells from given column we skip:
+		// - Cells that are not on that column.
+		const isCurrentColumn = column === this.column;
+		// - CSells that are before given column and they overlaps given column.
+		const isPreviousThatOverlapsColumn = column < this.column && column + colspan > this.column;
+
+		return !isCurrentColumn && !isPreviousThatOverlapsColumn;
 	}
 
+	/**
+	 * Checks if current cell location - row x column - is spanned by other cell.
+	 *
+	 * @param {Number} row Row index of a cell location to check.
+	 * @param {Number} column Column index of a cell location to check.
+	 * @returns {Boolean}
+	 * @private
+	 */
 	_isSpanned( row, column ) {
-		if ( !this._spans.has( row ) ) {
+		if ( !this._spannedCells.has( row ) ) {
+			// No spans for given row.
 			return false;
 		}
 
-		const rowSpans = this._spans.get( row );
+		const rowSpans = this._spannedCells.get( row );
 
-		return rowSpans.has( column ) ? rowSpans.get( column ) : false;
+		// If spans for given rows has entry for column it means that this location if spanned by other cell.
+		return rowSpans.has( column );
 	}
 
+	/**
+	 * Updates spanned cells map relative to current cell location and it's span dimensions.
+	 *
+	 * @param {Number} row Row index of a cell.
+	 * @param {Number} column Column index of a cell.
+	 * @param {Number} rowspan Cell's height.
+	 * @param {Number} colspan Cell's width.
+	 * @private
+	 */
 	_recordSpans( row, column, rowspan, colspan ) {
-		// This will update all rows after columns
+		// This will update all cell locations after current column - ie a cell has colspan set.
 		for ( let columnToUpdate = column + 1; columnToUpdate <= column + colspan - 1; columnToUpdate++ ) {
-			this._recordSpan( row, columnToUpdate );
+			this._markSpannedCell( row, columnToUpdate );
 		}
 
-		// This will update all rows below up to row height with value of span width.
+		// This will update all rows below current up to row's height.
 		for ( let rowToUpdate = row + 1; rowToUpdate < row + rowspan; rowToUpdate++ ) {
 			for ( let columnToUpdate = column; columnToUpdate <= column + colspan - 1; columnToUpdate++ ) {
-				this._recordSpan( rowToUpdate, columnToUpdate );
+				this._markSpannedCell( rowToUpdate, columnToUpdate );
 			}
 		}
 	}
 
-	_recordSpan( row, column ) {
-		if ( !this._spans.has( row ) ) {
-			this._spans.set( row, new Map() );
+	/**
+	 * Marks cell location as spanned by other cell.
+	 *
+	 * @param {Number} row Row index of cell location.
+	 * @param {Number} column Column index of cell location.
+	 * @private
+	 */
+	_markSpannedCell( row, column ) {
+		if ( !this._spannedCells.has( row ) ) {
+			this._spannedCells.set( row, new Map() );
 		}
 
-		const rowSpans = this._spans.get( row );
+		const rowSpans = this._spannedCells.get( row );
 
-		rowSpans.set( column, 1 );
+		rowSpans.set( column, true );
 	}
 }
 
@@ -305,9 +392,6 @@ export default class TableWalker {
  * {@link module:table/tablewalker~TableWalker#includeSpanned} is set to true.
  * @property {Number} [rowspan] The rowspan attribute of a cell - always defined even if model attribute is not present. Not set if
  * {@link module:table/tablewalker~TableWalker#includeSpanned} is set to true.
- * @property {Number} cellIndex The index of a current cell in parent row. When using `includeSpanned` option it will indicate next child
- * index if #cell is empty (spanned cell).
- * @property {Object} table Table attributes
- * @property {Object} table.headingRows The heading rows attribute of a table - always defined even if model attribute is not present.
- * @property {Object} table.headingColumns The heading columns attribute of a table - always defined even if model attribute is not present.
+ * @property {Number} cellIndex The index of a current cell in a parent row. When using `includeSpanned` option it will indicate next child
+ * index if #cell is empty (which indicates that cell is spanned by other cell).
  */