mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 19:04:45 +00:00
Bug 1656430 - part 3: Create EditorBase::DeleteRangesWithTransaction()
r=m_kato
This patch makes `EditorBase::DeleteSelectionWithTransaction()` a wrapper of `EditorBase::DeleteRangesWithTransaction()`. Differential Revision: https://phabricator.services.mozilla.com/D85686
This commit is contained in:
parent
65db771e7f
commit
e12a28bb16
@ -3344,12 +3344,13 @@ void EditorBase::DoAfterRedoTransaction() {
|
||||
|
||||
already_AddRefed<EditAggregateTransaction>
|
||||
EditorBase::CreateTransactionForDeleteSelection(
|
||||
HowToHandleCollapsedRange aHowToHandleCollapsedRange) {
|
||||
HowToHandleCollapsedRange aHowToHandleCollapsedRange,
|
||||
const AutoRangeArray& aRangesToDelete) {
|
||||
MOZ_ASSERT(IsEditActionDataAvailable());
|
||||
MOZ_ASSERT(SelectionRefPtr()->RangeCount());
|
||||
MOZ_ASSERT(!aRangesToDelete.Ranges().IsEmpty());
|
||||
|
||||
// Check whether the selection is collapsed and we should do nothing:
|
||||
if (NS_WARN_IF(SelectionRefPtr()->IsCollapsed() &&
|
||||
if (NS_WARN_IF(aRangesToDelete.IsCollapsed() &&
|
||||
aHowToHandleCollapsedRange ==
|
||||
HowToHandleCollapsedRange::Ignore)) {
|
||||
return nullptr;
|
||||
@ -3358,18 +3359,12 @@ EditorBase::CreateTransactionForDeleteSelection(
|
||||
// allocate the out-param transaction
|
||||
RefPtr<EditAggregateTransaction> aggregateTransaction =
|
||||
EditAggregateTransaction::Create();
|
||||
for (uint32_t rangeIdx = 0; rangeIdx < SelectionRefPtr()->RangeCount();
|
||||
++rangeIdx) {
|
||||
const nsRange* range = SelectionRefPtr()->GetRangeAt(rangeIdx);
|
||||
if (NS_WARN_IF(!range)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
for (const OwningNonNull<nsRange>& range : aRangesToDelete.Ranges()) {
|
||||
// Same with range as with selection; if it is collapsed and action
|
||||
// is eNone, do nothing.
|
||||
if (!range->Collapsed()) {
|
||||
RefPtr<DeleteRangeTransaction> deleteRangeTransaction =
|
||||
DeleteRangeTransaction::Create(*this, *range);
|
||||
DeleteRangeTransaction::Create(*this, range);
|
||||
// XXX Oh, not checking if deleteRangeTransaction can modify the range...
|
||||
DebugOnly<nsresult> rvIgnored =
|
||||
aggregateTransaction->AppendChild(deleteRangeTransaction);
|
||||
@ -3385,7 +3380,7 @@ EditorBase::CreateTransactionForDeleteSelection(
|
||||
|
||||
// Let's extend the collapsed range to delete content around it.
|
||||
RefPtr<EditTransactionBase> deleteNodeOrTextTransaction =
|
||||
CreateTransactionForCollapsedRange(*range, aHowToHandleCollapsedRange);
|
||||
CreateTransactionForCollapsedRange(range, aHowToHandleCollapsedRange);
|
||||
// XXX When there are two or more ranges and at least one of them is
|
||||
// not editable, deleteNodeOrTextTransaction may be nullptr.
|
||||
// In such case, should we stop removing other ranges too?
|
||||
@ -3948,15 +3943,38 @@ nsresult EditorBase::DeleteSelectionWithTransaction(
|
||||
nsIEditor::EStripWrappers aStripWrappers) {
|
||||
MOZ_ASSERT(IsEditActionDataAvailable());
|
||||
MOZ_ASSERT(aStripWrappers == eStrip || aStripWrappers == eNoStrip);
|
||||
|
||||
if (NS_WARN_IF(Destroyed())) {
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
}
|
||||
|
||||
AutoRangeArray rangesToDelete(*SelectionRefPtr());
|
||||
if (NS_WARN_IF(rangesToDelete.Ranges().IsEmpty())) {
|
||||
NS_ASSERTION(
|
||||
false,
|
||||
"For avoiding to throw incompatible exception for `execCommand`, fix "
|
||||
"the caller");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsresult rv = DeleteRangesWithTransaction(aDirectionAndAmount, aStripWrappers,
|
||||
rangesToDelete);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"EditorBase::DeleteRangesWithTransaction() failed");
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult EditorBase::DeleteRangesWithTransaction(
|
||||
nsIEditor::EDirection aDirectionAndAmount,
|
||||
nsIEditor::EStripWrappers aStripWrappers,
|
||||
const AutoRangeArray& aRangesToDelete) {
|
||||
MOZ_ASSERT(IsEditActionDataAvailable());
|
||||
MOZ_ASSERT(!Destroyed());
|
||||
MOZ_ASSERT(aStripWrappers == eStrip || aStripWrappers == eNoStrip);
|
||||
MOZ_ASSERT(!aRangesToDelete.Ranges().IsEmpty());
|
||||
|
||||
HowToHandleCollapsedRange howToHandleCollapsedRange =
|
||||
EditorBase::HowToHandleCollapsedRangeFor(aDirectionAndAmount);
|
||||
if (NS_WARN_IF(!SelectionRefPtr()->RangeCount()) ||
|
||||
NS_WARN_IF(SelectionRefPtr()->IsCollapsed() &&
|
||||
if (NS_WARN_IF(aRangesToDelete.IsCollapsed() &&
|
||||
howToHandleCollapsedRange ==
|
||||
HowToHandleCollapsedRange::Ignore)) {
|
||||
NS_ASSERTION(
|
||||
@ -3967,7 +3985,8 @@ nsresult EditorBase::DeleteSelectionWithTransaction(
|
||||
}
|
||||
|
||||
RefPtr<EditAggregateTransaction> deleteSelectionTransaction =
|
||||
CreateTransactionForDeleteSelection(howToHandleCollapsedRange);
|
||||
CreateTransactionForDeleteSelection(howToHandleCollapsedRange,
|
||||
aRangesToDelete);
|
||||
if (!deleteSelectionTransaction) {
|
||||
NS_WARNING("EditorBase::CreateTransactionForDeleteSelection() failed");
|
||||
return NS_ERROR_FAILURE;
|
||||
@ -4013,8 +4032,8 @@ nsresult EditorBase::DeleteSelectionWithTransaction(
|
||||
// this must have a bug since we only add the first range into
|
||||
// the changed range.
|
||||
TopLevelEditSubActionDataRef().WillDeleteRange(
|
||||
*this, EditorBase::GetStartPoint(*SelectionRefPtr()),
|
||||
EditorBase::GetEndPoint(*SelectionRefPtr()));
|
||||
*this, aRangesToDelete.GetStartPointOfFirstRange(),
|
||||
aRangesToDelete.GetEndPointOfFirstRange());
|
||||
} else if (!deleteCharData) {
|
||||
TopLevelEditSubActionDataRef().WillDeleteContent(*this, *deleteContent);
|
||||
}
|
||||
@ -4023,25 +4042,19 @@ nsresult EditorBase::DeleteSelectionWithTransaction(
|
||||
// Notify nsIEditActionListener::WillDelete[Selection|Text]
|
||||
if (!mActionListeners.IsEmpty()) {
|
||||
if (!deleteContent) {
|
||||
if (SelectionRefPtr()->RangeCount()) {
|
||||
AutoActionListenerArray listeners(mActionListeners.Clone());
|
||||
for (auto& listener : listeners) {
|
||||
// FYI: Currently, there should be only one listener at most.
|
||||
// Therefore, retrieving the lastest ranges everytime before
|
||||
// calling `WillDeleteRanges()` must be fine.
|
||||
AutoTArray<RefPtr<nsRange>, 8> ranges;
|
||||
for (uint32_t i = 0; i < SelectionRefPtr()->RangeCount(); i++) {
|
||||
ranges.AppendElement(
|
||||
SelectionRefPtr()->GetRangeAt(i)->CloneRange());
|
||||
}
|
||||
DebugOnly<nsresult> rvIgnored = listener->WillDeleteRanges(ranges);
|
||||
NS_WARNING_ASSERTION(
|
||||
NS_SUCCEEDED(rvIgnored),
|
||||
"nsIEditActionListener::WillDeleteRanges() failed, but ignored");
|
||||
MOZ_DIAGNOSTIC_ASSERT(!Destroyed(),
|
||||
"nsIEditActionListener::WillDeleteRanges() "
|
||||
"must not destroy the editor");
|
||||
}
|
||||
MOZ_ASSERT(!aRangesToDelete.Ranges().IsEmpty());
|
||||
AutoTArray<RefPtr<nsRange>, 8> rangesToDelete(
|
||||
aRangesToDelete.CloneRanges<RefPtr>());
|
||||
AutoActionListenerArray listeners(mActionListeners.Clone());
|
||||
for (auto& listener : listeners) {
|
||||
DebugOnly<nsresult> rvIgnored =
|
||||
listener->WillDeleteRanges(rangesToDelete);
|
||||
NS_WARNING_ASSERTION(
|
||||
NS_SUCCEEDED(rvIgnored),
|
||||
"nsIEditActionListener::WillDeleteRanges() failed, but ignored");
|
||||
MOZ_DIAGNOSTIC_ASSERT(!Destroyed(),
|
||||
"nsIEditActionListener::WillDeleteRanges() "
|
||||
"must not destroy the editor");
|
||||
}
|
||||
} else if (deleteCharData) {
|
||||
AutoActionListenerArray listeners(mActionListeners.Clone());
|
||||
|
@ -59,6 +59,7 @@ class nsRange;
|
||||
|
||||
namespace mozilla {
|
||||
class AlignStateAtSelection;
|
||||
class AutoRangeArray;
|
||||
class AutoSelectionRestorer;
|
||||
class AutoTopLevelEditSubActionNotifier;
|
||||
class AutoTransactionBatch;
|
||||
@ -2227,20 +2228,41 @@ class EditorBase : public nsIEditor,
|
||||
nsIEditor::EStripWrappers aStripWrappers);
|
||||
|
||||
/**
|
||||
* Create an aggregate transaction for delete selection. The result may
|
||||
* include DeleteNodeTransactions and/or DeleteTextTransactions as its
|
||||
* children.
|
||||
* DeleteRangesWithTransaction() removes content in aRangesToDelete or content
|
||||
* around collapsed ranges in aRangesToDelete with transactions and remove
|
||||
* empty inclusive ancestor inline elements of collapsed ranges after
|
||||
* removing the contents.
|
||||
*
|
||||
* @param aDirectionAndAmount How much range should be removed.
|
||||
* @param aStripWrappers Whether the parent blocks should be removed
|
||||
* when they become empty.
|
||||
* Note that this must be `nsIEditor::eNoStrip`
|
||||
* if this is a TextEditor because anyway it'll
|
||||
* be ignored.
|
||||
* @param aRangesToDelete The ranges to delete content.
|
||||
*/
|
||||
[[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
|
||||
DeleteRangesWithTransaction(nsIEditor::EDirection aDirectionAndAmount,
|
||||
nsIEditor::EStripWrappers aStripWrappers,
|
||||
const AutoRangeArray& aRangesToDelete);
|
||||
|
||||
/**
|
||||
* Create an aggregate transaction for delete the content in aRangesToDelete.
|
||||
* The result may include DeleteNodeTransactions and/or DeleteTextTransactions
|
||||
* as its children.
|
||||
*
|
||||
* @param aHowToHandleCollapsedRange
|
||||
* How to handle collapsed ranges.
|
||||
* @return If it can remove the selection, returns an
|
||||
* aggregate transaction which has some
|
||||
* @param aRangesToDelete The ranges to delete content.
|
||||
* @return If it can remove the content in ranges, returns
|
||||
* an aggregate transaction which has some
|
||||
* DeleteNodeTransactions and/or
|
||||
* DeleteTextTransactions as its children.
|
||||
*/
|
||||
already_AddRefed<EditAggregateTransaction>
|
||||
CreateTransactionForDeleteSelection(
|
||||
HowToHandleCollapsedRange aHowToHandleCollapsedRange);
|
||||
HowToHandleCollapsedRange aHowToHandleCollapsedRange,
|
||||
const AutoRangeArray& aRangesToDelete);
|
||||
|
||||
/**
|
||||
* Create a transaction for removing the nodes and/or text around
|
||||
|
@ -753,6 +753,28 @@ class MOZ_STACK_CLASS AutoRangeArray final {
|
||||
auto& Ranges() { return mRanges; }
|
||||
const auto& Ranges() const { return mRanges; }
|
||||
|
||||
template <template <typename> typename StrongPtrType>
|
||||
AutoTArray<StrongPtrType<nsRange>, 8> CloneRanges() const {
|
||||
AutoTArray<StrongPtrType<nsRange>, 8> ranges;
|
||||
for (const auto& range : mRanges) {
|
||||
ranges.AppendElement(range->CloneRange());
|
||||
}
|
||||
return ranges;
|
||||
}
|
||||
|
||||
EditorDOMPoint GetStartPointOfFirstRange() const {
|
||||
if (mRanges.IsEmpty() || !mRanges[0]->IsPositioned()) {
|
||||
return EditorDOMPoint();
|
||||
}
|
||||
return EditorDOMPoint(mRanges[0]->StartRef());
|
||||
}
|
||||
EditorDOMPoint GetEndPointOfFirstRange() const {
|
||||
if (mRanges.IsEmpty() || !mRanges[0]->IsPositioned()) {
|
||||
return EditorDOMPoint();
|
||||
}
|
||||
return EditorDOMPoint(mRanges[0]->EndRef());
|
||||
}
|
||||
|
||||
/**
|
||||
* The following methods are same as `Selection`'s methods.
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user