/src/mozilla-central/editor/libeditor/JoinNodeTransaction.cpp
Line | Count | Source (jump to first uncovered line) |
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 "mozilla/dom/Text.h" |
10 | | #include "nsAString.h" |
11 | | #include "nsDebug.h" // for NS_ASSERTION, etc. |
12 | | #include "nsError.h" // for NS_ERROR_NULL_POINTER, etc. |
13 | | #include "nsIContent.h" // for nsIContent |
14 | | #include "nsISupportsImpl.h" // for QueryInterface, etc. |
15 | | |
16 | | namespace mozilla { |
17 | | |
18 | | using namespace dom; |
19 | | |
20 | | // static |
21 | | already_AddRefed<JoinNodeTransaction> |
22 | | JoinNodeTransaction::MaybeCreate(EditorBase& aEditorBase, |
23 | | nsINode& aLeftNode, |
24 | | nsINode& aRightNode) |
25 | 0 | { |
26 | 0 | RefPtr<JoinNodeTransaction> transaction = |
27 | 0 | new JoinNodeTransaction(aEditorBase, aLeftNode, aRightNode); |
28 | 0 | if (NS_WARN_IF(!transaction->CanDoIt())) { |
29 | 0 | return nullptr; |
30 | 0 | } |
31 | 0 | return transaction.forget(); |
32 | 0 | } |
33 | | |
34 | | JoinNodeTransaction::JoinNodeTransaction(EditorBase& aEditorBase, |
35 | | nsINode& aLeftNode, |
36 | | nsINode& aRightNode) |
37 | | : mEditorBase(&aEditorBase) |
38 | | , mLeftNode(&aLeftNode) |
39 | | , mRightNode(&aRightNode) |
40 | | , mOffset(0) |
41 | 0 | { |
42 | 0 | } |
43 | | |
44 | | NS_IMPL_CYCLE_COLLECTION_INHERITED(JoinNodeTransaction, EditTransactionBase, |
45 | | mEditorBase, |
46 | | mLeftNode, |
47 | | mRightNode, |
48 | | mParent) |
49 | | |
50 | 0 | NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(JoinNodeTransaction) |
51 | 0 | NS_INTERFACE_MAP_END_INHERITING(EditTransactionBase) |
52 | | |
53 | | bool |
54 | | JoinNodeTransaction::CanDoIt() const |
55 | 0 | { |
56 | 0 | if (NS_WARN_IF(!mLeftNode) || |
57 | 0 | NS_WARN_IF(!mRightNode) || |
58 | 0 | NS_WARN_IF(!mEditorBase) || |
59 | 0 | !mLeftNode->GetParentNode()) { |
60 | 0 | return false; |
61 | 0 | } |
62 | 0 | return mEditorBase->IsModifiableNode(*mLeftNode->GetParentNode()); |
63 | 0 | } |
64 | | |
65 | | // After DoTransaction() and RedoTransaction(), the left node is removed from |
66 | | // the content tree and right node remains. |
67 | | NS_IMETHODIMP |
68 | | JoinNodeTransaction::DoTransaction() |
69 | 0 | { |
70 | 0 | if (NS_WARN_IF(!mEditorBase) || |
71 | 0 | NS_WARN_IF(!mLeftNode) || |
72 | 0 | NS_WARN_IF(!mRightNode)) { |
73 | 0 | return NS_ERROR_NOT_INITIALIZED; |
74 | 0 | } |
75 | 0 | |
76 | 0 | // Get the parent node |
77 | 0 | nsCOMPtr<nsINode> leftParent = mLeftNode->GetParentNode(); |
78 | 0 | NS_ENSURE_TRUE(leftParent, NS_ERROR_NULL_POINTER); |
79 | 0 |
|
80 | 0 | // Verify that mLeftNode and mRightNode have the same parent |
81 | 0 | if (leftParent != mRightNode->GetParentNode()) { |
82 | 0 | NS_ASSERTION(false, "Nodes do not have same parent"); |
83 | 0 | return NS_ERROR_INVALID_ARG; |
84 | 0 | } |
85 | 0 |
|
86 | 0 | // Set this instance's mParent. Other methods will see a non-null mParent |
87 | 0 | // and know all is well |
88 | 0 | mParent = leftParent; |
89 | 0 | mOffset = mLeftNode->Length(); |
90 | 0 |
|
91 | 0 | return mEditorBase->DoJoinNodes(mRightNode, mLeftNode, mParent); |
92 | 0 | } |
93 | | |
94 | | //XXX: What if instead of split, we just deleted the unneeded children of |
95 | | // mRight and re-inserted mLeft? |
96 | | NS_IMETHODIMP |
97 | | JoinNodeTransaction::UndoTransaction() |
98 | 0 | { |
99 | 0 | if (NS_WARN_IF(!mParent) || |
100 | 0 | NS_WARN_IF(!mLeftNode) || |
101 | 0 | NS_WARN_IF(!mRightNode)) { |
102 | 0 | return NS_ERROR_NOT_INITIALIZED; |
103 | 0 | } |
104 | 0 | |
105 | 0 | // First, massage the existing node so it is in its post-split state |
106 | 0 | ErrorResult rv; |
107 | 0 | if (mRightNode->GetAsText()) { |
108 | 0 | mRightNode->GetAsText()->DeleteData(0, mOffset, rv); |
109 | 0 | if (rv.Failed()) { |
110 | 0 | return rv.StealNSResult(); |
111 | 0 | } |
112 | 0 | } else { |
113 | 0 | nsCOMPtr<nsIContent> child = mRightNode->GetFirstChild(); |
114 | 0 | for (uint32_t i = 0; i < mOffset; i++) { |
115 | 0 | if (rv.Failed()) { |
116 | 0 | return rv.StealNSResult(); |
117 | 0 | } |
118 | 0 | if (!child) { |
119 | 0 | return NS_ERROR_NULL_POINTER; |
120 | 0 | } |
121 | 0 | nsCOMPtr<nsIContent> nextSibling = child->GetNextSibling(); |
122 | 0 | mLeftNode->AppendChild(*child, rv); |
123 | 0 | child = nextSibling; |
124 | 0 | } |
125 | 0 | } |
126 | 0 | // Second, re-insert the left node into the tree |
127 | 0 | nsCOMPtr<nsINode> refNode = mRightNode; |
128 | 0 | mParent->InsertBefore(*mLeftNode, refNode, rv); |
129 | 0 | return rv.StealNSResult(); |
130 | 0 | } |
131 | | |
132 | | } // namespace mozilla |