зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1675779 - HandleDeleteAtomicContent should handle non-editable text node. r=masayuki
Since `WSScanResult` can return non-editable/non-removable text node, `HandleDeleteAtomicContent` is called with non editable text node, then it cannot remove atomic content. This fix doesn't follow other block case such as added newer test. Differential Revision: https://phabricator.services.mozilla.com/D96298
This commit is contained in:
Родитель
93b37bfebb
Коммит
6d173e8282
|
@ -257,6 +257,23 @@ class MOZ_STACK_CLASS HTMLEditor::AutoDeleteRangesHandler final {
|
||||||
const HTMLEditor& aHTMLEditor, const nsIContent& aAtomicContent,
|
const HTMLEditor& aHTMLEditor, const nsIContent& aAtomicContent,
|
||||||
AutoRangeArray& aRangesToDelete) const;
|
AutoRangeArray& aRangesToDelete) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GetAtomicContnetToDelete() returns better content that is deletion of
|
||||||
|
* atomic element. If aScanFromCaretPointResult is special, since this
|
||||||
|
* point may not be editable, we look for better point to remove atomic
|
||||||
|
* content.
|
||||||
|
*
|
||||||
|
* @param aDirectionAndAmount Direction of the deletion.
|
||||||
|
* @param aWSRunScannerAtCaret WSRunScanner instance which was
|
||||||
|
* initialized with the caret point.
|
||||||
|
* @param aScanFromCaretPointResult Scan result of aWSRunScannerAtCaret
|
||||||
|
* toward aDirectionAndAmount.
|
||||||
|
*/
|
||||||
|
static nsIContent* GetAtomicContentToDelete(
|
||||||
|
nsIEditor::EDirection aDirectionAndAmount,
|
||||||
|
const WSRunScanner& aWSRunScannerAtCaret,
|
||||||
|
const WSScanResult& aScanFromCaretPointResult) MOZ_NONNULL_RETURN;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HandleDeleteHRElement() handles deletion around `<hr>` element. If
|
* HandleDeleteHRElement() handles deletion around `<hr>` element. If
|
||||||
* aDirectionAndAmount is nsIEditor::ePrevious, aHTElement is removed only
|
* aDirectionAndAmount is nsIEditor::ePrevious, aHTElement is removed only
|
||||||
|
@ -1637,8 +1654,16 @@ HTMLEditor::AutoDeleteRangesHandler::ComputeRangesToDeleteAroundCollapsedRanges(
|
||||||
aWSRunScannerAtCaret.GetEditingHost()) {
|
aWSRunScannerAtCaret.GetEditingHost()) {
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
nsIContent* atomicContent = GetAtomicContentToDelete(
|
||||||
|
aDirectionAndAmount, aWSRunScannerAtCaret, aScanFromCaretPointResult);
|
||||||
|
if (!HTMLEditUtils::IsRemovableNode(*atomicContent)) {
|
||||||
|
NS_WARNING(
|
||||||
|
"AutoDeleteRangesHandler::GetAtomicContentToDelete() cannot find "
|
||||||
|
"removable atomic content");
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
nsresult rv = ComputeRangesToDeleteAtomicContent(
|
nsresult rv = ComputeRangesToDeleteAtomicContent(
|
||||||
aHTMLEditor, *aScanFromCaretPointResult.GetContent(), aRangesToDelete);
|
aHTMLEditor, *atomicContent, aRangesToDelete);
|
||||||
NS_WARNING_ASSERTION(
|
NS_WARNING_ASSERTION(
|
||||||
NS_SUCCEEDED(rv),
|
NS_SUCCEEDED(rv),
|
||||||
"AutoDeleteRangesHandler::ComputeRangesToDeleteAtomicContent() failed");
|
"AutoDeleteRangesHandler::ComputeRangesToDeleteAtomicContent() failed");
|
||||||
|
@ -1665,6 +1690,10 @@ HTMLEditor::AutoDeleteRangesHandler::ComputeRangesToDeleteAroundCollapsedRanges(
|
||||||
if (NS_WARN_IF(!aScanFromCaretPointResult.GetContent()->IsElement())) {
|
if (NS_WARN_IF(!aScanFromCaretPointResult.GetContent()->IsElement())) {
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
// TODO(m_kato):
|
||||||
|
// When aScanFromCaretPointResult.GetContent isn't editable and is
|
||||||
|
// removable, PrepareToDeleteAtOtherBlockBoundary will return false.
|
||||||
|
// But this should be removed.
|
||||||
AutoBlockElementsJoiner joiner(*this);
|
AutoBlockElementsJoiner joiner(*this);
|
||||||
if (!joiner.PrepareToDeleteAtOtherBlockBoundary(
|
if (!joiner.PrepareToDeleteAtOtherBlockBoundary(
|
||||||
aHTMLEditor, aDirectionAndAmount,
|
aHTMLEditor, aDirectionAndAmount,
|
||||||
|
@ -1764,9 +1793,17 @@ HTMLEditor::AutoDeleteRangesHandler::HandleDeleteAroundCollapsedRanges(
|
||||||
aWSRunScannerAtCaret.GetEditingHost()) {
|
aWSRunScannerAtCaret.GetEditingHost()) {
|
||||||
return EditActionHandled();
|
return EditActionHandled();
|
||||||
}
|
}
|
||||||
|
nsCOMPtr<nsIContent> atomicContent = GetAtomicContentToDelete(
|
||||||
|
aDirectionAndAmount, aWSRunScannerAtCaret, aScanFromCaretPointResult);
|
||||||
|
if (!HTMLEditUtils::IsRemovableNode(*atomicContent)) {
|
||||||
|
NS_WARNING(
|
||||||
|
"AutoDeleteRangesHandler::GetAtomicContentToDelete() cannot find "
|
||||||
|
"removable atomic content");
|
||||||
|
return EditActionResult(NS_ERROR_FAILURE);
|
||||||
|
}
|
||||||
EditActionResult result = HandleDeleteAtomicContent(
|
EditActionResult result = HandleDeleteAtomicContent(
|
||||||
aHTMLEditor, MOZ_KnownLive(*aScanFromCaretPointResult.GetContent()),
|
aHTMLEditor, *atomicContent, aWSRunScannerAtCaret.ScanStartRef(),
|
||||||
aWSRunScannerAtCaret.ScanStartRef(), aWSRunScannerAtCaret);
|
aWSRunScannerAtCaret);
|
||||||
NS_WARNING_ASSERTION(
|
NS_WARNING_ASSERTION(
|
||||||
result.Succeeded(),
|
result.Succeeded(),
|
||||||
"AutoDeleteRangesHandler::HandleDeleteAtomicContent() failed");
|
"AutoDeleteRangesHandler::HandleDeleteAtomicContent() failed");
|
||||||
|
@ -2264,6 +2301,38 @@ EditActionResult HTMLEditor::AutoDeleteRangesHandler::HandleDeleteHRElement(
|
||||||
return EditActionHandled(rv);
|
return EditActionHandled(rv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
nsIContent* HTMLEditor::AutoDeleteRangesHandler::GetAtomicContentToDelete(
|
||||||
|
nsIEditor::EDirection aDirectionAndAmount,
|
||||||
|
const WSRunScanner& aWSRunScannerAtCaret,
|
||||||
|
const WSScanResult& aScanFromCaretPointResult) {
|
||||||
|
MOZ_ASSERT(aScanFromCaretPointResult.GetContent());
|
||||||
|
|
||||||
|
if (!aScanFromCaretPointResult.ReachedSpecialContent()) {
|
||||||
|
return aScanFromCaretPointResult.GetContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!aScanFromCaretPointResult.GetContent()->IsText() ||
|
||||||
|
HTMLEditUtils::IsRemovableNode(*aScanFromCaretPointResult.GetContent())) {
|
||||||
|
return aScanFromCaretPointResult.GetContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
// aScanFromCaretPointResult is non-removable text node.
|
||||||
|
// Since we try removing atomic content, we look for removable node from
|
||||||
|
// scanned point that is non-removable text.
|
||||||
|
nsIContent* removableRoot = aScanFromCaretPointResult.GetContent();
|
||||||
|
while (removableRoot && !HTMLEditUtils::IsRemovableNode(*removableRoot)) {
|
||||||
|
removableRoot = removableRoot->GetParent();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (removableRoot) {
|
||||||
|
return removableRoot;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not found better content. This content may not be removable.
|
||||||
|
return aScanFromCaretPointResult.GetContent();
|
||||||
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
HTMLEditor::AutoDeleteRangesHandler::ComputeRangesToDeleteAtomicContent(
|
HTMLEditor::AutoDeleteRangesHandler::ComputeRangesToDeleteAtomicContent(
|
||||||
const HTMLEditor& aHTMLEditor, const nsIContent& aAtomicContent,
|
const HTMLEditor& aHTMLEditor, const nsIContent& aAtomicContent,
|
||||||
|
|
|
@ -697,3 +697,6 @@
|
||||||
[[["delete",""\]\] "<div> a[\]bc</div>" compare innerHTML]
|
[[["delete",""\]\] "<div> a[\]bc</div>" compare innerHTML]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
[[["delete",""\]\] "foo<div contenteditable=false>bar</div>[\]baz" compare innerHTML]
|
||||||
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -506,8 +506,8 @@
|
||||||
|
|
||||||
|
|
||||||
[forwarddelete.html?6001-last]
|
[forwarddelete.html?6001-last]
|
||||||
max-asserts: 3
|
max-asserts: 6
|
||||||
min-asserts: 3
|
min-asserts: 6
|
||||||
[[["forwarddelete",""\]\] "<ol><li>foo</ol><p>{}<br></p><ol><li>bar</ol>" compare innerHTML]
|
[[["forwarddelete",""\]\] "<ol><li>foo</ol><p>{}<br></p><ol><li>bar</ol>" compare innerHTML]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
|
|
|
@ -300,7 +300,7 @@
|
||||||
|
|
||||||
|
|
||||||
[insertparagraph.html?5001-6000]
|
[insertparagraph.html?5001-6000]
|
||||||
min-asserts: 14 # Retrieving meaningless raw DOM point from WSScannerResult
|
min-asserts: 10 # Retrieving meaningless raw DOM point from WSScannerResult
|
||||||
max-asserts: 16 # Only on W-fis on Linux1804-64-qr and on Android, there are 2 additional assertions.
|
max-asserts: 16 # Only on W-fis on Linux1804-64-qr and on Android, there are 2 additional assertions.
|
||||||
[[["defaultparagraphseparator","p"\],["insertparagraph",""\]\] "<ul><li><div>foo[\]</ul>" compare innerHTML]
|
[[["defaultparagraphseparator","p"\],["insertparagraph",""\]\] "<ul><li><div>foo[\]</ul>" compare innerHTML]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
|
@ -52,6 +52,3 @@
|
||||||
[Backspace at "<div>abc <ul><li>[\] def </li></ul> ghi</div>" - comparing innerHTML]
|
[Backspace at "<div>abc <ul><li>[\] def </li></ul> ghi</div>" - comparing innerHTML]
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
||||||
[Backspace at "<p>abc<span contenteditable=\"false\">def</span>[\]ghi</p>"]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
|
|
|
@ -2560,4 +2560,29 @@ var browserTests = [
|
||||||
"foo{}bar",
|
"foo{}bar",
|
||||||
[true],
|
[true],
|
||||||
{"delete":[false,false,"",false,false,""]}],
|
{"delete":[false,false,"",false,false,""]}],
|
||||||
|
["foo<span contenteditable=false>bar</span>[]baz",
|
||||||
|
[["delete",""]],
|
||||||
|
"foo{}baz",
|
||||||
|
[true],
|
||||||
|
{"delete":[false,false,"",false,false,""]}],
|
||||||
|
["foo<span contenteditable=false><span>b</span><span>a</span><span>r</span></span>[]baz",
|
||||||
|
[["delete",""]],
|
||||||
|
"foo{}baz",
|
||||||
|
[true],
|
||||||
|
{"delete":[false,false,"",false,false,""]}],
|
||||||
|
["foo<div contenteditable=false>bar</div>[]baz",
|
||||||
|
[["delete",""]],
|
||||||
|
"foo{}baz",
|
||||||
|
[true],
|
||||||
|
{"delete":[false,false,"",false,false,""]}],
|
||||||
|
["foo<span contenteditable=false><b>bar</b></span>[]baz",
|
||||||
|
[["delete",""]],
|
||||||
|
"foo{}baz",
|
||||||
|
[true],
|
||||||
|
{"delete":[false,false,"",false,false,""]}],
|
||||||
|
["foo<span>bar<span contenteditable=false>baz</span></span>[]qux",
|
||||||
|
[["delete",""]],
|
||||||
|
"foo<span>bar{}</span>qux",
|
||||||
|
[true],
|
||||||
|
{"delete":[false,false,"",false,false,""]}],
|
||||||
]
|
]
|
||||||
|
|
|
@ -2445,4 +2445,29 @@ var browserTests = [
|
||||||
"foo{}bar",
|
"foo{}bar",
|
||||||
[true],
|
[true],
|
||||||
{"forwarddelete":[false,false,"",false,false,""]}],
|
{"forwarddelete":[false,false,"",false,false,""]}],
|
||||||
|
["foo[]<span contenteditable=false>bar</span>baz",
|
||||||
|
[["forwarddelete",""]],
|
||||||
|
"foo{}baz",
|
||||||
|
[true],
|
||||||
|
{"forwarddelete":[false,false,"",false,false,""]}],
|
||||||
|
["foo[]<span contenteditable=false><span>b</span><span>a</span><span>r</span></span>baz",
|
||||||
|
[["forwarddelete",""]],
|
||||||
|
"foo{}baz",
|
||||||
|
[true],
|
||||||
|
{"forwarddelete":[false,false,"",false,false,""]}],
|
||||||
|
["foo[]<div contenteditable=false>bar</div>baz",
|
||||||
|
[["forwarddelete",""]],
|
||||||
|
"foo{}baz",
|
||||||
|
[true],
|
||||||
|
{"forwarddelete":[false,false,"",false,false,""]}],
|
||||||
|
["foo[]<span contenteditable=false><b>bar</b></span>baz",
|
||||||
|
[["forwarddelete",""]],
|
||||||
|
"foo{}baz",
|
||||||
|
[true],
|
||||||
|
{"forwarddelete":[false,false,"",false,false,""]}],
|
||||||
|
["foo<span>bar[]<span contenteditable=false>baz</span></span>qux",
|
||||||
|
[["forwarddelete",""]],
|
||||||
|
"foo<span>bar{}</span>qux",
|
||||||
|
[true],
|
||||||
|
{"forwarddelete":[false,false,"",false,false,""]}],
|
||||||
]
|
]
|
||||||
|
|
Загрузка…
Ссылка в новой задаче