michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "DeleteNodeTxn.h" michael@0: #include "nsDebug.h" michael@0: #include "nsEditor.h" michael@0: #include "nsError.h" michael@0: #include "nsSelectionState.h" // nsRangeUpdater michael@0: #include "nsAString.h" michael@0: michael@0: using namespace mozilla; michael@0: michael@0: DeleteNodeTxn::DeleteNodeTxn() michael@0: : EditTxn(), mNode(), mParent(), mRefNode(), mRangeUpdater(nullptr) michael@0: { michael@0: } michael@0: michael@0: NS_IMPL_CYCLE_COLLECTION_INHERITED(DeleteNodeTxn, EditTxn, michael@0: mNode, michael@0: mParent, michael@0: mRefNode) michael@0: michael@0: NS_IMPL_ADDREF_INHERITED(DeleteNodeTxn, EditTxn) michael@0: NS_IMPL_RELEASE_INHERITED(DeleteNodeTxn, EditTxn) michael@0: NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DeleteNodeTxn) michael@0: NS_INTERFACE_MAP_END_INHERITING(EditTxn) michael@0: michael@0: nsresult michael@0: DeleteNodeTxn::Init(nsEditor* aEditor, nsINode* aNode, michael@0: nsRangeUpdater* aRangeUpdater) michael@0: { michael@0: NS_ENSURE_TRUE(aEditor && aNode, NS_ERROR_NULL_POINTER); michael@0: mEditor = aEditor; michael@0: mNode = aNode; michael@0: mParent = aNode->GetParentNode(); michael@0: michael@0: // do nothing if the node has a parent and it's read-only michael@0: NS_ENSURE_TRUE(!mParent || mEditor->IsModifiableNode(mParent), michael@0: NS_ERROR_FAILURE); michael@0: michael@0: mRangeUpdater = aRangeUpdater; michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: NS_IMETHODIMP michael@0: DeleteNodeTxn::DoTransaction() michael@0: { michael@0: NS_ENSURE_TRUE(mNode, NS_ERROR_NOT_INITIALIZED); michael@0: michael@0: if (!mParent) { michael@0: // this is a no-op, there's no parent to delete mNode from michael@0: return NS_OK; michael@0: } michael@0: michael@0: // remember which child mNode was (by remembering which child was next); michael@0: // mRefNode can be null michael@0: mRefNode = mNode->GetNextSibling(); michael@0: michael@0: // give range updater a chance. SelAdjDeleteNode() needs to be called michael@0: // *before* we do the action, unlike some of the other nsRangeStore update michael@0: // methods. michael@0: if (mRangeUpdater) { michael@0: mRangeUpdater->SelAdjDeleteNode(mNode->AsDOMNode()); michael@0: } michael@0: michael@0: ErrorResult error; michael@0: mParent->RemoveChild(*mNode, error); michael@0: return error.ErrorCode(); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: DeleteNodeTxn::UndoTransaction() michael@0: { michael@0: if (!mParent) { michael@0: // this is a legal state, the txn is a no-op michael@0: return NS_OK; michael@0: } michael@0: if (!mNode) { michael@0: return NS_ERROR_NULL_POINTER; michael@0: } michael@0: michael@0: ErrorResult error; michael@0: mParent->InsertBefore(*mNode, mRefNode, error); michael@0: return error.ErrorCode(); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: DeleteNodeTxn::RedoTransaction() michael@0: { michael@0: if (!mParent) { michael@0: // this is a legal state, the txn is a no-op michael@0: return NS_OK; michael@0: } michael@0: if (!mNode) { michael@0: return NS_ERROR_NULL_POINTER; michael@0: } michael@0: michael@0: if (mRangeUpdater) { michael@0: mRangeUpdater->SelAdjDeleteNode(mNode->AsDOMNode()); michael@0: } michael@0: michael@0: ErrorResult error; michael@0: mParent->RemoveChild(*mNode, error); michael@0: return error.ErrorCode(); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: DeleteNodeTxn::GetTxnDescription(nsAString& aString) michael@0: { michael@0: aString.AssignLiteral("DeleteNodeTxn"); michael@0: return NS_OK; michael@0: }