Commit 8e652599 authored by Masayuki Nakano's avatar Masayuki Nakano
Browse files

Bug 1730442 - part 6: Make `HTMLEditor::InsertTableColumnsWithTransaction()`...

Bug 1730442 - part 6: Make `HTMLEditor::InsertTableColumnsWithTransaction()` collects all necessary data before touching the DOM tree r=m_kato

It needs to work with the latest layout information to consider which cell
element is the insertion point due to rowspan and colspan.  Therefore,
this patch makes it collects all cell data before touching the DOM except
the case that it needs to normalize the table to make it rectanble.

Note that the case requring the normalizer should be fixed in a later patch.

This method is corresponding to an XPCOM method.  Therefore, this is tested
by `test_nsITableEditor_insertTableColumn.html`.

And also it's used by the inline table editor, but we don't have automated tests
for this because of no API to get the buttons.  Therefore, I tested it by my
hand.

Depends on D146363

Differential Revision: https://phabricator.services.mozilla.com/D146364
parent 34b66d7d
Loading
Loading
Loading
Loading
+48 −0
Original line number Diff line number Diff line
@@ -1384,6 +1384,54 @@ class HTMLEditUtils final {
    return nullptr;
  }

  /**
   * GetFirstTableCellElementChild() and GetLastTableCellElementChild()
   * return the first/last element child of <tr> element if it's a table
   * cell element.
   */
  static Element* GetFirstTableCellElementChild(
      const Element& aTableRowElement) {
    MOZ_ASSERT(aTableRowElement.IsHTMLElement(nsGkAtoms::tr));
    Element* firstElementChild = aTableRowElement.GetFirstElementChild();
    return firstElementChild && HTMLEditUtils::IsTableCell(firstElementChild)
               ? firstElementChild
               : nullptr;
  }
  static Element* GetLastTableCellElementChild(
      const Element& aTableRowElement) {
    MOZ_ASSERT(aTableRowElement.IsHTMLElement(nsGkAtoms::tr));
    Element* lastElementChild = aTableRowElement.GetLastElementChild();
    return lastElementChild && HTMLEditUtils::IsTableCell(lastElementChild)
               ? lastElementChild
               : nullptr;
  }

  /**
   * GetPreviousTableCellElementSibling() and GetNextTableCellElementSibling()
   * return a table cell element of previous/next element sibling of given
   * content node if and only if the element sibling is a table cell element.
   */
  static Element* GetPreviousTableCellElementSibling(
      const nsIContent& aChildOfTableRow) {
    MOZ_ASSERT(aChildOfTableRow.GetParentNode());
    MOZ_ASSERT(aChildOfTableRow.GetParentNode()->IsHTMLElement(nsGkAtoms::tr));
    Element* previousElementSibling =
        aChildOfTableRow.GetPreviousElementSibling();
    return previousElementSibling &&
                   HTMLEditUtils::IsTableCell(previousElementSibling)
               ? previousElementSibling
               : nullptr;
  }
  static Element* GetNextTableCellElementSibling(
      const nsIContent& aChildOfTableRow) {
    MOZ_ASSERT(aChildOfTableRow.GetParentNode());
    MOZ_ASSERT(aChildOfTableRow.GetParentNode()->IsHTMLElement(nsGkAtoms::tr));
    Element* nextElementSibling = aChildOfTableRow.GetNextElementSibling();
    return nextElementSibling && HTMLEditUtils::IsTableCell(nextElementSibling)
               ? nextElementSibling
               : nullptr;
  }

  /**
   * GetMostDistantAncestorInlineElement() returns the most distant ancestor
   * inline element between aContent and the aEditingHost.  Even if aEditingHost
+11 −10
Original line number Diff line number Diff line
@@ -3242,6 +3242,13 @@ class HTMLEditor final : public EditorBase,
  Result<RefPtr<Element>, nsresult> GetSelectedOrParentTableElement(
      bool* aIsCellSelected = nullptr) const;

  /**
   * GetFirstSelectedCellElementInTable() returns <td> or <th> element at
   * first selection (using GetSelectedOrParentTableElement).  If found cell
   * element is not in <table> or <tr> element, this returns nullptr.
   */
  Result<RefPtr<Element>, nsresult> GetFirstSelectedCellElementInTable() const;

  /**
   * PasteInternal() pasts text with replacing selected content.
   * This tries to dispatch ePaste event first.  If its defaultPrevent() is
@@ -3595,19 +3602,13 @@ class HTMLEditor final : public EditorBase,
      const EditorDOMPoint& aPointToInsert, int32_t aNumberOfCellsToInsert);

  /**
   * InsertTableColumnsWithTransaction() inserts columns 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 row which contains the cell.
   * If first selection range is not in table cell element, this does nothing
   * but does not return error.
   * InsertTableColumnsWithTransaction() inserts cell elements to every rows
   * at same column index as the cell specified by aPointToInsert.
   *
   * @param aNumberOfColumnsToInsert    Number of columns to insert.
   * @param aInsertPosition             Before or after the target cell which
   *                                    contains first selection range.
   */
  MOZ_CAN_RUN_SCRIPT nsresult InsertTableColumnsWithTransaction(
      int32_t aNumberOfColumnsToInsert, InsertPosition aInsertPosition);
  [[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult InsertTableColumnsWithTransaction(
      const EditorDOMPoint& aPointToInsert, int32_t aNumberOfColumnsToInsert);

  /**
   * InsertTableRowsWithTransaction() inserts <tr> elements before or after
+24 −9
Original line number Diff line number Diff line
@@ -209,7 +209,10 @@ nsresult HTMLEditor::DoInlineTableEditingAction(const Element& aElement) {
    return NS_OK;
  }

  if (NS_WARN_IF(!mInlineEditedCell)) {
  if (NS_WARN_IF(!mInlineEditedCell) ||
      NS_WARN_IF(!mInlineEditedCell->IsInComposedDoc()) ||
      NS_WARN_IF(
          !HTMLEditUtils::IsTableRow(mInlineEditedCell->GetParentNode()))) {
    return NS_ERROR_NOT_AVAILABLE;
  }

@@ -244,12 +247,13 @@ nsresult HTMLEditor::DoInlineTableEditingAction(const Element& aElement) {
          "CanHandleAndMaybeDispatchBeforeInputEvent(), failed");
      return EditorBase::ToGenericNSResult(rv);
    }
    DebugOnly<nsresult> rvIgnored = InsertTableColumnsWithTransaction(
        1, InsertPosition::eBeforeSelectedCell);

    DebugOnly<nsresult> rvIgnored =
        InsertTableColumnsWithTransaction(EditorDOMPoint(mInlineEditedCell), 1);
    NS_WARNING_ASSERTION(
        NS_SUCCEEDED(rvIgnored),
        "HTMLEditor::InsertTableColumnsWithTransaction(1, "
        "InsertPosition::eBeforeSelectedCell) failed, but ignored");
        "HTMLEditor::InsertTableColumnsWithTransaction("
        "EditorDOMPoint(mInlineEditedCell), 1) failed, but ignored");
  } else if (anonclass.EqualsLiteral("mozTableAddColumnAfter")) {
    AutoEditActionDataSetter editActionData(*this,
                                            EditAction::eInsertTableColumn);
@@ -260,12 +264,24 @@ nsresult HTMLEditor::DoInlineTableEditingAction(const Element& aElement) {
          "CanHandleAndMaybeDispatchBeforeInputEvent(), failed");
      return EditorBase::ToGenericNSResult(rv);
    }
    Element* nextCellElement = nullptr;
    for (nsIContent* maybeNextCellElement = mInlineEditedCell->GetNextSibling();
         maybeNextCellElement;
         maybeNextCellElement = maybeNextCellElement->GetNextSibling()) {
      if (HTMLEditUtils::IsTableCell(maybeNextCellElement)) {
        nextCellElement = maybeNextCellElement->AsElement();
        break;
      }
    }
    DebugOnly<nsresult> rvIgnored = InsertTableColumnsWithTransaction(
        1, InsertPosition::eAfterSelectedCell);
        nextCellElement
            ? EditorDOMPoint(nextCellElement)
            : EditorDOMPoint::AtEndOf(*mInlineEditedCell->GetParentElement()),
        1);
    NS_WARNING_ASSERTION(
        NS_SUCCEEDED(rvIgnored),
        "HTMLEditor::InsertTableColumnsWithTransaction(1, "
        "InsertPosition::eAfterSelectedCell) failed, but ignored");
        "HTMLEditor::InsertTableColumnsWithTransaction("
        "EditorDOMPoint(nextCellElement), 1) failed, but ignored");
  } else if (anonclass.EqualsLiteral("mozTableAddRowBefore")) {
    AutoEditActionDataSetter editActionData(*this,
                                            EditAction::eInsertTableRowElement);
@@ -334,7 +350,6 @@ nsresult HTMLEditor::DoInlineTableEditingAction(const Element& aElement) {
    return NS_OK;
  }

  // InsertTableRowsWithTransaction() might causes reframe.
  if (NS_WARN_IF(Destroyed())) {
    return NS_OK;
  }
+247 −153

File changed.

Preview size limit exceeded, changes collapsed.