Bug 1657270 - part 3: Split <br> element insertion part for empty list element off from AutoEmptyBlockAncestorDeleter::Run() r=m_kato

Differential Revision: https://phabricator.services.mozilla.com/D85997
This commit is contained in:
Masayuki Nakano 2020-08-11 04:35:05 +00:00
parent d76fe99f0d
commit 087c7979ab
2 changed files with 70 additions and 42 deletions

View File

@ -7901,50 +7901,68 @@ HTMLEditor::AutoEmptyBlockAncestorDeleter::ScanEmptyBlockInclusiveAncestor(
return mEmptyInclusiveAncestorBlockElement;
}
Result<RefPtr<Element>, nsresult> HTMLEditor::AutoEmptyBlockAncestorDeleter::
MaybeInsertBRElementBeforeEmptyListItemElement(HTMLEditor& aHTMLEditor) {
MOZ_ASSERT(mEmptyInclusiveAncestorBlockElement);
MOZ_ASSERT(mEmptyInclusiveAncestorBlockElement->GetParentElement());
MOZ_ASSERT(HTMLEditUtils::IsListItem(mEmptyInclusiveAncestorBlockElement));
// If the found empty block is a list item element and its grand parent
// (i.e., parent of list element) is NOT a list element, insert <br>
// element before the list element which has the empty list item.
// This odd list structure may occur if `Document.execCommand("indent")`
// is performed for list items.
// XXX Chrome does not remove empty list elements when last content in
// last list item is deleted. We should follow it since current
// behavior is annoying when you type new list item with selecting
// all list items.
if (!aHTMLEditor.IsFirstEditableChild(mEmptyInclusiveAncestorBlockElement)) {
return RefPtr<Element>();
}
EditorDOMPoint atParentOfEmptyListItem(
mEmptyInclusiveAncestorBlockElement->GetParentElement());
if (NS_WARN_IF(!atParentOfEmptyListItem.IsSet())) {
return Err(NS_ERROR_FAILURE);
}
if (HTMLEditUtils::IsAnyListElement(atParentOfEmptyListItem.GetContainer())) {
return RefPtr<Element>();
}
RefPtr<Element> brElement =
aHTMLEditor.InsertBRElementWithTransaction(atParentOfEmptyListItem);
if (NS_WARN_IF(aHTMLEditor.Destroyed())) {
return Err(NS_ERROR_EDITOR_DESTROYED);
}
if (!brElement) {
NS_WARNING("HTMLEditor::InsertBRElementWithTransaction() failed");
return Err(NS_ERROR_FAILURE);
}
return brElement;
}
EditActionResult HTMLEditor::AutoEmptyBlockAncestorDeleter::Run(
HTMLEditor& aHTMLEditor, nsIEditor::EDirection aDirectionAndAmount) {
MOZ_ASSERT(mEmptyInclusiveAncestorBlockElement);
MOZ_ASSERT(mEmptyInclusiveAncestorBlockElement->GetParentElement());
MOZ_ASSERT(aHTMLEditor.IsEditActionDataAvailable());
RefPtr<Element> parentOfEmptyBlockElement =
mEmptyInclusiveAncestorBlockElement->GetParentElement();
if (HTMLEditUtils::IsListItem(mEmptyInclusiveAncestorBlockElement)) {
// If the found empty block is a list item element and its grand parent
// (i.e., parent of list element) is NOT a list element, insert <br>
// element before the list element which has the empty list item.
// This odd list structure may occur if `Document.execCommand("indent")`
// is performed for list items.
// XXX Chrome does not remove empty list elements when last content in
// last list item is deleted. We should follow it since current
// behavior is annoying when you type new list item with selecting
// all list items.
if (aHTMLEditor.IsFirstEditableChild(mEmptyInclusiveAncestorBlockElement)) {
EditorDOMPoint atParentOfEmptyBlock(parentOfEmptyBlockElement);
if (NS_WARN_IF(!atParentOfEmptyBlock.IsSet())) {
return EditActionResult(NS_ERROR_FAILURE);
}
// If the grand parent IS a list element, we'll adjust Selection in
// OnEndHandlingEditSubAction().
if (!HTMLEditUtils::IsAnyListElement(
atParentOfEmptyBlock.GetContainer())) {
RefPtr<Element> brElement =
aHTMLEditor.InsertBRElementWithTransaction(atParentOfEmptyBlock);
if (NS_WARN_IF(aHTMLEditor.Destroyed())) {
return EditActionResult(NS_ERROR_EDITOR_DESTROYED);
}
if (!brElement) {
NS_WARNING("HTMLEditor::InsertBRElementWithTransaction() failed");
return EditActionResult(NS_ERROR_FAILURE);
}
nsresult rv =
aHTMLEditor.CollapseSelectionTo(EditorRawDOMPoint(brElement));
if (NS_FAILED(rv)) {
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
"HTMLEditor::CollapseSelectionTo() failed");
return EditActionResult(rv);
}
Result<RefPtr<Element>, nsresult> result =
MaybeInsertBRElementBeforeEmptyListItemElement(aHTMLEditor);
if (result.isErr()) {
NS_WARNING(
"AutoEmptyBlockAncestorDeleter::"
"MaybeInsertBRElementBeforeEmptyListItemElement() failed");
return EditActionResult(result.inspectErr());
}
// If a `<br>` element is inserted, caret should be moved to after it.
if (RefPtr<Element> brElement = result.unwrap()) {
nsresult rv =
aHTMLEditor.CollapseSelectionTo(EditorRawDOMPoint(brElement));
if (NS_FAILED(rv)) {
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
"HTMLEditor::CollapseSelectionTo() failed");
return EditActionResult(rv);
}
}
} else {

View File

@ -2675,11 +2675,12 @@ class HTMLEditor final : public TextEditor,
/**
* Deletes found empty block element by `ScanEmptyBlockInclusiveAncestor()`.
* If found one is a list item element, inserts a <br> element before its
* parent element if grand parent is a list element. Then, collapse
* Selection to after the empty block. If found empty ancestor is not a
* list item element, collapse Selection to somewhere depending on aAction.
* Finally, removes the empty block ancestor.
* If found one is a list item element, calls
* `MaybeInsertBRElementBeforeEmptyListItemElement()` before deleting
* the list item element.
* If found empty ancestor is not a list item element, collapse Selection
* to somewhere depending on aDirectionAndAmount. Finally, removes the
* empty block ancestor.
*
* @param aHTMLEditor The HTMLEditor.
* @param aDirectionAndAmount If found empty ancestor block is a list item
@ -2697,6 +2698,15 @@ class HTMLEditor final : public TextEditor,
Run(HTMLEditor& aHTMLEditor, nsIEditor::EDirection aDirectionAndAmount);
private:
/**
* MaybeInsertBRElementBeforeEmptyListItemElement() inserts a `<br>` element
* if `mEmptyInclusiveAncestorBlockElement` is a list item element which
* is first editable element in its parent, and its grand parent is not a
* list element, inserts a `<br>` element before the empty list item.
*/
[[nodiscard]] MOZ_CAN_RUN_SCRIPT Result<RefPtr<Element>, nsresult>
MaybeInsertBRElementBeforeEmptyListItemElement(HTMLEditor& aHTMLEditor);
RefPtr<Element> mEmptyInclusiveAncestorBlockElement;
};