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