|
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 <stdio.h> // for printf |
|
7 |
|
8 #include "JoinElementTxn.h" |
|
9 #include "nsAString.h" |
|
10 #include "nsDebug.h" // for NS_ASSERTION, etc |
|
11 #include "nsEditor.h" // for nsEditor |
|
12 #include "nsError.h" // for NS_ERROR_NULL_POINTER, etc |
|
13 #include "nsIDOMCharacterData.h" // for nsIDOMCharacterData |
|
14 #include "nsIEditor.h" // for nsEditor::IsModifiableNode |
|
15 #include "nsINode.h" // for nsINode |
|
16 #include "nsISupportsImpl.h" // for EditTxn::QueryInterface, etc |
|
17 |
|
18 JoinElementTxn::JoinElementTxn() |
|
19 : EditTxn() |
|
20 { |
|
21 } |
|
22 |
|
23 NS_IMPL_CYCLE_COLLECTION_INHERITED(JoinElementTxn, EditTxn, |
|
24 mLeftNode, |
|
25 mRightNode, |
|
26 mParent) |
|
27 |
|
28 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(JoinElementTxn) |
|
29 NS_INTERFACE_MAP_END_INHERITING(EditTxn) |
|
30 |
|
31 NS_IMETHODIMP JoinElementTxn::Init(nsEditor *aEditor, |
|
32 nsIDOMNode *aLeftNode, |
|
33 nsIDOMNode *aRightNode) |
|
34 { |
|
35 NS_PRECONDITION((aEditor && aLeftNode && aRightNode), "null arg"); |
|
36 if (!aEditor || !aLeftNode || !aRightNode) { return NS_ERROR_NULL_POINTER; } |
|
37 mEditor = aEditor; |
|
38 mLeftNode = do_QueryInterface(aLeftNode); |
|
39 nsCOMPtr<nsIDOMNode>leftParent; |
|
40 nsresult result = mLeftNode->GetParentNode(getter_AddRefs(leftParent)); |
|
41 NS_ENSURE_SUCCESS(result, result); |
|
42 if (!mEditor->IsModifiableNode(leftParent)) { |
|
43 return NS_ERROR_FAILURE; |
|
44 } |
|
45 mRightNode = do_QueryInterface(aRightNode); |
|
46 mOffset = 0; |
|
47 return NS_OK; |
|
48 } |
|
49 |
|
50 // After DoTransaction() and RedoTransaction(), the left node is removed from the content tree and right node remains. |
|
51 NS_IMETHODIMP JoinElementTxn::DoTransaction(void) |
|
52 { |
|
53 NS_PRECONDITION((mEditor && mLeftNode && mRightNode), "null arg"); |
|
54 if (!mEditor || !mLeftNode || !mRightNode) { return NS_ERROR_NOT_INITIALIZED; } |
|
55 |
|
56 // get the parent node |
|
57 nsCOMPtr<nsIDOMNode> leftParent; |
|
58 mLeftNode->GetParentNode(getter_AddRefs(leftParent)); |
|
59 NS_ENSURE_TRUE(leftParent, NS_ERROR_NULL_POINTER); |
|
60 |
|
61 // verify that mLeftNode and mRightNode have the same parent |
|
62 nsCOMPtr<nsIDOMNode> rightParent; |
|
63 mRightNode->GetParentNode(getter_AddRefs(rightParent)); |
|
64 NS_ENSURE_TRUE(rightParent, NS_ERROR_NULL_POINTER); |
|
65 |
|
66 if (leftParent != rightParent) { |
|
67 NS_ASSERTION(false, "2 nodes do not have same parent"); |
|
68 return NS_ERROR_INVALID_ARG; |
|
69 } |
|
70 |
|
71 // set this instance mParent. |
|
72 // Other methods will see a non-null mParent and know all is well |
|
73 mParent = leftParent; |
|
74 nsCOMPtr<nsINode> leftNode = do_QueryInterface(mLeftNode); |
|
75 nsCOMPtr<nsINode> rightNode = do_QueryInterface(mRightNode); |
|
76 nsCOMPtr<nsINode> parent = do_QueryInterface(mParent); |
|
77 NS_ENSURE_TRUE(leftNode && rightNode && parent, NS_ERROR_FAILURE); |
|
78 mOffset = leftNode->Length(); |
|
79 |
|
80 return mEditor->JoinNodesImpl(rightNode, leftNode, parent); |
|
81 } |
|
82 |
|
83 //XXX: what if instead of split, we just deleted the unneeded children of mRight |
|
84 // and re-inserted mLeft? |
|
85 NS_IMETHODIMP JoinElementTxn::UndoTransaction(void) |
|
86 { |
|
87 NS_ASSERTION(mRightNode && mLeftNode && mParent, "bad state"); |
|
88 if (!mRightNode || !mLeftNode || !mParent) { return NS_ERROR_NOT_INITIALIZED; } |
|
89 nsresult result; |
|
90 nsCOMPtr<nsIDOMNode>resultNode; |
|
91 // first, massage the existing node so it is in its post-split state |
|
92 nsCOMPtr<nsIDOMCharacterData>rightNodeAsText = do_QueryInterface(mRightNode); |
|
93 if (rightNodeAsText) |
|
94 { |
|
95 result = rightNodeAsText->DeleteData(0, mOffset); |
|
96 } |
|
97 else |
|
98 { |
|
99 nsCOMPtr<nsIDOMNode>child; |
|
100 result = mRightNode->GetFirstChild(getter_AddRefs(child)); |
|
101 nsCOMPtr<nsIDOMNode>nextSibling; |
|
102 uint32_t i; |
|
103 for (i=0; i<mOffset; i++) |
|
104 { |
|
105 if (NS_FAILED(result)) {return result;} |
|
106 if (!child) {return NS_ERROR_NULL_POINTER;} |
|
107 child->GetNextSibling(getter_AddRefs(nextSibling)); |
|
108 result = mLeftNode->AppendChild(child, getter_AddRefs(resultNode)); |
|
109 child = do_QueryInterface(nextSibling); |
|
110 } |
|
111 } |
|
112 // second, re-insert the left node into the tree |
|
113 result = mParent->InsertBefore(mLeftNode, mRightNode, getter_AddRefs(resultNode)); |
|
114 return result; |
|
115 |
|
116 } |
|
117 |
|
118 NS_IMETHODIMP JoinElementTxn::GetTxnDescription(nsAString& aString) |
|
119 { |
|
120 aString.AssignLiteral("JoinElementTxn"); |
|
121 return NS_OK; |
|
122 } |