|
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 "mozilla/dom/Selection.h" |
|
7 #include "nsCOMArray.h" |
|
8 #include "nsComponentManagerUtils.h" |
|
9 #include "nsEditorUtils.h" |
|
10 #include "nsError.h" |
|
11 #include "nsIClipboardDragDropHookList.h" |
|
12 // hooks |
|
13 #include "nsIClipboardDragDropHooks.h" |
|
14 #include "nsIContent.h" |
|
15 #include "nsIContentIterator.h" |
|
16 #include "nsIDOMDocument.h" |
|
17 #include "nsIDocShell.h" |
|
18 #include "nsIDocument.h" |
|
19 #include "nsIInterfaceRequestorUtils.h" |
|
20 #include "nsINode.h" |
|
21 #include "nsISimpleEnumerator.h" |
|
22 |
|
23 class nsIDOMRange; |
|
24 class nsISupports; |
|
25 |
|
26 using namespace mozilla; |
|
27 using namespace mozilla::dom; |
|
28 |
|
29 /****************************************************************************** |
|
30 * nsAutoSelectionReset |
|
31 *****************************************************************************/ |
|
32 |
|
33 nsAutoSelectionReset::nsAutoSelectionReset(Selection* aSel, nsEditor* aEd) |
|
34 : mSel(nullptr), mEd(nullptr) |
|
35 { |
|
36 if (!aSel || !aEd) return; // not much we can do, bail. |
|
37 if (aEd->ArePreservingSelection()) return; // we already have initted mSavedSel, so this must be nested call. |
|
38 mSel = aSel; |
|
39 mEd = aEd; |
|
40 if (mSel) |
|
41 { |
|
42 mEd->PreserveSelectionAcrossActions(mSel); |
|
43 } |
|
44 } |
|
45 |
|
46 nsAutoSelectionReset::~nsAutoSelectionReset() |
|
47 { |
|
48 NS_ASSERTION(!mSel || mEd, "mEd should be non-null when mSel is"); |
|
49 if (mSel && mEd->ArePreservingSelection()) // mSel will be null if this was nested call |
|
50 { |
|
51 mEd->RestorePreservedSelection(mSel); |
|
52 } |
|
53 } |
|
54 |
|
55 void |
|
56 nsAutoSelectionReset::Abort() |
|
57 { |
|
58 NS_ASSERTION(!mSel || mEd, "mEd should be non-null when mSel is"); |
|
59 if (mSel) |
|
60 mEd->StopPreservingSelection(); |
|
61 } |
|
62 |
|
63 |
|
64 /****************************************************************************** |
|
65 * some helper classes for iterating the dom tree |
|
66 *****************************************************************************/ |
|
67 |
|
68 nsDOMIterator::nsDOMIterator() : |
|
69 mIter(nullptr) |
|
70 { |
|
71 } |
|
72 |
|
73 nsDOMIterator::~nsDOMIterator() |
|
74 { |
|
75 } |
|
76 |
|
77 nsresult |
|
78 nsDOMIterator::Init(nsIDOMRange* aRange) |
|
79 { |
|
80 nsresult res; |
|
81 mIter = do_CreateInstance("@mozilla.org/content/post-content-iterator;1", &res); |
|
82 NS_ENSURE_SUCCESS(res, res); |
|
83 NS_ENSURE_TRUE(mIter, NS_ERROR_FAILURE); |
|
84 return mIter->Init(aRange); |
|
85 } |
|
86 |
|
87 nsresult |
|
88 nsDOMIterator::Init(nsIDOMNode* aNode) |
|
89 { |
|
90 nsresult res; |
|
91 mIter = do_CreateInstance("@mozilla.org/content/post-content-iterator;1", &res); |
|
92 NS_ENSURE_SUCCESS(res, res); |
|
93 NS_ENSURE_TRUE(mIter, NS_ERROR_FAILURE); |
|
94 nsCOMPtr<nsIContent> content = do_QueryInterface(aNode); |
|
95 return mIter->Init(content); |
|
96 } |
|
97 |
|
98 nsresult |
|
99 nsDOMIterator::AppendList(nsBoolDomIterFunctor& functor, |
|
100 nsCOMArray<nsIDOMNode>& arrayOfNodes) const |
|
101 { |
|
102 nsCOMPtr<nsIDOMNode> node; |
|
103 |
|
104 // iterate through dom and build list |
|
105 while (!mIter->IsDone()) |
|
106 { |
|
107 node = do_QueryInterface(mIter->GetCurrentNode()); |
|
108 NS_ENSURE_TRUE(node, NS_ERROR_NULL_POINTER); |
|
109 |
|
110 if (functor(node)) |
|
111 { |
|
112 arrayOfNodes.AppendObject(node); |
|
113 } |
|
114 mIter->Next(); |
|
115 } |
|
116 return NS_OK; |
|
117 } |
|
118 |
|
119 nsDOMSubtreeIterator::nsDOMSubtreeIterator() |
|
120 { |
|
121 } |
|
122 |
|
123 nsDOMSubtreeIterator::~nsDOMSubtreeIterator() |
|
124 { |
|
125 } |
|
126 |
|
127 nsresult |
|
128 nsDOMSubtreeIterator::Init(nsIDOMRange* aRange) |
|
129 { |
|
130 nsresult res; |
|
131 mIter = do_CreateInstance("@mozilla.org/content/subtree-content-iterator;1", &res); |
|
132 NS_ENSURE_SUCCESS(res, res); |
|
133 NS_ENSURE_TRUE(mIter, NS_ERROR_FAILURE); |
|
134 return mIter->Init(aRange); |
|
135 } |
|
136 |
|
137 /****************************************************************************** |
|
138 * some general purpose editor utils |
|
139 *****************************************************************************/ |
|
140 |
|
141 bool |
|
142 nsEditorUtils::IsDescendantOf(nsIDOMNode *aNode, nsIDOMNode *aParent, int32_t *aOffset) |
|
143 { |
|
144 NS_ENSURE_TRUE(aNode || aParent, false); |
|
145 if (aNode == aParent) return false; |
|
146 |
|
147 nsCOMPtr<nsIDOMNode> parent, node = do_QueryInterface(aNode); |
|
148 nsresult res; |
|
149 |
|
150 do |
|
151 { |
|
152 res = node->GetParentNode(getter_AddRefs(parent)); |
|
153 NS_ENSURE_SUCCESS(res, false); |
|
154 if (parent == aParent) |
|
155 { |
|
156 if (aOffset) |
|
157 { |
|
158 nsCOMPtr<nsIContent> pCon(do_QueryInterface(parent)); |
|
159 nsCOMPtr<nsIContent> cCon(do_QueryInterface(node)); |
|
160 if (pCon) |
|
161 { |
|
162 *aOffset = pCon->IndexOf(cCon); |
|
163 } |
|
164 } |
|
165 return true; |
|
166 } |
|
167 node = parent; |
|
168 } while (parent); |
|
169 |
|
170 return false; |
|
171 } |
|
172 |
|
173 bool |
|
174 nsEditorUtils::IsLeafNode(nsIDOMNode *aNode) |
|
175 { |
|
176 bool hasChildren = false; |
|
177 if (aNode) |
|
178 aNode->HasChildNodes(&hasChildren); |
|
179 return !hasChildren; |
|
180 } |
|
181 |
|
182 /****************************************************************************** |
|
183 * utility methods for drag/drop/copy/paste hooks |
|
184 *****************************************************************************/ |
|
185 |
|
186 nsresult |
|
187 nsEditorHookUtils::GetHookEnumeratorFromDocument(nsIDOMDocument *aDoc, |
|
188 nsISimpleEnumerator **aResult) |
|
189 { |
|
190 nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDoc); |
|
191 NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE); |
|
192 |
|
193 nsCOMPtr<nsIDocShell> docShell = doc->GetDocShell(); |
|
194 nsCOMPtr<nsIClipboardDragDropHookList> hookObj = do_GetInterface(docShell); |
|
195 NS_ENSURE_TRUE(hookObj, NS_ERROR_FAILURE); |
|
196 |
|
197 return hookObj->GetHookEnumerator(aResult); |
|
198 } |
|
199 |
|
200 bool |
|
201 nsEditorHookUtils::DoInsertionHook(nsIDOMDocument *aDoc, nsIDOMEvent *aDropEvent, |
|
202 nsITransferable *aTrans) |
|
203 { |
|
204 nsCOMPtr<nsISimpleEnumerator> enumerator; |
|
205 GetHookEnumeratorFromDocument(aDoc, getter_AddRefs(enumerator)); |
|
206 NS_ENSURE_TRUE(enumerator, true); |
|
207 |
|
208 bool hasMoreHooks = false; |
|
209 while (NS_SUCCEEDED(enumerator->HasMoreElements(&hasMoreHooks)) && hasMoreHooks) |
|
210 { |
|
211 nsCOMPtr<nsISupports> isupp; |
|
212 if (NS_FAILED(enumerator->GetNext(getter_AddRefs(isupp)))) |
|
213 break; |
|
214 |
|
215 nsCOMPtr<nsIClipboardDragDropHooks> override = do_QueryInterface(isupp); |
|
216 if (override) |
|
217 { |
|
218 bool doInsert = true; |
|
219 #ifdef DEBUG |
|
220 nsresult hookResult = |
|
221 #endif |
|
222 override->OnPasteOrDrop(aDropEvent, aTrans, &doInsert); |
|
223 NS_ASSERTION(NS_SUCCEEDED(hookResult), "hook failure in OnPasteOrDrop"); |
|
224 NS_ENSURE_TRUE(doInsert, false); |
|
225 } |
|
226 } |
|
227 |
|
228 return true; |
|
229 } |