зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1574852 - part 86: Move `HTMLEditRules::WillAlign()` and `HTMLEditRules::AlignContentsAtSelection()` to `HTMLEditor` r=m_kato
And also this splits large 2 blocks of `HTMLEditRules::AlignContentsAtSelection()` to 2 methods. Differential Revision: https://phabricator.services.mozilla.com/D44790 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
04e8f93b98
Коммит
b1ead5a6f3
|
@ -788,8 +788,6 @@ nsresult HTMLEditRules::WillDoAction(EditSubActionInfo& aInfo, bool* aCancel,
|
|||
return WillAbsolutePosition(aCancel, aHandled);
|
||||
case EditSubAction::eSetPositionToStatic:
|
||||
return WillRemoveAbsolutePosition(aCancel, aHandled);
|
||||
case EditSubAction::eSetOrClearAlignment:
|
||||
return WillAlign(*aInfo.alignType, aCancel, aHandled);
|
||||
case EditSubAction::eInsertElement:
|
||||
case EditSubAction::eInsertQuotedText: {
|
||||
nsresult rv = MOZ_KnownLive(HTMLEditorRef()).WillInsert(aCancel);
|
||||
|
@ -813,6 +811,7 @@ nsresult HTMLEditRules::WillDoAction(EditSubActionInfo& aInfo, bool* aCancel,
|
|||
case EditSubAction::eUndo:
|
||||
case EditSubAction::eRedo:
|
||||
case EditSubAction::eRemoveList:
|
||||
case EditSubAction::eSetOrClearAlignment:
|
||||
MOZ_ASSERT_UNREACHABLE("This path should've been dead code");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
default:
|
||||
|
@ -835,9 +834,6 @@ nsresult HTMLEditRules::DidDoAction(EditSubActionInfo& aInfo,
|
|||
return NS_OK;
|
||||
case EditSubAction::eDeleteSelectedContent:
|
||||
return DidDeleteSelection();
|
||||
case EditSubAction::eSetOrClearAlignment:
|
||||
return MOZ_KnownLive(HTMLEditorRef())
|
||||
.MaybeInsertPaddingBRElementForEmptyLastLineAtSelection();
|
||||
case EditSubAction::eSetPositionToAbsolute: {
|
||||
nsresult rv =
|
||||
MOZ_KnownLive(HTMLEditorRef())
|
||||
|
@ -860,6 +856,7 @@ nsresult HTMLEditRules::DidDoAction(EditSubActionInfo& aInfo,
|
|||
case EditSubAction::eUndo:
|
||||
case EditSubAction::eRedo:
|
||||
case EditSubAction::eRemoveList:
|
||||
case EditSubAction::eSetOrClearAlignment:
|
||||
MOZ_ASSERT_UNREACHABLE("This path should've been dead code");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
default:
|
||||
|
@ -6273,54 +6270,61 @@ bool HTMLEditor::IsEmptyBlockElement(Element& aElement,
|
|||
return NS_SUCCEEDED(rv) && isEmpty;
|
||||
}
|
||||
|
||||
nsresult HTMLEditRules::WillAlign(const nsAString& aAlignType, bool* aCancel,
|
||||
bool* aHandled) {
|
||||
MOZ_ASSERT(IsEditorDataAvailable());
|
||||
MOZ_ASSERT(aCancel && aHandled);
|
||||
EditActionResult HTMLEditor::AlignAsSubAction(const nsAString& aAlignType) {
|
||||
MOZ_ASSERT(IsEditActionDataAvailable());
|
||||
|
||||
*aCancel = false;
|
||||
*aHandled = false;
|
||||
AutoPlaceholderBatch treatAsOneTransaction(*this);
|
||||
AutoEditSubActionNotifier startToHandleEditSubAction(
|
||||
*this, EditSubAction::eSetOrClearAlignment, nsIEditor::eNext);
|
||||
|
||||
EditActionResult result = CanHandleHTMLEditSubAction();
|
||||
if (NS_WARN_IF(result.Failed()) || result.Canceled()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// FYI: Ignore cancel result of WillInsert().
|
||||
nsresult rv = MOZ_KnownLive(HTMLEditorRef()).WillInsert();
|
||||
nsresult rv = WillInsert();
|
||||
if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
return EditActionResult(NS_ERROR_EDITOR_DESTROYED);
|
||||
}
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WillInsert() failed");
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "WillInsert() failed, but ignored");
|
||||
|
||||
if (!SelectionRefPtr()->IsCollapsed()) {
|
||||
nsresult rv = MOZ_KnownLive(HTMLEditorRef())
|
||||
.MaybeExtendSelectionToHardLineEdgesForBlockEditAction();
|
||||
nsresult rv = MaybeExtendSelectionToHardLineEdgesForBlockEditAction();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
return EditActionResult(rv);
|
||||
}
|
||||
}
|
||||
|
||||
*aHandled = true;
|
||||
// AlignContentsAtSelection() creates AutoSelectionRestorer. Therefore,
|
||||
// we need to check whether we've been destroyed or not even if it returns
|
||||
// NS_OK.
|
||||
rv = AlignContentsAtSelection(aAlignType);
|
||||
if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED) ||
|
||||
NS_WARN_IF(!CanHandleEditAction())) {
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
if (NS_WARN_IF(Destroyed())) {
|
||||
return EditActionHandled(NS_ERROR_EDITOR_DESTROYED);
|
||||
}
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
return EditActionHandled(rv);
|
||||
}
|
||||
return NS_OK;
|
||||
|
||||
rv = MaybeInsertPaddingBRElementForEmptyLastLineAtSelection();
|
||||
NS_WARNING_ASSERTION(
|
||||
NS_SUCCEEDED(rv),
|
||||
"MaybeInsertPaddingBRElementForEmptyLastLineAtSelection() failed");
|
||||
return EditActionHandled(rv);
|
||||
}
|
||||
|
||||
nsresult HTMLEditRules::AlignContentsAtSelection(const nsAString& aAlignType) {
|
||||
AutoSelectionRestorer restoreSelectionLater(HTMLEditorRef());
|
||||
nsresult HTMLEditor::AlignContentsAtSelection(const nsAString& aAlignType) {
|
||||
AutoSelectionRestorer restoreSelectionLater(*this);
|
||||
|
||||
// Convert the selection ranges into "promoted" selection ranges: This
|
||||
// basically just expands the range to include the immediate block parent,
|
||||
// and then further expands to include any ancestors whose children are all
|
||||
// in the range
|
||||
AutoTArray<OwningNonNull<nsINode>, 64> nodeArray;
|
||||
nsresult rv =
|
||||
MOZ_KnownLive(HTMLEditorRef())
|
||||
.SplitInlinesAndCollectEditTargetNodesInExtendedSelectionRanges(
|
||||
nsresult rv = SplitInlinesAndCollectEditTargetNodesInExtendedSelectionRanges(
|
||||
nodeArray, EditSubAction::eSetOrClearAlignment,
|
||||
HTMLEditor::CollectNonEditableNodes::Yes);
|
||||
CollectNonEditableNodes::Yes);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -6328,7 +6332,7 @@ nsresult HTMLEditRules::AlignContentsAtSelection(const nsAString& aAlignType) {
|
|||
// If we don't have any nodes, or we have only a single br, then we are
|
||||
// creating an empty alignment div. We have to do some different things for
|
||||
// these.
|
||||
bool emptyDiv = nodeArray.IsEmpty();
|
||||
bool createEmptyDivElement = nodeArray.IsEmpty();
|
||||
if (nodeArray.Length() == 1) {
|
||||
OwningNonNull<nsINode> node = nodeArray[0];
|
||||
|
||||
|
@ -6337,26 +6341,27 @@ nsresult HTMLEditRules::AlignContentsAtSelection(const nsAString& aAlignType) {
|
|||
// header; in HTML 4, it can directly carry the ALIGN attribute and we
|
||||
// don't need to make a div! If we are in CSS mode, all the work is done
|
||||
// in SetBlockElementAlign().
|
||||
nsresult rv = MOZ_KnownLive(HTMLEditorRef())
|
||||
.SetBlockElementAlign(
|
||||
MOZ_KnownLive(*node->AsElement()), aAlignType,
|
||||
HTMLEditor::EditTarget::OnlyDescendantsExceptTable);
|
||||
nsresult rv =
|
||||
SetBlockElementAlign(MOZ_KnownLive(*node->AsElement()), aAlignType,
|
||||
EditTarget::OnlyDescendantsExceptTable);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "SetBlockElementAlign() failed");
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (TextEditUtils::IsBreak(node)) {
|
||||
// The special case emptyDiv code (below) that consumes BRs can cause
|
||||
// tables to split if the start node of the selection is not in a table
|
||||
// cell or caption, for example parent is a <tr>. Avoid this unnecessary
|
||||
// splitting if possible by leaving emptyDiv FALSE so that we fall
|
||||
// through to the normal case alignment code.
|
||||
// The special case createEmptyDivElement code (below) that consumes
|
||||
// `<br>` elements can cause tables to split if the start node of the
|
||||
// selection is not in a table cell or caption, for example parent is a
|
||||
// `<tr>`. Avoid this unnecessary splitting if possible by leaving
|
||||
// createEmptyDivElement false so that we fall through to the normal case
|
||||
// alignment code.
|
||||
//
|
||||
// XXX: It seems a little error prone for the emptyDiv special case code
|
||||
// to assume that the start node of the selection is the parent of the
|
||||
// single node in the nodeArray, as the paragraph above points out. Do we
|
||||
// rely on the selection start node because of the fact that nodeArray
|
||||
// can be empty? We should probably revisit this issue. - kin
|
||||
// XXX: It seems a little error prone for the createEmptyDivElement
|
||||
// special case code to assume that the start node of the selection
|
||||
// is the parent of the single node in the nodeArray, as the
|
||||
// paragraph above points out. Do we rely on the selection start
|
||||
// node because of the fact that nodeArray can be empty? We should
|
||||
// probably revisit this issue. - kin
|
||||
|
||||
nsRange* firstRange = SelectionRefPtr()->GetRangeAt(0);
|
||||
if (NS_WARN_IF(!firstRange)) {
|
||||
|
@ -6367,116 +6372,128 @@ nsresult HTMLEditRules::AlignContentsAtSelection(const nsAString& aAlignType) {
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
nsINode* parent = atStartOfSelection.Container();
|
||||
emptyDiv = !HTMLEditUtils::IsTableElement(parent) ||
|
||||
createEmptyDivElement = !HTMLEditUtils::IsTableElement(parent) ||
|
||||
HTMLEditUtils::IsTableCellOrCaption(*parent);
|
||||
}
|
||||
}
|
||||
if (emptyDiv) {
|
||||
|
||||
if (createEmptyDivElement) {
|
||||
EditActionResult result =
|
||||
AlignContentsAtSelectionWithEmptyDivElement(aAlignType);
|
||||
NS_WARNING_ASSERTION(
|
||||
result.Succeeded(),
|
||||
"AlignContentsAtSelectionWithEmptyDivElement() failed");
|
||||
if (result.Handled()) {
|
||||
restoreSelectionLater.Abort();
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = AlignNodesAndDescendants(nodeArray, aAlignType);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "AlignNodesAndDescendants() failed");
|
||||
return rv;
|
||||
}
|
||||
|
||||
EditActionResult HTMLEditor::AlignContentsAtSelectionWithEmptyDivElement(
|
||||
const nsAString& aAlignType) {
|
||||
MOZ_ASSERT(IsTopLevelEditSubActionDataAvailable());
|
||||
|
||||
nsRange* firstRange = SelectionRefPtr()->GetRangeAt(0);
|
||||
if (NS_WARN_IF(!firstRange)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
return EditActionResult(NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
EditorDOMPoint atStartOfSelection(firstRange->StartRef());
|
||||
if (NS_WARN_IF(!atStartOfSelection.IsSet())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
return EditActionResult(NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
SplitNodeResult splitNodeResult =
|
||||
MOZ_KnownLive(HTMLEditorRef())
|
||||
.MaybeSplitAncestorsForInsertWithTransaction(*nsGkAtoms::div,
|
||||
atStartOfSelection);
|
||||
SplitNodeResult splitNodeResult = MaybeSplitAncestorsForInsertWithTransaction(
|
||||
*nsGkAtoms::div, atStartOfSelection);
|
||||
if (NS_WARN_IF(splitNodeResult.Failed())) {
|
||||
return splitNodeResult.Rv();
|
||||
return EditActionResult(splitNodeResult.Rv());
|
||||
}
|
||||
|
||||
EditorDOMPoint pointToInsertDiv(splitNodeResult.SplitPoint());
|
||||
|
||||
// Consume a trailing br, if any. This is to keep an alignment from
|
||||
// creating extra lines, if possible.
|
||||
nsCOMPtr<nsIContent> brContent =
|
||||
HTMLEditorRef().GetNextEditableHTMLNodeInBlock(
|
||||
splitNodeResult.SplitPoint());
|
||||
EditorDOMPoint pointToInsertDiv(splitNodeResult.SplitPoint());
|
||||
if (brContent && TextEditUtils::IsBreak(brContent)) {
|
||||
if (nsCOMPtr<nsIContent> maybeBRContent =
|
||||
GetNextEditableHTMLNodeInBlock(splitNodeResult.SplitPoint())) {
|
||||
if (TextEditUtils::IsBreak(maybeBRContent) && pointToInsertDiv.GetChild()) {
|
||||
// Making use of html structure... if next node after where we are
|
||||
// putting our div is not a block, then the br we found is in same block
|
||||
// we are, so it's safe to consume it.
|
||||
nsCOMPtr<nsIContent> sibling;
|
||||
if (pointToInsertDiv.GetChild()) {
|
||||
sibling =
|
||||
HTMLEditorRef().GetNextHTMLSibling(pointToInsertDiv.GetChild());
|
||||
}
|
||||
if (sibling && !HTMLEditor::NodeIsBlockStatic(*sibling)) {
|
||||
if (nsIContent* nextEditableSibling =
|
||||
GetNextHTMLSibling(pointToInsertDiv.GetChild())) {
|
||||
if (!HTMLEditor::NodeIsBlockStatic(*nextEditableSibling)) {
|
||||
AutoEditorDOMPointChildInvalidator lockOffset(pointToInsertDiv);
|
||||
rv = MOZ_KnownLive(HTMLEditorRef())
|
||||
.DeleteNodeWithTransaction(*brContent);
|
||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
nsresult rv = DeleteNodeWithTransaction(*maybeBRContent);
|
||||
if (NS_WARN_IF(Destroyed())) {
|
||||
return EditActionResult(NS_ERROR_EDITOR_DESTROYED);
|
||||
}
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
return EditActionResult(rv);
|
||||
}
|
||||
}
|
||||
}
|
||||
RefPtr<Element> div =
|
||||
MOZ_KnownLive(HTMLEditorRef())
|
||||
.CreateNodeWithTransaction(*nsGkAtoms::div, pointToInsertDiv);
|
||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
}
|
||||
if (NS_WARN_IF(!div)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
RefPtr<Element> divElement =
|
||||
CreateNodeWithTransaction(*nsGkAtoms::div, pointToInsertDiv);
|
||||
if (NS_WARN_IF(Destroyed())) {
|
||||
return EditActionResult(NS_ERROR_EDITOR_DESTROYED);
|
||||
}
|
||||
if (NS_WARN_IF(!divElement)) {
|
||||
return EditActionResult(NS_ERROR_FAILURE);
|
||||
}
|
||||
// Remember our new block for postprocessing
|
||||
HTMLEditorRef().TopLevelEditSubActionDataRef().mNewBlockElement = div;
|
||||
TopLevelEditSubActionDataRef().mNewBlockElement = divElement;
|
||||
// Set up the alignment on the div, using HTML or CSS
|
||||
rv = MOZ_KnownLive(HTMLEditorRef())
|
||||
.SetBlockElementAlign(
|
||||
*div, aAlignType,
|
||||
HTMLEditor::EditTarget::OnlyDescendantsExceptTable);
|
||||
nsresult rv = SetBlockElementAlign(*divElement, aAlignType,
|
||||
EditTarget::OnlyDescendantsExceptTable);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
return EditActionResult(rv);
|
||||
}
|
||||
// Put in a padding <br> element for empty last line so that it won't get
|
||||
// deleted.
|
||||
CreateElementResult createPaddingBRResult =
|
||||
MOZ_KnownLive(HTMLEditorRef())
|
||||
.InsertPaddingBRElementForEmptyLastLineWithTransaction(
|
||||
EditorDOMPoint(div, 0));
|
||||
InsertPaddingBRElementForEmptyLastLineWithTransaction(
|
||||
EditorDOMPoint(divElement, 0));
|
||||
if (NS_WARN_IF(createPaddingBRResult.Failed())) {
|
||||
return createPaddingBRResult.Rv();
|
||||
return EditActionResult(createPaddingBRResult.Rv());
|
||||
}
|
||||
EditorRawDOMPoint atStartOfDiv(div, 0);
|
||||
// Don't restore the selection
|
||||
restoreSelectionLater.Abort();
|
||||
EditorRawDOMPoint atStartOfDiv(divElement, 0);
|
||||
ErrorResult error;
|
||||
SelectionRefPtr()->Collapse(atStartOfDiv, error);
|
||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||
if (NS_WARN_IF(Destroyed())) {
|
||||
error.SuppressException();
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
}
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.StealNSResult();
|
||||
}
|
||||
return NS_OK;
|
||||
return EditActionHandled(NS_ERROR_EDITOR_DESTROYED);
|
||||
}
|
||||
NS_WARNING_ASSERTION(!error.Failed(), "Selection::Collapse() failed");
|
||||
return EditActionHandled(error.StealNSResult());
|
||||
}
|
||||
|
||||
// Next we detect all the transitions in the array, where a transition
|
||||
// means that adjacent nodes in the array don't have the same parent.
|
||||
|
||||
nsresult HTMLEditor::AlignNodesAndDescendants(
|
||||
nsTArray<OwningNonNull<nsINode>>& aArrayOfNodes,
|
||||
const nsAString& aAlignType) {
|
||||
// Detect all the transitions in the array, where a transition means that
|
||||
// adjacent nodes in the array don't have the same parent.
|
||||
AutoTArray<bool, 64> transitionList;
|
||||
HTMLEditor::MakeTransitionList(nodeArray, transitionList);
|
||||
HTMLEditor::MakeTransitionList(aArrayOfNodes, transitionList);
|
||||
|
||||
// Okay, now go through all the nodes and give them an align attrib or put
|
||||
// them in a div, or whatever is appropriate. Woohoo!
|
||||
|
||||
nsCOMPtr<Element> curDiv;
|
||||
bool useCSS = HTMLEditorRef().IsCSSEnabled();
|
||||
RefPtr<Element> createdDivElement;
|
||||
bool useCSS = IsCSSEnabled();
|
||||
int32_t indexOfTransitionList = -1;
|
||||
for (OwningNonNull<nsINode>& curNode : nodeArray) {
|
||||
for (OwningNonNull<nsINode>& curNode : aArrayOfNodes) {
|
||||
++indexOfTransitionList;
|
||||
|
||||
// Ignore all non-editable nodes. Leave them be.
|
||||
if (!HTMLEditorRef().IsEditable(curNode)) {
|
||||
if (!IsEditable(curNode)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -6486,15 +6503,14 @@ nsresult HTMLEditRules::AlignContentsAtSelection(const nsAString& aAlignType) {
|
|||
// corresponding CSS styles in SetBlockElementAlign().
|
||||
if (HTMLEditUtils::SupportsAlignAttr(*curNode)) {
|
||||
nsresult rv =
|
||||
MOZ_KnownLive(HTMLEditorRef())
|
||||
.SetBlockElementAlign(
|
||||
MOZ_KnownLive(*curNode->AsElement()), aAlignType,
|
||||
HTMLEditor::EditTarget::NodeAndDescendantsExceptTable);
|
||||
SetBlockElementAlign(MOZ_KnownLive(*curNode->AsElement()), aAlignType,
|
||||
EditTarget::NodeAndDescendantsExceptTable);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
// Clear out curDiv so that we don't put nodes after this one into it
|
||||
curDiv = nullptr;
|
||||
// Clear out createdDivElement so that we don't put nodes after this one
|
||||
// into it
|
||||
createdDivElement = nullptr;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -6506,12 +6522,11 @@ nsresult HTMLEditRules::AlignContentsAtSelection(const nsAString& aAlignType) {
|
|||
// Skip insignificant formatting text nodes to prevent unnecessary
|
||||
// structure splitting!
|
||||
bool isEmptyTextNode = false;
|
||||
if (curNode->GetAsText() &&
|
||||
if (curNode->IsText() &&
|
||||
((HTMLEditUtils::IsTableElement(atCurNode.GetContainer()) &&
|
||||
!HTMLEditUtils::IsTableCellOrCaption(*atCurNode.GetContainer())) ||
|
||||
HTMLEditUtils::IsList(atCurNode.GetContainer()) ||
|
||||
(NS_SUCCEEDED(
|
||||
HTMLEditorRef().IsEmptyNode(curNode, &isEmptyTextNode)) &&
|
||||
(NS_SUCCEEDED(IsEmptyNode(curNode, &isEmptyTextNode)) &&
|
||||
isEmptyTextNode))) {
|
||||
continue;
|
||||
}
|
||||
|
@ -6521,74 +6536,73 @@ nsresult HTMLEditRules::AlignContentsAtSelection(const nsAString& aAlignType) {
|
|||
if (HTMLEditUtils::IsListItem(curNode) || HTMLEditUtils::IsList(curNode)) {
|
||||
Element* listOrListItemElement = curNode->AsElement();
|
||||
AutoEditorDOMPointOffsetInvalidator lockChild(atCurNode);
|
||||
rv = MOZ_KnownLive(HTMLEditorRef())
|
||||
.RemoveAlignFromDescendants(
|
||||
nsresult rv = RemoveAlignFromDescendants(
|
||||
MOZ_KnownLive(*listOrListItemElement), aAlignType,
|
||||
HTMLEditor::EditTarget::OnlyDescendantsExceptTable);
|
||||
EditTarget::OnlyDescendantsExceptTable);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (useCSS) {
|
||||
HTMLEditorRef().mCSSEditUtils->SetCSSEquivalentToHTMLStyle(
|
||||
mCSSEditUtils->SetCSSEquivalentToHTMLStyle(
|
||||
MOZ_KnownLive(listOrListItemElement), nullptr, nsGkAtoms::align,
|
||||
&aAlignType, false);
|
||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||
if (NS_WARN_IF(Destroyed())) {
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
}
|
||||
curDiv = nullptr;
|
||||
createdDivElement = nullptr;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (HTMLEditUtils::IsList(atCurNode.GetContainer())) {
|
||||
// If we don't use CSS, add a content to list element: they have to
|
||||
// be inside another list, i.e., >= second level of nesting.
|
||||
// XXX AlignContentsInAllTableCellsAndListItems() handles only list
|
||||
// item elements and table cells. Is it intentional? Why don't
|
||||
// we need to align contents in other type blocks?
|
||||
rv = MOZ_KnownLive(HTMLEditorRef())
|
||||
.AlignContentsInAllTableCellsAndListItems(
|
||||
nsresult rv = AlignContentsInAllTableCellsAndListItems(
|
||||
MOZ_KnownLive(*listOrListItemElement), aAlignType);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
curDiv = nullptr;
|
||||
createdDivElement = nullptr;
|
||||
continue;
|
||||
}
|
||||
// Clear out curDiv so that we don't put nodes after this one into it
|
||||
|
||||
// Clear out createdDivElement so that we don't put nodes after this one
|
||||
// into it
|
||||
}
|
||||
|
||||
// Need to make a div to put things in if we haven't already, or if this
|
||||
// node doesn't go in div we used earlier.
|
||||
if (!curDiv || transitionList[indexOfTransitionList]) {
|
||||
if (!createdDivElement || transitionList[indexOfTransitionList]) {
|
||||
// First, check that our element can contain a div.
|
||||
if (!HTMLEditorRef().CanContainTag(*atCurNode.GetContainer(),
|
||||
*nsGkAtoms::div)) {
|
||||
// Cancelled
|
||||
if (!CanContainTag(*atCurNode.GetContainer(), *nsGkAtoms::div)) {
|
||||
// XXX Why do we return NS_OK here rather than returning error or
|
||||
// doing continue?
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
SplitNodeResult splitNodeResult =
|
||||
MOZ_KnownLive(HTMLEditorRef())
|
||||
.MaybeSplitAncestorsForInsertWithTransaction(*nsGkAtoms::div,
|
||||
MaybeSplitAncestorsForInsertWithTransaction(*nsGkAtoms::div,
|
||||
atCurNode);
|
||||
if (NS_WARN_IF(splitNodeResult.Failed())) {
|
||||
return splitNodeResult.Rv();
|
||||
}
|
||||
curDiv = MOZ_KnownLive(HTMLEditorRef())
|
||||
.CreateNodeWithTransaction(*nsGkAtoms::div,
|
||||
splitNodeResult.SplitPoint());
|
||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||
createdDivElement = CreateNodeWithTransaction(
|
||||
*nsGkAtoms::div, splitNodeResult.SplitPoint());
|
||||
if (NS_WARN_IF(Destroyed())) {
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
}
|
||||
if (NS_WARN_IF(!curDiv)) {
|
||||
if (NS_WARN_IF(!createdDivElement)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
// Remember our new block for postprocessing
|
||||
HTMLEditorRef().TopLevelEditSubActionDataRef().mNewBlockElement = curDiv;
|
||||
TopLevelEditSubActionDataRef().mNewBlockElement = createdDivElement;
|
||||
// Set up the alignment on the div
|
||||
rv = MOZ_KnownLive(HTMLEditorRef())
|
||||
.SetBlockElementAlign(
|
||||
*curDiv, aAlignType,
|
||||
HTMLEditor::EditTarget::OnlyDescendantsExceptTable);
|
||||
nsresult rv =
|
||||
SetBlockElementAlign(*createdDivElement, aAlignType,
|
||||
EditTarget::OnlyDescendantsExceptTable);
|
||||
if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
}
|
||||
|
@ -6597,10 +6611,9 @@ nsresult HTMLEditRules::AlignContentsAtSelection(const nsAString& aAlignType) {
|
|||
}
|
||||
|
||||
// Tuck the node into the end of the active div
|
||||
rv = MOZ_KnownLive(HTMLEditorRef())
|
||||
.MoveNodeToEndWithTransaction(MOZ_KnownLive(*curNode->AsContent()),
|
||||
*curDiv);
|
||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||
nsresult rv = MoveNodeToEndWithTransaction(
|
||||
MOZ_KnownLive(*curNode->AsContent()), *createdDivElement);
|
||||
if (NS_WARN_IF(Destroyed())) {
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
}
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
|
|
|
@ -113,19 +113,6 @@ class HTMLEditRules : public TextEditRules {
|
|||
*/
|
||||
MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE nsresult DidDeleteSelection();
|
||||
|
||||
/**
|
||||
* Called before aligning contents around Selection. This method actually
|
||||
* sets align attributes to align contents.
|
||||
*
|
||||
* @param aAlignType New align attribute value where the contents
|
||||
* should be aligned to.
|
||||
* @param aCancel Returns true if the operation is canceled.
|
||||
* @param aHandled Returns true if the edit action is handled.
|
||||
*/
|
||||
MOZ_CAN_RUN_SCRIPT
|
||||
nsresult WillAlign(const nsAString& aAlignType, bool* aCancel,
|
||||
bool* aHandled);
|
||||
|
||||
/**
|
||||
* Called before changing absolute positioned element to static positioned.
|
||||
* This method actually changes the position property of nearest absolute
|
||||
|
@ -191,20 +178,6 @@ class HTMLEditRules : public TextEditRules {
|
|||
MOZ_CAN_RUN_SCRIPT
|
||||
MOZ_MUST_USE nsresult DidAbsolutePosition();
|
||||
|
||||
/**
|
||||
* AlignContentsAtSelection() aligns contents around Selection to aAlignType.
|
||||
* This creates AutoSelectionRestorer. Therefore, even if this returns
|
||||
* NS_OK, CanHandleEditAction() may return false if the editor is destroyed
|
||||
* during restoring the Selection. So, every caller needs to check if
|
||||
* CanHandleEditAction() returns true before modifying the DOM tree or
|
||||
* changing Selection.
|
||||
*
|
||||
* @param aAlignType New align attribute value where the contents
|
||||
* should be aligned to.
|
||||
*/
|
||||
MOZ_CAN_RUN_SCRIPT
|
||||
MOZ_MUST_USE nsresult AlignContentsAtSelection(const nsAString& aAlignType);
|
||||
|
||||
nsresult AppendInnerFormatNodes(nsTArray<OwningNonNull<nsINode>>& aArray,
|
||||
nsINode* aNode);
|
||||
nsresult GetFormatString(nsINode* aNode, nsAString& outFormat);
|
||||
|
|
|
@ -2205,28 +2205,9 @@ nsresult HTMLEditor::AlignAsAction(const nsAString& aAlignType,
|
|||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
// Protect the edit rules object from dying
|
||||
RefPtr<TextEditRules> rules(mRules);
|
||||
|
||||
AutoPlaceholderBatch treatAsOneTransaction(*this);
|
||||
AutoEditSubActionNotifier startToHandleEditSubAction(
|
||||
*this, EditSubAction::eSetOrClearAlignment, nsIEditor::eNext);
|
||||
|
||||
bool cancel, handled;
|
||||
|
||||
// Find out if the selection is collapsed:
|
||||
EditSubActionInfo subActionInfo(EditSubAction::eSetOrClearAlignment);
|
||||
subActionInfo.alignType = &aAlignType;
|
||||
nsresult rv = rules->WillDoAction(subActionInfo, &cancel, &handled);
|
||||
if (cancel || NS_FAILED(rv)) {
|
||||
return EditorBase::ToGenericNSResult(rv);
|
||||
}
|
||||
|
||||
rv = rules->DidDoAction(subActionInfo, rv);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return EditorBase::ToGenericNSResult(rv);
|
||||
}
|
||||
return NS_OK;
|
||||
EditActionResult result = AlignAsSubAction(aAlignType);
|
||||
NS_WARNING_ASSERTION(result.Succeeded(), "AlignAsSubAction() failed");
|
||||
return EditorBase::ToGenericNSResult(result.Rv());
|
||||
}
|
||||
|
||||
Element* HTMLEditor::GetElementOrParentByTagName(const nsAtom& aTagName,
|
||||
|
|
|
@ -259,7 +259,7 @@ class HTMLEditor final : public TextEditor,
|
|||
MOZ_CAN_RUN_SCRIPT nsresult SetParagraphFormatAsAction(
|
||||
const nsAString& aParagraphFormat, nsIPrincipal* aPrincipal = nullptr);
|
||||
|
||||
nsresult AlignAsAction(const nsAString& aAlignType,
|
||||
MOZ_CAN_RUN_SCRIPT nsresult AlignAsAction(const nsAString& aAlignType,
|
||||
nsIPrincipal* aPrincipal = nullptr);
|
||||
|
||||
MOZ_CAN_RUN_SCRIPT nsresult RemoveListAsAction(
|
||||
|
@ -2523,6 +2523,52 @@ class HTMLEditor final : public TextEditor,
|
|||
SetBlockElementAlign(Element& aBlockOrHRElement, const nsAString& aAlignType,
|
||||
EditTarget aEditTarget);
|
||||
|
||||
/**
|
||||
* AlignContentsAtSelectionWithEmptyDivElement() inserts new `<div>` element
|
||||
* at `Selection` to align selected contents. This returns as "handled"
|
||||
* if this modifies `Selection` so that callers shouldn't modify `Selection`
|
||||
* in such case especially when using AutoSelectionRestorer.
|
||||
*
|
||||
* @param aAlignType New align attribute value where the contents
|
||||
* should be aligned to.
|
||||
*/
|
||||
MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE EditActionResult
|
||||
AlignContentsAtSelectionWithEmptyDivElement(const nsAString& aAlignType);
|
||||
|
||||
/**
|
||||
* AlignNodesAndDescendants() make contents of nodes in aArrayOfNodes and
|
||||
* their descendants aligned to aAlignType.
|
||||
*
|
||||
* @param aAlignType New align attribute value where the contents
|
||||
* should be aligned to.
|
||||
*/
|
||||
MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE nsresult
|
||||
AlignNodesAndDescendants(nsTArray<OwningNonNull<nsINode>>& aArrayOfNodes,
|
||||
const nsAString& aAlignType);
|
||||
|
||||
/**
|
||||
* AlignContentsAtSelection() aligns contents around Selection to aAlignType.
|
||||
* This creates AutoSelectionRestorer. Therefore, even if this returns
|
||||
* NS_OK, we might have been destroyed. So, every caller needs to check if
|
||||
* Destroyed() returns false before modifying the DOM tree or changing
|
||||
* Selection.
|
||||
* NOTE: Call AlignAsSubAction() instead.
|
||||
*
|
||||
* @param aAlignType New align attribute value where the contents
|
||||
* should be aligned to.
|
||||
*/
|
||||
MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE nsresult
|
||||
AlignContentsAtSelection(const nsAString& aAlignType);
|
||||
|
||||
/**
|
||||
* AlignAsSubAction() handles "align" command with `Selection`.
|
||||
*
|
||||
* @param aAlignType New align attribute value where the contents
|
||||
* should be aligned to.
|
||||
*/
|
||||
MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE EditActionResult
|
||||
AlignAsSubAction(const nsAString& aAlignType);
|
||||
|
||||
protected: // Called by helper classes.
|
||||
virtual void OnStartToHandleTopLevelEditSubAction(
|
||||
EditSubAction aEditSubAction, nsIEditor::EDirection aDirection) override;
|
||||
|
|
|
@ -307,6 +307,7 @@ interface nsIHTMLEditor : nsISupports
|
|||
* Document me!
|
||||
*
|
||||
*/
|
||||
[can_run_script]
|
||||
void align(in AString aAlign);
|
||||
|
||||
/**
|
||||
|
|
Загрузка…
Ссылка в новой задаче