1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #include "JoinNodeTransaction.h"
7
8 #include "mozilla/EditorBase.h" // for EditorBase
9 #include "nsAString.h"
10 #include "nsDebug.h" // for NS_ASSERTION, etc.
11 #include "nsError.h" // for NS_ERROR_NULL_POINTER, etc.
12 #include "nsIContent.h" // for nsIContent
13 #include "nsIDOMCharacterData.h" // for nsIDOMCharacterData
14 #include "nsIEditor.h" // for EditorBase::IsModifiableNode
15 #include "nsISupportsImpl.h" // for QueryInterface, etc.
16
17 namespace mozilla {
18
19 using namespace dom;
20
JoinNodeTransaction(EditorBase & aEditorBase,nsINode & aLeftNode,nsINode & aRightNode)21 JoinNodeTransaction::JoinNodeTransaction(EditorBase& aEditorBase,
22 nsINode& aLeftNode,
23 nsINode& aRightNode)
24 : mEditorBase(aEditorBase)
25 , mLeftNode(&aLeftNode)
26 , mRightNode(&aRightNode)
27 , mOffset(0)
28 {
29 }
30
NS_IMPL_CYCLE_COLLECTION_INHERITED(JoinNodeTransaction,EditTransactionBase,mLeftNode,mRightNode,mParent)31 NS_IMPL_CYCLE_COLLECTION_INHERITED(JoinNodeTransaction, EditTransactionBase,
32 mLeftNode,
33 mRightNode,
34 mParent)
35
36 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(JoinNodeTransaction)
37 NS_INTERFACE_MAP_END_INHERITING(EditTransactionBase)
38
39 nsresult
40 JoinNodeTransaction::CheckValidity()
41 {
42 if (!mEditorBase.IsModifiableNode(mLeftNode->GetParentNode())) {
43 return NS_ERROR_FAILURE;
44 }
45 return NS_OK;
46 }
47
48 // After DoTransaction() and RedoTransaction(), the left node is removed from
49 // the content tree and right node remains.
50 NS_IMETHODIMP
DoTransaction()51 JoinNodeTransaction::DoTransaction()
52 {
53 // Get the parent node
54 nsCOMPtr<nsINode> leftParent = mLeftNode->GetParentNode();
55 NS_ENSURE_TRUE(leftParent, NS_ERROR_NULL_POINTER);
56
57 // Verify that mLeftNode and mRightNode have the same parent
58 if (leftParent != mRightNode->GetParentNode()) {
59 NS_ASSERTION(false, "Nodes do not have same parent");
60 return NS_ERROR_INVALID_ARG;
61 }
62
63 // Set this instance's mParent. Other methods will see a non-null mParent
64 // and know all is well
65 mParent = leftParent;
66 mOffset = mLeftNode->Length();
67
68 return mEditorBase.JoinNodesImpl(mRightNode, mLeftNode, mParent);
69 }
70
71 //XXX: What if instead of split, we just deleted the unneeded children of
72 // mRight and re-inserted mLeft?
73 NS_IMETHODIMP
UndoTransaction()74 JoinNodeTransaction::UndoTransaction()
75 {
76 MOZ_ASSERT(mParent);
77
78 // First, massage the existing node so it is in its post-split state
79 ErrorResult rv;
80 if (mRightNode->GetAsText()) {
81 rv = mRightNode->GetAsText()->DeleteData(0, mOffset);
82 } else {
83 nsCOMPtr<nsIContent> child = mRightNode->GetFirstChild();
84 for (uint32_t i = 0; i < mOffset; i++) {
85 if (rv.Failed()) {
86 return rv.StealNSResult();
87 }
88 if (!child) {
89 return NS_ERROR_NULL_POINTER;
90 }
91 nsCOMPtr<nsIContent> nextSibling = child->GetNextSibling();
92 mLeftNode->AppendChild(*child, rv);
93 child = nextSibling;
94 }
95 }
96 // Second, re-insert the left node into the tree
97 nsCOMPtr<nsINode> refNode = mRightNode;
98 mParent->InsertBefore(*mLeftNode, refNode, rv);
99 return rv.StealNSResult();
100 }
101
102 NS_IMETHODIMP
GetTxnDescription(nsAString & aString)103 JoinNodeTransaction::GetTxnDescription(nsAString& aString)
104 {
105 aString.AssignLiteral("JoinNodeTransaction");
106 return NS_OK;
107 }
108
109 } // namespace mozilla
110