mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-29 07:42:04 +00:00
Bug 1540037 - part 10: Move EditorBase::DoJoinNodes()
to HTMLEditor
r=m_kato
Then, we can make `JoinNodeTransaction` store `HTMLEditor` instead of `EditorBase`. Differential Revision: https://phabricator.services.mozilla.com/D72835
This commit is contained in:
parent
4f86d45835
commit
42b619b62e
@ -2970,199 +2970,6 @@ nsresult EditorBase::DeleteTextWithTransaction(Text& aTextNode,
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult EditorBase::DoJoinNodes(nsIContent& aContentToKeep,
|
||||
nsIContent& aContentToJoin) {
|
||||
MOZ_ASSERT(IsEditActionDataAvailable());
|
||||
MOZ_DIAGNOSTIC_ASSERT(AsHTMLEditor());
|
||||
|
||||
uint32_t firstNodeLength = aContentToJoin.Length();
|
||||
|
||||
EditorRawDOMPoint atNodeToJoin(&aContentToJoin);
|
||||
EditorRawDOMPoint atNodeToKeep(&aContentToKeep);
|
||||
|
||||
// Remember all selection points.
|
||||
// XXX Do we need to restore all types of selections by ourselves? Normal
|
||||
// selection should be modified later as result of handling edit action.
|
||||
// IME selections shouldn't be there when nodes are joined. Spellcheck
|
||||
// selections should be recreated with newer text. URL selections
|
||||
// shouldn't be there because of used only by the URL bar.
|
||||
AutoTArray<SavedRange, 10> savedRanges;
|
||||
for (SelectionType selectionType : kPresentSelectionTypes) {
|
||||
SavedRange range;
|
||||
range.mSelection = GetSelection(selectionType);
|
||||
if (selectionType == SelectionType::eNormal) {
|
||||
if (NS_WARN_IF(!range.mSelection)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
} else if (!range.mSelection) {
|
||||
// For non-normal selections, skip over the non-existing ones.
|
||||
continue;
|
||||
}
|
||||
|
||||
for (uint32_t j = 0; j < range.mSelection->RangeCount(); ++j) {
|
||||
RefPtr<nsRange> r = range.mSelection->GetRangeAt(j);
|
||||
MOZ_ASSERT(r->IsPositioned());
|
||||
range.mStartContainer = r->GetStartContainer();
|
||||
range.mStartOffset = r->StartOffset();
|
||||
range.mEndContainer = r->GetEndContainer();
|
||||
range.mEndOffset = r->EndOffset();
|
||||
|
||||
// If selection endpoint is between the nodes, remember it as being
|
||||
// in the one that is going away instead. This simplifies later selection
|
||||
// adjustment logic at end of this method.
|
||||
if (range.mStartContainer) {
|
||||
if (range.mStartContainer == atNodeToKeep.GetContainer() &&
|
||||
atNodeToJoin.Offset() < static_cast<uint32_t>(range.mStartOffset) &&
|
||||
static_cast<uint32_t>(range.mStartOffset) <=
|
||||
atNodeToKeep.Offset()) {
|
||||
range.mStartContainer = &aContentToJoin;
|
||||
range.mStartOffset = firstNodeLength;
|
||||
}
|
||||
if (range.mEndContainer == atNodeToKeep.GetContainer() &&
|
||||
atNodeToJoin.Offset() < static_cast<uint32_t>(range.mEndOffset) &&
|
||||
static_cast<uint32_t>(range.mEndOffset) <= atNodeToKeep.Offset()) {
|
||||
range.mEndContainer = &aContentToJoin;
|
||||
range.mEndOffset = firstNodeLength;
|
||||
}
|
||||
}
|
||||
|
||||
savedRanges.AppendElement(range);
|
||||
}
|
||||
}
|
||||
|
||||
// OK, ready to do join now.
|
||||
// If it's a text node, just shuffle around some text.
|
||||
if (aContentToKeep.IsText() && aContentToJoin.IsText()) {
|
||||
nsAutoString rightText;
|
||||
nsAutoString leftText;
|
||||
aContentToKeep.AsText()->GetData(rightText);
|
||||
aContentToJoin.AsText()->GetData(leftText);
|
||||
leftText += rightText;
|
||||
IgnoredErrorResult ignoredError;
|
||||
DoSetText(MOZ_KnownLive(*aContentToKeep.AsText()), leftText, ignoredError);
|
||||
if (NS_WARN_IF(Destroyed())) {
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
}
|
||||
NS_WARNING_ASSERTION(!ignoredError.Failed(),
|
||||
"EditorBase::DoSetText() failed, but ignored");
|
||||
} else {
|
||||
// Otherwise it's an interior node, so shuffle around the children.
|
||||
nsCOMPtr<nsINodeList> childNodes = aContentToJoin.ChildNodes();
|
||||
MOZ_ASSERT(childNodes);
|
||||
|
||||
// Remember the first child in aContentToKeep, we'll insert all the children
|
||||
// of aContentToJoin in front of it GetFirstChild returns nullptr firstNode
|
||||
// if aContentToKeep has no children, that's OK.
|
||||
nsCOMPtr<nsIContent> firstNode = aContentToKeep.GetFirstChild();
|
||||
|
||||
// Have to go through the list backwards to keep deletes from interfering
|
||||
// with iteration.
|
||||
for (uint32_t i = childNodes->Length(); i; --i) {
|
||||
nsCOMPtr<nsIContent> childNode = childNodes->Item(i - 1);
|
||||
if (childNode) {
|
||||
// prepend children of aContentToJoin
|
||||
ErrorResult error;
|
||||
aContentToKeep.InsertBefore(*childNode, firstNode, error);
|
||||
if (NS_WARN_IF(Destroyed())) {
|
||||
error.SuppressException();
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
}
|
||||
if (error.Failed()) {
|
||||
NS_WARNING("nsINode::InsertBefore() failed");
|
||||
return error.StealNSResult();
|
||||
}
|
||||
firstNode = std::move(childNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Delete the extra node.
|
||||
aContentToJoin.Remove();
|
||||
if (NS_WARN_IF(Destroyed())) {
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
}
|
||||
|
||||
bool allowedTransactionsToChangeSelection =
|
||||
AllowsTransactionsToChangeSelection();
|
||||
|
||||
RefPtr<Selection> previousSelection;
|
||||
for (size_t i = 0; i < savedRanges.Length(); ++i) {
|
||||
// And adjust the selection if needed.
|
||||
SavedRange& range = savedRanges[i];
|
||||
|
||||
// If we have not seen the selection yet, clear all of its ranges.
|
||||
if (range.mSelection != previousSelection) {
|
||||
ErrorResult error;
|
||||
range.mSelection->RemoveAllRanges(error);
|
||||
if (NS_WARN_IF(Destroyed())) {
|
||||
error.SuppressException();
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
}
|
||||
if (error.Failed()) {
|
||||
NS_WARNING("Selection::RemoveAllRanges() failed");
|
||||
return error.StealNSResult();
|
||||
}
|
||||
previousSelection = range.mSelection;
|
||||
}
|
||||
|
||||
if (allowedTransactionsToChangeSelection &&
|
||||
range.mSelection->Type() == SelectionType::eNormal) {
|
||||
// If the editor should adjust the selection, don't bother restoring
|
||||
// the ranges for the normal selection here.
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check to see if we joined nodes where selection starts.
|
||||
if (range.mStartContainer == &aContentToJoin) {
|
||||
range.mStartContainer = &aContentToKeep;
|
||||
} else if (range.mStartContainer == &aContentToKeep) {
|
||||
range.mStartOffset += firstNodeLength;
|
||||
}
|
||||
|
||||
// Check to see if we joined nodes where selection ends.
|
||||
if (range.mEndContainer == &aContentToJoin) {
|
||||
range.mEndContainer = &aContentToKeep;
|
||||
} else if (range.mEndContainer == &aContentToKeep) {
|
||||
range.mEndOffset += firstNodeLength;
|
||||
}
|
||||
|
||||
RefPtr<nsRange> newRange =
|
||||
nsRange::Create(range.mStartContainer, range.mStartOffset,
|
||||
range.mEndContainer, range.mEndOffset, IgnoreErrors());
|
||||
if (!newRange) {
|
||||
NS_WARNING("nsRange::Create() failed");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
ErrorResult error;
|
||||
// The `MOZ_KnownLive` annotation is only necessary because of a bug
|
||||
// (https://bugzilla.mozilla.org/show_bug.cgi?id=1622253) in the
|
||||
// static analyzer.
|
||||
MOZ_KnownLive(range.mSelection)
|
||||
->AddRangeAndSelectFramesAndNotifyListeners(*newRange, error);
|
||||
if (NS_WARN_IF(Destroyed())) {
|
||||
error.SuppressException();
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
}
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.StealNSResult();
|
||||
}
|
||||
}
|
||||
|
||||
if (allowedTransactionsToChangeSelection) {
|
||||
// Editor wants us to set selection at join point.
|
||||
DebugOnly<nsresult> rvIgnored = SelectionRefPtr()->Collapse(
|
||||
&aContentToKeep, AssertedCast<int32_t>(firstNodeLength));
|
||||
if (NS_WARN_IF(Destroyed())) {
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
}
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored),
|
||||
"Selection::Collapse() failed, but ignored");
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsIContent* EditorBase::GetPreviousNodeInternal(nsINode& aNode,
|
||||
bool aFindEditableNode,
|
||||
bool aFindAnyDataNode,
|
||||
|
@ -1631,28 +1631,6 @@ class EditorBase : public nsIEditor,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength);
|
||||
|
||||
struct MOZ_STACK_CLASS SavedRange final {
|
||||
RefPtr<Selection> mSelection;
|
||||
nsCOMPtr<nsINode> mStartContainer;
|
||||
nsCOMPtr<nsINode> mEndContainer;
|
||||
int32_t mStartOffset = 0;
|
||||
int32_t mEndOffset = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* DoJoinNodes() merges contents in aContentToJoin to aContentToKeep and
|
||||
* remove aContentToJoin from the DOM tree. aContentToJoin and aContentToKeep
|
||||
* must have same parent, aParent. Additionally, if one of aContentToJoin or
|
||||
* aContentToKeep is a text node, the other must be a text node.
|
||||
*
|
||||
* @param aContentToKeep The node that will remain after the join.
|
||||
* @param aContentToJoin The node that will be joined with aContentToKeep.
|
||||
* There is no requirement that the two nodes be of the
|
||||
* same type.
|
||||
*/
|
||||
[[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
|
||||
DoJoinNodes(nsIContent& aContentToKeep, nsIContent& aContentToJoin);
|
||||
|
||||
/**
|
||||
* EnsureNoPaddingBRElementForEmptyEditor() removes padding <br> element
|
||||
* for empty editor if there is.
|
||||
|
@ -130,6 +130,15 @@ class MOZ_RAII AutoSetTemporaryAncestorLimiter final {
|
||||
RefPtr<Selection> mSelection;
|
||||
};
|
||||
|
||||
// Helper struct for DoJoinNodes() and DoSplitNode().
|
||||
struct MOZ_STACK_CLASS SavedRange final {
|
||||
RefPtr<Selection> mSelection;
|
||||
nsCOMPtr<nsINode> mStartContainer;
|
||||
nsCOMPtr<nsINode> mEndContainer;
|
||||
int32_t mStartOffset = 0;
|
||||
int32_t mEndOffset = 0;
|
||||
};
|
||||
|
||||
template void HTMLEditor::SelectBRElementIfCollapsedInEmptyBlock(
|
||||
RangeBoundary& aStartRef, RangeBoundary& aEndRef);
|
||||
template void HTMLEditor::SelectBRElementIfCollapsedInEmptyBlock(
|
||||
|
@ -4471,6 +4471,199 @@ nsresult HTMLEditor::JoinNodesWithTransaction(nsINode& aLeftNode,
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult HTMLEditor::DoJoinNodes(nsIContent& aContentToKeep,
|
||||
nsIContent& aContentToJoin) {
|
||||
MOZ_ASSERT(IsEditActionDataAvailable());
|
||||
MOZ_DIAGNOSTIC_ASSERT(AsHTMLEditor());
|
||||
|
||||
uint32_t firstNodeLength = aContentToJoin.Length();
|
||||
|
||||
EditorRawDOMPoint atNodeToJoin(&aContentToJoin);
|
||||
EditorRawDOMPoint atNodeToKeep(&aContentToKeep);
|
||||
|
||||
// Remember all selection points.
|
||||
// XXX Do we need to restore all types of selections by ourselves? Normal
|
||||
// selection should be modified later as result of handling edit action.
|
||||
// IME selections shouldn't be there when nodes are joined. Spellcheck
|
||||
// selections should be recreated with newer text. URL selections
|
||||
// shouldn't be there because of used only by the URL bar.
|
||||
AutoTArray<SavedRange, 10> savedRanges;
|
||||
for (SelectionType selectionType : kPresentSelectionTypes) {
|
||||
SavedRange range;
|
||||
range.mSelection = GetSelection(selectionType);
|
||||
if (selectionType == SelectionType::eNormal) {
|
||||
if (NS_WARN_IF(!range.mSelection)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
} else if (!range.mSelection) {
|
||||
// For non-normal selections, skip over the non-existing ones.
|
||||
continue;
|
||||
}
|
||||
|
||||
for (uint32_t j = 0; j < range.mSelection->RangeCount(); ++j) {
|
||||
RefPtr<nsRange> r = range.mSelection->GetRangeAt(j);
|
||||
MOZ_ASSERT(r->IsPositioned());
|
||||
range.mStartContainer = r->GetStartContainer();
|
||||
range.mStartOffset = r->StartOffset();
|
||||
range.mEndContainer = r->GetEndContainer();
|
||||
range.mEndOffset = r->EndOffset();
|
||||
|
||||
// If selection endpoint is between the nodes, remember it as being
|
||||
// in the one that is going away instead. This simplifies later selection
|
||||
// adjustment logic at end of this method.
|
||||
if (range.mStartContainer) {
|
||||
if (range.mStartContainer == atNodeToKeep.GetContainer() &&
|
||||
atNodeToJoin.Offset() < static_cast<uint32_t>(range.mStartOffset) &&
|
||||
static_cast<uint32_t>(range.mStartOffset) <=
|
||||
atNodeToKeep.Offset()) {
|
||||
range.mStartContainer = &aContentToJoin;
|
||||
range.mStartOffset = firstNodeLength;
|
||||
}
|
||||
if (range.mEndContainer == atNodeToKeep.GetContainer() &&
|
||||
atNodeToJoin.Offset() < static_cast<uint32_t>(range.mEndOffset) &&
|
||||
static_cast<uint32_t>(range.mEndOffset) <= atNodeToKeep.Offset()) {
|
||||
range.mEndContainer = &aContentToJoin;
|
||||
range.mEndOffset = firstNodeLength;
|
||||
}
|
||||
}
|
||||
|
||||
savedRanges.AppendElement(range);
|
||||
}
|
||||
}
|
||||
|
||||
// OK, ready to do join now.
|
||||
// If it's a text node, just shuffle around some text.
|
||||
if (aContentToKeep.IsText() && aContentToJoin.IsText()) {
|
||||
nsAutoString rightText;
|
||||
nsAutoString leftText;
|
||||
aContentToKeep.AsText()->GetData(rightText);
|
||||
aContentToJoin.AsText()->GetData(leftText);
|
||||
leftText += rightText;
|
||||
IgnoredErrorResult ignoredError;
|
||||
DoSetText(MOZ_KnownLive(*aContentToKeep.AsText()), leftText, ignoredError);
|
||||
if (NS_WARN_IF(Destroyed())) {
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
}
|
||||
NS_WARNING_ASSERTION(!ignoredError.Failed(),
|
||||
"EditorBase::DoSetText() failed, but ignored");
|
||||
} else {
|
||||
// Otherwise it's an interior node, so shuffle around the children.
|
||||
nsCOMPtr<nsINodeList> childNodes = aContentToJoin.ChildNodes();
|
||||
MOZ_ASSERT(childNodes);
|
||||
|
||||
// Remember the first child in aContentToKeep, we'll insert all the children
|
||||
// of aContentToJoin in front of it GetFirstChild returns nullptr firstNode
|
||||
// if aContentToKeep has no children, that's OK.
|
||||
nsCOMPtr<nsIContent> firstNode = aContentToKeep.GetFirstChild();
|
||||
|
||||
// Have to go through the list backwards to keep deletes from interfering
|
||||
// with iteration.
|
||||
for (uint32_t i = childNodes->Length(); i; --i) {
|
||||
nsCOMPtr<nsIContent> childNode = childNodes->Item(i - 1);
|
||||
if (childNode) {
|
||||
// prepend children of aContentToJoin
|
||||
ErrorResult error;
|
||||
aContentToKeep.InsertBefore(*childNode, firstNode, error);
|
||||
if (NS_WARN_IF(Destroyed())) {
|
||||
error.SuppressException();
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
}
|
||||
if (error.Failed()) {
|
||||
NS_WARNING("nsINode::InsertBefore() failed");
|
||||
return error.StealNSResult();
|
||||
}
|
||||
firstNode = std::move(childNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Delete the extra node.
|
||||
aContentToJoin.Remove();
|
||||
if (NS_WARN_IF(Destroyed())) {
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
}
|
||||
|
||||
bool allowedTransactionsToChangeSelection =
|
||||
AllowsTransactionsToChangeSelection();
|
||||
|
||||
RefPtr<Selection> previousSelection;
|
||||
for (size_t i = 0; i < savedRanges.Length(); ++i) {
|
||||
// And adjust the selection if needed.
|
||||
SavedRange& range = savedRanges[i];
|
||||
|
||||
// If we have not seen the selection yet, clear all of its ranges.
|
||||
if (range.mSelection != previousSelection) {
|
||||
ErrorResult error;
|
||||
range.mSelection->RemoveAllRanges(error);
|
||||
if (NS_WARN_IF(Destroyed())) {
|
||||
error.SuppressException();
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
}
|
||||
if (error.Failed()) {
|
||||
NS_WARNING("Selection::RemoveAllRanges() failed");
|
||||
return error.StealNSResult();
|
||||
}
|
||||
previousSelection = range.mSelection;
|
||||
}
|
||||
|
||||
if (allowedTransactionsToChangeSelection &&
|
||||
range.mSelection->Type() == SelectionType::eNormal) {
|
||||
// If the editor should adjust the selection, don't bother restoring
|
||||
// the ranges for the normal selection here.
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check to see if we joined nodes where selection starts.
|
||||
if (range.mStartContainer == &aContentToJoin) {
|
||||
range.mStartContainer = &aContentToKeep;
|
||||
} else if (range.mStartContainer == &aContentToKeep) {
|
||||
range.mStartOffset += firstNodeLength;
|
||||
}
|
||||
|
||||
// Check to see if we joined nodes where selection ends.
|
||||
if (range.mEndContainer == &aContentToJoin) {
|
||||
range.mEndContainer = &aContentToKeep;
|
||||
} else if (range.mEndContainer == &aContentToKeep) {
|
||||
range.mEndOffset += firstNodeLength;
|
||||
}
|
||||
|
||||
RefPtr<nsRange> newRange =
|
||||
nsRange::Create(range.mStartContainer, range.mStartOffset,
|
||||
range.mEndContainer, range.mEndOffset, IgnoreErrors());
|
||||
if (!newRange) {
|
||||
NS_WARNING("nsRange::Create() failed");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
ErrorResult error;
|
||||
// The `MOZ_KnownLive` annotation is only necessary because of a bug
|
||||
// (https://bugzilla.mozilla.org/show_bug.cgi?id=1622253) in the
|
||||
// static analyzer.
|
||||
MOZ_KnownLive(range.mSelection)
|
||||
->AddRangeAndSelectFramesAndNotifyListeners(*newRange, error);
|
||||
if (NS_WARN_IF(Destroyed())) {
|
||||
error.SuppressException();
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
}
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.StealNSResult();
|
||||
}
|
||||
}
|
||||
|
||||
if (allowedTransactionsToChangeSelection) {
|
||||
// Editor wants us to set selection at join point.
|
||||
DebugOnly<nsresult> rvIgnored = SelectionRefPtr()->Collapse(
|
||||
&aContentToKeep, AssertedCast<int32_t>(firstNodeLength));
|
||||
if (NS_WARN_IF(Destroyed())) {
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
}
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored),
|
||||
"Selection::Collapse() failed, but ignored");
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
already_AddRefed<Element> HTMLEditor::DeleteSelectionAndCreateElement(
|
||||
nsAtom& aTag) {
|
||||
MOZ_ASSERT(IsEditActionDataAvailable());
|
||||
|
@ -46,6 +46,7 @@ class AutoSetTemporaryAncestorLimiter;
|
||||
class EditActionResult;
|
||||
class EditResult;
|
||||
class EmptyEditableFunctor;
|
||||
class JoinNodeTransaction;
|
||||
class ListElementSelectionState;
|
||||
class ListItemElementSelectionState;
|
||||
class MoveNodeResult;
|
||||
@ -1192,6 +1193,20 @@ class HTMLEditor final : public TextEditor,
|
||||
nsIContent& aNewLeftNode,
|
||||
ErrorResult& aError);
|
||||
|
||||
/**
|
||||
* DoJoinNodes() merges contents in aContentToJoin to aContentToKeep and
|
||||
* remove aContentToJoin from the DOM tree. aContentToJoin and aContentToKeep
|
||||
* must have same parent, aParent. Additionally, if one of aContentToJoin or
|
||||
* aContentToKeep is a text node, the other must be a text node.
|
||||
*
|
||||
* @param aContentToKeep The node that will remain after the join.
|
||||
* @param aContentToJoin The node that will be joined with aContentToKeep.
|
||||
* There is no requirement that the two nodes be of the
|
||||
* same type.
|
||||
*/
|
||||
[[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
|
||||
DoJoinNodes(nsIContent& aContentToKeep, nsIContent& aContentToJoin);
|
||||
|
||||
protected: // edit sub-action handler
|
||||
/**
|
||||
* CanHandleHTMLEditSubAction() checks whether there is at least one
|
||||
@ -4750,6 +4765,7 @@ class HTMLEditor final : public TextEditor,
|
||||
friend class CSSEditUtils;
|
||||
friend class EditorBase;
|
||||
friend class EmptyEditableFunctor;
|
||||
friend class JoinNodeTransaction;
|
||||
friend class ListElementSelectionState;
|
||||
friend class ListItemElementSelectionState;
|
||||
friend class ParagraphStateAtSelection;
|
||||
|
@ -6,7 +6,7 @@
|
||||
#include "JoinNodeTransaction.h"
|
||||
|
||||
#include "HTMLEditUtils.h"
|
||||
#include "mozilla/EditorBase.h" // for EditorBase
|
||||
#include "mozilla/HTMLEditor.h" // for HTMLEditor
|
||||
#include "mozilla/dom/Text.h"
|
||||
#include "nsAString.h"
|
||||
#include "nsDebug.h" // for NS_ASSERTION, etc.
|
||||
@ -20,26 +20,26 @@ using namespace dom;
|
||||
|
||||
// static
|
||||
already_AddRefed<JoinNodeTransaction> JoinNodeTransaction::MaybeCreate(
|
||||
EditorBase& aEditorBase, nsIContent& aLeftContent,
|
||||
HTMLEditor& aHTMLEditor, nsIContent& aLeftContent,
|
||||
nsIContent& aRightContent) {
|
||||
RefPtr<JoinNodeTransaction> transaction =
|
||||
new JoinNodeTransaction(aEditorBase, aLeftContent, aRightContent);
|
||||
new JoinNodeTransaction(aHTMLEditor, aLeftContent, aRightContent);
|
||||
if (NS_WARN_IF(!transaction->CanDoIt())) {
|
||||
return nullptr;
|
||||
}
|
||||
return transaction.forget();
|
||||
}
|
||||
|
||||
JoinNodeTransaction::JoinNodeTransaction(EditorBase& aEditorBase,
|
||||
JoinNodeTransaction::JoinNodeTransaction(HTMLEditor& aHTMLEditor,
|
||||
nsIContent& aLeftContent,
|
||||
nsIContent& aRightContent)
|
||||
: mEditorBase(&aEditorBase),
|
||||
: mHTMLEditor(&aHTMLEditor),
|
||||
mLeftContent(&aLeftContent),
|
||||
mRightContent(&aRightContent),
|
||||
mOffset(0) {}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_INHERITED(JoinNodeTransaction, EditTransactionBase,
|
||||
mEditorBase, mLeftContent, mRightContent,
|
||||
mHTMLEditor, mLeftContent, mRightContent,
|
||||
mParentNode)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(JoinNodeTransaction)
|
||||
@ -47,17 +47,16 @@ NS_INTERFACE_MAP_END_INHERITING(EditTransactionBase)
|
||||
|
||||
bool JoinNodeTransaction::CanDoIt() const {
|
||||
if (NS_WARN_IF(!mLeftContent) || NS_WARN_IF(!mRightContent) ||
|
||||
NS_WARN_IF(!mEditorBase) || !mLeftContent->GetParentNode()) {
|
||||
NS_WARN_IF(!mHTMLEditor) || !mLeftContent->GetParentNode()) {
|
||||
return false;
|
||||
}
|
||||
return mEditorBase->IsTextEditor() ||
|
||||
HTMLEditUtils::IsRemovableFromParentNode(*mLeftContent);
|
||||
return HTMLEditUtils::IsRemovableFromParentNode(*mLeftContent);
|
||||
}
|
||||
|
||||
// After DoTransaction() and RedoTransaction(), the left node is removed from
|
||||
// the content tree and right node remains.
|
||||
NS_IMETHODIMP JoinNodeTransaction::DoTransaction() {
|
||||
if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mLeftContent) ||
|
||||
if (NS_WARN_IF(!mHTMLEditor) || NS_WARN_IF(!mLeftContent) ||
|
||||
NS_WARN_IF(!mRightContent)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
@ -79,11 +78,11 @@ NS_IMETHODIMP JoinNodeTransaction::DoTransaction() {
|
||||
mParentNode = leftContentParent;
|
||||
mOffset = mLeftContent->Length();
|
||||
|
||||
OwningNonNull<EditorBase> editorBase = *mEditorBase;
|
||||
OwningNonNull<HTMLEditor> htmlEditor = *mHTMLEditor;
|
||||
OwningNonNull<nsIContent> leftContent = *mLeftContent;
|
||||
OwningNonNull<nsIContent> rightContent = *mRightContent;
|
||||
nsresult rv = editorBase->DoJoinNodes(rightContent, leftContent);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "EditorBase::DoJoinNodes() failed");
|
||||
nsresult rv = htmlEditor->DoJoinNodes(rightContent, leftContent);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "HTMLEditor::DoJoinNodes() failed");
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -91,7 +90,7 @@ NS_IMETHODIMP JoinNodeTransaction::DoTransaction() {
|
||||
// mRight and re-inserted mLeft?
|
||||
NS_IMETHODIMP JoinNodeTransaction::UndoTransaction() {
|
||||
if (NS_WARN_IF(!mParentNode) || NS_WARN_IF(!mLeftContent) ||
|
||||
NS_WARN_IF(!mRightContent) || NS_WARN_IF(!mEditorBase)) {
|
||||
NS_WARN_IF(!mRightContent) || NS_WARN_IF(!mHTMLEditor)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
@ -102,8 +101,8 @@ NS_IMETHODIMP JoinNodeTransaction::UndoTransaction() {
|
||||
// First, massage the existing node so it is in its post-split state
|
||||
ErrorResult error;
|
||||
if (Text* rightTextNode = rightContent->GetAsText()) {
|
||||
OwningNonNull<EditorBase> editorBase = *mEditorBase;
|
||||
editorBase->DoDeleteText(MOZ_KnownLive(*rightTextNode), 0, mOffset, error);
|
||||
OwningNonNull<HTMLEditor> htmlEditor = *mHTMLEditor;
|
||||
htmlEditor->DoDeleteText(MOZ_KnownLive(*rightTextNode), 0, mOffset, error);
|
||||
if (error.Failed()) {
|
||||
NS_WARNING("EditorBase::DoDeleteText() failed");
|
||||
return error.StealNSResult();
|
||||
|
@ -17,7 +17,7 @@ class nsINode;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class EditorBase;
|
||||
class HTMLEditor;
|
||||
|
||||
/**
|
||||
* A transaction that joins two nodes E1 (left node) and E2 (right node) into a
|
||||
@ -27,7 +27,7 @@ class EditorBase;
|
||||
*/
|
||||
class JoinNodeTransaction final : public EditTransactionBase {
|
||||
protected:
|
||||
JoinNodeTransaction(EditorBase& aEditorBase, nsIContent& aLeftContent,
|
||||
JoinNodeTransaction(HTMLEditor& aHTMLEditor, nsIContent& aLeftContent,
|
||||
nsIContent& aRightContent);
|
||||
|
||||
public:
|
||||
@ -35,12 +35,12 @@ class JoinNodeTransaction final : public EditTransactionBase {
|
||||
* Creates a join node transaction. This returns nullptr if cannot join the
|
||||
* nodes.
|
||||
*
|
||||
* @param aEditorBase The provider of core editing operations.
|
||||
* @param aHTMLEditor The provider of core editing operations.
|
||||
* @param aLeftContent The first of two nodes to join.
|
||||
* @param aRightContent The second of two nodes to join.
|
||||
*/
|
||||
static already_AddRefed<JoinNodeTransaction> MaybeCreate(
|
||||
EditorBase& aEditorBase, nsIContent& aLeftContent,
|
||||
HTMLEditor& aHTMLEditor, nsIContent& aLeftContent,
|
||||
nsIContent& aRightContent);
|
||||
|
||||
/**
|
||||
@ -57,7 +57,7 @@ class JoinNodeTransaction final : public EditTransactionBase {
|
||||
NS_DECL_EDITTRANSACTIONBASE_GETASMETHODS_OVERRIDE(JoinNodeTransaction)
|
||||
|
||||
protected:
|
||||
RefPtr<EditorBase> mEditorBase;
|
||||
RefPtr<HTMLEditor> mHTMLEditor;
|
||||
|
||||
// The nodes to operate upon. After the merge, mRightContent remains and
|
||||
// mLeftContent is removed from the content tree.
|
||||
|
@ -132,7 +132,7 @@ NS_IMETHODIMP SplitNodeTransaction::UndoTransaction() {
|
||||
*mStartOfRightContent.ContainerAsContent();
|
||||
OwningNonNull<nsIContent> newLeftContent = *mNewLeftContent;
|
||||
nsresult rv = htmlEditor->DoJoinNodes(containerContent, newLeftContent);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "EditorBase::DoJoinNodes() failed");
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "HTMLEditor::DoJoinNodes() failed");
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user