зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1677566 - part 2: Make `HTMLEditUtils` treat a found non-editable element as a leaf node even if it has children r=m_kato
Blink treats each non-editable node as an atomic object. E.g., deleting or forward-deleting from next to a non-editable element, it deletes only one non-editable element. Unfortunately, our layout treat adjacent non-editable nodes as a node. Therefore, the adding WPTs do not work, but they are not new regression of this patch. Differential Revision: https://phabricator.services.mozilla.com/D107587
This commit is contained in:
Родитель
e659ab60ed
Коммит
1229430221
|
@ -126,7 +126,8 @@ namespace mozilla {
|
|||
using namespace dom;
|
||||
using namespace widget;
|
||||
|
||||
using ChildBlockBoundary = HTMLEditUtils::ChildBlockBoundary;
|
||||
using LeafNodeType = HTMLEditUtils::LeafNodeType;
|
||||
using LeafNodeTypes = HTMLEditUtils::LeafNodeTypes;
|
||||
|
||||
/*****************************************************************************
|
||||
* mozilla::EditorBase
|
||||
|
@ -2585,7 +2586,7 @@ nsINode* EditorBase::GetFirstEditableNode(nsINode* aRoot) {
|
|||
|
||||
EditorType editorType = GetEditorType();
|
||||
nsIContent* content =
|
||||
HTMLEditUtils::GetFirstLeafChild(*aRoot, ChildBlockBoundary::TreatAsLeaf);
|
||||
HTMLEditUtils::GetFirstLeafChild(*aRoot, {LeafNodeType::OnlyLeafNode});
|
||||
if (content && !EditorUtils::IsEditableContent(*content, editorType)) {
|
||||
content = GetNextEditableNode(*content);
|
||||
}
|
||||
|
@ -2830,8 +2831,9 @@ nsIContent* EditorBase::GetPreviousNodeInternal(const EditorRawDOMPoint& aPoint,
|
|||
// unless there isn't one, in which case we are at the end of the node
|
||||
// and want the deep-right child.
|
||||
nsIContent* lastLeafContent = HTMLEditUtils::GetLastLeafChild(
|
||||
*aPoint.GetContainer(), aNoBlockCrossing ? ChildBlockBoundary::TreatAsLeaf
|
||||
: ChildBlockBoundary::Ignore);
|
||||
*aPoint.GetContainer(),
|
||||
{aNoBlockCrossing ? LeafNodeType::LeafNodeOrChildBlock
|
||||
: LeafNodeType::OnlyLeafNode});
|
||||
if (!lastLeafContent) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -2884,8 +2886,9 @@ nsIContent* EditorBase::GetNextNodeInternal(const EditorRawDOMPoint& aPoint,
|
|||
}
|
||||
|
||||
nsIContent* firstLeafContent = HTMLEditUtils::GetFirstLeafChild(
|
||||
*point.GetChild(), aNoBlockCrossing ? ChildBlockBoundary::TreatAsLeaf
|
||||
: ChildBlockBoundary::Ignore);
|
||||
*point.GetChild(),
|
||||
{aNoBlockCrossing ? LeafNodeType::LeafNodeOrChildBlock
|
||||
: LeafNodeType::OnlyLeafNode});
|
||||
if (!firstLeafContent) {
|
||||
return point.GetChild();
|
||||
}
|
||||
|
@ -2936,13 +2939,12 @@ nsIContent* EditorBase::FindNextLeafNode(const nsINode* aCurrentNode,
|
|||
// don't look inside prevsib, since it is a block
|
||||
return sibling;
|
||||
}
|
||||
ChildBlockBoundary childBlockBoundary =
|
||||
bNoBlockCrossing ? ChildBlockBoundary::TreatAsLeaf
|
||||
: ChildBlockBoundary::Ignore;
|
||||
const LeafNodeTypes leafNodeTypes = {
|
||||
bNoBlockCrossing ? LeafNodeType::LeafNodeOrChildBlock
|
||||
: LeafNodeType::OnlyLeafNode};
|
||||
nsIContent* leafContent =
|
||||
aGoForward
|
||||
? HTMLEditUtils::GetFirstLeafChild(*sibling, childBlockBoundary)
|
||||
: HTMLEditUtils::GetLastLeafChild(*sibling, childBlockBoundary);
|
||||
aGoForward ? HTMLEditUtils::GetFirstLeafChild(*sibling, leafNodeTypes)
|
||||
: HTMLEditUtils::GetLastLeafChild(*sibling, leafNodeTypes);
|
||||
return leafContent ? leafContent : sibling;
|
||||
}
|
||||
|
||||
|
|
|
@ -71,7 +71,8 @@ class nsISupports;
|
|||
namespace mozilla {
|
||||
|
||||
using namespace dom;
|
||||
using ChildBlockBoundary = HTMLEditUtils::ChildBlockBoundary;
|
||||
using LeafNodeType = HTMLEditUtils::LeafNodeType;
|
||||
using LeafNodeTypes = HTMLEditUtils::LeafNodeTypes;
|
||||
using StyleDifference = HTMLEditUtils::StyleDifference;
|
||||
|
||||
/********************************************************
|
||||
|
@ -2195,7 +2196,8 @@ HTMLEditor::DeleteTextAndNormalizeSurroundingWhiteSpaces(
|
|||
// Try to put caret next to immediately after previous editable leaf.
|
||||
nsIContent* previousContent =
|
||||
HTMLEditUtils::GetPreviousLeafContentOrPreviousBlockElement(
|
||||
newCaretPosition, *currentBlock, editingHost);
|
||||
newCaretPosition, *currentBlock,
|
||||
{LeafNodeType::LeafNodeOrNonEditableNode}, editingHost);
|
||||
if (previousContent && !HTMLEditUtils::IsBlockElement(*previousContent)) {
|
||||
newCaretPosition =
|
||||
previousContent->IsText() ||
|
||||
|
@ -2207,7 +2209,9 @@ HTMLEditor::DeleteTextAndNormalizeSurroundingWhiteSpaces(
|
|||
// a child block, look for next editable leaf instead.
|
||||
else if (nsIContent* nextContent =
|
||||
HTMLEditUtils::GetNextLeafContentOrNextBlockElement(
|
||||
newCaretPosition, *currentBlock, editingHost)) {
|
||||
newCaretPosition, *currentBlock,
|
||||
{LeafNodeType::LeafNodeOrNonEditableNode},
|
||||
editingHost)) {
|
||||
newCaretPosition = nextContent->IsText() ||
|
||||
HTMLEditUtils::IsContainerNode(*nextContent)
|
||||
? EditorDOMPoint(nextContent, 0)
|
||||
|
@ -5344,7 +5348,7 @@ nsresult HTMLEditor::MaybeExtendSelectionToHardLineEdgesForBlockEditAction() {
|
|||
// endpoint is just after the close of a block.
|
||||
nsIContent* child = HTMLEditUtils::GetLastLeafChild(
|
||||
*wsScannerAtEnd.StartReasonOtherBlockElementPtr(),
|
||||
ChildBlockBoundary::TreatAsLeaf);
|
||||
{LeafNodeType::LeafNodeOrChildBlock});
|
||||
if (child) {
|
||||
newEndPoint.SetAfter(child);
|
||||
}
|
||||
|
@ -5378,7 +5382,7 @@ nsresult HTMLEditor::MaybeExtendSelectionToHardLineEdgesForBlockEditAction() {
|
|||
// startpoint is just before the start of a block.
|
||||
nsINode* child = HTMLEditUtils::GetFirstLeafChild(
|
||||
*wsScannerAtStart.EndReasonOtherBlockElementPtr(),
|
||||
ChildBlockBoundary::TreatAsLeaf);
|
||||
{LeafNodeType::LeafNodeOrChildBlock});
|
||||
if (child) {
|
||||
newStartPoint.Set(child);
|
||||
}
|
||||
|
@ -6766,7 +6770,7 @@ nsresult HTMLEditor::SplitParagraph(
|
|||
// selection to beginning of right hand para;
|
||||
// look inside any containers that are up front.
|
||||
nsCOMPtr<nsIContent> child = HTMLEditUtils::GetFirstLeafChild(
|
||||
aParentDivOrP, ChildBlockBoundary::TreatAsLeaf);
|
||||
aParentDivOrP, {LeafNodeType::LeafNodeOrChildBlock});
|
||||
if (child && (child->IsText() || HTMLEditUtils::IsContainerNode(*child))) {
|
||||
nsresult rv = CollapseSelectionToStartOf(*child);
|
||||
if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/EditorDOMPoint.h"
|
||||
#include "mozilla/EditorUtils.h"
|
||||
#include "mozilla/EnumSet.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/dom/AbstractRange.h"
|
||||
#include "mozilla/dom/AncestorIterator.h"
|
||||
|
@ -307,46 +308,58 @@ class HTMLEditUtils final {
|
|||
|
||||
/**
|
||||
* GetLastLeafChild() returns rightmost leaf content in aNode. It depends on
|
||||
* aChildBlockBoundary whether this scans into a block child or treat
|
||||
* block as a leaf.
|
||||
* aLeafNodeTypes whether this which types of nodes are treated as leaf nodes.
|
||||
*/
|
||||
enum class ChildBlockBoundary {
|
||||
enum class LeafNodeType {
|
||||
// Even if there is a child block, keep scanning a leaf content in it.
|
||||
Ignore,
|
||||
// If there is a child block, return it.
|
||||
TreatAsLeaf,
|
||||
OnlyLeafNode,
|
||||
// If there is a child block, return it too. Note that this does not
|
||||
// mean that block siblings are not treated as leaf nodes.
|
||||
LeafNodeOrChildBlock,
|
||||
// If there is a non-editable element if and only if scanning from editable
|
||||
// node, return it too.
|
||||
LeafNodeOrNonEditableNode,
|
||||
};
|
||||
using LeafNodeTypes = EnumSet<LeafNodeType>;
|
||||
static nsIContent* GetLastLeafChild(nsINode& aNode,
|
||||
ChildBlockBoundary aChildBlockBoundary) {
|
||||
const LeafNodeTypes& aLeafNodeTypes) {
|
||||
for (nsIContent* content = aNode.GetLastChild(); content;
|
||||
content = content->GetLastChild()) {
|
||||
if (aChildBlockBoundary == ChildBlockBoundary::TreatAsLeaf &&
|
||||
if (aLeafNodeTypes.contains(LeafNodeType::LeafNodeOrChildBlock) &&
|
||||
HTMLEditUtils::IsBlockElement(*content)) {
|
||||
return content;
|
||||
}
|
||||
if (!content->HasChildren()) {
|
||||
return content;
|
||||
}
|
||||
if (aLeafNodeTypes.contains(LeafNodeType::LeafNodeOrNonEditableNode) &&
|
||||
aNode.IsEditable() && !content->IsEditable()) {
|
||||
return content;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* GetFirstLeafChild() returns leftmost leaf content in aNode. It depends on
|
||||
* aChildBlockBoundary whether this scans into a block child or treat
|
||||
* aLeafNodeTypes whether this scans into a block child or treat
|
||||
* block as a leaf.
|
||||
*/
|
||||
static nsIContent* GetFirstLeafChild(nsINode& aNode,
|
||||
ChildBlockBoundary aChildBlockBoundary) {
|
||||
const LeafNodeTypes& aLeafNodeTypes) {
|
||||
for (nsIContent* content = aNode.GetFirstChild(); content;
|
||||
content = content->GetFirstChild()) {
|
||||
if (aChildBlockBoundary == ChildBlockBoundary::TreatAsLeaf &&
|
||||
if (aLeafNodeTypes.contains(LeafNodeType::LeafNodeOrChildBlock) &&
|
||||
HTMLEditUtils::IsBlockElement(*content)) {
|
||||
return content;
|
||||
}
|
||||
if (!content->HasChildren()) {
|
||||
return content;
|
||||
}
|
||||
if (aLeafNodeTypes.contains(LeafNodeType::LeafNodeOrNonEditableNode) &&
|
||||
aNode.IsEditable() && !content->IsEditable()) {
|
||||
return content;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -361,12 +374,14 @@ class HTMLEditUtils final {
|
|||
* @param aCurrentBlock Must be ancestor of aStartContent. Dispite
|
||||
* the name, inline content is allowed if
|
||||
* aStartContent is in an inline editing host.
|
||||
* @param aLeafNodeTypes See LeafNodeType.
|
||||
* @param aAncestorLimiter Optional, setting this guarantees the
|
||||
* result is in aAncestorLimiter unless
|
||||
* aStartContent is not a descendant of this.
|
||||
*/
|
||||
static nsIContent* GetNextLeafContentOrNextBlockElement(
|
||||
const nsIContent& aStartContent, const nsIContent& aCurrentBlock,
|
||||
const LeafNodeTypes& aLeafNodeTypes,
|
||||
const Element* aAncestorLimiter = nullptr) {
|
||||
if (&aStartContent == aAncestorLimiter) {
|
||||
return nullptr;
|
||||
|
@ -402,10 +417,14 @@ class HTMLEditUtils final {
|
|||
if (HTMLEditUtils::IsBlockElement(*nextContent)) {
|
||||
return nextContent;
|
||||
}
|
||||
if (aLeafNodeTypes.contains(LeafNodeType::LeafNodeOrNonEditableNode) &&
|
||||
aStartContent.IsEditable() && !nextContent->IsEditable()) {
|
||||
return nextContent;
|
||||
}
|
||||
if (HTMLEditUtils::IsContainerNode(*nextContent)) {
|
||||
// Else if it's a container, get deep leftmost child
|
||||
if (nsIContent* child = HTMLEditUtils::GetFirstLeafChild(
|
||||
*nextContent, ChildBlockBoundary::Ignore)) {
|
||||
if (nsIContent* child =
|
||||
HTMLEditUtils::GetFirstLeafChild(*nextContent, aLeafNodeTypes)) {
|
||||
return child;
|
||||
}
|
||||
}
|
||||
|
@ -420,7 +439,7 @@ class HTMLEditUtils final {
|
|||
template <typename PT, typename CT>
|
||||
static nsIContent* GetNextLeafContentOrNextBlockElement(
|
||||
const EditorDOMPointBase<PT, CT>& aStartPoint,
|
||||
const nsIContent& aCurrentBlock,
|
||||
const nsIContent& aCurrentBlock, const LeafNodeTypes& aLeafNodeTypes,
|
||||
const Element* aAncestorLimiter = nullptr) {
|
||||
MOZ_ASSERT(aStartPoint.IsSet());
|
||||
|
||||
|
@ -429,11 +448,13 @@ class HTMLEditUtils final {
|
|||
}
|
||||
if (aStartPoint.IsInTextNode()) {
|
||||
return HTMLEditUtils::GetNextLeafContentOrNextBlockElement(
|
||||
*aStartPoint.ContainerAsText(), aCurrentBlock, aAncestorLimiter);
|
||||
*aStartPoint.ContainerAsText(), aCurrentBlock, aLeafNodeTypes,
|
||||
aAncestorLimiter);
|
||||
}
|
||||
if (!HTMLEditUtils::IsContainerNode(*aStartPoint.ContainerAsContent())) {
|
||||
return HTMLEditUtils::GetNextLeafContentOrNextBlockElement(
|
||||
*aStartPoint.ContainerAsContent(), aCurrentBlock, aAncestorLimiter);
|
||||
*aStartPoint.ContainerAsContent(), aCurrentBlock, aLeafNodeTypes,
|
||||
aAncestorLimiter);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIContent> nextContent = aStartPoint.GetChild();
|
||||
|
@ -445,17 +466,23 @@ class HTMLEditUtils final {
|
|||
|
||||
// We are at end of non-block container
|
||||
return HTMLEditUtils::GetNextLeafContentOrNextBlockElement(
|
||||
*aStartPoint.ContainerAsContent(), aCurrentBlock, aAncestorLimiter);
|
||||
*aStartPoint.ContainerAsContent(), aCurrentBlock, aLeafNodeTypes,
|
||||
aAncestorLimiter);
|
||||
}
|
||||
|
||||
// We have a next node. If it's a block, return it.
|
||||
if (HTMLEditUtils::IsBlockElement(*nextContent)) {
|
||||
return nextContent;
|
||||
}
|
||||
if (aLeafNodeTypes.contains(LeafNodeType::LeafNodeOrNonEditableNode) &&
|
||||
aStartPoint.GetContainer()->IsEditable() &&
|
||||
!nextContent->IsEditable()) {
|
||||
return nextContent;
|
||||
}
|
||||
if (HTMLEditUtils::IsContainerNode(*nextContent)) {
|
||||
// else if it's a container, get deep leftmost child
|
||||
if (nsIContent* child = HTMLEditUtils::GetFirstLeafChild(
|
||||
*nextContent, ChildBlockBoundary::Ignore)) {
|
||||
if (nsIContent* child =
|
||||
HTMLEditUtils::GetFirstLeafChild(*nextContent, aLeafNodeTypes)) {
|
||||
return child;
|
||||
}
|
||||
}
|
||||
|
@ -474,12 +501,14 @@ class HTMLEditUtils final {
|
|||
* @param aCurrentBlock Must be ancestor of aStartContent. Dispite
|
||||
* the name, inline content is allowed if
|
||||
* aStartContent is in an inline editing host.
|
||||
* @param aLeafNodeTypes See LeafNodeType.
|
||||
* @param aAncestorLimiter Optional, setting this guarantees the
|
||||
* result is in aAncestorLimiter unless
|
||||
* aStartContent is not a descendant of this.
|
||||
*/
|
||||
static nsIContent* GetPreviousLeafContentOrPreviousBlockElement(
|
||||
const nsIContent& aStartContent, const nsIContent& aCurrentBlock,
|
||||
const LeafNodeTypes& aLeafNodeTypes,
|
||||
const Element* aAncestorLimiter = nullptr) {
|
||||
if (&aStartContent == aAncestorLimiter) {
|
||||
return nullptr;
|
||||
|
@ -515,10 +544,14 @@ class HTMLEditUtils final {
|
|||
if (HTMLEditUtils::IsBlockElement(*previousContent)) {
|
||||
return previousContent;
|
||||
}
|
||||
if (aLeafNodeTypes.contains(LeafNodeType::LeafNodeOrNonEditableNode) &&
|
||||
aStartContent.IsEditable() && !previousContent->IsEditable()) {
|
||||
return previousContent;
|
||||
}
|
||||
if (HTMLEditUtils::IsContainerNode(*previousContent)) {
|
||||
// Else if it's a container, get deep rightmost child
|
||||
if (nsIContent* child = HTMLEditUtils::GetLastLeafChild(
|
||||
*previousContent, ChildBlockBoundary::Ignore)) {
|
||||
if (nsIContent* child = HTMLEditUtils::GetLastLeafChild(*previousContent,
|
||||
aLeafNodeTypes)) {
|
||||
return child;
|
||||
}
|
||||
}
|
||||
|
@ -533,7 +566,7 @@ class HTMLEditUtils final {
|
|||
template <typename PT, typename CT>
|
||||
static nsIContent* GetPreviousLeafContentOrPreviousBlockElement(
|
||||
const EditorDOMPointBase<PT, CT>& aStartPoint,
|
||||
const nsIContent& aCurrentBlock,
|
||||
const nsIContent& aCurrentBlock, const LeafNodeTypes& aLeafNodeTypes,
|
||||
const Element* aAncestorLimiter = nullptr) {
|
||||
MOZ_ASSERT(aStartPoint.IsSet());
|
||||
|
||||
|
@ -542,11 +575,13 @@ class HTMLEditUtils final {
|
|||
}
|
||||
if (aStartPoint.IsInTextNode()) {
|
||||
return HTMLEditUtils::GetPreviousLeafContentOrPreviousBlockElement(
|
||||
*aStartPoint.ContainerAsText(), aCurrentBlock, aAncestorLimiter);
|
||||
*aStartPoint.ContainerAsText(), aCurrentBlock, aLeafNodeTypes,
|
||||
aAncestorLimiter);
|
||||
}
|
||||
if (!HTMLEditUtils::IsContainerNode(*aStartPoint.ContainerAsContent())) {
|
||||
return HTMLEditUtils::GetPreviousLeafContentOrPreviousBlockElement(
|
||||
*aStartPoint.ContainerAsContent(), aCurrentBlock, aAncestorLimiter);
|
||||
*aStartPoint.ContainerAsContent(), aCurrentBlock, aLeafNodeTypes,
|
||||
aAncestorLimiter);
|
||||
}
|
||||
|
||||
if (aStartPoint.IsStartOfContainer()) {
|
||||
|
@ -557,7 +592,8 @@ class HTMLEditUtils final {
|
|||
|
||||
// We are at start of non-block container
|
||||
return HTMLEditUtils::GetPreviousLeafContentOrPreviousBlockElement(
|
||||
*aStartPoint.ContainerAsContent(), aCurrentBlock, aAncestorLimiter);
|
||||
*aStartPoint.ContainerAsContent(), aCurrentBlock, aLeafNodeTypes,
|
||||
aAncestorLimiter);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIContent> previousContent =
|
||||
|
@ -570,10 +606,15 @@ class HTMLEditUtils final {
|
|||
if (HTMLEditUtils::IsBlockElement(*previousContent)) {
|
||||
return previousContent;
|
||||
}
|
||||
if (aLeafNodeTypes.contains(LeafNodeType::LeafNodeOrNonEditableNode) &&
|
||||
aStartPoint.GetContainer()->IsEditable() &&
|
||||
!previousContent->IsEditable()) {
|
||||
return previousContent;
|
||||
}
|
||||
if (HTMLEditUtils::IsContainerNode(*previousContent)) {
|
||||
// Else if it's a container, get deep rightmost child
|
||||
if (nsIContent* child = HTMLEditUtils::GetLastLeafChild(
|
||||
*previousContent, ChildBlockBoundary::Ignore)) {
|
||||
if (nsIContent* child = HTMLEditUtils::GetLastLeafChild(*previousContent,
|
||||
aLeafNodeTypes)) {
|
||||
return child;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -69,7 +69,8 @@ namespace mozilla {
|
|||
using namespace dom;
|
||||
using namespace widget;
|
||||
|
||||
using ChildBlockBoundary = HTMLEditUtils::ChildBlockBoundary;
|
||||
using LeafNodeType = HTMLEditUtils::LeafNodeType;
|
||||
using LeafNodeTypes = HTMLEditUtils::LeafNodeTypes;
|
||||
|
||||
const char16_t kNBSP = 160;
|
||||
|
||||
|
@ -2856,7 +2857,7 @@ already_AddRefed<Element> HTMLEditor::GetSelectedElement(const nsAtom* aTagName,
|
|||
return nullptr;
|
||||
}
|
||||
nsIContent* firstEditableLeaf = HTMLEditUtils::GetFirstLeafChild(
|
||||
*nextSibling, ChildBlockBoundary::Ignore);
|
||||
*nextSibling, {LeafNodeType::OnlyLeafNode});
|
||||
if (firstEditableLeaf &&
|
||||
firstEditableLeaf->IsHTMLElement(nsGkAtoms::br)) {
|
||||
return nullptr;
|
||||
|
@ -5116,7 +5117,7 @@ nsIContent* HTMLEditor::GetLastEditableChild(nsINode& aNode) const {
|
|||
|
||||
nsIContent* HTMLEditor::GetFirstEditableLeaf(nsINode& aNode) const {
|
||||
nsIContent* child =
|
||||
HTMLEditUtils::GetFirstLeafChild(aNode, ChildBlockBoundary::Ignore);
|
||||
HTMLEditUtils::GetFirstLeafChild(aNode, {LeafNodeType::OnlyLeafNode});
|
||||
while (child && (!EditorUtils::IsEditableContent(*child, EditorType::HTML) ||
|
||||
child->HasChildren())) {
|
||||
child = GetNextEditableHTMLNode(*child);
|
||||
|
@ -5132,7 +5133,7 @@ nsIContent* HTMLEditor::GetFirstEditableLeaf(nsINode& aNode) const {
|
|||
|
||||
nsIContent* HTMLEditor::GetLastEditableLeaf(nsINode& aNode) const {
|
||||
nsIContent* child =
|
||||
HTMLEditUtils::GetLastLeafChild(aNode, ChildBlockBoundary::Ignore);
|
||||
HTMLEditUtils::GetLastLeafChild(aNode, {LeafNodeType::OnlyLeafNode});
|
||||
while (child && (!EditorUtils::IsEditableContent(*child, EditorType::HTML) ||
|
||||
child->HasChildren())) {
|
||||
child = GetPreviousEditableHTMLNode(*child);
|
||||
|
|
|
@ -47,7 +47,8 @@ namespace mozilla {
|
|||
|
||||
using namespace dom;
|
||||
|
||||
using ChildBlockBoundary = HTMLEditUtils::ChildBlockBoundary;
|
||||
using LeafNodeType = HTMLEditUtils::LeafNodeType;
|
||||
using LeafNodeTypes = HTMLEditUtils::LeafNodeTypes;
|
||||
|
||||
nsresult HTMLEditor::SetInlinePropertyAsAction(nsAtom& aProperty,
|
||||
nsAtom* aAttribute,
|
||||
|
@ -991,7 +992,7 @@ EditResult HTMLEditor::ClearStyleAt(const EditorDOMPoint& aPoint,
|
|||
// `<p><b><i>a</i></b><b><i></i></b><b><i>bc</i></b></p>`.
|
||||
// ^^^^^^^^^^^^^^
|
||||
nsIContent* firstLeafChildOfNextNode = HTMLEditUtils::GetFirstLeafChild(
|
||||
*splitResult.GetNextNode(), ChildBlockBoundary::Ignore);
|
||||
*splitResult.GetNextNode(), {LeafNodeType::OnlyLeafNode});
|
||||
EditorDOMPoint atStartOfNextNode(firstLeafChildOfNextNode
|
||||
? firstLeafChildOfNextNode
|
||||
: splitResult.GetNextNode(),
|
||||
|
@ -1050,7 +1051,7 @@ EditResult HTMLEditor::ClearStyleAt(const EditorDOMPoint& aPoint,
|
|||
// E.g., `<p><b><i>a</i></b><b><i><br></i></b><b><i>bc</i></b></p>`
|
||||
nsIContent* firstLeafChildOfPreviousNode = HTMLEditUtils::GetFirstLeafChild(
|
||||
*splitResultAtStartOfNextNode.GetPreviousNode(),
|
||||
ChildBlockBoundary::Ignore);
|
||||
{LeafNodeType::OnlyLeafNode});
|
||||
EditorDOMPoint pointToPutCaret(
|
||||
firstLeafChildOfPreviousNode
|
||||
? firstLeafChildOfPreviousNode
|
||||
|
|
|
@ -70,7 +70,8 @@ namespace mozilla {
|
|||
|
||||
using namespace dom;
|
||||
|
||||
using ChildBlockBoundary = HTMLEditUtils::ChildBlockBoundary;
|
||||
using LeafNodeType = HTMLEditUtils::LeafNodeType;
|
||||
using LeafNodeTypes = HTMLEditUtils::LeafNodeTypes;
|
||||
|
||||
TextEditor::TextEditor()
|
||||
: mMaxTextLength(-1),
|
||||
|
@ -1018,7 +1019,7 @@ nsresult TextEditor::UndoAsAction(uint32_t aCount, nsIPrincipal* aPrincipal) {
|
|||
// and redo are relatively rare, it makes sense to take the (small)
|
||||
// performance hit here.
|
||||
nsIContent* firstLeafChild = HTMLEditUtils::GetFirstLeafChild(
|
||||
*mRootElement, ChildBlockBoundary::Ignore);
|
||||
*mRootElement, {LeafNodeType::OnlyLeafNode});
|
||||
if (firstLeafChild &&
|
||||
EditorUtils::IsPaddingBRElementForEmptyEditor(*firstLeafChild)) {
|
||||
mPaddingBRElementForEmptyEditor =
|
||||
|
|
|
@ -36,7 +36,8 @@ namespace mozilla {
|
|||
|
||||
using namespace dom;
|
||||
|
||||
using ChildBlockBoundary = HTMLEditUtils::ChildBlockBoundary;
|
||||
using LeafNodeType = HTMLEditUtils::LeafNodeType;
|
||||
using LeafNodeTypes = HTMLEditUtils::LeafNodeTypes;
|
||||
|
||||
const char16_t kNBSP = 160;
|
||||
|
||||
|
@ -1259,6 +1260,12 @@ WSScanResult WSRunScanner::ScanPreviousVisibleNodeOrBlockBoundaryFrom(
|
|||
TextFragmentDataAtStartRef().VisibleWhiteSpacesDataRef();
|
||||
if (visibleWhiteSpaces.IsInitialized() &&
|
||||
visibleWhiteSpaces.StartRef().IsBefore(aPoint)) {
|
||||
// If the visible things are not editable, we shouldn't scan "editable"
|
||||
// things now. Whether keep scanning editable things or not should be
|
||||
// considered by the caller.
|
||||
if (aPoint.GetChild() && !aPoint.GetChild()->IsEditable()) {
|
||||
return WSScanResult(aPoint.GetChild(), WSType::SpecialContent);
|
||||
}
|
||||
EditorDOMPointInText atPreviousChar = GetPreviousEditableCharPoint(aPoint);
|
||||
// When it's a non-empty text node, return it.
|
||||
if (atPreviousChar.IsSet() && !atPreviousChar.IsContainerEmpty()) {
|
||||
|
@ -1297,6 +1304,12 @@ WSScanResult WSRunScanner::ScanNextVisibleNodeOrBlockBoundaryFrom(
|
|||
TextFragmentDataAtStartRef().VisibleWhiteSpacesDataRef();
|
||||
if (visibleWhiteSpaces.IsInitialized() &&
|
||||
aPoint.EqualsOrIsBefore(visibleWhiteSpaces.EndRef())) {
|
||||
// If the visible things are not editable, we shouldn't scan "editable"
|
||||
// things now. Whether keep scanning editable things or not should be
|
||||
// considered by the caller.
|
||||
if (aPoint.GetChild() && !aPoint.GetChild()->IsEditable()) {
|
||||
return WSScanResult(aPoint.GetChild(), WSType::SpecialContent);
|
||||
}
|
||||
EditorDOMPointInText atNextChar = GetInclusiveNextEditableCharPoint(aPoint);
|
||||
// When it's a non-empty text node, return it.
|
||||
if (atNextChar.IsSet() && !atNextChar.IsContainerEmpty()) {
|
||||
|
@ -1448,7 +1461,7 @@ WSRunScanner::TextFragmentData::BoundaryData WSRunScanner::TextFragmentData::
|
|||
nsIContent* previousLeafContentOrBlock =
|
||||
HTMLEditUtils::GetPreviousLeafContentOrPreviousBlockElement(
|
||||
aPoint, aEditableBlockParentOrTopmostEditableInlineContent,
|
||||
aEditingHost);
|
||||
{LeafNodeType::LeafNodeOrNonEditableNode}, aEditingHost);
|
||||
if (!previousLeafContentOrBlock) {
|
||||
// no prior node means we exhausted
|
||||
// aEditableBlockParentOrTopmostEditableInlineContent
|
||||
|
@ -1580,7 +1593,7 @@ WSRunScanner::TextFragmentData::BoundaryData::ScanCollapsibleWhiteSpaceEndFrom(
|
|||
nsIContent* nextLeafContentOrBlock =
|
||||
HTMLEditUtils::GetNextLeafContentOrNextBlockElement(
|
||||
aPoint, aEditableBlockParentOrTopmostEditableInlineElement,
|
||||
aEditingHost);
|
||||
{LeafNodeType::LeafNodeOrNonEditableNode}, aEditingHost);
|
||||
if (!nextLeafContentOrBlock) {
|
||||
// no next node means we exhausted
|
||||
// aEditableBlockParentOrTopmostEditableInlineElement
|
||||
|
@ -2280,7 +2293,7 @@ WSRunScanner::TextFragmentData::GetInclusiveNextEditableCharPoint(
|
|||
aPoint.CanContainerHaveChildren() ? aPoint.GetChild() : nullptr) {
|
||||
nsIContent* leafContent = child->HasChildren()
|
||||
? HTMLEditUtils::GetFirstLeafChild(
|
||||
*child, ChildBlockBoundary::Ignore)
|
||||
*child, {LeafNodeType::OnlyLeafNode})
|
||||
: child;
|
||||
if (NS_WARN_IF(!leafContent)) {
|
||||
return EditorDOMPointInText();
|
||||
|
@ -2326,11 +2339,11 @@ WSRunScanner::TextFragmentData::GetInclusiveNextEditableCharPoint(
|
|||
HTMLEditUtils::GetNextLeafContentOrNextBlockElement(
|
||||
*point.ContainerAsContent(),
|
||||
*editableBlockParentOrTopmostEditableInlineContent,
|
||||
mEditingHost);
|
||||
{LeafNodeType::LeafNodeOrNonEditableNode}, mEditingHost);
|
||||
nextContent;
|
||||
nextContent = HTMLEditUtils::GetNextLeafContentOrNextBlockElement(
|
||||
*nextContent, *editableBlockParentOrTopmostEditableInlineContent,
|
||||
mEditingHost)) {
|
||||
{LeafNodeType::LeafNodeOrNonEditableNode}, mEditingHost)) {
|
||||
if (!nextContent->IsText() || !nextContent->IsEditable()) {
|
||||
if (nextContent == GetEndReasonContent()) {
|
||||
break; // Reached end of current runs.
|
||||
|
@ -2360,7 +2373,7 @@ WSRunScanner::TextFragmentData::GetPreviousEditableCharPoint(
|
|||
nsIContent* leafContent =
|
||||
previousChild->HasChildren()
|
||||
? HTMLEditUtils::GetLastLeafChild(*previousChild,
|
||||
ChildBlockBoundary::Ignore)
|
||||
{LeafNodeType::OnlyLeafNode})
|
||||
: previousChild;
|
||||
if (NS_WARN_IF(!leafContent)) {
|
||||
return EditorDOMPointInText();
|
||||
|
@ -2407,13 +2420,13 @@ WSRunScanner::TextFragmentData::GetPreviousEditableCharPoint(
|
|||
HTMLEditUtils::GetPreviousLeafContentOrPreviousBlockElement(
|
||||
*point.ContainerAsContent(),
|
||||
*editableBlockParentOrTopmostEditableInlineContent,
|
||||
mEditingHost);
|
||||
{LeafNodeType::LeafNodeOrNonEditableNode}, mEditingHost);
|
||||
previousContent;
|
||||
previousContent =
|
||||
HTMLEditUtils::GetPreviousLeafContentOrPreviousBlockElement(
|
||||
*previousContent,
|
||||
*editableBlockParentOrTopmostEditableInlineContent,
|
||||
mEditingHost)) {
|
||||
{LeafNodeType::LeafNodeOrNonEditableNode}, mEditingHost)) {
|
||||
if (!previousContent->IsText() || !previousContent->IsEditable()) {
|
||||
if (previousContent == GetStartReasonContent()) {
|
||||
break; // Reached start of current runs.
|
||||
|
|
|
@ -700,3 +700,5 @@
|
|||
[[["delete",""\]\] "foo<div contenteditable=false>bar</div>[\]baz" compare innerHTML]
|
||||
expected: FAIL
|
||||
|
||||
[[["delete",""\]\] "foo<span contenteditable=false>bar</span><span contenteditable=false>baz</span>[\]qux" compare innerHTML]
|
||||
expected: FAIL
|
||||
|
|
|
@ -613,9 +613,6 @@
|
|||
[[["forwarddelete",""\]\] "<div>abc[\] </div>" compare innerHTML]
|
||||
expected: FAIL
|
||||
|
||||
[[["forwarddelete",""\]\] "foo[\]<span contenteditable=false><span>b</span><span>a</span><span>r</span></span>baz": execCommand("forwarddelete", false, "") return value]
|
||||
expected: FAIL
|
||||
|
||||
[[["forwarddelete",""\]\] "foo[\]<span contenteditable=false><span>b</span><span>a</span><span>r</span></span>baz" compare innerHTML]
|
||||
[[["forwarddelete",""\]\] "foo[\]<span contenteditable=false>bar</span><span contenteditable=false>baz</span>qux" compare innerHTML]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -102,6 +102,3 @@
|
|||
[Delete at "<div>abc <ul><li> def[\] </li></ul> ghi</div>"]
|
||||
expected: FAIL
|
||||
|
||||
[Delete at "<p>abc[\]<span contenteditable=\"false\">def</span>ghi</p>"]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -2565,6 +2565,11 @@ var browserTests = [
|
|||
"foo{}baz",
|
||||
[true],
|
||||
{"delete":[false,false,"",false,false,""]}],
|
||||
["foo<span contenteditable=false>bar</span><span contenteditable=false>baz</span>[]qux",
|
||||
[["delete",""]],
|
||||
"foo<span contenteditable=\"false\">bar</span>[]qux",
|
||||
[true],
|
||||
{"delete":[false,false,"",false,false,""]}],
|
||||
["foo<span contenteditable=false><span>b</span><span>a</span><span>r</span></span>[]baz",
|
||||
[["delete",""]],
|
||||
"foo{}baz",
|
||||
|
|
|
@ -2450,6 +2450,11 @@ var browserTests = [
|
|||
"foo{}baz",
|
||||
[true],
|
||||
{"forwarddelete":[false,false,"",false,false,""]}],
|
||||
["foo[]<span contenteditable=false>bar</span><span contenteditable=false>baz</span>qux",
|
||||
[["forwarddelete",""]],
|
||||
"foo[]<span contenteditable=\"false\">baz</span>qux",
|
||||
[true],
|
||||
{"forwarddelete":[false,false,"",false,false,""]}],
|
||||
["foo[]<span contenteditable=false><span>b</span><span>a</span><span>r</span></span>baz",
|
||||
[["forwarddelete",""]],
|
||||
"foo{}baz",
|
||||
|
|
Загрузка…
Ссылка в новой задаче