mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-26 12:20:56 +00:00
Bug 1762115 - part 13: Make EditorBase::InsertNodeWithTransaction
stop touching Selection
directly r=m_kato
Differential Revision: https://phabricator.services.mozilla.com/D144656
This commit is contained in:
parent
6ce22cc7c4
commit
fef1b61ead
@ -147,6 +147,13 @@ template EditorRawDOMPoint EditorBase::GetFirstIMESelectionStartPoint() const;
|
||||
template EditorDOMPoint EditorBase::GetLastIMESelectionEndPoint() const;
|
||||
template EditorRawDOMPoint EditorBase::GetLastIMESelectionEndPoint() const;
|
||||
|
||||
template CreateContentResult EditorBase::InsertNodeWithTransaction(
|
||||
nsIContent& aContentToInsert, const EditorDOMPoint& aPointToInsert);
|
||||
template CreateElementResult EditorBase::InsertNodeWithTransaction(
|
||||
Element& aContentToInsert, const EditorDOMPoint& aPointToInsert);
|
||||
template CreateTextResult EditorBase::InsertNodeWithTransaction(
|
||||
Text& aContentToInsert, const EditorDOMPoint& aPointToInsert);
|
||||
|
||||
template EditorDOMPoint EditorBase::GetFirstSelectionStartPoint() const;
|
||||
template EditorRawDOMPoint EditorBase::GetFirstSelectionStartPoint() const;
|
||||
template EditorDOMPoint EditorBase::GetFirstSelectionEndPoint() const;
|
||||
@ -2032,21 +2039,37 @@ NS_IMETHODIMP EditorBase::InsertNode(nsINode* aNodeToInsert,
|
||||
return EditorBase::ToGenericNSResult(rv);
|
||||
}
|
||||
|
||||
uint32_t offset = std::min(aOffset, aContainer->Length());
|
||||
rv = InsertNodeWithTransaction(*contentToInsert,
|
||||
EditorDOMPoint(aContainer, offset));
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"EditorBase::InsertNodeWithTransaction() failed");
|
||||
return EditorBase::ToGenericNSResult(rv);
|
||||
const uint32_t offset = std::min(aOffset, aContainer->Length());
|
||||
CreateContentResult insertContentResult = InsertNodeWithTransaction(
|
||||
*contentToInsert, EditorDOMPoint(aContainer, offset));
|
||||
if (insertContentResult.isErr()) {
|
||||
NS_WARNING("EditorBase::InsertNodeWithTransaction() failed");
|
||||
return EditorBase::ToGenericNSResult(insertContentResult.unwrapErr());
|
||||
}
|
||||
rv = insertContentResult.SuggestCaretPointTo(
|
||||
*this, {SuggestCaret::OnlyIfHasSuggestion,
|
||||
SuggestCaret::OnlyIfTransactionsAllowedToDoIt,
|
||||
SuggestCaret::AndIgnoreTrivialError});
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("CreateContentResult::SuggestCaretPointTo() failed");
|
||||
return EditorBase::ToGenericNSResult(rv);
|
||||
}
|
||||
NS_WARNING_ASSERTION(
|
||||
rv != NS_SUCCESS_EDITOR_BUT_IGNORED_TRIVIAL_ERROR,
|
||||
"CreateContentResult::SuggestCaretPointTo() failed, but ignored");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult EditorBase::InsertNodeWithTransaction(
|
||||
nsIContent& aContentToInsert, const EditorDOMPoint& aPointToInsert) {
|
||||
template <typename ContentNodeType>
|
||||
CreateNodeResultBase<ContentNodeType> EditorBase::InsertNodeWithTransaction(
|
||||
ContentNodeType& aContentToInsert, const EditorDOMPoint& aPointToInsert) {
|
||||
MOZ_ASSERT(IsEditActionDataAvailable());
|
||||
MOZ_ASSERT_IF(IsTextEditor(), !aContentToInsert.IsText());
|
||||
|
||||
using ResultType = CreateNodeResultBase<ContentNodeType>;
|
||||
|
||||
if (NS_WARN_IF(!aPointToInsert.IsSet())) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
return ResultType(NS_ERROR_INVALID_ARG);
|
||||
}
|
||||
MOZ_ASSERT(aPointToInsert.IsSetAndValid());
|
||||
|
||||
@ -2054,7 +2077,7 @@ nsresult EditorBase::InsertNodeWithTransaction(
|
||||
AutoEditSubActionNotifier startToHandleEditSubAction(
|
||||
*this, EditSubAction::eInsertNode, nsIEditor::eNext, ignoredError);
|
||||
if (NS_WARN_IF(ignoredError.ErrorCodeIs(NS_ERROR_EDITOR_DESTROYED))) {
|
||||
return ignoredError.StealNSResult();
|
||||
return ResultType(ignoredError.StealNSResult());
|
||||
}
|
||||
NS_WARNING_ASSERTION(
|
||||
!ignoredError.Failed(),
|
||||
@ -2066,17 +2089,6 @@ nsresult EditorBase::InsertNodeWithTransaction(
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"EditorBase::DoTransactionInternal() failed");
|
||||
|
||||
if (NS_SUCCEEDED(rv) && AllowsTransactionsToChangeSelection()) {
|
||||
const auto pointToPutCaret =
|
||||
transaction->SuggestPointToPutCaret<EditorRawDOMPoint>();
|
||||
if (pointToPutCaret.IsSet()) {
|
||||
DebugOnly<nsresult> rvIgnored = CollapseSelectionTo(pointToPutCaret);
|
||||
NS_WARNING_ASSERTION(
|
||||
NS_SUCCEEDED(rvIgnored) || rvIgnored == NS_ERROR_EDITOR_DESTROYED,
|
||||
"EditorBase::CollapseSelectionTo() failed, but ignored");
|
||||
}
|
||||
}
|
||||
|
||||
DebugOnly<nsresult> rvIgnored =
|
||||
RangeUpdaterRef().SelAdjInsertNode(aPointToInsert);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored),
|
||||
@ -2086,7 +2098,15 @@ nsresult EditorBase::InsertNodeWithTransaction(
|
||||
TopLevelEditSubActionDataRef().DidInsertContent(*this, aContentToInsert);
|
||||
}
|
||||
|
||||
return MOZ_UNLIKELY(Destroyed()) ? NS_ERROR_EDITOR_DESTROYED : rv;
|
||||
if (NS_WARN_IF(Destroyed())) {
|
||||
return ResultType(NS_ERROR_EDITOR_DESTROYED);
|
||||
}
|
||||
if (NS_FAILED(rv)) {
|
||||
return ResultType(rv);
|
||||
}
|
||||
|
||||
return ResultType(&aContentToInsert,
|
||||
transaction->SuggestPointToPutCaret<EditorDOMPoint>());
|
||||
}
|
||||
|
||||
CreateElementResult
|
||||
@ -2118,15 +2138,24 @@ EditorBase::InsertPaddingBRElementForEmptyLastLineWithTransaction(
|
||||
}
|
||||
newBRElement->SetFlags(NS_PADDING_FOR_EMPTY_LAST_LINE);
|
||||
|
||||
nsresult rv = InsertNodeWithTransaction(*newBRElement, pointToInsert);
|
||||
if (NS_WARN_IF(Destroyed())) {
|
||||
return CreateElementResult(NS_ERROR_EDITOR_DESTROYED);
|
||||
}
|
||||
if (NS_FAILED(rv)) {
|
||||
CreateElementResult insertBRElementResult =
|
||||
InsertNodeWithTransaction<Element>(*newBRElement, pointToInsert);
|
||||
if (insertBRElementResult.isErr()) {
|
||||
NS_WARNING("EditorBase::InsertNodeWithTransaction() failed");
|
||||
return CreateElementResult(rv);
|
||||
return CreateElementResult(insertBRElementResult.unwrapErr());
|
||||
}
|
||||
|
||||
nsresult rv = insertBRElementResult.SuggestCaretPointTo(
|
||||
*this, {SuggestCaret::OnlyIfHasSuggestion,
|
||||
SuggestCaret::OnlyIfTransactionsAllowedToDoIt,
|
||||
SuggestCaret::AndIgnoreTrivialError});
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("CreateElementResult::SuggestCaretPointTo() failed");
|
||||
return CreateElementResult(rv);
|
||||
}
|
||||
NS_WARNING_ASSERTION(
|
||||
rv != NS_SUCCESS_EDITOR_BUT_IGNORED_TRIVIAL_ERROR,
|
||||
"CreateElementResult::SuggestCaretPointTo() failed, but ignored");
|
||||
return CreateElementResult(std::move(newBRElement));
|
||||
}
|
||||
|
||||
@ -2830,25 +2859,34 @@ Result<EditorDOMPoint, nsresult> EditorBase::InsertTextWithTransaction(
|
||||
CheckedUint32 newOffset;
|
||||
if (!pointToInsert.IsInTextNode()) {
|
||||
// create a text node
|
||||
RefPtr<nsTextNode> newNode = CreateTextNode(u""_ns);
|
||||
if (MOZ_UNLIKELY(NS_WARN_IF(!newNode))) {
|
||||
RefPtr<nsTextNode> newTextNode = CreateTextNode(u""_ns);
|
||||
if (NS_WARN_IF(!newTextNode)) {
|
||||
return Err(NS_ERROR_FAILURE);
|
||||
}
|
||||
// then we insert it into the dom tree
|
||||
nsresult rv = InsertNodeWithTransaction(*newNode, pointToInsert);
|
||||
if (MOZ_UNLIKELY(NS_WARN_IF(Destroyed()))) {
|
||||
return Err(NS_ERROR_EDITOR_DESTROYED);
|
||||
}
|
||||
if (MOZ_UNLIKELY(NS_FAILED(rv))) {
|
||||
CreateTextResult insertTextNodeResult =
|
||||
InsertNodeWithTransaction<Text>(*newTextNode, pointToInsert);
|
||||
if (insertTextNodeResult.isErr()) {
|
||||
NS_WARNING("EditorBase::InsertNodeWithTransaction() failed");
|
||||
return Err(insertTextNodeResult.unwrapErr());
|
||||
}
|
||||
nsresult rv = insertTextNodeResult.SuggestCaretPointTo(
|
||||
*this, {SuggestCaret::OnlyIfHasSuggestion,
|
||||
SuggestCaret::OnlyIfTransactionsAllowedToDoIt,
|
||||
SuggestCaret::AndIgnoreTrivialError});
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("CreateTextResult::SuggestCaretPointTo() failed");
|
||||
return Err(rv);
|
||||
}
|
||||
pointToInsert.Set(newNode, 0u);
|
||||
NS_WARNING_ASSERTION(
|
||||
rv != NS_SUCCESS_EDITOR_BUT_IGNORED_TRIVIAL_ERROR,
|
||||
"CreateTextResult::SuggestCaretPointTo() failed, but ignored");
|
||||
pointToInsert.Set(newTextNode, 0u);
|
||||
newOffset = aStringToInsert.Length();
|
||||
} else {
|
||||
newOffset = aStringToInsert.Length();
|
||||
newOffset += pointToInsert.Offset();
|
||||
if (MOZ_UNLIKELY(NS_WARN_IF(!newOffset.isValid()))) {
|
||||
if (NS_WARN_IF(!newOffset.isValid())) {
|
||||
return Err(NS_ERROR_FAILURE);
|
||||
}
|
||||
}
|
||||
@ -2860,7 +2898,7 @@ Result<EditorDOMPoint, nsresult> EditorBase::InsertTextWithTransaction(
|
||||
"destroying the editor");
|
||||
return Err(NS_ERROR_EDITOR_DESTROYED);
|
||||
}
|
||||
if (MOZ_UNLIKELY(NS_FAILED(rv))) {
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("EditorBase::InsertTextIntoTextNodeWithTransaction() failed");
|
||||
return Err(rv);
|
||||
}
|
||||
@ -2870,7 +2908,7 @@ Result<EditorDOMPoint, nsresult> EditorBase::InsertTextWithTransaction(
|
||||
if (pointToInsert.IsInTextNode()) {
|
||||
CheckedUint32 newOffset = aStringToInsert.Length();
|
||||
newOffset += pointToInsert.Offset();
|
||||
if (MOZ_UNLIKELY(NS_WARN_IF(!newOffset.isValid()))) {
|
||||
if (NS_WARN_IF(!newOffset.isValid())) {
|
||||
return Err(NS_ERROR_FAILURE);
|
||||
}
|
||||
// we are inserting text into an existing text node.
|
||||
@ -2883,7 +2921,7 @@ Result<EditorDOMPoint, nsresult> EditorBase::InsertTextWithTransaction(
|
||||
"destroying the editor");
|
||||
return Err(NS_ERROR_EDITOR_DESTROYED);
|
||||
}
|
||||
if (MOZ_UNLIKELY(NS_FAILED(rv))) {
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("EditorBase::InsertTextIntoTextNodeWithTransaction() failed");
|
||||
return Err(rv);
|
||||
}
|
||||
@ -2892,22 +2930,30 @@ Result<EditorDOMPoint, nsresult> EditorBase::InsertTextWithTransaction(
|
||||
|
||||
// we are inserting text into a non-text node. first we have to create a
|
||||
// textnode (this also populates it with the text)
|
||||
RefPtr<nsTextNode> newNode = CreateTextNode(aStringToInsert);
|
||||
if (MOZ_UNLIKELY(NS_WARN_IF(!newNode))) {
|
||||
RefPtr<nsTextNode> newTextNode = CreateTextNode(aStringToInsert);
|
||||
if (NS_WARN_IF(!newTextNode)) {
|
||||
return Err(NS_ERROR_FAILURE);
|
||||
}
|
||||
// then we insert it into the dom tree
|
||||
nsresult rv = InsertNodeWithTransaction(*newNode, pointToInsert);
|
||||
if (MOZ_UNLIKELY(Destroyed())) {
|
||||
NS_WARNING(
|
||||
"EditorBase::InsertNodeWithTransaction() caused destroying the editor");
|
||||
return Err(NS_ERROR_EDITOR_DESTROYED);
|
||||
}
|
||||
if (MOZ_UNLIKELY(NS_FAILED(rv))) {
|
||||
CreateTextResult insertTextNodeResult =
|
||||
InsertNodeWithTransaction<Text>(*newTextNode, pointToInsert);
|
||||
if (insertTextNodeResult.isErr()) {
|
||||
NS_WARNING("EditorBase::InsertNodeWithTransaction() failed");
|
||||
return Err(insertTextNodeResult.unwrapErr());
|
||||
}
|
||||
nsresult rv = insertTextNodeResult.SuggestCaretPointTo(
|
||||
*this, {SuggestCaret::OnlyIfHasSuggestion,
|
||||
SuggestCaret::OnlyIfTransactionsAllowedToDoIt,
|
||||
SuggestCaret::AndIgnoreTrivialError});
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("CreateTextResult::SuggestCaretPointTo() failed");
|
||||
return Err(rv);
|
||||
}
|
||||
return EditorDOMPoint(newNode, aStringToInsert.Length());
|
||||
NS_WARNING_ASSERTION(
|
||||
rv != NS_SUCCESS_EDITOR_BUT_IGNORED_TRIVIAL_ERROR,
|
||||
"CreateTextResult::SuggestCaretPointTo() failed, but ignored");
|
||||
return EditorDOMPoint(insertTextNodeResult.UnwrapNewNode(),
|
||||
aStringToInsert.Length());
|
||||
}
|
||||
|
||||
static bool TextFragmentBeginsWithStringAtOffset(
|
||||
|
@ -73,7 +73,6 @@ class PresShell;
|
||||
class TextComposition;
|
||||
class TextInputListener;
|
||||
class TextServicesDocument;
|
||||
|
||||
namespace dom {
|
||||
class AbstractRange;
|
||||
class DataTransfer;
|
||||
@ -1694,9 +1693,13 @@ class EditorBase : public nsIEditor,
|
||||
* transaction will append the node to the
|
||||
* container. Otherwise, will insert the node
|
||||
* before child node referred by this.
|
||||
* @return If succeeded, returns the new content node and
|
||||
* point to put caret.
|
||||
*/
|
||||
MOZ_CAN_RUN_SCRIPT nsresult InsertNodeWithTransaction(
|
||||
nsIContent& aContentToInsert, const EditorDOMPoint& aPointToInsert);
|
||||
template <typename ContentNodeType>
|
||||
[[nodiscard]] MOZ_CAN_RUN_SCRIPT CreateNodeResultBase<ContentNodeType>
|
||||
InsertNodeWithTransaction(ContentNodeType& aContentToInsert,
|
||||
const EditorDOMPoint& aPointToInsert);
|
||||
|
||||
/**
|
||||
* InsertPaddingBRElementForEmptyLastLineWithTransaction() creates a padding
|
||||
|
@ -30,8 +30,6 @@
|
||||
class nsITransferable;
|
||||
|
||||
namespace mozilla {
|
||||
template <class T>
|
||||
class OwningNonNull;
|
||||
|
||||
/***************************************************************************
|
||||
* EditActionResult is useful to return multiple results of an editor
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/ContentIterator.h"
|
||||
#include "mozilla/EditorDOMPoint.h"
|
||||
#include "mozilla/EditorForwards.h"
|
||||
#include "mozilla/EditorUtils.h" // for SuggestCaretOption(s)
|
||||
#include "mozilla/IntegerRange.h"
|
||||
#include "mozilla/RangeBoundary.h"
|
||||
@ -31,8 +32,6 @@
|
||||
class nsISimpleEnumerator;
|
||||
|
||||
namespace mozilla {
|
||||
template <class T>
|
||||
class OwningNonNull;
|
||||
|
||||
// JoinNodesDirection is also affected to which one is new node at splitting
|
||||
// a node because a couple of undo/redo.
|
||||
@ -973,9 +972,6 @@ class MOZ_STACK_CLASS ReplaceRangeDataBase final {
|
||||
nsString mReplaceString;
|
||||
};
|
||||
|
||||
using ReplaceRangeData = ReplaceRangeDataBase<EditorDOMPoint>;
|
||||
using ReplaceRangeInTextsData = ReplaceRangeDataBase<EditorDOMPointInText>;
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // #ifndef mozilla_HTMLEditHelpers_h
|
||||
|
@ -922,18 +922,17 @@ nsresult HTMLEditor::MaybeCreatePaddingBRElementForEmptyEditor() {
|
||||
newBRElement->SetFlags(NS_PADDING_FOR_EMPTY_EDITOR);
|
||||
|
||||
// Put the node in the document.
|
||||
nsresult rv =
|
||||
InsertNodeWithTransaction(*newBRElement, EditorDOMPoint(rootElement, 0));
|
||||
if (NS_WARN_IF(Destroyed())) {
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
}
|
||||
if (NS_FAILED(rv)) {
|
||||
CreateElementResult insertBRElementResult =
|
||||
InsertNodeWithTransaction<Element>(*newBRElement,
|
||||
EditorDOMPoint(rootElement, 0u));
|
||||
if (insertBRElementResult.isErr()) {
|
||||
NS_WARNING("EditorBase::InsertNodeWithTransaction() failed");
|
||||
return rv;
|
||||
return insertBRElementResult.unwrapErr();
|
||||
}
|
||||
|
||||
// Set selection.
|
||||
rv = CollapseSelectionToStartOf(*rootElement);
|
||||
insertBRElementResult.IgnoreCaretPointSuggestion();
|
||||
nsresult rv = CollapseSelectionToStartOf(*rootElement);
|
||||
if (MOZ_UNLIKELY(rv == NS_ERROR_EDITOR_DESTROYED)) {
|
||||
NS_WARNING(
|
||||
"EditorBase::CollapseSelectionToStartOf() caused destroying the "
|
||||
@ -5410,15 +5409,14 @@ nsresult HTMLEditor::CreateStyleForInsertText(
|
||||
NS_WARNING("EditorBase::CreateTextNode() failed");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
nsresult rv = InsertNodeWithTransaction(*newEmptyTextNode, pointToPutCaret);
|
||||
if (NS_WARN_IF(Destroyed())) {
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
}
|
||||
if (NS_FAILED(rv)) {
|
||||
CreateTextResult insertNewTextNodeResult =
|
||||
InsertNodeWithTransaction<Text>(*newEmptyTextNode, pointToPutCaret);
|
||||
if (insertNewTextNodeResult.isErr()) {
|
||||
NS_WARNING("EditorBase::InsertNodeWithTransaction() failed");
|
||||
return rv;
|
||||
return insertNewTextNodeResult.unwrapErr();
|
||||
}
|
||||
pointToPutCaret.Set(newEmptyTextNode, 0);
|
||||
insertNewTextNodeResult.IgnoreCaretPointSuggestion();
|
||||
pointToPutCaret.Set(newEmptyTextNode, 0u);
|
||||
putCaret = true;
|
||||
|
||||
if (relFontSize) {
|
||||
|
@ -1462,12 +1462,15 @@ nsresult HTMLEditor::ReplaceHeadContentsWithSourceWithTransaction(
|
||||
|
||||
// Loop over the contents of the fragment and move into the document
|
||||
while (nsCOMPtr<nsIContent> child = documentFragment->GetFirstChild()) {
|
||||
nsresult rv = InsertNodeWithTransaction(
|
||||
CreateContentResult insertChildContentResult = InsertNodeWithTransaction(
|
||||
*child, EditorDOMPoint(primaryHeadElement, offsetOfNewNode++));
|
||||
if (NS_FAILED(rv)) {
|
||||
if (insertChildContentResult.isErr()) {
|
||||
NS_WARNING("EditorBase::InsertNodeWithTransaction() failed");
|
||||
return rv;
|
||||
return insertChildContentResult.unwrapErr();
|
||||
}
|
||||
// We probably don't need to adjust selection here, although we've done it
|
||||
// unless AutoTransactionsConserveSelection is created in a caller.
|
||||
insertChildContentResult.IgnoreCaretPointSuggestion();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
@ -1974,11 +1977,23 @@ EditorDOMPoint HTMLEditor::InsertNodeIntoProperAncestorWithTransaction(
|
||||
// when it's necessary.
|
||||
AutoEditorDOMPointChildInvalidator lockOffset(pointToInsert);
|
||||
// Now we can insert the new node.
|
||||
nsresult rv = InsertNodeWithTransaction(aNode, pointToInsert);
|
||||
if (NS_FAILED(rv)) {
|
||||
CreateContentResult insertContentNodeResult =
|
||||
InsertNodeWithTransaction(aNode, pointToInsert);
|
||||
if (insertContentNodeResult.isErr()) {
|
||||
NS_WARNING("EditorBase::InsertNodeWithTransaction() failed");
|
||||
return EditorDOMPoint();
|
||||
}
|
||||
nsresult rv = insertContentNodeResult.SuggestCaretPointTo(
|
||||
*this, {SuggestCaret::OnlyIfHasSuggestion,
|
||||
SuggestCaret::OnlyIfTransactionsAllowedToDoIt,
|
||||
SuggestCaret::AndIgnoreTrivialError});
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("CreateContentResult::SuggestCaretPointTo() failed");
|
||||
return EditorDOMPoint();
|
||||
}
|
||||
NS_WARNING_ASSERTION(
|
||||
rv != NS_SUCCESS_EDITOR_BUT_IGNORED_TRIVIAL_ERROR,
|
||||
"CreateContentResult::SuggestCaretPointTo() failed, but ignored");
|
||||
}
|
||||
return pointToInsert;
|
||||
}
|
||||
@ -3773,21 +3788,39 @@ already_AddRefed<Element> HTMLEditor::InsertContainerWithTransactionInternal(
|
||||
}
|
||||
|
||||
{
|
||||
// TODO: Remove AutoTransactionsConserveSelection here. It's not necessary
|
||||
// in normal cases. However, it may be required for nested edit
|
||||
// actions which may be caused by legacy mutation event listeners or
|
||||
// chrome script.
|
||||
AutoTransactionsConserveSelection conserveSelection(*this);
|
||||
rv = InsertNodeWithTransaction(aContent, EditorDOMPoint(newContainer, 0));
|
||||
if (NS_FAILED(rv)) {
|
||||
CreateContentResult insertContentNodeResult =
|
||||
InsertNodeWithTransaction(aContent, EditorDOMPoint(newContainer, 0u));
|
||||
if (insertContentNodeResult.isErr()) {
|
||||
NS_WARNING("EditorBase::InsertNodeWithTransaction() failed");
|
||||
return nullptr;
|
||||
}
|
||||
insertContentNodeResult.IgnoreCaretPointSuggestion();
|
||||
}
|
||||
|
||||
// Put the new container where aNode was.
|
||||
rv = InsertNodeWithTransaction(*newContainer, pointToInsertNewContainer);
|
||||
if (NS_FAILED(rv)) {
|
||||
CreateElementResult insertNewContainerElementResult =
|
||||
InsertNodeWithTransaction<Element>(*newContainer,
|
||||
pointToInsertNewContainer);
|
||||
if (insertNewContainerElementResult.isErr()) {
|
||||
NS_WARNING("EditorBase::InsertNodeWithTransaction() failed");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
rv = insertNewContainerElementResult.SuggestCaretPointTo(
|
||||
*this, {SuggestCaret::OnlyIfHasSuggestion,
|
||||
SuggestCaret::OnlyIfTransactionsAllowedToDoIt,
|
||||
SuggestCaret::AndIgnoreTrivialError});
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("CreateElementResult::SuggestCaretPointTo() failed");
|
||||
return nullptr;
|
||||
}
|
||||
NS_WARNING_ASSERTION(
|
||||
rv != NS_SUCCESS_EDITOR_BUT_IGNORED_TRIVIAL_ERROR,
|
||||
"CreateElementResult::SuggestCaretPointTo() failed, but ignored");
|
||||
return newContainer.forget();
|
||||
}
|
||||
|
||||
@ -3838,23 +3871,36 @@ already_AddRefed<Element> HTMLEditor::ReplaceContainerWithTransactionInternal(
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
rv = InsertNodeWithTransaction(
|
||||
*child, EditorDOMPoint(newContainer, newContainer->Length()));
|
||||
if (NS_FAILED(rv)) {
|
||||
CreateContentResult insertChildContentResult = InsertNodeWithTransaction(
|
||||
*child, EditorDOMPoint::AtEndOf(newContainer));
|
||||
if (insertChildContentResult.isErr()) {
|
||||
NS_WARNING("EditorBase::InsertNodeWithTransaction() failed");
|
||||
return nullptr;
|
||||
}
|
||||
insertChildContentResult.IgnoreCaretPointSuggestion();
|
||||
}
|
||||
}
|
||||
|
||||
// Insert new container into tree.
|
||||
NS_WARNING_ASSERTION(atOldContainer.IsSetAndValid(),
|
||||
"The old container might be moved by mutation observer");
|
||||
nsresult rv = InsertNodeWithTransaction(*newContainer, atOldContainer);
|
||||
if (NS_FAILED(rv)) {
|
||||
CreateElementResult insertNewContainerElementResult =
|
||||
InsertNodeWithTransaction<Element>(*newContainer, atOldContainer);
|
||||
if (insertNewContainerElementResult.isErr()) {
|
||||
NS_WARNING("EditorBase::InsertNodeWithTransaction() failed");
|
||||
return nullptr;
|
||||
}
|
||||
nsresult rv = insertNewContainerElementResult.SuggestCaretPointTo(
|
||||
*this, {SuggestCaret::OnlyIfHasSuggestion,
|
||||
SuggestCaret::OnlyIfTransactionsAllowedToDoIt,
|
||||
SuggestCaret::AndIgnoreTrivialError});
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("CreateElementResult::SuggestCaretPointTo() failed");
|
||||
return nullptr;
|
||||
}
|
||||
NS_WARNING_ASSERTION(
|
||||
rv != NS_SUCCESS_EDITOR_BUT_IGNORED_TRIVIAL_ERROR,
|
||||
"CreateElementResult::SuggestCaretPointTo() failed, but ignored");
|
||||
|
||||
// Delete old container.
|
||||
rv = DeleteNodeWithTransaction(aOldContainer);
|
||||
@ -3879,6 +3925,7 @@ nsresult HTMLEditor::RemoveContainerWithTransaction(Element& aElement) {
|
||||
pointToInsertChildren);
|
||||
|
||||
// Move all children from aNode to its parent.
|
||||
EditorDOMPoint pointToPutCaret;
|
||||
while (aElement.HasChildren()) {
|
||||
nsCOMPtr<nsIContent> child = aElement.GetLastChild();
|
||||
if (NS_WARN_IF(!child)) {
|
||||
@ -3893,13 +3940,29 @@ nsresult HTMLEditor::RemoveContainerWithTransaction(Element& aElement) {
|
||||
// Insert the last child before the previous last child. So, we need to
|
||||
// use offset here because previous child might have been moved to
|
||||
// container.
|
||||
rv = InsertNodeWithTransaction(
|
||||
CreateContentResult insertChildContentResult = InsertNodeWithTransaction(
|
||||
*child, EditorDOMPoint(pointToInsertChildren.GetContainer(),
|
||||
pointToInsertChildren.Offset()));
|
||||
if (NS_FAILED(rv)) {
|
||||
if (insertChildContentResult.isErr()) {
|
||||
NS_WARNING("EditorBase::InsertNodeWithTransaction() failed");
|
||||
return rv;
|
||||
return insertChildContentResult.unwrapErr();
|
||||
}
|
||||
insertChildContentResult.MoveCaretPointTo(
|
||||
pointToPutCaret, *this,
|
||||
{SuggestCaret::OnlyIfHasSuggestion,
|
||||
SuggestCaret::OnlyIfTransactionsAllowedToDoIt});
|
||||
}
|
||||
|
||||
if (pointToPutCaret.IsSet()) {
|
||||
nsresult rv = CollapseSelectionTo(pointToPutCaret);
|
||||
if (MOZ_UNLIKELY(rv == NS_ERROR_EDITOR_DESTROYED)) {
|
||||
NS_WARNING(
|
||||
"EditorBase::CollapseSelectionTo() caused destring the editor");
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
}
|
||||
NS_WARNING_ASSERTION(
|
||||
NS_SUCCEEDED(rv),
|
||||
"EditorBase::CollapseSelectionTo() failed, but ignored");
|
||||
}
|
||||
|
||||
nsresult rv = DeleteNodeWithTransaction(aElement);
|
||||
@ -5089,10 +5152,24 @@ nsresult HTMLEditor::MoveNodeWithTransaction(
|
||||
if (NS_WARN_IF(!pointToInsert.IsSetAndValid())) {
|
||||
pointToInsert.SetToEndOf(pointToInsert.GetContainer());
|
||||
}
|
||||
rv = InsertNodeWithTransaction(aContent, pointToInsert);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"EditorBase::InsertNodeWithTransaction() failed");
|
||||
return rv;
|
||||
CreateContentResult insertContentNodeResult =
|
||||
InsertNodeWithTransaction(aContent, pointToInsert);
|
||||
if (insertContentNodeResult.isErr()) {
|
||||
NS_WARNING("EditorBase::InsertNodeWithTransaction() failed");
|
||||
return insertContentNodeResult.unwrapErr();
|
||||
}
|
||||
rv = insertContentNodeResult.SuggestCaretPointTo(
|
||||
*this, {SuggestCaret::OnlyIfHasSuggestion,
|
||||
SuggestCaret::OnlyIfTransactionsAllowedToDoIt,
|
||||
SuggestCaret::AndIgnoreTrivialError});
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("CreateContentResult::SuggestCaretPointTo() failed");
|
||||
return rv;
|
||||
}
|
||||
NS_WARNING_ASSERTION(
|
||||
rv != NS_SUCCESS_EDITOR_BUT_IGNORED_TRIVIAL_ERROR,
|
||||
"CreateContentResult::SuggestCaretPointTo() failed, but ignored");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
Result<RefPtr<Element>, nsresult> HTMLEditor::DeleteSelectionAndCreateElement(
|
||||
|
@ -199,13 +199,19 @@ nsresult HTMLEditor::LoadHTML(const nsAString& aInputString) {
|
||||
// changes the behavior when inserted child is moved by mutation
|
||||
// observer. We need to investigate what we should do here.
|
||||
Unused << pointToInsert.Offset();
|
||||
EditorDOMPoint pointToPutCaret;
|
||||
for (nsCOMPtr<nsIContent> contentToInsert = documentFragment->GetFirstChild();
|
||||
contentToInsert; contentToInsert = documentFragment->GetFirstChild()) {
|
||||
rv = InsertNodeWithTransaction(*contentToInsert, pointToInsert);
|
||||
if (NS_FAILED(rv)) {
|
||||
CreateContentResult insertChildContentNodeResult =
|
||||
InsertNodeWithTransaction(*contentToInsert, pointToInsert);
|
||||
if (insertChildContentNodeResult.isErr()) {
|
||||
NS_WARNING("EditorBase::InsertNodeWithTransaction() failed");
|
||||
return rv;
|
||||
return insertChildContentNodeResult.unwrapErr();
|
||||
}
|
||||
insertChildContentNodeResult.MoveCaretPointTo(
|
||||
pointToPutCaret, *this,
|
||||
{SuggestCaret::OnlyIfHasSuggestion,
|
||||
SuggestCaret::OnlyIfTransactionsAllowedToDoIt});
|
||||
// XXX If the inserted node has been moved by mutation observer,
|
||||
// incrementing offset will cause odd result. Next new node
|
||||
// will be inserted after existing node and the offset will be
|
||||
@ -218,6 +224,17 @@ nsresult HTMLEditor::LoadHTML(const nsAString& aInputString) {
|
||||
}
|
||||
}
|
||||
|
||||
if (pointToPutCaret.IsSet()) {
|
||||
nsresult rv = CollapseSelectionTo(pointToPutCaret);
|
||||
if (MOZ_UNLIKELY(rv == NS_ERROR_EDITOR_DESTROYED)) {
|
||||
NS_WARNING("EditorBase::CollapseSelectionTo() failed, but ignored");
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
}
|
||||
NS_WARNING_ASSERTION(
|
||||
NS_SUCCEEDED(rv),
|
||||
"EditorBase::CollapseSelectionTo() failed, but ignored");
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "mozilla/EditorDOMPoint.h"
|
||||
#include "mozilla/EditorUtils.h"
|
||||
#include "mozilla/FlushType.h"
|
||||
#include "mozilla/IntegerRange.h"
|
||||
#include "mozilla/PresShell.h"
|
||||
#include "mozilla/dom/Selection.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
@ -135,12 +136,21 @@ nsresult HTMLEditor::InsertCell(Element* aCell, int32_t aRowSpan,
|
||||
"Failed to advance offset to after the old cell");
|
||||
}
|
||||
|
||||
// Don't let Rules System change the selection.
|
||||
// TODO: Remove AutoTransactionsConserveSelection here. It's not necessary
|
||||
// in normal cases. However, it may be required for nested edit
|
||||
// actions which may be caused by legacy mutation event listeners or
|
||||
// chrome script.
|
||||
AutoTransactionsConserveSelection dontChangeSelection(*this);
|
||||
nsresult rv = InsertNodeWithTransaction(*newCell, pointToInsert);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"EditorBase::InsertNodeWithTransaction() failed");
|
||||
return rv;
|
||||
CreateElementResult insertNewCellResult =
|
||||
InsertNodeWithTransaction<Element>(*newCell, pointToInsert);
|
||||
if (insertNewCellResult.isErr()) {
|
||||
NS_WARNING("EditorBase::InsertNodeWithTransaction() failed");
|
||||
return insertNewCellResult.unwrapErr();
|
||||
}
|
||||
// Because of dontChangeSelection, we've never allowed to transactions to
|
||||
// update selection here.
|
||||
insertNewCellResult.IgnoreCaretPointSuggestion();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult HTMLEditor::SetColSpan(Element* aCell, int32_t aColSpan) {
|
||||
@ -254,7 +264,10 @@ nsresult HTMLEditor::InsertTableCellsWithTransaction(
|
||||
AutoSelectionSetterAfterTableEdit setCaret(
|
||||
*this, table, cellDataAtSelection.mCurrent.mRow, newCellIndex,
|
||||
ePreviousColumn, false);
|
||||
// So, suppress Rules System selection munging.
|
||||
// TODO: Remove AutoTransactionsConserveSelection here. It's not necessary
|
||||
// in normal cases. However, it may be required for nested edit
|
||||
// actions which may be caused by legacy mutation event listeners or
|
||||
// chrome script.
|
||||
AutoTransactionsConserveSelection dontChangeSelection(*this);
|
||||
|
||||
EditorDOMPoint pointToInsert(cellParent, cellOffset);
|
||||
@ -266,18 +279,23 @@ nsresult HTMLEditor::InsertTableCellsWithTransaction(
|
||||
NS_WARNING_ASSERTION(advanced,
|
||||
"Failed to move insertion point after the cell");
|
||||
}
|
||||
for (int32_t i = 0; i < aNumberOfCellsToInsert; i++) {
|
||||
for ([[maybe_unused]] const auto i :
|
||||
IntegerRange<uint32_t>(aNumberOfCellsToInsert)) {
|
||||
RefPtr<Element> newCell = CreateElementWithDefaults(*nsGkAtoms::td);
|
||||
if (!newCell) {
|
||||
if (MOZ_UNLIKELY(!newCell)) {
|
||||
NS_WARNING("HTMLEditor::CreateElementWithDefaults(nsGkAtoms::td) failed");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
AutoEditorDOMPointChildInvalidator lockOffset(pointToInsert);
|
||||
nsresult rv = InsertNodeWithTransaction(*newCell, pointToInsert);
|
||||
if (NS_FAILED(rv)) {
|
||||
CreateElementResult insertNewCellResult =
|
||||
InsertNodeWithTransaction<Element>(*newCell, pointToInsert);
|
||||
if (insertNewCellResult.isErr()) {
|
||||
NS_WARNING("EditorBase::InsertNodeWithTransaction() failed");
|
||||
return rv;
|
||||
return insertNewCellResult.unwrapErr();
|
||||
}
|
||||
// Because of dontChangeSelection, we've never allowed to transactions to
|
||||
// update selection here.
|
||||
insertNewCellResult.IgnoreCaretPointSuggestion();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
@ -762,7 +780,10 @@ nsresult HTMLEditor::InsertTableRowsWithTransaction(
|
||||
AutoSelectionSetterAfterTableEdit setCaret(
|
||||
*this, table, startRowIndex, cellDataAtSelection.mCurrent.mColumn,
|
||||
ePreviousColumn, false);
|
||||
// Suppress Rules System selection munging.
|
||||
// TODO: Remove AutoTransactionsConserveSelection here. It's not necessary
|
||||
// in normal cases. However, it may be required for nested edit
|
||||
// actions which may be caused by legacy mutation event listeners or
|
||||
// chrome script.
|
||||
AutoTransactionsConserveSelection dontChangeSelection(*this);
|
||||
|
||||
RefPtr<Element> cellForRowParent;
|
||||
@ -890,11 +911,15 @@ nsresult HTMLEditor::InsertTableRowsWithTransaction(
|
||||
}
|
||||
|
||||
AutoEditorDOMPointChildInvalidator lockOffset(pointToInsert);
|
||||
nsresult rv = InsertNodeWithTransaction(*newRow, pointToInsert);
|
||||
if (NS_FAILED(rv)) {
|
||||
CreateElementResult insertNewRowResult =
|
||||
InsertNodeWithTransaction<Element>(*newRow, pointToInsert);
|
||||
if (insertNewRowResult.isErr()) {
|
||||
NS_WARNING("EditorBase::InsertNodeWithTransaction() failed");
|
||||
return rv;
|
||||
return insertNewRowResult.unwrapErr();
|
||||
}
|
||||
// Because of dontChangeSelection, we've never allowed to transactions to
|
||||
// update selection here.
|
||||
insertNewRowResult.IgnoreCaretPointSuggestion();
|
||||
}
|
||||
|
||||
// SetSelectionAfterTableEdit from AutoSelectionSetterAfterTableEdit will
|
||||
@ -3110,6 +3135,7 @@ nsresult HTMLEditor::MergeCells(RefPtr<Element> aTargetCell,
|
||||
}
|
||||
|
||||
// Move the contents
|
||||
EditorDOMPoint pointToPutCaret;
|
||||
while (aCellToMerge->HasChildren()) {
|
||||
nsCOMPtr<nsIContent> cellChild = aCellToMerge->GetLastChild();
|
||||
if (NS_WARN_IF(!cellChild)) {
|
||||
@ -3120,12 +3146,27 @@ nsresult HTMLEditor::MergeCells(RefPtr<Element> aTargetCell,
|
||||
NS_WARNING("HTMLEditor::DeleteNodeWithTransaction() failed");
|
||||
return rv;
|
||||
}
|
||||
rv = InsertNodeWithTransaction(*cellChild,
|
||||
EditorDOMPoint(aTargetCell, insertIndex));
|
||||
if (NS_FAILED(rv)) {
|
||||
CreateContentResult insertChildContentResult = InsertNodeWithTransaction(
|
||||
*cellChild, EditorDOMPoint(aTargetCell, insertIndex));
|
||||
if (insertChildContentResult.isErr()) {
|
||||
NS_WARNING("EditorBase::InsertNodeWithTransaction() failed");
|
||||
return rv;
|
||||
return insertChildContentResult.unwrapErr();
|
||||
}
|
||||
insertChildContentResult.MoveCaretPointTo(
|
||||
pointToPutCaret, *this,
|
||||
{SuggestCaret::OnlyIfHasSuggestion,
|
||||
SuggestCaret::OnlyIfTransactionsAllowedToDoIt});
|
||||
}
|
||||
if (pointToPutCaret.IsSet()) {
|
||||
nsresult rv = CollapseSelectionTo(pointToPutCaret);
|
||||
if (MOZ_UNLIKELY(rv == NS_ERROR_EDITOR_DESTROYED)) {
|
||||
NS_WARNING(
|
||||
"EditorBase::CollapseSelectionTo() caused destroying the editor");
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
}
|
||||
NS_WARNING_ASSERTION(
|
||||
NS_SUCCEEDED(rv),
|
||||
"EditorBase::CollapseSelectionTo() failed, but ignored");
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user