Bug 1484111 - part 1: Create HTMLEditor::InsertTableCellsWithTransaction() for internal use of nsITableEditor::InsertTableCell() r=m_kato

nsITableEditor::InsertTableCell() is an XPCOM method but used internally.  So,
HTMLEditor should implement it with a non-virtual method and all internal users
should use it instead.

Differential Revision: https://phabricator.services.mozilla.com/D6259

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Masayuki Nakano 2018-09-20 11:44:35 +00:00
parent 3a48cf1623
commit 20d1804f6b
3 changed files with 120 additions and 45 deletions

View File

@ -1568,6 +1568,28 @@ protected: // Shouldn't be used by friend classes
eAfterSelectedCell,
};
/**
* InsertTableCellsWithTransaction() inserts <td> elements before or after
* a cell element containing first selection range. I.e., if the cell
* spans columns and aInsertPosition is eAfterSelectedCell, new columns
* will be inserted after the right-most column which contains the cell.
* Note that this simply inserts <td> elements, i.e., colspan and rowspan
* around the cell containing selection are not modified. So, for example,
* adding a cell to rectangular table changes non-rectangular table.
* And if the cell containing selection is at left of row-spanning cell,
* it may be moved to right side of the row-spanning cell after inserting
* some cell elements before it. Similarly, colspan won't be adjusted
* for keeping table rectangle.
* If first selection range is not in table cell element, this does nothing
* but does not return error.
*
* @param aNumberOfCellssToInsert Number of cells to insert.
* @param aInsertPosition Before or after the target cell which
* contains first selection range.
*/
nsresult InsertTableCellsWithTransaction(int32_t aNumberOfCellsToInsert,
InsertPosition aInsertPosition);
/**
* InsertTableColumnsWithTransaction() inserts columns before or after
* a cell element containing first selection range. I.e., if the cell

View File

@ -167,8 +167,22 @@ HTMLEditor::SetRowSpan(Element* aCell,
}
NS_IMETHODIMP
HTMLEditor::InsertTableCell(int32_t aNumber,
bool aAfter)
HTMLEditor::InsertTableCell(int32_t aNumberOfCellsToInsert,
bool aInsertAfterSelectedCell)
{
nsresult rv =
InsertTableCellsWithTransaction(aNumberOfCellsToInsert,
aInsertAfterSelectedCell ? InsertPosition::eAfterSelectedCell :
InsertPosition::eBeforeSelectedCell);
if (NS_WARN_IF(NS_FAILED(rv))) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
nsresult
HTMLEditor::InsertTableCellsWithTransaction(int32_t aNumberOfCellsToInsert,
InsertPosition aInsertPosition)
{
RefPtr<Element> table;
RefPtr<Element> curCell;
@ -179,45 +193,71 @@ HTMLEditor::InsertTableCell(int32_t aNumber,
getter_AddRefs(curCell),
getter_AddRefs(cellParent), &cellOffset,
&startRowIndex, &startColIndex);
NS_ENSURE_SUCCESS(rv, rv);
// Don't fail if no cell found
NS_ENSURE_TRUE(curCell, NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (NS_WARN_IF(!curCell)) {
// Don't fail if no cell found.
return NS_OK;
}
// Get more data for current cell in row we are inserting at (we need COLSPAN)
int32_t curStartRowIndex, curStartColIndex, rowSpan, colSpan, actualRowSpan, actualColSpan;
bool isSelected;
// Get more data for current cell in row we are inserting at since we need
// colspan value.
int32_t curStartRowIndex = 0, curStartColIndex = 0;
int32_t rowSpan = 0, colSpan = 0;
int32_t actualRowSpan = 0, actualColSpan = 0;
bool isSelected = false;
rv = GetCellDataAt(table, startRowIndex, startColIndex,
getter_AddRefs(curCell),
&curStartRowIndex, &curStartColIndex, &rowSpan, &colSpan,
&actualRowSpan, &actualColSpan, &isSelected);
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(curCell, NS_ERROR_FAILURE);
int32_t newCellIndex = aAfter ? (startColIndex+colSpan) : startColIndex;
//We control selection resetting after the insert...
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (NS_WARN_IF(!curCell)) {
return NS_ERROR_FAILURE;
}
int32_t newCellIndex;
switch (aInsertPosition) {
case InsertPosition::eBeforeSelectedCell:
newCellIndex = startColIndex;
break;
case InsertPosition::eAfterSelectedCell:
newCellIndex = startColIndex + colSpan;
break;
default:
MOZ_ASSERT_UNREACHABLE("Invalid InsertPosition");
}
// We control selection resetting after the insert.
AutoSelectionSetterAfterTableEdit setCaret(*this, table, startRowIndex,
newCellIndex, ePreviousColumn,
false);
//...so suppress Rules System selection munging
// So, suppress Rules System selection munging.
AutoTransactionsConserveSelection dontChangeSelection(*this);
for (int32_t i = 0; i < aNumber; i++) {
EditorDOMPoint pointToInsert(cellParent, cellOffset);
if (NS_WARN_IF(!pointToInsert.IsSet())) {
return NS_ERROR_FAILURE;
}
if (aInsertPosition == InsertPosition::eAfterSelectedCell) {
DebugOnly<bool> advanced = pointToInsert.AdvanceOffset();
NS_WARNING_ASSERTION(advanced,
"Faild to move insertion point after the cell");
}
for (int32_t i = 0; i < aNumberOfCellsToInsert; i++) {
RefPtr<Element> newCell = CreateElementWithDefaults(*nsGkAtoms::td);
if (newCell) {
if (aAfter) {
cellOffset++;
}
rv = InsertNodeWithTransaction(*newCell,
EditorRawDOMPoint(cellParent, cellOffset));
if (NS_FAILED(rv)) {
break;
}
} else {
rv = NS_ERROR_FAILURE;
if (NS_WARN_IF(!newCell)) {
return NS_ERROR_FAILURE;
}
AutoEditorDOMPointChildInvalidator lockOffset(pointToInsert);
rv = InsertNodeWithTransaction(*newCell, pointToInsert);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
}
// XXX This is perhaps the result of the last call of
// InsertNodeWithTransaction() or CreateElementWithDefaults().
return rv;
return NS_OK;
}
NS_IMETHODIMP
@ -503,12 +543,14 @@ HTMLEditor::InsertTableColumnsWithTransaction(int32_t aNumberOfColumnsToInsert,
}
// Simply set selection to the current cell. So, we can let
// InsertTableCell() do the work. Insert a new cell before current one.
// InsertTableCellsWithTransaction() do the work. Insert a new cell
// before current one.
IgnoredErrorResult ignoredError;
selection->Collapse(RawRangeBoundary(curCell, 0), ignoredError);
NS_WARNING_ASSERTION(!ignoredError.Failed(),
"Failed to collapse Selection into the cell");
rv = InsertTableCell(aNumberOfColumnsToInsert, false);
rv = InsertTableCellsWithTransaction(aNumberOfColumnsToInsert,
InsertPosition::eBeforeSelectedCell);
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to insert a cell element");
continue;
}
@ -555,10 +597,12 @@ HTMLEditor::InsertTableColumnsWithTransaction(int32_t aNumberOfColumnsToInsert,
selection->Collapse(RawRangeBoundary(curCell, 0), ignoredError);
NS_WARNING_ASSERTION(!ignoredError.Failed(),
"Failed to collapse Selection into the cell");
rv = InsertTableCell(aNumberOfColumnsToInsert, true);
rv = InsertTableCellsWithTransaction(aNumberOfColumnsToInsert,
InsertPosition::eAfterSelectedCell);
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to insert a cell element");
}
// XXX This is perhaps the result of the last call of InsertTableCell().
// XXX This is perhaps the result of the last call of
// InsertTableCellsWithTransaction().
return rv;
}

View File

@ -17,19 +17,28 @@ interface nsITableEditor : nsISupports
const short ePreviousColumn = 1;
const short ePreviousRow = 2;
/* ------------ Table editing Methods -------------- */
/** Insert table methods
* Insert relative to the selected cell or the
* cell enclosing the selection anchor
* The selection is collapsed and is left in the new cell
* at the same row,col location as the original anchor cell
*
* @param aNumber Number of items to insert
* @param aAfter If TRUE, insert after the current cell,
* else insert before current cell
*/
void insertTableCell(in long aNumber, in boolean aAfter);
/**
* insertTableCell() inserts <td> elements before or after a cell element
* containing first selection range. I.e., if the cell spans columns and
* aInsertPosition is true, new columns will be inserted after the
* right-most column which contains the cell. Note that this simply
* inserts <td> elements, i.e., colspan and rowspan around the cell
* containing selection are not modified. So, for example, adding a cell
* to rectangular table changes non-rectangular table. And if a cell
* containing selection is at left of row-spanning cell, it may be moved to
* right side of the row-spanning cell after inserting some cell elements
* before it. Similarly, colspan won't be adjusted for keeping table
* rectangle.
* If first selection range is not in table cell element, this does nothing
* without exception.
*
* @param aNumberOfCellssToInsert Number of cells to insert.
* @param aInsertAfterSelectedCell true if new cells should be inserted
* before current cell. Otherwise, will
* be inserted after the cell.
*/
void insertTableCell(in long aNumberOfColumnsToInsert,
in boolean aInsertAfterSelectedCell);
/**
* insertTableColumn() inserts columns before or after a cell element