зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1627175 - part 46: Move `HTMLEditor::GetPriorHTMLSibling()` to `HTMLEditUtils` r=m_kato
Differential Revision: https://phabricator.services.mozilla.com/D115115
This commit is contained in:
Родитель
691fb1b366
Коммит
1d94e91f3f
|
@ -3376,7 +3376,9 @@ nsresult HTMLEditor::IndentListChild(RefPtr<Element>* aCurList,
|
|||
// 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 (nsCOMPtr<nsIContent> previousEditableSibling =
|
||||
GetPriorHTMLSibling(&aContent, SkipWhiteSpace::Yes)) {
|
||||
HTMLEditUtils::GetPreviousSibling(
|
||||
aContent, {WalkTreeOption::IgnoreWhiteSpaceOnlyText,
|
||||
WalkTreeOption::IgnoreNonEditableNode})) {
|
||||
if (HTMLEditUtils::IsAnyListElement(previousEditableSibling) &&
|
||||
aCurPoint.GetContainer()->NodeInfo()->NameAtom() ==
|
||||
previousEditableSibling->NodeInfo()->NameAtom() &&
|
||||
|
@ -3396,7 +3398,10 @@ nsresult HTMLEditor::IndentListChild(RefPtr<Element>* aCurList,
|
|||
// check to see if aCurList is still appropriate. Which it is if
|
||||
// aContent is still right after it in the same list.
|
||||
nsIContent* previousEditableSibling =
|
||||
*aCurList ? GetPriorHTMLSibling(&aContent, SkipWhiteSpace::Yes) : nullptr;
|
||||
*aCurList ? HTMLEditUtils::GetPreviousSibling(
|
||||
aContent, {WalkTreeOption::IgnoreWhiteSpaceOnlyText,
|
||||
WalkTreeOption::IgnoreNonEditableNode})
|
||||
: nullptr;
|
||||
if (!*aCurList ||
|
||||
(previousEditableSibling && previousEditableSibling != *aCurList)) {
|
||||
nsAtom* containerName = aCurPoint.GetContainer()->NodeInfo()->NameAtom();
|
||||
|
@ -3873,7 +3878,9 @@ nsresult HTMLEditor::HandleHTMLIndentAtSelectionInternal() {
|
|||
// check to see if curList is still appropriate. Which it is if
|
||||
// content is still right after it in the same list.
|
||||
nsIContent* previousEditableSibling =
|
||||
curList ? GetPriorHTMLSibling(listItem) : nullptr;
|
||||
curList ? HTMLEditUtils::GetPreviousSibling(
|
||||
*listItem, {WalkTreeOption::IgnoreNonEditableNode})
|
||||
: nullptr;
|
||||
if (!curList ||
|
||||
(previousEditableSibling && previousEditableSibling != curList)) {
|
||||
EditorDOMPoint atListItem(listItem);
|
||||
|
@ -6506,7 +6513,8 @@ nsresult HTMLEditor::HandleInsertParagraphInHeadingElement(Element& aHeader,
|
|||
|
||||
// If the previous heading of split point is empty, put a padding <br>
|
||||
// element for empty last line into it.
|
||||
nsCOMPtr<nsIContent> prevItem = GetPriorHTMLSibling(&aHeader);
|
||||
nsCOMPtr<nsIContent> prevItem = HTMLEditUtils::GetPreviousSibling(
|
||||
aHeader, {WalkTreeOption::IgnoreNonEditableNode});
|
||||
if (prevItem) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(HTMLEditUtils::IsHeader(*prevItem));
|
||||
if (HTMLEditUtils::IsEmptyNode(
|
||||
|
@ -6689,7 +6697,11 @@ EditActionResult HTMLEditor::HandleInsertParagraphInParagraph(
|
|||
// at beginning of text node?
|
||||
if (atStartOfSelection.IsStartOfContainer()) {
|
||||
// is there a BR prior to it?
|
||||
brContent = GetPriorHTMLSibling(atStartOfSelection.GetContainer());
|
||||
brContent = atStartOfSelection.IsInContentNode()
|
||||
? HTMLEditUtils::GetPreviousSibling(
|
||||
*atStartOfSelection.ContainerAsContent(),
|
||||
{WalkTreeOption::IgnoreNonEditableNode})
|
||||
: nullptr;
|
||||
if (!brContent || !HTMLEditUtils::IsVisibleBRElement(*brContent) ||
|
||||
EditorUtils::IsPaddingBRElementForEmptyLastLine(*brContent)) {
|
||||
pointToInsertBR.Set(atStartOfSelection.GetContainer());
|
||||
|
@ -7031,7 +7043,8 @@ nsresult HTMLEditor::HandleInsertParagraphInListItemElement(Element& aListItem,
|
|||
// Hack: until I can change the damaged doc range code back to being
|
||||
// extra-inclusive, I have to manually detect certain list items that may be
|
||||
// left empty.
|
||||
nsCOMPtr<nsIContent> prevItem = GetPriorHTMLSibling(&aListItem);
|
||||
nsCOMPtr<nsIContent> prevItem = HTMLEditUtils::GetPreviousSibling(
|
||||
aListItem, {WalkTreeOption::IgnoreNonEditableNode});
|
||||
if (prevItem && HTMLEditUtils::IsListItem(prevItem)) {
|
||||
if (HTMLEditUtils::IsEmptyNode(
|
||||
*prevItem, {EmptyCheckOption::TreatSingleBRElementAsVisible})) {
|
||||
|
@ -8094,7 +8107,8 @@ void HTMLEditor::SetSelectionInterlinePosition() {
|
|||
// immediately after non-editable contents, but previous editable
|
||||
// content is a block, does this do right thing?
|
||||
if (nsIContent* previousEditableContentInBlockAtCaret =
|
||||
GetPriorHTMLSibling(atCaret.GetChild())) {
|
||||
HTMLEditUtils::GetPreviousSibling(
|
||||
*atCaret.GetChild(), {WalkTreeOption::IgnoreNonEditableNode})) {
|
||||
if (HTMLEditUtils::IsBlockElement(*previousEditableContentInBlockAtCaret)) {
|
||||
IgnoredErrorResult ignoredError;
|
||||
SelectionRef().SetInterlinePosition(true, ignoredError);
|
||||
|
@ -9003,8 +9017,8 @@ nsresult HTMLEditor::EnsureHardLineBeginsWithFirstChildOf(
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsIContent* previousEditableContent =
|
||||
GetPriorHTMLSibling(&aRemovingContainerElement);
|
||||
nsIContent* previousEditableContent = HTMLEditUtils::GetPreviousSibling(
|
||||
aRemovingContainerElement, {WalkTreeOption::IgnoreNonEditableNode});
|
||||
if (!previousEditableContent) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -9040,8 +9054,8 @@ nsresult HTMLEditor::EnsureHardLineEndsWithLastChildOf(
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsIContent* nextEditableContent =
|
||||
GetPriorHTMLSibling(&aRemovingContainerElement);
|
||||
nsIContent* nextEditableContent = HTMLEditUtils::GetPreviousSibling(
|
||||
aRemovingContainerElement, {WalkTreeOption::IgnoreNonEditableNode});
|
||||
if (!nextEditableContent) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -9418,7 +9432,10 @@ nsresult HTMLEditor::MoveSelectedContentsToDivElementToMakeItAbsolutePosition(
|
|||
// Therefore, duplicate same list element into the target `<div>`
|
||||
// element.
|
||||
nsIContent* previousEditableContent =
|
||||
createdListElement ? GetPriorHTMLSibling(content) : nullptr;
|
||||
createdListElement
|
||||
? HTMLEditUtils::GetPreviousSibling(
|
||||
content, {WalkTreeOption::IgnoreNonEditableNode})
|
||||
: nullptr;
|
||||
if (!createdListElement ||
|
||||
(previousEditableContent &&
|
||||
previousEditableContent != createdListElement)) {
|
||||
|
@ -9480,7 +9497,10 @@ nsresult HTMLEditor::MoveSelectedContentsToDivElementToMakeItAbsolutePosition(
|
|||
// If we cannot move the list item element into created list element,
|
||||
// we need another list element in the target `<div>` element.
|
||||
nsIContent* previousEditableContent =
|
||||
createdListElement ? GetPriorHTMLSibling(listItemElement) : nullptr;
|
||||
createdListElement
|
||||
? HTMLEditUtils::GetPreviousSibling(
|
||||
*listItemElement, {WalkTreeOption::IgnoreNonEditableNode})
|
||||
: nullptr;
|
||||
if (!createdListElement ||
|
||||
(previousEditableContent &&
|
||||
previousEditableContent != createdListElement)) {
|
||||
|
|
|
@ -996,10 +996,7 @@ nsIContent* HTMLEditUtils::GetPreviousContent(
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
if ((!aOptions.contains(WalkTreeOption::IgnoreNonEditableNode) ||
|
||||
EditorUtils::IsEditableContent(*lastLeafContent, EditorType::HTML)) &&
|
||||
(!aOptions.contains(WalkTreeOption::IgnoreDataNodeExceptText) ||
|
||||
EditorUtils::IsElementOrText(*lastLeafContent))) {
|
||||
if (!HTMLEditUtils::IsContentIgnored(*lastLeafContent, aOptions)) {
|
||||
return lastLeafContent;
|
||||
}
|
||||
|
||||
|
@ -1052,10 +1049,7 @@ nsIContent* HTMLEditUtils::GetNextContent(
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
if ((!aOptions.contains(WalkTreeOption::IgnoreNonEditableNode) ||
|
||||
EditorUtils::IsEditableContent(*firstLeafContent, EditorType::HTML)) &&
|
||||
(!aOptions.contains(WalkTreeOption::IgnoreDataNodeExceptText) ||
|
||||
EditorUtils::IsElementOrText(*firstLeafContent))) {
|
||||
if (!HTMLEditUtils::IsContentIgnored(*firstLeafContent, aOptions)) {
|
||||
return firstLeafContent;
|
||||
}
|
||||
|
||||
|
@ -1147,10 +1141,7 @@ nsIContent* HTMLEditUtils::GetAdjacentContent(
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
if ((!aOptions.contains(WalkTreeOption::IgnoreNonEditableNode) ||
|
||||
EditorUtils::IsEditableContent(*leafContent, EditorType::HTML)) &&
|
||||
(!aOptions.contains(WalkTreeOption::IgnoreDataNodeExceptText) ||
|
||||
EditorUtils::IsElementOrText(*leafContent))) {
|
||||
if (!HTMLEditUtils::IsContentIgnored(*leafContent, aOptions)) {
|
||||
return leafContent;
|
||||
}
|
||||
|
||||
|
|
|
@ -401,6 +401,7 @@ class HTMLEditUtils final {
|
|||
enum class WalkTreeOption {
|
||||
IgnoreNonEditableNode, // Ignore non-editable nodes and their children.
|
||||
IgnoreDataNodeExceptText, // Ignore data nodes which are not text node.
|
||||
IgnoreWhiteSpaceOnlyText, // Ignore text nodes having only white-spaces.
|
||||
StopAtBlockBoundary, // Stop waking the tree at a block boundary.
|
||||
};
|
||||
using WalkTreeOptions = EnumSet<WalkTreeOption>;
|
||||
|
@ -463,6 +464,26 @@ class HTMLEditUtils final {
|
|||
const WalkTreeOptions& aOptions,
|
||||
const Element* aAncestorLimiter = nullptr);
|
||||
|
||||
/**
|
||||
* GetPreviousSibling() returns the nearest sibling of aContent which does
|
||||
* not match with aOption.
|
||||
*/
|
||||
static nsIContent* GetPreviousSibling(const nsIContent& aContent,
|
||||
const WalkTreeOptions& aOptions) {
|
||||
for (nsIContent* sibling = aContent.GetPreviousSibling(); sibling;
|
||||
sibling = sibling->GetPreviousSibling()) {
|
||||
if (HTMLEditUtils::IsContentIgnored(*sibling, aOptions)) {
|
||||
continue;
|
||||
}
|
||||
if (aOptions.contains(WalkTreeOption::StopAtBlockBoundary) &&
|
||||
HTMLEditUtils::IsBlockElement(*sibling)) {
|
||||
return nullptr;
|
||||
}
|
||||
return sibling;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* GetLastLeafChild() returns rightmost leaf content in aNode. It depends on
|
||||
* aLeafNodeTypes whether this which types of nodes are treated as leaf nodes.
|
||||
|
@ -1161,6 +1182,25 @@ class HTMLEditUtils final {
|
|||
return !cannotCrossBoundary;
|
||||
}
|
||||
|
||||
static bool IsContentIgnored(const nsIContent& aContent,
|
||||
const WalkTreeOptions& aOptions) {
|
||||
if (aOptions.contains(WalkTreeOption::IgnoreNonEditableNode) &&
|
||||
!EditorUtils::IsEditableContent(aContent,
|
||||
EditorUtils::EditorType::HTML)) {
|
||||
return true;
|
||||
}
|
||||
if (aOptions.contains(WalkTreeOption::IgnoreDataNodeExceptText) &&
|
||||
!EditorUtils::IsElementOrText(aContent)) {
|
||||
return true;
|
||||
}
|
||||
if (aOptions.contains(WalkTreeOption::IgnoreWhiteSpaceOnlyText) &&
|
||||
aContent.IsText() &&
|
||||
const_cast<dom::Text*>(aContent.AsText())->TextIsOnlyWhitespace()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper for GetPreviousContent() and GetNextContent().
|
||||
*/
|
||||
|
|
|
@ -4061,7 +4061,8 @@ nsresult HTMLEditor::RemoveBlockContainerWithTransaction(Element& aElement) {
|
|||
// 3) first child of aNode is a block OR
|
||||
// 4) either is null
|
||||
|
||||
if (nsIContent* previousSibling = GetPriorHTMLSibling(&aElement)) {
|
||||
if (nsIContent* previousSibling = HTMLEditUtils::GetPreviousSibling(
|
||||
aElement, {WalkTreeOption::IgnoreNonEditableNode})) {
|
||||
if (!HTMLEditUtils::IsBlockElement(*previousSibling) &&
|
||||
!previousSibling->IsHTMLElement(nsGkAtoms::br) &&
|
||||
!HTMLEditUtils::IsBlockElement(*child)) {
|
||||
|
@ -4099,7 +4100,8 @@ nsresult HTMLEditor::RemoveBlockContainerWithTransaction(Element& aElement) {
|
|||
}
|
||||
}
|
||||
}
|
||||
} else if (nsIContent* previousSibling = GetPriorHTMLSibling(&aElement)) {
|
||||
} else if (nsIContent* previousSibling = HTMLEditUtils::GetPreviousSibling(
|
||||
aElement, {WalkTreeOption::IgnoreNonEditableNode})) {
|
||||
// The case of aNode being empty. We need a br at start unless:
|
||||
// 1) previous sibling of aNode is a block, OR
|
||||
// 2) previous sibling of aNode is a br, OR
|
||||
|
@ -4926,20 +4928,6 @@ nsresult HTMLEditor::DeleteSelectionAndPrepareToCreateNode() {
|
|||
return error.StealNSResult();
|
||||
}
|
||||
|
||||
nsIContent* HTMLEditor::GetPriorHTMLSibling(nsINode* aNode,
|
||||
SkipWhiteSpace aSkipWS) const {
|
||||
MOZ_ASSERT(aNode);
|
||||
|
||||
nsIContent* content = aNode->GetPreviousSibling();
|
||||
while (content &&
|
||||
(!EditorUtils::IsEditableContent(*content, EditorType::HTML) ||
|
||||
SkippableWhiteSpace(content, aSkipWS))) {
|
||||
content = content->GetPreviousSibling();
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
nsIContent* HTMLEditor::GetNextHTMLSibling(nsINode* aNode,
|
||||
SkipWhiteSpace aSkipWS) const {
|
||||
MOZ_ASSERT(aNode);
|
||||
|
|
|
@ -917,14 +917,7 @@ class HTMLEditor final : public TextEditor,
|
|||
SplitAncestorStyledInlineElementsAt(const EditorDOMPoint& aPointToSplit,
|
||||
nsAtom* aProperty, nsAtom* aAttribute);
|
||||
|
||||
/**
|
||||
* GetPriorHTMLSibling() returns the previous editable sibling, if there is
|
||||
* one within the parent, optionally skipping text nodes that are only
|
||||
* white-space.
|
||||
*/
|
||||
enum class SkipWhiteSpace { Yes, No };
|
||||
nsIContent* GetPriorHTMLSibling(nsINode* aNode,
|
||||
SkipWhiteSpace = SkipWhiteSpace::No) const;
|
||||
|
||||
/**
|
||||
* GetNextHTMLSibling() returns the next editable sibling, if there is
|
||||
|
@ -934,7 +927,7 @@ class HTMLEditor final : public TextEditor,
|
|||
nsIContent* GetNextHTMLSibling(nsINode* aNode,
|
||||
SkipWhiteSpace = SkipWhiteSpace::No) const;
|
||||
|
||||
// Helper for GetPriorHTMLSibling/GetNextHTMLSibling.
|
||||
// Helper for GetNextHTMLSibling.
|
||||
static bool SkippableWhiteSpace(nsINode* aNode, SkipWhiteSpace aSkipWS) {
|
||||
return aSkipWS == SkipWhiteSpace::Yes && aNode->IsText() &&
|
||||
aNode->AsText()->TextIsOnlyWhitespace();
|
||||
|
|
|
@ -50,6 +50,7 @@ using namespace dom;
|
|||
using EmptyCheckOption = HTMLEditUtils::EmptyCheckOption;
|
||||
using LeafNodeType = HTMLEditUtils::LeafNodeType;
|
||||
using LeafNodeTypes = HTMLEditUtils::LeafNodeTypes;
|
||||
using WalkTreeOption = HTMLEditUtils::WalkTreeOption;
|
||||
|
||||
nsresult HTMLEditor::SetInlinePropertyAsAction(nsAtom& aProperty,
|
||||
nsAtom* aAttribute,
|
||||
|
@ -494,7 +495,8 @@ nsresult HTMLEditor::SetInlinePropertyOnTextNode(
|
|||
|
||||
if (aAttribute) {
|
||||
// Look for siblings that are correct type of node
|
||||
nsIContent* sibling = GetPriorHTMLSibling(textNodeForTheRange);
|
||||
nsIContent* sibling = HTMLEditUtils::GetPreviousSibling(
|
||||
*textNodeForTheRange, {WalkTreeOption::IgnoreNonEditableNode});
|
||||
if (sibling && sibling->IsElement()) {
|
||||
OwningNonNull<Element> element(*sibling->AsElement());
|
||||
Result<bool, nsresult> result = ElementIsGoodContainerForTheStyle(
|
||||
|
@ -586,7 +588,8 @@ nsresult HTMLEditor::SetInlinePropertyOnNodeImpl(nsIContent& aContent,
|
|||
}
|
||||
|
||||
// First check if there's an adjacent sibling we can put our node into.
|
||||
nsCOMPtr<nsIContent> previousSibling = GetPriorHTMLSibling(&aContent);
|
||||
nsCOMPtr<nsIContent> previousSibling = HTMLEditUtils::GetPreviousSibling(
|
||||
aContent, {WalkTreeOption::IgnoreNonEditableNode});
|
||||
nsCOMPtr<nsIContent> nextSibling = GetNextHTMLSibling(&aContent);
|
||||
if (previousSibling && previousSibling->IsElement()) {
|
||||
OwningNonNull<Element> previousElement(*previousSibling->AsElement());
|
||||
|
@ -2403,6 +2406,7 @@ nsresult HTMLEditor::RelativeFontChangeOnTextNode(FontSize aDir,
|
|||
NS_WARNING("HTMLEditor::SplitNodeWithTransaction() failed");
|
||||
return error.StealNSResult();
|
||||
}
|
||||
MOZ_DIAGNOSTIC_ASSERT(textNodeForTheRange);
|
||||
}
|
||||
|
||||
// Split at the start of the range.
|
||||
|
@ -2420,7 +2424,8 @@ nsresult HTMLEditor::RelativeFontChangeOnTextNode(FontSize aDir,
|
|||
|
||||
// Look for siblings that are correct type of node
|
||||
nsAtom* nodeType = aDir == FontSize::incr ? nsGkAtoms::big : nsGkAtoms::small;
|
||||
nsCOMPtr<nsIContent> sibling = GetPriorHTMLSibling(textNodeForTheRange);
|
||||
nsCOMPtr<nsIContent> sibling = HTMLEditUtils::GetPreviousSibling(
|
||||
*textNodeForTheRange, {WalkTreeOption::IgnoreNonEditableNode});
|
||||
if (sibling && sibling->IsHTMLElement(nodeType)) {
|
||||
// Previous sib is already right kind of inline node; slide this over
|
||||
nsresult rv = MoveNodeToEndWithTransaction(*textNodeForTheRange, *sibling);
|
||||
|
@ -2549,7 +2554,8 @@ nsresult HTMLEditor::RelativeFontChangeOnNode(int32_t aSizeChange,
|
|||
// ok, chuck it in.
|
||||
// first look at siblings of aNode for matching bigs or smalls.
|
||||
// if we find one, move aNode into it.
|
||||
nsCOMPtr<nsIContent> sibling = GetPriorHTMLSibling(aNode);
|
||||
nsCOMPtr<nsIContent> sibling = HTMLEditUtils::GetPreviousSibling(
|
||||
*aNode, {WalkTreeOption::IgnoreNonEditableNode});
|
||||
if (sibling && sibling->IsHTMLElement(atom)) {
|
||||
// previous sib is already right kind of inline node; slide this over into
|
||||
// it
|
||||
|
|
|
@ -38,6 +38,7 @@ using namespace dom;
|
|||
|
||||
using LeafNodeType = HTMLEditUtils::LeafNodeType;
|
||||
using LeafNodeTypes = HTMLEditUtils::LeafNodeTypes;
|
||||
using WalkTreeOption = HTMLEditUtils::WalkTreeOption;
|
||||
|
||||
const char16_t kNBSP = 160;
|
||||
|
||||
|
@ -1201,7 +1202,8 @@ nsresult WhiteSpaceVisibilityKeeper::DeleteContentNodeAndJoinTextNodesAroundIt(
|
|||
}
|
||||
|
||||
nsCOMPtr<nsIContent> previousEditableSibling =
|
||||
aHTMLEditor.GetPriorHTMLSibling(&aContentToDelete);
|
||||
HTMLEditUtils::GetPreviousSibling(
|
||||
aContentToDelete, {WalkTreeOption::IgnoreNonEditableNode});
|
||||
// Delete the node, and join like nodes if appropriate
|
||||
rv = aHTMLEditor.DeleteNodeWithTransaction(aContentToDelete);
|
||||
if (NS_WARN_IF(aHTMLEditor.Destroyed())) {
|
||||
|
|
Загрузка…
Ссылка в новой задаче