зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1774704 - part 5-2: Make `HTMLEditor::IndentListChild` stop touching `Selection` directly r=m_kato
Differential Revision: https://phabricator.services.mozilla.com/D152971
This commit is contained in:
Родитель
49869c2825
Коммит
2296d580e7
|
@ -4154,101 +4154,77 @@ EditActionResult HTMLEditor::IndentAsSubAction(const Element& aEditingHost) {
|
|||
return result.SetResult(rv);
|
||||
}
|
||||
|
||||
// Helper for Handle[CSS|HTML]IndentAtSelectionInternal
|
||||
nsresult HTMLEditor::IndentListChild(RefPtr<Element>* aCurList,
|
||||
const EditorDOMPoint& aCurPoint,
|
||||
nsIContent& aContent) {
|
||||
MOZ_ASSERT(HTMLEditUtils::IsAnyListElement(aCurPoint.GetContainer()),
|
||||
"unexpected container");
|
||||
Result<EditorDOMPoint, nsresult> HTMLEditor::IndentListChildWithTransaction(
|
||||
RefPtr<Element>* aSubListElement, const EditorDOMPoint& aPointInListElement,
|
||||
nsIContent& aContentMovingToSubList, const Element& aEditingHost) {
|
||||
MOZ_ASSERT(
|
||||
HTMLEditUtils::IsAnyListElement(aPointInListElement.GetContainer()),
|
||||
"unexpected container");
|
||||
MOZ_ASSERT(IsTopLevelEditSubActionDataAvailable());
|
||||
|
||||
RefPtr<Element> editingHost = ComputeEditingHost();
|
||||
if (MOZ_UNLIKELY(NS_WARN_IF(!editingHost))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// some logic for putting list items into nested lists...
|
||||
|
||||
// Check for whether we should join a list that follows aContent.
|
||||
// We do this if the next element is a list, and the list is of the
|
||||
// same type (li/ol) as aContent was a part it.
|
||||
// If aContentMovingToSubList is followed by a sub-list element whose tag is
|
||||
// same as the parent list element's tag, we can move it to start of the
|
||||
// sub-list.
|
||||
if (nsIContent* nextEditableSibling = HTMLEditUtils::GetNextSibling(
|
||||
aContent, {WalkTreeOption::IgnoreWhiteSpaceOnlyText,
|
||||
WalkTreeOption::IgnoreNonEditableNode})) {
|
||||
aContentMovingToSubList, {WalkTreeOption::IgnoreWhiteSpaceOnlyText,
|
||||
WalkTreeOption::IgnoreNonEditableNode})) {
|
||||
if (HTMLEditUtils::IsAnyListElement(nextEditableSibling) &&
|
||||
aCurPoint.GetContainer()->NodeInfo()->NameAtom() ==
|
||||
aPointInListElement.GetContainer()->NodeInfo()->NameAtom() ==
|
||||
nextEditableSibling->NodeInfo()->NameAtom() &&
|
||||
aCurPoint.GetContainer()->NodeInfo()->NamespaceID() ==
|
||||
aPointInListElement.GetContainer()->NodeInfo()->NamespaceID() ==
|
||||
nextEditableSibling->NodeInfo()->NamespaceID()) {
|
||||
const MoveNodeResult moveListElementResult = MoveNodeWithTransaction(
|
||||
aContent, EditorDOMPoint(nextEditableSibling, 0u));
|
||||
MoveNodeResult moveListElementResult = MoveNodeWithTransaction(
|
||||
aContentMovingToSubList, EditorDOMPoint(nextEditableSibling, 0u));
|
||||
if (moveListElementResult.isErr()) {
|
||||
NS_WARNING("HTMLEditor::MoveNodeWithTransaction() failed");
|
||||
return moveListElementResult.unwrapErr();
|
||||
return Err(moveListElementResult.unwrapErr());
|
||||
}
|
||||
nsresult rv = moveListElementResult.SuggestCaretPointTo(
|
||||
*this, {SuggestCaret::OnlyIfHasSuggestion,
|
||||
SuggestCaret::OnlyIfTransactionsAllowedToDoIt,
|
||||
SuggestCaret::AndIgnoreTrivialError});
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("MoveNodeResult::SuggestCaretPointTo() failed");
|
||||
return rv;
|
||||
}
|
||||
NS_WARNING_ASSERTION(
|
||||
rv != NS_SUCCESS_EDITOR_BUT_IGNORED_TRIVIAL_ERROR,
|
||||
"MoveNodeResult::SuggestCaretPointTo() failed, but ignored");
|
||||
return NS_OK;
|
||||
return moveListElementResult.UnwrapCaretPoint();
|
||||
}
|
||||
}
|
||||
|
||||
// Check for whether we should join a list that preceeds aContent.
|
||||
// We do this if the previous element is a list, and the list is of
|
||||
// the same type (li/ol) as aContent was a part of.
|
||||
// If aContentMovingToSubList follows a sub-list element whose tag is same
|
||||
// as the parent list element's tag, we can move it to end of the sub-list.
|
||||
if (nsCOMPtr<nsIContent> previousEditableSibling =
|
||||
HTMLEditUtils::GetPreviousSibling(
|
||||
aContent, {WalkTreeOption::IgnoreWhiteSpaceOnlyText,
|
||||
WalkTreeOption::IgnoreNonEditableNode})) {
|
||||
aContentMovingToSubList,
|
||||
{WalkTreeOption::IgnoreWhiteSpaceOnlyText,
|
||||
WalkTreeOption::IgnoreNonEditableNode})) {
|
||||
if (HTMLEditUtils::IsAnyListElement(previousEditableSibling) &&
|
||||
aCurPoint.GetContainer()->NodeInfo()->NameAtom() ==
|
||||
aPointInListElement.GetContainer()->NodeInfo()->NameAtom() ==
|
||||
previousEditableSibling->NodeInfo()->NameAtom() &&
|
||||
aCurPoint.GetContainer()->NodeInfo()->NamespaceID() ==
|
||||
aPointInListElement.GetContainer()->NodeInfo()->NamespaceID() ==
|
||||
previousEditableSibling->NodeInfo()->NamespaceID()) {
|
||||
const MoveNodeResult moveListElementResult =
|
||||
MoveNodeToEndWithTransaction(aContent, *previousEditableSibling);
|
||||
MoveNodeResult moveListElementResult = MoveNodeToEndWithTransaction(
|
||||
aContentMovingToSubList, *previousEditableSibling);
|
||||
if (moveListElementResult.isErr()) {
|
||||
NS_WARNING("HTMLEditor::MoveNodeToEndWithTransaction() failed");
|
||||
return moveListElementResult.unwrapErr();
|
||||
return Err(moveListElementResult.unwrapErr());
|
||||
}
|
||||
nsresult rv = moveListElementResult.SuggestCaretPointTo(
|
||||
*this, {SuggestCaret::OnlyIfHasSuggestion,
|
||||
SuggestCaret::OnlyIfTransactionsAllowedToDoIt,
|
||||
SuggestCaret::AndIgnoreTrivialError});
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("MoveNodeResult::SuggestCaretPointTo() failed");
|
||||
return rv;
|
||||
}
|
||||
NS_WARNING_ASSERTION(
|
||||
rv != NS_SUCCESS_EDITOR_BUT_IGNORED_TRIVIAL_ERROR,
|
||||
"MoveNodeResult::SuggestCaretPointTo() failed, but ignored");
|
||||
return NS_OK;
|
||||
return moveListElementResult.UnwrapCaretPoint();
|
||||
}
|
||||
}
|
||||
|
||||
// check to see if aCurList is still appropriate. Which it is if
|
||||
// aContent is still right after it in the same list.
|
||||
// If aContentMovingToSubList does not follow aSubListElement, we need
|
||||
// to create new sub-list element.
|
||||
EditorDOMPoint pointToPutCaret;
|
||||
nsIContent* previousEditableSibling =
|
||||
*aCurList ? HTMLEditUtils::GetPreviousSibling(
|
||||
aContent, {WalkTreeOption::IgnoreWhiteSpaceOnlyText,
|
||||
WalkTreeOption::IgnoreNonEditableNode})
|
||||
: nullptr;
|
||||
if (!*aCurList ||
|
||||
(previousEditableSibling && previousEditableSibling != *aCurList)) {
|
||||
nsAtom* containerName = aCurPoint.GetContainer()->NodeInfo()->NameAtom();
|
||||
*aSubListElement ? HTMLEditUtils::GetPreviousSibling(
|
||||
aContentMovingToSubList,
|
||||
{WalkTreeOption::IgnoreWhiteSpaceOnlyText,
|
||||
WalkTreeOption::IgnoreNonEditableNode})
|
||||
: nullptr;
|
||||
if (!*aSubListElement || (previousEditableSibling &&
|
||||
previousEditableSibling != *aSubListElement)) {
|
||||
nsAtom* containerName =
|
||||
aPointInListElement.GetContainer()->NodeInfo()->NameAtom();
|
||||
// Create a new nested list of correct type.
|
||||
CreateElementResult createNewListElementResult =
|
||||
InsertElementWithSplittingAncestorsWithTransaction(
|
||||
MOZ_KnownLive(*containerName), aCurPoint,
|
||||
BRElementNextToSplitPoint::Keep, *editingHost);
|
||||
MOZ_KnownLive(*containerName), aPointInListElement,
|
||||
BRElementNextToSplitPoint::Keep, aEditingHost);
|
||||
if (createNewListElementResult.isErr()) {
|
||||
NS_WARNING(
|
||||
nsPrintfCString(
|
||||
|
@ -4256,42 +4232,25 @@ nsresult HTMLEditor::IndentListChild(RefPtr<Element>* aCurList,
|
|||
"%s) failed",
|
||||
nsAtomCString(containerName).get())
|
||||
.get());
|
||||
return createNewListElementResult.unwrapErr();
|
||||
}
|
||||
nsresult rv = createNewListElementResult.SuggestCaretPointTo(
|
||||
*this, {SuggestCaret::OnlyIfHasSuggestion,
|
||||
SuggestCaret::OnlyIfTransactionsAllowedToDoIt});
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("CreateElementResult::SuggestCaretPointTo() failed");
|
||||
return rv;
|
||||
return Err(createNewListElementResult.unwrapErr());
|
||||
}
|
||||
MOZ_ASSERT(createNewListElementResult.GetNewNode());
|
||||
// aCurList is now the correct thing to put aContent in
|
||||
// remember our new block for postprocessing
|
||||
TopLevelEditSubActionDataRef().mNewBlockElement =
|
||||
createNewListElementResult.GetNewNode();
|
||||
*aCurList = createNewListElementResult.UnwrapNewNode();
|
||||
pointToPutCaret = createNewListElementResult.UnwrapCaretPoint();
|
||||
*aSubListElement = createNewListElementResult.UnwrapNewNode();
|
||||
}
|
||||
// tuck the node into the end of the active list
|
||||
RefPtr<nsINode> container = *aCurList;
|
||||
const MoveNodeResult moveNodeResult =
|
||||
MoveNodeToEndWithTransaction(aContent, *container);
|
||||
|
||||
// Finally, we should move aContentMovingToSubList into aSubListElement.
|
||||
const RefPtr<Element> subListElement = *aSubListElement;
|
||||
MoveNodeResult moveNodeResult =
|
||||
MoveNodeToEndWithTransaction(aContentMovingToSubList, *subListElement);
|
||||
if (moveNodeResult.isErr()) {
|
||||
NS_WARNING("HTMLEditor::MoveNodeToEndWithTransaction() failed");
|
||||
return moveNodeResult.unwrapErr();
|
||||
return Err(moveNodeResult.unwrapErr());
|
||||
}
|
||||
nsresult rv = moveNodeResult.SuggestCaretPointTo(
|
||||
*this, {SuggestCaret::OnlyIfHasSuggestion,
|
||||
SuggestCaret::OnlyIfTransactionsAllowedToDoIt,
|
||||
SuggestCaret::AndIgnoreTrivialError});
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("MoveNodeResult::SuggestCaretPointTo() failed");
|
||||
return rv;
|
||||
if (moveNodeResult.HasCaretPointSuggestion()) {
|
||||
pointToPutCaret = moveNodeResult.UnwrapCaretPoint();
|
||||
}
|
||||
NS_WARNING_ASSERTION(
|
||||
rv != NS_SUCCESS_EDITOR_BUT_IGNORED_TRIVIAL_ERROR,
|
||||
"MoveNodeResult::SuggestCaretPointTo() failed, but ignored");
|
||||
return NS_OK;
|
||||
return pointToPutCaret;
|
||||
}
|
||||
|
||||
EditActionResult HTMLEditor::HandleIndentAtSelection(
|
||||
|
@ -4551,13 +4510,31 @@ nsresult HTMLEditor::HandleCSSIndentAtSelectionInternal(
|
|||
}
|
||||
|
||||
if (HTMLEditUtils::IsAnyListElement(atContent.GetContainer())) {
|
||||
const RefPtr<Element> listElement = curList;
|
||||
// MOZ_KnownLive because 'arrayOfContents' is guaranteed to
|
||||
// keep it alive.
|
||||
nsresult rv =
|
||||
IndentListChild(&curList, atContent, MOZ_KnownLive(content));
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("HTMLEditor::IndentListChild() failed");
|
||||
return rv;
|
||||
Result<EditorDOMPoint, nsresult> pointToPutCaretOrError =
|
||||
IndentListChildWithTransaction(&curList, atContent,
|
||||
MOZ_KnownLive(content), aEditingHost);
|
||||
if (MOZ_UNLIKELY(pointToPutCaretOrError.isErr())) {
|
||||
NS_WARNING("HTMLEditor::IndentListChildWithTransaction() failed");
|
||||
return pointToPutCaretOrError.unwrapErr();
|
||||
}
|
||||
if (curList != listElement) {
|
||||
// New list element is created, so we should put caret into the new list
|
||||
// element.
|
||||
TopLevelEditSubActionDataRef().mNewBlockElement = curList;
|
||||
}
|
||||
if (AllowsTransactionsToChangeSelection() &&
|
||||
pointToPutCaretOrError.inspect().IsSet()) {
|
||||
nsresult rv = CollapseSelectionTo(pointToPutCaretOrError.inspect());
|
||||
if (MOZ_UNLIKELY(rv == NS_ERROR_EDITOR_DESTROYED)) {
|
||||
NS_WARNING("EditorBase::CollapseSelectionTo() failed");
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
}
|
||||
NS_WARNING_ASSERTION(
|
||||
NS_SUCCEEDED(rv),
|
||||
"EditorBase::CollapseSelectionTo() failed, but ignored");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
@ -4836,13 +4813,31 @@ nsresult HTMLEditor::HandleHTMLIndentAtSelectionInternal(
|
|||
}
|
||||
|
||||
if (HTMLEditUtils::IsAnyListElement(atContent.GetContainer())) {
|
||||
const RefPtr<Element> listElement = curList;
|
||||
// MOZ_KnownLive because 'arrayOfContents' is guaranteed to
|
||||
// keep it alive.
|
||||
nsresult rv =
|
||||
IndentListChild(&curList, atContent, MOZ_KnownLive(content));
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("HTMLEditor::IndentListChild() failed");
|
||||
return rv;
|
||||
Result<EditorDOMPoint, nsresult> pointToPutCaretOrError =
|
||||
IndentListChildWithTransaction(&curList, atContent,
|
||||
MOZ_KnownLive(content), aEditingHost);
|
||||
if (MOZ_UNLIKELY(pointToPutCaretOrError.isErr())) {
|
||||
NS_WARNING("HTMLEditor::IndentListChildWithTransaction() failed");
|
||||
return pointToPutCaretOrError.unwrapErr();
|
||||
}
|
||||
if (listElement != curList) {
|
||||
// New list element is created, so we should put caret into the new list
|
||||
// element.
|
||||
TopLevelEditSubActionDataRef().mNewBlockElement = curList;
|
||||
}
|
||||
if (AllowsTransactionsToChangeSelection() &&
|
||||
pointToPutCaretOrError.inspect().IsSet()) {
|
||||
nsresult rv = CollapseSelectionTo(pointToPutCaretOrError.inspect());
|
||||
if (MOZ_UNLIKELY(rv == NS_ERROR_EDITOR_DESTROYED)) {
|
||||
NS_WARNING("EditorBase::CollapseSelectionTo() failed");
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
}
|
||||
NS_WARNING_ASSERTION(
|
||||
NS_SUCCEEDED(rv),
|
||||
"EditorBase::CollapseSelectionTo() failed, but ignored");
|
||||
}
|
||||
// forget curQuote, if any
|
||||
curQuote = nullptr;
|
||||
|
|
|
@ -4321,10 +4321,32 @@ class HTMLEditor final : public EditorBase,
|
|||
}
|
||||
|
||||
protected:
|
||||
// Helper for Handle[CSS|HTML]IndentAtSelectionInternal
|
||||
[[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
|
||||
IndentListChild(RefPtr<Element>* aCurList, const EditorDOMPoint& aCurPoint,
|
||||
nsIContent& aContent);
|
||||
/**
|
||||
* IndentListChildWithTransaction() is a helper method of
|
||||
* Handle(CSS|HTML)IndentAtSelectionInternal().
|
||||
*
|
||||
* @param aSubListElement [in/out] Specify a sub-list element of the
|
||||
* container of aPointInListElement or nullptr.
|
||||
* When there is no proper sub-list element to
|
||||
* move aContentMovingToSubList, this method
|
||||
* inserts a new sub-list element and update this
|
||||
* to it.
|
||||
* @param aPointInListElement A point in a list element whose child should
|
||||
* be indented. If this method creates new list
|
||||
* element into the list element, this inserts
|
||||
* the new list element to this point.
|
||||
* @param aContentMovingToSubList
|
||||
* A content node which is a child of a list
|
||||
* element and should be moved into a sub-list
|
||||
* element.
|
||||
* @param aEditingHost The editing host.
|
||||
* @return A candidate caret position.
|
||||
*/
|
||||
[[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<EditorDOMPoint, nsresult>
|
||||
IndentListChildWithTransaction(RefPtr<Element>* aSubListElement,
|
||||
const EditorDOMPoint& aPointInListElement,
|
||||
nsIContent& aContentMovingToSubList,
|
||||
const Element& aEditingHost);
|
||||
|
||||
/**
|
||||
* Stack based helper class for saving/restoring selection. Note that this
|
||||
|
|
Загрузка…
Ссылка в новой задаче