jenkins-bot has submitted this change and it was merged. Change subject: Don't unmerge spanned cells when spanned cell is removed ......................................................................
Don't unmerge spanned cells when spanned cell is removed Previously we inserted regular cells in place of every placeholder in the matrix, which meant that deleting a row which happened to contain a rowspanned cell would split the rest of the cell apart, and the contents would be lost. (Same for columns.) Now we only replace one of the placeholders with a new spanned cell, appropriately smaller. The new cell inherits all of the properties and content of the removed cell, with the span adjusted. Bonus: When unmerging a header cell, all newly split cells also get header style. Previously first row would get header style and the rest would get data style, which was an accidental effect of how ve.dm.TableMatrix#findClosestCell works. Bug: 73213 Change-Id: I62e56657c18bc67be859ece882770ce008bc3838 --- M src/dm/nodes/ve.dm.TableCellNode.js M src/ui/actions/ve.ui.TableAction.js 2 files changed, 39 insertions(+), 26 deletions(-) Approvals: Esanders: Looks good to me, approved jenkins-bot: Verified diff --git a/src/dm/nodes/ve.dm.TableCellNode.js b/src/dm/nodes/ve.dm.TableCellNode.js index c9017dc..662cfe8 100644 --- a/src/dm/nodes/ve.dm.TableCellNode.js +++ b/src/dm/nodes/ve.dm.TableCellNode.js @@ -88,22 +88,29 @@ /** * Creates data that can be inserted into the model to create a new table cell. * - * @param {Object} [options] An object with property 'style' which can be either 'header' or 'data'. + * @param {Object} [options] + * @param {string} [options.style='data'] Either 'header' or 'data' + * @param {number} [options.rowspan=1] Number of rows the cell spans + * @param {number} [options.colspan=1] Number of columns the cell spans + * @param {Array} [options.content] Linear model data, defaults to empty wrapper paragraph * @return {Array} Model data for a new table cell */ ve.dm.TableCellNode.static.createData = function ( options ) { + var opening, content; options = options || {}; - return [ - { - type: 'tableCell', - attributes: { - style: options.style || 'data' - } - }, + opening = { + type: 'tableCell', + attributes: { + style: options.style || 'data', + rowspan: options.rowspan || 1, + colspan: options.colspan || 1 + } + }; + content = options.content || [ { type: 'paragraph', internal: { generated: 'wrapper' } }, - { type: '/paragraph' }, - { type: '/tableCell' } + { type: '/paragraph' } ]; + return [ opening ].concat( content ).concat( [ { type: '/tableCell' } ] ); }; /* Methods */ diff --git a/src/ui/actions/ve.ui.TableAction.js b/src/ui/actions/ve.ui.TableAction.js index 56574f0..8e47a2d 100644 --- a/src/ui/actions/ve.ui.TableAction.js +++ b/src/ui/actions/ve.ui.TableAction.js @@ -199,7 +199,11 @@ ); for ( i = cells.length - 1; i >= 1; i-- ) { txs.push( - this.replacePlaceholder( selection.getTableNode().getMatrix(), cells[i] ) + this.replacePlaceholder( + selection.getTableNode().getMatrix(), + cells[i], + { style: cells[0].node.getStyle() } + ) ); } } else { @@ -452,10 +456,10 @@ surfaceModel = this.surface.getModel(); // Deleting cells can have two additional consequences: - // 1. The cell is a Placeholder. The owner's span might be decreased. + // 1. The cell is a Placeholder. The owner's span must be decreased. // 2. The cell is owner of placeholders which get orphaned by the deletion. - // New, empty cells must be inserted to replace the placeholders and keep the - // table in proper shape. + // The first of the placeholders now becomes the real cell, with the span adjusted. + // It also inherits all of the properties and content of the removed cell. // Insertions and deletions of cells must be done in an appropriate order, so that the transactions // do not interfere with each other. To achieve that, we record insertions and deletions and // sort them by the position of the cell (row, column) in the table matrix. @@ -502,11 +506,14 @@ endCol = cell.col + cell.node.getColspan() - 1; // Record the insertion to apply it later - for ( row = startRow; row <= endRow; row++ ) { - for ( col = startCol; col <= endCol; col++ ) { - actions.push( { action: 'insert', cell: matrix.getCell( row, col ) } ); - } - } + actions.push( { + action: 'insert', + cell: matrix.getCell( startRow, startCol ), + colspan: 1 + endCol - startCol, + rowspan: 1 + endRow - startRow, + style: cell.node.getStyle(), + content: surfaceModel.getDocument().getData( cell.node.getRange() ) + } ); } // Cell nodes only get deleted when deleting columns (otherwise row nodes) @@ -526,7 +533,7 @@ // First replace orphaned placeholders which are below the last deleted row, // thus, this works with regard to transaction offsets for ( i = 0; i < actions.length; i++ ) { - txs.push( this.replacePlaceholder( matrix, actions[i].cell ) ); + txs.push( this.replacePlaceholder( matrix, actions[i].cell, actions[i] ) ); } // Remove rows in reverse order to have valid transaction offsets for ( row = maxIndex; row >= minIndex; row-- ) { @@ -536,7 +543,7 @@ } else { for ( i = 0; i < actions.length; i++ ) { if ( actions[i].action === 'insert' ) { - txs.push( this.replacePlaceholder( matrix, actions[i].cell ) ); + txs.push( this.replacePlaceholder( matrix, actions[i].cell, actions[i] ) ); } else { txs.push( ve.dm.Transaction.newFromRemoval( surfaceModel.getDocument(), actions[i].cell.node.getOuterRange() ) ); } @@ -550,10 +557,11 @@ * * @param {ve.dm.TableMatrix} matrix Table matrix * @param {ve.dm.TableMatrixCell} placeholder Placeholder cell to replace + * @param {Object} [options] Options to pass to ve.dm.TableCellNode.static.createData * @return {ve.dm.Transaction} Transaction */ -ve.ui.TableAction.prototype.replacePlaceholder = function ( matrix, placeholder ) { - var range, offset, data, style, +ve.ui.TableAction.prototype.replacePlaceholder = function ( matrix, placeholder, options ) { + var range, offset, data, // For inserting the new cell a reference cell node // which is used to get an insertion offset. refCell = matrix.findClosestCell( placeholder ), @@ -562,14 +570,12 @@ if ( refCell ) { range = refCell.node.getOuterRange(); offset = ( placeholder.col < refCell.col ) ? range.start : range.end; - style = refCell.node.getStyle(); } else { // if there are only placeholders in the row, the row node's inner range is used range = matrix.getRowNode( placeholder.row ).getRange(); offset = range.start; - style = placeholder.node.getStyle(); } - data = ve.dm.TableCellNode.static.createData( { style: style } ); + data = ve.dm.TableCellNode.static.createData( options ); return ve.dm.Transaction.newFromInsertion( surfaceModel.getDocument(), offset, data ); }; -- To view, visit https://gerrit.wikimedia.org/r/172193 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: I62e56657c18bc67be859ece882770ce008bc3838 Gerrit-PatchSet: 6 Gerrit-Project: VisualEditor/VisualEditor Gerrit-Branch: master Gerrit-Owner: Bartosz Dziewoński <matma....@gmail.com> Gerrit-Reviewer: Bartosz Dziewoński <matma....@gmail.com> Gerrit-Reviewer: Esanders <esand...@wikimedia.org> Gerrit-Reviewer: jenkins-bot <> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits