|
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 #ifndef __editor_h__ |
|
7 #define __editor_h__ |
|
8 |
|
9 #include "mozilla/Assertions.h" // for MOZ_ASSERT, etc. |
|
10 #include "mozilla/TypedEnum.h" // for MOZ_BEGIN_ENUM_CLASS, etc. |
|
11 #include "nsAutoPtr.h" // for nsRefPtr |
|
12 #include "nsCOMArray.h" // for nsCOMArray |
|
13 #include "nsCOMPtr.h" // for already_AddRefed, nsCOMPtr |
|
14 #include "nsCycleCollectionParticipant.h" |
|
15 #include "nsEditProperty.h" // for nsEditProperty, etc |
|
16 #include "nsIEditor.h" // for nsIEditor::EDirection, etc |
|
17 #include "nsIEditorIMESupport.h" // for NS_DECL_NSIEDITORIMESUPPORT, etc |
|
18 #include "nsIObserver.h" // for NS_DECL_NSIOBSERVER, etc |
|
19 #include "nsIPhonetic.h" // for NS_DECL_NSIPHONETIC, etc |
|
20 #include "nsIPlaintextEditor.h" // for nsIPlaintextEditor, etc |
|
21 #include "nsISupportsImpl.h" // for nsEditor::Release, etc |
|
22 #include "nsIWeakReferenceUtils.h" // for nsWeakPtr |
|
23 #include "nsLiteralString.h" // for NS_LITERAL_STRING |
|
24 #include "nsSelectionState.h" // for nsRangeUpdater, etc |
|
25 #include "nsString.h" // for nsCString |
|
26 #include "nsWeakReference.h" // for nsSupportsWeakReference |
|
27 #include "nscore.h" // for nsresult, nsAString, etc |
|
28 |
|
29 class AddStyleSheetTxn; |
|
30 class ChangeAttributeTxn; |
|
31 class CreateElementTxn; |
|
32 class DeleteNodeTxn; |
|
33 class DeleteTextTxn; |
|
34 class EditAggregateTxn; |
|
35 class IMETextTxn; |
|
36 class InsertElementTxn; |
|
37 class InsertTextTxn; |
|
38 class JoinElementTxn; |
|
39 class RemoveStyleSheetTxn; |
|
40 class SplitElementTxn; |
|
41 class nsCSSStyleSheet; |
|
42 class nsIAtom; |
|
43 class nsIContent; |
|
44 class nsIDOMCharacterData; |
|
45 class nsIDOMDataTransfer; |
|
46 class nsIDOMDocument; |
|
47 class nsIDOMElement; |
|
48 class nsIDOMEvent; |
|
49 class nsIDOMEventListener; |
|
50 class nsIDOMEventTarget; |
|
51 class nsIDOMKeyEvent; |
|
52 class nsIDOMNode; |
|
53 class nsIDOMRange; |
|
54 class nsIDocument; |
|
55 class nsIDocumentStateListener; |
|
56 class nsIEditActionListener; |
|
57 class nsIEditorObserver; |
|
58 class nsIInlineSpellChecker; |
|
59 class nsINode; |
|
60 class nsIPresShell; |
|
61 class nsISelection; |
|
62 class nsISupports; |
|
63 class nsITransaction; |
|
64 class nsIWidget; |
|
65 class nsRange; |
|
66 class nsString; |
|
67 class nsTransactionManager; |
|
68 |
|
69 namespace mozilla { |
|
70 class TextComposition; |
|
71 |
|
72 namespace dom { |
|
73 class DataTransfer; |
|
74 class Element; |
|
75 class EventTarget; |
|
76 class Selection; |
|
77 } // namespace dom |
|
78 } // namespace mozilla |
|
79 |
|
80 namespace mozilla { |
|
81 namespace widget { |
|
82 struct IMEState; |
|
83 } // namespace widget |
|
84 } // namespace mozilla |
|
85 |
|
86 #define kMOZEditorBogusNodeAttrAtom nsEditProperty::mozEditorBogusNode |
|
87 #define kMOZEditorBogusNodeValue NS_LITERAL_STRING("TRUE") |
|
88 |
|
89 // This is int32_t instead of int16_t because nsIInlineSpellChecker.idl's |
|
90 // spellCheckAfterEditorChange is defined to take it as a long. |
|
91 MOZ_BEGIN_ENUM_CLASS(EditAction, int32_t) |
|
92 ignore = -1, |
|
93 none = 0, |
|
94 undo, |
|
95 redo, |
|
96 insertNode, |
|
97 createNode, |
|
98 deleteNode, |
|
99 splitNode, |
|
100 joinNode, |
|
101 deleteText = 1003, |
|
102 |
|
103 // text commands |
|
104 insertText = 2000, |
|
105 insertIMEText = 2001, |
|
106 deleteSelection = 2002, |
|
107 setTextProperty = 2003, |
|
108 removeTextProperty = 2004, |
|
109 outputText = 2005, |
|
110 |
|
111 // html only action |
|
112 insertBreak = 3000, |
|
113 makeList = 3001, |
|
114 indent = 3002, |
|
115 outdent = 3003, |
|
116 align = 3004, |
|
117 makeBasicBlock = 3005, |
|
118 removeList = 3006, |
|
119 makeDefListItem = 3007, |
|
120 insertElement = 3008, |
|
121 insertQuotation = 3009, |
|
122 htmlPaste = 3012, |
|
123 loadHTML = 3013, |
|
124 resetTextProperties = 3014, |
|
125 setAbsolutePosition = 3015, |
|
126 removeAbsolutePosition = 3016, |
|
127 decreaseZIndex = 3017, |
|
128 increaseZIndex = 3018 |
|
129 MOZ_END_ENUM_CLASS(EditAction) |
|
130 |
|
131 inline bool operator!(const EditAction& aOp) |
|
132 { |
|
133 return aOp == EditAction::none; |
|
134 } |
|
135 |
|
136 /** implementation of an editor object. it will be the controller/focal point |
|
137 * for the main editor services. i.e. the GUIManager, publishing, transaction |
|
138 * manager, event interfaces. the idea for the event interfaces is to have them |
|
139 * delegate the actual commands to the editor independent of the XPFE implementation. |
|
140 */ |
|
141 class nsEditor : public nsIEditor, |
|
142 public nsIEditorIMESupport, |
|
143 public nsSupportsWeakReference, |
|
144 public nsIObserver, |
|
145 public nsIPhonetic |
|
146 { |
|
147 public: |
|
148 |
|
149 enum IterDirection |
|
150 { |
|
151 kIterForward, |
|
152 kIterBackward |
|
153 }; |
|
154 |
|
155 /** The default constructor. This should suffice. the setting of the interfaces is done |
|
156 * after the construction of the editor class. |
|
157 */ |
|
158 nsEditor(); |
|
159 /** The default destructor. This should suffice. Should this be pure virtual |
|
160 * for someone to derive from the nsEditor later? I don't believe so. |
|
161 */ |
|
162 virtual ~nsEditor(); |
|
163 |
|
164 //Interfaces for addref and release and queryinterface |
|
165 //NOTE: Use NS_DECL_ISUPPORTS_INHERITED in any class inherited from nsEditor |
|
166 NS_DECL_CYCLE_COLLECTING_ISUPPORTS |
|
167 NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsEditor, |
|
168 nsIEditor) |
|
169 |
|
170 /* ------------ utility methods -------------- */ |
|
171 already_AddRefed<nsIDOMDocument> GetDOMDocument(); |
|
172 already_AddRefed<nsIDocument> GetDocument(); |
|
173 already_AddRefed<nsIPresShell> GetPresShell(); |
|
174 already_AddRefed<nsIWidget> GetWidget(); |
|
175 void NotifyEditorObservers(); |
|
176 |
|
177 /* ------------ nsIEditor methods -------------- */ |
|
178 NS_DECL_NSIEDITOR |
|
179 |
|
180 /* ------------ nsIEditorIMESupport methods -------------- */ |
|
181 NS_DECL_NSIEDITORIMESUPPORT |
|
182 |
|
183 /* ------------ nsIObserver methods -------------- */ |
|
184 NS_DECL_NSIOBSERVER |
|
185 |
|
186 // nsIPhonetic |
|
187 NS_DECL_NSIPHONETIC |
|
188 |
|
189 public: |
|
190 |
|
191 virtual bool IsModifiableNode(nsINode *aNode); |
|
192 |
|
193 NS_IMETHOD InsertTextImpl(const nsAString& aStringToInsert, |
|
194 nsCOMPtr<nsIDOMNode> *aInOutNode, |
|
195 int32_t *aInOutOffset, |
|
196 nsIDOMDocument *aDoc); |
|
197 nsresult InsertTextIntoTextNodeImpl(const nsAString& aStringToInsert, |
|
198 nsIDOMCharacterData *aTextNode, |
|
199 int32_t aOffset, |
|
200 bool aSuppressIME = false); |
|
201 NS_IMETHOD DeleteSelectionImpl(EDirection aAction, |
|
202 EStripWrappers aStripWrappers); |
|
203 NS_IMETHOD DeleteSelectionAndCreateNode(const nsAString& aTag, |
|
204 nsIDOMNode ** aNewNode); |
|
205 |
|
206 /* helper routines for node/parent manipulations */ |
|
207 nsresult DeleteNode(nsINode* aNode); |
|
208 nsresult ReplaceContainer(nsINode* inNode, |
|
209 mozilla::dom::Element** outNode, |
|
210 const nsAString& aNodeType, |
|
211 const nsAString* aAttribute = nullptr, |
|
212 const nsAString* aValue = nullptr, |
|
213 bool aCloneAttributes = false); |
|
214 nsresult ReplaceContainer(nsIDOMNode *inNode, |
|
215 nsCOMPtr<nsIDOMNode> *outNode, |
|
216 const nsAString &aNodeType, |
|
217 const nsAString *aAttribute = nullptr, |
|
218 const nsAString *aValue = nullptr, |
|
219 bool aCloneAttributes = false); |
|
220 |
|
221 nsresult RemoveContainer(nsINode* aNode); |
|
222 nsresult RemoveContainer(nsIDOMNode *inNode); |
|
223 nsresult InsertContainerAbove(nsIContent* aNode, |
|
224 mozilla::dom::Element** aOutNode, |
|
225 const nsAString& aNodeType, |
|
226 const nsAString* aAttribute = nullptr, |
|
227 const nsAString* aValue = nullptr); |
|
228 nsresult InsertContainerAbove(nsIDOMNode *inNode, |
|
229 nsCOMPtr<nsIDOMNode> *outNode, |
|
230 const nsAString &aNodeType, |
|
231 const nsAString *aAttribute = nullptr, |
|
232 const nsAString *aValue = nullptr); |
|
233 nsresult JoinNodes(nsINode* aNodeToKeep, nsIContent* aNodeToMove); |
|
234 nsresult MoveNode(nsINode* aNode, nsINode* aParent, int32_t aOffset); |
|
235 nsresult MoveNode(nsIDOMNode *aNode, nsIDOMNode *aParent, int32_t aOffset); |
|
236 |
|
237 /* Method to replace certain CreateElementNS() calls. |
|
238 Arguments: |
|
239 nsString& aTag - tag you want |
|
240 nsIContent** aContent - returned Content that was created with above namespace. |
|
241 */ |
|
242 nsresult CreateHTMLContent(const nsAString& aTag, |
|
243 mozilla::dom::Element** aContent); |
|
244 |
|
245 // IME event handlers |
|
246 virtual nsresult BeginIMEComposition(mozilla::WidgetCompositionEvent* aEvent); |
|
247 virtual nsresult UpdateIMEComposition(nsIDOMEvent* aDOMTextEvent) = 0; |
|
248 void EndIMEComposition(); |
|
249 |
|
250 void SwitchTextDirectionTo(uint32_t aDirection); |
|
251 |
|
252 protected: |
|
253 nsresult DetermineCurrentDirection(); |
|
254 void FireInputEvent(); |
|
255 |
|
256 /** create a transaction for setting aAttribute to aValue on aElement |
|
257 */ |
|
258 NS_IMETHOD CreateTxnForSetAttribute(nsIDOMElement *aElement, |
|
259 const nsAString & aAttribute, |
|
260 const nsAString & aValue, |
|
261 ChangeAttributeTxn ** aTxn); |
|
262 |
|
263 /** create a transaction for removing aAttribute on aElement |
|
264 */ |
|
265 NS_IMETHOD CreateTxnForRemoveAttribute(nsIDOMElement *aElement, |
|
266 const nsAString & aAttribute, |
|
267 ChangeAttributeTxn ** aTxn); |
|
268 |
|
269 /** create a transaction for creating a new child node of aParent of type aTag. |
|
270 */ |
|
271 NS_IMETHOD CreateTxnForCreateElement(const nsAString & aTag, |
|
272 nsIDOMNode *aParent, |
|
273 int32_t aPosition, |
|
274 CreateElementTxn ** aTxn); |
|
275 |
|
276 /** create a transaction for inserting aNode as a child of aParent. |
|
277 */ |
|
278 NS_IMETHOD CreateTxnForInsertElement(nsIDOMNode * aNode, |
|
279 nsIDOMNode * aParent, |
|
280 int32_t aOffset, |
|
281 InsertElementTxn ** aTxn); |
|
282 |
|
283 /** create a transaction for removing aNode from its parent. |
|
284 */ |
|
285 nsresult CreateTxnForDeleteNode(nsINode* aNode, DeleteNodeTxn** aTxn); |
|
286 |
|
287 |
|
288 nsresult CreateTxnForDeleteSelection(EDirection aAction, |
|
289 EditAggregateTxn** aTxn, |
|
290 nsINode** aNode, |
|
291 int32_t* aOffset, |
|
292 int32_t* aLength); |
|
293 |
|
294 nsresult CreateTxnForDeleteInsertionPoint(nsRange* aRange, |
|
295 EDirection aAction, |
|
296 EditAggregateTxn* aTxn, |
|
297 nsINode** aNode, |
|
298 int32_t* aOffset, |
|
299 int32_t* aLength); |
|
300 |
|
301 |
|
302 /** create a transaction for inserting aStringToInsert into aTextNode |
|
303 * if aTextNode is null, the string is inserted at the current selection. |
|
304 */ |
|
305 NS_IMETHOD CreateTxnForInsertText(const nsAString & aStringToInsert, |
|
306 nsIDOMCharacterData *aTextNode, |
|
307 int32_t aOffset, |
|
308 InsertTextTxn ** aTxn); |
|
309 |
|
310 NS_IMETHOD CreateTxnForIMEText(const nsAString & aStringToInsert, |
|
311 IMETextTxn ** aTxn); |
|
312 |
|
313 /** create a transaction for adding a style sheet |
|
314 */ |
|
315 NS_IMETHOD CreateTxnForAddStyleSheet(nsCSSStyleSheet* aSheet, AddStyleSheetTxn* *aTxn); |
|
316 |
|
317 /** create a transaction for removing a style sheet |
|
318 */ |
|
319 NS_IMETHOD CreateTxnForRemoveStyleSheet(nsCSSStyleSheet* aSheet, RemoveStyleSheetTxn* *aTxn); |
|
320 |
|
321 NS_IMETHOD DeleteText(nsIDOMCharacterData *aElement, |
|
322 uint32_t aOffset, |
|
323 uint32_t aLength); |
|
324 |
|
325 // NS_IMETHOD DeleteRange(nsIDOMRange *aRange); |
|
326 |
|
327 nsresult CreateTxnForDeleteText(nsIDOMCharacterData* aElement, |
|
328 uint32_t aOffset, |
|
329 uint32_t aLength, |
|
330 DeleteTextTxn** aTxn); |
|
331 |
|
332 nsresult CreateTxnForDeleteCharacter(nsIDOMCharacterData* aData, |
|
333 uint32_t aOffset, |
|
334 EDirection aDirection, |
|
335 DeleteTextTxn** aTxn); |
|
336 |
|
337 NS_IMETHOD CreateTxnForSplitNode(nsIDOMNode *aNode, |
|
338 uint32_t aOffset, |
|
339 SplitElementTxn **aTxn); |
|
340 |
|
341 NS_IMETHOD CreateTxnForJoinNode(nsIDOMNode *aLeftNode, |
|
342 nsIDOMNode *aRightNode, |
|
343 JoinElementTxn **aTxn); |
|
344 |
|
345 /** |
|
346 * This method first deletes the selection, if it's not collapsed. Then if |
|
347 * the selection lies in a CharacterData node, it splits it. If the |
|
348 * selection is at this point collapsed in a CharacterData node, it's |
|
349 * adjusted to be collapsed right before or after the node instead (which is |
|
350 * always possible, since the node was split). |
|
351 */ |
|
352 nsresult DeleteSelectionAndPrepareToCreateNode(); |
|
353 |
|
354 |
|
355 // called after a transaction is done successfully |
|
356 void DoAfterDoTransaction(nsITransaction *aTxn); |
|
357 // called after a transaction is undone successfully |
|
358 void DoAfterUndoTransaction(); |
|
359 // called after a transaction is redone successfully |
|
360 void DoAfterRedoTransaction(); |
|
361 |
|
362 typedef enum { |
|
363 eDocumentCreated, |
|
364 eDocumentToBeDestroyed, |
|
365 eDocumentStateChanged |
|
366 } TDocumentListenerNotification; |
|
367 |
|
368 // tell the doc state listeners that the doc state has changed |
|
369 NS_IMETHOD NotifyDocumentListeners(TDocumentListenerNotification aNotificationType); |
|
370 |
|
371 /** make the given selection span the entire document */ |
|
372 NS_IMETHOD SelectEntireDocument(nsISelection *aSelection); |
|
373 |
|
374 /** helper method for scrolling the selection into view after |
|
375 * an edit operation. aScrollToAnchor should be true if you |
|
376 * want to scroll to the point where the selection was started. |
|
377 * If false, it attempts to scroll the end of the selection into view. |
|
378 * |
|
379 * Editor methods *should* call this method instead of the versions |
|
380 * in the various selection interfaces, since this version makes sure |
|
381 * that the editor's sync/async settings for reflowing, painting, and |
|
382 * scrolling match. |
|
383 */ |
|
384 NS_IMETHOD ScrollSelectionIntoView(bool aScrollToAnchor); |
|
385 |
|
386 // Convenience method; forwards to IsBlockNode(nsINode*). |
|
387 bool IsBlockNode(nsIDOMNode* aNode); |
|
388 // stub. see comment in source. |
|
389 virtual bool IsBlockNode(nsINode* aNode); |
|
390 |
|
391 // helper for GetPriorNode and GetNextNode |
|
392 nsIContent* FindNextLeafNode(nsINode *aCurrentNode, |
|
393 bool aGoForward, |
|
394 bool bNoBlockCrossing); |
|
395 |
|
396 // install the event listeners for the editor |
|
397 virtual nsresult InstallEventListeners(); |
|
398 |
|
399 virtual void CreateEventListeners(); |
|
400 |
|
401 // unregister and release our event listeners |
|
402 virtual void RemoveEventListeners(); |
|
403 |
|
404 /** |
|
405 * Return true if spellchecking should be enabled for this editor. |
|
406 */ |
|
407 bool GetDesiredSpellCheckState(); |
|
408 |
|
409 bool CanEnableSpellCheck() |
|
410 { |
|
411 // Check for password/readonly/disabled, which are not spellchecked |
|
412 // regardless of DOM. Also, check to see if spell check should be skipped or not. |
|
413 return !IsPasswordEditor() && !IsReadonly() && !IsDisabled() && !ShouldSkipSpellCheck(); |
|
414 } |
|
415 |
|
416 /** |
|
417 * EnsureComposition() should be composition event handlers or text event |
|
418 * handler. This tries to get the composition for the event and set it to |
|
419 * mComposition. |
|
420 */ |
|
421 void EnsureComposition(mozilla::WidgetGUIEvent* aEvent); |
|
422 |
|
423 public: |
|
424 |
|
425 /** All editor operations which alter the doc should be prefaced |
|
426 * with a call to StartOperation, naming the action and direction */ |
|
427 NS_IMETHOD StartOperation(EditAction opID, |
|
428 nsIEditor::EDirection aDirection); |
|
429 |
|
430 /** All editor operations which alter the doc should be followed |
|
431 * with a call to EndOperation */ |
|
432 NS_IMETHOD EndOperation(); |
|
433 |
|
434 /** routines for managing the preservation of selection across |
|
435 * various editor actions */ |
|
436 bool ArePreservingSelection(); |
|
437 void PreserveSelectionAcrossActions(mozilla::dom::Selection* aSel); |
|
438 nsresult RestorePreservedSelection(nsISelection *aSel); |
|
439 void StopPreservingSelection(); |
|
440 |
|
441 /** |
|
442 * SplitNode() creates a new node identical to an existing node, and split the contents between the two nodes |
|
443 * @param aExistingRightNode the node to split. It will become the new node's next sibling. |
|
444 * @param aOffset the offset of aExistingRightNode's content|children to do the split at |
|
445 * @param aNewLeftNode [OUT] the new node resulting from the split, becomes aExistingRightNode's previous sibling. |
|
446 * @param aParent the parent of aExistingRightNode |
|
447 */ |
|
448 nsresult SplitNodeImpl(nsIDOMNode *aExistingRightNode, |
|
449 int32_t aOffset, |
|
450 nsIDOMNode *aNewLeftNode, |
|
451 nsIDOMNode *aParent); |
|
452 |
|
453 /** |
|
454 * JoinNodes() takes 2 nodes and merge their content|children. |
|
455 * @param aNodeToKeep The node that will remain after the join. |
|
456 * @param aNodeToJoin The node that will be joined with aNodeToKeep. |
|
457 * There is no requirement that the two nodes be of the same type. |
|
458 * @param aParent The parent of aNodeToKeep |
|
459 */ |
|
460 nsresult JoinNodesImpl(nsINode* aNodeToKeep, |
|
461 nsINode* aNodeToJoin, |
|
462 nsINode* aParent); |
|
463 |
|
464 /** |
|
465 * Return the offset of aChild in aParent. Asserts fatally if parent or |
|
466 * child is null, or parent is not child's parent. |
|
467 */ |
|
468 static int32_t GetChildOffset(nsIDOMNode *aChild, |
|
469 nsIDOMNode *aParent); |
|
470 |
|
471 /** |
|
472 * Set outOffset to the offset of aChild in the parent. |
|
473 * Returns the parent of aChild. |
|
474 */ |
|
475 static already_AddRefed<nsIDOMNode> GetNodeLocation(nsIDOMNode* aChild, |
|
476 int32_t* outOffset); |
|
477 static nsINode* GetNodeLocation(nsINode* aChild, int32_t* aOffset); |
|
478 |
|
479 /** returns the number of things inside aNode in the out-param aCount. |
|
480 * @param aNode is the node to get the length of. |
|
481 * If aNode is text, returns number of characters. |
|
482 * If not, returns number of children nodes. |
|
483 * @param aCount [OUT] the result of the above calculation. |
|
484 */ |
|
485 static nsresult GetLengthOfDOMNode(nsIDOMNode *aNode, uint32_t &aCount); |
|
486 |
|
487 /** get the node immediately prior to aCurrentNode |
|
488 * @param aCurrentNode the node from which we start the search |
|
489 * @param aEditableNode if true, only return an editable node |
|
490 * @param aResultNode [OUT] the node that occurs before aCurrentNode in the tree, |
|
491 * skipping non-editable nodes if aEditableNode is true. |
|
492 * If there is no prior node, aResultNode will be nullptr. |
|
493 * @param bNoBlockCrossing If true, don't move across "block" nodes, whatever that means. |
|
494 */ |
|
495 nsresult GetPriorNode(nsIDOMNode *aCurrentNode, |
|
496 bool aEditableNode, |
|
497 nsCOMPtr<nsIDOMNode> *aResultNode, |
|
498 bool bNoBlockCrossing = false); |
|
499 nsIContent* GetPriorNode(nsINode* aCurrentNode, bool aEditableNode, |
|
500 bool aNoBlockCrossing = false); |
|
501 |
|
502 // and another version that takes a {parent,offset} pair rather than a node |
|
503 nsresult GetPriorNode(nsIDOMNode *aParentNode, |
|
504 int32_t aOffset, |
|
505 bool aEditableNode, |
|
506 nsCOMPtr<nsIDOMNode> *aResultNode, |
|
507 bool bNoBlockCrossing = false); |
|
508 nsIContent* GetPriorNode(nsINode* aParentNode, |
|
509 int32_t aOffset, |
|
510 bool aEditableNode, |
|
511 bool aNoBlockCrossing = false); |
|
512 |
|
513 |
|
514 /** get the node immediately after to aCurrentNode |
|
515 * @param aCurrentNode the node from which we start the search |
|
516 * @param aEditableNode if true, only return an editable node |
|
517 * @param aResultNode [OUT] the node that occurs after aCurrentNode in the tree, |
|
518 * skipping non-editable nodes if aEditableNode is true. |
|
519 * If there is no prior node, aResultNode will be nullptr. |
|
520 */ |
|
521 nsresult GetNextNode(nsIDOMNode *aCurrentNode, |
|
522 bool aEditableNode, |
|
523 nsCOMPtr<nsIDOMNode> *aResultNode, |
|
524 bool bNoBlockCrossing = false); |
|
525 nsIContent* GetNextNode(nsINode* aCurrentNode, |
|
526 bool aEditableNode, |
|
527 bool bNoBlockCrossing = false); |
|
528 |
|
529 // and another version that takes a {parent,offset} pair rather than a node |
|
530 nsresult GetNextNode(nsIDOMNode *aParentNode, |
|
531 int32_t aOffset, |
|
532 bool aEditableNode, |
|
533 nsCOMPtr<nsIDOMNode> *aResultNode, |
|
534 bool bNoBlockCrossing = false); |
|
535 nsIContent* GetNextNode(nsINode* aParentNode, |
|
536 int32_t aOffset, |
|
537 bool aEditableNode, |
|
538 bool aNoBlockCrossing = false); |
|
539 |
|
540 // Helper for GetNextNode and GetPriorNode |
|
541 nsIContent* FindNode(nsINode *aCurrentNode, |
|
542 bool aGoForward, |
|
543 bool aEditableNode, |
|
544 bool bNoBlockCrossing); |
|
545 /** |
|
546 * Get the rightmost child of aCurrentNode; |
|
547 * return nullptr if aCurrentNode has no children. |
|
548 */ |
|
549 nsIDOMNode* GetRightmostChild(nsIDOMNode* aCurrentNode, |
|
550 bool bNoBlockCrossing = false); |
|
551 nsIContent* GetRightmostChild(nsINode *aCurrentNode, |
|
552 bool bNoBlockCrossing = false); |
|
553 |
|
554 /** |
|
555 * Get the leftmost child of aCurrentNode; |
|
556 * return nullptr if aCurrentNode has no children. |
|
557 */ |
|
558 nsIDOMNode* GetLeftmostChild(nsIDOMNode* aCurrentNode, |
|
559 bool bNoBlockCrossing = false); |
|
560 nsIContent* GetLeftmostChild(nsINode *aCurrentNode, |
|
561 bool bNoBlockCrossing = false); |
|
562 |
|
563 /** returns true if aNode is of the type implied by aTag */ |
|
564 static inline bool NodeIsType(nsIDOMNode *aNode, nsIAtom *aTag) |
|
565 { |
|
566 return GetTag(aNode) == aTag; |
|
567 } |
|
568 |
|
569 /** returns true if aParent can contain a child of type aTag */ |
|
570 bool CanContain(nsIDOMNode* aParent, nsIDOMNode* aChild); |
|
571 bool CanContainTag(nsIDOMNode* aParent, nsIAtom* aTag); |
|
572 bool TagCanContain(nsIAtom* aParentTag, nsIDOMNode* aChild); |
|
573 virtual bool TagCanContainTag(nsIAtom* aParentTag, nsIAtom* aChildTag); |
|
574 |
|
575 /** returns true if aNode is our root node */ |
|
576 bool IsRoot(nsIDOMNode* inNode); |
|
577 bool IsRoot(nsINode* inNode); |
|
578 bool IsEditorRoot(nsINode* aNode); |
|
579 |
|
580 /** returns true if aNode is a descendant of our root node */ |
|
581 bool IsDescendantOfRoot(nsIDOMNode* inNode); |
|
582 bool IsDescendantOfRoot(nsINode* inNode); |
|
583 bool IsDescendantOfEditorRoot(nsIDOMNode* aNode); |
|
584 bool IsDescendantOfEditorRoot(nsINode* aNode); |
|
585 |
|
586 /** returns true if aNode is a container */ |
|
587 virtual bool IsContainer(nsIDOMNode *aNode); |
|
588 |
|
589 /** returns true if aNode is an editable node */ |
|
590 bool IsEditable(nsIDOMNode *aNode); |
|
591 virtual bool IsEditable(nsIContent *aNode); |
|
592 |
|
593 /** returns true if aNode is a MozEditorBogus node */ |
|
594 bool IsMozEditorBogusNode(nsIContent *aNode); |
|
595 |
|
596 /** counts number of editable child nodes */ |
|
597 uint32_t CountEditableChildren(nsINode* aNode); |
|
598 |
|
599 /** Find the deep first and last children. */ |
|
600 nsINode* GetFirstEditableNode(nsINode* aRoot); |
|
601 |
|
602 /** |
|
603 * Returns current composition. |
|
604 */ |
|
605 mozilla::TextComposition* GetComposition() const; |
|
606 /** |
|
607 * Returns true if there is composition string and not fixed. |
|
608 */ |
|
609 bool IsIMEComposing() const; |
|
610 |
|
611 /** from html rules code - migration in progress */ |
|
612 static nsresult GetTagString(nsIDOMNode *aNode, nsAString& outString); |
|
613 static nsIAtom *GetTag(nsIDOMNode *aNode); |
|
614 |
|
615 bool NodesSameType(nsIDOMNode *aNode1, nsIDOMNode *aNode2); |
|
616 virtual bool AreNodesSameType(nsIContent* aNode1, nsIContent* aNode2); |
|
617 |
|
618 static bool IsTextNode(nsIDOMNode *aNode); |
|
619 static bool IsTextNode(nsINode *aNode); |
|
620 |
|
621 static nsCOMPtr<nsIDOMNode> GetChildAt(nsIDOMNode *aParent, int32_t aOffset); |
|
622 static nsCOMPtr<nsIDOMNode> GetNodeAtRangeOffsetPoint(nsIDOMNode* aParentOrNode, int32_t aOffset); |
|
623 |
|
624 static nsresult GetStartNodeAndOffset(nsISelection *aSelection, nsIDOMNode **outStartNode, int32_t *outStartOffset); |
|
625 static nsresult GetStartNodeAndOffset(mozilla::dom::Selection* aSelection, |
|
626 nsINode** aStartNode, |
|
627 int32_t* aStartOffset); |
|
628 static nsresult GetEndNodeAndOffset(nsISelection *aSelection, nsIDOMNode **outEndNode, int32_t *outEndOffset); |
|
629 static nsresult GetEndNodeAndOffset(mozilla::dom::Selection* aSelection, |
|
630 nsINode** aEndNode, |
|
631 int32_t* aEndOffset); |
|
632 #if DEBUG_JOE |
|
633 static void DumpNode(nsIDOMNode *aNode, int32_t indent=0); |
|
634 #endif |
|
635 mozilla::dom::Selection* GetSelection(); |
|
636 |
|
637 // Helpers to add a node to the selection. |
|
638 // Used by table cell selection methods |
|
639 nsresult CreateRange(nsIDOMNode *aStartParent, int32_t aStartOffset, |
|
640 nsIDOMNode *aEndParent, int32_t aEndOffset, |
|
641 nsIDOMRange **aRange); |
|
642 |
|
643 // Creates a range with just the supplied node and appends that to the selection |
|
644 nsresult AppendNodeToSelectionAsRange(nsIDOMNode *aNode); |
|
645 // When you are using AppendNodeToSelectionAsRange, call this first to start a new selection |
|
646 nsresult ClearSelection(); |
|
647 |
|
648 nsresult IsPreformatted(nsIDOMNode *aNode, bool *aResult); |
|
649 |
|
650 nsresult SplitNodeDeep(nsIDOMNode *aNode, |
|
651 nsIDOMNode *aSplitPointParent, |
|
652 int32_t aSplitPointOffset, |
|
653 int32_t *outOffset, |
|
654 bool aNoEmptyContainers = false, |
|
655 nsCOMPtr<nsIDOMNode> *outLeftNode = 0, |
|
656 nsCOMPtr<nsIDOMNode> *outRightNode = 0); |
|
657 nsresult JoinNodeDeep(nsIDOMNode *aLeftNode, nsIDOMNode *aRightNode, nsCOMPtr<nsIDOMNode> *aOutJoinNode, int32_t *outOffset); |
|
658 |
|
659 nsresult GetString(const nsAString& name, nsAString& value); |
|
660 |
|
661 void BeginUpdateViewBatch(void); |
|
662 virtual nsresult EndUpdateViewBatch(void); |
|
663 |
|
664 bool GetShouldTxnSetSelection(); |
|
665 |
|
666 virtual nsresult HandleKeyPressEvent(nsIDOMKeyEvent* aKeyEvent); |
|
667 |
|
668 nsresult HandleInlineSpellCheck(EditAction action, |
|
669 nsISelection *aSelection, |
|
670 nsIDOMNode *previousSelectedNode, |
|
671 int32_t previousSelectedOffset, |
|
672 nsIDOMNode *aStartNode, |
|
673 int32_t aStartOffset, |
|
674 nsIDOMNode *aEndNode, |
|
675 int32_t aEndOffset); |
|
676 |
|
677 virtual already_AddRefed<mozilla::dom::EventTarget> GetDOMEventTarget() = 0; |
|
678 |
|
679 // Fast non-refcounting editor root element accessor |
|
680 mozilla::dom::Element *GetRoot(); |
|
681 |
|
682 // Likewise, but gets the editor's root instead, which is different for HTML |
|
683 // editors |
|
684 virtual mozilla::dom::Element* GetEditorRoot(); |
|
685 |
|
686 // Likewise, but gets the text control element instead of the root for |
|
687 // plaintext editors |
|
688 mozilla::dom::Element* GetExposedRoot(); |
|
689 |
|
690 // Accessor methods to flags |
|
691 bool IsPlaintextEditor() const |
|
692 { |
|
693 return (mFlags & nsIPlaintextEditor::eEditorPlaintextMask) != 0; |
|
694 } |
|
695 |
|
696 bool IsSingleLineEditor() const |
|
697 { |
|
698 return (mFlags & nsIPlaintextEditor::eEditorSingleLineMask) != 0; |
|
699 } |
|
700 |
|
701 bool IsPasswordEditor() const |
|
702 { |
|
703 return (mFlags & nsIPlaintextEditor::eEditorPasswordMask) != 0; |
|
704 } |
|
705 |
|
706 bool IsReadonly() const |
|
707 { |
|
708 return (mFlags & nsIPlaintextEditor::eEditorReadonlyMask) != 0; |
|
709 } |
|
710 |
|
711 bool IsDisabled() const |
|
712 { |
|
713 return (mFlags & nsIPlaintextEditor::eEditorDisabledMask) != 0; |
|
714 } |
|
715 |
|
716 bool IsInputFiltered() const |
|
717 { |
|
718 return (mFlags & nsIPlaintextEditor::eEditorFilterInputMask) != 0; |
|
719 } |
|
720 |
|
721 bool IsMailEditor() const |
|
722 { |
|
723 return (mFlags & nsIPlaintextEditor::eEditorMailMask) != 0; |
|
724 } |
|
725 |
|
726 bool IsWrapHackEnabled() const |
|
727 { |
|
728 return (mFlags & nsIPlaintextEditor::eEditorEnableWrapHackMask) != 0; |
|
729 } |
|
730 |
|
731 bool IsFormWidget() const |
|
732 { |
|
733 return (mFlags & nsIPlaintextEditor::eEditorWidgetMask) != 0; |
|
734 } |
|
735 |
|
736 bool NoCSS() const |
|
737 { |
|
738 return (mFlags & nsIPlaintextEditor::eEditorNoCSSMask) != 0; |
|
739 } |
|
740 |
|
741 bool IsInteractionAllowed() const |
|
742 { |
|
743 return (mFlags & nsIPlaintextEditor::eEditorAllowInteraction) != 0; |
|
744 } |
|
745 |
|
746 bool DontEchoPassword() const |
|
747 { |
|
748 return (mFlags & nsIPlaintextEditor::eEditorDontEchoPassword) != 0; |
|
749 } |
|
750 |
|
751 bool ShouldSkipSpellCheck() const |
|
752 { |
|
753 return (mFlags & nsIPlaintextEditor::eEditorSkipSpellCheck) != 0; |
|
754 } |
|
755 |
|
756 bool IsTabbable() const |
|
757 { |
|
758 return IsSingleLineEditor() || IsPasswordEditor() || IsFormWidget() || |
|
759 IsInteractionAllowed(); |
|
760 } |
|
761 |
|
762 bool HasIndependentSelection() const |
|
763 { |
|
764 return !!mSelConWeak; |
|
765 } |
|
766 |
|
767 // Get the input event target. This might return null. |
|
768 virtual already_AddRefed<nsIContent> GetInputEventTargetContent() = 0; |
|
769 |
|
770 // Get the focused content, if we're focused. Returns null otherwise. |
|
771 virtual already_AddRefed<nsIContent> GetFocusedContent(); |
|
772 |
|
773 // Get the focused content for the argument of some IMEStateManager's |
|
774 // methods. |
|
775 virtual already_AddRefed<nsIContent> GetFocusedContentForIME(); |
|
776 |
|
777 // Whether the editor is active on the DOM window. Note that when this |
|
778 // returns true but GetFocusedContent() returns null, it means that this editor was |
|
779 // focused when the DOM window was active. |
|
780 virtual bool IsActiveInDOMWindow(); |
|
781 |
|
782 // Whether the aEvent should be handled by this editor or not. When this |
|
783 // returns FALSE, The aEvent shouldn't be handled on this editor, |
|
784 // i.e., The aEvent should be handled by another inner editor or ancestor |
|
785 // elements. |
|
786 virtual bool IsAcceptableInputEvent(nsIDOMEvent* aEvent); |
|
787 |
|
788 // FindSelectionRoot() returns a selection root of this editor when aNode |
|
789 // gets focus. aNode must be a content node or a document node. When the |
|
790 // target isn't a part of this editor, returns nullptr. If this is for |
|
791 // designMode, you should set the document node to aNode except that an |
|
792 // element in the document has focus. |
|
793 virtual already_AddRefed<nsIContent> FindSelectionRoot(nsINode* aNode); |
|
794 |
|
795 // Initializes selection and caret for the editor. If aEventTarget isn't |
|
796 // a host of the editor, i.e., the editor doesn't get focus, this does |
|
797 // nothing. |
|
798 nsresult InitializeSelection(nsIDOMEventTarget* aFocusEventTarget); |
|
799 |
|
800 // Finalizes selection and caret for the editor. |
|
801 void FinalizeSelection(); |
|
802 |
|
803 // This method has to be called by nsEditorEventListener::Focus. |
|
804 // All actions that have to be done when the editor is focused needs to be |
|
805 // added here. |
|
806 void OnFocus(nsIDOMEventTarget* aFocusEventTarget); |
|
807 |
|
808 // Used to insert content from a data transfer into the editable area. |
|
809 // This is called for each item in the data transfer, with the index of |
|
810 // each item passed as aIndex. |
|
811 virtual nsresult InsertFromDataTransfer(mozilla::dom::DataTransfer *aDataTransfer, |
|
812 int32_t aIndex, |
|
813 nsIDOMDocument *aSourceDoc, |
|
814 nsIDOMNode *aDestinationNode, |
|
815 int32_t aDestOffset, |
|
816 bool aDoDeleteSelection) = 0; |
|
817 |
|
818 virtual nsresult InsertFromDrop(nsIDOMEvent* aDropEvent) = 0; |
|
819 |
|
820 virtual already_AddRefed<nsIDOMNode> FindUserSelectAllNode(nsIDOMNode* aNode) { return nullptr; } |
|
821 |
|
822 protected: |
|
823 enum Tristate { |
|
824 eTriUnset, |
|
825 eTriFalse, |
|
826 eTriTrue |
|
827 }; |
|
828 // Spellchecking |
|
829 nsCString mContentMIMEType; // MIME type of the doc we are editing. |
|
830 |
|
831 nsCOMPtr<nsIInlineSpellChecker> mInlineSpellChecker; |
|
832 |
|
833 nsRefPtr<nsTransactionManager> mTxnMgr; |
|
834 nsCOMPtr<mozilla::dom::Element> mRootElement; // cached root node |
|
835 nsCOMPtr<nsIDOMCharacterData> mIMETextNode; // current IME text node |
|
836 nsCOMPtr<mozilla::dom::EventTarget> mEventTarget; // The form field as an event receiver |
|
837 nsCOMPtr<nsIDOMEventListener> mEventListener; |
|
838 nsWeakPtr mSelConWeak; // weak reference to the nsISelectionController |
|
839 nsWeakPtr mPlaceHolderTxn; // weak reference to placeholder for begin/end batch purposes |
|
840 nsWeakPtr mDocWeak; // weak reference to the nsIDOMDocument |
|
841 nsIAtom *mPlaceHolderName; // name of placeholder transaction |
|
842 nsSelectionState *mSelState; // saved selection state for placeholder txn batching |
|
843 nsString *mPhonetic; |
|
844 // IME composition this is not null between compositionstart and |
|
845 // compositionend. |
|
846 nsRefPtr<mozilla::TextComposition> mComposition; |
|
847 |
|
848 // various listeners |
|
849 nsCOMArray<nsIEditActionListener> mActionListeners; // listens to all low level actions on the doc |
|
850 nsCOMArray<nsIEditorObserver> mEditorObservers; // just notify once per high level change |
|
851 nsCOMArray<nsIDocumentStateListener> mDocStateListeners;// listen to overall doc state (dirty or not, just created, etc) |
|
852 |
|
853 nsSelectionState mSavedSel; // cached selection for nsAutoSelectionReset |
|
854 nsRangeUpdater mRangeUpdater; // utility class object for maintaining preserved ranges |
|
855 |
|
856 uint32_t mModCount; // number of modifications (for undo/redo stack) |
|
857 uint32_t mFlags; // behavior flags. See nsIPlaintextEditor.idl for the flags we use. |
|
858 |
|
859 int32_t mUpdateCount; |
|
860 |
|
861 int32_t mPlaceHolderBatch; // nesting count for batching |
|
862 EditAction mAction; // the current editor action |
|
863 |
|
864 uint32_t mIMETextOffset; // offset in text node where IME comp string begins |
|
865 |
|
866 EDirection mDirection; // the current direction of editor action |
|
867 int8_t mDocDirtyState; // -1 = not initialized |
|
868 uint8_t mSpellcheckCheckboxState; // a Tristate value |
|
869 |
|
870 bool mShouldTxnSetSelection; // turn off for conservative selection adjustment by txns |
|
871 bool mDidPreDestroy; // whether PreDestroy has been called |
|
872 bool mDidPostCreate; // whether PostCreate has been called |
|
873 bool mDispatchInputEvent; |
|
874 |
|
875 friend bool NSCanUnload(nsISupports* serviceMgr); |
|
876 friend class nsAutoTxnsConserveSelection; |
|
877 friend class nsAutoSelectionReset; |
|
878 friend class nsAutoRules; |
|
879 friend class nsRangeUpdater; |
|
880 }; |
|
881 |
|
882 |
|
883 #endif |